From: Yangbo Lu Date: Wed, 27 Sep 2017 07:31:31 +0000 (+0800) Subject: layerscape: add linux 4.9 support X-Git-Tag: v18.06.0-rc1~2077 X-Git-Url: http://git.openwrt.org/?p=openwrt%2Fstaging%2Fchunkeey.git;a=commitdiff_plain;h=8fdda1cc1033e2bd0d048188af5167faffbf9b38 layerscape: add linux 4.9 support This patch is to add linux 4.9 support for layerscape. All these kernel patches are from NXP LSDK 1709 release. Signed-off-by: Yangbo Lu --- diff --git a/target/linux/layerscape/Makefile b/target/linux/layerscape/Makefile index 9c92bb4896..67da8449aa 100644 --- a/target/linux/layerscape/Makefile +++ b/target/linux/layerscape/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk BOARD:=layerscape BOARDNAME:=NXP Layerscape DEVICE_TYPE:=developerboard -KERNEL_PATCHVER:=4.4 +KERNEL_PATCHVER:=4.9 FEATURES:=squashfs nand usb pcie gpio SUBTARGETS:=armv8_64b armv8_32b MAINTAINER:=Yangbo Lu diff --git a/target/linux/layerscape/armv8_32b/config-4.9 b/target/linux/layerscape/armv8_32b/config-4.9 new file mode 100644 index 0000000000..ec7d0c1640 --- /dev/null +++ b/target/linux/layerscape/armv8_32b/config-4.9 @@ -0,0 +1,1461 @@ +CONFIG_ABX500_CORE=y +CONFIG_AD525X_DPOT=y +CONFIG_AD525X_DPOT_I2C=y +# CONFIG_AD525X_DPOT_SPI is not set +CONFIG_ADVISE_SYSCALLS=y +CONFIG_AHCI_IMX=y +CONFIG_AHCI_QORIQ=y +CONFIG_AK8975=y +CONFIG_ALIGNMENT_TRAP=y +CONFIG_APDS9802ALS=y +CONFIG_AQUANTIA_PHY=y +# CONFIG_ARCH_AXXIA is not set +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_HAS_BANDGAP=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +CONFIG_ARCH_HAS_RESET_CONTROLLER=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_MXC=y +CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED=y +CONFIG_ARCH_NR_GPIO=512 +CONFIG_ARCH_OMAP=y +CONFIG_ARCH_OMAP2PLUS=y +CONFIG_ARCH_OMAP2PLUS_TYPICAL=y +CONFIG_ARCH_OMAP3=y +CONFIG_ARCH_OMAP4=y +CONFIG_ARCH_PHYS_ADDR_T_64BIT=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_VIRT=y +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y +CONFIG_ARM=y +CONFIG_ARM_AMBA=y +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set +CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y +CONFIG_ARM_CPUIDLE=y +CONFIG_ARM_CPU_SUSPEND=y +CONFIG_ARM_CRYPTO=y +CONFIG_ARM_ERRATA_430973=y +CONFIG_ARM_ERRATA_643719=y +CONFIG_ARM_ERRATA_720789=y +CONFIG_ARM_ERRATA_754322=y +CONFIG_ARM_ERRATA_754327=y +CONFIG_ARM_ERRATA_764369=y +CONFIG_ARM_ERRATA_775420=y +CONFIG_ARM_ERRATA_798181=y +CONFIG_ARM_GIC=y +CONFIG_ARM_GIC_V2M=y +CONFIG_ARM_GIC_V3=y +CONFIG_ARM_HAS_SG_CHAIN=y +CONFIG_ARM_HEAVY_MB=y +# CONFIG_ARM_HIGHBANK_CPUIDLE is not set +CONFIG_ARM_IMX6Q_CPUFREQ=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_LPAE=y +CONFIG_ARM_OMAP2PLUS_CPUFREQ=y +CONFIG_ARM_PATCH_IDIV=y +CONFIG_ARM_PATCH_PHYS_VIRT=y +# CONFIG_ARM_PL172_MPMC is not set +CONFIG_ARM_PMU=y +CONFIG_ARM_PSCI=y +CONFIG_ARM_PSCI_FW=y +# CONFIG_ARM_SCPI_PROTOCOL is not set +# CONFIG_ARM_SMMU is not set +CONFIG_ARM_SP805_WATCHDOG=y +CONFIG_ARM_THUMB=y +CONFIG_ARM_THUMBEE=y +CONFIG_ARM_TIMER_SP804=y +CONFIG_ARM_UNWIND=y +CONFIG_ARM_VIRT_EXT=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_AT803X_PHY=y +CONFIG_ATA=y +CONFIG_ATAGS=y +CONFIG_ATA_VERBOSE_ERROR=y +# CONFIG_ATH5K_PCI is not set +CONFIG_AUTOFS4_FS=y +CONFIG_AUTO_ZRELADDR=y +# CONFIG_AXP20X_POWER is not set +CONFIG_BACKLIGHT_AS3711=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_GENERIC=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_PWM=y +# CONFIG_BACKLIGHT_TPS65217 is not set +CONFIG_BATTERY_ACT8945A=y +CONFIG_BATTERY_SBS=y +CONFIG_BCMA=y +CONFIG_BCMA_BLOCKIO=y +# CONFIG_BCMA_DEBUG is not set +CONFIG_BCMA_DRIVER_GMAC_CMN=y +CONFIG_BCMA_DRIVER_GPIO=y +CONFIG_BCMA_DRIVER_PCI=y +CONFIG_BCMA_HOST_PCI=y +CONFIG_BCMA_HOST_PCI_POSSIBLE=y +CONFIG_BCMA_HOST_SOC=y +CONFIG_BCMA_SFLASH=y +CONFIG_BCM_NET_PHYLIB=y +# CONFIG_BLK_CGROUP is not set +CONFIG_BLK_CMDLINE_PARSER=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NVME=y +# CONFIG_BLK_DEV_NVME_SCSI is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=262144 +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_BLK_MQ_PCI=y +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_BOUNCE=y +# CONFIG_BPF_SYSCALL is not set +CONFIG_BRCMSTB_GISB_ARB=y +CONFIG_BROADCOM_PHY=y +CONFIG_BUILD_BIN2C=y +CONFIG_CACHE_L2X0=y +# CONFIG_CACHE_L2X0_PMU is not set +CONFIG_CAN=y +# CONFIG_CAN_8DEV_USB is not set +CONFIG_CAN_BCM=y +CONFIG_CAN_CALC_BITTIMING=y +# CONFIG_CAN_CC770 is not set +# CONFIG_CAN_C_CAN is not set +CONFIG_CAN_DEV=y +# CONFIG_CAN_EMS_USB is not set +# CONFIG_CAN_ESD_USB2 is not set +CONFIG_CAN_FLEXCAN=y +# CONFIG_CAN_GRCAN is not set +CONFIG_CAN_GW=y +# CONFIG_CAN_KVASER_USB is not set +# CONFIG_CAN_LEDS is not set +CONFIG_CAN_MCP251X=y +# CONFIG_CAN_PEAK_USB is not set +CONFIG_CAN_RAW=y +# CONFIG_CAN_SJA1000 is not set +# CONFIG_CAN_SOFTING is not set +# CONFIG_CAN_TI_HECC is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_CGROUPS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_NET_CLASSID is not set +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_SCHED=y +# CONFIG_CHARGER_MAX14577 is not set +CONFIG_CHARGER_TPS65090=y +# CONFIG_CHARGER_TPS65217 is not set +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_CHROME_PLATFORMS=y +CONFIG_CHR_DEV_SG=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_IMX_GPT=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLKSRC_OF=y +CONFIG_CLKSRC_PROBE=y +CONFIG_CLKSRC_TI_32K=y +CONFIG_CLKSRC_VERSATILE=y +CONFIG_CLK_QORIQ=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CMA=y +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 +# CONFIG_CMA_DEBUG is not set +# CONFIG_CMA_DEBUGFS is not set +CONFIG_CMA_SIZE_MBYTES=64 +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +CONFIG_CMDLINE_PARTITION=y +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_MAX77686=y +# CONFIG_COMMON_CLK_PALMAS is not set +# CONFIG_COMMON_CLK_RK808 is not set +# CONFIG_COMMON_CLK_S2MPS11 is not set +CONFIG_COMMON_CLK_TI_ADPLL=y +CONFIG_COMPACTION=y +CONFIG_COMPAT_BRK=y +CONFIG_CONFIGFS_FS=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_COREDUMP=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +# CONFIG_CORTINA_PHY is not set +CONFIG_CPUFREQ_DT=y +CONFIG_CPUFREQ_DT_PLATDEV=y +CONFIG_CPUSETS=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +# CONFIG_CPU_BIG_ENDIAN is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_HAS_ASID=y +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +CONFIG_CPU_IDLE=y +# CONFIG_CPU_IDLE_GOV_LADDER is not set +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_PABRT_V7=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_CRC32_SARWATE is not set +CONFIG_CRC32_SLICEBY8=y +CONFIG_CROSS_MEMORY_ATTACH=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +# CONFIG_CRYPTO_AES_ARM_CE is not set +# CONFIG_CRYPTO_ARC4 is not set +CONFIG_CRYPTO_AUTHENC=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC is not set +# CONFIG_CRYPTO_DEV_MXC_SCC is not set +# CONFIG_CRYPTO_DEV_OMAP_AES is not set +# CONFIG_CRYPTO_DEV_OMAP_DES is not set +# CONFIG_CRYPTO_DEV_OMAP_SHAM is not set +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_ECHAINIV=y +# CONFIG_CRYPTO_GHASH_ARM_CE is not set +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_SHA1=y +# CONFIG_CRYPTO_SHA1_ARM_CE is not set +# CONFIG_CRYPTO_SHA1_ARM_NEON is not set +CONFIG_CRYPTO_SHA256=y +# CONFIG_CRYPTO_SHA256_ARM is not set +# CONFIG_CRYPTO_SHA2_ARM_CE is not set +# CONFIG_CRYPTO_SHA512_ARM is not set +# CONFIG_CRYPTO_TLS is not set +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_IMX_UART_PORT=1 +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +CONFIG_DEBUG_RODATA=y +# CONFIG_DEBUG_UART_8250 is not set +# CONFIG_DEBUG_USER is not set +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZO=y +CONFIG_DECOMPRESS_XZ=y +CONFIG_DEFAULT_CFQ=y +# CONFIG_DEFAULT_DEADLINE is not set +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_DETECT_HUNG_TASK=y +# CONFIG_DEVFREQ_GOV_PASSIVE is not set +# CONFIG_DEVFREQ_GOV_PERFORMANCE is not set +# CONFIG_DEVFREQ_GOV_POWERSAVE is not set +# CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND is not set +# CONFIG_DEVFREQ_GOV_USERSPACE is not set +# CONFIG_DEVFREQ_THERMAL is not set +CONFIG_DEVKMEM=y +CONFIG_DEVMEM=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DMADEVICES=y +CONFIG_DMA_CMA=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y +CONFIG_DMA_OMAP=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DNOTIFY=y +CONFIG_DNS_RESOLVER=y +CONFIG_DRM=y +CONFIG_DRM_BRIDGE=y +CONFIG_DRM_FBDEV_EMULATION=y +CONFIG_DRM_FSL_DCU=y +CONFIG_DRM_GEM_CMA_HELPER=y +CONFIG_DRM_KMS_CMA_HELPER=y +CONFIG_DRM_KMS_FB_HELPER=y +CONFIG_DRM_KMS_HELPER=y +CONFIG_DRM_PANEL=y +CONFIG_DRM_PANEL_SIMPLE=y +CONFIG_DRM_SII902X=y +# CONFIG_DRM_VIRTIO_GPU is not set +CONFIG_DST_CACHE=y +CONFIG_DTC=y +CONFIG_DT_IDLE_STATES=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_DWMAC_GENERIC=y +CONFIG_DW_DMAC=y +CONFIG_DW_DMAC_CORE=y +CONFIG_DW_WATCHDOG=y +CONFIG_E1000E=y +CONFIG_EDAC=y +CONFIG_EDAC_ATOMIC_SCRUB=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_LEGACY_SYSFS=y +# CONFIG_EDAC_MM_EDAC is not set +CONFIG_EDAC_SUPPORT=y +CONFIG_EEPROM_93CX6=y +CONFIG_EEPROM_AT24=y +CONFIG_EFI=y +# CONFIG_EFIVAR_FS is not set +CONFIG_EFI_ARMSTUB=y +# CONFIG_EFI_CAPSULE_LOADER is not set +CONFIG_EFI_ESRT=y +CONFIG_EFI_PARAMS_FROM_FDT=y +CONFIG_EFI_RUNTIME_WRAPPERS=y +CONFIG_EFI_STUB=y +# CONFIG_EFI_TEST is not set +# CONFIG_EFI_VARS is not set +CONFIG_ELF_CORE=y +# CONFIG_ENABLE_DEFAULT_TRACERS is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_EXPORTFS=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXTCON=y +# CONFIG_EXTCON_AXP288 is not set +# CONFIG_EXTCON_MAX14577 is not set +# CONFIG_EXTCON_MAX8997 is not set +# CONFIG_EXTCON_PALMAS is not set +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_FAT_FS=y +CONFIG_FB=y +CONFIG_FB_ARMCLCD=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_CMDLINE=y +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_EFI=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_MX3=y +CONFIG_FB_SIMPLE=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_FOPS=y +CONFIG_FB_SYS_IMAGEBLIT=y +CONFIG_FEC=y +CONFIG_FHANDLE=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FMAN_ARM=y +# CONFIG_FMAN_MIB_CNT_OVF_IRQ_EN is not set +# CONFIG_FMAN_P1023 is not set +# CONFIG_FMAN_P3040_P4080_P5020 is not set +# CONFIG_FMAN_PFC is not set +# CONFIG_FMAN_V3H is not set +# CONFIG_FMAN_V3L is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +CONFIG_FONT_SUPPORT=y +CONFIG_FORCE_MAX_ZONEORDER=12 +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_FREEZER=y +CONFIG_FSL_BMAN_CONFIG=y +CONFIG_FSL_BMAN_DEBUGFS=y +# CONFIG_FSL_BMAN_TEST is not set +# CONFIG_FSL_DPAA_1588 is not set +CONFIG_FSL_DPAA_ADVANCED_DRIVERS=y +# CONFIG_FSL_DPAA_CEETM is not set +CONFIG_FSL_DPAA_CS_THRESHOLD_10G=0x10000000 +CONFIG_FSL_DPAA_CS_THRESHOLD_1G=0x06000000 +# CONFIG_FSL_DPAA_DBG_LOOP is not set +# CONFIG_FSL_DPAA_ETH_DEBUG is not set +CONFIG_FSL_DPAA_ETH_DEBUGFS=y +# CONFIG_FSL_DPAA_ETH_JUMBO_FRAME is not set +CONFIG_FSL_DPAA_ETH_MAX_BUF_COUNT=128 +CONFIG_FSL_DPAA_ETH_REFILL_THRESHOLD=80 +CONFIG_FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE=y +# CONFIG_FSL_DPAA_HOOKS is not set +CONFIG_FSL_DPAA_INGRESS_CS_THRESHOLD=0x10000000 +CONFIG_FSL_DPAA_OFFLINE_PORTS=y +# CONFIG_FSL_DPAA_TS is not set +CONFIG_FSL_DPA_CAN_WAIT=y +CONFIG_FSL_DPA_CAN_WAIT_SYNC=y +# CONFIG_FSL_DPA_CHECKING is not set +CONFIG_FSL_DPA_PIRQ_FAST=y +CONFIG_FSL_DPA_PIRQ_SLOW=y +CONFIG_FSL_DPA_PORTAL_SHARE=y +CONFIG_FSL_EDMA=y +CONFIG_FSL_FM_MAX_FRAME_SIZE=1522 +CONFIG_FSL_FM_RX_EXTRA_HEADROOM=64 +CONFIG_FSL_GUTS=y +CONFIG_FSL_PQ_MDIO=y +# CONFIG_FSL_QDMA is not set +CONFIG_FSL_QMAN_CI_SCHED_CFG_BMAN_W=2 +CONFIG_FSL_QMAN_CI_SCHED_CFG_RW_W=2 +CONFIG_FSL_QMAN_CI_SCHED_CFG_SRCCIV=4 +CONFIG_FSL_QMAN_CI_SCHED_CFG_SRQ_W=3 +CONFIG_FSL_QMAN_CONFIG=y +CONFIG_FSL_QMAN_DEBUGFS=y +CONFIG_FSL_QMAN_FQD_SZ=10 +# CONFIG_FSL_QMAN_FQ_LOOKUP is not set +CONFIG_FSL_QMAN_INIT_TIMEOUT=10 +CONFIG_FSL_QMAN_PFDR_SZ=13 +CONFIG_FSL_QMAN_PIRQ_DQRR_ITHRESH=12 +CONFIG_FSL_QMAN_PIRQ_IPERIOD=100 +CONFIG_FSL_QMAN_PIRQ_MR_ITHRESH=4 +CONFIG_FSL_QMAN_POLL_LIMIT=32 +# CONFIG_FSL_QMAN_TEST is not set +CONFIG_FSL_SDK_BMAN=y +CONFIG_FSL_SDK_DPA=y +CONFIG_FSL_SDK_DPAA_ETH=y +CONFIG_FSL_SDK_FMAN=y +# CONFIG_FSL_SDK_FMAN_TEST is not set +CONFIG_FSL_SDK_QMAN=y +CONFIG_FSL_USDPAA=y +CONFIG_FSL_XGMAC_MDIO=y +CONFIG_FS_MBCACHE=y +CONFIG_FS_POSIX_ACL=y +CONFIG_FTRACE=y +# CONFIG_FTRACE_SYSCALLS is not set +CONFIG_FUSE_FS=y +# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_EARLY_IOREMAP=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_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GIANFAR=y +CONFIG_GLOB=y +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_IRQCHIP=y +# CONFIG_GPIO_AXP209 is not set +CONFIG_GPIO_DWAPB=y +CONFIG_GPIO_EM=y +CONFIG_GPIO_GENERIC=y +CONFIG_GPIO_GENERIC_PLATFORM=y +CONFIG_GPIO_MXC=y +CONFIG_GPIO_OMAP=y +CONFIG_GPIO_PALMAS=y +CONFIG_GPIO_PCA953X=y +CONFIG_GPIO_PCA953X_IRQ=y +CONFIG_GPIO_PCF857X=y +CONFIG_GPIO_PL061=y +# CONFIG_GPIO_STMPE is not set +CONFIG_GPIO_SYSCON=y +# CONFIG_GPIO_TPS65218 is not set +CONFIG_GPIO_TPS6586X=y +CONFIG_GPIO_TPS65910=y +CONFIG_GPIO_TWL4030=y +CONFIG_GPIO_XILINX=y +CONFIG_GRACE_PERIOD=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_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARM_ARCH_TIMER=y +CONFIG_HAVE_ARM_SCU=y +CONFIG_HAVE_ARM_SMCCC=y +CONFIG_HAVE_ARM_TWD=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_HAVE_CBPF_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_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_GENERIC_RCU_GUP=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_IMX_SRC=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_KVM_ARCH_TLB_FLUSH_ALL=y +CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y +CONFIG_HAVE_KVM_EVENTFD=y +CONFIG_HAVE_KVM_IRQCHIP=y +CONFIG_HAVE_KVM_IRQFD=y +CONFIG_HAVE_KVM_IRQ_ROUTING=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_RCU_TABLE_FREE=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_HDMI=y +CONFIG_HID=y +CONFIG_HID_GENERIC=y +CONFIG_HIGHMEM=y +CONFIG_HIGHPTE=y +CONFIG_HIX5HD2_GMAC=y +CONFIG_HOTPLUG_CPU=y +# CONFIG_HUGETLBFS is not set +CONFIG_HVC_DRIVER=y +CONFIG_HWMON=y +CONFIG_HW_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_OMAP=y +CONFIG_HW_RANDOM_OMAP3_ROM=y +CONFIG_HZ_FIXED=0 +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_DEMUX_PINCTRL=y +CONFIG_I2C_DESIGNWARE_CORE=y +CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_IMX=y +CONFIG_I2C_MUX=y +CONFIG_I2C_MUX_PCA954x=y +CONFIG_I2C_MUX_PINCTRL=y +CONFIG_I2C_NOMADIK=y +CONFIG_I2C_OMAP=y +CONFIG_I2C_RK3X=y +CONFIG_I2C_SLAVE=y +CONFIG_I2C_SLAVE_EEPROM=y +CONFIG_I2C_XILINX=y +CONFIG_ICPLUS_PHY=y +CONFIG_ICS932S401=y +CONFIG_IGB=y +CONFIG_IGB_HWMON=y +CONFIG_IIO=y +CONFIG_IIO_BUFFER=y +CONFIG_IIO_CONFIGFS=y +CONFIG_IIO_HRTIMER_TRIGGER=y +CONFIG_IIO_KFIFO_BUF=y +CONFIG_IIO_SW_TRIGGER=y +# CONFIG_IIO_TIGHTLOOP_TRIGGER is not set +CONFIG_IIO_TRIGGER=y +CONFIG_IIO_TRIGGERED_BUFFER=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_IMX2_WDT=y +CONFIG_IMX_DMA=y +CONFIG_IMX_SDMA=y +# CONFIG_IMX_WEIM is not set +CONFIG_INET6_XFRM_MODE_BEET=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET_DIAG=y +# CONFIG_INET_DIAG_DESTROY is not set +CONFIG_INET_ESP=y +CONFIG_INET_TCP_DIAG=y +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INPUT=y +# CONFIG_INPUT_AXP20X_PEK is not set +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_JOYDEV=y +CONFIG_INPUT_KEYBOARD=y +CONFIG_INPUT_LEDS=y +CONFIG_INPUT_MATRIXKMAP=y +# CONFIG_INPUT_MAX8997_HAPTIC is not set +CONFIG_INPUT_MOUSE=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_IOMMU_HELPER=y +# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set +# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_IOSCHED_CFQ=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_NAT=y +CONFIG_IP6_NF_TARGET_MASQUERADE=y +# CONFIG_IP6_NF_TARGET_NPT is not set +CONFIG_IPC_NS=y +CONFIG_IPV6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SUBTREES is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_RARP=y +CONFIG_IP_VS=y +# CONFIG_IP_VS_DEBUG is not set +# CONFIG_IP_VS_DH is not set +# CONFIG_IP_VS_FO is not set +# CONFIG_IP_VS_IPV6 is not set +# CONFIG_IP_VS_LBLC is not set +# CONFIG_IP_VS_LBLCR is not set +# CONFIG_IP_VS_LC is not set +# CONFIG_IP_VS_NFCT is not set +# CONFIG_IP_VS_NQ is not set +# CONFIG_IP_VS_OVF is not set +# CONFIG_IP_VS_PROTO_AH is not set +# CONFIG_IP_VS_PROTO_AH_ESP is not set +# CONFIG_IP_VS_PROTO_ESP is not set +# CONFIG_IP_VS_PROTO_SCTP is not set +# CONFIG_IP_VS_PROTO_TCP is not set +# CONFIG_IP_VS_PROTO_UDP is not set +# CONFIG_IP_VS_RR is not set +# CONFIG_IP_VS_SED is not set +# CONFIG_IP_VS_SH is not set +CONFIG_IP_VS_SH_TAB_BITS=8 +CONFIG_IP_VS_TAB_BITS=12 +# CONFIG_IP_VS_WLC is not set +# CONFIG_IP_VS_WRR is not set +CONFIG_IRQCHIP=y +CONFIG_IRQ_CROSSBAR=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_ISDN is not set +CONFIG_ISL29003=y +CONFIG_JBD2=y +# CONFIG_JFFS2_FS is not set +CONFIG_KALLSYMS=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_XZ is not set +CONFIG_KEXEC=y +CONFIG_KEXEC_CORE=y +CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYBOARD_BCM=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_KEYBOARD_IMX is not set +# CONFIG_KEYBOARD_STMPE is not set +CONFIG_KEYS=y +CONFIG_KS8851=y +CONFIG_KVM=y +CONFIG_KVM_ARM_HOST=y +CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y +CONFIG_KVM_MMIO=y +CONFIG_KVM_VFIO=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_LEDS_GPIO=y +# CONFIG_LEDS_MAX8997 is not set +CONFIG_LEDS_PWM=y +CONFIG_LEDS_TRIGGER_BACKLIGHT=y +CONFIG_LEDS_TRIGGER_CAMERA=y +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_ONESHOT=y +CONFIG_LEDS_TRIGGER_TRANSIENT=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LIBFDT=y +CONFIG_LOCALVERSION_AUTO=y +CONFIG_LOCKD=y +CONFIG_LOCKUP_DETECTOR=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_CLUT224=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_MACB=y +CONFIG_MACH_OMAP3517EVM=y +CONFIG_MACH_OMAP3_PANDORA=y +CONFIG_MACH_OMAP_GENERIC=y +CONFIG_MACVLAN=y +CONFIG_MACVTAP=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAILBOX=y +# CONFIG_MAILBOX_TEST is not set +CONFIG_MANDATORY_FILE_LOCKING=y +CONFIG_MARVELL_PHY=y +CONFIG_MCPM=y +CONFIG_MDIO_BITBANG=y +CONFIG_MDIO_BOARDINFO=y +CONFIG_MDIO_BUS_MUX=y +CONFIG_MDIO_BUS_MUX_MMIOREG=y +# CONFIG_MDIO_FSL_BACKPLANE is not set +# CONFIG_MDIO_GPIO is not set +CONFIG_MEMCG=y +# CONFIG_MEMCG_SWAP is not set +CONFIG_MEMORY=y +CONFIG_MEMORY_ISOLATION=y +CONFIG_MFD_ACT8945A=y +CONFIG_MFD_AS3711=y +CONFIG_MFD_AS3722=y +CONFIG_MFD_ATMEL_FLEXCOM=y +CONFIG_MFD_AXP20X=y +CONFIG_MFD_AXP20X_I2C=y +CONFIG_MFD_BCM590XX=y +CONFIG_MFD_CORE=y +CONFIG_MFD_MAX14577=y +CONFIG_MFD_MAX77686=y +CONFIG_MFD_MAX8907=y +CONFIG_MFD_MAX8997=y +CONFIG_MFD_MAX8998=y +CONFIG_MFD_OMAP_USB_HOST=y +CONFIG_MFD_PALMAS=y +CONFIG_MFD_RK808=y +CONFIG_MFD_SEC_CORE=y +CONFIG_MFD_STMPE=y +CONFIG_MFD_SYSCON=y +CONFIG_MFD_TPS65090=y +CONFIG_MFD_TPS65217=y +CONFIG_MFD_TPS65218=y +CONFIG_MFD_TPS6586X=y +CONFIG_MFD_TPS65910=y +# CONFIG_MFD_TWL4030_AUDIO is not set +CONFIG_MFD_VEXPRESS_SYSREG=y +CONFIG_MICREL_PHY=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_MIGHT_HAVE_PCI=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_ARMMMCI=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=16 +CONFIG_MMC_DW=y +CONFIG_MMC_DW_EXYNOS=y +# CONFIG_MMC_DW_K3 is not set +# CONFIG_MMC_DW_PCI is not set +CONFIG_MMC_DW_PLTFM=y +# CONFIG_MMC_MXC is not set +CONFIG_MMC_OMAP=y +CONFIG_MMC_OMAP_HS=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_ESDHC_IMX=y +CONFIG_MMC_SDHCI_IO_ACCESSORS=y +CONFIG_MMC_SDHCI_OF_ARASAN=y +CONFIG_MMC_SDHCI_OF_AT91=y +CONFIG_MMC_SDHCI_OF_ESDHC=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +# CONFIG_MMC_TIFM_SD is not set +CONFIG_MMU_NOTIFIER=y +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_MODULES_USE_ELF_REL=y +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_CYAPA is not set +CONFIG_MOUSE_ELAN_I2C=y +CONFIG_MOUSE_ELAN_I2C_I2C=y +# CONFIG_MOUSE_ELAN_I2C_SMBUS is not set +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_BYD=y +CONFIG_MOUSE_PS2_CYPRESS=y +CONFIG_MOUSE_PS2_ELANTECH=y +CONFIG_MOUSE_PS2_FOCALTECH=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +CONFIG_MSDOS_FS=y +# CONFIG_MTD_BCM47XXSFLASH is not set +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_GEOMETRY=y +CONFIG_MTD_CFI_STAA=y +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_DATAFLASH=y +# CONFIG_MTD_DATAFLASH_OTP is not set +# CONFIG_MTD_DATAFLASH_WRITE_VERIFY is not set +CONFIG_MTD_M25P80=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_BRCMNAND=y +CONFIG_MTD_NAND_DENALI=y +CONFIG_MTD_NAND_DENALI_DT=y +CONFIG_MTD_NAND_ECC=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y +CONFIG_MTD_SST25L=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BEB_LIMIT=20 +# CONFIG_MTD_UBI_BLOCK is not set +# CONFIG_MTD_UBI_FASTMAP is not set +# CONFIG_MTD_UBI_GLUEBI is not set +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MULTI_IRQ_HANDLER=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_MVMDIO=y +CONFIG_MX3_IPU=y +CONFIG_MX3_IPU_IRQS=4 +CONFIG_NAMESPACES=y +CONFIG_NATIONAL_PHY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEON=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_XTABLES=y +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_IPVS=y +CONFIG_NETFILTER_XT_NAT=y +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=y +CONFIG_NETLINK_DIAG=y +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_INGRESS=y +CONFIG_NET_IP_TUNNEL=y +CONFIG_NET_KEY=y +CONFIG_NET_NS=y +CONFIG_NET_PACKET_ENGINE=y +CONFIG_NET_PTP_CLASSIFY=y +CONFIG_NET_SWITCHDEV=y +# CONFIG_NET_VENDOR_AURORA is not set +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_FS=y +CONFIG_NFS_USE_KERNEL_DNS=y +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_V2=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_RTCACHE is not set +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_DEFRAG_IPV6=y +# CONFIG_NF_LOG_IPV6 is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_IPV4=y +CONFIG_NF_NAT_IPV6=y +CONFIG_NF_NAT_MASQUERADE_IPV4=y +CONFIG_NF_NAT_MASQUERADE_IPV6=y +CONFIG_NF_NAT_NEEDED=y +# CONFIG_NF_NAT_REDIRECT is not set +CONFIG_NLS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_NO_BOOTMEM=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NR_CPUS=16 +CONFIG_NTFS_FS=y +CONFIG_NVMEM=y +CONFIG_NVME_CORE=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_ADDRESS_PCI=y +CONFIG_OF_DYNAMIC=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_MDIO=y +CONFIG_OF_NET=y +CONFIG_OF_PCI=y +CONFIG_OF_PCI_IRQ=y +CONFIG_OF_RESERVED_MEM=y +CONFIG_OID_REGISTRY=y +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +# CONFIG_OMAP2PLUS_MBOX is not set +# CONFIG_OMAP3_L2_AUX_SECURE_SAVE_RESTORE is not set +# CONFIG_OMAP3_SDRC_AC_TIMING is not set +# CONFIG_OMAP5_ERRATA_801819 is not set +CONFIG_OMAP_32K_TIMER=y +CONFIG_OMAP_CONTROL_PHY=y +CONFIG_OMAP_DM_TIMER=y +CONFIG_OMAP_GPMC=y +# CONFIG_OMAP_GPMC_DEBUG is not set +CONFIG_OMAP_INTERCONNECT=y +CONFIG_OMAP_INTERCONNECT_BARRIER=y +# CONFIG_OMAP_IOMMU is not set +CONFIG_OMAP_IRQCHIP=y +CONFIG_OMAP_MUX=y +# CONFIG_OMAP_MUX_DEBUG is not set +CONFIG_OMAP_MUX_WARNINGS=y +CONFIG_OMAP_OCP2SCP=y +CONFIG_OMAP_PACKAGE_CBB=y +CONFIG_OMAP_PM_NOOP=y +# CONFIG_OMAP_RESET_CLOCKS is not set +CONFIG_OMAP_USB2=y +# CONFIG_OMAP_WATCHDOG is not set +CONFIG_OUTER_CACHE=y +CONFIG_OUTER_CACHE_SYNC=y +CONFIG_PACKET_DIAG=y +CONFIG_PAGE_COUNTER=y +CONFIG_PAGE_OFFSET=0xC0000000 +# CONFIG_PALMAS_GPADC is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_PARTITION_PERCPU=y +CONFIG_PCI=y +CONFIG_PCIEAER=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEBUG is not set +CONFIG_PCIEASPM_DEFAULT=y +# CONFIG_PCIEASPM_PERFORMANCE is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +CONFIG_PCIEPORTBUS=y +CONFIG_PCIE_DW=y +CONFIG_PCIE_PME=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +# CONFIG_PCI_DRA7XX is not set +CONFIG_PCI_ECAM=y +CONFIG_PCI_HOST_COMMON=y +CONFIG_PCI_HOST_GENERIC=y +CONFIG_PCI_LAYERSCAPE=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=3 +CONFIG_PHYLIB=y +CONFIG_PHYS_ADDR_T_64BIT=y +# CONFIG_PHY_DM816X_USB is not set +CONFIG_PID_NS=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_AS3722=y +CONFIG_PINCTRL_PALMAS=y +CONFIG_PL310_ERRATA_588369=y +CONFIG_PL310_ERRATA_727915=y +CONFIG_PL310_ERRATA_753970=y +CONFIG_PL310_ERRATA_769419=y +CONFIG_PL320_MBOX=y +CONFIG_PL330_DMA=y +# CONFIG_PLAT_VERSATILE_CLCD is not set +CONFIG_PM=y +CONFIG_PM_CLK=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_DEVFREQ=y +# CONFIG_PM_DEVFREQ_EVENT is not set +CONFIG_PM_OPP=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +CONFIG_POWER_AVS=y +# CONFIG_POWER_AVS_OMAP is not set +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_AS3722=y +CONFIG_POWER_RESET_BRCMKONA=y +CONFIG_POWER_RESET_BRCMSTB=y +CONFIG_POWER_RESET_GPIO=y +CONFIG_POWER_RESET_GPIO_RESTART=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_POWER_RESET_SYSCON_POWEROFF=y +CONFIG_POWER_RESET_VEXPRESS=y +CONFIG_POWER_SUPPLY=y +CONFIG_PPS=y +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_PRINTK_TIME=y +# CONFIG_PROBE_EVENTS is not set +CONFIG_PROC_CHILDREN=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PROC_PID_CPUSET=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +# CONFIG_PSTORE_LZ4_COMPRESS is not set +# CONFIG_PSTORE_LZO_COMPRESS is not set +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +CONFIG_PSTORE_ZLIB_COMPRESS=y +CONFIG_PTP_1588_CLOCK=y +# CONFIG_PTP_1588_CLOCK_DPAA is not set +CONFIG_PTP_1588_CLOCK_GIANFAR=y +CONFIG_PWM=y +# CONFIG_PWM_IMX is not set +# CONFIG_PWM_OMAP_DMTIMER is not set +# CONFIG_PWM_STMPE is not set +CONFIG_PWM_SYSFS=y +# CONFIG_PWM_TIECAP is not set +# CONFIG_PWM_TIEHRPWM is not set +# CONFIG_PWM_TWL is not set +# CONFIG_PWM_TWL_LED is not set +CONFIG_QMAN_CEETM_UPDATE_PERIOD=1000 +CONFIG_QORIQ_CPUFREQ=y +# CONFIG_QUICC_ENGINE is not set +CONFIG_R8169=y +CONFIG_RAS=y +CONFIG_RATIONAL=y +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +# CONFIG_RCU_EXPERT is not set +CONFIG_RCU_STALL_COMMON=y +CONFIG_RD_BZIP2=y +CONFIG_RD_GZIP=y +CONFIG_RD_LZ4=y +CONFIG_RD_LZMA=y +CONFIG_RD_LZO=y +CONFIG_RD_XZ=y +CONFIG_REALTEK_PHY=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_IRQ=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGMAP_SPI=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_ACT8865=y +CONFIG_REGULATOR_ACT8945A=y +CONFIG_REGULATOR_ANATOP=y +CONFIG_REGULATOR_AS3711=y +CONFIG_REGULATOR_AS3722=y +CONFIG_REGULATOR_AXP20X=y +CONFIG_REGULATOR_BCM590XX=y +CONFIG_REGULATOR_DA9210=y +CONFIG_REGULATOR_FAN53555=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_LP872X=y +# CONFIG_REGULATOR_MAX14577 is not set +CONFIG_REGULATOR_MAX77686=y +# CONFIG_REGULATOR_MAX77802 is not set +CONFIG_REGULATOR_MAX8907=y +CONFIG_REGULATOR_MAX8973=y +# CONFIG_REGULATOR_MAX8997 is not set +# CONFIG_REGULATOR_MAX8998 is not set +CONFIG_REGULATOR_PALMAS=y +CONFIG_REGULATOR_PBIAS=y +CONFIG_REGULATOR_PWM=y +# CONFIG_REGULATOR_QCOM_SPMI is not set +CONFIG_REGULATOR_RK808=y +# CONFIG_REGULATOR_S2MPA01 is not set +CONFIG_REGULATOR_S2MPS11=y +CONFIG_REGULATOR_S5M8767=y +CONFIG_REGULATOR_TI_ABB=y +CONFIG_REGULATOR_TPS51632=y +CONFIG_REGULATOR_TPS62360=y +CONFIG_REGULATOR_TPS65090=y +CONFIG_REGULATOR_TPS65217=y +CONFIG_REGULATOR_TPS65218=y +CONFIG_REGULATOR_TPS6586X=y +CONFIG_REGULATOR_TPS65910=y +CONFIG_REGULATOR_TWL4030=y +CONFIG_REGULATOR_VEXPRESS=y +CONFIG_RESET_CONTROLLER=y +CONFIG_RFS_ACCEL=y +CONFIG_ROOT_NFS=y +CONFIG_RPS=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_AS3722=y +# CONFIG_RTC_DRV_CMOS is not set +CONFIG_RTC_DRV_DS1307=y +CONFIG_RTC_DRV_DS1307_HWMON=y +CONFIG_RTC_DRV_DS3232=y +# CONFIG_RTC_DRV_EFI is not set +CONFIG_RTC_DRV_EM3027=y +# CONFIG_RTC_DRV_IMXDI is not set +CONFIG_RTC_DRV_MAX77686=y +CONFIG_RTC_DRV_MAX8907=y +# CONFIG_RTC_DRV_MAX8997 is not set +# CONFIG_RTC_DRV_MAX8998 is not set +# CONFIG_RTC_DRV_MXC is not set +CONFIG_RTC_DRV_PALMAS=y +CONFIG_RTC_DRV_PCF2127=y +CONFIG_RTC_DRV_PCF85263=y +CONFIG_RTC_DRV_PL031=y +# CONFIG_RTC_DRV_RK808 is not set +# CONFIG_RTC_DRV_S5M is not set +CONFIG_RTC_DRV_TPS6586X=y +CONFIG_RTC_DRV_TPS65910=y +CONFIG_RTC_DRV_TWL4030=y +CONFIG_RTC_I2C_AND_SPI=y +# CONFIG_RT_GROUP_SCHED is not set +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_SATA_AHCI=y +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_SATA_MV=y +CONFIG_SATA_PMP=y +CONFIG_SATA_SIL24=y +CONFIG_SCHED_DEBUG=y +# CONFIG_SCHED_INFO is not set +CONFIG_SCSI=y +CONFIG_SECCOMP=y +CONFIG_SECCOMP_FILTER=y +CONFIG_SENSORS_IIO_HWMON=y +CONFIG_SENSORS_ISL29018=y +CONFIG_SENSORS_ISL29028=y +CONFIG_SENSORS_LM90=y +CONFIG_SENSORS_LM95245=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_8250_EM=y +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_OMAP is not set +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +# CONFIG_SERIAL_AMBA_PL010 is not set +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_SERIAL_BCM63XX=y +CONFIG_SERIAL_BCM63XX_CONSOLE=y +CONFIG_SERIAL_CONEXANT_DIGICOLOR=y +CONFIG_SERIAL_CONEXANT_DIGICOLOR_CONSOLE=y +CONFIG_SERIAL_FSL_LPUART=y +CONFIG_SERIAL_FSL_LPUART_CONSOLE=y +CONFIG_SERIAL_IMX=y +CONFIG_SERIAL_IMX_CONSOLE=y +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_OMAP=y +CONFIG_SERIAL_OMAP_CONSOLE=y +CONFIG_SERIAL_ST_ASC=y +CONFIG_SERIAL_ST_ASC_CONSOLE=y +CONFIG_SERIAL_XILINX_PS_UART=y +CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y +CONFIG_SERIO=y +CONFIG_SERIO_AMBAKMI=y +CONFIG_SERIO_LIBPS2=y +CONFIG_SERIO_SERPORT=y +CONFIG_SG_POOL=y +CONFIG_SG_SPLIT=y +CONFIG_SLUB_DEBUG=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +CONFIG_SMSC911X=y +# CONFIG_SMSC911X_ARCH_HOOKS is not set +CONFIG_SMSC_PHY=y +CONFIG_SOCK_DIAG=y +CONFIG_SOC_AM33XX=y +CONFIG_SOC_AM43XX=y +CONFIG_SOC_BRCMSTB=y +CONFIG_SOC_BUS=y +CONFIG_SOC_DRA7XX=y +CONFIG_SOC_HAS_OMAP2_SDRC=y +CONFIG_SOC_HAS_REALTIME_COUNTER=y +# CONFIG_SOC_IMX50 is not set +# CONFIG_SOC_IMX51 is not set +# CONFIG_SOC_IMX53 is not set +# CONFIG_SOC_IMX6Q is not set +# CONFIG_SOC_IMX6SL is not set +# CONFIG_SOC_IMX6SX is not set +# CONFIG_SOC_IMX6UL is not set +# CONFIG_SOC_IMX7D is not set +# CONFIG_SOC_LS1021A is not set +CONFIG_SOC_OMAP3430=y +CONFIG_SOC_OMAP5=y +CONFIG_SOC_TI81XX=y +# CONFIG_SOC_VF610 is not set +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +CONFIG_SPI_BITBANG=y +CONFIG_SPI_CADENCE=y +# CONFIG_SPI_CADENCE_QUADSPI is not set +CONFIG_SPI_FSL_QUADSPI=y +# CONFIG_SPI_IMX is not set +CONFIG_SPI_MASTER=y +CONFIG_SPI_OMAP24XX=y +CONFIG_SPI_PL022=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPI_XILINX=y +CONFIG_SPMI=y +# CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU is not set +CONFIG_SQUASHFS_DECOMP_SINGLE=y +CONFIG_SQUASHFS_FILE_CACHE=y +# CONFIG_SQUASHFS_FILE_DIRECT is not set +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_ZLIB=y +CONFIG_SRAM=y +CONFIG_SRCU=y +CONFIG_STAGING_BOARD=y +CONFIG_STMMAC_ETH=y +CONFIG_STMMAC_PLATFORM=y +CONFIG_STMPE_I2C=y +# CONFIG_STMPE_SPI is not set +CONFIG_STMP_DEVICE=y +# CONFIG_STRIP_ASM_SYMS is not set +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_SWIOTLB=y +CONFIG_SWPHY=y +CONFIG_SWP_EMULATE=y +# CONFIG_SW_SYNC is not set +CONFIG_SYNC_FILE=y +# CONFIG_SYN_COOKIES is not set +CONFIG_SYSFS_SYSCALL=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_SYS_SUPPORTS_HUGETLBFS=y +# CONFIG_TCP_CONG_ADVANCED is not set +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_TI_CPPI41 is not set +CONFIG_TI_CPSW=y +CONFIG_TI_CPSW_ALE=y +CONFIG_TI_CPSW_PHY_SEL=y +CONFIG_TI_DAVINCI_CPDMA=y +# CONFIG_TI_DAVINCI_EMAC is not set +CONFIG_TI_DAVINCI_MDIO=y +CONFIG_TI_DMA_CROSSBAR=y +CONFIG_TI_EDMA=y +# CONFIG_TI_EMIF is not set +CONFIG_TI_PIPE3=y +# CONFIG_TI_SOC_THERMAL is not set +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TOUCHSCREEN_PROPERTIES=y +CONFIG_TOUCHSCREEN_STMPE=y +CONFIG_TRACING_EVENTS_GPIO=y +CONFIG_TREE_RCU=y +CONFIG_TUN=y +CONFIG_TWL4030_CORE=y +CONFIG_TWL4030_POWER=y +# CONFIG_TWL4030_WATCHDOG is not set +CONFIG_UBIFS_FS=y +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +CONFIG_UCS2_STRING=y +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_UNIX_DIAG=y +CONFIG_USB=y +# CONFIG_USB_ALI_M5632 is not set +# CONFIG_USB_AN2720 is not set +CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_CHIPIDEA_OF=y +CONFIG_USB_CHIPIDEA_UDC=y +CONFIG_USB_COMMON=y +CONFIG_USB_DWC2=y +CONFIG_USB_DWC2_DUAL_ROLE=y +# CONFIG_USB_DWC2_PCI is not set +# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_DUAL_ROLE=y +# CONFIG_USB_DWC3_GADGET is not set +# CONFIG_USB_DWC3_HOST is not set +CONFIG_USB_DWC3_OF_SIMPLE=y +CONFIG_USB_DWC3_OMAP=y +CONFIG_USB_DWC3_PCI=y +# CONFIG_USB_EHCI_FSL is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +# CONFIG_USB_EHCI_MXC is not set +CONFIG_USB_EHCI_PCI=y +CONFIG_USB_FSL_USB2=y +CONFIG_USB_GADGET=y +CONFIG_USB_GPIO_VBUS=y +# CONFIG_USB_HCD_BCMA is not set +CONFIG_USB_HID=y +# CONFIG_USB_IMX21_HCD is not set +CONFIG_USB_ISP1301=y +CONFIG_USB_ISP1760=y +CONFIG_USB_ISP1760_DUAL_ROLE=y +# CONFIG_USB_ISP1760_GADGET_ROLE is not set +CONFIG_USB_ISP1760_HCD=y +# CONFIG_USB_ISP1760_HOST_ROLE is not set +CONFIG_USB_ISP1761_UDC=y +CONFIG_USB_MXS_PHY=y +CONFIG_USB_NET_AX88179_178A=y +CONFIG_USB_NET_AX8817X=y +CONFIG_USB_NET_CDCETHER=y +CONFIG_USB_NET_CDC_NCM=y +CONFIG_USB_NET_CDC_SUBSET=y +CONFIG_USB_NET_CDC_SUBSET_ENABLE=y +CONFIG_USB_NET_DRIVERS=y +CONFIG_USB_NET_NET1080=y +CONFIG_USB_NET_SMSC75XX=y +CONFIG_USB_NET_SMSC95XX=y +CONFIG_USB_NET_ZAURUS=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_OMAP3=y +CONFIG_USB_OHCI_HCD_PCI=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_PEGASUS=y +CONFIG_USB_PHY=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SUPPORT=y +# CONFIG_USB_UHCI_HCD is not set +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT=y +CONFIG_USB_USBNET=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PCI=y +CONFIG_USB_XHCI_PLATFORM=y +# CONFIG_USERIO is not set +CONFIG_USER_NS=y +CONFIG_USE_OF=y +CONFIG_UTS_NS=y +CONFIG_VDSO=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_VETH=y +CONFIG_VEXPRESS_CONFIG=y +CONFIG_VEXPRESS_SYSCFG=y +CONFIG_VFAT_FS=y +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +CONFIG_VHOST=y +CONFIG_VHOST_NET=y +CONFIG_VIDEOMODE_HELPERS=y +CONFIG_VIRTIO=y +CONFIG_VIRTIO_BLK=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_VIRTIO_MMIO=y +# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set +CONFIG_VIRTIO_NET=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_PCI_LEGACY=y +CONFIG_VIRTUALIZATION=y +CONFIG_VITESSE_PHY=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WKUP_M3_RPROC is not set +CONFIG_WLAN_VENDOR_ADMTEK=y +CONFIG_WLAN_VENDOR_ATH=y +CONFIG_WLAN_VENDOR_ATMEL=y +CONFIG_WLAN_VENDOR_BROADCOM=y +CONFIG_WLAN_VENDOR_CISCO=y +CONFIG_WLAN_VENDOR_INTEL=y +CONFIG_WLAN_VENDOR_INTERSIL=y +CONFIG_WLAN_VENDOR_MARVELL=y +CONFIG_WLAN_VENDOR_MEDIATEK=y +CONFIG_WLAN_VENDOR_RALINK=y +CONFIG_WLAN_VENDOR_REALTEK=y +CONFIG_WLAN_VENDOR_RSI=y +CONFIG_WLAN_VENDOR_ST=y +CONFIG_WLAN_VENDOR_TI=y +CONFIG_WLAN_VENDOR_ZYDAS=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +CONFIG_XFRM_ALGO=y +CONFIG_XFRM_USER=y +CONFIG_XILINX_WATCHDOG=y +CONFIG_XPS=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_ARMTHUMB=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_XZ_DEC_IA64=y +CONFIG_XZ_DEC_POWERPC=y +CONFIG_XZ_DEC_SPARC=y +CONFIG_XZ_DEC_X86=y +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZLIB_DEFLATE=y +CONFIG_ZLIB_INFLATE=y diff --git a/target/linux/layerscape/armv8_64b/config-4.9 b/target/linux/layerscape/armv8_64b/config-4.9 new file mode 100644 index 0000000000..8fafc1cbf5 --- /dev/null +++ b/target/linux/layerscape/armv8_64b/config-4.9 @@ -0,0 +1,1371 @@ +CONFIG_64BIT=y +CONFIG_ACPI=y +CONFIG_ACPI_BUTTON=y +CONFIG_ACPI_CCA_REQUIRED=y +CONFIG_ACPI_CONTAINER=y +# CONFIG_ACPI_CPPC_CPUFREQ is not set +# CONFIG_ACPI_CUSTOM_DSDT is not set +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_DEBUGGER is not set +# CONFIG_ACPI_DOCK is not set +# CONFIG_ACPI_EC_DEBUGFS is not set +CONFIG_ACPI_FAN=y +CONFIG_ACPI_GENERIC_GSI=y +CONFIG_ACPI_HOTPLUG_CPU=y +CONFIG_ACPI_I2C_OPREGION=y +CONFIG_ACPI_IORT=y +CONFIG_ACPI_MCFG=y +CONFIG_ACPI_NUMA=y +# CONFIG_ACPI_PCI_SLOT is not set +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_REDUCED_HARDWARE_ONLY=y +CONFIG_ACPI_SPCR_TABLE=y +CONFIG_ACPI_TABLE_UPGRADE=y +CONFIG_ACPI_THERMAL=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_AHCI_CEVA=y +CONFIG_AHCI_QORIQ=y +CONFIG_AHCI_XGENE=y +CONFIG_AMD_XGBE=y +CONFIG_AQUANTIA_PHY=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +CONFIG_ARCH_HAS_KCOV=y +CONFIG_ARCH_HAS_SG_CHAIN=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_ARCH_HIBERNATION_HEADER=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_LAYERSCAPE=y +CONFIG_ARCH_MMAP_RND_BITS=18 +CONFIG_ARCH_MMAP_RND_BITS_MAX=33 +CONFIG_ARCH_MMAP_RND_BITS_MIN=18 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=11 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11 +CONFIG_ARCH_PHYS_ADDR_T_64BIT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_FRAME_POINTERS=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_ARM64=y +# CONFIG_ARM64_16K_PAGES is not set +CONFIG_ARM64_4K_PAGES=y +# CONFIG_ARM64_64K_PAGES is not set +# CONFIG_ARM64_ACPI_PARKING_PROTOCOL is not set +CONFIG_ARM64_CONT_SHIFT=4 +CONFIG_ARM64_CRYPTO=y +CONFIG_ARM64_ERRATUM_819472=y +CONFIG_ARM64_ERRATUM_824069=y +CONFIG_ARM64_ERRATUM_826319=y +CONFIG_ARM64_ERRATUM_827319=y +CONFIG_ARM64_ERRATUM_832075=y +CONFIG_ARM64_ERRATUM_834220=y +CONFIG_ARM64_ERRATUM_843419=y +CONFIG_ARM64_ERRATUM_845719=y +CONFIG_ARM64_HW_AFDBM=y +# CONFIG_ARM64_LSE_ATOMICS is not set +CONFIG_ARM64_MODULE_CMODEL_LARGE=y +CONFIG_ARM64_PAGE_SHIFT=12 +CONFIG_ARM64_PAN=y +# CONFIG_ARM64_PTDUMP is not set +# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set +CONFIG_ARM64_UAO=y +CONFIG_ARM64_VA_BITS=48 +# CONFIG_ARM64_VA_BITS_39 is not set +CONFIG_ARM64_VA_BITS_48=y +CONFIG_ARM64_VHE=y +# CONFIG_ARMV8_DEPRECATED is not set +CONFIG_ARM_AMBA=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_BIG_LITTLE_CPUFREQ=y +CONFIG_ARM_CPUIDLE=y +# CONFIG_ARM_DT_BL_CPUFREQ is not set +CONFIG_ARM_GIC=y +CONFIG_ARM_GIC_V2M=y +CONFIG_ARM_GIC_V3=y +CONFIG_ARM_GIC_V3_ITS=y +# CONFIG_ARM_PL172_MPMC is not set +CONFIG_ARM_PMU=y +CONFIG_ARM_PSCI_FW=y +# CONFIG_ARM_SBSA_WATCHDOG is not set +CONFIG_ARM_SMMU=y +CONFIG_ARM_SMMU_V3=y +CONFIG_ARM_SP805_WATCHDOG=y +CONFIG_ARM_TIMER_SP804=y +CONFIG_ASN1=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH=y +CONFIG_ATA=y +CONFIG_ATA_ACPI=y +CONFIG_ATA_VERBOSE_ERROR=y +# CONFIG_ATH5K_PCI is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y +CONFIG_AUDIT_COMPAT_GENERIC=y +CONFIG_AUDIT_GENERIC=y +CONFIG_AUDIT_TREE=y +CONFIG_AUDIT_WATCH=y +CONFIG_AUTOFS4_FS=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_BACKLIGHT_PWM is not set +CONFIG_BALLOON_COMPACTION=y +CONFIG_BATTERY_BQ27XXX=y +CONFIG_BATTERY_BQ27XXX_I2C=y +CONFIG_BLK_CGROUP=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NVME=y +# CONFIG_BLK_DEV_NVME_SCSI is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=262144 +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_THROTTLING=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BLOCK_COMPAT=y +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 +CONFIG_BOUNCE=y +CONFIG_BPF_JIT=y +# CONFIG_BPF_SYSCALL is not set +CONFIG_BRIDGE_EBT_DNAT=y +CONFIG_BRIDGE_EBT_SNAT=y +CONFIG_BRIDGE_EBT_T_NAT=y +CONFIG_BRIDGE_NETFILTER=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_BTRFS_FS=y +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_BUILD_BIN2C=y +CONFIG_CAVIUM_ERRATUM_22375=y +CONFIG_CAVIUM_ERRATUM_23144=y +CONFIG_CAVIUM_ERRATUM_23154=y +CONFIG_CAVIUM_ERRATUM_27456=y +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_CEPH_LIB=y +# CONFIG_CEPH_LIB_PRETTYDEBUG is not set +# CONFIG_CEPH_LIB_USE_DNS_RESOLVER is not set +CONFIG_CFQ_GROUP_IOSCHED=y +# CONFIG_CFS_BANDWIDTH is not set +CONFIG_CGROUPS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_DEVICE=y +# CONFIG_CGROUP_FREEZER is not set +CONFIG_CGROUP_HUGETLB=y +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUP_WRITEBACK=y +CONFIG_CHECKPOINT_RESTORE=y +CONFIG_CHROME_PLATFORMS=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_CLKSRC_ACPI=y +CONFIG_CLKSRC_MMIO=y +CONFIG_CLKSRC_OF=y +CONFIG_CLKSRC_PROBE=y +CONFIG_CLKSRC_VERSATILE=y +CONFIG_CLK_QORIQ=y +CONFIG_CLK_SP810=y +CONFIG_CLK_VEXPRESS_OSC=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CLZ_TAB=y +CONFIG_CMA=y +CONFIG_CMA_ALIGNMENT=8 +CONFIG_CMA_AREAS=7 +# CONFIG_CMA_DEBUG is not set +# CONFIG_CMA_DEBUGFS is not set +CONFIG_CMA_SIZE_MBYTES=16 +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_CS2000_CP=y +# CONFIG_COMMON_CLK_MAX77686 is not set +CONFIG_COMMON_CLK_PWM=y +CONFIG_COMMON_CLK_RK808=y +CONFIG_COMMON_CLK_S2MPS11=y +CONFIG_COMMON_CLK_VERSATILE=y +CONFIG_COMMON_CLK_XGENE=y +CONFIG_COMPACTION=y +CONFIG_COMPAT=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_COMPAT_NETLINK_MESSAGES=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_CONFIGFS_FS=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_COREDUMP=y +# CONFIG_CORTINA_PHY is not set +CONFIG_CPUFREQ_DT=y +CONFIG_CPUFREQ_DT_PLATDEV=y +CONFIG_CPUSETS=y +# CONFIG_CPU_BIG_ENDIAN is not set +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +CONFIG_CPU_IDLE=y +# CONFIG_CPU_IDLE_GOV_LADDER is not set +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +CONFIG_CPU_THERMAL=y +CONFIG_CRC16=y +# CONFIG_CRC32_SARWATE is not set +CONFIG_CRC32_SLICEBY8=y +CONFIG_CRC7=y +CONFIG_CRC_ITU_T=y +CONFIG_CRC_T10DIF=y +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_CROS_EC_CHARDEV is not set +CONFIG_CROS_EC_PROTO=y +# CONFIG_CROS_KBD_LED_BACKLIGHT is not set +CONFIG_CRYPTO_ABLK_HELPER=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_AES_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +# CONFIG_CRYPTO_AES_ARM64_NEON_BLK is not set +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_ANSI_CPRNG=y +# CONFIG_CRYPTO_ARC4 is not set +CONFIG_CRYPTO_AUTHENC=y +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32_ARM64 is not set +CONFIG_CRYPTO_CRCT10DIF=y +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_DES=y +CONFIG_CRYPTO_DEV_FSL_CAAM=y +CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API=y +CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON=y +CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API=y +CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC=y +CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI=y +# CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG is not set +# CONFIG_CRYPTO_DEV_FSL_CAAM_INTC is not set +CONFIG_CRYPTO_DEV_FSL_CAAM_JR=y +CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API=y +CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE=9 +CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API=y +# CONFIG_CRYPTO_DEV_FSL_DPAA2_CAAM is not set +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_ECHAINIV=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_RSA=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_TLS is not set +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_DEBUG_ALIGN_RODATA is not set +# CONFIG_DEBUG_BLK_CGROUP is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO_REDUCED is not set +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_DEBUG_RODATA=y +CONFIG_DEBUG_SET_MODULE_RONX=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_LZO=y +CONFIG_DECOMPRESS_XZ=y +CONFIG_DEFAULT_CFQ=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +CONFIG_DEFAULT_IOSCHED="cfq" +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEVKMEM=y +CONFIG_DEVMEM=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_DEV_DAX is not set +CONFIG_DMADEVICES=y +CONFIG_DMATEST=y +CONFIG_DMA_ACPI=y +CONFIG_DMA_CMA=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_ENGINE_RAID=y +CONFIG_DMA_OF=y +CONFIG_DMA_SHARED_BUFFER=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DMI=y +CONFIG_DMIID=y +# CONFIG_DMI_SYSFS is not set +CONFIG_DNOTIFY=y +CONFIG_DNS_RESOLVER=y +CONFIG_DST_CACHE=y +CONFIG_DTC=y +CONFIG_DT_IDLE_STATES=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_E1000=y +CONFIG_E1000E=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EEPROM_AT24=y +CONFIG_EFI=y +CONFIG_EFIVAR_FS=y +CONFIG_EFI_ARMSTUB=y +# CONFIG_EFI_CAPSULE_LOADER is not set +CONFIG_EFI_ESRT=y +CONFIG_EFI_PARAMS_FROM_FDT=y +CONFIG_EFI_RUNTIME_WRAPPERS=y +CONFIG_EFI_STUB=y +# CONFIG_EFI_TEST is not set +# CONFIG_EFI_VARS is not set +CONFIG_ELF_CORE=y +# CONFIG_EMBEDDED is not set +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_EVM is not set +CONFIG_EXPORTFS=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_POSIX_ACL=y +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_POSIX_ACL=y +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXTCON=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_FANOTIFY=y +CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y +CONFIG_FAT_FS=y +CONFIG_FB=y +CONFIG_FB_ARMCLCD=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_CMDLINE=y +CONFIG_FB_DEFERRED_IO=y +# CONFIG_FB_EFI is not set +CONFIG_FB_MODE_HELPERS=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_FOPS=y +CONFIG_FB_SYS_IMAGEBLIT=y +CONFIG_FHANDLE=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FMAN_ARM=y +# CONFIG_FMAN_MIB_CNT_OVF_IRQ_EN is not set +# CONFIG_FMAN_P1023 is not set +# CONFIG_FMAN_P3040_P4080_P5020 is not set +# CONFIG_FMAN_PFC is not set +# CONFIG_FMAN_V3H is not set +# CONFIG_FMAN_V3L is not set +# CONFIG_FONTS is not set +CONFIG_FONT_8x16=y +CONFIG_FONT_8x8=y +CONFIG_FONT_SUPPORT=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +CONFIG_FRAME_POINTER=y +CONFIG_FRAME_WARN=2048 +CONFIG_FREEZER=y +CONFIG_FSL_BMAN_CONFIG=y +CONFIG_FSL_BMAN_DEBUGFS=y +# CONFIG_FSL_BMAN_TEST is not set +CONFIG_FSL_DPAA2=y +CONFIG_FSL_DPAA2_ETH=y +CONFIG_FSL_DPAA2_ETHSW=y +# CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE is not set +CONFIG_FSL_DPAA2_EVB=y +CONFIG_FSL_DPAA2_MAC=y +# CONFIG_FSL_DPAA2_MAC_NETDEVS is not set +# CONFIG_FSL_DPAA2_QDMA is not set +# CONFIG_FSL_DPAA_1588 is not set +CONFIG_FSL_DPAA_ADVANCED_DRIVERS=y +# CONFIG_FSL_DPAA_CEETM is not set +CONFIG_FSL_DPAA_CS_THRESHOLD_10G=0x10000000 +CONFIG_FSL_DPAA_CS_THRESHOLD_1G=0x06000000 +# CONFIG_FSL_DPAA_DBG_LOOP is not set +# CONFIG_FSL_DPAA_ETH_DEBUG is not set +CONFIG_FSL_DPAA_ETH_DEBUGFS=y +# CONFIG_FSL_DPAA_ETH_JUMBO_FRAME is not set +CONFIG_FSL_DPAA_ETH_MAX_BUF_COUNT=128 +CONFIG_FSL_DPAA_ETH_REFILL_THRESHOLD=80 +CONFIG_FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE=y +# CONFIG_FSL_DPAA_HOOKS is not set +CONFIG_FSL_DPAA_INGRESS_CS_THRESHOLD=0x10000000 +CONFIG_FSL_DPAA_OFFLINE_PORTS=y +# CONFIG_FSL_DPAA_TS is not set +CONFIG_FSL_DPA_CAN_WAIT=y +CONFIG_FSL_DPA_CAN_WAIT_SYNC=y +# CONFIG_FSL_DPA_CHECKING is not set +CONFIG_FSL_DPA_PIRQ_FAST=y +CONFIG_FSL_DPA_PIRQ_SLOW=y +CONFIG_FSL_DPA_PORTAL_SHARE=y +CONFIG_FSL_EDMA=y +CONFIG_FSL_ERRATUM_A008585=y +CONFIG_FSL_FM_MAX_FRAME_SIZE=1522 +CONFIG_FSL_FM_RX_EXTRA_HEADROOM=64 +CONFIG_FSL_GUTS=y +CONFIG_FSL_IFC=y +CONFIG_FSL_LS2_CONSOLE=y +CONFIG_FSL_MC_BUS=y +CONFIG_FSL_MC_DPIO=y +CONFIG_FSL_MC_RESTOOL=y +# CONFIG_FSL_QBMAN_DEBUG is not set +# CONFIG_FSL_QDMA is not set +CONFIG_FSL_QMAN_CI_SCHED_CFG_BMAN_W=2 +CONFIG_FSL_QMAN_CI_SCHED_CFG_RW_W=2 +CONFIG_FSL_QMAN_CI_SCHED_CFG_SRCCIV=4 +CONFIG_FSL_QMAN_CI_SCHED_CFG_SRQ_W=3 +CONFIG_FSL_QMAN_CONFIG=y +CONFIG_FSL_QMAN_DEBUGFS=y +CONFIG_FSL_QMAN_FQD_SZ=10 +CONFIG_FSL_QMAN_FQ_LOOKUP=y +CONFIG_FSL_QMAN_INIT_TIMEOUT=10 +CONFIG_FSL_QMAN_PFDR_SZ=13 +CONFIG_FSL_QMAN_PIRQ_DQRR_ITHRESH=12 +CONFIG_FSL_QMAN_PIRQ_IPERIOD=100 +CONFIG_FSL_QMAN_PIRQ_MR_ITHRESH=4 +CONFIG_FSL_QMAN_POLL_LIMIT=32 +# CONFIG_FSL_QMAN_TEST is not set +CONFIG_FSL_SDK_BMAN=y +CONFIG_FSL_SDK_DPA=y +CONFIG_FSL_SDK_DPAA_ETH=y +CONFIG_FSL_SDK_FMAN=y +# CONFIG_FSL_SDK_FMAN_TEST is not set +CONFIG_FSL_SDK_QMAN=y +CONFIG_FSL_USDPAA=y +CONFIG_FSL_XGMAC_MDIO=y +CONFIG_FS_IOMAP=y +CONFIG_FS_MBCACHE=y +CONFIG_FS_POSIX_ACL=y +CONFIG_FTM_ALARM=y +CONFIG_FUSE_FS=y +# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set +CONFIG_GARP=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CSUM=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IO=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +# CONFIG_GIANFAR is not set +CONFIG_GLOB=y +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_ACPI=y +# CONFIG_GPIO_AMDPT is not set +CONFIG_GPIO_DWAPB=y +CONFIG_GPIO_GENERIC=y +CONFIG_GPIO_GENERIC_PLATFORM=y +CONFIG_GPIO_MAX77620=y +CONFIG_GPIO_MPC8XXX=y +CONFIG_GPIO_PCA953X=y +CONFIG_GPIO_PCA953X_IRQ=y +CONFIG_GPIO_PL061=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_XGENE=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_HUGE_VMAP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARM_SMCCC=y +# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set +CONFIG_HAVE_CC_STACKPROTECTOR=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DEBUG_BUGVERBOSE=y +CONFIG_HAVE_DEBUG_KMEMLEAK=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_EBPF_JIT=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_GENERIC_RCU_GUP=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_KVM_ARCH_TLB_FLUSH_ALL=y +CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y +CONFIG_HAVE_KVM_EVENTFD=y +CONFIG_HAVE_KVM_IRQCHIP=y +CONFIG_HAVE_KVM_IRQFD=y +CONFIG_HAVE_KVM_IRQ_ROUTING=y +CONFIG_HAVE_KVM_MSI=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MEMBLOCK_NODE_MAP=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_HAVE_NET_DSA=y +CONFIG_HAVE_PATA_PLATFORM=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_RCU_TABLE_FREE=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_UID16=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_HID=y +CONFIG_HID_A4TECH=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_EZKEY=y +CONFIG_HID_GENERIC=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HNS=y +CONFIG_HNS_DSAF=y +CONFIG_HNS_ENET=y +CONFIG_HNS_MDIO=y +CONFIG_HOTPLUG_CPU=y +# CONFIG_HPET is not set +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_HVC_DRIVER=y +CONFIG_HVC_IRQ=y +CONFIG_HVC_XEN=y +CONFIG_HVC_XEN_FRONTEND=y +CONFIG_HWMON=y +CONFIG_HW_CONSOLE=y +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_CAVIUM is not set +CONFIG_HZ=250 +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CROS_EC_TUNNEL=y +CONFIG_I2C_DESIGNWARE_CORE=y +CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_IMX=y +CONFIG_I2C_MUX=y +CONFIG_I2C_MUX_PCA954x=y +CONFIG_I2C_RK3X=y +CONFIG_I2C_SLAVE=y +# CONFIG_I2C_SLAVE_EEPROM is not set +CONFIG_IGB=y +CONFIG_IGBVF=y +CONFIG_IGB_HWMON=y +CONFIG_IIO=y +# CONFIG_IIO_BUFFER is not set +# CONFIG_IIO_TRIGGER is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_IMA is not set +CONFIG_IMX2_WDT=y +CONFIG_INET_DIAG=y +# CONFIG_INET_DIAG_DESTROY is not set +CONFIG_INET_ESP=y +CONFIG_INET_TCP_DIAG=y +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INPUT=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYBOARD=y +CONFIG_INPUT_LEDS=y +CONFIG_INPUT_MOUSE=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_XEN_KBDDEV_FRONTEND=y +CONFIG_INTEGRITY=y +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_IOMMU_API=y +CONFIG_IOMMU_DMA=y +CONFIG_IOMMU_HELPER=y +CONFIG_IOMMU_IOVA=y +CONFIG_IOMMU_IO_PGTABLE=y +# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set +CONFIG_IOMMU_IO_PGTABLE_LPAE=y +# CONFIG_IOMMU_IO_PGTABLE_LPAE_SELFTEST is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_IPC_NS=y +CONFIG_IPV6=y +CONFIG_IPV6_SIT=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_RARP is not set +CONFIG_IRQCHIP=y +CONFIG_IRQ_BYPASS_MANAGER=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +# CONFIG_ISDN is not set +CONFIG_JBD2=y +# CONFIG_JFFS2_FS is not set +CONFIG_JUMP_LABEL=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_ALL=y +# CONFIG_KASAN is not set +CONFIG_KEXEC=y +CONFIG_KEXEC_CORE=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_CROS_EC is not set +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYS=y +CONFIG_KSM=y +CONFIG_KVM=y +CONFIG_KVM_ARM_HOST=y +CONFIG_KVM_ARM_PMU=y +CONFIG_KVM_ARM_VGIC_V3_ITS=y +CONFIG_KVM_COMPAT=y +CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y +CONFIG_KVM_MMIO=y +CONFIG_KVM_VFIO=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_PWM=y +CONFIG_LEDS_SYSCON=y +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_TIMER is not set +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=16 +CONFIG_LIBCRC32C=y +CONFIG_LIBFDT=y +# CONFIG_LIQUIDIO is not set +CONFIG_LOCALVERSION_AUTO=y +CONFIG_LOCKUP_DETECTOR=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_CLUT224=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LS_SCFG_MSI=y +CONFIG_LS_SOC_DRIVERS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_MACB=y +CONFIG_MACVLAN=y +CONFIG_MACVTAP=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_MANDATORY_FILE_LOCKING=y +# CONFIG_MAX77620_THERMAL is not set +# CONFIG_MAX77620_WATCHDOG is not set +CONFIG_MDIO_BITBANG=y +CONFIG_MDIO_BOARDINFO=y +CONFIG_MDIO_BUS_MUX=y +CONFIG_MDIO_BUS_MUX_MMIOREG=y +# CONFIG_MDIO_FSL_BACKPLANE is not set +# CONFIG_MDIO_GPIO is not set +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_MEMCG_SWAP_ENABLED=y +CONFIG_MEMORY=y +CONFIG_MEMORY_BALLOON=y +CONFIG_MEMORY_ISOLATION=y +CONFIG_MEMTEST=y +CONFIG_MFD_CORE=y +CONFIG_MFD_CROS_EC=y +CONFIG_MFD_CROS_EC_I2C=y +# CONFIG_MFD_CROS_EC_SPI is not set +CONFIG_MFD_MAX77620=y +CONFIG_MFD_RK808=y +CONFIG_MFD_SEC_CORE=y +CONFIG_MFD_SYSCON=y +CONFIG_MFD_VEXPRESS_SYSREG=y +CONFIG_MICREL_PHY=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_ARMMMCI=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_DW=y +CONFIG_MMC_DW_EXYNOS=y +CONFIG_MMC_DW_K3=y +# CONFIG_MMC_DW_PCI is not set +CONFIG_MMC_DW_PLTFM=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_ACPI=y +CONFIG_MMC_SDHCI_IO_ACCESSORS=y +CONFIG_MMC_SDHCI_OF_ARASAN=y +CONFIG_MMC_SDHCI_OF_ESDHC=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SPI=y +# CONFIG_MMC_TIFM_SD is not set +CONFIG_MMU_NOTIFIER=y +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_CYAPA is not set +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_BYD=y +CONFIG_MOUSE_PS2_CYPRESS=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +CONFIG_MOUSE_PS2_FOCALTECH=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_VSXXXAA is not set +CONFIG_MPILIB=y +CONFIG_MRP=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +# CONFIG_MTD_CFI_GEOMETRY is not set +CONFIG_MTD_CFI_STAA=y +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_DATAFLASH=y +# CONFIG_MTD_DATAFLASH_OTP is not set +# CONFIG_MTD_DATAFLASH_WRITE_VERIFY is not set +CONFIG_MTD_M25P80=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_DENALI=y +CONFIG_MTD_NAND_DENALI_DT=y +CONFIG_MTD_NAND_ECC=y +CONFIG_MTD_NAND_FSL_IFC=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y +CONFIG_MTD_SST25L=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_MV_XOR_V2=y +CONFIG_NAMESPACES=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEED_MULTIPLE_NODES=y +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=y +CONFIG_NETFILTER_XTABLES=y +CONFIG_NETFILTER_XT_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_NAT=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +# CONFIG_NETLABEL is not set +CONFIG_NETLINK_DIAG=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NET_9P=y +# CONFIG_NET_9P_DEBUG is not set +CONFIG_NET_9P_VIRTIO=y +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_INGRESS=y +CONFIG_NET_IP_TUNNEL=y +CONFIG_NET_KEY=y +CONFIG_NET_NS=y +CONFIG_NET_PACKET_ENGINE=y +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NFT_CHAIN_NAT_IPV4 is not set +# CONFIG_NFT_CHAIN_ROUTE_IPV4 is not set +CONFIG_NFT_COMPAT=y +# CONFIG_NFT_COUNTER is not set +CONFIG_NFT_CT=y +# CONFIG_NFT_EXTHDR is not set +# CONFIG_NFT_HASH is not set +# CONFIG_NFT_LIMIT is not set +# CONFIG_NFT_LOG is not set +CONFIG_NFT_MASQ=y +# CONFIG_NFT_MASQ_IPV4 is not set +# CONFIG_NFT_META is not set +CONFIG_NFT_NAT=y +# CONFIG_NFT_NUMGEN is not set +# CONFIG_NFT_QUOTA is not set +# CONFIG_NFT_REDIR is not set +# CONFIG_NFT_REJECT is not set +# CONFIG_NFT_REJECT_IPV4 is not set +# CONFIG_NFT_SET_HASH is not set +# CONFIG_NFT_SET_RBTREE is not set +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_CONNTRACK_MARK=y +# CONFIG_NF_CONNTRACK_RTCACHE is not set +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_DEFRAG_IPV6=y +# CONFIG_NF_LOG_BRIDGE is not set +CONFIG_NF_LOG_COMMON=y +CONFIG_NF_LOG_IPV6=y +CONFIG_NF_NAT=y +CONFIG_NF_NAT_IPV4=y +CONFIG_NF_NAT_IPV6=y +CONFIG_NF_NAT_MASQUERADE_IPV4=y +CONFIG_NF_NAT_MASQUERADE_IPV6=y +CONFIG_NF_NAT_NEEDED=y +# CONFIG_NF_NAT_REDIRECT is not set +CONFIG_NF_REJECT_IPV6=y +CONFIG_NF_TABLES=y +# CONFIG_NF_TABLES_ARP is not set +CONFIG_NF_TABLES_BRIDGE=y +# CONFIG_NF_TABLES_INET is not set +CONFIG_NF_TABLES_IPV4=y +# CONFIG_NF_TABLES_IPV6 is not set +CONFIG_NLS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NODES_SHIFT=2 +CONFIG_NO_BOOTMEM=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NR_CPUS=64 +CONFIG_NUMA=y +CONFIG_NUMA_BALANCING=y +CONFIG_NUMA_BALANCING_DEFAULT_ENABLED=y +CONFIG_NVMEM=y +CONFIG_NVME_CORE=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_ADDRESS_PCI=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IOMMU=y +CONFIG_OF_IRQ=y +CONFIG_OF_MDIO=y +CONFIG_OF_NET=y +CONFIG_OF_NUMA=y +CONFIG_OF_PCI=y +CONFIG_OF_PCI_IRQ=y +CONFIG_OF_RESERVED_MEM=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_PACKET_DIAG=y +CONFIG_PAGE_COUNTER=y +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +CONFIG_PARAVIRT=y +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_PARTITION_PERCPU=y +# CONFIG_PATA_ACPI is not set +CONFIG_PATA_OF_PLATFORM=y +CONFIG_PATA_PLATFORM=y +CONFIG_PCI=y +CONFIG_PCIEAER=y +CONFIG_PCIEASPM=y +# CONFIG_PCIEASPM_DEBUG is not set +CONFIG_PCIEASPM_DEFAULT=y +# CONFIG_PCIEASPM_PERFORMANCE is not set +# CONFIG_PCIEASPM_POWERSAVE is not set +CONFIG_PCIEPORTBUS=y +CONFIG_PCIE_DW=y +CONFIG_PCIE_PME=y +CONFIG_PCI_ATS=y +CONFIG_PCI_BUS_ADDR_T_64BIT=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_ECAM=y +CONFIG_PCI_HISI=y +CONFIG_PCI_HOST_COMMON=y +CONFIG_PCI_HOST_GENERIC=y +# CONFIG_PCI_HOST_THUNDER_ECAM is not set +# CONFIG_PCI_HOST_THUNDER_PEM is not set +CONFIG_PCI_IOV=y +CONFIG_PCI_LABEL=y +CONFIG_PCI_LAYERSCAPE=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PERF_EVENTS=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_PHYLIB=y +CONFIG_PHYS_ADDR_T_64BIT=y +# CONFIG_PHY_EXYNOS4210_USB2 is not set +# CONFIG_PHY_EXYNOS4X12_USB2 is not set +# CONFIG_PHY_EXYNOS5250_USB2 is not set +CONFIG_PHY_SAMSUNG_USB2=y +CONFIG_PHY_XGENE=y +CONFIG_PID_IN_CONTEXTIDR=y +CONFIG_PID_NS=y +CONFIG_PL330_DMA=y +CONFIG_PM=y +# CONFIG_PMIC_OPREGION is not set +CONFIG_PM_CLK=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_OPP=y +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +CONFIG_PM_STD_PARTITION="" +CONFIG_PNP=y +CONFIG_PNPACPI=y +CONFIG_PNP_DEBUG_MESSAGES=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_POWER_RESET_VEXPRESS=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_SUPPLY=y +CONFIG_PPS=y +CONFIG_PREEMPT=y +CONFIG_PREEMPT_COUNT=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_PREEMPT_RCU=y +CONFIG_PRINTK_TIME=y +CONFIG_PRINT_QUOTA_WARNING=y +CONFIG_PROC_CHILDREN=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_PROC_PID_CPUSET=y +CONFIG_PROFILING=y +CONFIG_PTP_1588_CLOCK=y +# CONFIG_PTP_1588_CLOCK_DPAA is not set +CONFIG_PTP_1588_CLOCK_DPAA2=y +CONFIG_PWM=y +# CONFIG_PWM_CROS_EC is not set +CONFIG_PWM_SYSFS=y +CONFIG_QCOM_HIDMA=y +CONFIG_QCOM_HIDMA_MGMT=y +CONFIG_QCOM_QDF2400_ERRATUM_0065=y +# CONFIG_QFMT_V1 is not set +# CONFIG_QFMT_V2 is not set +CONFIG_QMAN_CEETM_UPDATE_PERIOD=1000 +CONFIG_QORIQ_CPUFREQ=y +# CONFIG_QUICC_ENGINE is not set +CONFIG_QUOTA=y +CONFIG_QUOTACTL=y +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +CONFIG_RADIX_TREE_MULTIORDER=y +CONFIG_RAID6_PQ=y +# CONFIG_RANDOMIZE_BASE is not set +CONFIG_RAS=y +CONFIG_RATIONAL=y +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +# CONFIG_RCU_EXPERT is not set +CONFIG_RCU_STALL_COMMON=y +CONFIG_RD_BZIP2=y +CONFIG_RD_GZIP=y +CONFIG_RD_LZ4=y +CONFIG_RD_LZMA=y +CONFIG_RD_LZO=y +CONFIG_RD_XZ=y +CONFIG_REALTEK_PHY=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_IRQ=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGMAP_SPI=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_GPIO=y +CONFIG_REGULATOR_MAX77620=y +CONFIG_REGULATOR_PWM=y +CONFIG_REGULATOR_QCOM_SPMI=y +CONFIG_REGULATOR_RK808=y +# CONFIG_REGULATOR_S2MPA01 is not set +CONFIG_REGULATOR_S2MPS11=y +# CONFIG_REGULATOR_S5M8767 is not set +# CONFIG_REGULATOR_VEXPRESS is not set +CONFIG_RESET_CONTROLLER=y +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_DS1307=y +CONFIG_RTC_DRV_DS1307_HWMON=y +CONFIG_RTC_DRV_DS3232=y +CONFIG_RTC_DRV_EFI=y +CONFIG_RTC_DRV_MAX77686=y +CONFIG_RTC_DRV_PCF2127=y +CONFIG_RTC_DRV_PCF85263=y +CONFIG_RTC_DRV_PL031=y +# CONFIG_RTC_DRV_RK808 is not set +CONFIG_RTC_DRV_S5M=y +CONFIG_RTC_I2C_AND_SPI=y +# CONFIG_RT_GROUP_SCHED is not set +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_SATA_AHCI=y +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_SATA_PMP=y +CONFIG_SATA_SIL24=y +# CONFIG_SATA_ZPODD is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_INFO=y +CONFIG_SCHED_MC=y +CONFIG_SCSI=y +CONFIG_SCSI_HISI_SAS=y +# CONFIG_SCSI_PROC_FS is not set +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_SAS_ATTRS=y +CONFIG_SCSI_SAS_HOST_SMP=y +CONFIG_SCSI_SAS_LIBSAS=y +CONFIG_SECCOMP=y +CONFIG_SECCOMP_FILTER=y +CONFIG_SECURITY=y +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_NETWORK is not set +# CONFIG_SECURITY_PATH is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_YAMA is not set +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_PNP=y +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_AMBA_PL010 is not set +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_SERIAL_FSL_LPUART=y +CONFIG_SERIAL_FSL_LPUART_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_XILINX_PS_UART=y +CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y +CONFIG_SERIO=y +CONFIG_SERIO_AMBAKMI=y +CONFIG_SERIO_LIBPS2=y +CONFIG_SG_POOL=y +CONFIG_SKY2=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +CONFIG_SMC91X=y +CONFIG_SMP=y +CONFIG_SMSC911X=y +# CONFIG_SMSC911X_ARCH_HOOKS is not set +CONFIG_SND=y +# CONFIG_SND_COMPRESS_OFFLOAD is not set +CONFIG_SND_DMAENGINE_PCM=y +CONFIG_SND_JACK=y +CONFIG_SND_JACK_INPUT_DEV=y +CONFIG_SND_PCM=y +CONFIG_SND_PCM_TIMER=y +CONFIG_SND_SIMPLE_CARD=y +CONFIG_SND_SIMPLE_CARD_UTILS=y +CONFIG_SND_SOC=y +CONFIG_SND_SOC_AK4613=y +CONFIG_SND_SOC_FSL_SAI=y +CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y +CONFIG_SND_SOC_I2C_AND_SPI=y +CONFIG_SND_SOC_SGTL5000=y +CONFIG_SND_SPI=y +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_TIMER=y +CONFIG_SOCK_DIAG=y +CONFIG_SOC_BUS=y +CONFIG_SOUND=y +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +CONFIG_SPI_FSL_DSPI=y +CONFIG_SPI_FSL_QUADSPI=y +CONFIG_SPI_MASTER=y +CONFIG_SPI_PL022=y +CONFIG_SPMI=y +# CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU is not set +CONFIG_SQUASHFS_DECOMP_SINGLE=y +CONFIG_SQUASHFS_FILE_CACHE=y +# CONFIG_SQUASHFS_FILE_DIRECT is not set +# CONFIG_SQUASHFS_XZ is not set +CONFIG_SQUASHFS_ZLIB=y +CONFIG_SRAM=y +CONFIG_SRCU=y +# CONFIG_STRIP_ASM_SYMS is not set +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_SWIOTLB=y +CONFIG_SWIOTLB_XEN=y +CONFIG_SWPHY=y +# CONFIG_SW_SYNC is not set +CONFIG_SYNC_FILE=y +# CONFIG_SYN_COOKIES is not set +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_SYSVIPC_COMPAT=y +CONFIG_SYS_HYPERVISOR=y +CONFIG_SYS_SUPPORTS_HUGETLBFS=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_TASK_XACCT=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMULATION=y +CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +# CONFIG_THUNDER_NIC_BGX is not set +# CONFIG_THUNDER_NIC_PF is not set +# CONFIG_THUNDER_NIC_RGX is not set +# CONFIG_THUNDER_NIC_VF is not set +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y +# CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set +CONFIG_TRANSPARENT_HUGE_PAGECACHE=y +CONFIG_TUN=y +CONFIG_UCS2_STRING=y +CONFIG_UIO=y +CONFIG_UIO_AEC=y +CONFIG_UIO_CIF=y +CONFIG_UIO_DMEM_GENIRQ=y +CONFIG_UIO_MF624=y +CONFIG_UIO_NETX=y +CONFIG_UIO_PCI_GENERIC=y +CONFIG_UIO_PDRV_GENIRQ=y +# CONFIG_UIO_PRUSS is not set +CONFIG_UIO_SERCOS3=y +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_UNIX_DIAG=y +CONFIG_USB=y +CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_CHIPIDEA_OF=y +CONFIG_USB_CHIPIDEA_UDC=y +CONFIG_USB_COMMON=y +CONFIG_USB_DWC2=y +CONFIG_USB_DWC2_DUAL_ROLE=y +# CONFIG_USB_DWC2_PCI is not set +# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_DUAL_ROLE=y +# CONFIG_USB_DWC3_GADGET is not set +# CONFIG_USB_DWC3_HOST is not set +CONFIG_USB_DWC3_OF_SIMPLE=y +CONFIG_USB_DWC3_PCI=y +# CONFIG_USB_EHCI_FSL is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_EHCI_PCI=y +CONFIG_USB_GADGET=y +CONFIG_USB_HID=y +CONFIG_USB_HSIC_USB3503=y +CONFIG_USB_ISP1760=y +CONFIG_USB_ISP1760_DUAL_ROLE=y +# CONFIG_USB_ISP1760_GADGET_ROLE is not set +CONFIG_USB_ISP1760_HCD=y +# CONFIG_USB_ISP1760_HOST_ROLE is not set +CONFIG_USB_ISP1761_UDC=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PCI=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_OTG=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SUPPORT=y +# CONFIG_USB_UHCI_HCD is not set +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PCI=y +CONFIG_USB_XHCI_PLATFORM=y +# CONFIG_USERIO is not set +CONFIG_USER_NS=y +CONFIG_USE_PERCPU_NUMA_NODE_ID=y +CONFIG_UTS_NS=y +CONFIG_VEXPRESS_CONFIG=y +CONFIG_VEXPRESS_SYSCFG=y +CONFIG_VFAT_FS=y +CONFIG_VFIO=y +CONFIG_VFIO_FSL_MC=y +CONFIG_VFIO_IOMMU_TYPE1=y +# CONFIG_VFIO_NOIOMMU is not set +CONFIG_VFIO_PCI=y +CONFIG_VFIO_PCI_INTX=y +CONFIG_VFIO_PCI_MMAP=y +# CONFIG_VFIO_PLATFORM is not set +CONFIG_VFIO_VIRQFD=y +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +CONFIG_VHOST=y +CONFIG_VHOST_NET=y +CONFIG_VIDEOMODE_HELPERS=y +CONFIG_VIRTIO=y +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_BLK=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_VIRTIO_MMIO=y +# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set +CONFIG_VIRTIO_NET=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_PCI_LEGACY=y +CONFIG_VIRTUALIZATION=y +CONFIG_VITESSE_PHY=y +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_VLAN_8021Q_MVRP=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_WATCHDOG_CORE=y +CONFIG_WLAN_VENDOR_ADMTEK=y +CONFIG_WLAN_VENDOR_ATH=y +CONFIG_WLAN_VENDOR_ATMEL=y +CONFIG_WLAN_VENDOR_BROADCOM=y +CONFIG_WLAN_VENDOR_CISCO=y +CONFIG_WLAN_VENDOR_INTEL=y +CONFIG_WLAN_VENDOR_INTERSIL=y +CONFIG_WLAN_VENDOR_MARVELL=y +CONFIG_WLAN_VENDOR_MEDIATEK=y +CONFIG_WLAN_VENDOR_RALINK=y +CONFIG_WLAN_VENDOR_REALTEK=y +CONFIG_WLAN_VENDOR_RSI=y +CONFIG_WLAN_VENDOR_ST=y +CONFIG_WLAN_VENDOR_TI=y +CONFIG_WLAN_VENDOR_ZYDAS=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +CONFIG_XEN=y +CONFIG_XENFS=y +CONFIG_XEN_AUTO_XLATE=y +CONFIG_XEN_BACKEND=y +CONFIG_XEN_BALLOON=y +# CONFIG_XEN_BLKDEV_BACKEND is not set +CONFIG_XEN_BLKDEV_FRONTEND=y +CONFIG_XEN_COMPAT_XENFS=y +CONFIG_XEN_DEV_EVTCHN=y +CONFIG_XEN_DOM0=y +CONFIG_XEN_EFI=y +CONFIG_XEN_FBDEV_FRONTEND=y +CONFIG_XEN_GNTDEV=y +CONFIG_XEN_GRANT_DEV_ALLOC=y +# CONFIG_XEN_NETDEV_BACKEND is not set +CONFIG_XEN_NETDEV_FRONTEND=y +CONFIG_XEN_PRIVCMD=y +CONFIG_XEN_SCRUB_PAGES=y +# CONFIG_XEN_SCSI_FRONTEND is not set +CONFIG_XEN_SYS_HYPERVISOR=y +# CONFIG_XEN_WDT is not set +CONFIG_XEN_XENBUS_FRONTEND=y +CONFIG_XFRM_ALGO=y +CONFIG_XFRM_USER=y +CONFIG_XFS_FS=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_RT=y +CONFIG_XOR_BLOCKS=y +CONFIG_XPS=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_ARMTHUMB=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_XZ_DEC_IA64=y +CONFIG_XZ_DEC_POWERPC=y +CONFIG_XZ_DEC_SPARC=y +CONFIG_XZ_DEC_X86=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_ZLIB_INFLATE=y diff --git a/target/linux/layerscape/patches-4.9/201-config-support-layerscape.patch b/target/linux/layerscape/patches-4.9/201-config-support-layerscape.patch new file mode 100644 index 0000000000..0105f5930b --- /dev/null +++ b/target/linux/layerscape/patches-4.9/201-config-support-layerscape.patch @@ -0,0 +1,532 @@ +From 11edf9c88acea13d1a02901289060263b4027a77 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 09:52:26 +0800 +Subject: [PATCH] config: support layerscape +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is a integrated patch for layerscape config/makefile support. + +Signed-off-by: Yuantian Tang +Signed-off-by: Zhang Ying-22455 +Signed-off-by: Zhao Qiang +Signed-off-by: Bogdan Purcareata +Signed-off-by: Zhao Qiang +Signed-off-by: Horia Geantă +Signed-off-by: Yangbo Lu +--- + drivers/base/Kconfig | 1 + + drivers/crypto/Makefile | 2 +- + drivers/net/ethernet/freescale/Kconfig | 4 +- + drivers/net/ethernet/freescale/Makefile | 2 + + drivers/ptp/Kconfig | 29 ++++++ + drivers/rtc/Kconfig | 8 ++ + drivers/rtc/Makefile | 1 + + drivers/soc/Kconfig | 3 +- + drivers/soc/fsl/Kconfig | 22 +++++ + drivers/soc/fsl/Kconfig.arm | 16 ++++ + drivers/soc/fsl/Makefile | 4 + + drivers/soc/fsl/layerscape/Kconfig | 10 +++ + drivers/soc/fsl/layerscape/Makefile | 1 + + drivers/soc/fsl/rcpm.c | 154 ++++++++++++++++++++++++++++++++ + drivers/staging/Kconfig | 4 + + drivers/staging/Makefile | 2 + + drivers/staging/fsl-dpaa2/Kconfig | 41 +++++++++ + drivers/staging/fsl-dpaa2/Makefile | 9 ++ + 18 files changed, 309 insertions(+), 4 deletions(-) + create mode 100644 drivers/soc/fsl/Kconfig + create mode 100644 drivers/soc/fsl/Kconfig.arm + create mode 100644 drivers/soc/fsl/layerscape/Kconfig + create mode 100644 drivers/soc/fsl/layerscape/Makefile + create mode 100644 drivers/soc/fsl/rcpm.c + create mode 100644 drivers/staging/fsl-dpaa2/Kconfig + create mode 100644 drivers/staging/fsl-dpaa2/Makefile + +diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig +index e1c0e2e0..4211a7fd 100644 +--- a/drivers/base/Kconfig ++++ b/drivers/base/Kconfig +@@ -237,6 +237,7 @@ config GENERIC_CPU_AUTOPROBE + + config SOC_BUS + bool ++ select GLOB + + source "drivers/base/regmap/Kconfig" + +diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile +index ad7250fa..6d788fd7 100644 +--- a/drivers/crypto/Makefile ++++ b/drivers/crypto/Makefile +@@ -3,7 +3,7 @@ obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o + obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o + obj-$(CONFIG_CRYPTO_DEV_BFIN_CRC) += bfin_crc.o + obj-$(CONFIG_CRYPTO_DEV_CCP) += ccp/ +-obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam/ ++obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON) += caam/ + obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o + obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o + obj-$(CONFIG_CRYPTO_DEV_IMGTEC_HASH) += img-hash.o +diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig +index d1ca45fb..74a2864e 100644 +--- a/drivers/net/ethernet/freescale/Kconfig ++++ b/drivers/net/ethernet/freescale/Kconfig +@@ -5,7 +5,7 @@ + config NET_VENDOR_FREESCALE + bool "Freescale devices" + default y +- depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \ ++ depends on FSL_SOC || (QUICC_ENGINE && PPC32) || CPM1 || CPM2 || PPC_MPC512x || \ + M523x || M527x || M5272 || M528x || M520x || M532x || \ + ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM) || \ + ARCH_LAYERSCAPE +@@ -93,4 +93,6 @@ config GIANFAR + and MPC86xx family of chips, the eTSEC on LS1021A and the FEC + on the 8540. + ++source "drivers/net/ethernet/freescale/sdk_fman/Kconfig" ++source "drivers/net/ethernet/freescale/sdk_dpaa/Kconfig" + endif # NET_VENDOR_FREESCALE +diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile +index cbe21dc7..a5d4405f 100644 +--- a/drivers/net/ethernet/freescale/Makefile ++++ b/drivers/net/ethernet/freescale/Makefile +@@ -21,4 +21,6 @@ gianfar_driver-objs := gianfar.o \ + obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o + ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o + ++obj-$(if $(CONFIG_FSL_SDK_FMAN),y) += sdk_fman/ ++obj-$(if $(CONFIG_FSL_SDK_DPAA_ETH),y) += sdk_dpaa/ + obj-$(CONFIG_FSL_FMAN) += fman/ +diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig +index ee3de342..4c45beda 100644 +--- a/drivers/ptp/Kconfig ++++ b/drivers/ptp/Kconfig +@@ -39,6 +39,35 @@ config PTP_1588_CLOCK_GIANFAR + To compile this driver as a module, choose M here: the module + will be called gianfar_ptp. + ++config PTP_1588_CLOCK_DPAA ++ tristate "Freescale DPAA as PTP clock" ++ depends on FSL_SDK_DPAA_ETH ++ select PTP_1588_CLOCK ++ select FSL_DPAA_TS ++ default n ++ help ++ This driver adds support for using the DPAA 1588 timer module ++ as a PTP clock. This clock is only useful if your PTP programs are ++ getting hardware time stamps on the PTP Ethernet packets ++ using the SO_TIMESTAMPING API. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called dpaa_ptp. ++ ++config PTP_1588_CLOCK_DPAA2 ++ tristate "Freescale DPAA2 as PTP clock" ++ depends on FSL_DPAA2_ETH ++ select PTP_1588_CLOCK ++ default y ++ help ++ This driver adds support for using the DPAA2 1588 timer module ++ as a PTP clock. This clock is only useful if your PTP programs are ++ getting hardware time stamps on the PTP Ethernet packets ++ using the SO_TIMESTAMPING API. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called dpaa2-rtc. ++ + config PTP_1588_CLOCK_IXP46X + tristate "Intel IXP46x as PTP clock" + depends on IXP4XX_ETH +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index 0723c97e..df610dcd 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -414,6 +414,14 @@ config RTC_DRV_PCF85063 + This driver can also be built as a module. If so, the module + will be called rtc-pcf85063. + ++config RTC_DRV_PCF85263 ++ tristate "NXP PCF85263" ++ help ++ If you say yes here you get support for the PCF85263 RTC chip ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-pcf85263. ++ + config RTC_DRV_PCF8563 + tristate "Philips PCF8563/Epson RTC8564" + help +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 1ac694a3..7675b8a7 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -111,6 +111,7 @@ obj-$(CONFIG_RTC_DRV_PCF2127) += rtc-pcf2127.o + obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o + obj-$(CONFIG_RTC_DRV_PCF85063) += rtc-pcf85063.o + obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o ++obj-$(CONFIG_RTC_DRV_PCF85263) += rtc-pcf85263.o + obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o + obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o + obj-$(CONFIG_RTC_DRV_PIC32) += rtc-pic32.o +diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig +index e6e90e80..f31bceb6 100644 +--- a/drivers/soc/Kconfig ++++ b/drivers/soc/Kconfig +@@ -1,8 +1,7 @@ + menu "SOC (System On Chip) specific Drivers" + + source "drivers/soc/bcm/Kconfig" +-source "drivers/soc/fsl/qbman/Kconfig" +-source "drivers/soc/fsl/qe/Kconfig" ++source "drivers/soc/fsl/Kconfig" + source "drivers/soc/mediatek/Kconfig" + source "drivers/soc/qcom/Kconfig" + source "drivers/soc/rockchip/Kconfig" +diff --git a/drivers/soc/fsl/Kconfig b/drivers/soc/fsl/Kconfig +new file mode 100644 +index 00000000..d4cd25f1 +--- /dev/null ++++ b/drivers/soc/fsl/Kconfig +@@ -0,0 +1,22 @@ ++# ++# Freescale SOC drivers ++# ++ ++source "drivers/soc/fsl/qbman/Kconfig" ++source "drivers/soc/fsl/qe/Kconfig" ++source "drivers/soc/fsl/ls2-console/Kconfig" ++ ++config FSL_GUTS ++ bool ++ select SOC_BUS ++ help ++ The global utilities block controls power management, I/O device ++ enabling, power-onreset(POR) configuration monitoring, alternate ++ function selection for multiplexed signals,and clock control. ++ This driver is to manage and access global utilities block. ++ Initially only reading SVR and registering soc device are supported. ++ Other guts accesses, such as reading RCW, should eventually be moved ++ into this driver as well. ++if ARM || ARM64 ++source "drivers/soc/fsl/Kconfig.arm" ++endif +diff --git a/drivers/soc/fsl/Kconfig.arm b/drivers/soc/fsl/Kconfig.arm +new file mode 100644 +index 00000000..106c9b98 +--- /dev/null ++++ b/drivers/soc/fsl/Kconfig.arm +@@ -0,0 +1,16 @@ ++# ++# Freescale ARM SOC Drivers ++# ++ ++config LS_SOC_DRIVERS ++ bool "Layerscape Soc Drivers" ++ depends on ARCH_LAYERSCAPE || SOC_LS1021A ++ default n ++ help ++ Say y here to enable Freescale Layerscape Soc Device Drivers support. ++ The Soc Drivers provides the device driver that is a specific block ++ or feature on Layerscape platform. ++ ++if LS_SOC_DRIVERS ++ source "drivers/soc/fsl/layerscape/Kconfig" ++endif +diff --git a/drivers/soc/fsl/Makefile b/drivers/soc/fsl/Makefile +index 75e1f533..b8708569 100644 +--- a/drivers/soc/fsl/Makefile ++++ b/drivers/soc/fsl/Makefile +@@ -5,3 +5,7 @@ + obj-$(CONFIG_FSL_DPAA) += qbman/ + obj-$(CONFIG_QUICC_ENGINE) += qe/ + obj-$(CONFIG_CPM) += qe/ ++obj-$(CONFIG_FSL_GUTS) += guts.o ++obj-$(CONFIG_FSL_LS2_CONSOLE) += ls2-console/ ++obj-$(CONFIG_SUSPEND) += rcpm.o ++obj-$(CONFIG_LS_SOC_DRIVERS) += layerscape/ +diff --git a/drivers/soc/fsl/layerscape/Kconfig b/drivers/soc/fsl/layerscape/Kconfig +new file mode 100644 +index 00000000..e1373aa1 +--- /dev/null ++++ b/drivers/soc/fsl/layerscape/Kconfig +@@ -0,0 +1,10 @@ ++# ++# Layerscape Soc drivers ++# ++config FTM_ALARM ++ bool "FTM alarm driver" ++ default n ++ help ++ Say y here to enable FTM alarm support. The FTM alarm provides ++ alarm functions for wakeup system from deep sleep. There is only ++ one FTM can be used in ALARM(FTM 0). +diff --git a/drivers/soc/fsl/layerscape/Makefile b/drivers/soc/fsl/layerscape/Makefile +new file mode 100644 +index 00000000..6299aa1d +--- /dev/null ++++ b/drivers/soc/fsl/layerscape/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_FTM_ALARM) += ftm_alarm.o +diff --git a/drivers/soc/fsl/rcpm.c b/drivers/soc/fsl/rcpm.c +new file mode 100644 +index 00000000..a6a31c87 +--- /dev/null ++++ b/drivers/soc/fsl/rcpm.c +@@ -0,0 +1,154 @@ ++/* ++ * Run Control and Power Management (RCPM) driver ++ * ++ * Copyright 2016 NXP ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++#define pr_fmt(fmt) "RCPM: %s: " fmt, __func__ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* RCPM register offset */ ++#define RCPM_IPPDEXPCR0 0x140 ++ ++#define RCPM_WAKEUP_CELL_SIZE 2 ++ ++struct rcpm_config { ++ int ipp_num; ++ int ippdexpcr_offset; ++ u32 ippdexpcr[2]; ++ void *rcpm_reg_base; ++}; ++ ++static struct rcpm_config *rcpm; ++ ++static inline void rcpm_reg_write(u32 offset, u32 value) ++{ ++ iowrite32be(value, rcpm->rcpm_reg_base + offset); ++} ++ ++static inline u32 rcpm_reg_read(u32 offset) ++{ ++ return ioread32be(rcpm->rcpm_reg_base + offset); ++} ++ ++static void rcpm_wakeup_fixup(struct device *dev, void *data) ++{ ++ struct device_node *node = dev ? dev->of_node : NULL; ++ u32 value[RCPM_WAKEUP_CELL_SIZE]; ++ int ret, i; ++ ++ if (!dev || !node || !device_may_wakeup(dev)) ++ return; ++ ++ /* ++ * Get the values in the "rcpm-wakeup" property. ++ * Three values are: ++ * The first is a pointer to the RCPM node. ++ * The second is the value of the ippdexpcr0 register. ++ * The third is the value of the ippdexpcr1 register. ++ */ ++ ret = of_property_read_u32_array(node, "fsl,rcpm-wakeup", ++ value, RCPM_WAKEUP_CELL_SIZE); ++ if (ret) ++ return; ++ ++ pr_debug("wakeup source: the device %s\n", node->full_name); ++ ++ for (i = 0; i < rcpm->ipp_num; i++) ++ rcpm->ippdexpcr[i] |= value[i + 1]; ++} ++ ++static int rcpm_suspend_prepare(void) ++{ ++ int i; ++ ++ BUG_ON(!rcpm); ++ ++ for (i = 0; i < rcpm->ipp_num; i++) ++ rcpm->ippdexpcr[i] = 0; ++ ++ dpm_for_each_dev(NULL, rcpm_wakeup_fixup); ++ ++ for (i = 0; i < rcpm->ipp_num; i++) { ++ rcpm_reg_write(rcpm->ippdexpcr_offset + 4 * i, ++ rcpm->ippdexpcr[i]); ++ pr_debug("ippdexpcr%d = 0x%x\n", i, rcpm->ippdexpcr[i]); ++ } ++ ++ return 0; ++} ++ ++static int rcpm_suspend_notifier_call(struct notifier_block *bl, ++ unsigned long state, ++ void *unused) ++{ ++ switch (state) { ++ case PM_SUSPEND_PREPARE: ++ rcpm_suspend_prepare(); ++ break; ++ } ++ ++ return NOTIFY_DONE; ++} ++ ++static struct rcpm_config rcpm_default_config = { ++ .ipp_num = 1, ++ .ippdexpcr_offset = RCPM_IPPDEXPCR0, ++}; ++ ++static const struct of_device_id rcpm_matches[] = { ++ { ++ .compatible = "fsl,qoriq-rcpm-2.1", ++ .data = &rcpm_default_config, ++ }, ++ {} ++}; ++ ++static struct notifier_block rcpm_suspend_notifier = { ++ .notifier_call = rcpm_suspend_notifier_call, ++}; ++ ++static int __init layerscape_rcpm_init(void) ++{ ++ const struct of_device_id *match; ++ struct device_node *np; ++ ++ np = of_find_matching_node_and_match(NULL, rcpm_matches, &match); ++ if (!np) { ++ pr_err("Can't find the RCPM node.\n"); ++ return -EINVAL; ++ } ++ ++ if (match->data) ++ rcpm = (struct rcpm_config *)match->data; ++ else ++ return -EINVAL; ++ ++ rcpm->rcpm_reg_base = of_iomap(np, 0); ++ of_node_put(np); ++ if (!rcpm->rcpm_reg_base) ++ return -ENOMEM; ++ ++ register_pm_notifier(&rcpm_suspend_notifier); ++ ++ pr_info("The RCPM driver initialized.\n"); ++ ++ return 0; ++} ++ ++subsys_initcall(layerscape_rcpm_init); +diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig +index 58a7b350..f8e54860 100644 +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -94,6 +94,8 @@ source "drivers/staging/fbtft/Kconfig" + + source "drivers/staging/fsl-mc/Kconfig" + ++source "drivers/staging/fsl-dpaa2/Kconfig" ++ + source "drivers/staging/wilc1000/Kconfig" + + source "drivers/staging/most/Kconfig" +@@ -106,4 +108,6 @@ source "drivers/staging/greybus/Kconfig" + + source "drivers/staging/vc04_services/Kconfig" + ++source "drivers/staging/fsl_qbman/Kconfig" ++ + endif # STAGING +diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile +index 2fa9745d..cbd7b089 100644 +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -36,9 +36,11 @@ obj-$(CONFIG_UNISYSSPAR) += unisys/ + obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/ + obj-$(CONFIG_FB_TFT) += fbtft/ + obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/ ++obj-$(CONFIG_FSL_DPAA2) += fsl-dpaa2/ + obj-$(CONFIG_WILC1000) += wilc1000/ + obj-$(CONFIG_MOST) += most/ + obj-$(CONFIG_ISDN_I4L) += i4l/ + obj-$(CONFIG_KS7010) += ks7010/ + obj-$(CONFIG_GREYBUS) += greybus/ + obj-$(CONFIG_BCM2708_VCHIQ) += vc04_services/ ++obj-$(CONFIG_FSL_SDK_DPA) += fsl_qbman/ +diff --git a/drivers/staging/fsl-dpaa2/Kconfig b/drivers/staging/fsl-dpaa2/Kconfig +new file mode 100644 +index 00000000..8042d9cc +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/Kconfig +@@ -0,0 +1,41 @@ ++# ++# Freescale DataPath Acceleration Architecture Gen2 (DPAA2) drivers ++# ++ ++config FSL_DPAA2 ++ bool "Freescale DPAA2 devices" ++ depends on FSL_MC_BUS ++ ---help--- ++ Build drivers for Freescale DataPath Acceleration ++ Architecture (DPAA2) family of SoCs. ++ ++config FSL_DPAA2_ETH ++ tristate "Freescale DPAA2 Ethernet" ++ depends on FSL_DPAA2 && FSL_MC_DPIO ++ ---help--- ++ Ethernet driver for Freescale DPAA2 SoCs, using the ++ Freescale MC bus driver ++ ++if FSL_DPAA2_ETH ++config FSL_DPAA2_ETH_USE_ERR_QUEUE ++ bool "Enable Rx error queue" ++ default n ++ ---help--- ++ Allow Rx error frames to be enqueued on an error queue ++ and processed by the driver (by default they are dropped ++ in hardware). ++ This may impact performance, recommended for debugging ++ purposes only. ++ ++# QBMAN_DEBUG requires some additional DPIO APIs ++config FSL_DPAA2_ETH_DEBUGFS ++ depends on DEBUG_FS && FSL_QBMAN_DEBUG ++ bool "Enable debugfs support" ++ default n ++ ---help--- ++ Enable advanced statistics through debugfs interface. ++endif ++ ++source "drivers/staging/fsl-dpaa2/mac/Kconfig" ++source "drivers/staging/fsl-dpaa2/evb/Kconfig" ++source "drivers/staging/fsl-dpaa2/ethsw/Kconfig" +diff --git a/drivers/staging/fsl-dpaa2/Makefile b/drivers/staging/fsl-dpaa2/Makefile +new file mode 100644 +index 00000000..cbaa8c20 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/Makefile +@@ -0,0 +1,9 @@ ++# ++# Freescale DataPath Acceleration Architecture Gen2 (DPAA2) drivers ++# ++ ++obj-$(CONFIG_FSL_DPAA2_ETH) += ethernet/ ++obj-$(CONFIG_FSL_DPAA2_MAC) += mac/ ++obj-$(CONFIG_FSL_DPAA2_EVB) += evb/ ++obj-$(CONFIG_FSL_DPAA2_ETHSW) += ethsw/ ++obj-$(CONFIG_PTP_1588_CLOCK_DPAA2) += rtc/ +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/301-arch-support-layerscape.patch b/target/linux/layerscape/patches-4.9/301-arch-support-layerscape.patch new file mode 100644 index 0000000000..da3dc120b7 --- /dev/null +++ b/target/linux/layerscape/patches-4.9/301-arch-support-layerscape.patch @@ -0,0 +1,461 @@ +From 7edaf7ed8fbd5fb50950a4fc8067a9c14557d010 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 10:03:52 +0800 +Subject: [PATCH] arch: support layerscape +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is a integrated patch for layerscape arch support. + +Signed-off-by: Madalin Bucur +Signed-off-by: Nipun Gupta +Signed-off-by: Zhao Qiang +Signed-off-by: Camelia Groza +Signed-off-by: Haiying Wang +Signed-off-by: Pan Jiafei +Signed-off-by: Po Liu +Signed-off-by: Bharat Bhushan +Signed-off-by: Jianhua Xie +Signed-off-by: Horia Geantă +Signed-off-by: Yangbo Lu +--- + arch/arm/include/asm/delay.h | 16 +++++++++ + arch/arm/include/asm/io.h | 31 ++++++++++++++++++ + arch/arm/include/asm/mach/map.h | 4 +-- + arch/arm/include/asm/pgtable.h | 7 ++++ + arch/arm/kernel/bios32.c | 43 ++++++++++++++++++++++++ + arch/arm/mm/dma-mapping.c | 1 + + arch/arm/mm/ioremap.c | 7 ++++ + arch/arm/mm/mmu.c | 9 +++++ + arch/arm64/include/asm/cache.h | 2 +- + arch/arm64/include/asm/io.h | 2 ++ + arch/arm64/include/asm/pci.h | 4 +++ + arch/arm64/include/asm/pgtable-prot.h | 1 + + arch/arm64/include/asm/pgtable.h | 5 +++ + arch/arm64/kernel/pci.c | 62 +++++++++++++++++++++++++++++++++++ + arch/arm64/mm/dma-mapping.c | 6 ++++ + 15 files changed, 197 insertions(+), 3 deletions(-) + +diff --git a/arch/arm/include/asm/delay.h b/arch/arm/include/asm/delay.h +index b1ce037e..1445b0ca 100644 +--- a/arch/arm/include/asm/delay.h ++++ b/arch/arm/include/asm/delay.h +@@ -57,6 +57,22 @@ extern void __bad_udelay(void); + __const_udelay((n) * UDELAY_MULT)) : \ + __udelay(n)) + ++#define spin_event_timeout(condition, timeout, delay) \ ++({ \ ++ typeof(condition) __ret; \ ++ int i = 0; \ ++ while (!(__ret = (condition)) && (i++ < timeout)) { \ ++ if (delay) \ ++ udelay(delay); \ ++ else \ ++ cpu_relax(); \ ++ udelay(1); \ ++ } \ ++ if (!__ret) \ ++ __ret = (condition); \ ++ __ret; \ ++}) ++ + /* Loop-based definitions for assembly code. */ + extern void __loop_delay(unsigned long loops); + extern void __loop_udelay(unsigned long usecs); +diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h +index 021692c6..172a4f2e 100644 +--- a/arch/arm/include/asm/io.h ++++ b/arch/arm/include/asm/io.h +@@ -129,6 +129,7 @@ static inline u32 __raw_readl(const volatile void __iomem *addr) + #define MT_DEVICE_NONSHARED 1 + #define MT_DEVICE_CACHED 2 + #define MT_DEVICE_WC 3 ++#define MT_MEMORY_RW_NS 4 + /* + * types 4 onwards can be found in asm/mach/map.h and are undefined + * for ioremap +@@ -220,6 +221,34 @@ extern int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr); + #endif + #endif + ++/* access ports */ ++#define setbits32(_addr, _v) iowrite32be(ioread32be(_addr) | (_v), (_addr)) ++#define clrbits32(_addr, _v) iowrite32be(ioread32be(_addr) & ~(_v), (_addr)) ++ ++#define setbits16(_addr, _v) iowrite16be(ioread16be(_addr) | (_v), (_addr)) ++#define clrbits16(_addr, _v) iowrite16be(ioread16be(_addr) & ~(_v), (_addr)) ++ ++#define setbits8(_addr, _v) iowrite8(ioread8(_addr) | (_v), (_addr)) ++#define clrbits8(_addr, _v) iowrite8(ioread8(_addr) & ~(_v), (_addr)) ++ ++/* Clear and set bits in one shot. These macros can be used to clear and ++ * set multiple bits in a register using a single read-modify-write. These ++ * macros can also be used to set a multiple-bit bit pattern using a mask, ++ * by specifying the mask in the 'clear' parameter and the new bit pattern ++ * in the 'set' parameter. ++ */ ++ ++#define clrsetbits_be32(addr, clear, set) \ ++ iowrite32be((ioread32be(addr) & ~(clear)) | (set), (addr)) ++#define clrsetbits_le32(addr, clear, set) \ ++ iowrite32le((ioread32le(addr) & ~(clear)) | (set), (addr)) ++#define clrsetbits_be16(addr, clear, set) \ ++ iowrite16be((ioread16be(addr) & ~(clear)) | (set), (addr)) ++#define clrsetbits_le16(addr, clear, set) \ ++ iowrite16le((ioread16le(addr) & ~(clear)) | (set), (addr)) ++#define clrsetbits_8(addr, clear, set) \ ++ iowrite8((ioread8(addr) & ~(clear)) | (set), (addr)) ++ + /* + * IO port access primitives + * ------------------------- +@@ -408,6 +437,8 @@ void __iomem *ioremap_wc(resource_size_t res_cookie, size_t size); + #define ioremap_wc ioremap_wc + #define ioremap_wt ioremap_wc + ++void __iomem *ioremap_cache_ns(resource_size_t res_cookie, size_t size); ++ + void iounmap(volatile void __iomem *iomem_cookie); + #define iounmap iounmap + +diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h +index 9b7c328f..27f3df7d 100644 +--- a/arch/arm/include/asm/mach/map.h ++++ b/arch/arm/include/asm/mach/map.h +@@ -21,9 +21,9 @@ struct map_desc { + unsigned int type; + }; + +-/* types 0-3 are defined in asm/io.h */ ++/* types 0-4 are defined in asm/io.h */ + enum { +- MT_UNCACHED = 4, ++ MT_UNCACHED = 5, + MT_CACHECLEAN, + MT_MINICLEAN, + MT_LOW_VECTORS, +diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h +index a8d656d9..4ab57b37 100644 +--- a/arch/arm/include/asm/pgtable.h ++++ b/arch/arm/include/asm/pgtable.h +@@ -118,6 +118,13 @@ extern pgprot_t pgprot_s2_device; + #define pgprot_noncached(prot) \ + __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED) + ++#define pgprot_cached(prot) \ ++ __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_DEV_CACHED) ++ ++#define pgprot_cached_ns(prot) \ ++ __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_DEV_CACHED | \ ++ L_PTE_MT_DEV_NONSHARED) ++ + #define pgprot_writecombine(prot) \ + __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE) + +diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c +index 2f0e0773..d2f4869a 100644 +--- a/arch/arm/kernel/bios32.c ++++ b/arch/arm/kernel/bios32.c +@@ -11,6 +11,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -63,6 +65,47 @@ void pcibios_report_status(u_int status_mask, int warn) + pcibios_bus_report_status(bus, status_mask, warn); + } + ++/* ++ * Check device tree if the service interrupts are there ++ */ ++int pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask) ++{ ++ int ret, count = 0; ++ struct device_node *np = NULL; ++ ++ if (dev->bus->dev.of_node) ++ np = dev->bus->dev.of_node; ++ ++ if (np == NULL) ++ return 0; ++ ++ if (!IS_ENABLED(CONFIG_OF_IRQ)) ++ return 0; ++ ++ /* If root port doesn't support MSI/MSI-X/INTx in RC mode, ++ * request irq for aer ++ */ ++ if (mask & PCIE_PORT_SERVICE_AER) { ++ ret = of_irq_get_byname(np, "aer"); ++ if (ret > 0) { ++ irqs[PCIE_PORT_SERVICE_AER_SHIFT] = ret; ++ count++; ++ } ++ } ++ ++ if (mask & PCIE_PORT_SERVICE_PME) { ++ ret = of_irq_get_byname(np, "pme"); ++ if (ret > 0) { ++ irqs[PCIE_PORT_SERVICE_PME_SHIFT] = ret; ++ count++; ++ } ++ } ++ ++ /* TODO: add more service interrupts if there it is in the device tree*/ ++ ++ return count; ++} ++ + /* + * We don't use this to fix the device, but initialisation of it. + * It's not the correct use for this, but it works. +diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c +index ab771000..9b5f4465 100644 +--- a/arch/arm/mm/dma-mapping.c ++++ b/arch/arm/mm/dma-mapping.c +@@ -2392,6 +2392,7 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, + + set_dma_ops(dev, dma_ops); + } ++EXPORT_SYMBOL(arch_setup_dma_ops); + + void arch_teardown_dma_ops(struct device *dev) + { +diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c +index ff0eed23..2f2f4269 100644 +--- a/arch/arm/mm/ioremap.c ++++ b/arch/arm/mm/ioremap.c +@@ -398,6 +398,13 @@ void __iomem *ioremap_wc(resource_size_t res_cookie, size_t size) + } + EXPORT_SYMBOL(ioremap_wc); + ++void __iomem *ioremap_cache_ns(resource_size_t res_cookie, size_t size) ++{ ++ return arch_ioremap_caller(res_cookie, size, MT_MEMORY_RW_NS, ++ __builtin_return_address(0)); ++} ++EXPORT_SYMBOL(ioremap_cache_ns); ++ + /* + * Remap an arbitrary physical address space into the kernel virtual + * address space as memory. Needed when the kernel wants to execute +diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c +index f7c74135..4a2fb704 100644 +--- a/arch/arm/mm/mmu.c ++++ b/arch/arm/mm/mmu.c +@@ -313,6 +313,13 @@ static struct mem_type mem_types[] __ro_after_init = { + .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, + .domain = DOMAIN_KERNEL, + }, ++ [MT_MEMORY_RW_NS] = { ++ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | ++ L_PTE_XN, ++ .prot_l1 = PMD_TYPE_TABLE, ++ .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_XN, ++ .domain = DOMAIN_KERNEL, ++ }, + [MT_ROM] = { + .prot_sect = PMD_TYPE_SECT, + .domain = DOMAIN_KERNEL, +@@ -644,6 +651,7 @@ static void __init build_mem_type_table(void) + } + kern_pgprot |= PTE_EXT_AF; + vecs_pgprot |= PTE_EXT_AF; ++ mem_types[MT_MEMORY_RW_NS].prot_pte |= PTE_EXT_AF | cp->pte; + + /* + * Set PXN for user mappings +@@ -672,6 +680,7 @@ static void __init build_mem_type_table(void) + mem_types[MT_MEMORY_RWX].prot_pte |= kern_pgprot; + mem_types[MT_MEMORY_RW].prot_sect |= ecc_mask | cp->pmd; + mem_types[MT_MEMORY_RW].prot_pte |= kern_pgprot; ++ mem_types[MT_MEMORY_RW_NS].prot_sect |= ecc_mask | cp->pmd; + mem_types[MT_MEMORY_DMA_READY].prot_pte |= kern_pgprot; + mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= ecc_mask; + mem_types[MT_ROM].prot_sect |= cp->pmd; +diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h +index 5082b30b..bde44993 100644 +--- a/arch/arm64/include/asm/cache.h ++++ b/arch/arm64/include/asm/cache.h +@@ -18,7 +18,7 @@ + + #include + +-#define L1_CACHE_SHIFT 7 ++#define L1_CACHE_SHIFT 6 + #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) + + /* +diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h +index 0bba427b..36c1fbf3 100644 +--- a/arch/arm64/include/asm/io.h ++++ b/arch/arm64/include/asm/io.h +@@ -171,6 +171,8 @@ extern void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size); + #define ioremap_nocache(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE)) + #define ioremap_wc(addr, size) __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC)) + #define ioremap_wt(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE)) ++#define ioremap_cache_ns(addr, size) __ioremap((addr), (size), \ ++ __pgprot(PROT_NORMAL_NS)) + #define iounmap __iounmap + + /* +diff --git a/arch/arm64/include/asm/pci.h b/arch/arm64/include/asm/pci.h +index b9a7ba9c..8a189159 100644 +--- a/arch/arm64/include/asm/pci.h ++++ b/arch/arm64/include/asm/pci.h +@@ -31,6 +31,10 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) + return -ENODEV; + } + ++#define HAVE_PCI_MMAP ++extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, ++ enum pci_mmap_state mmap_state, ++ int write_combine); + static inline int pci_proc_domain(struct pci_bus *bus) + { + return 1; +diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h +index 2142c772..cdf8b25d 100644 +--- a/arch/arm64/include/asm/pgtable-prot.h ++++ b/arch/arm64/include/asm/pgtable-prot.h +@@ -42,6 +42,7 @@ + #define PROT_NORMAL_NC (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_NC)) + #define PROT_NORMAL_WT (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL_WT)) + #define PROT_NORMAL (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL)) ++#define PROT_NORMAL_NS (PTE_TYPE_PAGE | PTE_AF | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_NORMAL)) + + #define PROT_SECT_DEVICE_nGnRE (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_DEVICE_nGnRE)) + #define PROT_SECT_NORMAL (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL)) +diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h +index 61e21401..b8c876fb 100644 +--- a/arch/arm64/include/asm/pgtable.h ++++ b/arch/arm64/include/asm/pgtable.h +@@ -356,6 +356,11 @@ static inline int pmd_protnone(pmd_t pmd) + __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE) | PTE_PXN | PTE_UXN) + #define pgprot_writecombine(prot) \ + __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN) ++#define pgprot_cached(prot) \ ++ __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL) | \ ++ PTE_PXN | PTE_UXN) ++#define pgprot_cached_ns(prot) \ ++ __pgprot(pgprot_val(pgprot_cached(prot)) ^ PTE_SHARED) + #define pgprot_device(prot) \ + __pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN) + #define __HAVE_PHYS_MEM_ACCESS_PROT +diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c +index 409abc45..0568ec3a 100644 +--- a/arch/arm64/kernel/pci.c ++++ b/arch/arm64/kernel/pci.c +@@ -17,6 +17,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -54,6 +56,66 @@ int pcibios_alloc_irq(struct pci_dev *dev) + return 0; + } + ++/* ++ * Check device tree if the service interrupts are there ++ */ ++int pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask) ++{ ++ int ret, count = 0; ++ struct device_node *np = NULL; ++ ++ if (dev->bus->dev.of_node) ++ np = dev->bus->dev.of_node; ++ ++ if (np == NULL) ++ return 0; ++ ++ if (!IS_ENABLED(CONFIG_OF_IRQ)) ++ return 0; ++ ++ /* If root port doesn't support MSI/MSI-X/INTx in RC mode, ++ * request irq for aer ++ */ ++ if (mask & PCIE_PORT_SERVICE_AER) { ++ ret = of_irq_get_byname(np, "aer"); ++ if (ret > 0) { ++ irqs[PCIE_PORT_SERVICE_AER_SHIFT] = ret; ++ count++; ++ } ++ } ++ ++ if (mask & PCIE_PORT_SERVICE_PME) { ++ ret = of_irq_get_byname(np, "pme"); ++ if (ret > 0) { ++ irqs[PCIE_PORT_SERVICE_PME_SHIFT] = ret; ++ count++; ++ } ++ } ++ ++ /* TODO: add more service interrupts if there it is in the device tree*/ ++ ++ return count; ++} ++ ++int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, ++ enum pci_mmap_state mmap_state, int write_combine) ++{ ++ if (mmap_state == pci_mmap_io) ++ return -EINVAL; ++ ++ /* ++ * Mark this as IO ++ */ ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ ++ if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, ++ vma->vm_end - vma->vm_start, ++ vma->vm_page_prot)) ++ return -EAGAIN; ++ ++ return 0; ++} ++ + /* + * raw_pci_read/write - Platform-specific PCI config space access. + */ +diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c +index b5bf46ce..1ef0d6df 100644 +--- a/arch/arm64/mm/dma-mapping.c ++++ b/arch/arm64/mm/dma-mapping.c +@@ -30,6 +30,7 @@ + #include + + #include ++#include <../../../drivers/staging/fsl-mc/include/mc-bus.h> + + static int swiotlb __ro_after_init; + +@@ -917,6 +918,10 @@ static int __init __iommu_dma_init(void) + #ifdef CONFIG_PCI + if (!ret) + ret = register_iommu_dma_ops_notifier(&pci_bus_type); ++#endif ++#ifdef CONFIG_FSL_MC_BUS ++ if (!ret) ++ ret = register_iommu_dma_ops_notifier(&fsl_mc_bus_type); + #endif + return ret; + } +@@ -971,3 +976,4 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, + dev->archdata.dma_coherent = coherent; + __iommu_setup_dma_ops(dev, dma_base, size, iommu); + } ++EXPORT_SYMBOL(arch_setup_dma_ops); +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/302-dts-support-layercape.patch b/target/linux/layerscape/patches-4.9/302-dts-support-layercape.patch new file mode 100644 index 0000000000..c820c9f9c9 --- /dev/null +++ b/target/linux/layerscape/patches-4.9/302-dts-support-layercape.patch @@ -0,0 +1,10085 @@ +From 2b2e3b9a0d2abf276b40843f75d97b623e4ee109 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 10:02:10 +0800 +Subject: [PATCH] dts: support layercape + +This is a integrated patch for layerscape dts support. + +Signed-off-by: Amrita Kumari +Signed-off-by: Alison Wang +Signed-off-by: Li Yang +Signed-off-by: Ashish Kumar +Signed-off-by: Zhao Qiang +Signed-off-by: Rajesh Bhagat +Signed-off-by: Zhang Ying-22455 +Signed-off-by: Madalin Bucur +Signed-off-by: Minghuan Lian +Signed-off-by: Suresh Gupta +Signed-off-by: Chenhui Zhao +Signed-off-by: Priyanka Jain +Signed-off-by: Hou Zhiqiang +Signed-off-by: Changming Huang +Signed-off-by: Bharat Bhushan +Signed-off-by: Meng Yi +Signed-off-by: Shaohui Xie +Signed-off-by: Marc Zyngier +Signed-off-by: Prabhakar Kushwaha +Signed-off-by: Ran Wang +Signed-off-by: Yangbo Lu +--- + arch/arm/boot/dts/alpine.dtsi | 2 +- + arch/arm/boot/dts/axm55xx.dtsi | 2 +- + arch/arm/boot/dts/ecx-2000.dts | 2 +- + arch/arm/boot/dts/imx6ul.dtsi | 4 +- + arch/arm/boot/dts/keystone.dtsi | 4 +- + arch/arm/boot/dts/ls1021a-qds.dts | 13 + + arch/arm/boot/dts/ls1021a-twr.dts | 13 + + arch/arm/boot/dts/ls1021a.dtsi | 155 ++-- + arch/arm/boot/dts/mt6580.dtsi | 2 +- + arch/arm/boot/dts/mt6589.dtsi | 2 +- + arch/arm/boot/dts/mt8127.dtsi | 2 +- + arch/arm/boot/dts/mt8135.dtsi | 2 +- + arch/arm/boot/dts/rk3288.dtsi | 2 +- + arch/arm/boot/dts/sun6i-a31.dtsi | 2 +- + arch/arm/boot/dts/sun7i-a20.dtsi | 4 +- + arch/arm/boot/dts/sun8i-a23-a33.dtsi | 2 +- + arch/arm/boot/dts/sun9i-a80.dtsi | 2 +- + arch/arm64/boot/dts/freescale/Makefile | 16 + + arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts | 134 +++ + arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts | 155 ++++ + arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts | 91 +++ + arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 517 ++++++++++++ + arch/arm64/boot/dts/freescale/fsl-ls1043-post.dtsi | 45 + + .../boot/dts/freescale/fsl-ls1043a-qds-sdk.dts | 69 ++ + arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts | 171 +++- + .../boot/dts/freescale/fsl-ls1043a-rdb-sdk.dts | 69 ++ + .../boot/dts/freescale/fsl-ls1043a-rdb-usdpaa.dts | 117 +++ + arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts | 113 ++- + arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 302 ++++++- + arch/arm64/boot/dts/freescale/fsl-ls1046-post.dtsi | 48 ++ + .../boot/dts/freescale/fsl-ls1046a-qds-sdk.dts | 109 +++ + arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts | 363 ++++++++ + .../boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts | 76 ++ + .../boot/dts/freescale/fsl-ls1046a-rdb-usdpaa.dts | 110 +++ + arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts | 218 +++++ + arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 793 ++++++++++++++++++ + arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts | 173 ++++ + arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts | 236 ++++++ + arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi | 816 ++++++++++++++++++ + arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts | 191 ++--- + arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts | 169 ++-- + arch/arm64/boot/dts/freescale/fsl-ls2080a-simu.dts | 9 +- + arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi | 763 +++-------------- + arch/arm64/boot/dts/freescale/fsl-ls2081a-rdb.dts | 161 ++++ + arch/arm64/boot/dts/freescale/fsl-ls2088a-qds.dts | 162 ++++ + arch/arm64/boot/dts/freescale/fsl-ls2088a-rdb.dts | 140 ++++ + arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi | 195 +++++ + arch/arm64/boot/dts/freescale/fsl-ls208xa-qds.dtsi | 198 +++++ + arch/arm64/boot/dts/freescale/fsl-ls208xa-rdb.dtsi | 161 ++++ + arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi | 910 +++++++++++++++++++++ + .../boot/dts/freescale/qoriq-bman1-portals.dtsi | 81 ++ + arch/arm64/boot/dts/freescale/qoriq-dpaa-eth.dtsi | 66 ++ + .../boot/dts/freescale/qoriq-fman3-0-10g-0.dtsi | 43 + + .../boot/dts/freescale/qoriq-fman3-0-10g-1.dtsi | 43 + + .../boot/dts/freescale/qoriq-fman3-0-1g-0.dtsi | 42 + + .../boot/dts/freescale/qoriq-fman3-0-1g-1.dtsi | 42 + + .../boot/dts/freescale/qoriq-fman3-0-1g-2.dtsi | 42 + + .../boot/dts/freescale/qoriq-fman3-0-1g-3.dtsi | 42 + + .../boot/dts/freescale/qoriq-fman3-0-1g-4.dtsi | 42 + + .../boot/dts/freescale/qoriq-fman3-0-1g-5.dtsi | 42 + + .../boot/dts/freescale/qoriq-fman3-0-6oh.dtsi | 47 ++ + arch/arm64/boot/dts/freescale/qoriq-fman3-0.dtsi | 130 +++ + .../boot/dts/freescale/qoriq-qman1-portals.dtsi | 104 +++ + arch/powerpc/boot/dts/fsl/qoriq-bman1-portals.dtsi | 10 + + arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0.dtsi | 4 +- + arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1.dtsi | 4 +- + 66 files changed, 7778 insertions(+), 1021 deletions(-) + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1043-post.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1043a-qds-sdk.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-usdpaa.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1046-post.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1046a-qds-sdk.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-usdpaa.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls2081a-rdb.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls2088a-qds.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls2088a-rdb.dts + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls208xa-qds.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls208xa-rdb.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/qoriq-bman1-portals.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/qoriq-dpaa-eth.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/qoriq-fman3-0-10g-0.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/qoriq-fman3-0-10g-1.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-0.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-1.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-2.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-3.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-4.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-5.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/qoriq-fman3-0-6oh.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/qoriq-fman3-0.dtsi + create mode 100644 arch/arm64/boot/dts/freescale/qoriq-qman1-portals.dtsi + +diff --git a/arch/arm/boot/dts/alpine.dtsi b/arch/arm/boot/dts/alpine.dtsi +index db8752fc..d0eefc3b 100644 +--- a/arch/arm/boot/dts/alpine.dtsi ++++ b/arch/arm/boot/dts/alpine.dtsi +@@ -93,7 +93,7 @@ + interrupt-controller; + reg = <0x0 0xfb001000 0x0 0x1000>, + <0x0 0xfb002000 0x0 0x2000>, +- <0x0 0xfb004000 0x0 0x1000>, ++ <0x0 0xfb004000 0x0 0x2000>, + <0x0 0xfb006000 0x0 0x2000>; + interrupts = + ; +diff --git a/arch/arm/boot/dts/axm55xx.dtsi b/arch/arm/boot/dts/axm55xx.dtsi +index a9d6d593..47799f59 100644 +--- a/arch/arm/boot/dts/axm55xx.dtsi ++++ b/arch/arm/boot/dts/axm55xx.dtsi +@@ -62,7 +62,7 @@ + #address-cells = <0>; + interrupt-controller; + reg = <0x20 0x01001000 0 0x1000>, +- <0x20 0x01002000 0 0x1000>, ++ <0x20 0x01002000 0 0x2000>, + <0x20 0x01004000 0 0x2000>, + <0x20 0x01006000 0 0x2000>; + interrupts = ; + reg = <0xfff11000 0x1000>, +- <0xfff12000 0x1000>, ++ <0xfff12000 0x2000>, + <0xfff14000 0x2000>, + <0xfff16000 0x2000>; + }; +diff --git a/arch/arm/boot/dts/imx6ul.dtsi b/arch/arm/boot/dts/imx6ul.dtsi +index c5c05fdc..c1396873 100644 +--- a/arch/arm/boot/dts/imx6ul.dtsi ++++ b/arch/arm/boot/dts/imx6ul.dtsi +@@ -89,11 +89,11 @@ + }; + + intc: interrupt-controller@00a01000 { +- compatible = "arm,cortex-a7-gic"; ++ compatible = "arm,gic-400", "arm,cortex-a7-gic"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x00a01000 0x1000>, +- <0x00a02000 0x1000>, ++ <0x00a02000 0x2000>, + <0x00a04000 0x2000>, + <0x00a06000 0x2000>; + }; +diff --git a/arch/arm/boot/dts/keystone.dtsi b/arch/arm/boot/dts/keystone.dtsi +index 02708ba2..e30c83fc 100644 +--- a/arch/arm/boot/dts/keystone.dtsi ++++ b/arch/arm/boot/dts/keystone.dtsi +@@ -30,12 +30,12 @@ + }; + + gic: interrupt-controller { +- compatible = "arm,cortex-a15-gic"; ++ compatible = "arm,gic-400", "arm,cortex-a15-gic"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x0 0x02561000 0x0 0x1000>, + <0x0 0x02562000 0x0 0x2000>, +- <0x0 0x02564000 0x0 0x1000>, ++ <0x0 0x02564000 0x0 0x2000>, + <0x0 0x02566000 0x0 0x2000>; + interrupts = ; +diff --git a/arch/arm/boot/dts/ls1021a-qds.dts b/arch/arm/boot/dts/ls1021a-qds.dts +index 94087531..5611a9c9 100644 +--- a/arch/arm/boot/dts/ls1021a-qds.dts ++++ b/arch/arm/boot/dts/ls1021a-qds.dts +@@ -124,6 +124,19 @@ + }; + }; + ++&qspi { ++ num-cs = <2>; ++ status = "okay"; ++ ++ qflash0: s25fl128s@0 { ++ compatible = "spansion,m25p80"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++}; ++ + &enet0 { + tbi-handle = <&tbi0>; + phy-handle = <&sgmii_phy1c>; +diff --git a/arch/arm/boot/dts/ls1021a-twr.dts b/arch/arm/boot/dts/ls1021a-twr.dts +index a8b148ad..907e5392 100644 +--- a/arch/arm/boot/dts/ls1021a-twr.dts ++++ b/arch/arm/boot/dts/ls1021a-twr.dts +@@ -142,6 +142,19 @@ + }; + }; + ++&qspi { ++ num-cs = <2>; ++ status = "okay"; ++ ++ qflash0: n25q128a13@0 { ++ compatible = "n25q128a13", "jedec,spi-nor"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++}; ++ + &enet0 { + tbi-handle = <&tbi1>; + phy-handle = <&sgmii_phy2>; +diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi +index 368e2193..def82fef 100644 +--- a/arch/arm/boot/dts/ls1021a.dtsi ++++ b/arch/arm/boot/dts/ls1021a.dtsi +@@ -74,17 +74,24 @@ + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <0xf00>; +- clocks = <&cluster1_clk>; ++ clocks = <&clockgen 1 0>; + }; + + cpu@f01 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <0xf01>; +- clocks = <&cluster1_clk>; ++ clocks = <&clockgen 1 0>; + }; + }; + ++ sysclk: sysclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <100000000>; ++ clock-output-names = "sysclk"; ++ }; ++ + timer { + compatible = "arm,armv7-timer"; + interrupts = , +@@ -108,11 +115,11 @@ + ranges; + + gic: interrupt-controller@1400000 { +- compatible = "arm,cortex-a7-gic"; ++ compatible = "arm,gic-400", "arm,cortex-a7-gic"; + #interrupt-cells = <3>; + interrupt-controller; + reg = <0x0 0x1401000 0x0 0x1000>, +- <0x0 0x1402000 0x0 0x1000>, ++ <0x0 0x1402000 0x0 0x2000>, + <0x0 0x1404000 0x0 0x2000>, + <0x0 0x1406000 0x0 0x2000>; + interrupts = ; +@@ -120,14 +127,14 @@ + }; + + msi1: msi-controller@1570e00 { +- compatible = "fsl,1s1021a-msi"; ++ compatible = "fsl,ls1021a-msi"; + reg = <0x0 0x1570e00 0x0 0x8>; + msi-controller; + interrupts = ; + }; + + msi2: msi-controller@1570e08 { +- compatible = "fsl,1s1021a-msi"; ++ compatible = "fsl,ls1021a-msi"; + reg = <0x0 0x1570e08 0x0 0x8>; + msi-controller; + interrupts = ; +@@ -137,11 +144,12 @@ + compatible = "fsl,ifc", "simple-bus"; + reg = <0x0 0x1530000 0x0 0x10000>; + interrupts = ; ++ big-endian; + }; + + dcfg: dcfg@1ee0000 { + compatible = "fsl,ls1021a-dcfg", "syscon"; +- reg = <0x0 0x1ee0000 0x0 0x10000>; ++ reg = <0x0 0x1ee0000 0x0 0x1000>; + big-endian; + }; + +@@ -163,7 +171,7 @@ + <0x0 0x20220520 0x0 0x4>; + reg-names = "ahci", "sata-ecc"; + interrupts = ; +- clocks = <&platform_clk 1>; ++ clocks = <&clockgen 4 1>; + dma-coherent; + status = "disabled"; + }; +@@ -214,41 +222,10 @@ + }; + + clockgen: clocking@1ee1000 { +- #address-cells = <1>; +- #size-cells = <1>; +- ranges = <0x0 0x0 0x1ee1000 0x10000>; +- +- sysclk: sysclk { +- compatible = "fixed-clock"; +- #clock-cells = <0>; +- clock-output-names = "sysclk"; +- }; +- +- cga_pll1: pll@800 { +- compatible = "fsl,qoriq-core-pll-2.0"; +- #clock-cells = <1>; +- reg = <0x800 0x10>; +- clocks = <&sysclk>; +- clock-output-names = "cga-pll1", "cga-pll1-div2", +- "cga-pll1-div4"; +- }; +- +- platform_clk: pll@c00 { +- compatible = "fsl,qoriq-core-pll-2.0"; +- #clock-cells = <1>; +- reg = <0xc00 0x10>; +- clocks = <&sysclk>; +- clock-output-names = "platform-clk", "platform-clk-div2"; +- }; +- +- cluster1_clk: clk0c0@0 { +- compatible = "fsl,qoriq-core-mux-2.0"; +- #clock-cells = <0>; +- reg = <0x0 0x10>; +- clock-names = "pll1cga", "pll1cga-div2", "pll1cga-div4"; +- clocks = <&cga_pll1 0>, <&cga_pll1 1>, <&cga_pll1 2>; +- clock-output-names = "cluster1-clk"; +- }; ++ compatible = "fsl,ls1021a-clockgen"; ++ reg = <0x0 0x1ee1000 0x0 0x1000>; ++ #clock-cells = <2>; ++ clocks = <&sysclk>; + }; + + dspi0: dspi@2100000 { +@@ -258,7 +235,7 @@ + reg = <0x0 0x2100000 0x0 0x10000>; + interrupts = ; + clock-names = "dspi"; +- clocks = <&platform_clk 1>; ++ clocks = <&clockgen 4 1>; + spi-num-chipselects = <6>; + big-endian; + status = "disabled"; +@@ -271,12 +248,27 @@ + reg = <0x0 0x2110000 0x0 0x10000>; + interrupts = ; + clock-names = "dspi"; +- clocks = <&platform_clk 1>; ++ clocks = <&clockgen 4 1>; + spi-num-chipselects = <6>; + big-endian; + status = "disabled"; + }; + ++ qspi: quadspi@1550000 { ++ compatible = "fsl,ls1021a-qspi"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x1550000 0x0 0x10000>, ++ <0x0 0x40000000 0x0 0x4000000>; ++ reg-names = "QuadSPI", "QuadSPI-memory"; ++ interrupts = ; ++ clock-names = "qspi_en", "qspi"; ++ clocks = <&clockgen 4 1>, <&clockgen 4 1>; ++ big-endian; ++ amba-base = <0x40000000>; ++ status = "disabled"; ++ }; ++ + i2c0: i2c@2180000 { + compatible = "fsl,vf610-i2c"; + #address-cells = <1>; +@@ -284,7 +276,7 @@ + reg = <0x0 0x2180000 0x0 0x10000>; + interrupts = ; + clock-names = "i2c"; +- clocks = <&platform_clk 1>; ++ clocks = <&clockgen 4 1>; + status = "disabled"; + }; + +@@ -295,7 +287,7 @@ + reg = <0x0 0x2190000 0x0 0x10000>; + interrupts = ; + clock-names = "i2c"; +- clocks = <&platform_clk 1>; ++ clocks = <&clockgen 4 1>; + status = "disabled"; + }; + +@@ -306,7 +298,7 @@ + reg = <0x0 0x21a0000 0x0 0x10000>; + interrupts = ; + clock-names = "i2c"; +- clocks = <&platform_clk 1>; ++ clocks = <&clockgen 4 1>; + status = "disabled"; + }; + +@@ -399,7 +391,7 @@ + compatible = "fsl,ls1021a-lpuart"; + reg = <0x0 0x2960000 0x0 0x1000>; + interrupts = ; +- clocks = <&platform_clk 1>; ++ clocks = <&clockgen 4 1>; + clock-names = "ipg"; + status = "disabled"; + }; +@@ -408,7 +400,7 @@ + compatible = "fsl,ls1021a-lpuart"; + reg = <0x0 0x2970000 0x0 0x1000>; + interrupts = ; +- clocks = <&platform_clk 1>; ++ clocks = <&clockgen 4 1>; + clock-names = "ipg"; + status = "disabled"; + }; +@@ -417,7 +409,7 @@ + compatible = "fsl,ls1021a-lpuart"; + reg = <0x0 0x2980000 0x0 0x1000>; + interrupts = ; +- clocks = <&platform_clk 1>; ++ clocks = <&clockgen 4 1>; + clock-names = "ipg"; + status = "disabled"; + }; +@@ -426,7 +418,7 @@ + compatible = "fsl,ls1021a-lpuart"; + reg = <0x0 0x2990000 0x0 0x1000>; + interrupts = ; +- clocks = <&platform_clk 1>; ++ clocks = <&clockgen 4 1>; + clock-names = "ipg"; + status = "disabled"; + }; +@@ -435,16 +427,26 @@ + compatible = "fsl,ls1021a-lpuart"; + reg = <0x0 0x29a0000 0x0 0x1000>; + interrupts = ; +- clocks = <&platform_clk 1>; ++ clocks = <&clockgen 4 1>; + clock-names = "ipg"; + status = "disabled"; + }; + ++ ftm0: ftm0@29d0000 { ++ compatible = "fsl,ftm-alarm"; ++ reg = <0x0 0x29d0000 0x0 0x10000>, ++ <0x0 0x1ee2140 0x0 0x4>; ++ reg-names = "ftm", "FlexTimer1"; ++ interrupts = ; ++ big-endian; ++ status = "okay"; ++ }; ++ + wdog0: watchdog@2ad0000 { + compatible = "fsl,imx21-wdt"; + reg = <0x0 0x2ad0000 0x0 0x10000>; + interrupts = ; +- clocks = <&platform_clk 1>; ++ clocks = <&clockgen 4 1>; + clock-names = "wdog-en"; + big-endian; + }; +@@ -454,8 +456,8 @@ + compatible = "fsl,vf610-sai"; + reg = <0x0 0x2b50000 0x0 0x10000>; + interrupts = ; +- clocks = <&platform_clk 1>, <&platform_clk 1>, +- <&platform_clk 1>, <&platform_clk 1>; ++ clocks = <&clockgen 4 1>, <&clockgen 4 1>, ++ <&clockgen 4 1>, <&clockgen 4 1>; + clock-names = "bus", "mclk1", "mclk2", "mclk3"; + dma-names = "tx", "rx"; + dmas = <&edma0 1 47>, +@@ -468,8 +470,8 @@ + compatible = "fsl,vf610-sai"; + reg = <0x0 0x2b60000 0x0 0x10000>; + interrupts = ; +- clocks = <&platform_clk 1>, <&platform_clk 1>, +- <&platform_clk 1>, <&platform_clk 1>; ++ clocks = <&clockgen 4 1>, <&clockgen 4 1>, ++ <&clockgen 4 1>, <&clockgen 4 1>; + clock-names = "bus", "mclk1", "mclk2", "mclk3"; + dma-names = "tx", "rx"; + dmas = <&edma0 1 45>, +@@ -489,16 +491,31 @@ + dma-channels = <32>; + big-endian; + clock-names = "dmamux0", "dmamux1"; +- clocks = <&platform_clk 1>, +- <&platform_clk 1>; ++ clocks = <&clockgen 4 1>, ++ <&clockgen 4 1>; ++ }; ++ ++ qdma: qdma@8390000 { ++ compatible = "fsl,ls1021a-qdma"; ++ reg = <0x0 0x8388000 0x0 0x1000>, /* Controller regs */ ++ <0x0 0x8389000 0x0 0x1000>, /* Status regs */ ++ <0x0 0x838a000 0x0 0x2000>; /* Block regs */ ++ interrupts = , ++ ; ++ interrupt-names = "qdma-error", "qdma-queue"; ++ channels = <8>; ++ queues = <2>; ++ status-sizes = <64>; ++ queue-sizes = <64 64>; ++ big-endian; + }; + + dcu: dcu@2ce0000 { + compatible = "fsl,ls1021a-dcu"; + reg = <0x0 0x2ce0000 0x0 0x10000>; + interrupts = ; +- clocks = <&platform_clk 0>, +- <&platform_clk 0>; ++ clocks = <&clockgen 4 0>, ++ <&clockgen 4 0>; + clock-names = "dcu", "pix"; + big-endian; + status = "disabled"; +@@ -626,6 +643,8 @@ + interrupts = ; + dr_mode = "host"; + snps,quirk-frame-length-adjustment = <0x20>; ++ configure-gfladj; ++ dma-coherent; + snps,dis_rxdet_inp3_quirk; + }; + +@@ -634,7 +653,9 @@ + reg = <0x00 0x03400000 0x0 0x00010000 /* controller registers */ + 0x40 0x00000000 0x0 0x00002000>; /* configuration space */ + reg-names = "regs", "config"; +- interrupts = ; /* controller interrupt */ ++ interrupts = , ++ ; /* aer interrupt */ ++ interrupt-names = "pme", "aer"; + fsl,pcie-scfg = <&scfg 0>; + #address-cells = <3>; + #size-cells = <2>; +@@ -643,7 +664,7 @@ + bus-range = <0x0 0xff>; + ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000 /* downstream I/O */ + 0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ +- msi-parent = <&msi1>; ++ msi-parent = <&msi1>, <&msi2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0000 0 0 1 &gic GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>, +@@ -657,7 +678,9 @@ + reg = <0x00 0x03500000 0x0 0x00010000 /* controller registers */ + 0x48 0x00000000 0x0 0x00002000>; /* configuration space */ + reg-names = "regs", "config"; +- interrupts = ; ++ interrupts = , ++ ; /* aer interrupt */ ++ interrupt-names = "pme", "aer"; + fsl,pcie-scfg = <&scfg 1>; + #address-cells = <3>; + #size-cells = <2>; +@@ -666,7 +689,7 @@ + bus-range = <0x0 0xff>; + ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000 /* downstream I/O */ + 0x82000000 0x0 0x40000000 0x48 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ +- msi-parent = <&msi2>; ++ msi-parent = <&msi1>, <&msi2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0000 0 0 1 &gic GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>, +diff --git a/arch/arm/boot/dts/mt6580.dtsi b/arch/arm/boot/dts/mt6580.dtsi +index 06fdf6c2..a349dba5 100644 +--- a/arch/arm/boot/dts/mt6580.dtsi ++++ b/arch/arm/boot/dts/mt6580.dtsi +@@ -91,7 +91,7 @@ + #interrupt-cells = <3>; + interrupt-parent = <&gic>; + reg = <0x10211000 0x1000>, +- <0x10212000 0x1000>, ++ <0x10212000 0x2000>, + <0x10214000 0x2000>, + <0x10216000 0x2000>; + }; +diff --git a/arch/arm/boot/dts/mt6589.dtsi b/arch/arm/boot/dts/mt6589.dtsi +index 88b3cb12..0d6f60af 100644 +--- a/arch/arm/boot/dts/mt6589.dtsi ++++ b/arch/arm/boot/dts/mt6589.dtsi +@@ -102,7 +102,7 @@ + #interrupt-cells = <3>; + interrupt-parent = <&gic>; + reg = <0x10211000 0x1000>, +- <0x10212000 0x1000>, ++ <0x10212000 0x2000>, + <0x10214000 0x2000>, + <0x10216000 0x2000>; + }; +diff --git a/arch/arm/boot/dts/mt8127.dtsi b/arch/arm/boot/dts/mt8127.dtsi +index 52086c80..916c095d 100644 +--- a/arch/arm/boot/dts/mt8127.dtsi ++++ b/arch/arm/boot/dts/mt8127.dtsi +@@ -129,7 +129,7 @@ + #interrupt-cells = <3>; + interrupt-parent = <&gic>; + reg = <0 0x10211000 0 0x1000>, +- <0 0x10212000 0 0x1000>, ++ <0 0x10212000 0 0x2000>, + <0 0x10214000 0 0x2000>, + <0 0x10216000 0 0x2000>; + }; +diff --git a/arch/arm/boot/dts/mt8135.dtsi b/arch/arm/boot/dts/mt8135.dtsi +index 1d7f92bd..a97b4ee4 100644 +--- a/arch/arm/boot/dts/mt8135.dtsi ++++ b/arch/arm/boot/dts/mt8135.dtsi +@@ -221,7 +221,7 @@ + #interrupt-cells = <3>; + interrupt-parent = <&gic>; + reg = <0 0x10211000 0 0x1000>, +- <0 0x10212000 0 0x1000>, ++ <0 0x10212000 0 0x2000>, + <0 0x10214000 0 0x2000>, + <0 0x10216000 0 0x2000>; + }; +diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi +index 17ec2e2d..559fc549 100644 +--- a/arch/arm/boot/dts/rk3288.dtsi ++++ b/arch/arm/boot/dts/rk3288.dtsi +@@ -1109,7 +1109,7 @@ + #address-cells = <0>; + + reg = <0xffc01000 0x1000>, +- <0xffc02000 0x1000>, ++ <0xffc02000 0x2000>, + <0xffc04000 0x2000>, + <0xffc06000 0x2000>; + interrupts = ; +diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi +index ce196045..97f28399 100644 +--- a/arch/arm/boot/dts/sun6i-a31.dtsi ++++ b/arch/arm/boot/dts/sun6i-a31.dtsi +@@ -791,7 +791,7 @@ + gic: interrupt-controller@01c81000 { + compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; + reg = <0x01c81000 0x1000>, +- <0x01c82000 0x1000>, ++ <0x01c82000 0x2000>, + <0x01c84000 0x2000>, + <0x01c86000 0x2000>; + interrupt-controller; +diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi +index 94cf5a1c..81e5a44c 100644 +--- a/arch/arm/boot/dts/sun7i-a20.dtsi ++++ b/arch/arm/boot/dts/sun7i-a20.dtsi +@@ -1685,9 +1685,9 @@ + }; + + gic: interrupt-controller@01c81000 { +- compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; ++ compatible = "arm,gic-400", "arm,cortex-a7-gic", "arm,cortex-a15-gic"; + reg = <0x01c81000 0x1000>, +- <0x01c82000 0x1000>, ++ <0x01c82000 0x2000>, + <0x01c84000 0x2000>, + <0x01c86000 0x2000>; + interrupt-controller; +diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi +index 300a1bd5..cdff5888 100644 +--- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi ++++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi +@@ -488,7 +488,7 @@ + gic: interrupt-controller@01c81000 { + compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; + reg = <0x01c81000 0x1000>, +- <0x01c82000 0x1000>, ++ <0x01c82000 0x2000>, + <0x01c84000 0x2000>, + <0x01c86000 0x2000>; + interrupt-controller; +diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi +index 3c5214cb..ba7e7c71 100644 +--- a/arch/arm/boot/dts/sun9i-a80.dtsi ++++ b/arch/arm/boot/dts/sun9i-a80.dtsi +@@ -613,7 +613,7 @@ + gic: interrupt-controller@01c41000 { + compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; + reg = <0x01c41000 0x1000>, +- <0x01c42000 0x1000>, ++ <0x01c42000 0x2000>, + <0x01c44000 0x2000>, + <0x01c46000 0x2000>; + interrupt-controller; +diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile +index 1b7783db..2d7986a1 100644 +--- a/arch/arm64/boot/dts/freescale/Makefile ++++ b/arch/arm64/boot/dts/freescale/Makefile +@@ -1,8 +1,24 @@ ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-frdm.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-qds.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-rdb.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds-sdk.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb-sdk.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb-usdpaa.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-qds.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-qds-sdk.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-sdk.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-usdpaa.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1088a-qds.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1088a-rdb.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-qds.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-rdb.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2081a-rdb.dtb + dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-simu.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2088a-qds.dtb ++dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2088a-rdb.dtb + + always := $(dtb-y) + subdir-y := $(dts-dirs) +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts b/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts +new file mode 100644 +index 00000000..e1274c18 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-frdm.dts +@@ -0,0 +1,134 @@ ++/* ++ * Device Tree file for Freescale LS1012A Freedom Board. ++ * ++ * Copyright 2016 Freescale Semiconductor, Inc. ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 "fsl-ls1012a.dtsi" ++ ++/ { ++ model = "LS1012A Freedom Board"; ++ compatible = "fsl,ls1012a-frdm", "fsl,ls1012a"; ++ ++ sys_mclk: clock-mclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <25000000>; ++ }; ++ ++ reg_1p8v: regulator-1p8v { ++ compatible = "regulator-fixed"; ++ regulator-name = "1P8V"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-always-on; ++ }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,format = "i2s"; ++ simple-audio-card,widgets = ++ "Microphone", "Microphone Jack", ++ "Headphone", "Headphone Jack", ++ "Speaker", "Speaker Ext", ++ "Line", "Line In Jack"; ++ simple-audio-card,routing = ++ "MIC_IN", "Microphone Jack", ++ "Microphone Jack", "Mic Bias", ++ "LINE_IN", "Line In Jack", ++ "Headphone Jack", "HP_OUT", ++ "Speaker Ext", "LINE_OUT"; ++ ++ simple-audio-card,cpu { ++ sound-dai = <&sai2>; ++ frame-master; ++ bitclock-master; ++ }; ++ ++ simple-audio-card,codec { ++ sound-dai = <&codec>; ++ frame-master; ++ bitclock-master; ++ system-clock-frequency = <25000000>; ++ }; ++ }; ++}; ++ ++&duart0 { ++ status = "okay"; ++}; ++ ++&i2c0 { ++ status = "okay"; ++ ++ codec: sgtl5000@a { ++ #sound-dai-cells = <0>; ++ compatible = "fsl,sgtl5000"; ++ reg = <0xa>; ++ VDDA-supply = <®_1p8v>; ++ VDDIO-supply = <®_1p8v>; ++ clocks = <&sys_mclk>; ++ }; ++}; ++ ++&qspi { ++ num-cs = <1>; ++ bus-num = <0>; ++ status = "okay"; ++ ++ qflash0: s25fs512s@0 { ++ compatible = "spansion,m25p80"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ m25p,fast-read; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++}; ++ ++&sai2 { ++ status = "okay"; ++}; ++ ++&sata { ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts +new file mode 100644 +index 00000000..1e1b2802 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-qds.dts +@@ -0,0 +1,155 @@ ++/* ++ * Device Tree file for Freescale LS1012A QDS Board. ++ * ++ * Copyright 2016 Freescale Semiconductor, Inc. ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 "fsl-ls1012a.dtsi" ++ ++/ { ++ model = "LS1012A QDS Board"; ++ compatible = "fsl,ls1012a-qds", "fsl,ls1012a"; ++ ++ sys_mclk: clock-mclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <24576000>; ++ }; ++ ++ reg_3p3v: regulator-3p3v { ++ compatible = "regulator-fixed"; ++ regulator-name = "3P3V"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-always-on; ++ }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,format = "i2s"; ++ simple-audio-card,widgets = ++ "Microphone", "Microphone Jack", ++ "Headphone", "Headphone Jack", ++ "Speaker", "Speaker Ext", ++ "Line", "Line In Jack"; ++ simple-audio-card,routing = ++ "MIC_IN", "Microphone Jack", ++ "Microphone Jack", "Mic Bias", ++ "LINE_IN", "Line In Jack", ++ "Headphone Jack", "HP_OUT", ++ "Speaker Ext", "LINE_OUT"; ++ ++ simple-audio-card,cpu { ++ sound-dai = <&sai2>; ++ frame-master; ++ bitclock-master; ++ }; ++ ++ simple-audio-card,codec { ++ sound-dai = <&codec>; ++ frame-master; ++ bitclock-master; ++ system-clock-frequency = <24576000>; ++ }; ++ }; ++}; ++ ++&duart0 { ++ status = "okay"; ++}; ++ ++&i2c0 { ++ status = "okay"; ++ ++ pca9547@77 { ++ compatible = "nxp,pca9547"; ++ reg = <0x77>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ i2c@4 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x4>; ++ ++ codec: sgtl5000@a { ++ #sound-dai-cells = <0>; ++ compatible = "fsl,sgtl5000"; ++ reg = <0xa>; ++ VDDA-supply = <®_3p3v>; ++ VDDIO-supply = <®_3p3v>; ++ clocks = <&sys_mclk>; ++ }; ++ }; ++ }; ++}; ++ ++&qspi { ++ num-cs = <2>; ++ bus-num = <0>; ++ status = "okay"; ++ ++ qflash0: s25fs512s@0 { ++ compatible = "spansion,m25p80"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ spi-max-frequency = <20000000>; ++ m25p,fast-read; ++ reg = <0>; ++ }; ++}; ++ ++&sai2 { ++ status = "okay"; ++}; ++ ++&sata { ++ status = "okay"; ++}; ++ ++&esdhc0 { ++ status = "okay"; ++}; ++ ++&esdhc1 { ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts +new file mode 100644 +index 00000000..90bd2307 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts +@@ -0,0 +1,91 @@ ++/* ++ * Device Tree file for Freescale LS1012A RDB Board. ++ * ++ * Copyright 2016 Freescale Semiconductor, Inc. ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 "fsl-ls1012a.dtsi" ++ ++/ { ++ model = "LS1012A RDB Board"; ++ compatible = "fsl,ls1012a-rdb", "fsl,ls1012a"; ++}; ++ ++&duart0 { ++ status = "okay"; ++}; ++ ++&i2c0 { ++ status = "okay"; ++}; ++ ++&qspi { ++ num-cs = <2>; ++ bus-num = <0>; ++ status = "okay"; ++ ++ qflash0: s25fs512s@0 { ++ compatible = "spansion,m25p80"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ spi-max-frequency = <20000000>; ++ m25p,fast-read; ++ reg = <0>; ++ }; ++}; ++ ++&sata { ++ status = "okay"; ++}; ++ ++&esdhc0 { ++ sd-uhs-sdr104; ++ sd-uhs-sdr50; ++ sd-uhs-sdr25; ++ sd-uhs-sdr12; ++ status = "okay"; ++}; ++ ++&esdhc1 { ++ mmc-hs200-1_8v; ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi +new file mode 100644 +index 00000000..9ede9d52 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi +@@ -0,0 +1,517 @@ ++/* ++ * Device Tree Include file for Freescale Layerscape-1012A family SoC. ++ * ++ * Copyright 2016 Freescale Semiconductor, Inc. ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 ++#include ++ ++/ { ++ compatible = "fsl,ls1012a"; ++ interrupt-parent = <&gic>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ aliases { ++ crypto = &crypto; ++ rtic_a = &rtic_a; ++ rtic_b = &rtic_b; ++ rtic_c = &rtic_c; ++ rtic_d = &rtic_d; ++ sec_mon = &sec_mon; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53"; ++ reg = <0x0>; ++ clocks = <&clockgen 1 0>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ }; ++ ++ idle-states { ++ /* ++ * PSCI node is not added default, U-boot will add missing ++ * parts if it determines to use PSCI. ++ */ ++ entry-method = "arm,psci"; ++ ++ CPU_PH20: cpu-ph20 { ++ compatible = "arm,idle-state"; ++ idle-state-name = "PH20"; ++ arm,psci-suspend-param = <0x0>; ++ entry-latency-us = <1000>; ++ exit-latency-us = <1000>; ++ min-residency-us = <3000>; ++ }; ++ }; ++ ++ sysclk: sysclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <125000000>; ++ clock-output-names = "sysclk"; ++ }; ++ ++ coreclk: coreclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <100000000>; ++ clock-output-names = "coreclk"; ++ }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupts = <1 13 IRQ_TYPE_LEVEL_LOW>,/* Physical Secure PPI */ ++ <1 14 IRQ_TYPE_LEVEL_LOW>,/* Physical Non-Secure PPI */ ++ <1 11 IRQ_TYPE_LEVEL_LOW>,/* Virtual PPI */ ++ <1 10 IRQ_TYPE_LEVEL_LOW>;/* Hypervisor PPI */ ++ }; ++ ++ pmu { ++ compatible = "arm,armv8-pmuv3"; ++ interrupts = <0 106 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ ++ gic: interrupt-controller@1400000 { ++ compatible = "arm,gic-400"; ++ #interrupt-cells = <3>; ++ interrupt-controller; ++ reg = <0x0 0x1401000 0 0x1000>, /* GICD */ ++ <0x0 0x1402000 0 0x2000>, /* GICC */ ++ <0x0 0x1404000 0 0x2000>, /* GICH */ ++ <0x0 0x1406000 0 0x2000>; /* GICV */ ++ interrupts = <1 9 IRQ_TYPE_LEVEL_LOW>; ++ }; ++ ++ reboot { ++ compatible = "syscon-reboot"; ++ regmap = <&dcfg>; ++ offset = <0xb0>; ++ mask = <0x02>; ++ }; ++ ++ soc { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ scfg: scfg@1570000 { ++ compatible = "fsl,ls1012a-scfg", "syscon"; ++ reg = <0x0 0x1570000 0x0 0x10000>; ++ big-endian; ++ }; ++ ++ crypto: crypto@1700000 { ++ compatible = "fsl,sec-v5.4", "fsl,sec-v5.0", ++ "fsl,sec-v4.0"; ++ fsl,sec-era = <8>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0x0 0x00 0x1700000 0x100000>; ++ reg = <0x00 0x1700000 0x0 0x100000>; ++ interrupts = ; ++ ++ sec_jr0: jr@10000 { ++ compatible = "fsl,sec-v5.4-job-ring", ++ "fsl,sec-v5.0-job-ring", ++ "fsl,sec-v4.0-job-ring"; ++ reg = <0x10000 0x10000>; ++ interrupts = ; ++ }; ++ ++ sec_jr1: jr@20000 { ++ compatible = "fsl,sec-v5.4-job-ring", ++ "fsl,sec-v5.0-job-ring", ++ "fsl,sec-v4.0-job-ring"; ++ reg = <0x20000 0x10000>; ++ interrupts = ; ++ }; ++ ++ sec_jr2: jr@30000 { ++ compatible = "fsl,sec-v5.4-job-ring", ++ "fsl,sec-v5.0-job-ring", ++ "fsl,sec-v4.0-job-ring"; ++ reg = <0x30000 0x10000>; ++ interrupts = ; ++ }; ++ ++ sec_jr3: jr@40000 { ++ compatible = "fsl,sec-v5.4-job-ring", ++ "fsl,sec-v5.0-job-ring", ++ "fsl,sec-v4.0-job-ring"; ++ reg = <0x40000 0x10000>; ++ interrupts = ; ++ }; ++ ++ rtic@60000 { ++ compatible = "fsl,sec-v5.4-rtic", ++ "fsl,sec-v5.0-rtic", ++ "fsl,sec-v4.0-rtic"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x60000 0x100 0x60e00 0x18>; ++ ranges = <0x0 0x60100 0x500>; ++ ++ rtic_a: rtic-a@0 { ++ compatible = "fsl,sec-v5.4-rtic-memory", ++ "fsl,sec-v5.0-rtic-memory", ++ "fsl,sec-v4.0-rtic-memory"; ++ reg = <0x00 0x20 0x100 0x100>; ++ }; ++ ++ rtic_b: rtic-b@20 { ++ compatible = "fsl,sec-v5.4-rtic-memory", ++ "fsl,sec-v5.0-rtic-memory", ++ "fsl,sec-v4.0-rtic-memory"; ++ reg = <0x20 0x20 0x200 0x100>; ++ }; ++ ++ rtic_c: rtic-c@40 { ++ compatible = "fsl,sec-v5.4-rtic-memory", ++ "fsl,sec-v5.0-rtic-memory", ++ "fsl,sec-v4.0-rtic-memory"; ++ reg = <0x40 0x20 0x300 0x100>; ++ }; ++ ++ rtic_d: rtic-d@60 { ++ compatible = "fsl,sec-v5.4-rtic-memory", ++ "fsl,sec-v5.0-rtic-memory", ++ "fsl,sec-v4.0-rtic-memory"; ++ reg = <0x60 0x20 0x400 0x100>; ++ }; ++ }; ++ }; ++ ++ sec_mon: sec_mon@1e90000 { ++ compatible = "fsl,sec-v5.4-mon", "fsl,sec-v5.0-mon", ++ "fsl,sec-v4.0-mon"; ++ reg = <0x0 0x1e90000 0x0 0x10000>; ++ interrupts = , ++ ; ++ }; ++ ++ dcfg: dcfg@1ee0000 { ++ compatible = "fsl,ls1012a-dcfg", ++ "syscon"; ++ reg = <0x0 0x1ee0000 0x0 0x10000>; ++ big-endian; ++ }; ++ ++ clockgen: clocking@1ee1000 { ++ compatible = "fsl,ls1012a-clockgen"; ++ reg = <0x0 0x1ee1000 0x0 0x1000>; ++ #clock-cells = <2>; ++ clocks = <&sysclk &coreclk>; ++ clock-names = "sysclk", "coreclk"; ++ }; ++ ++ tmu: tmu@1f00000 { ++ compatible = "fsl,qoriq-tmu"; ++ reg = <0x0 0x1f00000 0x0 0x10000>; ++ interrupts = <0 33 0x4>; ++ fsl,tmu-range = <0xb0000 0x9002a 0x6004c 0x30062>; ++ fsl,tmu-calibration = <0x00000000 0x00000026 ++ 0x00000001 0x0000002d ++ 0x00000002 0x00000032 ++ 0x00000003 0x00000039 ++ 0x00000004 0x0000003f ++ 0x00000005 0x00000046 ++ 0x00000006 0x0000004d ++ 0x00000007 0x00000054 ++ 0x00000008 0x0000005a ++ 0x00000009 0x00000061 ++ 0x0000000a 0x0000006a ++ 0x0000000b 0x00000071 ++ ++ 0x00010000 0x00000025 ++ 0x00010001 0x0000002c ++ 0x00010002 0x00000035 ++ 0x00010003 0x0000003d ++ 0x00010004 0x00000045 ++ 0x00010005 0x0000004e ++ 0x00010006 0x00000057 ++ 0x00010007 0x00000061 ++ 0x00010008 0x0000006b ++ 0x00010009 0x00000076 ++ ++ 0x00020000 0x00000029 ++ 0x00020001 0x00000033 ++ 0x00020002 0x0000003d ++ 0x00020003 0x00000049 ++ 0x00020004 0x00000056 ++ 0x00020005 0x00000061 ++ 0x00020006 0x0000006d ++ ++ 0x00030000 0x00000021 ++ 0x00030001 0x0000002a ++ 0x00030002 0x0000003c ++ 0x00030003 0x0000004e>; ++ big-endian; ++ #thermal-sensor-cells = <1>; ++ }; ++ ++ thermal-zones { ++ cpu_thermal: cpu-thermal { ++ polling-delay-passive = <1000>; ++ polling-delay = <5000>; ++ thermal-sensors = <&tmu 0>; ++ ++ trips { ++ cpu_alert: cpu-alert { ++ temperature = <85000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ ++ cpu_crit: cpu-crit { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map0 { ++ trip = <&cpu_alert>; ++ cooling-device = ++ <&cpu0 THERMAL_NO_LIMIT ++ THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ }; ++ ++ esdhc0: esdhc@1560000 { ++ compatible = "fsl,ls1012a-esdhc", "fsl,esdhc"; ++ reg = <0x0 0x1560000 0x0 0x10000>; ++ interrupts = <0 62 0x4>; ++ clocks = <&clockgen 4 0>; ++ voltage-ranges = <1800 1800 3300 3300>; ++ sdhci,auto-cmd12; ++ big-endian; ++ bus-width = <4>; ++ status = "disabled"; ++ }; ++ ++ esdhc1: esdhc@1580000 { ++ compatible = "fsl,ls1012a-esdhc", "fsl,esdhc"; ++ reg = <0x0 0x1580000 0x0 0x10000>; ++ interrupts = <0 65 0x4>; ++ clocks = <&clockgen 4 0>; ++ voltage-ranges = <1800 1800 3300 3300>; ++ sdhci,auto-cmd12; ++ big-endian; ++ broken-cd; ++ bus-width = <4>; ++ status = "disabled"; ++ }; ++ ++ ftm0: ftm0@29d0000 { ++ compatible = "fsl,ftm-alarm"; ++ reg = <0x0 0x29d0000 0x0 0x10000>, ++ <0x0 0x1ee2140 0x0 0x4>; ++ reg-names = "ftm", "FlexTimer1"; ++ interrupts = <0 86 0x4>; ++ big-endian; ++ }; ++ ++ i2c0: i2c@2180000 { ++ compatible = "fsl,vf610-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x2180000 0x0 0x10000>; ++ interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clockgen 4 0>; ++ status = "disabled"; ++ }; ++ ++ i2c1: i2c@2190000 { ++ compatible = "fsl,vf610-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x2190000 0x0 0x10000>; ++ interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clockgen 4 0>; ++ status = "disabled"; ++ }; ++ ++ duart0: serial@21c0500 { ++ compatible = "fsl,ns16550", "ns16550a"; ++ reg = <0x00 0x21c0500 0x0 0x100>; ++ interrupts = <0 54 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clockgen 4 0>; ++ status = "disabled"; ++ }; ++ ++ duart1: serial@21c0600 { ++ compatible = "fsl,ns16550", "ns16550a"; ++ reg = <0x00 0x21c0600 0x0 0x100>; ++ interrupts = <0 54 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clockgen 4 0>; ++ status = "disabled"; ++ }; ++ ++ gpio0: gpio@2300000 { ++ compatible = "fsl,qoriq-gpio"; ++ reg = <0x0 0x2300000 0x0 0x10000>; ++ interrupts = <0 66 IRQ_TYPE_LEVEL_HIGH>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio1: gpio@2310000 { ++ compatible = "fsl,qoriq-gpio"; ++ reg = <0x0 0x2310000 0x0 0x10000>; ++ interrupts = <0 67 IRQ_TYPE_LEVEL_HIGH>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ qspi: quadspi@1550000 { ++ compatible = "fsl,ls1012a-qspi", "fsl,ls1021a-qspi"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x1550000 0x0 0x10000>, ++ <0x0 0x40000000 0x0 0x10000000>; ++ reg-names = "QuadSPI", "QuadSPI-memory"; ++ interrupts = <0 99 IRQ_TYPE_LEVEL_HIGH>; ++ clock-names = "qspi_en", "qspi"; ++ clocks = <&clockgen 4 0>, <&clockgen 4 0>; ++ big-endian; ++ fsl,qspi-has-second-chip; ++ status = "disabled"; ++ }; ++ ++ wdog0: wdog@2ad0000 { ++ compatible = "fsl,ls1012a-wdt", ++ "fsl,imx21-wdt"; ++ reg = <0x0 0x2ad0000 0x0 0x10000>; ++ interrupts = <0 83 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clockgen 4 0>; ++ big-endian; ++ }; ++ ++ sai1: sai@2b50000 { ++ #sound-dai-cells = <0>; ++ compatible = "fsl,vf610-sai"; ++ reg = <0x0 0x2b50000 0x0 0x10000>; ++ interrupts = <0 148 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>, ++ <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "bus", "mclk1", "mclk2", "mclk3"; ++ dma-names = "tx", "rx"; ++ dmas = <&edma0 1 47>, ++ <&edma0 1 46>; ++ status = "disabled"; ++ }; ++ ++ sai2: sai@2b60000 { ++ #sound-dai-cells = <0>; ++ compatible = "fsl,vf610-sai"; ++ reg = <0x0 0x2b60000 0x0 0x10000>; ++ interrupts = <0 149 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>, ++ <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "bus", "mclk1", "mclk2", "mclk3"; ++ dma-names = "tx", "rx"; ++ dmas = <&edma0 1 45>, ++ <&edma0 1 44>; ++ status = "disabled"; ++ }; ++ ++ edma0: edma@2c00000 { ++ #dma-cells = <2>; ++ compatible = "fsl,vf610-edma"; ++ reg = <0x0 0x2c00000 0x0 0x10000>, ++ <0x0 0x2c10000 0x0 0x10000>, ++ <0x0 0x2c20000 0x0 0x10000>; ++ interrupts = <0 103 IRQ_TYPE_LEVEL_HIGH>, ++ <0 103 IRQ_TYPE_LEVEL_HIGH>; ++ interrupt-names = "edma-tx", "edma-err"; ++ dma-channels = <32>; ++ big-endian; ++ clock-names = "dmamux0", "dmamux1"; ++ clocks = <&clockgen 4 3>, ++ <&clockgen 4 3>; ++ }; ++ ++ usb0: usb3@2f00000 { ++ compatible = "snps,dwc3"; ++ reg = <0x0 0x2f00000 0x0 0x10000>; ++ interrupts = <0 60 0x4>; ++ dr_mode = "host"; ++ snps,quirk-frame-length-adjustment = <0x20>; ++ snps,dis_rxdet_inp3_quirk; ++ }; ++ ++ usb1: usb2@8600000 { ++ compatible = "fsl-usb2-dr-v2.5", "fsl-usb2-dr"; ++ reg = <0x0 0x8600000 0x0 0x1000>; ++ interrupts = <0 139 0x4>; ++ dr_mode = "host"; ++ phy_type = "ulpi"; ++ }; ++ ++ sata: sata@3200000 { ++ compatible = "fsl,ls1012a-ahci", "fsl,ls1043a-ahci"; ++ reg = <0x0 0x3200000 0x0 0x10000>, ++ <0x0 0x20140520 0x0 0x4>; ++ reg-names = "ahci", "sata-ecc"; ++ interrupts = <0 69 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clockgen 4 0>; ++ dma-coherent; ++ status = "disabled"; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043-post.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043-post.dtsi +new file mode 100644 +index 00000000..169e1714 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043-post.dtsi +@@ -0,0 +1,45 @@ ++/* ++ * QorIQ FMan v3 device tree nodes for ls1043 ++ * ++ * Copyright 2015-2016 Freescale Semiconductor Inc. ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++ */ ++ ++&soc { ++ ++/* include used FMan blocks */ ++#include "qoriq-fman3-0.dtsi" ++#include "qoriq-fman3-0-1g-0.dtsi" ++#include "qoriq-fman3-0-1g-1.dtsi" ++#include "qoriq-fman3-0-1g-2.dtsi" ++#include "qoriq-fman3-0-1g-3.dtsi" ++#include "qoriq-fman3-0-1g-4.dtsi" ++#include "qoriq-fman3-0-1g-5.dtsi" ++#include "qoriq-fman3-0-10g-0.dtsi" ++ ++}; ++ ++&fman0 { ++ /* these aliases provide the FMan ports mapping */ ++ enet0: ethernet@e0000 { ++ }; ++ ++ enet1: ethernet@e2000 { ++ }; ++ ++ enet2: ethernet@e4000 { ++ }; ++ ++ enet3: ethernet@e6000 { ++ }; ++ ++ enet4: ethernet@e8000 { ++ }; ++ ++ enet5: ethernet@ea000 { ++ }; ++ ++ enet6: ethernet@f0000 { ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds-sdk.dts b/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds-sdk.dts +new file mode 100644 +index 00000000..6c13b416 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds-sdk.dts +@@ -0,0 +1,69 @@ ++/* ++ * Device Tree Include file for Freescale Layerscape-1043A family SoC. ++ * ++ * Copyright 2014-2015 Freescale Semiconductor, Inc. ++ * ++ * Mingkai Hu ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 "fsl-ls1043a-qds.dts" ++ ++&bman_fbpr { ++ compatible = "fsl,bman-fbpr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_fqd { ++ compatible = "fsl,qman-fqd"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_pfdr { ++ compatible = "fsl,qman-pfdr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++ ++&soc { ++#include "qoriq-dpaa-eth.dtsi" ++#include "qoriq-fman3-0-6oh.dtsi" ++}; ++ ++&fman0 { ++ compatible = "fsl,fman", "simple-bus"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts +index dd9e9194..08abff73 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-qds.dts +@@ -1,7 +1,7 @@ + /* + * Device Tree Include file for Freescale Layerscape-1043A family SoC. + * +- * Copyright 2014-2015, Freescale Semiconductor ++ * Copyright 2014-2015 Freescale Semiconductor, Inc. + * + * Mingkai Hu + * +@@ -45,7 +45,7 @@ + */ + + /dts-v1/; +-/include/ "fsl-ls1043a.dtsi" ++#include "fsl-ls1043a.dtsi" + + / { + model = "LS1043A QDS Board"; +@@ -60,6 +60,22 @@ + serial1 = &duart1; + serial2 = &duart2; + serial3 = &duart3; ++ sgmii_riser_s1_p1 = &sgmii_phy_s1_p1; ++ sgmii_riser_s2_p1 = &sgmii_phy_s2_p1; ++ sgmii_riser_s3_p1 = &sgmii_phy_s3_p1; ++ sgmii_riser_s4_p1 = &sgmii_phy_s4_p1; ++ qsgmii_s1_p1 = &qsgmii_phy_s1_p1; ++ qsgmii_s1_p2 = &qsgmii_phy_s1_p2; ++ qsgmii_s1_p3 = &qsgmii_phy_s1_p3; ++ qsgmii_s1_p4 = &qsgmii_phy_s1_p4; ++ qsgmii_s2_p1 = &qsgmii_phy_s2_p1; ++ qsgmii_s2_p2 = &qsgmii_phy_s2_p2; ++ qsgmii_s2_p3 = &qsgmii_phy_s2_p3; ++ qsgmii_s2_p4 = &qsgmii_phy_s2_p4; ++ emi1_slot1 = &ls1043mdio_s1; ++ emi1_slot2 = &ls1043mdio_s2; ++ emi1_slot3 = &ls1043mdio_s3; ++ emi1_slot4 = &ls1043mdio_s4; + }; + + chosen { +@@ -97,8 +113,11 @@ + }; + + fpga: board-control@2,0 { +- compatible = "fsl,ls1043aqds-fpga", "fsl,fpga-qixis"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "fsl,ls1043aqds-fpga", "fsl,fpga-qixis", "simple-bus"; + reg = <0x2 0x0 0x0000100>; ++ ranges = <0 2 0 0x100>; + }; + }; + +@@ -181,3 +200,149 @@ + reg = <0>; + }; + }; ++ ++#include "fsl-ls1043-post.dtsi" ++ ++&fman0 { ++ ethernet@e0000 { ++ phy-handle = <&qsgmii_phy_s2_p1>; ++ phy-connection-type = "sgmii"; ++ }; ++ ++ ethernet@e2000 { ++ phy-handle = <&qsgmii_phy_s2_p2>; ++ phy-connection-type = "sgmii"; ++ }; ++ ++ ethernet@e4000 { ++ phy-handle = <&rgmii_phy1>; ++ phy-connection-type = "rgmii"; ++ }; ++ ++ ethernet@e6000 { ++ phy-handle = <&rgmii_phy2>; ++ phy-connection-type = "rgmii"; ++ }; ++ ++ ethernet@e8000 { ++ phy-handle = <&qsgmii_phy_s2_p3>; ++ phy-connection-type = "sgmii"; ++ }; ++ ++ ethernet@ea000 { ++ phy-handle = <&qsgmii_phy_s2_p4>; ++ phy-connection-type = "sgmii"; ++ }; ++ ++ ethernet@f0000 { /* DTSEC9/10GEC1 */ ++ fixed-link = <1 1 10000 0 0>; ++ phy-connection-type = "xgmii"; ++ }; ++}; ++ ++&fpga { ++ mdio-mux-emi1 { ++ compatible = "mdio-mux-mmioreg", "mdio-mux"; ++ mdio-parent-bus = <&mdio0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x54 1>; /* BRDCFG4 */ ++ mux-mask = <0xe0>; /* EMI1 */ ++ ++ /* On-board RGMII1 PHY */ ++ ls1043mdio0: mdio@0 { ++ reg = <0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ rgmii_phy1: ethernet-phy@1 { /* MAC3 */ ++ reg = <0x1>; ++ }; ++ }; ++ ++ /* On-board RGMII2 PHY */ ++ ls1043mdio1: mdio@1 { ++ reg = <0x20>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ rgmii_phy2: ethernet-phy@2 { /* MAC4 */ ++ reg = <0x2>; ++ }; ++ }; ++ ++ /* Slot 1 */ ++ ls1043mdio_s1: mdio@2 { ++ reg = <0x40>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ ++ qsgmii_phy_s1_p1: ethernet-phy@4 { ++ reg = <0x4>; ++ }; ++ qsgmii_phy_s1_p2: ethernet-phy@5 { ++ reg = <0x5>; ++ }; ++ qsgmii_phy_s1_p3: ethernet-phy@6 { ++ reg = <0x6>; ++ }; ++ qsgmii_phy_s1_p4: ethernet-phy@7 { ++ reg = <0x7>; ++ }; ++ ++ sgmii_phy_s1_p1: ethernet-phy@1c { ++ reg = <0x1c>; ++ }; ++ }; ++ ++ /* Slot 2 */ ++ ls1043mdio_s2: mdio@3 { ++ reg = <0x60>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ ++ qsgmii_phy_s2_p1: ethernet-phy@8 { ++ reg = <0x8>; ++ }; ++ qsgmii_phy_s2_p2: ethernet-phy@9 { ++ reg = <0x9>; ++ }; ++ qsgmii_phy_s2_p3: ethernet-phy@a { ++ reg = <0xa>; ++ }; ++ qsgmii_phy_s2_p4: ethernet-phy@b { ++ reg = <0xb>; ++ }; ++ ++ sgmii_phy_s2_p1: ethernet-phy@1c { ++ reg = <0x1c>; ++ }; ++ }; ++ ++ /* Slot 3 */ ++ ls1043mdio_s3: mdio@4 { ++ reg = <0x80>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ ++ sgmii_phy_s3_p1: ethernet-phy@1c { ++ reg = <0x1c>; ++ }; ++ }; ++ ++ /* Slot 4 */ ++ ls1043mdio_s4: mdio@5 { ++ reg = <0xa0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ ++ sgmii_phy_s4_p1: ethernet-phy@1c { ++ reg = <0x1c>; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk.dts b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk.dts +new file mode 100644 +index 00000000..ac4b9a41 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk.dts +@@ -0,0 +1,69 @@ ++/* ++ * Device Tree Include file for Freescale Layerscape-1043A family SoC. ++ * ++ * Copyright 2014-2015 Freescale Semiconductor, Inc. ++ * ++ * Mingkai Hu ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 "fsl-ls1043a-rdb.dts" ++ ++&bman_fbpr { ++ compatible = "fsl,bman-fbpr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_fqd { ++ compatible = "fsl,qman-fqd"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_pfdr { ++ compatible = "fsl,qman-pfdr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++ ++&soc { ++#include "qoriq-dpaa-eth.dtsi" ++#include "qoriq-fman3-0-6oh.dtsi" ++}; ++ ++&fman0 { ++ compatible = "fsl,fman", "simple-bus"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-usdpaa.dts b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-usdpaa.dts +new file mode 100644 +index 00000000..4e46a0a5 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-usdpaa.dts +@@ -0,0 +1,117 @@ ++/* ++ * Device Tree Include file for Freescale Layerscape-1043A family SoC. ++ * ++ * Copyright 2014-2015 Freescale Semiconductor, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include "fsl-ls1043a-rdb-sdk.dts" ++ ++&soc { ++ bp7: buffer-pool@7 { ++ compatible = "fsl,p4080-bpool", "fsl,bpool"; ++ fsl,bpid = <7>; ++ fsl,bpool-ethernet-cfg = <0 0 0 192 0 0xdeadbeef>; ++ fsl,bpool-thresholds = <0x400 0xc00 0x0 0x0>; ++ }; ++ ++ bp8: buffer-pool@8 { ++ compatible = "fsl,p4080-bpool", "fsl,bpool"; ++ fsl,bpid = <8>; ++ fsl,bpool-ethernet-cfg = <0 0 0 576 0 0xabbaf00d>; ++ fsl,bpool-thresholds = <0x100 0x300 0x0 0x0>; ++ }; ++ ++ bp9: buffer-pool@9 { ++ compatible = "fsl,p4080-bpool", "fsl,bpool"; ++ fsl,bpid = <9>; ++ fsl,bpool-ethernet-cfg = <0 0 0 2048 0 0xfeedabba>; ++ fsl,bpool-thresholds = <0x100 0x300 0x0 0x0>; ++ }; ++ ++ fsl,dpaa { ++ compatible = "fsl,ls1043a", "fsl,dpaa", "simple-bus"; ++ ++ ethernet@0 { ++ compatible = "fsl,dpa-ethernet-init"; ++ fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>; ++ fsl,qman-frame-queues-rx = <0x50 1 0x51 1>; ++ fsl,qman-frame-queues-tx = <0x70 1 0x71 1>; ++ }; ++ ++ ethernet@1 { ++ compatible = "fsl,dpa-ethernet-init"; ++ fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>; ++ fsl,qman-frame-queues-rx = <0x52 1 0x53 1>; ++ fsl,qman-frame-queues-tx = <0x72 1 0x73 1>; ++ }; ++ ++ ethernet@2 { ++ compatible = "fsl,dpa-ethernet-init"; ++ fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>; ++ fsl,qman-frame-queues-rx = <0x54 1 0x55 1>; ++ fsl,qman-frame-queues-tx = <0x74 1 0x75 1>; ++ }; ++ ++ ethernet@3 { ++ compatible = "fsl,dpa-ethernet-init"; ++ fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>; ++ fsl,qman-frame-queues-rx = <0x56 1 0x57 1>; ++ fsl,qman-frame-queues-tx = <0x76 1 0x77 1>; ++ }; ++ ++ ethernet@4 { ++ compatible = "fsl,dpa-ethernet-init"; ++ fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>; ++ fsl,qman-frame-queues-rx = <0x58 1 0x59 1>; ++ fsl,qman-frame-queues-tx = <0x78 1 0x79 1>; ++ }; ++ ++ ethernet@5 { ++ compatible = "fsl,dpa-ethernet-init"; ++ fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>; ++ fsl,qman-frame-queues-rx = <0x60 1 0x61 1>; ++ fsl,qman-frame-queues-tx = <0x80 1 0x81 1>; ++ }; ++ ++ ethernet@8 { ++ compatible = "fsl,dpa-ethernet-init"; ++ fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>; ++ fsl,qman-frame-queues-rx = <0x5c 1 0x5d 1>; ++ fsl,qman-frame-queues-tx = <0x7c 1 0x7d 1>; ++ ++ }; ++ dpa-fman0-oh@2 { ++ compatible = "fsl,dpa-oh"; ++ /* Define frame queues for the OH port*/ ++ /* */ ++ fsl,qman-frame-queues-oh = <0x5a 1 0x5b 1>; ++ fsl,fman-oh-port = <&fman0_oh2>; ++ }; ++ }; ++}; ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ usdpaa_mem: usdpaa_mem { ++ compatible = "fsl,usdpaa-mem"; ++ alloc-ranges = <0 0 0x10000 0>; ++ size = <0 0x10000000>; ++ alignment = <0 0x10000000>; ++ }; ++ }; ++}; ++ ++&fman0 { ++ fman0_oh2: port@83000 { ++ cell-index = <1>; ++ compatible = "fsl,fman-port-oh"; ++ reg = <0x83000 0x1000>; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts +index d2313e05..f92ae325 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts +@@ -1,7 +1,7 @@ + /* + * Device Tree Include file for Freescale Layerscape-1043A family SoC. + * +- * Copyright 2014-2015, Freescale Semiconductor ++ * Copyright 2014-2015 Freescale Semiconductor, Inc. + * + * Mingkai Hu + * +@@ -45,7 +45,7 @@ + */ + + /dts-v1/; +-/include/ "fsl-ls1043a.dtsi" ++#include "fsl-ls1043a.dtsi" + + / { + model = "LS1043A RDB Board"; +@@ -86,6 +86,10 @@ + compatible = "pericom,pt7c4338"; + reg = <0x68>; + }; ++ rtc@51 { ++ compatible = "nxp,pcf85263"; ++ reg = <0x51>; ++ }; + }; + + &ifc { +@@ -130,6 +134,38 @@ + reg = <0>; + spi-max-frequency = <1000000>; /* input clock */ + }; ++ ++ slic@2 { ++ compatible = "maxim,ds26522"; ++ reg = <2>; ++ spi-max-frequency = <2000000>; ++ fsl,spi-cs-sck-delay = <100>; ++ fsl,spi-sck-cs-delay = <50>; ++ }; ++ ++ slic@3 { ++ compatible = "maxim,ds26522"; ++ reg = <3>; ++ spi-max-frequency = <2000000>; ++ fsl,spi-cs-sck-delay = <100>; ++ fsl,spi-sck-cs-delay = <50>; ++ }; ++}; ++ ++&uqe { ++ ucc_hdlc: ucc@2000 { ++ compatible = "fsl,ucc-hdlc"; ++ rx-clock-name = "clk8"; ++ tx-clock-name = "clk9"; ++ fsl,rx-sync-clock = "rsync_pin"; ++ fsl,tx-sync-clock = "tsync_pin"; ++ fsl,tx-timeslot-mask = <0xfffffffe>; ++ fsl,rx-timeslot-mask = <0xfffffffe>; ++ fsl,tdm-framer-type = "e1"; ++ fsl,tdm-id = <0>; ++ fsl,siram-entry-id = <0>; ++ fsl,tdm-interface; ++ }; + }; + + &duart0 { +@@ -139,3 +175,76 @@ + &duart1 { + status = "okay"; + }; ++ ++#include "fsl-ls1043-post.dtsi" ++ ++&fman0 { ++ ethernet@e0000 { ++ phy-handle = <&qsgmii_phy1>; ++ phy-connection-type = "qsgmii"; ++ }; ++ ++ ethernet@e2000 { ++ phy-handle = <&qsgmii_phy2>; ++ phy-connection-type = "qsgmii"; ++ }; ++ ++ ethernet@e4000 { ++ phy-handle = <&rgmii_phy1>; ++ phy-connection-type = "rgmii-txid"; ++ }; ++ ++ ethernet@e6000 { ++ phy-handle = <&rgmii_phy2>; ++ phy-connection-type = "rgmii-txid"; ++ }; ++ ++ ethernet@e8000 { ++ phy-handle = <&qsgmii_phy3>; ++ phy-connection-type = "qsgmii"; ++ }; ++ ++ ethernet@ea000 { ++ phy-handle = <&qsgmii_phy4>; ++ phy-connection-type = "qsgmii"; ++ }; ++ ++ ethernet@f0000 { /* 10GEC1 */ ++ phy-handle = <&aqr105_phy>; ++ phy-connection-type = "xgmii"; ++ }; ++ ++ mdio@fc000 { ++ rgmii_phy1: ethernet-phy@1 { ++ reg = <0x1>; ++ }; ++ ++ rgmii_phy2: ethernet-phy@2 { ++ reg = <0x2>; ++ }; ++ ++ qsgmii_phy1: ethernet-phy@4 { ++ reg = <0x4>; ++ }; ++ ++ qsgmii_phy2: ethernet-phy@5 { ++ reg = <0x5>; ++ }; ++ ++ qsgmii_phy3: ethernet-phy@6 { ++ reg = <0x6>; ++ }; ++ ++ qsgmii_phy4: ethernet-phy@7 { ++ reg = <0x7>; ++ }; ++ }; ++ ++ mdio@fd000 { ++ aqr105_phy: ethernet-phy@1 { ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ interrupts = <0 132 4>; ++ reg = <0x1>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +index 97d331ec..8b27faaf 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +@@ -1,7 +1,7 @@ + /* + * Device Tree Include file for Freescale Layerscape-1043A family SoC. + * +- * Copyright 2014-2015, Freescale Semiconductor ++ * Copyright 2014-2015 Freescale Semiconductor, Inc. + * + * Mingkai Hu + * +@@ -44,12 +44,25 @@ + * OTHER DEALINGS IN THE SOFTWARE. + */ + ++#include ++ + / { + compatible = "fsl,ls1043a"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + ++ aliases { ++ fman0 = &fman0; ++ ethernet0 = &enet0; ++ ethernet1 = &enet1; ++ ethernet2 = &enet2; ++ ethernet3 = &enet3; ++ ethernet4 = &enet4; ++ ethernet5 = &enet5; ++ ethernet6 = &enet6; ++ }; ++ + cpus { + #address-cells = <1>; + #size-cells = <0>; +@@ -66,6 +79,8 @@ + reg = <0x0>; + clocks = <&clockgen 1 0>; + next-level-cache = <&l2>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_PH20>; + }; + + cpu1: cpu@1 { +@@ -74,6 +89,7 @@ + reg = <0x1>; + clocks = <&clockgen 1 0>; + next-level-cache = <&l2>; ++ cpu-idle-states = <&CPU_PH20>; + }; + + cpu2: cpu@2 { +@@ -82,6 +98,7 @@ + reg = <0x2>; + clocks = <&clockgen 1 0>; + next-level-cache = <&l2>; ++ cpu-idle-states = <&CPU_PH20>; + }; + + cpu3: cpu@3 { +@@ -90,6 +107,7 @@ + reg = <0x3>; + clocks = <&clockgen 1 0>; + next-level-cache = <&l2>; ++ cpu-idle-states = <&CPU_PH20>; + }; + + l2: l2-cache { +@@ -97,12 +115,56 @@ + }; + }; + ++ idle-states { ++ /* ++ * PSCI node is not added default, U-boot will add missing ++ * parts if it determines to use PSCI. ++ */ ++ entry-method = "arm,psci"; ++ ++ CPU_PH20: cpu-ph20 { ++ compatible = "arm,idle-state"; ++ idle-state-name = "PH20"; ++ arm,psci-suspend-param = <0x0>; ++ entry-latency-us = <1000>; ++ exit-latency-us = <1000>; ++ min-residency-us = <3000>; ++ }; ++ }; ++ + memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 0 0x80000000>; + /* DRAM space 1, size: 2GiB DRAM */ + }; + ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ bman_fbpr: bman-fbpr { ++ compatible = "shared-dma-pool"; ++ size = <0 0x1000000>; ++ alignment = <0 0x1000000>; ++ no-map; ++ }; ++ ++ qman_fqd: qman-fqd { ++ compatible = "shared-dma-pool"; ++ size = <0 0x400000>; ++ alignment = <0 0x400000>; ++ no-map; ++ }; ++ ++ qman_pfdr: qman-pfdr { ++ compatible = "shared-dma-pool"; ++ size = <0 0x2000000>; ++ alignment = <0 0x2000000>; ++ no-map; ++ }; ++ }; ++ + sysclk: sysclk { + compatible = "fixed-clock"; + #clock-cells = <0>; +@@ -149,7 +211,7 @@ + interrupts = <1 9 0xf08>; + }; + +- soc { ++ soc: soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; +@@ -213,13 +275,14 @@ + + dcfg: dcfg@1ee0000 { + compatible = "fsl,ls1043a-dcfg", "syscon"; +- reg = <0x0 0x1ee0000 0x0 0x10000>; ++ reg = <0x0 0x1ee0000 0x0 0x1000>; + big-endian; + }; + + ifc: ifc@1530000 { + compatible = "fsl,ifc", "simple-bus"; + reg = <0x0 0x1530000 0x0 0x10000>; ++ big-endian; + interrupts = <0 43 0x4>; + }; + +@@ -255,6 +318,103 @@ + big-endian; + }; + ++ tmu: tmu@1f00000 { ++ compatible = "fsl,qoriq-tmu"; ++ reg = <0x0 0x1f00000 0x0 0x10000>; ++ interrupts = <0 33 0x4>; ++ fsl,tmu-range = <0xb0000 0x9002a 0x6004c 0x30062>; ++ fsl,tmu-calibration = <0x00000000 0x00000026 ++ 0x00000001 0x0000002d ++ 0x00000002 0x00000032 ++ 0x00000003 0x00000039 ++ 0x00000004 0x0000003f ++ 0x00000005 0x00000046 ++ 0x00000006 0x0000004d ++ 0x00000007 0x00000054 ++ 0x00000008 0x0000005a ++ 0x00000009 0x00000061 ++ 0x0000000a 0x0000006a ++ 0x0000000b 0x00000071 ++ ++ 0x00010000 0x00000025 ++ 0x00010001 0x0000002c ++ 0x00010002 0x00000035 ++ 0x00010003 0x0000003d ++ 0x00010004 0x00000045 ++ 0x00010005 0x0000004e ++ 0x00010006 0x00000057 ++ 0x00010007 0x00000061 ++ 0x00010008 0x0000006b ++ 0x00010009 0x00000076 ++ ++ 0x00020000 0x00000029 ++ 0x00020001 0x00000033 ++ 0x00020002 0x0000003d ++ 0x00020003 0x00000049 ++ 0x00020004 0x00000056 ++ 0x00020005 0x00000061 ++ 0x00020006 0x0000006d ++ ++ 0x00030000 0x00000021 ++ 0x00030001 0x0000002a ++ 0x00030002 0x0000003c ++ 0x00030003 0x0000004e>; ++ #thermal-sensor-cells = <1>; ++ }; ++ ++ thermal-zones { ++ cpu_thermal: cpu-thermal { ++ polling-delay-passive = <1000>; ++ polling-delay = <5000>; ++ ++ thermal-sensors = <&tmu 3>; ++ ++ trips { ++ cpu_alert: cpu-alert { ++ temperature = <85000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ cpu_crit: cpu-crit { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map0 { ++ trip = <&cpu_alert>; ++ cooling-device = ++ <&cpu0 THERMAL_NO_LIMIT ++ THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ }; ++ ++ qman: qman@1880000 { ++ compatible = "fsl,qman"; ++ reg = <0x00 0x1880000 0x0 0x10000>; ++ interrupts = <0 45 0x4>; ++ memory-region = <&qman_fqd &qman_pfdr>; ++ }; ++ ++ bman: bman@1890000 { ++ compatible = "fsl,bman"; ++ reg = <0x00 0x1890000 0x0 0x10000>; ++ interrupts = <0 45 0x4>; ++ memory-region = <&bman_fbpr>; ++ }; ++ ++ bportals: bman-portals@508000000 { ++ ranges = <0x0 0x5 0x08000000 0x8000000>; ++ }; ++ ++ qportals: qman-portals@500000000 { ++ ranges = <0x0 0x5 0x00000000 0x8000000>; ++ }; ++ + dspi0: dspi@2100000 { + compatible = "fsl,ls1043a-dspi", "fsl,ls1021a-v1.0-dspi"; + #address-cells = <1>; +@@ -396,6 +556,72 @@ + #interrupt-cells = <2>; + }; + ++ uqe: uqe@2400000 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ device_type = "qe"; ++ compatible = "fsl,qe", "simple-bus"; ++ ranges = <0x0 0x0 0x2400000 0x40000>; ++ reg = <0x0 0x2400000 0x0 0x480>; ++ brg-frequency = <100000000>; ++ bus-frequency = <200000000>; ++ ++ fsl,qe-num-riscs = <1>; ++ fsl,qe-num-snums = <28>; ++ ++ qeic: qeic@80 { ++ compatible = "fsl,qe-ic"; ++ reg = <0x80 0x80>; ++ #address-cells = <0>; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ interrupts = <0 77 0x04 0 77 0x04>; ++ }; ++ ++ si1: si@700 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,ls1043-qe-si", ++ "fsl,t1040-qe-si"; ++ reg = <0x700 0x80>; ++ }; ++ ++ siram1: siram@1000 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "fsl,ls1043-qe-siram", ++ "fsl,t1040-qe-siram"; ++ reg = <0x1000 0x800>; ++ }; ++ ++ ucc@2000 { ++ cell-index = <1>; ++ reg = <0x2000 0x200>; ++ interrupts = <32>; ++ interrupt-parent = <&qeic>; ++ }; ++ ++ ucc@2200 { ++ cell-index = <3>; ++ reg = <0x2200 0x200>; ++ interrupts = <34>; ++ interrupt-parent = <&qeic>; ++ }; ++ ++ muram@10000 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "fsl,qe-muram", "fsl,cpm-muram"; ++ ranges = <0x0 0x10000 0x6000>; ++ ++ data-only@0 { ++ compatible = "fsl,qe-muram-data", ++ "fsl,cpm-muram-data"; ++ reg = <0x0 0x6000>; ++ }; ++ }; ++ }; ++ + lpuart0: serial@2950000 { + compatible = "fsl,ls1021a-lpuart"; + reg = <0x0 0x2950000 0x0 0x1000>; +@@ -450,6 +676,16 @@ + status = "disabled"; + }; + ++ ftm0: ftm0@29d0000 { ++ compatible = "fsl,ftm-alarm"; ++ reg = <0x0 0x29d0000 0x0 0x10000>, ++ <0x0 0x1ee2140 0x0 0x4>; ++ reg-names = "ftm", "FlexTimer1"; ++ interrupts = <0 86 0x4>; ++ big-endian; ++ status = "okay"; ++ }; ++ + wdog0: wdog@2ad0000 { + compatible = "fsl,ls1043a-wdt", "fsl,imx21-wdt"; + reg = <0x0 0x2ad0000 0x0 0x10000>; +@@ -482,6 +718,8 @@ + dr_mode = "host"; + snps,quirk-frame-length-adjustment = <0x20>; + snps,dis_rxdet_inp3_quirk; ++ snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>; ++ snps,dma-snooping; + }; + + usb1: usb3@3000000 { +@@ -491,6 +729,9 @@ + dr_mode = "host"; + snps,quirk-frame-length-adjustment = <0x20>; + snps,dis_rxdet_inp3_quirk; ++ snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>; ++ snps,dma-snooping; ++ configure-gfladj; + }; + + usb2: usb3@3100000 { +@@ -500,32 +741,52 @@ + dr_mode = "host"; + snps,quirk-frame-length-adjustment = <0x20>; + snps,dis_rxdet_inp3_quirk; ++ snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>; ++ snps,dma-snooping; ++ configure-gfladj; + }; + + sata: sata@3200000 { + compatible = "fsl,ls1043a-ahci"; +- reg = <0x0 0x3200000 0x0 0x10000>; ++ reg = <0x0 0x3200000 0x0 0x10000>, ++ <0x0 0x20140520 0x0 0x4>; ++ reg-names = "ahci", "sata-ecc"; + interrupts = <0 69 0x4>; + clocks = <&clockgen 4 0>; + dma-coherent; + }; + ++ qdma: qdma@8380000 { ++ compatible = "fsl,ls1021a-qdma", "fsl,ls1043a-qdma"; ++ reg = <0x0 0x8380000 0x0 0x1000>, /* Controller regs */ ++ <0x0 0x8390000 0x0 0x10000>, /* Status regs */ ++ <0x0 0x83a0000 0x0 0x40000>; /* Block regs */ ++ interrupts = <0 152 0x4>, ++ <0 39 0x4>; ++ interrupt-names = "qdma-error", "qdma-queue"; ++ channels = <8>; ++ queues = <2>; ++ status-sizes = <64>; ++ queue-sizes = <64 64>; ++ big-endian; ++ }; ++ + msi1: msi-controller1@1571000 { +- compatible = "fsl,1s1043a-msi"; ++ compatible = "fsl,ls1043a-msi"; + reg = <0x0 0x1571000 0x0 0x8>; + msi-controller; + interrupts = <0 116 0x4>; + }; + + msi2: msi-controller2@1572000 { +- compatible = "fsl,1s1043a-msi"; ++ compatible = "fsl,ls1043a-msi"; + reg = <0x0 0x1572000 0x0 0x8>; + msi-controller; + interrupts = <0 126 0x4>; + }; + + msi3: msi-controller3@1573000 { +- compatible = "fsl,1s1043a-msi"; ++ compatible = "fsl,ls1043a-msi"; + reg = <0x0 0x1573000 0x0 0x8>; + msi-controller; + interrupts = <0 160 0x4>; +@@ -536,9 +797,9 @@ + reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ + 0x40 0x00000000 0x0 0x00002000>; /* configuration space */ + reg-names = "regs", "config"; +- interrupts = <0 118 0x4>, /* controller interrupt */ +- <0 117 0x4>; /* PME interrupt */ +- interrupt-names = "intr", "pme"; ++ interrupts = <0 117 0x4>, /* PME interrupt */ ++ <0 118 0x4>; /* aer interrupt */ ++ interrupt-names = "pme", "aer"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; +@@ -547,7 +808,7 @@ + bus-range = <0x0 0xff>; + ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000 /* downstream I/O */ + 0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ +- msi-parent = <&msi1>; ++ msi-parent = <&msi1>, <&msi2>, <&msi3>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0000 0 0 1 &gic 0 110 0x4>, +@@ -561,9 +822,9 @@ + reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */ + 0x48 0x00000000 0x0 0x00002000>; /* configuration space */ + reg-names = "regs", "config"; +- interrupts = <0 128 0x4>, +- <0 127 0x4>; +- interrupt-names = "intr", "pme"; ++ interrupts = <0 127 0x4>, ++ <0 128 0x4>; ++ interrupt-names = "pme", "aer"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; +@@ -572,7 +833,7 @@ + bus-range = <0x0 0xff>; + ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000 /* downstream I/O */ + 0x82000000 0x0 0x40000000 0x48 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ +- msi-parent = <&msi2>; ++ msi-parent = <&msi1>, <&msi2>, <&msi3>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0000 0 0 1 &gic 0 120 0x4>, +@@ -586,9 +847,9 @@ + reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */ + 0x50 0x00000000 0x0 0x00002000>; /* configuration space */ + reg-names = "regs", "config"; +- interrupts = <0 162 0x4>, +- <0 161 0x4>; +- interrupt-names = "intr", "pme"; ++ interrupts = <0 161 0x4>, ++ <0 162 0x4>; ++ interrupt-names = "pme", "aer"; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; +@@ -597,7 +858,7 @@ + bus-range = <0x0 0xff>; + ranges = <0x81000000 0x0 0x00000000 0x50 0x00010000 0x0 0x00010000 /* downstream I/O */ + 0x82000000 0x0 0x40000000 0x50 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ +- msi-parent = <&msi3>; ++ msi-parent = <&msi1>, <&msi2>, <&msi3>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0000 0 0 1 &gic 0 154 0x4>, +@@ -608,3 +869,6 @@ + }; + + }; ++ ++#include "qoriq-qman1-portals.dtsi" ++#include "qoriq-bman1-portals.dtsi" +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046-post.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046-post.dtsi +new file mode 100644 +index 00000000..f5017dba +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046-post.dtsi +@@ -0,0 +1,48 @@ ++/* ++ * QorIQ FMan v3 device tree nodes for ls1046 ++ * ++ * Copyright 2015-2016 Freescale Semiconductor Inc. ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++ */ ++ ++&soc { ++ ++/* include used FMan blocks */ ++#include "qoriq-fman3-0.dtsi" ++#include "qoriq-fman3-0-1g-0.dtsi" ++#include "qoriq-fman3-0-1g-1.dtsi" ++#include "qoriq-fman3-0-1g-2.dtsi" ++#include "qoriq-fman3-0-1g-3.dtsi" ++#include "qoriq-fman3-0-1g-4.dtsi" ++#include "qoriq-fman3-0-1g-5.dtsi" ++#include "qoriq-fman3-0-10g-0.dtsi" ++#include "qoriq-fman3-0-10g-1.dtsi" ++}; ++ ++&fman0 { ++ /* these aliases provide the FMan ports mapping */ ++ enet0: ethernet@e0000 { ++ }; ++ ++ enet1: ethernet@e2000 { ++ }; ++ ++ enet2: ethernet@e4000 { ++ }; ++ ++ enet3: ethernet@e6000 { ++ }; ++ ++ enet4: ethernet@e8000 { ++ }; ++ ++ enet5: ethernet@ea000 { ++ }; ++ ++ enet6: ethernet@f0000 { ++ }; ++ ++ enet7: ethernet@f2000 { ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds-sdk.dts b/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds-sdk.dts +new file mode 100644 +index 00000000..c375af47 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds-sdk.dts +@@ -0,0 +1,109 @@ ++/* ++ * Device Tree Include file for Freescale Layerscape-1046A family SoC. ++ * ++ * Copyright 2014-2015 Freescale Semiconductor, Inc. ++ * ++ * Mingkai Hu ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 "fsl-ls1046a-qds.dts" ++ ++&bman_fbpr { ++ compatible = "fsl,bman-fbpr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_fqd { ++ compatible = "fsl,qman-fqd"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_pfdr { ++ compatible = "fsl,qman-pfdr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++ ++&soc { ++#include "qoriq-dpaa-eth.dtsi" ++#include "qoriq-fman3-0-6oh.dtsi" ++}; ++ ++&fsldpaa { ++ ethernet@9 { ++ compatible = "fsl,dpa-ethernet"; ++ fsl,fman-mac = <&enet7>; ++ }; ++}; ++ ++&fman0 { ++ compatible = "fsl,fman", "simple-bus"; ++}; ++ ++&dspi { ++ bus-num = <0>; ++ status = "okay"; ++ ++ flash@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "n25q128a11", "jedec,spi-nor"; ++ reg = <0>; ++ spi-max-frequency = <10000000>; ++ }; ++ ++ flash@1 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "sst25wf040b", "jedec,spi-nor"; ++ spi-cpol; ++ spi-cpha; ++ reg = <1>; ++ spi-max-frequency = <10000000>; ++ }; ++ ++ flash@2 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "en25s64", "jedec,spi-nor"; ++ spi-cpol; ++ spi-cpha; ++ reg = <2>; ++ spi-max-frequency = <10000000>; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts +new file mode 100644 +index 00000000..3b8e9b7e +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-qds.dts +@@ -0,0 +1,363 @@ ++/* ++ * Device Tree Include file for Freescale Layerscape-1046A family SoC. ++ * ++ * Copyright 2016 Freescale Semiconductor, Inc. ++ * ++ * Shaohui Xie ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 "fsl-ls1046a.dtsi" ++ ++/ { ++ model = "LS1046A QDS Board"; ++ compatible = "fsl,ls1046a-qds", "fsl,ls1046a"; ++ ++ aliases { ++ gpio0 = &gpio0; ++ gpio1 = &gpio1; ++ gpio2 = &gpio2; ++ gpio3 = &gpio3; ++ serial0 = &duart0; ++ serial1 = &duart1; ++ serial2 = &duart2; ++ serial3 = &duart3; ++ ++ emi1_slot1 = &ls1046mdio_s1; ++ emi1_slot2 = &ls1046mdio_s2; ++ emi1_slot4 = &ls1046mdio_s4; ++ ++ sgmii_s1_p1 = &sgmii_phy_s1_p1; ++ sgmii_s1_p2 = &sgmii_phy_s1_p2; ++ sgmii_s1_p3 = &sgmii_phy_s1_p3; ++ sgmii_s1_p4 = &sgmii_phy_s1_p4; ++ sgmii_s4_p1 = &sgmii_phy_s4_p1; ++ qsgmii_s2_p1 = &qsgmii_phy_s2_p1; ++ qsgmii_s2_p2 = &qsgmii_phy_s2_p2; ++ qsgmii_s2_p3 = &qsgmii_phy_s2_p3; ++ qsgmii_s2_p4 = &qsgmii_phy_s2_p4; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++}; ++ ++&dspi { ++ bus-num = <0>; ++ status = "okay"; ++ ++ flash@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "n25q128a11", "jedec,spi-nor"; ++ reg = <0>; ++ spi-max-frequency = <10000000>; ++ }; ++ ++ flash@1 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "sst25wf040b", "jedec,spi-nor"; ++ spi-cpol; ++ spi-cpha; ++ reg = <1>; ++ spi-max-frequency = <10000000>; ++ }; ++ ++ flash@2 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "en25s64", "jedec,spi-nor"; ++ spi-cpol; ++ spi-cpha; ++ reg = <2>; ++ spi-max-frequency = <10000000>; ++ }; ++}; ++ ++&duart0 { ++ status = "okay"; ++}; ++ ++&duart1 { ++ status = "okay"; ++}; ++ ++&i2c0 { ++ status = "okay"; ++ ++ pca9547@77 { ++ compatible = "nxp,pca9547"; ++ reg = <0x77>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x2>; ++ ++ ina220@40 { ++ compatible = "ti,ina220"; ++ reg = <0x40>; ++ shunt-resistor = <1000>; ++ }; ++ ++ ina220@41 { ++ compatible = "ti,ina220"; ++ reg = <0x41>; ++ shunt-resistor = <1000>; ++ }; ++ }; ++ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x3>; ++ ++ rtc@51 { ++ compatible = "nxp,pcf2129"; ++ reg = <0x51>; ++ /* IRQ10_B */ ++ interrupts = <0 150 0x4>; ++ }; ++ ++ eeprom@56 { ++ compatible = "atmel,24c512"; ++ reg = <0x56>; ++ }; ++ ++ eeprom@57 { ++ compatible = "atmel,24c512"; ++ reg = <0x57>; ++ }; ++ ++ temp-sensor@4c { ++ compatible = "adi,adt7461a"; ++ reg = <0x4c>; ++ }; ++ }; ++ }; ++}; ++ ++&ifc { ++ #address-cells = <2>; ++ #size-cells = <1>; ++ /* NOR, NAND Flashes and FPGA on board */ ++ ranges = <0x0 0x0 0x0 0x60000000 0x08000000 ++ 0x1 0x0 0x0 0x7e800000 0x00010000 ++ 0x2 0x0 0x0 0x7fb00000 0x00000100>; ++ status = "okay"; ++ ++ nor@0,0 { ++ compatible = "cfi-flash"; ++ reg = <0x0 0x0 0x8000000>; ++ bank-width = <2>; ++ device-width = <1>; ++ }; ++ ++ nand@1,0 { ++ compatible = "fsl,ifc-nand"; ++ reg = <0x1 0x0 0x10000>; ++ }; ++ ++ fpga: board-control@2,0 { ++ compatible = "fsl,ls1046aqds-fpga", "fsl,fpga-qixis", "simple-bus"; ++ reg = <0x2 0x0 0x0000100>; ++ ranges = <0 2 0 0x100>; ++ }; ++}; ++ ++&lpuart0 { ++ status = "okay"; ++}; ++ ++&qspi { ++ num-cs = <2>; ++ bus-num = <0>; ++ status = "okay"; ++ ++ qflash0: s25fl128s@0 { ++ compatible = "spansion,m25p80"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++}; ++ ++#include "fsl-ls1046-post.dtsi" ++ ++&fman0 { ++ ethernet@e0000 { ++ phy-handle = <&qsgmii_phy_s2_p1>; ++ phy-connection-type = "sgmii"; ++ }; ++ ++ ethernet@e2000 { ++ phy-handle = <&sgmii_phy_s4_p1>; ++ phy-connection-type = "sgmii"; ++ }; ++ ++ ethernet@e4000 { ++ phy-handle = <&rgmii_phy1>; ++ phy-connection-type = "rgmii"; ++ }; ++ ++ ethernet@e6000 { ++ phy-handle = <&rgmii_phy2>; ++ phy-connection-type = "rgmii"; ++ }; ++ ++ ethernet@e8000 { ++ phy-handle = <&sgmii_phy_s1_p3>; ++ phy-connection-type = "sgmii"; ++ }; ++ ++ ethernet@ea000 { ++ phy-handle = <&sgmii_phy_s1_p4>; ++ phy-connection-type = "sgmii"; ++ }; ++ ++ ethernet@f0000 { /* DTSEC9/10GEC1 */ ++ phy-handle = <&sgmii_phy_s1_p1>; ++ phy-connection-type = "xgmii"; ++ }; ++ ++ ethernet@f2000 { /* DTSEC10/10GEC2 */ ++ phy-handle = <&sgmii_phy_s1_p2>; ++ phy-connection-type = "xgmii"; ++ }; ++}; ++ ++&fpga { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ mdio-mux-emi1 { ++ compatible = "mdio-mux-mmioreg", "mdio-mux"; ++ mdio-parent-bus = <&mdio0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x54 1>; /* BRDCFG4 */ ++ mux-mask = <0xe0>; /* EMI1 */ ++ ++ /* On-board RGMII1 PHY */ ++ ls1046mdio0: mdio@0 { ++ reg = <0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ rgmii_phy1: ethernet-phy@1 { /* MAC3 */ ++ reg = <0x1>; ++ }; ++ }; ++ ++ /* On-board RGMII2 PHY */ ++ ls1046mdio1: mdio@1 { ++ reg = <0x20>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ rgmii_phy2: ethernet-phy@2 { /* MAC4 */ ++ reg = <0x2>; ++ }; ++ }; ++ ++ /* Slot 1 */ ++ ls1046mdio_s1: mdio@2 { ++ reg = <0x40>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ ++ sgmii_phy_s1_p1: ethernet-phy@1c { ++ reg = <0x1c>; ++ }; ++ ++ sgmii_phy_s1_p2: ethernet-phy@1d { ++ reg = <0x1d>; ++ }; ++ ++ sgmii_phy_s1_p3: ethernet-phy@1e { ++ reg = <0x1e>; ++ }; ++ ++ sgmii_phy_s1_p4: ethernet-phy@1f { ++ reg = <0x1f>; ++ }; ++ }; ++ ++ /* Slot 2 */ ++ ls1046mdio_s2: mdio@3 { ++ reg = <0x60>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ ++ qsgmii_phy_s2_p1: ethernet-phy@8 { ++ reg = <0x8>; ++ }; ++ qsgmii_phy_s2_p2: ethernet-phy@9 { ++ reg = <0x9>; ++ }; ++ qsgmii_phy_s2_p3: ethernet-phy@a { ++ reg = <0xa>; ++ }; ++ qsgmii_phy_s2_p4: ethernet-phy@b { ++ reg = <0xb>; ++ }; ++ }; ++ ++ /* Slot 4 */ ++ ls1046mdio_s4: mdio@5 { ++ reg = <0x80>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ ++ sgmii_phy_s4_p1: ethernet-phy@1c { ++ reg = <0x1c>; ++ }; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts +new file mode 100644 +index 00000000..bfe2f36c +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk.dts +@@ -0,0 +1,76 @@ ++/* ++ * Device Tree Include file for Freescale Layerscape-1046A family SoC. ++ * ++ * Copyright 2014-2015 Freescale Semiconductor, Inc. ++ * ++ * Mingkai Hu ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 "fsl-ls1046a-rdb.dts" ++ ++&bman_fbpr { ++ compatible = "fsl,bman-fbpr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_fqd { ++ compatible = "fsl,qman-fqd"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++&qman_pfdr { ++ compatible = "fsl,qman-pfdr"; ++ alloc-ranges = <0 0 0x10000 0>; ++}; ++ ++&soc { ++#include "qoriq-dpaa-eth.dtsi" ++#include "qoriq-fman3-0-6oh.dtsi" ++}; ++ ++&fsldpaa { ++ ethernet@9 { ++ compatible = "fsl,dpa-ethernet"; ++ fsl,fman-mac = <&enet7>; ++ }; ++}; ++ ++&fman0 { ++ compatible = "fsl,fman", "simple-bus"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-usdpaa.dts b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-usdpaa.dts +new file mode 100644 +index 00000000..54336aa6 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-usdpaa.dts +@@ -0,0 +1,110 @@ ++/* ++ * Device Tree Include file for Freescale Layerscape-1046A family SoC. ++ * ++ * Copyright 2016 Freescale Semiconductor, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include "fsl-ls1046a-rdb-sdk.dts" ++ ++&soc { ++ bp7: buffer-pool@7 { ++ compatible = "fsl,ls1046a-bpool", "fsl,bpool"; ++ fsl,bpid = <7>; ++ fsl,bpool-ethernet-cfg = <0 0 0 192 0 0xdeadbeef>; ++ fsl,bpool-thresholds = <0x400 0xc00 0x0 0x0>; ++ }; ++ ++ bp8: buffer-pool@8 { ++ compatible = "fsl,ls1046a-bpool", "fsl,bpool"; ++ fsl,bpid = <8>; ++ fsl,bpool-ethernet-cfg = <0 0 0 576 0 0xabbaf00d>; ++ fsl,bpool-thresholds = <0x100 0x300 0x0 0x0>; ++ }; ++ ++ bp9: buffer-pool@9 { ++ compatible = "fsl,ls1046a-bpool", "fsl,bpool"; ++ fsl,bpid = <9>; ++ fsl,bpool-ethernet-cfg = <0 0 0 2048 0 0xfeedabba>; ++ fsl,bpool-thresholds = <0x100 0x300 0x0 0x0>; ++ }; ++ ++ fsl,dpaa { ++ compatible = "fsl,ls1046a", "fsl,dpaa", "simple-bus"; ++ ++ ethernet@2 { ++ compatible = "fsl,dpa-ethernet-init"; ++ fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>; ++ fsl,qman-frame-queues-rx = <0x54 1 0x55 1>; ++ fsl,qman-frame-queues-tx = <0x74 1 0x75 1>; ++ }; ++ ++ ethernet@3 { ++ compatible = "fsl,dpa-ethernet-init"; ++ fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>; ++ fsl,qman-frame-queues-rx = <0x56 1 0x57 1>; ++ fsl,qman-frame-queues-tx = <0x76 1 0x77 1>; ++ }; ++ ++ ethernet@4 { ++ compatible = "fsl,dpa-ethernet-init"; ++ fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>; ++ fsl,qman-frame-queues-rx = <0x58 1 0x59 1>; ++ fsl,qman-frame-queues-tx = <0x78 1 0x79 1>; ++ }; ++ ++ ethernet@5 { ++ compatible = "fsl,dpa-ethernet-init"; ++ fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>; ++ fsl,qman-frame-queues-rx = <0x5a 1 0x5b 1>; ++ fsl,qman-frame-queues-tx = <0x7a 1 0x7b 1>; ++ }; ++ ++ ethernet@8 { ++ compatible = "fsl,dpa-ethernet-init"; ++ fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>; ++ fsl,qman-frame-queues-rx = <0x5c 1 0x5d 1>; ++ fsl,qman-frame-queues-tx = <0x7c 1 0x7d 1>; ++ }; ++ ++ ethernet@9 { ++ compatible = "fsl,dpa-ethernet-init"; ++ fsl,bman-buffer-pools = <&bp7 &bp8 &bp9>; ++ fsl,qman-frame-queues-rx = <0x5e 1 0x5f 1>; ++ fsl,qman-frame-queues-tx = <0x7e 1 0x7f 1>; ++ }; ++ ++ dpa-fman0-oh@2 { ++ compatible = "fsl,dpa-oh"; ++ /* Define frame queues for the OH port*/ ++ /* */ ++ fsl,qman-frame-queues-oh = <0x60 1 0x61 1>; ++ fsl,fman-oh-port = <&fman0_oh2>; ++ }; ++ }; ++}; ++/ { ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ usdpaa_mem: usdpaa_mem { ++ compatible = "fsl,usdpaa-mem"; ++ alloc-ranges = <0 0 0x10000 0>; ++ size = <0 0x10000000>; ++ alignment = <0 0x10000000>; ++ }; ++ }; ++}; ++ ++&fman0 { ++ fman0_oh2: port@83000 { ++ cell-index = <1>; ++ compatible = "fsl,fman-port-oh"; ++ reg = <0x83000 0x1000>; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts +new file mode 100644 +index 00000000..be9b62ca +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts +@@ -0,0 +1,218 @@ ++/* ++ * Device Tree Include file for Freescale Layerscape-1046A family SoC. ++ * ++ * Copyright 2016 Freescale Semiconductor, Inc. ++ * ++ * Mingkai Hu ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 "fsl-ls1046a.dtsi" ++ ++/ { ++ model = "LS1046A RDB Board"; ++ compatible = "fsl,ls1046a-rdb", "fsl,ls1046a"; ++ ++ aliases { ++ serial0 = &duart0; ++ serial1 = &duart1; ++ serial2 = &duart2; ++ serial3 = &duart3; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++}; ++ ++&esdhc { ++ mmc-hs200-1_8v; ++ sd-uhs-sdr104; ++ sd-uhs-sdr50; ++ sd-uhs-sdr25; ++ sd-uhs-sdr12; ++}; ++ ++&duart0 { ++ status = "okay"; ++}; ++ ++&duart1 { ++ status = "okay"; ++}; ++ ++&i2c0 { ++ status = "okay"; ++ ++ ina220@40 { ++ compatible = "ti,ina220"; ++ reg = <0x40>; ++ shunt-resistor = <1000>; ++ }; ++ ++ temp-sensor@4c { ++ compatible = "adi,adt7461"; ++ reg = <0x4c>; ++ }; ++ ++ eeprom@56 { ++ compatible = "atmel,24c512"; ++ reg = <0x52>; ++ }; ++ ++ eeprom@57 { ++ compatible = "atmel,24c512"; ++ reg = <0x53>; ++ }; ++}; ++ ++&i2c3 { ++ status = "okay"; ++ ++ rtc@51 { ++ compatible = "nxp,pcf2129"; ++ reg = <0x51>; ++ }; ++}; ++ ++&ifc { ++ #address-cells = <2>; ++ #size-cells = <1>; ++ /* NAND Flashe and CPLD on board */ ++ ranges = <0x0 0x0 0x0 0x7e800000 0x00010000 ++ 0x2 0x0 0x0 0x7fb00000 0x00000100>; ++ status = "okay"; ++ ++ nand@0,0 { ++ compatible = "fsl,ifc-nand"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ reg = <0x0 0x0 0x10000>; ++ }; ++ ++ cpld: board-control@2,0 { ++ compatible = "fsl,ls1046ardb-cpld"; ++ reg = <0x2 0x0 0x0000100>; ++ }; ++}; ++ ++&qspi { ++ num-cs = <2>; ++ bus-num = <0>; ++ status = "okay"; ++ ++ qflash0: s25fs512s@0 { ++ compatible = "spansion,m25p80"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++ ++ qflash1: s25fs512s@1 { ++ compatible = "spansion,m25p80"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ spi-max-frequency = <20000000>; ++ reg = <1>; ++ }; ++}; ++ ++#include "fsl-ls1046-post.dtsi" ++ ++&fman0 { ++ ethernet@e4000 { ++ phy-handle = <&rgmii_phy1>; ++ phy-connection-type = "rgmii"; ++ }; ++ ++ ethernet@e6000 { ++ phy-handle = <&rgmii_phy2>; ++ phy-connection-type = "rgmii"; ++ }; ++ ++ ethernet@e8000 { ++ phy-handle = <&sgmii_phy1>; ++ phy-connection-type = "sgmii"; ++ }; ++ ++ ethernet@ea000 { ++ phy-handle = <&sgmii_phy2>; ++ phy-connection-type = "sgmii"; ++ }; ++ ++ ethernet@f0000 { /* 10GEC1 */ ++ phy-handle = <&aqr106_phy>; ++ phy-connection-type = "xgmii"; ++ }; ++ ++ ethernet@f2000 { /* 10GEC2 */ ++ fixed-link = <0 1 1000 0 0>; ++ phy-connection-type = "xgmii"; ++ }; ++ ++ mdio@fc000 { ++ rgmii_phy1: ethernet-phy@1 { ++ reg = <0x1>; ++ }; ++ ++ rgmii_phy2: ethernet-phy@2 { ++ reg = <0x2>; ++ }; ++ ++ sgmii_phy1: ethernet-phy@3 { ++ reg = <0x3>; ++ }; ++ ++ sgmii_phy2: ethernet-phy@4 { ++ reg = <0x4>; ++ }; ++ }; ++ ++ mdio@fd000 { ++ aqr106_phy: ethernet-phy@0 { ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ interrupts = <0 131 4>; ++ reg = <0x0>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +new file mode 100644 +index 00000000..6b87266f +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +@@ -0,0 +1,793 @@ ++/* ++ * Device Tree Include file for Freescale Layerscape-1046A family SoC. ++ * ++ * Copyright 2016 Freescale Semiconductor, Inc. ++ * ++ * Mingkai Hu ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 ++#include ++ ++/ { ++ compatible = "fsl,ls1046a"; ++ interrupt-parent = <&gic>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ aliases { ++ crypto = &crypto; ++ fman0 = &fman0; ++ ethernet0 = &enet0; ++ ethernet1 = &enet1; ++ ethernet2 = &enet2; ++ ethernet3 = &enet3; ++ ethernet4 = &enet4; ++ ethernet5 = &enet5; ++ ethernet6 = &enet6; ++ ethernet7 = &enet7; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <0x0>; ++ clocks = <&clockgen 1 0>; ++ next-level-cache = <&l2>; ++ cpu-idle-states = <&CPU_PH20>; ++ #cooling-cells = <2>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <0x1>; ++ clocks = <&clockgen 1 0>; ++ next-level-cache = <&l2>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ cpu2: cpu@2 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <0x2>; ++ clocks = <&clockgen 1 0>; ++ next-level-cache = <&l2>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ cpu3: cpu@3 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <0x3>; ++ clocks = <&clockgen 1 0>; ++ next-level-cache = <&l2>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ l2: l2-cache { ++ compatible = "cache"; ++ }; ++ }; ++ ++ idle-states { ++ /* ++ * PSCI node is not added default, U-boot will add missing ++ * parts if it determines to use PSCI. ++ */ ++ entry-method = "arm,psci"; ++ ++ CPU_PH20: cpu-ph20 { ++ compatible = "arm,idle-state"; ++ idle-state-name = "PH20"; ++ arm,psci-suspend-param = <0x0>; ++ entry-latency-us = <1000>; ++ exit-latency-us = <1000>; ++ min-residency-us = <3000>; ++ }; ++ }; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ }; ++ ++ sysclk: sysclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <100000000>; ++ clock-output-names = "sysclk"; ++ }; ++ ++ reboot { ++ compatible ="syscon-reboot"; ++ regmap = <&dcfg>; ++ offset = <0xb0>; ++ mask = <0x02>; ++ }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupts = , ++ , ++ , ++ ; ++ }; ++ ++ pmu { ++ compatible = "arm,cortex-a72-pmu"; ++ interrupts = , ++ , ++ , ++ ; ++ interrupt-affinity = <&cpu0>, ++ <&cpu1>, ++ <&cpu2>, ++ <&cpu3>; ++ }; ++ ++ gic: interrupt-controller@1400000 { ++ compatible = "arm,gic-400"; ++ #interrupt-cells = <3>; ++ interrupt-controller; ++ reg = <0x0 0x1410000 0 0x10000>, /* GICD */ ++ <0x0 0x1420000 0 0x20000>, /* GICC */ ++ <0x0 0x1440000 0 0x20000>, /* GICH */ ++ <0x0 0x1460000 0 0x20000>; /* GICV */ ++ interrupts = ; ++ }; ++ ++ soc: soc { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ ddr: memory-controller@1080000 { ++ compatible = "fsl,qoriq-memory-controller"; ++ reg = <0x0 0x1080000 0x0 0x1000>; ++ interrupts = ; ++ big-endian; ++ }; ++ ++ ifc: ifc@1530000 { ++ compatible = "fsl,ifc", "simple-bus"; ++ reg = <0x0 0x1530000 0x0 0x10000>; ++ big-endian; ++ interrupts = ; ++ }; ++ ++ qspi: quadspi@1550000 { ++ compatible = "fsl,ls1021a-qspi"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x1550000 0x0 0x10000>, ++ <0x0 0x40000000 0x0 0x10000000>; ++ reg-names = "QuadSPI", "QuadSPI-memory"; ++ interrupts = ; ++ clock-names = "qspi_en", "qspi"; ++ clocks = <&clockgen 4 1>, <&clockgen 4 1>; ++ big-endian; ++ fsl,qspi-has-second-chip; ++ status = "disabled"; ++ }; ++ ++ esdhc: esdhc@1560000 { ++ compatible = "fsl,ls1046a-esdhc", "fsl,esdhc"; ++ reg = <0x0 0x1560000 0x0 0x10000>; ++ interrupts = ; ++ clocks = <&clockgen 2 1>; ++ voltage-ranges = <1800 1800 3300 3300>; ++ sdhci,auto-cmd12; ++ big-endian; ++ bus-width = <4>; ++ }; ++ ++ scfg: scfg@1570000 { ++ compatible = "fsl,ls1046a-scfg", "syscon"; ++ reg = <0x0 0x1570000 0x0 0x10000>; ++ big-endian; ++ }; ++ ++ crypto: crypto@1700000 { ++ compatible = "fsl,sec-v5.4", "fsl,sec-v5.0", ++ "fsl,sec-v4.0"; ++ fsl,sec-era = <8>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0x0 0x00 0x1700000 0x100000>; ++ reg = <0x00 0x1700000 0x0 0x100000>; ++ interrupts = ; ++ ++ sec_jr0: jr@10000 { ++ compatible = "fsl,sec-v5.4-job-ring", ++ "fsl,sec-v5.0-job-ring", ++ "fsl,sec-v4.0-job-ring"; ++ reg = <0x10000 0x10000>; ++ interrupts = ; ++ }; ++ ++ sec_jr1: jr@20000 { ++ compatible = "fsl,sec-v5.4-job-ring", ++ "fsl,sec-v5.0-job-ring", ++ "fsl,sec-v4.0-job-ring"; ++ reg = <0x20000 0x10000>; ++ interrupts = ; ++ }; ++ ++ sec_jr2: jr@30000 { ++ compatible = "fsl,sec-v5.4-job-ring", ++ "fsl,sec-v5.0-job-ring", ++ "fsl,sec-v4.0-job-ring"; ++ reg = <0x30000 0x10000>; ++ interrupts = ; ++ }; ++ ++ sec_jr3: jr@40000 { ++ compatible = "fsl,sec-v5.4-job-ring", ++ "fsl,sec-v5.0-job-ring", ++ "fsl,sec-v4.0-job-ring"; ++ reg = <0x40000 0x10000>; ++ interrupts = ; ++ }; ++ }; ++ ++ qman: qman@1880000 { ++ compatible = "fsl,qman"; ++ reg = <0x00 0x1880000 0x0 0x10000>; ++ interrupts = <0 45 0x4>; ++ memory-region = <&qman_fqd &qman_pfdr>; ++ ++ }; ++ ++ bman: bman@1890000 { ++ compatible = "fsl,bman"; ++ reg = <0x00 0x1890000 0x0 0x10000>; ++ interrupts = <0 45 0x4>; ++ memory-region = <&bman_fbpr>; ++ ++ }; ++ ++ qportals: qman-portals@500000000 { ++ ranges = <0x0 0x5 0x00000000 0x8000000>; ++ }; ++ ++ bportals: bman-portals@508000000 { ++ ranges = <0x0 0x5 0x08000000 0x8000000>; ++ }; ++ ++ dcfg: dcfg@1ee0000 { ++ compatible = "fsl,ls1046a-dcfg", "syscon"; ++ reg = <0x0 0x1ee0000 0x0 0x1000>; ++ big-endian; ++ }; ++ ++ clockgen: clocking@1ee1000 { ++ compatible = "fsl,ls1046a-clockgen"; ++ reg = <0x0 0x1ee1000 0x0 0x1000>; ++ #clock-cells = <2>; ++ clocks = <&sysclk>; ++ }; ++ ++ tmu: tmu@1f00000 { ++ compatible = "fsl,qoriq-tmu"; ++ reg = <0x0 0x1f00000 0x0 0x10000>; ++ interrupts = <0 33 0x4>; ++ fsl,tmu-range = <0xb0000 0x9002a 0x6004c 0x30062>; ++ fsl,tmu-calibration = ++ /* Calibration data group 1 */ ++ <0x00000000 0x00000026 ++ 0x00000001 0x0000002d ++ 0x00000002 0x00000032 ++ 0x00000003 0x00000039 ++ 0x00000004 0x0000003f ++ 0x00000005 0x00000046 ++ 0x00000006 0x0000004d ++ 0x00000007 0x00000054 ++ 0x00000008 0x0000005a ++ 0x00000009 0x00000061 ++ 0x0000000a 0x0000006a ++ 0x0000000b 0x00000071 ++ /* Calibration data group 2 */ ++ 0x00010000 0x00000025 ++ 0x00010001 0x0000002c ++ 0x00010002 0x00000035 ++ 0x00010003 0x0000003d ++ 0x00010004 0x00000045 ++ 0x00010005 0x0000004e ++ 0x00010006 0x00000057 ++ 0x00010007 0x00000061 ++ 0x00010008 0x0000006b ++ 0x00010009 0x00000076 ++ /* Calibration data group 3 */ ++ 0x00020000 0x00000029 ++ 0x00020001 0x00000033 ++ 0x00020002 0x0000003d ++ 0x00020003 0x00000049 ++ 0x00020004 0x00000056 ++ 0x00020005 0x00000061 ++ 0x00020006 0x0000006d ++ /* Calibration data group 4 */ ++ 0x00030000 0x00000021 ++ 0x00030001 0x0000002a ++ 0x00030002 0x0000003c ++ 0x00030003 0x0000004e>; ++ big-endian; ++ #thermal-sensor-cells = <1>; ++ }; ++ ++ thermal-zones { ++ cpu_thermal: cpu-thermal { ++ polling-delay-passive = <1000>; ++ polling-delay = <5000>; ++ thermal-sensors = <&tmu 3>; ++ ++ trips { ++ cpu_alert: cpu-alert { ++ temperature = <85000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ ++ cpu_crit: cpu-crit { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map0 { ++ trip = <&cpu_alert>; ++ cooling-device = ++ <&cpu0 THERMAL_NO_LIMIT ++ THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ }; ++ ++ dspi: dspi@2100000 { ++ compatible = "fsl,ls1021a-v1.0-dspi"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x2100000 0x0 0x10000>; ++ interrupts = ; ++ clock-names = "dspi"; ++ clocks = <&clockgen 4 1>; ++ spi-num-chipselects = <5>; ++ big-endian; ++ status = "disabled"; ++ }; ++ ++ i2c0: i2c@2180000 { ++ compatible = "fsl,vf610-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x2180000 0x0 0x10000>; ++ interrupts = ; ++ clocks = <&clockgen 4 1>; ++ dmas = <&edma0 1 39>, ++ <&edma0 1 38>; ++ dma-names = "tx", "rx"; ++ status = "disabled"; ++ }; ++ ++ i2c1: i2c@2190000 { ++ compatible = "fsl,vf610-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x2190000 0x0 0x10000>; ++ interrupts = ; ++ clocks = <&clockgen 4 1>; ++ status = "disabled"; ++ }; ++ ++ i2c2: i2c@21a0000 { ++ compatible = "fsl,vf610-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x21a0000 0x0 0x10000>; ++ interrupts = ; ++ clocks = <&clockgen 4 1>; ++ status = "disabled"; ++ }; ++ ++ i2c3: i2c@21b0000 { ++ compatible = "fsl,vf610-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x21b0000 0x0 0x10000>; ++ interrupts = ; ++ clocks = <&clockgen 4 1>; ++ status = "disabled"; ++ }; ++ ++ duart0: serial@21c0500 { ++ compatible = "fsl,ns16550", "ns16550a"; ++ reg = <0x00 0x21c0500 0x0 0x100>; ++ interrupts = ; ++ clocks = <&clockgen 4 1>; ++ }; ++ ++ duart1: serial@21c0600 { ++ compatible = "fsl,ns16550", "ns16550a"; ++ reg = <0x00 0x21c0600 0x0 0x100>; ++ interrupts = ; ++ clocks = <&clockgen 4 1>; ++ }; ++ ++ duart2: serial@21d0500 { ++ compatible = "fsl,ns16550", "ns16550a"; ++ reg = <0x0 0x21d0500 0x0 0x100>; ++ interrupts = ; ++ clocks = <&clockgen 4 1>; ++ }; ++ ++ duart3: serial@21d0600 { ++ compatible = "fsl,ns16550", "ns16550a"; ++ reg = <0x0 0x21d0600 0x0 0x100>; ++ interrupts = ; ++ clocks = <&clockgen 4 1>; ++ }; ++ ++ gpio0: gpio@2300000 { ++ compatible = "fsl,qoriq-gpio"; ++ reg = <0x0 0x2300000 0x0 0x10000>; ++ interrupts = ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio1: gpio@2310000 { ++ compatible = "fsl,qoriq-gpio"; ++ reg = <0x0 0x2310000 0x0 0x10000>; ++ interrupts = ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio2: gpio@2320000 { ++ compatible = "fsl,qoriq-gpio"; ++ reg = <0x0 0x2320000 0x0 0x10000>; ++ interrupts = ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio3: gpio@2330000 { ++ compatible = "fsl,qoriq-gpio"; ++ reg = <0x0 0x2330000 0x0 0x10000>; ++ interrupts = ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ lpuart0: serial@2950000 { ++ compatible = "fsl,ls1021a-lpuart"; ++ reg = <0x0 0x2950000 0x0 0x1000>; ++ interrupts = ; ++ clocks = <&clockgen 4 0>; ++ clock-names = "ipg"; ++ status = "disabled"; ++ }; ++ ++ lpuart1: serial@2960000 { ++ compatible = "fsl,ls1021a-lpuart"; ++ reg = <0x0 0x2960000 0x0 0x1000>; ++ interrupts = ; ++ clocks = <&clockgen 4 1>; ++ clock-names = "ipg"; ++ status = "disabled"; ++ }; ++ ++ lpuart2: serial@2970000 { ++ compatible = "fsl,ls1021a-lpuart"; ++ reg = <0x0 0x2970000 0x0 0x1000>; ++ interrupts = ; ++ clocks = <&clockgen 4 1>; ++ clock-names = "ipg"; ++ status = "disabled"; ++ }; ++ ++ lpuart3: serial@2980000 { ++ compatible = "fsl,ls1021a-lpuart"; ++ reg = <0x0 0x2980000 0x0 0x1000>; ++ interrupts = ; ++ clocks = <&clockgen 4 1>; ++ clock-names = "ipg"; ++ status = "disabled"; ++ }; ++ ++ lpuart4: serial@2990000 { ++ compatible = "fsl,ls1021a-lpuart"; ++ reg = <0x0 0x2990000 0x0 0x1000>; ++ interrupts = ; ++ clocks = <&clockgen 4 1>; ++ clock-names = "ipg"; ++ status = "disabled"; ++ }; ++ ++ lpuart5: serial@29a0000 { ++ compatible = "fsl,ls1021a-lpuart"; ++ reg = <0x0 0x29a0000 0x0 0x1000>; ++ interrupts = ; ++ clocks = <&clockgen 4 1>; ++ clock-names = "ipg"; ++ status = "disabled"; ++ }; ++ ++ ftm0: ftm0@29d0000 { ++ compatible = "fsl,ftm-alarm"; ++ reg = <0x0 0x29d0000 0x0 0x10000>, ++ <0x0 0x1ee2140 0x0 0x4>; ++ reg-names = "ftm", "FlexTimer1"; ++ interrupts = ; ++ big-endian; ++ }; ++ ++ wdog0: watchdog@2ad0000 { ++ compatible = "fsl,imx21-wdt"; ++ reg = <0x0 0x2ad0000 0x0 0x10000>; ++ interrupts = ; ++ clocks = <&clockgen 4 1>; ++ big-endian; ++ }; ++ ++ edma0: edma@2c00000 { ++ #dma-cells = <2>; ++ compatible = "fsl,vf610-edma"; ++ reg = <0x0 0x2c00000 0x0 0x10000>, ++ <0x0 0x2c10000 0x0 0x10000>, ++ <0x0 0x2c20000 0x0 0x10000>; ++ interrupts = , ++ ; ++ interrupt-names = "edma-tx", "edma-err"; ++ dma-channels = <32>; ++ big-endian; ++ clock-names = "dmamux0", "dmamux1"; ++ clocks = <&clockgen 4 1>, ++ <&clockgen 4 1>; ++ }; ++ ++ usb0: usb@2f00000 { ++ compatible = "snps,dwc3"; ++ reg = <0x0 0x2f00000 0x0 0x10000>; ++ interrupts = ; ++ dr_mode = "host"; ++ snps,quirk-frame-length-adjustment = <0x20>; ++ snps,dis_rxdet_inp3_quirk; ++ }; ++ ++ usb1: usb@3000000 { ++ compatible = "snps,dwc3"; ++ reg = <0x0 0x3000000 0x0 0x10000>; ++ interrupts = ; ++ dr_mode = "host"; ++ snps,quirk-frame-length-adjustment = <0x20>; ++ snps,dis_rxdet_inp3_quirk; ++ }; ++ ++ usb2: usb@3100000 { ++ compatible = "snps,dwc3"; ++ reg = <0x0 0x3100000 0x0 0x10000>; ++ interrupts = ; ++ dr_mode = "host"; ++ snps,quirk-frame-length-adjustment = <0x20>; ++ snps,dis_rxdet_inp3_quirk; ++ }; ++ ++ sata: sata@3200000 { ++ compatible = "fsl,ls1046a-ahci"; ++ reg = <0x0 0x3200000 0x0 0x10000>, ++ <0x0 0x20140520 0x0 0x4>; ++ reg-names = "ahci", "sata-ecc"; ++ interrupts = ; ++ clocks = <&clockgen 4 1>; ++ dma-coherent; ++ }; ++ ++ qdma: qdma@8380000 { ++ compatible = "fsl,ls1046a-qdma", "fsl,ls1021a-qdma"; ++ reg = <0x0 0x8380000 0x0 0x1000>, /* Controller regs */ ++ <0x0 0x8390000 0x0 0x10000>, /* Status regs */ ++ <0x0 0x83a0000 0x0 0x40000>; /* Block regs */ ++ interrupts = <0 153 0x4>, ++ <0 39 0x4>; ++ interrupt-names = "qdma-error", "qdma-queue"; ++ channels = <8>; ++ queues = <2>; ++ status-sizes = <64>; ++ queue-sizes = <64 64>; ++ big-endian; ++ }; ++ ++ msi1: msi-controller@1580000 { ++ compatible = "fsl,ls1046a-msi"; ++ msi-controller; ++ reg = <0x0 0x1580000 0x0 0x10000>; ++ interrupts = , ++ , ++ , ++ ; ++ }; ++ ++ msi2: msi-controller@1590000 { ++ compatible = "fsl,ls1046a-msi"; ++ msi-controller; ++ reg = <0x0 0x1590000 0x0 0x10000>; ++ interrupts = , ++ , ++ , ++ ; ++ }; ++ ++ msi3: msi-controller@15a0000 { ++ compatible = "fsl,ls1046a-msi"; ++ msi-controller; ++ reg = <0x0 0x15a0000 0x0 0x10000>; ++ interrupts = , ++ , ++ , ++ ; ++ }; ++ ++ pcie@3400000 { ++ compatible = "fsl,ls1046a-pcie", "snps,dw-pcie"; ++ reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ ++ 0x40 0x00000000 0x0 0x00002000>; /* configuration space */ ++ reg-names = "regs", "config"; ++ interrupts = , /* PME interrupt */ ++ ; /* aer interrupt */ ++ interrupt-names = "pme", "aer"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ dma-coherent; ++ num-lanes = <4>; ++ bus-range = <0x0 0xff>; ++ ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000 /* downstream I/O */ ++ 0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ ++ msi-parent = <&msi1>, <&msi2>, <&msi3>; ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0000 0 0 1 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 2 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 3 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 4 &gic GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ ++ pcie@3500000 { ++ compatible = "fsl,ls1046a-pcie", "snps,dw-pcie"; ++ reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */ ++ 0x48 0x00000000 0x0 0x00002000>; /* configuration space */ ++ reg-names = "regs", "config"; ++ interrupts = , ++ ; ++ interrupt-names = "pme", "aer"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ dma-coherent; ++ num-lanes = <2>; ++ bus-range = <0x0 0xff>; ++ ranges = <0x81000000 0x0 0x00000000 0x48 0x00010000 0x0 0x00010000 /* downstream I/O */ ++ 0x82000000 0x0 0x40000000 0x48 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ ++ msi-parent = <&msi1>, <&msi2>, <&msi3>; ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0000 0 0 1 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 2 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 3 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 4 &gic GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ ++ pcie@3600000 { ++ compatible = "fsl,ls1046a-pcie", "snps,dw-pcie"; ++ reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */ ++ 0x50 0x00000000 0x0 0x00002000>; /* configuration space */ ++ reg-names = "regs", "config"; ++ interrupts = , ++ ; ++ interrupt-names = "pme", "aer"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ dma-coherent; ++ num-lanes = <2>; ++ bus-range = <0x0 0xff>; ++ ranges = <0x81000000 0x0 0x00000000 0x50 0x00010000 0x0 0x00010000 /* downstream I/O */ ++ 0x82000000 0x0 0x40000000 0x50 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ ++ msi-parent = <&msi1>, <&msi2>, <&msi3>; ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0000 0 0 1 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 2 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 3 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 4 &gic GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ ++ }; ++ ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ bman_fbpr: bman-fbpr { ++ compatible = "shared-dma-pool"; ++ size = <0 0x1000000>; ++ alignment = <0 0x1000000>; ++ no-map; ++ }; ++ qman_fqd: qman-fqd { ++ compatible = "shared-dma-pool"; ++ size = <0 0x800000>; ++ alignment = <0 0x800000>; ++ no-map; ++ }; ++ qman_pfdr: qman-pfdr { ++ compatible = "shared-dma-pool"; ++ size = <0 0x2000000>; ++ alignment = <0 0x2000000>; ++ no-map; ++ }; ++ }; ++}; ++ ++#include "qoriq-qman1-portals.dtsi" ++#include "qoriq-bman1-portals.dtsi" +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts +new file mode 100644 +index 00000000..f61ec261 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a-qds.dts +@@ -0,0 +1,173 @@ ++/* ++ * Device Tree file for NXP LS1088A QDS Board. ++ * ++ * Copyright 2017 NXP ++ * ++ * Harninder Rai ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 "fsl-ls1088a.dtsi" ++ ++/ { ++ model = "LS1088A QDS Board"; ++ compatible = "fsl,ls1088a-qds", "fsl,ls1088a"; ++}; ++ ++&i2c0 { ++ status = "okay"; ++ ++ i2c-switch@77 { ++ compatible = "nxp,pca9547"; ++ reg = <0x77>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x2>; ++ ++ ina220@40 { ++ compatible = "ti,ina220"; ++ reg = <0x40>; ++ shunt-resistor = <1000>; ++ }; ++ ++ ina220@41 { ++ compatible = "ti,ina220"; ++ reg = <0x41>; ++ shunt-resistor = <1000>; ++ }; ++ }; ++ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x3>; ++ ++ temp-sensor@4c { ++ compatible = "adi,adt7461a"; ++ reg = <0x4c>; ++ }; ++ ++ rtc@51 { ++ compatible = "nxp,pcf2129"; ++ reg = <0x51>; ++ /* IRQ10_B */ ++ interrupts = <0 150 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ ++ eeprom@56 { ++ compatible = "atmel,24c512"; ++ reg = <0x56>; ++ }; ++ ++ eeprom@57 { ++ compatible = "atmel,24c512"; ++ reg = <0x57>; ++ }; ++ }; ++ }; ++}; ++ ++&qspi { ++ status = "okay"; ++ qflash0: s25fs512s@0 { ++ compatible = "spansion,m25p80"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ spi-max-frequency = <20000000>; ++ m25p,fast-read; ++ reg = <0>; ++ }; ++ ++ qflash1: s25fs512s@1 { ++ compatible = "spansion,m25p80"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ spi-max-frequency = <20000000>; ++ m25p,fast-read; ++ reg = <1>; ++ }; ++}; ++ ++&ifc { ++ status = "okay"; ++ ++ ranges = <0 0 0x5 0x80000000 0x08000000 ++ 2 0 0x5 0x30000000 0x00010000 ++ 3 0 0x5 0x20000000 0x00010000>; ++ ++ nor@0,0 { ++ compatible = "cfi-flash"; ++ reg = <0x0 0x0 0x8000000>; ++ bank-width = <2>; ++ device-width = <1>; ++ }; ++ ++ nand@2,0 { ++ compatible = "fsl,ifc-nand"; ++ reg = <0x2 0x0 0x10000>; ++ }; ++ ++ fpga: board-control@3,0 { ++ compatible = "fsl,ls1088aqds-fpga", "fsl,fpga-qixis"; ++ reg = <0x3 0x0 0x0000100>; ++ }; ++}; ++ ++&duart0 { ++ status = "okay"; ++}; ++ ++&duart1 { ++ status = "okay"; ++}; ++ ++&esdhc { ++ status = "okay"; ++}; ++ ++&sata { ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts +new file mode 100644 +index 00000000..a4cbc2d5 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts +@@ -0,0 +1,236 @@ ++/* ++ * Device Tree file for NXP LS1088A RDB Board. ++ * ++ * Copyright 2017 NXP ++ * ++ * Harninder Rai ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 "fsl-ls1088a.dtsi" ++ ++/ { ++ model = "L1088A RDB Board"; ++ compatible = "fsl,ls1088a-rdb", "fsl,ls1088a"; ++}; ++ ++&i2c0 { ++ status = "okay"; ++ ++ i2c-switch@77 { ++ compatible = "nxp,pca9547"; ++ reg = <0x77>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x2>; ++ ++ ina220@40 { ++ compatible = "ti,ina220"; ++ reg = <0x40>; ++ shunt-resistor = <1000>; ++ }; ++ }; ++ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x3>; ++ ++ temp-sensor@4c { ++ compatible = "adi,adt7461a"; ++ reg = <0x4c>; ++ }; ++ ++ rtc@51 { ++ compatible = "nxp,pcf2129"; ++ reg = <0x51>; ++ /* IRQ10_B */ ++ interrupts = <0 150 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ }; ++ }; ++}; ++ ++&qspi { ++ status = "okay"; ++ qflash0: s25fs512s@0 { ++ compatible = "spansion,m25p80"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ m25p,fast-read; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++ ++ qflash1: s25fs512s@1 { ++ compatible = "spansion,m25p80"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ m25p,fast-read; ++ spi-max-frequency = <20000000>; ++ reg = <1>; ++ }; ++}; ++ ++&ifc { ++ status = "okay"; ++ ++ ranges = <0 0 0x5 0x30000000 0x00010000 ++ 2 0 0x5 0x20000000 0x00010000>; ++ ++ nand@0,0 { ++ compatible = "fsl,ifc-nand"; ++ reg = <0x0 0x0 0x10000>; ++ }; ++ ++ fpga: board-control@2,0 { ++ compatible = "fsl,ls1088ardb-fpga", "fsl,fpga-qixis"; ++ reg = <0x2 0x0 0x0000100>; ++ }; ++}; ++ ++&duart0 { ++ status = "okay"; ++}; ++ ++&duart1 { ++ status = "okay"; ++}; ++ ++&usb0 { ++ status = "okay"; ++}; ++ ++&usb1 { ++ status = "okay"; ++}; ++ ++&esdhc { ++ status = "okay"; ++}; ++ ++&sata { ++ status = "okay"; ++}; ++ ++&emdio1 { ++ /* Freescale F104 PHY1 */ ++ mdio1_phy1: emdio1_phy@1 { ++ reg = <0x1c>; ++ phy-connection-type = "qsgmii"; ++ }; ++ mdio1_phy2: emdio1_phy@2 { ++ reg = <0x1d>; ++ phy-connection-type = "qsgmii"; ++ }; ++ mdio1_phy3: emdio1_phy@3 { ++ reg = <0x1e>; ++ phy-connection-type = "qsgmii"; ++ }; ++ mdio1_phy4: emdio1_phy@4 { ++ reg = <0x1f>; ++ phy-connection-type = "qsgmii"; ++ }; ++ /* F104 PHY2 */ ++ mdio1_phy5: emdio1_phy@5 { ++ reg = <0x0c>; ++ phy-connection-type = "qsgmii"; ++ }; ++ mdio1_phy6: emdio1_phy@6 { ++ reg = <0x0d>; ++ phy-connection-type = "qsgmii"; ++ }; ++ mdio1_phy7: emdio1_phy@7 { ++ reg = <0x0e>; ++ phy-connection-type = "qsgmii"; ++ }; ++ mdio1_phy8: emdio1_phy@8 { ++ reg = <0x0f>; ++ phy-connection-type = "qsgmii"; ++ }; ++}; ++ ++&emdio2 { ++ /* Aquantia AQR105 10G PHY */ ++ mdio2_phy1: emdio2_phy@1 { ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ interrupts = <0 2 0x4>; ++ reg = <0x0>; ++ phy-connection-type = "xfi"; ++ }; ++}; ++ ++/* DPMAC connections to external PHYs ++ * based on LS1088A RM RevC - $24.1.2 SerDes Options ++ */ ++/* DPMAC1 is 10G SFP+, fixed link */ ++&dpmac2 { ++ phy-handle = <&mdio2_phy1>; ++}; ++&dpmac3 { ++ phy-handle = <&mdio1_phy5>; ++}; ++&dpmac4 { ++ phy-handle = <&mdio1_phy6>; ++}; ++&dpmac5 { ++ phy-handle = <&mdio1_phy7>; ++}; ++&dpmac6 { ++ phy-handle = <&mdio1_phy8>; ++}; ++&dpmac7 { ++ phy-handle = <&mdio1_phy1>; ++}; ++&dpmac8 { ++ phy-handle = <&mdio1_phy2>; ++}; ++&dpmac9 { ++ phy-handle = <&mdio1_phy3>; ++}; ++&dpmac10 { ++ phy-handle = <&mdio1_phy4>; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi +new file mode 100644 +index 00000000..14585ab2 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi +@@ -0,0 +1,816 @@ ++/* ++ * Device Tree Include file for NXP Layerscape-1088A family SoC. ++ * ++ * Copyright 2017 NXP ++ * ++ * Harninder Rai ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 ++#include ++ ++/ { ++ compatible = "fsl,ls1088a"; ++ interrupt-parent = <&gic>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ aliases { ++ crypto = &crypto; ++ }; ++ ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ /* We have 2 clusters having 4 Cortex-A53 cores each */ ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53"; ++ reg = <0x0>; ++ clocks = <&clockgen 1 0>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53"; ++ reg = <0x1>; ++ clocks = <&clockgen 1 0>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ cpu2: cpu@2 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53"; ++ reg = <0x2>; ++ clocks = <&clockgen 1 0>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ cpu3: cpu@3 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53"; ++ reg = <0x3>; ++ clocks = <&clockgen 1 0>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ cpu4: cpu@100 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53"; ++ reg = <0x100>; ++ clocks = <&clockgen 1 1>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ cpu5: cpu@101 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53"; ++ reg = <0x101>; ++ clocks = <&clockgen 1 1>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ cpu6: cpu@102 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53"; ++ reg = <0x102>; ++ clocks = <&clockgen 1 1>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ cpu7: cpu@103 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a53"; ++ reg = <0x103>; ++ clocks = <&clockgen 1 1>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ }; ++ ++ idle-states { ++ /* ++ * PSCI node is not added default, U-boot will add missing ++ * parts if it determines to use PSCI. ++ */ ++ entry-method = "arm,psci"; ++ ++ CPU_PH20: cpu-ph20 { ++ compatible = "arm,idle-state"; ++ idle-state-name = "PH20"; ++ arm,psci-suspend-param = <0x0>; ++ entry-latency-us = <1000>; ++ exit-latency-us = <1000>; ++ min-residency-us = <3000>; ++ }; ++ }; ++ ++ gic: interrupt-controller@6000000 { ++ compatible = "arm,gic-v3"; ++ #interrupt-cells = <3>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ interrupt-controller; ++ reg = <0x0 0x06000000 0 0x10000>, /* GIC Dist */ ++ <0x0 0x06100000 0 0x100000>, /* GICR(RD_base+SGI_base)*/ ++ <0x0 0x0c0c0000 0 0x2000>, /* GICC */ ++ <0x0 0x0c0d0000 0 0x1000>, /* GICH */ ++ <0x0 0x0c0e0000 0 0x20000>; /* GICV */ ++ interrupts = <1 9 IRQ_TYPE_LEVEL_HIGH>; ++ ++ its: gic-its@6020000 { ++ compatible = "arm,gic-v3-its"; ++ msi-controller; ++ reg = <0x0 0x6020000 0 0x20000>; ++ }; ++ }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupts = <1 13 IRQ_TYPE_LEVEL_LOW>,/* Physical Secure PPI */ ++ <1 14 IRQ_TYPE_LEVEL_LOW>,/* Physical Non-Secure PPI */ ++ <1 11 IRQ_TYPE_LEVEL_LOW>,/* Virtual PPI */ ++ <1 10 IRQ_TYPE_LEVEL_LOW>;/* Hypervisor PPI */ ++ }; ++ ++ fsl_mc: fsl-mc@80c000000 { ++ compatible = "fsl,qoriq-mc"; ++ reg = <0x00000008 0x0c000000 0 0x40>, /* MC portal base */ ++ <0x00000000 0x08340000 0 0x40000>; /* MC control reg */ ++ msi-parent = <&its>; ++ iommu-map = <0 &smmu 0 0>; /* This is fixed-up by u-boot */ ++ #address-cells = <3>; ++ #size-cells = <1>; ++ ++ /* ++ * Region type 0x0 - MC portals ++ * Region type 0x1 - QBMAN portals ++ */ ++ ranges = <0x0 0x0 0x0 0x8 0x0c000000 0x4000000 ++ 0x1 0x0 0x0 0x8 0x18000000 0x8000000>; ++ ++ dpmacs { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ dpmac1: dpmac@1 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <1>; ++ }; ++ dpmac2: dpmac@2 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <2>; ++ }; ++ dpmac3: dpmac@3 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <3>; ++ }; ++ dpmac4: dpmac@4 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <4>; ++ }; ++ dpmac5: dpmac@5 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <5>; ++ }; ++ dpmac6: dpmac@6 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <6>; ++ }; ++ dpmac7: dpmac@7 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <7>; ++ }; ++ dpmac8: dpmac@8 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <8>; ++ }; ++ dpmac9: dpmac@9 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <9>; ++ }; ++ dpmac10: dpmac@10 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <0xa>; ++ }; ++ }; ++ ++ }; ++ ++ sysclk: sysclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <100000000>; ++ clock-output-names = "sysclk"; ++ }; ++ ++ dcfg: dcfg@1e00000 { ++ compatible = "fsl,ls1088a-dcfg", "syscon"; ++ reg = <0x0 0x1e00000 0x0 0x10000>; ++ little-endian; ++ }; ++ ++ rstcr: syscon@1e60000 { ++ compatible = "fsl,ls1088a-rstcr", "syscon"; ++ reg = <0x0 0x1e60000 0x0 0x4>; ++ }; ++ ++ reboot { ++ compatible = "syscon-reboot"; ++ regmap = <&rstcr>; ++ offset = <0x0>; ++ mask = <0x02>; ++ }; ++ ++ ++ soc { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ clockgen: clocking@1300000 { ++ compatible = "fsl,ls1088a-clockgen"; ++ reg = <0 0x1300000 0 0xa0000>; ++ #clock-cells = <2>; ++ clocks = <&sysclk>; ++ }; ++ ++ tmu: tmu@1f80000 { ++ compatible = "fsl,qoriq-tmu"; ++ reg = <0x0 0x1f80000 0x0 0x10000>; ++ interrupts = <0 23 0x4>; ++ fsl,tmu-range = <0xb0000 0x9002a 0x6004c 0x30062>; ++ fsl,tmu-calibration = ++ /* Calibration data group 1 */ ++ <0x00000000 0x00000026 ++ 0x00000001 0x0000002d ++ 0x00000002 0x00000032 ++ 0x00000003 0x00000039 ++ 0x00000004 0x0000003f ++ 0x00000005 0x00000046 ++ 0x00000006 0x0000004d ++ 0x00000007 0x00000054 ++ 0x00000008 0x0000005a ++ 0x00000009 0x00000061 ++ 0x0000000a 0x0000006a ++ 0x0000000b 0x00000071 ++ /* Calibration data group 2 */ ++ 0x00010000 0x00000025 ++ 0x00010001 0x0000002c ++ 0x00010002 0x00000035 ++ 0x00010003 0x0000003d ++ 0x00010004 0x00000045 ++ 0x00010005 0x0000004e ++ 0x00010006 0x00000057 ++ 0x00010007 0x00000061 ++ 0x00010008 0x0000006b ++ 0x00010009 0x00000076 ++ /* Calibration data group 3 */ ++ 0x00020000 0x00000029 ++ 0x00020001 0x00000033 ++ 0x00020002 0x0000003d ++ 0x00020003 0x00000049 ++ 0x00020004 0x00000056 ++ 0x00020005 0x00000061 ++ 0x00020006 0x0000006d ++ /* Calibration data group 4 */ ++ 0x00030000 0x00000021 ++ 0x00030001 0x0000002a ++ 0x00030002 0x0000003c ++ 0x00030003 0x0000004e>; ++ little-endian; ++ #thermal-sensor-cells = <1>; ++ }; ++ ++ thermal-zones { ++ cpu_thermal: cpu-thermal { ++ polling-delay-passive = <1000>; ++ polling-delay = <5000>; ++ thermal-sensors = <&tmu 0>; ++ ++ trips { ++ cpu_alert: cpu-alert { ++ temperature = <85000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ ++ cpu_crit: cpu-crit { ++ temperature = <95000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map0 { ++ trip = <&cpu_alert>; ++ cooling-device = ++ <&cpu0 THERMAL_NO_LIMIT ++ THERMAL_NO_LIMIT>; ++ }; ++ map1 { ++ trip = <&cpu_alert>; ++ cooling-device = ++ <&cpu4 THERMAL_NO_LIMIT ++ THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ }; ++ ++ duart0: serial@21c0500 { ++ compatible = "fsl,ns16550", "ns16550a"; ++ reg = <0x0 0x21c0500 0x0 0x100>; ++ clocks = <&clockgen 4 3>; ++ interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>; ++ status = "disabled"; ++ }; ++ ++ duart1: serial@21c0600 { ++ compatible = "fsl,ns16550", "ns16550a"; ++ reg = <0x0 0x21c0600 0x0 0x100>; ++ clocks = <&clockgen 4 3>; ++ interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>; ++ status = "disabled"; ++ }; ++ ++ cluster1_core0_watchdog: wdt@c000000 { ++ compatible = "arm,sp805-wdt", "arm,primecell"; ++ reg = <0x0 0xc000000 0x0 0x1000>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "apb_pclk", "wdog_clk"; ++ }; ++ ++ cluster1_core1_watchdog: wdt@c010000 { ++ compatible = "arm,sp805-wdt", "arm,primecell"; ++ reg = <0x0 0xc010000 0x0 0x1000>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "apb_pclk", "wdog_clk"; ++ }; ++ ++ cluster1_core2_watchdog: wdt@c020000 { ++ compatible = "arm,sp805-wdt", "arm,primecell"; ++ reg = <0x0 0xc020000 0x0 0x1000>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "apb_pclk", "wdog_clk"; ++ }; ++ ++ cluster1_core3_watchdog: wdt@c030000 { ++ compatible = "arm,sp805-wdt", "arm,primecell"; ++ reg = <0x0 0xc030000 0x0 0x1000>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "apb_pclk", "wdog_clk"; ++ }; ++ ++ cluster2_core0_watchdog: wdt@c100000 { ++ compatible = "arm,sp805-wdt", "arm,primecell"; ++ reg = <0x0 0xc100000 0x0 0x1000>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "apb_pclk", "wdog_clk"; ++ }; ++ ++ cluster2_core1_watchdog: wdt@c110000 { ++ compatible = "arm,sp805-wdt", "arm,primecell"; ++ reg = <0x0 0xc110000 0x0 0x1000>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "apb_pclk", "wdog_clk"; ++ }; ++ ++ cluster2_core2_watchdog: wdt@c120000 { ++ compatible = "arm,sp805-wdt", "arm,primecell"; ++ reg = <0x0 0xc120000 0x0 0x1000>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "apb_pclk", "wdog_clk"; ++ }; ++ ++ cluster2_core3_watchdog: wdt@c130000 { ++ compatible = "arm,sp805-wdt", "arm,primecell"; ++ reg = <0x0 0xc130000 0x0 0x1000>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "apb_pclk", "wdog_clk"; ++ }; ++ ++ gpio0: gpio@2300000 { ++ compatible = "fsl,qoriq-gpio"; ++ reg = <0x0 0x2300000 0x0 0x10000>; ++ interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio1: gpio@2310000 { ++ compatible = "fsl,qoriq-gpio"; ++ reg = <0x0 0x2310000 0x0 0x10000>; ++ interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio2: gpio@2320000 { ++ compatible = "fsl,qoriq-gpio"; ++ reg = <0x0 0x2320000 0x0 0x10000>; ++ interrupts = <0 37 IRQ_TYPE_LEVEL_HIGH>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio3: gpio@2330000 { ++ compatible = "fsl,qoriq-gpio"; ++ reg = <0x0 0x2330000 0x0 0x10000>; ++ interrupts = <0 37 IRQ_TYPE_LEVEL_HIGH>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ /* TODO: WRIOP (CCSR?) */ ++ emdio1: mdio@0x8B96000 { /* WRIOP0: 0x8B8_0000, ++ * E-MDIO1: 0x1_6000 ++ */ ++ compatible = "fsl,fman-memac-mdio"; ++ reg = <0x0 0x8B96000 0x0 0x1000>; ++ device_type = "mdio"; ++ little-endian; /* force the driver in LE mode */ ++ ++ /* Not necessary on the QDS, but needed on the RDB */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ emdio2: mdio@0x8B97000 { /* WRIOP0: 0x8B8_0000, ++ * E-MDIO2: 0x1_7000 ++ */ ++ compatible = "fsl,fman-memac-mdio"; ++ reg = <0x0 0x8B97000 0x0 0x1000>; ++ device_type = "mdio"; ++ little-endian; /* force the driver in LE mode */ ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ ifc: ifc@2240000 { ++ compatible = "fsl,ifc", "simple-bus"; ++ reg = <0x0 0x2240000 0x0 0x20000>; ++ interrupts = <0 21 IRQ_TYPE_LEVEL_HIGH>; ++ little-endian; ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ++ }; ++ ++ ftm0: ftm0@2800000 { ++ compatible = "fsl,ftm-alarm"; ++ reg = <0x0 0x2800000 0x0 0x10000>; ++ interrupts = <0 44 4>; ++ }; ++ ++ i2c0: i2c@2000000 { ++ compatible = "fsl,vf610-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x2000000 0x0 0x10000>; ++ interrupts = <0 34 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clockgen 4 3>; ++ status = "disabled"; ++ }; ++ ++ i2c1: i2c@2010000 { ++ compatible = "fsl,vf610-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x2010000 0x0 0x10000>; ++ interrupts = <0 34 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clockgen 4 3>; ++ status = "disabled"; ++ }; ++ ++ i2c2: i2c@2020000 { ++ compatible = "fsl,vf610-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x2020000 0x0 0x10000>; ++ interrupts = <0 35 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clockgen 4 3>; ++ status = "disabled"; ++ }; ++ ++ i2c3: i2c@2030000 { ++ compatible = "fsl,vf610-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x2030000 0x0 0x10000>; ++ interrupts = <0 35 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clockgen 4 3>; ++ status = "disabled"; ++ }; ++ ++ qspi: quadspi@20c0000 { ++ compatible = "fsl,ls2080a-qspi", "fsl,ls1088a-qspi"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x20c0000 0x0 0x10000>, ++ <0x0 0x20000000 0x0 0x10000000>; ++ reg-names = "QuadSPI", "QuadSPI-memory"; ++ interrupts = <0 25 0x4>; /* Level high type */ ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "qspi_en", "qspi"; ++ fsl,qspi-has-second-chip; ++ }; ++ ++ esdhc: esdhc@2140000 { ++ compatible = "fsl,ls1088a-esdhc", "fsl,esdhc"; ++ reg = <0x0 0x2140000 0x0 0x10000>; ++ interrupts = <0 28 0x4>; /* Level high type */ ++ clock-frequency = <0>; ++ voltage-ranges = <1800 1800 3300 3300>; ++ sdhci,auto-cmd12; ++ little-endian; ++ bus-width = <4>; ++ status = "disabled"; ++ }; ++ ++ usb0: usb3@3100000 { ++ compatible = "snps,dwc3"; ++ reg = <0x0 0x3100000 0x0 0x10000>; ++ interrupts = <0 80 0x4>; /* Level high type */ ++ dr_mode = "host"; ++ configure-gfladj; ++ snps,dis_rxdet_inp3_quirk; ++ }; ++ ++ usb1: usb3@3110000 { ++ compatible = "snps,dwc3"; ++ reg = <0x0 0x3110000 0x0 0x10000>; ++ interrupts = <0 81 0x4>; /* Level high type */ ++ dr_mode = "host"; ++ configure-gfladj; ++ snps,dis_rxdet_inp3_quirk; ++ }; ++ ++ sata: sata@3200000 { ++ compatible = "fsl,ls1088a-ahci"; ++ reg = <0x0 0x3200000 0x0 0x10000>, ++ <0x7 0x100520 0x0 0x4>; ++ reg-names = "ahci", "sata-ecc"; ++ interrupts = <0 133 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&clockgen 4 3>; ++ dma-coherent; ++ status = "disabled"; ++ }; ++ ++ pcie@3400000 { ++ compatible = "fsl,ls2088a-pcie", "fsl,ls1088a-pcie", ++ "snps,dw-pcie"; ++ reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ ++ 0x20 0x00000000 0x0 0x00002000>; /* configuration space */ ++ reg-names = "regs", "config"; ++ interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>; /* aer interrupt */ ++ interrupt-names = "aer"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ dma-coherent; ++ num-lanes = <4>; ++ bus-range = <0x0 0xff>; ++ ranges = <0x81000000 0x0 0x00000000 0x20 0x00010000 0x0 0x00010000 /* downstream I/O */ ++ 0x82000000 0x0 0x40000000 0x20 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ ++ msi-parent = <&its>; ++ iommu-map = <0 &smmu 0 1>; /* This is fixed-up by u-boot */ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0000 0 0 1 &gic 0 0 0 109 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 2 &gic 0 0 0 110 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 3 &gic 0 0 0 111 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 4 &gic 0 0 0 112 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ ++ pcie@3500000 { ++ compatible = "fsl,ls2088a-pcie", "fsl,ls1088a-pcie", ++ "snps,dw-pcie"; ++ reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */ ++ 0x28 0x00000000 0x0 0x00002000>; /* configuration space */ ++ reg-names = "regs", "config"; ++ interrupts = <0 113 IRQ_TYPE_LEVEL_HIGH>; /* aer interrupt */ ++ interrupt-names = "aer"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ dma-coherent; ++ num-lanes = <4>; ++ bus-range = <0x0 0xff>; ++ ranges = <0x81000000 0x0 0x00000000 0x28 0x00010000 0x0 0x00010000 /* downstream I/O */ ++ 0x82000000 0x0 0x40000000 0x28 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ ++ msi-parent = <&its>; ++ iommu-map = <0 &smmu 0 1>; /* This is fixed-up by u-boot */ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0000 0 0 1 &gic 0 0 0 114 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 2 &gic 0 0 0 115 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 3 &gic 0 0 0 116 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 4 &gic 0 0 0 117 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ ++ pcie@3600000 { ++ compatible = "fsl,ls2088a-pcie", "fsl,ls1088a-pcie", ++ "snps,dw-pcie"; ++ reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */ ++ 0x30 0x00000000 0x0 0x00002000>; /* configuration space */ ++ reg-names = "regs", "config"; ++ interrupts = <0 118 IRQ_TYPE_LEVEL_HIGH>; /* aer interrupt */ ++ interrupt-names = "aer"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ dma-coherent; ++ num-lanes = <8>; ++ bus-range = <0x0 0xff>; ++ ranges = <0x81000000 0x0 0x00000000 0x30 0x00010000 0x0 0x00010000 /* downstream I/O */ ++ 0x82000000 0x0 0x40000000 0x30 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ ++ msi-parent = <&its>; ++ iommu-map = <0 &smmu 0 1>; /* This is fixed-up by u-boot */ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0000 0 0 1 &gic 0 0 0 119 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 2 &gic 0 0 0 120 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 3 &gic 0 0 0 121 IRQ_TYPE_LEVEL_HIGH>, ++ <0000 0 0 4 &gic 0 0 0 122 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ ++ smmu: iommu@5000000 { ++ compatible = "arm,mmu-500"; ++ reg = <0 0x5000000 0 0x800000>; ++ #global-interrupts = <12>; ++ #iommu-cells = <1>; ++ stream-match-mask = <0x7C00>; ++ interrupts = <0 13 4>, /* global secure fault */ ++ <0 14 4>, /* combined secure interrupt */ ++ <0 15 4>, /* global non-secure fault */ ++ <0 16 4>, /* combined non-secure interrupt */ ++ /* performance counter interrupts 0-7 */ ++ <0 211 4>, ++ <0 212 4>, ++ <0 213 4>, ++ <0 214 4>, ++ <0 215 4>, ++ <0 216 4>, ++ <0 217 4>, ++ <0 218 4>, ++ /* per context interrupt, 64 interrupts */ ++ <0 146 4>, ++ <0 147 4>, ++ <0 148 4>, ++ <0 149 4>, ++ <0 150 4>, ++ <0 151 4>, ++ <0 152 4>, ++ <0 153 4>, ++ <0 154 4>, ++ <0 155 4>, ++ <0 156 4>, ++ <0 157 4>, ++ <0 158 4>, ++ <0 159 4>, ++ <0 160 4>, ++ <0 161 4>, ++ <0 162 4>, ++ <0 163 4>, ++ <0 164 4>, ++ <0 165 4>, ++ <0 166 4>, ++ <0 167 4>, ++ <0 168 4>, ++ <0 169 4>, ++ <0 170 4>, ++ <0 171 4>, ++ <0 172 4>, ++ <0 173 4>, ++ <0 174 4>, ++ <0 175 4>, ++ <0 176 4>, ++ <0 177 4>, ++ <0 178 4>, ++ <0 179 4>, ++ <0 180 4>, ++ <0 181 4>, ++ <0 182 4>, ++ <0 183 4>, ++ <0 184 4>, ++ <0 185 4>, ++ <0 186 4>, ++ <0 187 4>, ++ <0 188 4>, ++ <0 189 4>, ++ <0 190 4>, ++ <0 191 4>, ++ <0 192 4>, ++ <0 193 4>, ++ <0 194 4>, ++ <0 195 4>, ++ <0 196 4>, ++ <0 197 4>, ++ <0 198 4>, ++ <0 199 4>, ++ <0 200 4>, ++ <0 201 4>, ++ <0 202 4>, ++ <0 203 4>, ++ <0 204 4>, ++ <0 205 4>, ++ <0 206 4>, ++ <0 207 4>, ++ <0 208 4>, ++ <0 209 4>; ++ }; ++ ++ crypto: crypto@8000000 { ++ compatible = "fsl,sec-v5.0", "fsl,sec-v4.0"; ++ fsl,sec-era = <8>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0x0 0x00 0x8000000 0x100000>; ++ reg = <0x00 0x8000000 0x0 0x100000>; ++ interrupts = ; ++ dma-coherent; ++ ++ sec_jr0: jr@10000 { ++ compatible = "fsl,sec-v5.0-job-ring", ++ "fsl,sec-v4.0-job-ring"; ++ reg = <0x10000 0x10000>; ++ interrupts = ; ++ }; ++ ++ sec_jr1: jr@20000 { ++ compatible = "fsl,sec-v5.0-job-ring", ++ "fsl,sec-v4.0-job-ring"; ++ reg = <0x20000 0x10000>; ++ interrupts = ; ++ }; ++ ++ sec_jr2: jr@30000 { ++ compatible = "fsl,sec-v5.0-job-ring", ++ "fsl,sec-v4.0-job-ring"; ++ reg = <0x30000 0x10000>; ++ interrupts = ; ++ }; ++ ++ sec_jr3: jr@40000 { ++ compatible = "fsl,sec-v5.0-job-ring", ++ "fsl,sec-v4.0-job-ring"; ++ reg = <0x40000 0x10000>; ++ interrupts = ; ++ }; ++ }; ++ }; ++ ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts +index b0dd0109..ba1a79dd 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts ++++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts +@@ -1,8 +1,10 @@ + /* + * Device Tree file for Freescale LS2080a QDS Board. + * +- * Copyright (C) 2015, Freescale Semiconductor ++ * Copyright 2015-2016 Freescale Semiconductor, Inc. ++ * Copyright 2017 NXP + * ++ * Abhimanyu Saini + * Bhupesh Sharma + * + * This file is dual-licensed: you can use it either under the terms +@@ -46,169 +48,76 @@ + + /dts-v1/; + +-/include/ "fsl-ls2080a.dtsi" ++#include "fsl-ls2080a.dtsi" ++#include "fsl-ls208xa-qds.dtsi" + + / { + model = "Freescale Layerscape 2080a QDS Board"; + compatible = "fsl,ls2080a-qds", "fsl,ls2080a"; + +- aliases { +- serial0 = &serial0; +- serial1 = &serial1; +- }; +- + chosen { + stdout-path = "serial0:115200n8"; + }; + }; + +-&esdhc { +- status = "okay"; +-}; +- + &ifc { +- status = "okay"; +- #address-cells = <2>; +- #size-cells = <1>; +- ranges = <0x0 0x0 0x5 0x80000000 0x08000000 +- 0x2 0x0 0x5 0x30000000 0x00010000 +- 0x3 0x0 0x5 0x20000000 0x00010000>; +- +- nor@0,0 { ++ boardctrl: board-control@3,0 { + #address-cells = <1>; + #size-cells = <1>; +- compatible = "cfi-flash"; +- reg = <0x0 0x0 0x8000000>; +- bank-width = <2>; +- device-width = <1>; +- }; ++ compatible = "fsl,tetra-fpga", "fsl,fpga-qixis", "simple-bus"; ++ reg = <3 0 0x300>; /* TODO check address */ ++ ranges = <0 3 0 0x300>; + +- nand@2,0 { +- compatible = "fsl,ifc-nand"; +- reg = <0x2 0x0 0x10000>; +- }; ++ mdio_mux_emi1 { ++ compatible = "mdio-mux-mmioreg", "mdio-mux"; ++ mdio-parent-bus = <&emdio1>; ++ reg = <0x54 1>; /* BRDCFG4 */ ++ mux-mask = <0xe0>; /* EMI1_MDIO */ + +- cpld@3,0 { +- reg = <0x3 0x0 0x10000>; +- compatible = "fsl,ls2080aqds-fpga", "fsl,fpga-qixis"; +- }; +-}; +- +-&i2c0 { +- status = "okay"; +- pca9547@77 { +- compatible = "nxp,pca9547"; +- reg = <0x77>; +- #address-cells = <1>; +- #size-cells = <0>; +- i2c@0 { +- #address-cells = <1>; ++ #address-cells=<1>; + #size-cells = <0>; +- reg = <0x00>; +- rtc@68 { +- compatible = "dallas,ds3232"; +- reg = <0x68>; +- }; +- }; + +- i2c@2 { +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <0x02>; +- +- ina220@40 { +- compatible = "ti,ina220"; +- reg = <0x40>; +- shunt-resistor = <500>; +- }; +- +- ina220@41 { +- compatible = "ti,ina220"; +- reg = <0x41>; +- shunt-resistor = <1000>; +- }; +- }; +- +- i2c@3 { +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <0x3>; +- +- adt7481@4c { +- compatible = "adi,adt7461"; +- reg = <0x4c>; ++ /* Child MDIO buses, one for each riser card: ++ * reg = 0x0, 0x20, 0x40, 0x60, 0x80, 0xa0. ++ * VSC8234 PHYs on the riser cards. ++ */ ++ ++ mdio_mux3: mdio@60 { ++ reg = <0x60>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ mdio0_phy12: mdio_phy0@1c { ++ reg = <0x1c>; ++ phy-connection-type = "sgmii"; ++ }; ++ mdio0_phy13: mdio_phy1@1d { ++ reg = <0x1d>; ++ phy-connection-type = "sgmii"; ++ }; ++ mdio0_phy14: mdio_phy2@1e { ++ reg = <0x1e>; ++ phy-connection-type = "sgmii"; ++ }; ++ mdio0_phy15: mdio_phy3@1f { ++ reg = <0x1f>; ++ phy-connection-type = "sgmii"; ++ }; + }; + }; + }; + }; + +-&i2c1 { +- status = "disabled"; +-}; +- +-&i2c2 { +- status = "disabled"; +-}; +- +-&i2c3 { +- status = "disabled"; +-}; +- +-&dspi { +- status = "okay"; +- dflash0: n25q128a { +- #address-cells = <1>; +- #size-cells = <1>; +- compatible = "st,m25p80"; +- spi-max-frequency = <3000000>; +- reg = <0>; +- }; +- dflash1: sst25wf040b { +- #address-cells = <1>; +- #size-cells = <1>; +- compatible = "st,m25p80"; +- spi-max-frequency = <3000000>; +- reg = <1>; +- }; +- dflash2: en25s64 { +- #address-cells = <1>; +- #size-cells = <1>; +- compatible = "st,m25p80"; +- spi-max-frequency = <3000000>; +- reg = <2>; +- }; +-}; +- +-&qspi { +- status = "okay"; +- flash0: s25fl256s1@0 { +- #address-cells = <1>; +- #size-cells = <1>; +- compatible = "st,m25p80"; +- spi-max-frequency = <20000000>; +- reg = <0>; +- }; +- flash2: s25fl256s1@2 { +- #address-cells = <1>; +- #size-cells = <1>; +- compatible = "st,m25p80"; +- spi-max-frequency = <20000000>; +- reg = <0>; +- }; +-}; +- +-&sata0 { +- status = "okay"; ++/* Update DPMAC connections to external PHYs, under SerDes 0x2a_0x49. */ ++&dpmac9 { ++ phy-handle = <&mdio0_phy12>; + }; +- +-&sata1 { +- status = "okay"; ++&dpmac10 { ++ phy-handle = <&mdio0_phy13>; + }; +- +-&usb0 { +- status = "okay"; ++&dpmac11 { ++ phy-handle = <&mdio0_phy14>; + }; +- +-&usb1 { +- status = "okay"; ++&dpmac12 { ++ phy-handle = <&mdio0_phy15>; + }; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts +index ad0ebb8a..025f0f54 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts ++++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts +@@ -1,8 +1,10 @@ + /* + * Device Tree file for Freescale LS2080a RDB Board. + * +- * Copyright (C) 2015, Freescale Semiconductor ++ * Copyright 2016 Freescale Semiconductor, Inc. ++ * Copyright 2017 NXP + * ++ * Abhimanyu Saini + * Bhupesh Sharma + * + * This file is dual-licensed: you can use it either under the terms +@@ -46,125 +48,94 @@ + + /dts-v1/; + +-/include/ "fsl-ls2080a.dtsi" ++#include "fsl-ls2080a.dtsi" ++#include "fsl-ls208xa-rdb.dtsi" + + / { + model = "Freescale Layerscape 2080a RDB Board"; + compatible = "fsl,ls2080a-rdb", "fsl,ls2080a"; + +- aliases { +- serial0 = &serial0; +- serial1 = &serial1; +- }; +- + chosen { + stdout-path = "serial1:115200n8"; + }; + }; + +-&esdhc { +- status = "okay"; +-}; +- +-&ifc { +- status = "okay"; +- #address-cells = <2>; +- #size-cells = <1>; +- ranges = <0x0 0x0 0x5 0x80000000 0x08000000 +- 0x2 0x0 0x5 0x30000000 0x00010000 +- 0x3 0x0 0x5 0x20000000 0x00010000>; +- +- nor@0,0 { +- #address-cells = <1>; +- #size-cells = <1>; +- compatible = "cfi-flash"; +- reg = <0x0 0x0 0x8000000>; +- bank-width = <2>; +- device-width = <1>; ++&emdio1 { ++ status = "disabled"; ++ /* CS4340 PHYs */ ++ mdio1_phy1: emdio1_phy@1 { ++ reg = <0x10>; ++ phy-connection-type = "xfi"; + }; +- +- nand@2,0 { +- compatible = "fsl,ifc-nand"; +- reg = <0x2 0x0 0x10000>; ++ mdio1_phy2: emdio1_phy@2 { ++ reg = <0x11>; ++ phy-connection-type = "xfi"; + }; +- +- cpld@3,0 { +- reg = <0x3 0x0 0x10000>; +- compatible = "fsl,ls2080aqds-fpga", "fsl,fpga-qixis"; ++ mdio1_phy3: emdio1_phy@3 { ++ reg = <0x12>; ++ phy-connection-type = "xfi"; + }; +- +-}; +- +-&i2c0 { +- status = "okay"; +- pca9547@75 { +- compatible = "nxp,pca9547"; +- reg = <0x75>; +- #address-cells = <1>; +- #size-cells = <0>; +- status = "disabled"; +- i2c@1 { +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <0x01>; +- rtc@68 { +- compatible = "dallas,ds3232"; +- reg = <0x68>; +- }; +- }; +- +- i2c@3 { +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <0x3>; +- +- adt7481@4c { +- compatible = "adi,adt7461"; +- reg = <0x4c>; +- }; +- }; ++ mdio1_phy4: emdio1_phy@4 { ++ reg = <0x13>; ++ phy-connection-type = "xfi"; + }; + }; + +-&i2c1 { +- status = "disabled"; +-}; +- +-&i2c2 { +- status = "disabled"; +-}; +- +-&i2c3 { +- status = "disabled"; +-}; +- +-&dspi { +- status = "okay"; +- dflash0: n25q512a { +- #address-cells = <1>; +- #size-cells = <1>; +- compatible = "st,m25p80"; +- spi-max-frequency = <3000000>; +- reg = <0>; ++&emdio2 { ++ /* AQR405 PHYs */ ++ mdio2_phy1: emdio2_phy@1 { ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ interrupts = <0 1 0x4>; /* Level high type */ ++ reg = <0x0>; ++ phy-connection-type = "xfi"; ++ }; ++ mdio2_phy2: emdio2_phy@2 { ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ interrupts = <0 2 0x4>; /* Level high type */ ++ reg = <0x1>; ++ phy-connection-type = "xfi"; ++ }; ++ mdio2_phy3: emdio2_phy@3 { ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ interrupts = <0 4 0x4>; /* Level high type */ ++ reg = <0x2>; ++ phy-connection-type = "xfi"; ++ }; ++ mdio2_phy4: emdio2_phy@4 { ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ interrupts = <0 5 0x4>; /* Level high type */ ++ reg = <0x3>; ++ phy-connection-type = "xfi"; + }; + }; + +-&qspi { +- status = "disabled"; +-}; ++/* Update DPMAC connections to external PHYs, under the assumption of ++ * SerDes 0x2a_0x41. This is currently the only SerDes supported on the board. ++ */ ++/* Leave Cortina nodes commented out until driver is integrated ++ *&dpmac1 { ++ * phy-handle = <&mdio1_phy1>; ++ *}; ++ *&dpmac2 { ++ * phy-handle = <&mdio1_phy2>; ++ *}; ++ *&dpmac3 { ++ * phy-handle = <&mdio1_phy3>; ++ *}; ++ *&dpmac4 { ++ * phy-handle = <&mdio1_phy4>; ++ *}; ++ */ + +-&sata0 { +- status = "okay"; ++&dpmac5 { ++ phy-handle = <&mdio2_phy1>; + }; +- +-&sata1 { +- status = "okay"; ++&dpmac6 { ++ phy-handle = <&mdio2_phy2>; + }; +- +-&usb0 { +- status = "okay"; ++&dpmac7 { ++ phy-handle = <&mdio2_phy3>; + }; +- +-&usb1 { +- status = "okay"; ++&dpmac8 { ++ phy-handle = <&mdio2_phy4>; + }; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a-simu.dts b/arch/arm64/boot/dts/freescale/fsl-ls2080a-simu.dts +index 505d0380..fbbb73e5 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-ls2080a-simu.dts ++++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a-simu.dts +@@ -1,7 +1,7 @@ + /* + * Device Tree file for Freescale LS2080a software Simulator model + * +- * Copyright (C) 2014-2015, Freescale Semiconductor ++ * Copyright 2014-2015 Freescale Semiconductor, Inc. + * + * Bhupesh Sharma + * +@@ -46,17 +46,12 @@ + + /dts-v1/; + +-/include/ "fsl-ls2080a.dtsi" ++#include "fsl-ls2080a.dtsi" + + / { + model = "Freescale Layerscape 2080a software Simulator model"; + compatible = "fsl,ls2080a-simu", "fsl,ls2080a"; + +- aliases { +- serial0 = &serial0; +- serial1 = &serial1; +- }; +- + ethernet@2210000 { + compatible = "smsc,lan91c111"; + reg = <0x0 0x2210000 0x0 0x100>; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi +index 7f0dc13b..71f15fab 100644 +--- a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi ++++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi +@@ -1,8 +1,9 @@ + /* + * Device Tree Include file for Freescale Layerscape-2080A family SoC. + * +- * Copyright (C) 2014-2015, Freescale Semiconductor ++ * Copyright 2014-2016 Freescale Semiconductor, Inc. + * ++ * Abhimanyu Saini + * Bhupesh Sharma + * + * This file is dual-licensed: you can use it either under the terms +@@ -44,696 +45,132 @@ + * OTHER DEALINGS IN THE SOFTWARE. + */ + +-/ { +- compatible = "fsl,ls2080a"; +- interrupt-parent = <&gic>; +- #address-cells = <2>; +- #size-cells = <2>; ++#include "fsl-ls208xa.dtsi" + +- cpus { +- #address-cells = <1>; +- #size-cells = <0>; +- +- /* +- * We expect the enable-method for cpu's to be "psci", but this +- * is dependent on the SoC FW, which will fill this in. +- * +- * Currently supported enable-method is psci v0.2 +- */ +- +- /* We have 4 clusters having 2 Cortex-A57 cores each */ +- cpu@0 { +- device_type = "cpu"; +- compatible = "arm,cortex-a57"; +- reg = <0x0>; +- clocks = <&clockgen 1 0>; +- next-level-cache = <&cluster0_l2>; +- }; +- +- cpu@1 { +- device_type = "cpu"; +- compatible = "arm,cortex-a57"; +- reg = <0x1>; +- clocks = <&clockgen 1 0>; +- next-level-cache = <&cluster0_l2>; +- }; +- +- cpu@100 { +- device_type = "cpu"; +- compatible = "arm,cortex-a57"; +- reg = <0x100>; +- clocks = <&clockgen 1 1>; +- next-level-cache = <&cluster1_l2>; +- }; +- +- cpu@101 { +- device_type = "cpu"; +- compatible = "arm,cortex-a57"; +- reg = <0x101>; +- clocks = <&clockgen 1 1>; +- next-level-cache = <&cluster1_l2>; +- }; +- +- cpu@200 { +- device_type = "cpu"; +- compatible = "arm,cortex-a57"; +- reg = <0x200>; +- clocks = <&clockgen 1 2>; +- next-level-cache = <&cluster2_l2>; +- }; +- +- cpu@201 { +- device_type = "cpu"; +- compatible = "arm,cortex-a57"; +- reg = <0x201>; +- clocks = <&clockgen 1 2>; +- next-level-cache = <&cluster2_l2>; +- }; +- +- cpu@300 { +- device_type = "cpu"; +- compatible = "arm,cortex-a57"; +- reg = <0x300>; +- clocks = <&clockgen 1 3>; +- next-level-cache = <&cluster3_l2>; +- }; +- +- cpu@301 { +- device_type = "cpu"; +- compatible = "arm,cortex-a57"; +- reg = <0x301>; +- clocks = <&clockgen 1 3>; +- next-level-cache = <&cluster3_l2>; +- }; +- +- cluster0_l2: l2-cache0 { +- compatible = "cache"; +- }; +- +- cluster1_l2: l2-cache1 { +- compatible = "cache"; +- }; +- +- cluster2_l2: l2-cache2 { +- compatible = "cache"; +- }; +- +- cluster3_l2: l2-cache3 { +- compatible = "cache"; +- }; ++&cpu { ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a57"; ++ reg = <0x0>; ++ clocks = <&clockgen 1 0>; ++ next-level-cache = <&cluster0_l2>; ++ #cooling-cells = <2>; + }; + +- memory@80000000 { +- device_type = "memory"; +- reg = <0x00000000 0x80000000 0 0x80000000>; +- /* DRAM space - 1, size : 2 GB DRAM */ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a57"; ++ reg = <0x1>; ++ clocks = <&clockgen 1 0>; ++ next-level-cache = <&cluster0_l2>; + }; + +- sysclk: sysclk { +- compatible = "fixed-clock"; +- #clock-cells = <0>; +- clock-frequency = <100000000>; +- clock-output-names = "sysclk"; ++ cpu2: cpu@100 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a57"; ++ reg = <0x100>; ++ clocks = <&clockgen 1 1>; ++ next-level-cache = <&cluster1_l2>; ++ #cooling-cells = <2>; + }; + +- gic: interrupt-controller@6000000 { +- compatible = "arm,gic-v3"; +- reg = <0x0 0x06000000 0 0x10000>, /* GIC Dist */ +- <0x0 0x06100000 0 0x100000>, /* GICR (RD_base + SGI_base) */ +- <0x0 0x0c0c0000 0 0x2000>, /* GICC */ +- <0x0 0x0c0d0000 0 0x1000>, /* GICH */ +- <0x0 0x0c0e0000 0 0x20000>; /* GICV */ +- #interrupt-cells = <3>; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; +- interrupt-controller; +- interrupts = <1 9 0x4>; +- +- its: gic-its@6020000 { +- compatible = "arm,gic-v3-its"; +- msi-controller; +- reg = <0x0 0x6020000 0 0x20000>; +- }; ++ cpu3: cpu@101 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a57"; ++ reg = <0x101>; ++ clocks = <&clockgen 1 1>; ++ next-level-cache = <&cluster1_l2>; + }; + +- rstcr: syscon@1e60000 { +- compatible = "fsl,ls2080a-rstcr", "syscon"; +- reg = <0x0 0x1e60000 0x0 0x4>; ++ cpu4: cpu@200 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a57"; ++ reg = <0x200>; ++ clocks = <&clockgen 1 2>; ++ next-level-cache = <&cluster2_l2>; ++ #cooling-cells = <2>; + }; + +- reboot { +- compatible ="syscon-reboot"; +- regmap = <&rstcr>; +- offset = <0x0>; +- mask = <0x2>; ++ cpu5: cpu@201 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a57"; ++ reg = <0x201>; ++ clocks = <&clockgen 1 2>; ++ next-level-cache = <&cluster2_l2>; + }; + +- timer { +- compatible = "arm,armv8-timer"; +- interrupts = <1 13 4>, /* Physical Secure PPI, active-low */ +- <1 14 4>, /* Physical Non-Secure PPI, active-low */ +- <1 11 4>, /* Virtual PPI, active-low */ +- <1 10 4>; /* Hypervisor PPI, active-low */ +- fsl,erratum-a008585; ++ cpu6: cpu@300 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a57"; ++ reg = <0x300>; ++ clocks = <&clockgen 1 3>; ++ next-level-cache = <&cluster3_l2>; ++ #cooling-cells = <2>; + }; + +- pmu { +- compatible = "arm,armv8-pmuv3"; +- interrupts = <1 7 0x8>; /* PMU PPI, Level low type */ ++ cpu7: cpu@301 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a57"; ++ reg = <0x301>; ++ clocks = <&clockgen 1 3>; ++ next-level-cache = <&cluster3_l2>; + }; + +- soc { +- compatible = "simple-bus"; +- #address-cells = <2>; +- #size-cells = <2>; +- ranges; +- +- clockgen: clocking@1300000 { +- compatible = "fsl,ls2080a-clockgen"; +- reg = <0 0x1300000 0 0xa0000>; +- #clock-cells = <2>; +- clocks = <&sysclk>; +- }; +- +- serial0: serial@21c0500 { +- compatible = "fsl,ns16550", "ns16550a"; +- reg = <0x0 0x21c0500 0x0 0x100>; +- clocks = <&clockgen 4 3>; +- interrupts = <0 32 0x4>; /* Level high type */ +- }; +- +- serial1: serial@21c0600 { +- compatible = "fsl,ns16550", "ns16550a"; +- reg = <0x0 0x21c0600 0x0 0x100>; +- clocks = <&clockgen 4 3>; +- interrupts = <0 32 0x4>; /* Level high type */ +- }; +- +- cluster1_core0_watchdog: wdt@c000000 { +- compatible = "arm,sp805-wdt", "arm,primecell"; +- reg = <0x0 0xc000000 0x0 0x1000>; +- clocks = <&clockgen 4 3>, <&clockgen 4 3>; +- clock-names = "apb_pclk", "wdog_clk"; +- }; +- +- cluster1_core1_watchdog: wdt@c010000 { +- compatible = "arm,sp805-wdt", "arm,primecell"; +- reg = <0x0 0xc010000 0x0 0x1000>; +- clocks = <&clockgen 4 3>, <&clockgen 4 3>; +- clock-names = "apb_pclk", "wdog_clk"; +- }; +- +- cluster2_core0_watchdog: wdt@c100000 { +- compatible = "arm,sp805-wdt", "arm,primecell"; +- reg = <0x0 0xc100000 0x0 0x1000>; +- clocks = <&clockgen 4 3>, <&clockgen 4 3>; +- clock-names = "apb_pclk", "wdog_clk"; +- }; +- +- cluster2_core1_watchdog: wdt@c110000 { +- compatible = "arm,sp805-wdt", "arm,primecell"; +- reg = <0x0 0xc110000 0x0 0x1000>; +- clocks = <&clockgen 4 3>, <&clockgen 4 3>; +- clock-names = "apb_pclk", "wdog_clk"; +- }; +- +- cluster3_core0_watchdog: wdt@c200000 { +- compatible = "arm,sp805-wdt", "arm,primecell"; +- reg = <0x0 0xc200000 0x0 0x1000>; +- clocks = <&clockgen 4 3>, <&clockgen 4 3>; +- clock-names = "apb_pclk", "wdog_clk"; +- }; +- +- cluster3_core1_watchdog: wdt@c210000 { +- compatible = "arm,sp805-wdt", "arm,primecell"; +- reg = <0x0 0xc210000 0x0 0x1000>; +- clocks = <&clockgen 4 3>, <&clockgen 4 3>; +- clock-names = "apb_pclk", "wdog_clk"; +- }; +- +- cluster4_core0_watchdog: wdt@c300000 { +- compatible = "arm,sp805-wdt", "arm,primecell"; +- reg = <0x0 0xc300000 0x0 0x1000>; +- clocks = <&clockgen 4 3>, <&clockgen 4 3>; +- clock-names = "apb_pclk", "wdog_clk"; +- }; +- +- cluster4_core1_watchdog: wdt@c310000 { +- compatible = "arm,sp805-wdt", "arm,primecell"; +- reg = <0x0 0xc310000 0x0 0x1000>; +- clocks = <&clockgen 4 3>, <&clockgen 4 3>; +- clock-names = "apb_pclk", "wdog_clk"; +- }; +- +- fsl_mc: fsl-mc@80c000000 { +- compatible = "fsl,qoriq-mc"; +- reg = <0x00000008 0x0c000000 0 0x40>, /* MC portal base */ +- <0x00000000 0x08340000 0 0x40000>; /* MC control reg */ +- msi-parent = <&its>; +- #address-cells = <3>; +- #size-cells = <1>; +- +- /* +- * Region type 0x0 - MC portals +- * Region type 0x1 - QBMAN portals +- */ +- ranges = <0x0 0x0 0x0 0x8 0x0c000000 0x4000000 +- 0x1 0x0 0x0 0x8 0x18000000 0x8000000>; +- +- /* +- * Define the maximum number of MACs present on the SoC. +- */ +- dpmacs { +- #address-cells = <1>; +- #size-cells = <0>; +- +- dpmac1: dpmac@1 { +- compatible = "fsl,qoriq-mc-dpmac"; +- reg = <0x1>; +- }; +- +- dpmac2: dpmac@2 { +- compatible = "fsl,qoriq-mc-dpmac"; +- reg = <0x2>; +- }; +- +- dpmac3: dpmac@3 { +- compatible = "fsl,qoriq-mc-dpmac"; +- reg = <0x3>; +- }; +- +- dpmac4: dpmac@4 { +- compatible = "fsl,qoriq-mc-dpmac"; +- reg = <0x4>; +- }; +- +- dpmac5: dpmac@5 { +- compatible = "fsl,qoriq-mc-dpmac"; +- reg = <0x5>; +- }; +- +- dpmac6: dpmac@6 { +- compatible = "fsl,qoriq-mc-dpmac"; +- reg = <0x6>; +- }; +- +- dpmac7: dpmac@7 { +- compatible = "fsl,qoriq-mc-dpmac"; +- reg = <0x7>; +- }; +- +- dpmac8: dpmac@8 { +- compatible = "fsl,qoriq-mc-dpmac"; +- reg = <0x8>; +- }; +- +- dpmac9: dpmac@9 { +- compatible = "fsl,qoriq-mc-dpmac"; +- reg = <0x9>; +- }; +- +- dpmac10: dpmac@a { +- compatible = "fsl,qoriq-mc-dpmac"; +- reg = <0xa>; +- }; +- +- dpmac11: dpmac@b { +- compatible = "fsl,qoriq-mc-dpmac"; +- reg = <0xb>; +- }; +- +- dpmac12: dpmac@c { +- compatible = "fsl,qoriq-mc-dpmac"; +- reg = <0xc>; +- }; +- +- dpmac13: dpmac@d { +- compatible = "fsl,qoriq-mc-dpmac"; +- reg = <0xd>; +- }; +- +- dpmac14: dpmac@e { +- compatible = "fsl,qoriq-mc-dpmac"; +- reg = <0xe>; +- }; +- +- dpmac15: dpmac@f { +- compatible = "fsl,qoriq-mc-dpmac"; +- reg = <0xf>; +- }; +- +- dpmac16: dpmac@10 { +- compatible = "fsl,qoriq-mc-dpmac"; +- reg = <0x10>; +- }; +- }; +- }; +- +- smmu: iommu@5000000 { +- compatible = "arm,mmu-500"; +- reg = <0 0x5000000 0 0x800000>; +- #global-interrupts = <12>; +- interrupts = <0 13 4>, /* global secure fault */ +- <0 14 4>, /* combined secure interrupt */ +- <0 15 4>, /* global non-secure fault */ +- <0 16 4>, /* combined non-secure interrupt */ +- /* performance counter interrupts 0-7 */ +- <0 211 4>, <0 212 4>, +- <0 213 4>, <0 214 4>, +- <0 215 4>, <0 216 4>, +- <0 217 4>, <0 218 4>, +- /* per context interrupt, 64 interrupts */ +- <0 146 4>, <0 147 4>, +- <0 148 4>, <0 149 4>, +- <0 150 4>, <0 151 4>, +- <0 152 4>, <0 153 4>, +- <0 154 4>, <0 155 4>, +- <0 156 4>, <0 157 4>, +- <0 158 4>, <0 159 4>, +- <0 160 4>, <0 161 4>, +- <0 162 4>, <0 163 4>, +- <0 164 4>, <0 165 4>, +- <0 166 4>, <0 167 4>, +- <0 168 4>, <0 169 4>, +- <0 170 4>, <0 171 4>, +- <0 172 4>, <0 173 4>, +- <0 174 4>, <0 175 4>, +- <0 176 4>, <0 177 4>, +- <0 178 4>, <0 179 4>, +- <0 180 4>, <0 181 4>, +- <0 182 4>, <0 183 4>, +- <0 184 4>, <0 185 4>, +- <0 186 4>, <0 187 4>, +- <0 188 4>, <0 189 4>, +- <0 190 4>, <0 191 4>, +- <0 192 4>, <0 193 4>, +- <0 194 4>, <0 195 4>, +- <0 196 4>, <0 197 4>, +- <0 198 4>, <0 199 4>, +- <0 200 4>, <0 201 4>, +- <0 202 4>, <0 203 4>, +- <0 204 4>, <0 205 4>, +- <0 206 4>, <0 207 4>, +- <0 208 4>, <0 209 4>; +- mmu-masters = <&fsl_mc 0x300 0>; +- }; +- +- dspi: dspi@2100000 { +- status = "disabled"; +- compatible = "fsl,ls2080a-dspi", "fsl,ls2085a-dspi"; +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <0x0 0x2100000 0x0 0x10000>; +- interrupts = <0 26 0x4>; /* Level high type */ +- clocks = <&clockgen 4 3>; +- clock-names = "dspi"; +- spi-num-chipselects = <5>; +- bus-num = <0>; +- }; +- +- esdhc: esdhc@2140000 { +- status = "disabled"; +- compatible = "fsl,ls2080a-esdhc", "fsl,esdhc"; +- reg = <0x0 0x2140000 0x0 0x10000>; +- interrupts = <0 28 0x4>; /* Level high type */ +- clock-frequency = <0>; /* Updated by bootloader */ +- voltage-ranges = <1800 1800 3300 3300>; +- sdhci,auto-cmd12; +- little-endian; +- bus-width = <4>; +- }; +- +- gpio0: gpio@2300000 { +- compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; +- reg = <0x0 0x2300000 0x0 0x10000>; +- interrupts = <0 36 0x4>; /* Level high type */ +- gpio-controller; +- little-endian; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- }; +- +- gpio1: gpio@2310000 { +- compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; +- reg = <0x0 0x2310000 0x0 0x10000>; +- interrupts = <0 36 0x4>; /* Level high type */ +- gpio-controller; +- little-endian; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- }; +- +- gpio2: gpio@2320000 { +- compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; +- reg = <0x0 0x2320000 0x0 0x10000>; +- interrupts = <0 37 0x4>; /* Level high type */ +- gpio-controller; +- little-endian; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- }; +- +- gpio3: gpio@2330000 { +- compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; +- reg = <0x0 0x2330000 0x0 0x10000>; +- interrupts = <0 37 0x4>; /* Level high type */ +- gpio-controller; +- little-endian; +- #gpio-cells = <2>; +- interrupt-controller; +- #interrupt-cells = <2>; +- }; +- +- i2c0: i2c@2000000 { +- status = "disabled"; +- compatible = "fsl,vf610-i2c"; +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <0x0 0x2000000 0x0 0x10000>; +- interrupts = <0 34 0x4>; /* Level high type */ +- clock-names = "i2c"; +- clocks = <&clockgen 4 3>; +- }; +- +- i2c1: i2c@2010000 { +- status = "disabled"; +- compatible = "fsl,vf610-i2c"; +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <0x0 0x2010000 0x0 0x10000>; +- interrupts = <0 34 0x4>; /* Level high type */ +- clock-names = "i2c"; +- clocks = <&clockgen 4 3>; +- }; +- +- i2c2: i2c@2020000 { +- status = "disabled"; +- compatible = "fsl,vf610-i2c"; +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <0x0 0x2020000 0x0 0x10000>; +- interrupts = <0 35 0x4>; /* Level high type */ +- clock-names = "i2c"; +- clocks = <&clockgen 4 3>; +- }; +- +- i2c3: i2c@2030000 { +- status = "disabled"; +- compatible = "fsl,vf610-i2c"; +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <0x0 0x2030000 0x0 0x10000>; +- interrupts = <0 35 0x4>; /* Level high type */ +- clock-names = "i2c"; +- clocks = <&clockgen 4 3>; +- }; +- +- ifc: ifc@2240000 { +- compatible = "fsl,ifc", "simple-bus"; +- reg = <0x0 0x2240000 0x0 0x20000>; +- interrupts = <0 21 0x4>; /* Level high type */ +- little-endian; +- #address-cells = <2>; +- #size-cells = <1>; ++ cluster0_l2: l2-cache0 { ++ compatible = "cache"; ++ }; + +- ranges = <0 0 0x5 0x80000000 0x08000000 +- 2 0 0x5 0x30000000 0x00010000 +- 3 0 0x5 0x20000000 0x00010000>; +- }; ++ cluster1_l2: l2-cache1 { ++ compatible = "cache"; ++ }; + +- qspi: quadspi@20c0000 { +- status = "disabled"; +- compatible = "fsl,ls2080a-qspi", "fsl,ls1021a-qspi"; +- #address-cells = <1>; +- #size-cells = <0>; +- reg = <0x0 0x20c0000 0x0 0x10000>, +- <0x0 0x20000000 0x0 0x10000000>; +- reg-names = "QuadSPI", "QuadSPI-memory"; +- interrupts = <0 25 0x4>; /* Level high type */ +- clocks = <&clockgen 4 3>, <&clockgen 4 3>; +- clock-names = "qspi_en", "qspi"; +- }; ++ cluster2_l2: l2-cache2 { ++ compatible = "cache"; ++ }; + +- pcie@3400000 { +- compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", +- "snps,dw-pcie"; +- reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ +- 0x10 0x00000000 0x0 0x00002000>; /* configuration space */ +- reg-names = "regs", "config"; +- interrupts = <0 108 0x4>; /* Level high type */ +- interrupt-names = "intr"; +- #address-cells = <3>; +- #size-cells = <2>; +- device_type = "pci"; +- dma-coherent; +- num-lanes = <4>; +- bus-range = <0x0 0xff>; +- ranges = <0x81000000 0x0 0x00000000 0x10 0x00010000 0x0 0x00010000 /* downstream I/O */ +- 0x82000000 0x0 0x40000000 0x10 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ +- msi-parent = <&its>; +- #interrupt-cells = <1>; +- interrupt-map-mask = <0 0 0 7>; +- interrupt-map = <0000 0 0 1 &gic 0 0 0 109 4>, +- <0000 0 0 2 &gic 0 0 0 110 4>, +- <0000 0 0 3 &gic 0 0 0 111 4>, +- <0000 0 0 4 &gic 0 0 0 112 4>; +- }; ++ cluster3_l2: l2-cache3 { ++ compatible = "cache"; ++ }; ++}; + +- pcie@3500000 { +- compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", +- "snps,dw-pcie"; +- reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */ +- 0x12 0x00000000 0x0 0x00002000>; /* configuration space */ +- reg-names = "regs", "config"; +- interrupts = <0 113 0x4>; /* Level high type */ +- interrupt-names = "intr"; +- #address-cells = <3>; +- #size-cells = <2>; +- device_type = "pci"; +- dma-coherent; +- num-lanes = <4>; +- bus-range = <0x0 0xff>; +- ranges = <0x81000000 0x0 0x00000000 0x12 0x00010000 0x0 0x00010000 /* downstream I/O */ +- 0x82000000 0x0 0x40000000 0x12 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ +- msi-parent = <&its>; +- #interrupt-cells = <1>; +- interrupt-map-mask = <0 0 0 7>; +- interrupt-map = <0000 0 0 1 &gic 0 0 0 114 4>, +- <0000 0 0 2 &gic 0 0 0 115 4>, +- <0000 0 0 3 &gic 0 0 0 116 4>, +- <0000 0 0 4 &gic 0 0 0 117 4>; +- }; ++&usb0 { ++ snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>; ++ snps,dma-snooping; ++}; + +- pcie@3600000 { +- compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", +- "snps,dw-pcie"; +- reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */ +- 0x14 0x00000000 0x0 0x00002000>; /* configuration space */ +- reg-names = "regs", "config"; +- interrupts = <0 118 0x4>; /* Level high type */ +- interrupt-names = "intr"; +- #address-cells = <3>; +- #size-cells = <2>; +- device_type = "pci"; +- dma-coherent; +- num-lanes = <8>; +- bus-range = <0x0 0xff>; +- ranges = <0x81000000 0x0 0x00000000 0x14 0x00010000 0x0 0x00010000 /* downstream I/O */ +- 0x82000000 0x0 0x40000000 0x14 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ +- msi-parent = <&its>; +- #interrupt-cells = <1>; +- interrupt-map-mask = <0 0 0 7>; +- interrupt-map = <0000 0 0 1 &gic 0 0 0 119 4>, +- <0000 0 0 2 &gic 0 0 0 120 4>, +- <0000 0 0 3 &gic 0 0 0 121 4>, +- <0000 0 0 4 &gic 0 0 0 122 4>; +- }; ++&usb1 { ++ snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>; ++ snps,dma-snooping; ++}; + +- pcie@3700000 { +- compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", +- "snps,dw-pcie"; +- reg = <0x00 0x03700000 0x0 0x00100000 /* controller registers */ +- 0x16 0x00000000 0x0 0x00002000>; /* configuration space */ +- reg-names = "regs", "config"; +- interrupts = <0 123 0x4>; /* Level high type */ +- interrupt-names = "intr"; +- #address-cells = <3>; +- #size-cells = <2>; +- device_type = "pci"; +- dma-coherent; +- num-lanes = <4>; +- bus-range = <0x0 0xff>; +- ranges = <0x81000000 0x0 0x00000000 0x16 0x00010000 0x0 0x00010000 /* downstream I/O */ +- 0x82000000 0x0 0x40000000 0x16 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ +- msi-parent = <&its>; +- #interrupt-cells = <1>; +- interrupt-map-mask = <0 0 0 7>; +- interrupt-map = <0000 0 0 1 &gic 0 0 0 124 4>, +- <0000 0 0 2 &gic 0 0 0 125 4>, +- <0000 0 0 3 &gic 0 0 0 126 4>, +- <0000 0 0 4 &gic 0 0 0 127 4>; +- }; ++&pcie1 { ++ reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ ++ 0x10 0x00000000 0x0 0x00002000>; /* configuration space */ + +- sata0: sata@3200000 { +- status = "disabled"; +- compatible = "fsl,ls2080a-ahci"; +- reg = <0x0 0x3200000 0x0 0x10000>; +- interrupts = <0 133 0x4>; /* Level high type */ +- clocks = <&clockgen 4 3>; +- dma-coherent; +- }; ++ ranges = <0x81000000 0x0 0x00000000 0x10 0x00010000 0x0 0x00010000 /* downstream I/O */ ++ 0x82000000 0x0 0x40000000 0x10 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ ++}; + +- sata1: sata@3210000 { +- status = "disabled"; +- compatible = "fsl,ls2080a-ahci"; +- reg = <0x0 0x3210000 0x0 0x10000>; +- interrupts = <0 136 0x4>; /* Level high type */ +- clocks = <&clockgen 4 3>; +- dma-coherent; +- }; ++&pcie2 { ++ reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */ ++ 0x12 0x00000000 0x0 0x00002000>; /* configuration space */ + +- usb0: usb3@3100000 { +- status = "disabled"; +- compatible = "snps,dwc3"; +- reg = <0x0 0x3100000 0x0 0x10000>; +- interrupts = <0 80 0x4>; /* Level high type */ +- dr_mode = "host"; +- snps,quirk-frame-length-adjustment = <0x20>; +- snps,dis_rxdet_inp3_quirk; +- }; ++ ranges = <0x81000000 0x0 0x00000000 0x12 0x00010000 0x0 0x00010000 /* downstream I/O */ ++ 0x82000000 0x0 0x40000000 0x12 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ ++}; + +- usb1: usb3@3110000 { +- status = "disabled"; +- compatible = "snps,dwc3"; +- reg = <0x0 0x3110000 0x0 0x10000>; +- interrupts = <0 81 0x4>; /* Level high type */ +- dr_mode = "host"; +- snps,quirk-frame-length-adjustment = <0x20>; +- snps,dis_rxdet_inp3_quirk; +- }; ++&pcie3 { ++ reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */ ++ 0x14 0x00000000 0x0 0x00002000>; /* configuration space */ + +- ccn@4000000 { +- compatible = "arm,ccn-504"; +- reg = <0x0 0x04000000 0x0 0x01000000>; +- interrupts = <0 12 4>; +- }; +- }; ++ ranges = <0x81000000 0x0 0x00000000 0x14 0x00010000 0x0 0x00010000 /* downstream I/O */ ++ 0x82000000 0x0 0x40000000 0x14 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ ++}; + +- ddr1: memory-controller@1080000 { +- compatible = "fsl,qoriq-memory-controller"; +- reg = <0x0 0x1080000 0x0 0x1000>; +- interrupts = <0 17 0x4>; +- little-endian; +- }; ++&pcie4 { ++ reg = <0x00 0x03700000 0x0 0x00100000 /* controller registers */ ++ 0x16 0x00000000 0x0 0x00002000>; /* configuration space */ + +- ddr2: memory-controller@1090000 { +- compatible = "fsl,qoriq-memory-controller"; +- reg = <0x0 0x1090000 0x0 0x1000>; +- interrupts = <0 18 0x4>; +- little-endian; +- }; ++ ranges = <0x81000000 0x0 0x00000000 0x16 0x00010000 0x0 0x00010000 /* downstream I/O */ ++ 0x82000000 0x0 0x40000000 0x16 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */ + }; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2081a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls2081a-rdb.dts +new file mode 100644 +index 00000000..c3375bf7 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls2081a-rdb.dts +@@ -0,0 +1,161 @@ ++/* ++ * Device Tree file for NXP LS2081A RDB Board. ++ * ++ * Copyright 2017 NXP ++ * ++ * Priyanka Jain ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 "fsl-ls2088a.dtsi" ++ ++/ { ++ model = "NXP Layerscape 2081A RDB Board"; ++ compatible = "fsl,ls2081a-rdb", "fsl,ls2081a"; ++ ++ aliases { ++ serial0 = &serial0; ++ serial1 = &serial1; ++ }; ++ ++ chosen { ++ stdout-path = "serial1:115200n8"; ++ }; ++}; ++ ++&esdhc { ++ status = "okay"; ++}; ++ ++&ifc { ++ status = "disabled"; ++}; ++ ++&i2c0 { ++ status = "okay"; ++ pca9547@75 { ++ compatible = "nxp,pca9547"; ++ reg = <0x75>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x01>; ++ rtc@51 { ++ compatible = "nxp,pcf2129"; ++ reg = <0x51>; ++ }; ++ }; ++ ++ i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x02>; ++ ++ ina220@40 { ++ compatible = "ti,ina220"; ++ reg = <0x40>; ++ shunt-resistor = <500>; ++ }; ++ }; ++ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x3>; ++ ++ adt7481@4c { ++ compatible = "adi,adt7461"; ++ reg = <0x4c>; ++ }; ++ }; ++ }; ++}; ++ ++&dspi { ++ status = "okay"; ++ dflash0: n25q512a { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,m25p80"; ++ spi-max-frequency = <3000000>; ++ reg = <0>; ++ }; ++}; ++ ++&qspi { ++ status = "okay"; ++ fsl,qspi-has-second-chip; ++ flash0: s25fs512s@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "spansion,m25p80"; ++ m25p,fast-read; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++ flash1: s25fs512s@1 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "spansion,m25p80"; ++ m25p,fast-read; ++ spi-max-frequency = <20000000>; ++ reg = <1>; ++ }; ++}; ++ ++&sata0 { ++ status = "okay"; ++}; ++ ++&sata1 { ++ status = "okay"; ++}; ++ ++&usb0 { ++ status = "okay"; ++}; ++ ++&usb1 { ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2088a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls2088a-qds.dts +new file mode 100644 +index 00000000..1dbc7aa8 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls2088a-qds.dts +@@ -0,0 +1,162 @@ ++/* ++ * Device Tree file for Freescale LS2088A QDS Board. ++ * ++ * Copyright 2016 Freescale Semiconductor, Inc. ++ * Copyright 2017 NXP ++ * ++ * Abhimanyu Saini ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 "fsl-ls2088a.dtsi" ++#include "fsl-ls208xa-qds.dtsi" ++ ++/ { ++ model = "Freescale Layerscape 2088A QDS Board"; ++ compatible = "fsl,ls2088a-qds", "fsl,ls2088a"; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++}; ++ ++&ifc { ++ boardctrl: board-control@3,0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "fsl,tetra-fpga", "fsl,fpga-qixis", "simple-bus"; ++ reg = <3 0 0x300>; /* TODO check address */ ++ ranges = <0 3 0 0x300>; ++ ++ mdio_mux_emi1 { ++ compatible = "mdio-mux-mmioreg", "mdio-mux"; ++ mdio-parent-bus = <&emdio1>; ++ reg = <0x54 1>; /* BRDCFG4 */ ++ mux-mask = <0xe0>; /* EMI1_MDIO */ ++ ++ #address-cells=<1>; ++ #size-cells = <0>; ++ ++ /* Child MDIO buses, one for each riser card: ++ * reg = 0x0, 0x20, 0x40, 0x60, 0x80, 0xa0. ++ * VSC8234 PHYs on the riser cards. ++ */ ++ ++ mdio_mux3: mdio@60 { ++ reg = <0x60>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ mdio0_phy12: mdio_phy0@1c { ++ reg = <0x1c>; ++ phy-connection-type = "sgmii"; ++ }; ++ mdio0_phy13: mdio_phy1@1d { ++ reg = <0x1d>; ++ phy-connection-type = "sgmii"; ++ }; ++ mdio0_phy14: mdio_phy2@1e { ++ reg = <0x1e>; ++ phy-connection-type = "sgmii"; ++ }; ++ mdio0_phy15: mdio_phy3@1f { ++ reg = <0x1f>; ++ phy-connection-type = "sgmii"; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&pcs_mdio1 { ++ pcs_phy1: ethernet-phy@0 { ++ backplane-mode = "10gbase-kr"; ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ reg = <0x0>; ++ fsl,lane-handle = <&serdes1>; ++ fsl,lane-reg = <0x9C0 0x40>;/* lane H */ ++ }; ++}; ++ ++&pcs_mdio2 { ++ pcs_phy2: ethernet-phy@0 { ++ backplane-mode = "10gbase-kr"; ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ reg = <0x0>; ++ fsl,lane-handle = <&serdes1>; ++ fsl,lane-reg = <0x980 0x40>;/* lane G */ ++ }; ++}; ++ ++&pcs_mdio3 { ++ pcs_phy3: ethernet-phy@0 { ++ backplane-mode = "10gbase-kr"; ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ reg = <0x0>; ++ fsl,lane-handle = <&serdes1>; ++ fsl,lane-reg = <0x940 0x40>;/* lane F */ ++ }; ++}; ++ ++&pcs_mdio4 { ++ pcs_phy4: ethernet-phy@0 { ++ backplane-mode = "10gbase-kr"; ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ reg = <0x0>; ++ fsl,lane-handle = <&serdes1>; ++ fsl,lane-reg = <0x900 0x40>;/* lane E */ ++ }; ++}; ++ ++/* Update DPMAC connections to external PHYs, under SerDes 0x2a_0x49. */ ++&dpmac9 { ++ phy-handle = <&mdio0_phy12>; ++}; ++&dpmac10 { ++ phy-handle = <&mdio0_phy13>; ++}; ++&dpmac11 { ++ phy-handle = <&mdio0_phy14>; ++}; ++&dpmac12 { ++ phy-handle = <&mdio0_phy15>; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2088a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls2088a-rdb.dts +new file mode 100644 +index 00000000..9300119b +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls2088a-rdb.dts +@@ -0,0 +1,140 @@ ++/* ++ * Device Tree file for Freescale LS2088A RDB Board. ++ * ++ * Copyright 2016 Freescale Semiconductor, Inc. ++ * Copyright 2017 NXP ++ * ++ * Abhimanyu Saini ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 "fsl-ls2088a.dtsi" ++#include "fsl-ls208xa-rdb.dtsi" ++ ++/ { ++ model = "Freescale Layerscape 2088A RDB Board"; ++ compatible = "fsl,ls2088a-rdb", "fsl,ls2088a"; ++ ++ chosen { ++ stdout-path = "serial1:115200n8"; ++ }; ++}; ++ ++&emdio1 { ++ status = "disabled"; ++ /* CS4340 PHYs */ ++ mdio1_phy1: emdio1_phy@1 { ++ reg = <0x10>; ++ phy-connection-type = "xfi"; ++ }; ++ mdio1_phy2: emdio1_phy@2 { ++ reg = <0x11>; ++ phy-connection-type = "xfi"; ++ }; ++ mdio1_phy3: emdio1_phy@3 { ++ reg = <0x12>; ++ phy-connection-type = "xfi"; ++ }; ++ mdio1_phy4: emdio1_phy@4 { ++ reg = <0x13>; ++ phy-connection-type = "xfi"; ++ }; ++}; ++ ++&emdio2 { ++ /* AQR405 PHYs */ ++ mdio2_phy1: emdio2_phy@1 { ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ interrupts = <0 1 0x4>; /* Level high type */ ++ reg = <0x0>; ++ phy-connection-type = "xfi"; ++ }; ++ mdio2_phy2: emdio2_phy@2 { ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ interrupts = <0 2 0x4>; /* Level high type */ ++ reg = <0x1>; ++ phy-connection-type = "xfi"; ++ }; ++ mdio2_phy3: emdio2_phy@3 { ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ interrupts = <0 4 0x4>; /* Level high type */ ++ reg = <0x2>; ++ phy-connection-type = "xfi"; ++ }; ++ mdio2_phy4: emdio2_phy@4 { ++ compatible = "ethernet-phy-ieee802.3-c45"; ++ interrupts = <0 5 0x4>; /* Level high type */ ++ reg = <0x3>; ++ phy-connection-type = "xfi"; ++ }; ++}; ++ ++/* Update DPMAC connections to external PHYs, under the assumption of ++ * SerDes 0x2a_0x41. This is currently the only SerDes supported on the board. ++ */ ++/* Leave Cortina PHYs commented out until proper driver is integrated ++ *&dpmac1 { ++ * phy-handle = <&mdio1_phy1>; ++ *}; ++ *&dpmac2 { ++ * phy-handle = <&mdio1_phy2>; ++ *}; ++ *&dpmac3 { ++ * phy-handle = <&mdio1_phy3>; ++ *}; ++ *&dpmac4 { ++ * phy-handle = <&mdio1_phy4>; ++ *}; ++ */ ++ ++&dpmac5 { ++ phy-handle = <&mdio2_phy1>; ++}; ++&dpmac6 { ++ phy-handle = <&mdio2_phy2>; ++}; ++&dpmac7 { ++ phy-handle = <&mdio2_phy3>; ++}; ++&dpmac8 { ++ phy-handle = <&mdio2_phy4>; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi +new file mode 100644 +index 00000000..833699ea +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls2088a.dtsi +@@ -0,0 +1,195 @@ ++/* ++ * Device Tree Include file for Freescale Layerscape-2088A family SoC. ++ * ++ * Copyright 2016 Freescale Semiconductor, Inc. ++ * Copyright 2017 NXP ++ * ++ * Abhimanyu Saini ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 "fsl-ls208xa.dtsi" ++ ++&cpu { ++ cpu0: cpu@0 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <0x0>; ++ clocks = <&clockgen 1 0>; ++ next-level-cache = <&cluster0_l2>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ cpu1: cpu@1 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <0x1>; ++ clocks = <&clockgen 1 0>; ++ next-level-cache = <&cluster0_l2>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ cpu2: cpu@100 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <0x100>; ++ clocks = <&clockgen 1 1>; ++ next-level-cache = <&cluster1_l2>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ cpu3: cpu@101 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <0x101>; ++ clocks = <&clockgen 1 1>; ++ next-level-cache = <&cluster1_l2>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ cpu4: cpu@200 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <0x200>; ++ clocks = <&clockgen 1 2>; ++ next-level-cache = <&cluster2_l2>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ cpu5: cpu@201 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <0x201>; ++ clocks = <&clockgen 1 2>; ++ next-level-cache = <&cluster2_l2>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ cpu6: cpu@300 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <0x300>; ++ clocks = <&clockgen 1 3>; ++ next-level-cache = <&cluster3_l2>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ cpu7: cpu@301 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a72"; ++ reg = <0x301>; ++ clocks = <&clockgen 1 3>; ++ next-level-cache = <&cluster3_l2>; ++ cpu-idle-states = <&CPU_PH20>; ++ }; ++ ++ idle-states { ++ /* ++ * PSCI node is not added default, U-boot will add missing ++ * parts if it determines to use PSCI. ++ */ ++ entry-method = "arm,psci"; ++ ++ CPU_PH20: cpu-ph20 { ++ compatible = "arm,idle-state"; ++ idle-state-name = "PH20"; ++ arm,psci-suspend-param = <0x0>; ++ entry-latency-us = <1000>; ++ exit-latency-us = <1000>; ++ min-residency-us = <3000>; ++ }; ++ }; ++ ++ cluster0_l2: l2-cache0 { ++ compatible = "cache"; ++ }; ++ ++ cluster1_l2: l2-cache1 { ++ compatible = "cache"; ++ }; ++ ++ cluster2_l2: l2-cache2 { ++ compatible = "cache"; ++ }; ++ ++ cluster3_l2: l2-cache3 { ++ compatible = "cache"; ++ }; ++}; ++ ++&pcie1 { ++ compatible = "fsl,ls2088a-pcie", "snps,dw-pcie"; ++ reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */ ++ 0x20 0x00000000 0x0 0x00002000>; /* configuration space */ ++ ++ ranges = <0x81000000 0x0 0x00000000 0x20 0x00010000 0x0 0x00010000 ++ 0x82000000 0x0 0x40000000 0x20 0x40000000 0x0 0x40000000>; ++}; ++ ++&pcie2 { ++ compatible = "fsl,ls2088a-pcie", "snps,dw-pcie"; ++ reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */ ++ 0x28 0x00000000 0x0 0x00002000>; /* configuration space */ ++ ++ ranges = <0x81000000 0x0 0x00000000 0x28 0x00010000 0x0 0x00010000 ++ 0x82000000 0x0 0x40000000 0x28 0x40000000 0x0 0x40000000>; ++}; ++ ++&pcie3 { ++ compatible = "fsl,ls2088a-pcie", "snps,dw-pcie"; ++ reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */ ++ 0x30 0x00000000 0x0 0x00002000>; /* configuration space */ ++ ++ ranges = <0x81000000 0x0 0x00000000 0x30 0x00010000 0x0 0x00010000 ++ 0x82000000 0x0 0x40000000 0x30 0x40000000 0x0 0x40000000>; ++}; ++ ++&pcie4 { ++ compatible = "fsl,ls2088a-pcie", "snps,dw-pcie"; ++ reg = <0x00 0x03700000 0x0 0x00100000 /* controller registers */ ++ 0x38 0x00000000 0x0 0x00002000>; /* configuration space */ ++ ++ ranges = <0x81000000 0x0 0x00000000 0x38 0x00010000 0x0 0x00010000 ++ 0x82000000 0x0 0x40000000 0x38 0x40000000 0x0 0x40000000>; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa-qds.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa-qds.dtsi +new file mode 100644 +index 00000000..b2374469 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa-qds.dtsi +@@ -0,0 +1,198 @@ ++/* ++ * Device Tree file for Freescale LS2080A QDS Board. ++ * ++ * Copyright 2016 Freescale Semiconductor, Inc. ++ * Copyright 2017 NXP ++ * ++ * Abhimanyu Saini ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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. ++ */ ++ ++&esdhc { ++ mmc-hs200-1_8v; ++ status = "okay"; ++}; ++ ++&ifc { ++ status = "okay"; ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges = <0x0 0x0 0x5 0x80000000 0x08000000 ++ 0x2 0x0 0x5 0x30000000 0x00010000 ++ 0x3 0x0 0x5 0x20000000 0x00010000>; ++ ++ nor@0,0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "cfi-flash"; ++ reg = <0x0 0x0 0x8000000>; ++ bank-width = <2>; ++ device-width = <1>; ++ }; ++ ++ nand@2,0 { ++ compatible = "fsl,ifc-nand"; ++ reg = <0x2 0x0 0x10000>; ++ }; ++ ++ cpld@3,0 { ++ reg = <0x3 0x0 0x10000>; ++ compatible = "fsl,ls2080aqds-fpga", "fsl,fpga-qixis"; ++ }; ++}; ++ ++&i2c0 { ++ status = "okay"; ++ pca9547@77 { ++ compatible = "nxp,pca9547"; ++ reg = <0x77>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x00>; ++ rtc@68 { ++ compatible = "dallas,ds3232"; ++ reg = <0x68>; ++ }; ++ }; ++ ++ i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x02>; ++ ++ ina220@40 { ++ compatible = "ti,ina220"; ++ reg = <0x40>; ++ shunt-resistor = <500>; ++ }; ++ ++ ina220@41 { ++ compatible = "ti,ina220"; ++ reg = <0x41>; ++ shunt-resistor = <1000>; ++ }; ++ }; ++ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x3>; ++ ++ adt7481@4c { ++ compatible = "adi,adt7461"; ++ reg = <0x4c>; ++ }; ++ }; ++ }; ++}; ++ ++&i2c1 { ++ status = "disabled"; ++}; ++ ++&i2c2 { ++ status = "disabled"; ++}; ++ ++&i2c3 { ++ status = "disabled"; ++}; ++ ++&dspi { ++ status = "okay"; ++ dflash0: n25q128a { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,m25p80"; ++ spi-max-frequency = <3000000>; ++ reg = <0>; ++ }; ++ dflash1: sst25wf040b { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,m25p80"; ++ spi-max-frequency = <3000000>; ++ reg = <1>; ++ }; ++ dflash2: en25s64 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,m25p80"; ++ spi-max-frequency = <3000000>; ++ reg = <2>; ++ }; ++}; ++ ++&qspi { ++ status = "okay"; ++ flash0: s25fl256s1@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,m25p80"; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++ flash2: s25fl256s1@2 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,m25p80"; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++}; ++ ++&sata0 { ++ status = "okay"; ++}; ++ ++&sata1 { ++ status = "okay"; ++}; ++ ++&usb0 { ++ status = "okay"; ++}; ++ ++&usb1 { ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa-rdb.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa-rdb.dtsi +new file mode 100644 +index 00000000..8e919dc8 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa-rdb.dtsi +@@ -0,0 +1,161 @@ ++/* ++ * Device Tree file for Freescale LS2080A RDB Board. ++ * ++ * Copyright 2016 Freescale Semiconductor, Inc. ++ * Copyright 2017 NXP ++ * ++ * Abhimanyu Saini ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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. ++ */ ++ ++&esdhc { ++ status = "okay"; ++}; ++ ++&ifc { ++ status = "okay"; ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ranges = <0x0 0x0 0x5 0x80000000 0x08000000 ++ 0x2 0x0 0x5 0x30000000 0x00010000 ++ 0x3 0x0 0x5 0x20000000 0x00010000>; ++ ++ nor@0,0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "cfi-flash"; ++ reg = <0x0 0x0 0x8000000>; ++ bank-width = <2>; ++ device-width = <1>; ++ }; ++ ++ nand@2,0 { ++ compatible = "fsl,ifc-nand"; ++ reg = <0x2 0x0 0x10000>; ++ }; ++ ++ cpld@3,0 { ++ reg = <0x3 0x0 0x10000>; ++ compatible = "fsl,ls2080aqds-fpga", "fsl,fpga-qixis"; ++ }; ++ ++}; ++ ++&i2c0 { ++ status = "okay"; ++ pca9547@75 { ++ compatible = "nxp,pca9547"; ++ reg = <0x75>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ i2c-mux-never-disable; ++ i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x01>; ++ rtc@68 { ++ compatible = "dallas,ds3232"; ++ reg = <0x68>; ++ }; ++ }; ++ ++ i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x3>; ++ ++ adt7481@4c { ++ compatible = "adi,adt7461"; ++ reg = <0x4c>; ++ }; ++ }; ++ }; ++}; ++ ++&i2c1 { ++ status = "disabled"; ++}; ++ ++&i2c2 { ++ status = "disabled"; ++}; ++ ++&i2c3 { ++ status = "disabled"; ++}; ++ ++&dspi { ++ status = "okay"; ++ dflash0: n25q512a { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "st,m25p80"; ++ spi-max-frequency = <3000000>; ++ reg = <0>; ++ }; ++}; ++ ++&qspi { ++ status = "okay"; ++ flash0: s25fs512s@0 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "spansion,m25p80"; ++ m25p,fast-read; ++ spi-max-frequency = <20000000>; ++ reg = <0>; ++ }; ++}; ++ ++&sata0 { ++ status = "okay"; ++}; ++ ++&sata1 { ++ status = "okay"; ++}; ++ ++&usb0 { ++ status = "okay"; ++}; ++ ++&usb1 { ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi +new file mode 100644 +index 00000000..f694cac0 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi +@@ -0,0 +1,910 @@ ++/* ++ * Device Tree Include file for Freescale Layerscape-2080A family SoC. ++ * ++ * Copyright 2016 Freescale Semiconductor, Inc. ++ * Copyright 2017 NXP ++ * ++ * Abhimanyu Saini ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPLv2 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 library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library 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 "AS IS", 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 ++#include ++ ++/ { ++ compatible = "fsl,ls2080a"; ++ interrupt-parent = <&gic>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ aliases { ++ crypto = &crypto; ++ serial0 = &serial0; ++ serial1 = &serial1; ++ }; ++ ++ cpu: cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ reg = <0x00000000 0x80000000 0 0x80000000>; ++ /* DRAM space - 1, size : 2 GB DRAM */ ++ }; ++ ++ sysclk: sysclk { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <100000000>; ++ clock-output-names = "sysclk"; ++ }; ++ ++ gic: interrupt-controller@6000000 { ++ compatible = "arm,gic-v3"; ++ reg = <0x0 0x06000000 0 0x10000>, /* GIC Dist */ ++ <0x0 0x06100000 0 0x100000>, /* GICR (RD_base + SGI_base) */ ++ <0x0 0x0c0c0000 0 0x2000>, /* GICC */ ++ <0x0 0x0c0d0000 0 0x1000>, /* GICH */ ++ <0x0 0x0c0e0000 0 0x20000>; /* GICV */ ++ #interrupt-cells = <3>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ interrupt-controller; ++ interrupts = <1 9 0x4>; ++ ++ its: gic-its@6020000 { ++ compatible = "arm,gic-v3-its"; ++ msi-controller; ++ reg = <0x0 0x6020000 0 0x20000>; ++ }; ++ }; ++ ++ rstcr: syscon@1e60000 { ++ compatible = "fsl,ls2080a-rstcr", "syscon"; ++ reg = <0x0 0x1e60000 0x0 0x4>; ++ }; ++ ++ reboot { ++ compatible ="syscon-reboot"; ++ regmap = <&rstcr>; ++ offset = <0x0>; ++ mask = <0x2>; ++ }; ++ ++ timer { ++ compatible = "arm,armv8-timer"; ++ interrupts = <1 13 4>, /* Physical Secure PPI, active-low */ ++ <1 14 4>, /* Physical Non-Secure PPI, active-low */ ++ <1 11 4>, /* Virtual PPI, active-low */ ++ <1 10 4>; /* Hypervisor PPI, active-low */ ++ fsl,erratum-a008585; ++ }; ++ ++ pmu { ++ compatible = "arm,armv8-pmuv3"; ++ interrupts = <1 7 0x8>; /* PMU PPI, Level low type */ ++ }; ++ ++ soc { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ clockgen: clocking@1300000 { ++ compatible = "fsl,ls2080a-clockgen"; ++ reg = <0 0x1300000 0 0xa0000>; ++ #clock-cells = <2>; ++ clocks = <&sysclk>; ++ }; ++ ++ dcfg: dcfg@1e00000 { ++ compatible = "fsl,ls2080a-dcfg", "syscon"; ++ reg = <0x0 0x1e00000 0x0 0x10000>; ++ little-endian; ++ }; ++ ++ tmu: tmu@1f80000 { ++ compatible = "fsl,qoriq-tmu"; ++ reg = <0x0 0x1f80000 0x0 0x10000>; ++ interrupts = <0 23 0x4>; ++ fsl,tmu-range = <0xb0000 0x9002a 0x6004c 0x30062>; ++ fsl,tmu-calibration = <0x00000000 0x00000026 ++ 0x00000001 0x0000002d ++ 0x00000002 0x00000032 ++ 0x00000003 0x00000039 ++ 0x00000004 0x0000003f ++ 0x00000005 0x00000046 ++ 0x00000006 0x0000004d ++ 0x00000007 0x00000054 ++ 0x00000008 0x0000005a ++ 0x00000009 0x00000061 ++ 0x0000000a 0x0000006a ++ 0x0000000b 0x00000071 ++ ++ 0x00010000 0x00000025 ++ 0x00010001 0x0000002c ++ 0x00010002 0x00000035 ++ 0x00010003 0x0000003d ++ 0x00010004 0x00000045 ++ 0x00010005 0x0000004e ++ 0x00010006 0x00000057 ++ 0x00010007 0x00000061 ++ 0x00010008 0x0000006b ++ 0x00010009 0x00000076 ++ ++ 0x00020000 0x00000029 ++ 0x00020001 0x00000033 ++ 0x00020002 0x0000003d ++ 0x00020003 0x00000049 ++ 0x00020004 0x00000056 ++ 0x00020005 0x00000061 ++ 0x00020006 0x0000006d ++ ++ 0x00030000 0x00000021 ++ 0x00030001 0x0000002a ++ 0x00030002 0x0000003c ++ 0x00030003 0x0000004e>; ++ little-endian; ++ #thermal-sensor-cells = <1>; ++ }; ++ ++ thermal-zones { ++ cpu_thermal: cpu-thermal { ++ polling-delay-passive = <1000>; ++ polling-delay = <5000>; ++ ++ thermal-sensors = <&tmu 4>; ++ ++ trips { ++ cpu_alert: cpu-alert { ++ temperature = <75000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ cpu_crit: cpu-crit { ++ temperature = <85000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ }; ++ ++ cooling-maps { ++ map0 { ++ trip = <&cpu_alert>; ++ cooling-device = ++ <&cpu0 THERMAL_NO_LIMIT ++ THERMAL_NO_LIMIT>; ++ }; ++ map1 { ++ trip = <&cpu_alert>; ++ cooling-device = ++ <&cpu2 THERMAL_NO_LIMIT ++ THERMAL_NO_LIMIT>; ++ }; ++ map2 { ++ trip = <&cpu_alert>; ++ cooling-device = ++ <&cpu4 THERMAL_NO_LIMIT ++ THERMAL_NO_LIMIT>; ++ }; ++ map3 { ++ trip = <&cpu_alert>; ++ cooling-device = ++ <&cpu6 THERMAL_NO_LIMIT ++ THERMAL_NO_LIMIT>; ++ }; ++ }; ++ }; ++ }; ++ ++ serial0: serial@21c0500 { ++ compatible = "fsl,ns16550", "ns16550a"; ++ reg = <0x0 0x21c0500 0x0 0x100>; ++ clocks = <&clockgen 4 3>; ++ interrupts = <0 32 0x4>; /* Level high type */ ++ }; ++ ++ serial1: serial@21c0600 { ++ compatible = "fsl,ns16550", "ns16550a"; ++ reg = <0x0 0x21c0600 0x0 0x100>; ++ clocks = <&clockgen 4 3>; ++ interrupts = <0 32 0x4>; /* Level high type */ ++ }; ++ ++ cluster1_core0_watchdog: wdt@c000000 { ++ compatible = "arm,sp805-wdt", "arm,primecell"; ++ reg = <0x0 0xc000000 0x0 0x1000>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "apb_pclk", "wdog_clk"; ++ }; ++ ++ cluster1_core1_watchdog: wdt@c010000 { ++ compatible = "arm,sp805-wdt", "arm,primecell"; ++ reg = <0x0 0xc010000 0x0 0x1000>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "apb_pclk", "wdog_clk"; ++ }; ++ ++ cluster2_core0_watchdog: wdt@c100000 { ++ compatible = "arm,sp805-wdt", "arm,primecell"; ++ reg = <0x0 0xc100000 0x0 0x1000>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "apb_pclk", "wdog_clk"; ++ }; ++ ++ cluster2_core1_watchdog: wdt@c110000 { ++ compatible = "arm,sp805-wdt", "arm,primecell"; ++ reg = <0x0 0xc110000 0x0 0x1000>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "apb_pclk", "wdog_clk"; ++ }; ++ ++ cluster3_core0_watchdog: wdt@c200000 { ++ compatible = "arm,sp805-wdt", "arm,primecell"; ++ reg = <0x0 0xc200000 0x0 0x1000>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "apb_pclk", "wdog_clk"; ++ }; ++ ++ cluster3_core1_watchdog: wdt@c210000 { ++ compatible = "arm,sp805-wdt", "arm,primecell"; ++ reg = <0x0 0xc210000 0x0 0x1000>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "apb_pclk", "wdog_clk"; ++ }; ++ ++ cluster4_core0_watchdog: wdt@c300000 { ++ compatible = "arm,sp805-wdt", "arm,primecell"; ++ reg = <0x0 0xc300000 0x0 0x1000>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "apb_pclk", "wdog_clk"; ++ }; ++ ++ cluster4_core1_watchdog: wdt@c310000 { ++ compatible = "arm,sp805-wdt", "arm,primecell"; ++ reg = <0x0 0xc310000 0x0 0x1000>; ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "apb_pclk", "wdog_clk"; ++ }; ++ ++ crypto: crypto@8000000 { ++ compatible = "fsl,sec-v5.0", "fsl,sec-v4.0"; ++ fsl,sec-era = <8>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0x0 0x00 0x8000000 0x100000>; ++ reg = <0x00 0x8000000 0x0 0x100000>; ++ interrupts = ; ++ dma-coherent; ++ ++ sec_jr0: jr@10000 { ++ compatible = "fsl,sec-v5.0-job-ring", ++ "fsl,sec-v4.0-job-ring"; ++ reg = <0x10000 0x10000>; ++ interrupts = ; ++ }; ++ ++ sec_jr1: jr@20000 { ++ compatible = "fsl,sec-v5.0-job-ring", ++ "fsl,sec-v4.0-job-ring"; ++ reg = <0x20000 0x10000>; ++ interrupts = ; ++ }; ++ ++ sec_jr2: jr@30000 { ++ compatible = "fsl,sec-v5.0-job-ring", ++ "fsl,sec-v4.0-job-ring"; ++ reg = <0x30000 0x10000>; ++ interrupts = ; ++ }; ++ ++ sec_jr3: jr@40000 { ++ compatible = "fsl,sec-v5.0-job-ring", ++ "fsl,sec-v4.0-job-ring"; ++ reg = <0x40000 0x10000>; ++ interrupts = ; ++ }; ++ }; ++ ++ fsl_mc: fsl-mc@80c000000 { ++ compatible = "fsl,qoriq-mc"; ++ reg = <0x00000008 0x0c000000 0 0x40>, /* MC portal base */ ++ <0x00000000 0x08340000 0 0x40000>; /* MC control reg */ ++ msi-parent = <&its>; ++ iommu-map = <0 &smmu 0 0>; /* This is fixed-up by u-boot */ ++ #address-cells = <3>; ++ #size-cells = <1>; ++ ++ /* ++ * Region type 0x0 - MC portals ++ * Region type 0x1 - QBMAN portals ++ */ ++ ranges = <0x0 0x0 0x0 0x8 0x0c000000 0x4000000 ++ 0x1 0x0 0x0 0x8 0x18000000 0x8000000>; ++ ++ /* ++ * Define the maximum number of MACs present on the SoC. ++ */ ++ dpmacs { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ dpmac1: dpmac@1 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <0x1>; ++ }; ++ ++ dpmac2: dpmac@2 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <0x2>; ++ }; ++ ++ dpmac3: dpmac@3 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <0x3>; ++ }; ++ ++ dpmac4: dpmac@4 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <0x4>; ++ }; ++ ++ dpmac5: dpmac@5 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <0x5>; ++ }; ++ ++ dpmac6: dpmac@6 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <0x6>; ++ }; ++ ++ dpmac7: dpmac@7 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <0x7>; ++ }; ++ ++ dpmac8: dpmac@8 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <0x8>; ++ }; ++ ++ dpmac9: dpmac@9 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <0x9>; ++ }; ++ ++ dpmac10: dpmac@a { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <0xa>; ++ }; ++ ++ dpmac11: dpmac@b { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <0xb>; ++ }; ++ ++ dpmac12: dpmac@c { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <0xc>; ++ }; ++ ++ dpmac13: dpmac@d { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <0xd>; ++ }; ++ ++ dpmac14: dpmac@e { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <0xe>; ++ }; ++ ++ dpmac15: dpmac@f { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <0xf>; ++ }; ++ ++ dpmac16: dpmac@10 { ++ compatible = "fsl,qoriq-mc-dpmac"; ++ reg = <0x10>; ++ }; ++ }; ++ }; ++ ++ smmu: iommu@5000000 { ++ compatible = "arm,mmu-500"; ++ reg = <0 0x5000000 0 0x800000>; ++ #global-interrupts = <12>; ++ #iommu-cells = <1>; ++ stream-match-mask = <0x7C00>; ++ interrupts = <0 13 4>, /* global secure fault */ ++ <0 14 4>, /* combined secure interrupt */ ++ <0 15 4>, /* global non-secure fault */ ++ <0 16 4>, /* combined non-secure interrupt */ ++ /* performance counter interrupts 0-7 */ ++ <0 211 4>, <0 212 4>, ++ <0 213 4>, <0 214 4>, ++ <0 215 4>, <0 216 4>, ++ <0 217 4>, <0 218 4>, ++ /* per context interrupt, 64 interrupts */ ++ <0 146 4>, <0 147 4>, ++ <0 148 4>, <0 149 4>, ++ <0 150 4>, <0 151 4>, ++ <0 152 4>, <0 153 4>, ++ <0 154 4>, <0 155 4>, ++ <0 156 4>, <0 157 4>, ++ <0 158 4>, <0 159 4>, ++ <0 160 4>, <0 161 4>, ++ <0 162 4>, <0 163 4>, ++ <0 164 4>, <0 165 4>, ++ <0 166 4>, <0 167 4>, ++ <0 168 4>, <0 169 4>, ++ <0 170 4>, <0 171 4>, ++ <0 172 4>, <0 173 4>, ++ <0 174 4>, <0 175 4>, ++ <0 176 4>, <0 177 4>, ++ <0 178 4>, <0 179 4>, ++ <0 180 4>, <0 181 4>, ++ <0 182 4>, <0 183 4>, ++ <0 184 4>, <0 185 4>, ++ <0 186 4>, <0 187 4>, ++ <0 188 4>, <0 189 4>, ++ <0 190 4>, <0 191 4>, ++ <0 192 4>, <0 193 4>, ++ <0 194 4>, <0 195 4>, ++ <0 196 4>, <0 197 4>, ++ <0 198 4>, <0 199 4>, ++ <0 200 4>, <0 201 4>, ++ <0 202 4>, <0 203 4>, ++ <0 204 4>, <0 205 4>, ++ <0 206 4>, <0 207 4>, ++ <0 208 4>, <0 209 4>; ++ }; ++ ++ dspi: dspi@2100000 { ++ status = "disabled"; ++ compatible = "fsl,ls2080a-dspi", "fsl,ls2085a-dspi"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x2100000 0x0 0x10000>; ++ interrupts = <0 26 0x4>; /* Level high type */ ++ clocks = <&clockgen 4 3>; ++ clock-names = "dspi"; ++ spi-num-chipselects = <5>; ++ bus-num = <0>; ++ }; ++ ++ esdhc: esdhc@2140000 { ++ status = "disabled"; ++ compatible = "fsl,ls2080a-esdhc", "fsl,esdhc"; ++ reg = <0x0 0x2140000 0x0 0x10000>; ++ interrupts = <0 28 0x4>; /* Level high type */ ++ clocks = <&clockgen 4 1>; ++ voltage-ranges = <1800 1800 3300 3300>; ++ sdhci,auto-cmd12; ++ little-endian; ++ bus-width = <4>; ++ }; ++ ++ gpio0: gpio@2300000 { ++ compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; ++ reg = <0x0 0x2300000 0x0 0x10000>; ++ interrupts = <0 36 0x4>; /* Level high type */ ++ gpio-controller; ++ little-endian; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio1: gpio@2310000 { ++ compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; ++ reg = <0x0 0x2310000 0x0 0x10000>; ++ interrupts = <0 36 0x4>; /* Level high type */ ++ gpio-controller; ++ little-endian; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio2: gpio@2320000 { ++ compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; ++ reg = <0x0 0x2320000 0x0 0x10000>; ++ interrupts = <0 37 0x4>; /* Level high type */ ++ gpio-controller; ++ little-endian; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ gpio3: gpio@2330000 { ++ compatible = "fsl,ls2080a-gpio", "fsl,qoriq-gpio"; ++ reg = <0x0 0x2330000 0x0 0x10000>; ++ interrupts = <0 37 0x4>; /* Level high type */ ++ gpio-controller; ++ little-endian; ++ #gpio-cells = <2>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ }; ++ ++ /* TODO: WRIOP (CCSR?) */ ++ emdio1: mdio@0x8B96000 { /* WRIOP0: 0x8B8_0000, ++ * E-MDIO1: 0x1_6000 ++ */ ++ compatible = "fsl,fman-memac-mdio"; ++ reg = <0x0 0x8B96000 0x0 0x1000>; ++ device_type = "mdio"; /* TODO: is this necessary? */ ++ little-endian; /* force the driver in LE mode */ ++ ++ /* Not necessary on the QDS, but needed on the RDB */ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ emdio2: mdio@0x8B97000 { /* WRIOP0: 0x8B8_0000, ++ * E-MDIO2: 0x1_7000 ++ */ ++ compatible = "fsl,fman-memac-mdio"; ++ reg = <0x0 0x8B97000 0x0 0x1000>; ++ device_type = "mdio"; /* TODO: is this necessary? */ ++ little-endian; /* force the driver in LE mode */ ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ pcs_mdio1: mdio@0x8c07000 { ++ compatible = "fsl,fman-memac-mdio"; ++ reg = <0x0 0x8c07000 0x0 0x1000>; ++ device_type = "mdio"; ++ little-endian; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ pcs_mdio2: mdio@0x8c0b000 { ++ compatible = "fsl,fman-memac-mdio"; ++ reg = <0x0 0x8c0b000 0x0 0x1000>; ++ device_type = "mdio"; ++ little-endian; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ pcs_mdio3: mdio@0x8c0f000 { ++ compatible = "fsl,fman-memac-mdio"; ++ reg = <0x0 0x8c0f000 0x0 0x1000>; ++ device_type = "mdio"; ++ little-endian; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ pcs_mdio4: mdio@0x8c13000 { ++ compatible = "fsl,fman-memac-mdio"; ++ reg = <0x0 0x8c13000 0x0 0x1000>; ++ device_type = "mdio"; ++ little-endian; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ pcs_mdio5: mdio@0x8c17000 { ++ status = "disabled"; ++ compatible = "fsl,fman-memac-mdio"; ++ reg = <0x0 0x8c17000 0x0 0x1000>; ++ device_type = "mdio"; ++ little-endian; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ pcs_mdio6: mdio@0x8c1b000 { ++ status = "disabled"; ++ compatible = "fsl,fman-memac-mdio"; ++ reg = <0x0 0x8c1b000 0x0 0x1000>; ++ device_type = "mdio"; ++ little-endian; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ pcs_mdio7: mdio@0x8c1f000 { ++ status = "disabled"; ++ compatible = "fsl,fman-memac-mdio"; ++ reg = <0x0 0x8c1f000 0x0 0x1000>; ++ device_type = "mdio"; ++ little-endian; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ pcs_mdio8: mdio@0x8c23000 { ++ status = "disabled"; ++ compatible = "fsl,fman-memac-mdio"; ++ reg = <0x0 0x8c23000 0x0 0x1000>; ++ device_type = "mdio"; ++ little-endian; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ i2c0: i2c@2000000 { ++ status = "disabled"; ++ compatible = "fsl,vf610-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x2000000 0x0 0x10000>; ++ interrupts = <0 34 0x4>; /* Level high type */ ++ clock-names = "i2c"; ++ clocks = <&clockgen 4 3>; ++ }; ++ ++ i2c1: i2c@2010000 { ++ status = "disabled"; ++ compatible = "fsl,vf610-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x2010000 0x0 0x10000>; ++ interrupts = <0 34 0x4>; /* Level high type */ ++ clock-names = "i2c"; ++ clocks = <&clockgen 4 3>; ++ }; ++ ++ i2c2: i2c@2020000 { ++ status = "disabled"; ++ compatible = "fsl,vf610-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x2020000 0x0 0x10000>; ++ interrupts = <0 35 0x4>; /* Level high type */ ++ clock-names = "i2c"; ++ clocks = <&clockgen 4 3>; ++ }; ++ ++ i2c3: i2c@2030000 { ++ status = "disabled"; ++ compatible = "fsl,vf610-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x2030000 0x0 0x10000>; ++ interrupts = <0 35 0x4>; /* Level high type */ ++ clock-names = "i2c"; ++ clocks = <&clockgen 4 3>; ++ }; ++ ++ ifc: ifc@2240000 { ++ compatible = "fsl,ifc", "simple-bus"; ++ reg = <0x0 0x2240000 0x0 0x20000>; ++ interrupts = <0 21 0x4>; /* Level high type */ ++ little-endian; ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ++ ranges = <0 0 0x5 0x80000000 0x08000000 ++ 2 0 0x5 0x30000000 0x00010000 ++ 3 0 0x5 0x20000000 0x00010000>; ++ }; ++ ++ qspi: quadspi@20c0000 { ++ status = "disabled"; ++ compatible = "fsl,ls2080a-qspi", "fsl,ls1021a-qspi"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0x20c0000 0x0 0x10000>, ++ <0x0 0x20000000 0x0 0x10000000>; ++ reg-names = "QuadSPI", "QuadSPI-memory"; ++ interrupts = <0 25 0x4>; /* Level high type */ ++ clocks = <&clockgen 4 3>, <&clockgen 4 3>; ++ clock-names = "qspi_en", "qspi"; ++ }; ++ ++ pcie1: pcie@3400000 { ++ compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", ++ "snps,dw-pcie"; ++ reg-names = "regs", "config"; ++ interrupts = <0 108 0x4>; /* aer interrupt */ ++ interrupt-names = "aer"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ dma-coherent; ++ num-lanes = <4>; ++ bus-range = <0x0 0xff>; ++ msi-parent = <&its>; ++ iommu-map = <0 &smmu 0 1>; /* This is fixed-up by u-boot */ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0000 0 0 1 &gic 0 0 0 109 4>, ++ <0000 0 0 2 &gic 0 0 0 110 4>, ++ <0000 0 0 3 &gic 0 0 0 111 4>, ++ <0000 0 0 4 &gic 0 0 0 112 4>; ++ }; ++ ++ pcie2: pcie@3500000 { ++ compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", ++ "snps,dw-pcie"; ++ reg-names = "regs", "config"; ++ interrupts = <0 113 0x4>; /* aer interrupt */ ++ interrupt-names = "aer"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ dma-coherent; ++ num-lanes = <4>; ++ bus-range = <0x0 0xff>; ++ msi-parent = <&its>; ++ iommu-map = <0 &smmu 0 1>; /* This is fixed-up by u-boot */ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0000 0 0 1 &gic 0 0 0 114 4>, ++ <0000 0 0 2 &gic 0 0 0 115 4>, ++ <0000 0 0 3 &gic 0 0 0 116 4>, ++ <0000 0 0 4 &gic 0 0 0 117 4>; ++ }; ++ ++ pcie3: pcie@3600000 { ++ compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", ++ "snps,dw-pcie"; ++ reg-names = "regs", "config"; ++ interrupts = <0 118 0x4>; /* aer interrupt */ ++ interrupt-names = "aer"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ dma-coherent; ++ num-lanes = <8>; ++ bus-range = <0x0 0xff>; ++ msi-parent = <&its>; ++ iommu-map = <0 &smmu 0 1>; /* This is fixed-up by u-boot */ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0000 0 0 1 &gic 0 0 0 119 4>, ++ <0000 0 0 2 &gic 0 0 0 120 4>, ++ <0000 0 0 3 &gic 0 0 0 121 4>, ++ <0000 0 0 4 &gic 0 0 0 122 4>; ++ }; ++ ++ pcie4: pcie@3700000 { ++ compatible = "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", ++ "snps,dw-pcie"; ++ reg-names = "regs", "config"; ++ interrupts = <0 123 0x4>; /* aer interrupt */ ++ interrupt-names = "aer"; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ device_type = "pci"; ++ dma-coherent; ++ num-lanes = <4>; ++ bus-range = <0x0 0xff>; ++ msi-parent = <&its>; ++ iommu-map = <0 &smmu 0 1>; /* This is fixed-up by u-boot */ ++ #interrupt-cells = <1>; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0000 0 0 1 &gic 0 0 0 124 4>, ++ <0000 0 0 2 &gic 0 0 0 125 4>, ++ <0000 0 0 3 &gic 0 0 0 126 4>, ++ <0000 0 0 4 &gic 0 0 0 127 4>; ++ }; ++ ++ sata0: sata@3200000 { ++ status = "disabled"; ++ compatible = "fsl,ls2080a-ahci"; ++ reg = <0x0 0x3200000 0x0 0x10000>; ++ interrupts = <0 133 0x4>; /* Level high type */ ++ clocks = <&clockgen 4 3>; ++ dma-coherent; ++ }; ++ ++ sata1: sata@3210000 { ++ status = "disabled"; ++ compatible = "fsl,ls2080a-ahci"; ++ reg = <0x0 0x3210000 0x0 0x10000>; ++ interrupts = <0 136 0x4>; /* Level high type */ ++ clocks = <&clockgen 4 3>; ++ dma-coherent; ++ }; ++ ++ usb0: usb3@3100000 { ++ status = "disabled"; ++ compatible = "snps,dwc3"; ++ reg = <0x0 0x3100000 0x0 0x10000>; ++ interrupts = <0 80 0x4>; /* Level high type */ ++ dr_mode = "host"; ++ snps,quirk-frame-length-adjustment = <0x20>; ++ snps,dis_rxdet_inp3_quirk; ++ }; ++ ++ usb1: usb3@3110000 { ++ status = "disabled"; ++ compatible = "snps,dwc3"; ++ reg = <0x0 0x3110000 0x0 0x10000>; ++ interrupts = <0 81 0x4>; /* Level high type */ ++ dr_mode = "host"; ++ snps,quirk-frame-length-adjustment = <0x20>; ++ snps,dis_rxdet_inp3_quirk; ++ }; ++ ++ serdes1: serdes@1ea0000 { ++ reg = <0x0 0x1ea0000 0 0x00002000>; ++ }; ++ ++ ccn@4000000 { ++ compatible = "arm,ccn-504"; ++ reg = <0x0 0x04000000 0x0 0x01000000>; ++ interrupts = <0 12 4>; ++ }; ++ ++ ftm0: ftm0@2800000 { ++ compatible = "fsl,ftm-alarm"; ++ reg = <0x0 0x2800000 0x0 0x10000>; ++ interrupts = <0 44 4>; ++ }; ++ }; ++ ++ ddr1: memory-controller@1080000 { ++ compatible = "fsl,qoriq-memory-controller"; ++ reg = <0x0 0x1080000 0x0 0x1000>; ++ interrupts = <0 17 0x4>; ++ little-endian; ++ }; ++ ++ ddr2: memory-controller@1090000 { ++ compatible = "fsl,qoriq-memory-controller"; ++ reg = <0x0 0x1090000 0x0 0x1000>; ++ interrupts = <0 18 0x4>; ++ little-endian; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/qoriq-bman1-portals.dtsi b/arch/arm64/boot/dts/freescale/qoriq-bman1-portals.dtsi +new file mode 100644 +index 00000000..14680adb +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/qoriq-bman1-portals.dtsi +@@ -0,0 +1,81 @@ ++/* ++ * QorIQ BMan Portals device tree ++ * ++ * Copyright 2011-2016 Freescale Semiconductor Inc. ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++ */ ++ ++&bportals { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "simple-bus"; ++ ++ bman-portal@0 { ++ cell-index = <0>; ++ compatible = "fsl,bman-portal"; ++ reg = <0x0 0x4000 0x4000000 0x4000>; ++ interrupts = <0 173 0x4>; ++ }; ++ ++ bman-portal@10000 { ++ cell-index = <1>; ++ compatible = "fsl,bman-portal"; ++ reg = <0x10000 0x4000 0x4010000 0x4000>; ++ interrupts = <0 175 0x4>; ++ }; ++ ++ bman-portal@20000 { ++ cell-index = <2>; ++ compatible = "fsl,bman-portal"; ++ reg = <0x20000 0x4000 0x4020000 0x4000>; ++ interrupts = <0 177 0x4>; ++ }; ++ ++ bman-portal@30000 { ++ cell-index = <3>; ++ compatible = "fsl,bman-portal"; ++ reg = <0x30000 0x4000 0x4030000 0x4000>; ++ interrupts = <0 179 0x4>; ++ }; ++ ++ bman-portal@40000 { ++ cell-index = <4>; ++ compatible = "fsl,bman-portal"; ++ reg = <0x40000 0x4000 0x4040000 0x4000>; ++ interrupts = <0 181 0x4>; ++ }; ++ ++ bman-portal@50000 { ++ cell-index = <5>; ++ compatible = "fsl,bman-portal"; ++ reg = <0x50000 0x4000 0x4050000 0x4000>; ++ interrupts = <0 183 0x4>; ++ }; ++ ++ bman-portal@60000 { ++ cell-index = <6>; ++ compatible = "fsl,bman-portal"; ++ reg = <0x60000 0x4000 0x4060000 0x4000>; ++ interrupts = <0 185 0x4>; ++ }; ++ ++ bman-portal@70000 { ++ cell-index = <7>; ++ compatible = "fsl,bman-portal"; ++ reg = <0x70000 0x4000 0x4070000 0x4000>; ++ interrupts = <0 187 0x4>; ++ }; ++ ++ bman-portal@80000 { ++ cell-index = <8>; ++ compatible = "fsl,bman-portal"; ++ reg = <0x80000 0x4000 0x4080000 0x4000>; ++ interrupts = <0 189 0x4>; ++ }; ++ ++ bman-bpids@0 { ++ compatible = "fsl,bpid-range"; ++ fsl,bpid-range = <32 32>; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/qoriq-dpaa-eth.dtsi b/arch/arm64/boot/dts/freescale/qoriq-dpaa-eth.dtsi +new file mode 100644 +index 00000000..eb5af912 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/qoriq-dpaa-eth.dtsi +@@ -0,0 +1,66 @@ ++/* ++ * QorIQ FMan v3 10g port #1 device tree stub [ controller @ offset 0x400000 ] ++ * ++ * Copyright 2012 - 2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++fsldpaa: fsl,dpaa { ++ compatible = "fsl,ls1043a-dpaa", "simple-bus", "fsl,dpaa"; ++ ethernet@0 { ++ compatible = "fsl,dpa-ethernet"; ++ fsl,fman-mac = <&enet0>; ++ }; ++ ethernet@1 { ++ compatible = "fsl,dpa-ethernet"; ++ fsl,fman-mac = <&enet1>; ++ }; ++ ethernet@2 { ++ compatible = "fsl,dpa-ethernet"; ++ fsl,fman-mac = <&enet2>; ++ }; ++ ethernet@3 { ++ compatible = "fsl,dpa-ethernet"; ++ fsl,fman-mac = <&enet3>; ++ }; ++ ethernet@4 { ++ compatible = "fsl,dpa-ethernet"; ++ fsl,fman-mac = <&enet4>; ++ }; ++ ethernet@5 { ++ compatible = "fsl,dpa-ethernet"; ++ fsl,fman-mac = <&enet5>; ++ }; ++ ethernet@8 { ++ compatible = "fsl,dpa-ethernet"; ++ fsl,fman-mac = <&enet6>; ++ }; ++}; ++ +diff --git a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-10g-0.dtsi b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-10g-0.dtsi +new file mode 100644 +index 00000000..474bff5e +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-10g-0.dtsi +@@ -0,0 +1,43 @@ ++/* ++ * QorIQ FMan v3 10g port #0 device tree ++ * ++ * Copyright 2012-2015 Freescale Semiconductor Inc. ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++ */ ++ ++fman@1a00000 { ++ fman0_rx_0x10: port@90000 { ++ cell-index = <0x10>; ++ compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-10g-rx"; ++ reg = <0x90000 0x1000>; ++ fsl,fman-10g-port; ++ }; ++ ++ fman0_tx_0x30: port@b0000 { ++ cell-index = <0x30>; ++ compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-10g-tx"; ++ reg = <0xb0000 0x1000>; ++ fsl,fman-10g-port; ++ fsl,qman-channel-id = <0x800>; ++ }; ++ ++ ethernet@f0000 { ++ cell-index = <0x8>; ++ compatible = "fsl,fman-memac"; ++ reg = <0xf0000 0x1000>; ++ fsl,fman-ports = <&fman0_rx_0x10 &fman0_tx_0x30>; ++ pcsphy-handle = <&pcsphy6>; ++ }; ++ ++ mdio@f1000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; ++ reg = <0xf1000 0x1000>; ++ ++ pcsphy6: ethernet-phy@0 { ++ reg = <0x0>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-10g-1.dtsi b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-10g-1.dtsi +new file mode 100644 +index 00000000..d4326f85 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-10g-1.dtsi +@@ -0,0 +1,43 @@ ++/* ++ * QorIQ FMan v3 10g port #1 device tree ++ * ++ * Copyright 2012-2015 Freescale Semiconductor Inc. ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++ */ ++ ++fman@1a00000 { ++ fman0_rx_0x11: port@91000 { ++ cell-index = <0x11>; ++ compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-10g-rx"; ++ reg = <0x91000 0x1000>; ++ fsl,fman-10g-port; ++ }; ++ ++ fman0_tx_0x31: port@b1000 { ++ cell-index = <0x31>; ++ compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-10g-tx"; ++ reg = <0xb1000 0x1000>; ++ fsl,fman-10g-port; ++ fsl,qman-channel-id = <0x801>; ++ }; ++ ++ ethernet@f2000 { ++ cell-index = <0x9>; ++ compatible = "fsl,fman-memac"; ++ reg = <0xf2000 0x1000>; ++ fsl,fman-ports = <&fman0_rx_0x11 &fman0_tx_0x31>; ++ pcsphy-handle = <&pcsphy7>; ++ }; ++ ++ mdio@f3000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; ++ reg = <0xf3000 0x1000>; ++ ++ pcsphy7: ethernet-phy@0 { ++ reg = <0x0>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-0.dtsi b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-0.dtsi +new file mode 100644 +index 00000000..7170cab9 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-0.dtsi +@@ -0,0 +1,42 @@ ++/* ++ * QorIQ FMan v3 1g port #0 device tree ++ * ++ * Copyright 2012-2015 Freescale Semiconductor Inc. ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++ */ ++ ++fman@1a00000 { ++ fman0_rx_0x08: port@88000 { ++ cell-index = <0x8>; ++ compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx"; ++ reg = <0x88000 0x1000>; ++ }; ++ ++ fman0_tx_0x28: port@a8000 { ++ cell-index = <0x28>; ++ compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx"; ++ reg = <0xa8000 0x1000>; ++ fsl,qman-channel-id = <0x802>; ++ }; ++ ++ ethernet@e0000 { ++ cell-index = <0>; ++ compatible = "fsl,fman-memac"; ++ reg = <0xe0000 0x1000>; ++ fsl,fman-ports = <&fman0_rx_0x08 &fman0_tx_0x28>; ++ ptp-timer = <&ptp_timer0>; ++ pcsphy-handle = <&pcsphy0>; ++ }; ++ ++ mdio@e1000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; ++ reg = <0xe1000 0x1000>; ++ ++ pcsphy0: ethernet-phy@0 { ++ reg = <0x0>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-1.dtsi b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-1.dtsi +new file mode 100644 +index 00000000..c7eb8b6e +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-1.dtsi +@@ -0,0 +1,42 @@ ++/* ++ * QorIQ FMan v3 1g port #1 device tree ++ * ++ * Copyright 2012-2015 Freescale Semiconductor Inc. ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++ */ ++ ++fman@1a00000 { ++ fman0_rx_0x09: port@89000 { ++ cell-index = <0x9>; ++ compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx"; ++ reg = <0x89000 0x1000>; ++ }; ++ ++ fman0_tx_0x29: port@a9000 { ++ cell-index = <0x29>; ++ compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx"; ++ reg = <0xa9000 0x1000>; ++ fsl,qman-channel-id = <0x803>; ++ }; ++ ++ ethernet@e2000 { ++ cell-index = <1>; ++ compatible = "fsl,fman-memac"; ++ reg = <0xe2000 0x1000>; ++ fsl,fman-ports = <&fman0_rx_0x09 &fman0_tx_0x29>; ++ ptp-timer = <&ptp_timer0>; ++ pcsphy-handle = <&pcsphy1>; ++ }; ++ ++ mdio@e3000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; ++ reg = <0xe3000 0x1000>; ++ ++ pcsphy1: ethernet-phy@0 { ++ reg = <0x0>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-2.dtsi b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-2.dtsi +new file mode 100644 +index 00000000..56f9f0dd +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-2.dtsi +@@ -0,0 +1,42 @@ ++/* ++ * QorIQ FMan v3 1g port #2 device tree ++ * ++ * Copyright 2012-2015 Freescale Semiconductor Inc. ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++ */ ++ ++fman@1a00000 { ++ fman0_rx_0x0a: port@8a000 { ++ cell-index = <0xa>; ++ compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx"; ++ reg = <0x8a000 0x1000>; ++ }; ++ ++ fman0_tx_0x2a: port@aa000 { ++ cell-index = <0x2a>; ++ compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx"; ++ reg = <0xaa000 0x1000>; ++ fsl,qman-channel-id = <0x804>; ++ }; ++ ++ ethernet@e4000 { ++ cell-index = <2>; ++ compatible = "fsl,fman-memac"; ++ reg = <0xe4000 0x1000>; ++ fsl,fman-ports = <&fman0_rx_0x0a &fman0_tx_0x2a>; ++ ptp-timer = <&ptp_timer0>; ++ pcsphy-handle = <&pcsphy2>; ++ }; ++ ++ mdio@e5000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; ++ reg = <0xe5000 0x1000>; ++ ++ pcsphy2: ethernet-phy@0 { ++ reg = <0x0>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-3.dtsi b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-3.dtsi +new file mode 100644 +index 00000000..bbe7dbaf +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-3.dtsi +@@ -0,0 +1,42 @@ ++/* ++ * QorIQ FMan v3 1g port #3 device tree ++ * ++ * Copyright 2012-2015 Freescale Semiconductor Inc. ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++ */ ++ ++fman@1a00000 { ++ fman0_rx_0x0b: port@8b000 { ++ cell-index = <0xb>; ++ compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx"; ++ reg = <0x8b000 0x1000>; ++ }; ++ ++ fman0_tx_0x2b: port@ab000 { ++ cell-index = <0x2b>; ++ compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx"; ++ reg = <0xab000 0x1000>; ++ fsl,qman-channel-id = <0x805>; ++ }; ++ ++ ethernet@e6000 { ++ cell-index = <3>; ++ compatible = "fsl,fman-memac"; ++ reg = <0xe6000 0x1000>; ++ fsl,fman-ports = <&fman0_rx_0x0b &fman0_tx_0x2b>; ++ ptp-timer = <&ptp_timer0>; ++ pcsphy-handle = <&pcsphy3>; ++ }; ++ ++ mdio@e7000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; ++ reg = <0xe7000 0x1000>; ++ ++ pcsphy3: ethernet-phy@0 { ++ reg = <0x0>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-4.dtsi b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-4.dtsi +new file mode 100644 +index 00000000..ead4f062 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-4.dtsi +@@ -0,0 +1,42 @@ ++/* ++ * QorIQ FMan v3 1g port #4 device tree ++ * ++ * Copyright 2012-2015 Freescale Semiconductor Inc. ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++ */ ++ ++fman@1a00000 { ++ fman0_rx_0x0c: port@8c000 { ++ cell-index = <0xc>; ++ compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx"; ++ reg = <0x8c000 0x1000>; ++ }; ++ ++ fman0_tx_0x2c: port@ac000 { ++ cell-index = <0x2c>; ++ compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx"; ++ reg = <0xac000 0x1000>; ++ fsl,qman-channel-id = <0x806>; ++ }; ++ ++ ethernet@e8000 { ++ cell-index = <4>; ++ compatible = "fsl,fman-memac"; ++ reg = <0xe8000 0x1000>; ++ fsl,fman-ports = <&fman0_rx_0x0c &fman0_tx_0x2c>; ++ ptp-timer = <&ptp_timer0>; ++ pcsphy-handle = <&pcsphy4>; ++ }; ++ ++ mdio@e9000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; ++ reg = <0xe9000 0x1000>; ++ ++ pcsphy4: ethernet-phy@0 { ++ reg = <0x0>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-5.dtsi b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-5.dtsi +new file mode 100644 +index 00000000..389eadaf +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-1g-5.dtsi +@@ -0,0 +1,42 @@ ++/* ++ * QorIQ FMan v3 1g port #5 device tree ++ * ++ * Copyright 2012-2015 Freescale Semiconductor Inc. ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++ */ ++ ++fman@1a00000 { ++ fman0_rx_0x0d: port@8d000 { ++ cell-index = <0xd>; ++ compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-1g-rx"; ++ reg = <0x8d000 0x1000>; ++ }; ++ ++ fman0_tx_0x2d: port@ad000 { ++ cell-index = <0x2d>; ++ compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-1g-tx"; ++ reg = <0xad000 0x1000>; ++ fsl,qman-channel-id = <0x807>; ++ }; ++ ++ ethernet@ea000 { ++ cell-index = <5>; ++ compatible = "fsl,fman-memac"; ++ reg = <0xea000 0x1000>; ++ fsl,fman-ports = <&fman0_rx_0x0d &fman0_tx_0x2d>; ++ ptp-timer = <&ptp_timer0>; ++ pcsphy-handle = <&pcsphy5>; ++ }; ++ ++ mdio@eb000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; ++ reg = <0xeb000 0x1000>; ++ ++ pcsphy5: ethernet-phy@0 { ++ reg = <0x0>; ++ }; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/qoriq-fman3-0-6oh.dtsi b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-6oh.dtsi +new file mode 100644 +index 00000000..2d0df20d +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0-6oh.dtsi +@@ -0,0 +1,47 @@ ++/* ++ * QorIQ FMan v3 OH ports device tree ++ * ++ * Copyright 2012-2015 Freescale Semiconductor Inc. ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++ */ ++ ++fman@1a00000 { ++ ++ fman0_oh1: port@82000 { ++ cell-index = <0>; ++ compatible = "fsl,fman-port-oh"; ++ reg = <0x82000 0x1000>; ++ }; ++ ++ fman0_oh2: port@83000 { ++ cell-index = <1>; ++ compatible = "fsl,fman-port-oh"; ++ reg = <0x83000 0x1000>; ++ }; ++ ++ fman0_oh3: port@84000 { ++ cell-index = <2>; ++ compatible = "fsl,fman-port-oh"; ++ reg = <0x84000 0x1000>; ++ }; ++ ++ fman0_oh4: port@85000 { ++ cell-index = <3>; ++ compatible = "fsl,fman-port-oh"; ++ reg = <0x85000 0x1000>; ++ }; ++ ++ fman0_oh5: port@86000 { ++ cell-index = <4>; ++ compatible = "fsl,fman-port-oh"; ++ reg = <0x86000 0x1000>; ++ }; ++ ++ fman0_oh6: port@87000 { ++ cell-index = <5>; ++ compatible = "fsl,fman-port-oh"; ++ reg = <0x87000 0x1000>; ++ }; ++ ++}; +diff --git a/arch/arm64/boot/dts/freescale/qoriq-fman3-0.dtsi b/arch/arm64/boot/dts/freescale/qoriq-fman3-0.dtsi +new file mode 100644 +index 00000000..8e089f0c +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/qoriq-fman3-0.dtsi +@@ -0,0 +1,130 @@ ++/* ++ * QorIQ FMan v3 device tree ++ * ++ * Copyright 2012-2015 Freescale Semiconductor Inc. ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++ */ ++ ++fman0: fman@1a00000 { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ cell-index = <0>; ++ compatible = "fsl,fman"; ++ ranges = <0x0 0x00 0x1a00000 0x100000>; ++ reg = <0x0 0x1a00000 0x0 0x100000>; ++ interrupts = <0 44 0x4>, <0 45 0x4>; ++ clocks = <&clockgen 3 0>; ++ clock-names = "fmanclk"; ++ fsl,qman-channel-range = <0x800 0x10>; ++ ++ cc { ++ compatible = "fsl,fman-cc"; ++ }; ++ ++ muram@0 { ++ compatible = "fsl,fman-muram"; ++ reg = <0x0 0x60000>; ++ }; ++ ++ bmi@80000 { ++ compatible = "fsl,fman-bmi"; ++ reg = <0x80000 0x400>; ++ }; ++ ++ qmi@80400 { ++ compatible = "fsl,fman-qmi"; ++ reg = <0x80400 0x400>; ++ }; ++ ++ fman0_oh_0x2: port@82000 { ++ cell-index = <0x2>; ++ compatible = "fsl,fman-v3-port-oh"; ++ reg = <0x82000 0x1000>; ++ fsl,qman-channel-id = <0x809>; ++ }; ++ ++ fman0_oh_0x3: port@83000 { ++ cell-index = <0x3>; ++ compatible = "fsl,fman-v3-port-oh"; ++ reg = <0x83000 0x1000>; ++ fsl,qman-channel-id = <0x80a>; ++ }; ++ ++ fman0_oh_0x4: port@84000 { ++ cell-index = <0x4>; ++ compatible = "fsl,fman-v3-port-oh"; ++ reg = <0x84000 0x1000>; ++ fsl,qman-channel-id = <0x80b>; ++ }; ++ ++ fman0_oh_0x5: port@85000 { ++ cell-index = <0x5>; ++ compatible = "fsl,fman-v3-port-oh"; ++ reg = <0x85000 0x1000>; ++ fsl,qman-channel-id = <0x80c>; ++ }; ++ ++ fman0_oh_0x6: port@86000 { ++ cell-index = <0x6>; ++ compatible = "fsl,fman-v3-port-oh"; ++ reg = <0x86000 0x1000>; ++ fsl,qman-channel-id = <0x80d>; ++ }; ++ ++ fman0_oh_0x7: port@87000 { ++ cell-index = <0x7>; ++ compatible = "fsl,fman-v3-port-oh"; ++ reg = <0x87000 0x1000>; ++ fsl,qman-channel-id = <0x80e>; ++ }; ++ ++ policer@c0000 { ++ compatible = "fsl,fman-policer"; ++ reg = <0xc0000 0x1000>; ++ }; ++ ++ keygen@c1000 { ++ compatible = "fsl,fman-keygen"; ++ reg = <0xc1000 0x1000>; ++ }; ++ ++ dma@c2000 { ++ compatible = "fsl,fman-dma"; ++ reg = <0xc2000 0x1000>; ++ }; ++ ++ fpm@c3000 { ++ compatible = "fsl,fman-fpm"; ++ reg = <0xc3000 0x1000>; ++ }; ++ ++ parser@c7000 { ++ compatible = "fsl,fman-parser"; ++ reg = <0xc7000 0x1000>; ++ }; ++ ++ vsps@dc000 { ++ compatible = "fsl,fman-vsps"; ++ reg = <0xdc000 0x1000>; ++ }; ++ ++ mdio0: mdio@fc000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; ++ reg = <0xfc000 0x1000>; ++ }; ++ ++ xmdio0: mdio@fd000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio"; ++ reg = <0xfd000 0x1000>; ++ }; ++ ++ ptp_timer0: ptp-timer@fe000 { ++ compatible = "fsl,fman-ptp-timer", "fsl,fman-rtc"; ++ reg = <0xfe000 0x1000>; ++ }; ++}; +diff --git a/arch/arm64/boot/dts/freescale/qoriq-qman1-portals.dtsi b/arch/arm64/boot/dts/freescale/qoriq-qman1-portals.dtsi +new file mode 100644 +index 00000000..4f7edf48 +--- /dev/null ++++ b/arch/arm64/boot/dts/freescale/qoriq-qman1-portals.dtsi +@@ -0,0 +1,104 @@ ++/* ++ * QorIQ QMan Portals device tree ++ * ++ * Copyright 2011-2016 Freescale Semiconductor Inc. ++ * ++ * SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++ */ ++ ++&qportals { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ compatible = "simple-bus"; ++ ++ qportal0: qman-portal@0 { ++ compatible = "fsl,qman-portal"; ++ reg = <0x0 0x4000 0x4000000 0x4000>; ++ interrupts = <0 172 0x4>; ++ cell-index = <0>; ++ }; ++ ++ qportal1: qman-portal@10000 { ++ compatible = "fsl,qman-portal"; ++ reg = <0x10000 0x4000 0x4010000 0x4000>; ++ interrupts = <0 174 0x4>; ++ cell-index = <1>; ++ }; ++ ++ qportal2: qman-portal@20000 { ++ compatible = "fsl,qman-portal"; ++ reg = <0x20000 0x4000 0x4020000 0x4000>; ++ interrupts = <0 176 0x4>; ++ cell-index = <2>; ++ }; ++ ++ qportal3: qman-portal@30000 { ++ compatible = "fsl,qman-portal"; ++ reg = <0x30000 0x4000 0x4030000 0x4000>; ++ interrupts = <0 178 0x4>; ++ cell-index = <3>; ++ }; ++ ++ qportal4: qman-portal@40000 { ++ compatible = "fsl,qman-portal"; ++ reg = <0x40000 0x4000 0x4040000 0x4000>; ++ interrupts = <0 180 0x4>; ++ cell-index = <4>; ++ }; ++ ++ qportal5: qman-portal@50000 { ++ compatible = "fsl,qman-portal"; ++ reg = <0x50000 0x4000 0x4050000 0x4000>; ++ interrupts = <0 182 0x4>; ++ cell-index = <5>; ++ }; ++ ++ qportal6: qman-portal@60000 { ++ compatible = "fsl,qman-portal"; ++ reg = <0x60000 0x4000 0x4060000 0x4000>; ++ interrupts = <0 184 0x4>; ++ cell-index = <6>; ++ }; ++ ++ qportal7: qman-portal@70000 { ++ compatible = "fsl,qman-portal"; ++ reg = <0x70000 0x4000 0x4070000 0x4000>; ++ interrupts = <0 186 0x4>; ++ cell-index = <7>; ++ }; ++ ++ qportal8: qman-portal@80000 { ++ compatible = "fsl,qman-portal"; ++ reg = <0x80000 0x4000 0x4080000 0x4000>; ++ interrupts = <0 188 0x4>; ++ cell-index = <8>; ++ }; ++ ++ qman-fqids@0 { ++ compatible = "fsl,fqid-range"; ++ fsl,fqid-range = <256 256>; ++ }; ++ ++ qman-fqids@1 { ++ compatible = "fsl,fqid-range"; ++ fsl,fqid-range = <32768 32768>; ++ }; ++ ++ qman-pools@0 { ++ compatible = "fsl,pool-channel-range"; ++ fsl,pool-channel-range = <0x401 0xf>; ++ }; ++ ++ qman-cgrids@0 { ++ compatible = "fsl,cgrid-range"; ++ fsl,cgrid-range = <0 256>; ++ }; ++ ++ qman-ceetm@0 { ++ compatible = "fsl,qman-ceetm"; ++ fsl,ceetm-lfqid-range = <0xf00000 0x1000>; ++ fsl,ceetm-sp-range = <0 12>; ++ fsl,ceetm-lni-range = <0 8>; ++ fsl,ceetm-channel-range = <0 32>; ++ }; ++}; +diff --git a/arch/powerpc/boot/dts/fsl/qoriq-bman1-portals.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-bman1-portals.dtsi +index 5022432e..65701ada 100644 +--- a/arch/powerpc/boot/dts/fsl/qoriq-bman1-portals.dtsi ++++ b/arch/powerpc/boot/dts/fsl/qoriq-bman1-portals.dtsi +@@ -38,51 +38,61 @@ + compatible = "simple-bus"; + + bman-portal@0 { ++ cell-index = <0>; + compatible = "fsl,bman-portal"; + reg = <0x0 0x4000>, <0x100000 0x1000>; + interrupts = <105 2 0 0>; + }; + bman-portal@4000 { ++ cell-index = <1>; + compatible = "fsl,bman-portal"; + reg = <0x4000 0x4000>, <0x101000 0x1000>; + interrupts = <107 2 0 0>; + }; + bman-portal@8000 { ++ cell-index = <2>; + compatible = "fsl,bman-portal"; + reg = <0x8000 0x4000>, <0x102000 0x1000>; + interrupts = <109 2 0 0>; + }; + bman-portal@c000 { ++ cell-index = <3>; + compatible = "fsl,bman-portal"; + reg = <0xc000 0x4000>, <0x103000 0x1000>; + interrupts = <111 2 0 0>; + }; + bman-portal@10000 { ++ cell-index = <4>; + compatible = "fsl,bman-portal"; + reg = <0x10000 0x4000>, <0x104000 0x1000>; + interrupts = <113 2 0 0>; + }; + bman-portal@14000 { ++ cell-index = <5>; + compatible = "fsl,bman-portal"; + reg = <0x14000 0x4000>, <0x105000 0x1000>; + interrupts = <115 2 0 0>; + }; + bman-portal@18000 { ++ cell-index = <6>; + compatible = "fsl,bman-portal"; + reg = <0x18000 0x4000>, <0x106000 0x1000>; + interrupts = <117 2 0 0>; + }; + bman-portal@1c000 { ++ cell-index = <7>; + compatible = "fsl,bman-portal"; + reg = <0x1c000 0x4000>, <0x107000 0x1000>; + interrupts = <119 2 0 0>; + }; + bman-portal@20000 { ++ cell-index = <8>; + compatible = "fsl,bman-portal"; + reg = <0x20000 0x4000>, <0x108000 0x1000>; + interrupts = <121 2 0 0>; + }; + bman-portal@24000 { ++ cell-index = <9>; + compatible = "fsl,bman-portal"; + reg = <0x24000 0x4000>, <0x109000 0x1000>; + interrupts = <123 2 0 0>; +diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0.dtsi +index c288f3c6..dd200e28 100644 +--- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0.dtsi ++++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-0.dtsi +@@ -35,14 +35,14 @@ + fman@400000 { + fman0_rx_0x10: port@90000 { + cell-index = <0x10>; +- compatible = "fsl,fman-v3-port-rx"; ++ compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-10g-rx"; + reg = <0x90000 0x1000>; + fsl,fman-10g-port; + }; + + fman0_tx_0x30: port@b0000 { + cell-index = <0x30>; +- compatible = "fsl,fman-v3-port-tx"; ++ compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-10g-tx"; + reg = <0xb0000 0x1000>; + fsl,fman-10g-port; + }; +diff --git a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1.dtsi +index 94a76982..365770c9 100644 +--- a/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1.dtsi ++++ b/arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-1.dtsi +@@ -35,14 +35,14 @@ + fman@400000 { + fman0_rx_0x11: port@91000 { + cell-index = <0x11>; +- compatible = "fsl,fman-v3-port-rx"; ++ compatible = "fsl,fman-v3-port-rx", "fsl,fman-port-10g-rx"; + reg = <0x91000 0x1000>; + fsl,fman-10g-port; + }; + + fman0_tx_0x31: port@b1000 { + cell-index = <0x31>; +- compatible = "fsl,fman-v3-port-tx"; ++ compatible = "fsl,fman-v3-port-tx", "fsl,fman-port-10g-tx"; + reg = <0xb1000 0x1000>; + fsl,fman-10g-port; + }; +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/401-mtd-spi-nor-support-layerscape.patch b/target/linux/layerscape/patches-4.9/401-mtd-spi-nor-support-layerscape.patch new file mode 100644 index 0000000000..f61ae06ca2 --- /dev/null +++ b/target/linux/layerscape/patches-4.9/401-mtd-spi-nor-support-layerscape.patch @@ -0,0 +1,1042 @@ +From 120fa458ffe2250ea58578ccfc85e674005463dc Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 10:53:50 +0800 +Subject: [PATCH] mtd: spi-nor: support layerscape + +This is a integrated patch for layerscape qspi support. + +Signed-off-by: Suresh Gupta +Signed-off-by: Yunhui Cui +Signed-off-by: mar.krzeminski +Signed-off-by: Alison Wang +Signed-off-by: Nobuhiro Iwamatsu +Signed-off-by: LABBE Corentin +Signed-off-by: Yuan Yao +Signed-off-by: Alexander Kurz +Signed-off-by: L. D. Pinney +Signed-off-by: Ash Benz +Signed-off-by: Yangbo Lu +--- + drivers/mtd/mtdchar.c | 2 +- + drivers/mtd/spi-nor/fsl-quadspi.c | 356 +++++++++++++++++++++++++++++++------- + drivers/mtd/spi-nor/spi-nor.c | 136 +++++++++++++-- + include/linux/mtd/spi-nor.h | 14 +- + 4 files changed, 432 insertions(+), 76 deletions(-) + +diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c +index 2a47a3f0..4f21401d 100644 +--- a/drivers/mtd/mtdchar.c ++++ b/drivers/mtd/mtdchar.c +@@ -451,7 +451,7 @@ static int mtdchar_readoob(struct file *file, struct mtd_info *mtd, + * data. For our userspace tools it is important to dump areas + * with ECC errors! + * For kernel internal usage it also might return -EUCLEAN +- * to signal the caller that a bitflip has occured and has ++ * to signal the caller that a bitflip has occurred and has + * been corrected by the ECC algorithm. + * + * Note: currently the standard NAND function, nand_read_oob_std, +diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c +index 5c82e4ef..8fb75532 100644 +--- a/drivers/mtd/spi-nor/fsl-quadspi.c ++++ b/drivers/mtd/spi-nor/fsl-quadspi.c +@@ -41,6 +41,8 @@ + #define QUADSPI_QUIRK_TKT253890 (1 << 2) + /* Controller cannot wake up from wait mode, TKT245618 */ + #define QUADSPI_QUIRK_TKT245618 (1 << 3) ++/* QSPI_AMBA_BASE is internally added by SOC design */ ++#define QUADSPI_AMBA_BASE_INTERNAL (0x10000) + + /* The registers */ + #define QUADSPI_MCR 0x00 +@@ -193,7 +195,7 @@ + #define QUADSPI_LUT_NUM 64 + + /* SEQID -- we can have 16 seqids at most. */ +-#define SEQID_QUAD_READ 0 ++#define SEQID_READ 0 + #define SEQID_WREN 1 + #define SEQID_WRDI 2 + #define SEQID_RDSR 3 +@@ -205,15 +207,22 @@ + #define SEQID_RDCR 9 + #define SEQID_EN4B 10 + #define SEQID_BRWR 11 ++#define SEQID_RDAR_OR_RD_EVCR 12 ++#define SEQID_WRAR 13 ++#define SEQID_WD_EVCR 14 + + #define QUADSPI_MIN_IOMAP SZ_4M + ++#define FLASH_VENDOR_SPANSION_FS "s25fs" ++#define SPANSION_S25FS_FAMILY (1 << 1) ++ + enum fsl_qspi_devtype { + FSL_QUADSPI_VYBRID, + FSL_QUADSPI_IMX6SX, + FSL_QUADSPI_IMX7D, + FSL_QUADSPI_IMX6UL, + FSL_QUADSPI_LS1021A, ++ FSL_QUADSPI_LS2080A, + }; + + struct fsl_qspi_devtype_data { +@@ -224,7 +233,7 @@ struct fsl_qspi_devtype_data { + int driver_data; + }; + +-static struct fsl_qspi_devtype_data vybrid_data = { ++static const struct fsl_qspi_devtype_data vybrid_data = { + .devtype = FSL_QUADSPI_VYBRID, + .rxfifo = 128, + .txfifo = 64, +@@ -232,7 +241,7 @@ static struct fsl_qspi_devtype_data vybrid_data = { + .driver_data = QUADSPI_QUIRK_SWAP_ENDIAN, + }; + +-static struct fsl_qspi_devtype_data imx6sx_data = { ++static const struct fsl_qspi_devtype_data imx6sx_data = { + .devtype = FSL_QUADSPI_IMX6SX, + .rxfifo = 128, + .txfifo = 512, +@@ -241,7 +250,7 @@ static struct fsl_qspi_devtype_data imx6sx_data = { + | QUADSPI_QUIRK_TKT245618, + }; + +-static struct fsl_qspi_devtype_data imx7d_data = { ++static const struct fsl_qspi_devtype_data imx7d_data = { + .devtype = FSL_QUADSPI_IMX7D, + .rxfifo = 512, + .txfifo = 512, +@@ -250,7 +259,7 @@ static struct fsl_qspi_devtype_data imx7d_data = { + | QUADSPI_QUIRK_4X_INT_CLK, + }; + +-static struct fsl_qspi_devtype_data imx6ul_data = { ++static const struct fsl_qspi_devtype_data imx6ul_data = { + .devtype = FSL_QUADSPI_IMX6UL, + .rxfifo = 128, + .txfifo = 512, +@@ -267,6 +276,14 @@ static struct fsl_qspi_devtype_data ls1021a_data = { + .driver_data = 0, + }; + ++static struct fsl_qspi_devtype_data ls2080a_data = { ++ .devtype = FSL_QUADSPI_LS2080A, ++ .rxfifo = 128, ++ .txfifo = 64, ++ .ahb_buf_size = 1024, ++ .driver_data = QUADSPI_AMBA_BASE_INTERNAL | QUADSPI_QUIRK_TKT253890, ++}; ++ + #define FSL_QSPI_MAX_CHIP 4 + struct fsl_qspi { + struct spi_nor nor[FSL_QSPI_MAX_CHIP]; +@@ -282,6 +299,7 @@ struct fsl_qspi { + u32 nor_size; + u32 nor_num; + u32 clk_rate; ++ u32 ddr_smp; + unsigned int chip_base_addr; /* We may support two chips. */ + bool has_second_chip; + bool big_endian; +@@ -309,6 +327,23 @@ static inline int needs_wakeup_wait_mode(struct fsl_qspi *q) + return q->devtype_data->driver_data & QUADSPI_QUIRK_TKT245618; + } + ++static inline int has_added_amba_base_internal(struct fsl_qspi *q) ++{ ++ return q->devtype_data->driver_data & QUADSPI_AMBA_BASE_INTERNAL; ++} ++ ++static u32 fsl_get_nor_vendor(struct spi_nor *nor) ++{ ++ u32 vendor_id; ++ ++ if (nor->vendor) { ++ if (memcmp(nor->vendor, FLASH_VENDOR_SPANSION_FS, ++ sizeof(FLASH_VENDOR_SPANSION_FS) - 1)) ++ vendor_id = SPANSION_S25FS_FAMILY; ++ } ++ return vendor_id; ++} ++ + /* + * R/W functions for big- or little-endian registers: + * The qSPI controller's endian is independent of the CPU core's endian. +@@ -331,6 +366,31 @@ static u32 qspi_readl(struct fsl_qspi *q, void __iomem *addr) + return ioread32(addr); + } + ++static inline u32 *u8tou32(u32 *dest, const u8 *src, size_t n) ++{ ++ size_t i; ++ *dest = 0; ++ ++ n = n > 4 ? 4 : n; ++ for (i = 0; i < n; i++) ++ *dest |= *src++ << i * 8; ++ ++ return dest; ++ ++} ++ ++static inline u8 *u32tou8(u8 *dest, const u32 *src, size_t n) ++{ ++ size_t i; ++ u8 *xdest = dest; ++ ++ n = n > 4 ? 4 : n; ++ for (i = 0; i < n; i++) ++ *xdest++ = *src >> i * 8; ++ ++ return dest; ++} ++ + /* + * An IC bug makes us to re-arrange the 32-bit data. + * The following chips, such as IMX6SLX, have fixed this bug. +@@ -373,8 +433,15 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) + void __iomem *base = q->iobase; + int rxfifo = q->devtype_data->rxfifo; + u32 lut_base; +- u8 cmd, addrlen, dummy; + int i; ++ u32 vendor; ++ ++ struct spi_nor *nor = &q->nor[0]; ++ u8 addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT; ++ u8 read_op = nor->read_opcode; ++ u8 read_dm = nor->read_dummy; ++ ++ vendor = fsl_get_nor_vendor(nor); + + fsl_qspi_unlock_lut(q); + +@@ -382,25 +449,51 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) + for (i = 0; i < QUADSPI_LUT_NUM; i++) + qspi_writel(q, 0, base + QUADSPI_LUT_BASE + i * 4); + +- /* Quad Read */ +- lut_base = SEQID_QUAD_READ * 4; +- +- if (q->nor_size <= SZ_16M) { +- cmd = SPINOR_OP_READ_1_1_4; +- addrlen = ADDR24BIT; +- dummy = 8; +- } else { +- /* use the 4-byte address */ +- cmd = SPINOR_OP_READ_1_1_4; +- addrlen = ADDR32BIT; +- dummy = 8; +- } +- +- qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), ++ /* Read */ ++ lut_base = SEQID_READ * 4; ++ ++ if (nor->flash_read == SPI_NOR_FAST) { ++ qspi_writel(q, LUT0(CMD, PAD1, read_op) | ++ LUT1(ADDR, PAD1, addrlen), ++ base + QUADSPI_LUT(lut_base)); ++ qspi_writel(q, LUT0(DUMMY, PAD1, read_dm) | ++ LUT1(FSL_READ, PAD1, rxfifo), ++ base + QUADSPI_LUT(lut_base + 1)); ++ } else if (nor->flash_read == SPI_NOR_QUAD) { ++ if (q->nor_size == 0x4000000) { ++ read_op = 0xEC; ++ qspi_writel(q, ++ LUT0(CMD, PAD1, read_op) | LUT1(ADDR, PAD4, addrlen), ++ base + QUADSPI_LUT(lut_base)); ++ qspi_writel(q, ++ LUT0(MODE, PAD4, 0xff) | LUT1(DUMMY, PAD4, read_dm), ++ base + QUADSPI_LUT(lut_base + 1)); ++ qspi_writel(q, ++ LUT0(FSL_READ, PAD4, rxfifo), ++ base + QUADSPI_LUT(lut_base + 2)); ++ } else { ++ qspi_writel(q, LUT0(CMD, PAD1, read_op) | ++ LUT1(ADDR, PAD1, addrlen), ++ base + QUADSPI_LUT(lut_base)); ++ qspi_writel(q, LUT0(DUMMY, PAD1, read_dm) | ++ LUT1(FSL_READ, PAD4, rxfifo), ++ base + QUADSPI_LUT(lut_base + 1)); ++ } ++ } else if (nor->flash_read == SPI_NOR_DDR_QUAD) { ++ /* read mode : 1-4-4, such as Spansion s25fl128s. */ ++ qspi_writel(q, LUT0(CMD, PAD1, read_op) ++ | LUT1(ADDR_DDR, PAD4, addrlen), + base + QUADSPI_LUT(lut_base)); +- qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo), ++ ++ qspi_writel(q, LUT0(MODE_DDR, PAD4, 0xff) ++ | LUT1(DUMMY, PAD1, read_dm), + base + QUADSPI_LUT(lut_base + 1)); + ++ qspi_writel(q, LUT0(FSL_READ_DDR, PAD4, rxfifo) ++ | LUT1(JMP_ON_CS, PAD1, 0), ++ base + QUADSPI_LUT(lut_base + 2)); ++ } ++ + /* Write enable */ + lut_base = SEQID_WREN * 4; + qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WREN), +@@ -409,16 +502,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) + /* Page Program */ + lut_base = SEQID_PP * 4; + +- if (q->nor_size <= SZ_16M) { +- cmd = SPINOR_OP_PP; +- addrlen = ADDR24BIT; +- } else { +- /* use the 4-byte address */ +- cmd = SPINOR_OP_PP; +- addrlen = ADDR32BIT; +- } +- +- qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), ++ qspi_writel(q, LUT0(CMD, PAD1, nor->program_opcode) | ++ LUT1(ADDR, PAD1, addrlen), + base + QUADSPI_LUT(lut_base)); + qspi_writel(q, LUT0(FSL_WRITE, PAD1, 0), + base + QUADSPI_LUT(lut_base + 1)); +@@ -432,10 +517,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) + /* Erase a sector */ + lut_base = SEQID_SE * 4; + +- cmd = q->nor[0].erase_opcode; +- addrlen = q->nor_size <= SZ_16M ? ADDR24BIT : ADDR32BIT; +- +- qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), ++ qspi_writel(q, LUT0(CMD, PAD1, nor->erase_opcode) | ++ LUT1(ADDR, PAD1, addrlen), + base + QUADSPI_LUT(lut_base)); + + /* Erase the whole chip */ +@@ -476,6 +559,44 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) + qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_BRWR), + base + QUADSPI_LUT(lut_base)); + ++ ++ /* ++ * Flash Micron and Spansion command confilict ++ * use the same value 0x65. But it indicates different meaning. ++ */ ++ lut_base = SEQID_RDAR_OR_RD_EVCR * 4; ++ ++ if (vendor == SPANSION_S25FS_FAMILY) { ++ /* ++ * Read any device register. ++ * Used for Spansion S25FS-S family flash only. ++ */ ++ qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_SPANSION_RDAR) | ++ LUT1(ADDR, PAD1, ADDR24BIT), ++ base + QUADSPI_LUT(lut_base)); ++ qspi_writel(q, LUT0(DUMMY, PAD1, 8) | LUT1(FSL_READ, PAD1, 1), ++ base + QUADSPI_LUT(lut_base + 1)); ++ } else { ++ qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_RD_EVCR), ++ base + QUADSPI_LUT(lut_base)); ++ } ++ ++ /* ++ * Write any device register. ++ * Used for Spansion S25FS-S family flash only. ++ */ ++ lut_base = SEQID_WRAR * 4; ++ qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_SPANSION_WRAR) | ++ LUT1(ADDR, PAD1, ADDR24BIT), ++ base + QUADSPI_LUT(lut_base)); ++ qspi_writel(q, LUT0(FSL_WRITE, PAD1, 1), ++ base + QUADSPI_LUT(lut_base + 1)); ++ ++ /* Write EVCR register */ ++ lut_base = SEQID_WD_EVCR * 4; ++ qspi_writel(q, LUT0(CMD, PAD1, SPINOR_OP_WD_EVCR), ++ base + QUADSPI_LUT(lut_base)); ++ + fsl_qspi_lock_lut(q); + } + +@@ -483,8 +604,24 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) + static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) + { + switch (cmd) { ++ case SPINOR_OP_READ_1_4_4_D: ++ case SPINOR_OP_READ4_1_4_4_D: ++ case SPINOR_OP_READ4_1_1_4: + case SPINOR_OP_READ_1_1_4: +- return SEQID_QUAD_READ; ++ case SPINOR_OP_READ_FAST: ++ case SPINOR_OP_READ4_FAST: ++ return SEQID_READ; ++ /* ++ * Spansion & Micron use the same command value 0x65 ++ * Spansion: SPINOR_OP_SPANSION_RDAR, read any register. ++ * Micron: SPINOR_OP_RD_EVCR, ++ * read enhanced volatile configuration register. ++ * case SPINOR_OP_RD_EVCR: ++ */ ++ case SPINOR_OP_SPANSION_RDAR: ++ return SEQID_RDAR_OR_RD_EVCR; ++ case SPINOR_OP_SPANSION_WRAR: ++ return SEQID_WRAR; + case SPINOR_OP_WREN: + return SEQID_WREN; + case SPINOR_OP_WRDI: +@@ -496,6 +633,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) + case SPINOR_OP_CHIP_ERASE: + return SEQID_CHIP_ERASE; + case SPINOR_OP_PP: ++ case SPINOR_OP_PP_4B: + return SEQID_PP; + case SPINOR_OP_RDID: + return SEQID_RDID; +@@ -507,6 +645,8 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) + return SEQID_EN4B; + case SPINOR_OP_BRWR: + return SEQID_BRWR; ++ case SPINOR_OP_WD_EVCR: ++ return SEQID_WD_EVCR; + default: + if (cmd == q->nor[0].erase_opcode) + return SEQID_SE; +@@ -531,8 +671,11 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len) + /* save the reg */ + reg = qspi_readl(q, base + QUADSPI_MCR); + +- qspi_writel(q, q->memmap_phy + q->chip_base_addr + addr, +- base + QUADSPI_SFAR); ++ if (has_added_amba_base_internal(q)) ++ qspi_writel(q, q->chip_base_addr + addr, base + QUADSPI_SFAR); ++ else ++ qspi_writel(q, q->memmap_phy + q->chip_base_addr + addr, ++ base + QUADSPI_SFAR); + qspi_writel(q, QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS, + base + QUADSPI_RBCT); + qspi_writel(q, reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR); +@@ -582,10 +725,10 @@ static void fsl_qspi_read_data(struct fsl_qspi *q, int len, u8 *rxbuf) + q->chip_base_addr, tmp); + + if (len >= 4) { +- *((u32 *)rxbuf) = tmp; ++ u32tou8(rxbuf, &tmp, 4); + rxbuf += 4; + } else { +- memcpy(rxbuf, &tmp, len); ++ u32tou8(rxbuf, &tmp, len); + break; + } + +@@ -619,11 +762,12 @@ static inline void fsl_qspi_invalid(struct fsl_qspi *q) + } + + static ssize_t fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor, +- u8 opcode, unsigned int to, u32 *txbuf, ++ u8 opcode, unsigned int to, u8 *txbuf, + unsigned count) + { + int ret, i, j; + u32 tmp; ++ u8 byts; + + dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len : %d\n", + q->chip_base_addr, to, count); +@@ -633,10 +777,13 @@ static ssize_t fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor, + qspi_writel(q, tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR); + + /* fill the TX data to the FIFO */ ++ byts = count; + for (j = 0, i = ((count + 3) / 4); j < i; j++) { +- tmp = fsl_qspi_endian_xchg(q, *txbuf); ++ u8tou32(&tmp, txbuf, byts); ++ tmp = fsl_qspi_endian_xchg(q, tmp); + qspi_writel(q, tmp, q->iobase + QUADSPI_TBDR); +- txbuf++; ++ txbuf += 4; ++ byts -= 4; + } + + /* fill the TXFIFO upto 16 bytes for i.MX7d */ +@@ -657,11 +804,43 @@ static void fsl_qspi_set_map_addr(struct fsl_qspi *q) + { + int nor_size = q->nor_size; + void __iomem *base = q->iobase; ++ u32 mem_base; ++ ++ if (has_added_amba_base_internal(q)) ++ mem_base = 0x0; ++ else ++ mem_base = q->memmap_phy; ++ ++ qspi_writel(q, nor_size + mem_base, base + QUADSPI_SFA1AD); ++ qspi_writel(q, nor_size * 2 + mem_base, base + QUADSPI_SFA2AD); ++ qspi_writel(q, nor_size * 3 + mem_base, base + QUADSPI_SFB1AD); ++ qspi_writel(q, nor_size * 4 + mem_base, base + QUADSPI_SFB2AD); ++} ++ ++/* ++ * enable controller ddr quad mode to support different ++ * vender flashes ddr quad mode. ++ */ ++static void set_ddr_quad_mode(struct fsl_qspi *q) ++{ ++ u32 reg, reg2; ++ ++ reg = qspi_readl(q, q->iobase + QUADSPI_MCR); ++ ++ /* Firstly, disable the module */ ++ qspi_writel(q, reg | QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR); ++ ++ /* Set the Sampling Register for DDR */ ++ reg2 = qspi_readl(q, q->iobase + QUADSPI_SMPR); ++ reg2 &= ~QUADSPI_SMPR_DDRSMP_MASK; ++ reg2 |= (((q->ddr_smp) << QUADSPI_SMPR_DDRSMP_SHIFT) & ++ QUADSPI_SMPR_DDRSMP_MASK); ++ qspi_writel(q, reg2, q->iobase + QUADSPI_SMPR); ++ ++ /* Enable the module again (enable the DDR too) */ ++ reg |= QUADSPI_MCR_DDR_EN_MASK; ++ qspi_writel(q, reg, q->iobase + QUADSPI_MCR); + +- qspi_writel(q, nor_size + q->memmap_phy, base + QUADSPI_SFA1AD); +- qspi_writel(q, nor_size * 2 + q->memmap_phy, base + QUADSPI_SFA2AD); +- qspi_writel(q, nor_size * 3 + q->memmap_phy, base + QUADSPI_SFB1AD); +- qspi_writel(q, nor_size * 4 + q->memmap_phy, base + QUADSPI_SFB2AD); + } + + /* +@@ -681,19 +860,36 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q) + { + void __iomem *base = q->iobase; + int seqid; ++ const struct fsl_qspi_devtype_data *devtype_data = q->devtype_data; + + /* AHB configuration for access buffer 0/1/2 .*/ + qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR); + qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR); + qspi_writel(q, QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR); ++ + /* +- * Set ADATSZ with the maximum AHB buffer size to improve the +- * read performance. ++ * Errata: A-009282: QuadSPI data prefetch may result in incorrect data ++ * Workaround: Keep the read data size to 64 bits (8 bytes). ++ * This disables the prefetch on the AHB buffer and ++ * prevents this issue from occurring. + */ +- qspi_writel(q, QUADSPI_BUF3CR_ALLMST_MASK | +- ((q->devtype_data->ahb_buf_size / 8) +- << QUADSPI_BUF3CR_ADATSZ_SHIFT), +- base + QUADSPI_BUF3CR); ++ if (devtype_data->devtype == FSL_QUADSPI_LS2080A || ++ devtype_data->devtype == FSL_QUADSPI_LS1021A) { ++ ++ qspi_writel(q, QUADSPI_BUF3CR_ALLMST_MASK | ++ (1 << QUADSPI_BUF3CR_ADATSZ_SHIFT), ++ base + QUADSPI_BUF3CR); ++ ++ } else { ++ /* ++ * Set ADATSZ with the maximum AHB buffer size to improve the ++ * read performance. ++ */ ++ qspi_writel(q, QUADSPI_BUF3CR_ALLMST_MASK | ++ ((q->devtype_data->ahb_buf_size / 8) ++ << QUADSPI_BUF3CR_ADATSZ_SHIFT), ++ base + QUADSPI_BUF3CR); ++ } + + /* We only use the buffer3 */ + qspi_writel(q, 0, base + QUADSPI_BUF0IND); +@@ -704,6 +900,11 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q) + seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode); + qspi_writel(q, seqid << QUADSPI_BFGENCR_SEQID_SHIFT, + q->iobase + QUADSPI_BFGENCR); ++ ++ /* enable the DDR quad read */ ++ if (q->nor->flash_read == SPI_NOR_DDR_QUAD) ++ set_ddr_quad_mode(q); ++ + } + + /* This function was used to prepare and enable QSPI clock */ +@@ -822,6 +1023,7 @@ static const struct of_device_id fsl_qspi_dt_ids[] = { + { .compatible = "fsl,imx7d-qspi", .data = (void *)&imx7d_data, }, + { .compatible = "fsl,imx6ul-qspi", .data = (void *)&imx6ul_data, }, + { .compatible = "fsl,ls1021a-qspi", .data = (void *)&ls1021a_data, }, ++ { .compatible = "fsl,ls2080a-qspi", .data = (void *)&ls2080a_data, }, + { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids); +@@ -835,8 +1037,12 @@ static int fsl_qspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) + { + int ret; + struct fsl_qspi *q = nor->priv; ++ u32 to = 0; ++ ++ if (opcode == SPINOR_OP_SPANSION_RDAR) ++ u8tou32(&to, nor->cmd_buf, 4); + +- ret = fsl_qspi_runcmd(q, opcode, 0, len); ++ ret = fsl_qspi_runcmd(q, opcode, to, len); + if (ret) + return ret; + +@@ -848,9 +1054,13 @@ static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) + { + struct fsl_qspi *q = nor->priv; + int ret; ++ u32 to = 0; ++ ++ if (opcode == SPINOR_OP_SPANSION_WRAR) ++ u8tou32(&to, nor->cmd_buf, 4); + + if (!buf) { +- ret = fsl_qspi_runcmd(q, opcode, 0, 1); ++ ret = fsl_qspi_runcmd(q, opcode, to, 1); + if (ret) + return ret; + +@@ -859,7 +1069,7 @@ static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) + + } else if (len > 0) { + ret = fsl_qspi_nor_write(q, nor, opcode, 0, +- (u32 *)buf, len); ++ buf, len); + if (ret > 0) + return 0; + } else { +@@ -875,7 +1085,7 @@ static ssize_t fsl_qspi_write(struct spi_nor *nor, loff_t to, + { + struct fsl_qspi *q = nor->priv; + ssize_t ret = fsl_qspi_nor_write(q, nor, nor->program_opcode, to, +- (u32 *)buf, len); ++ (u8 *)buf, len); + + /* invalid the data in the AHB buffer. */ + fsl_qspi_invalid(q); +@@ -922,7 +1132,7 @@ static ssize_t fsl_qspi_read(struct spi_nor *nor, loff_t from, + len); + + /* Read out the data directly from the AHB buffer.*/ +- memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs, ++ memcpy_toio(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs, + len); + + return len; +@@ -980,6 +1190,8 @@ static int fsl_qspi_probe(struct platform_device *pdev) + struct spi_nor *nor; + struct mtd_info *mtd; + int ret, i = 0; ++ int find_node; ++ enum read_mode mode = SPI_NOR_QUAD; + + q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL); + if (!q) +@@ -1027,6 +1239,12 @@ static int fsl_qspi_probe(struct platform_device *pdev) + goto clk_failed; + } + ++ /* find ddrsmp value */ ++ ret = of_property_read_u32(dev->of_node, "fsl,ddr-sampling-point", ++ &q->ddr_smp); ++ if (ret) ++ q->ddr_smp = 0; ++ + /* find the irq */ + ret = platform_get_irq(pdev, 0); + if (ret < 0) { +@@ -1050,6 +1268,7 @@ static int fsl_qspi_probe(struct platform_device *pdev) + + mutex_init(&q->lock); + ++ find_node = 0; + /* iterate the subnodes. */ + for_each_available_child_of_node(dev->of_node, np) { + /* skip the holes */ +@@ -1076,18 +1295,25 @@ static int fsl_qspi_probe(struct platform_device *pdev) + ret = of_property_read_u32(np, "spi-max-frequency", + &q->clk_rate); + if (ret < 0) +- goto mutex_failed; ++ continue; + + /* set the chip address for READID */ + fsl_qspi_set_base_addr(q, nor); + +- ret = spi_nor_scan(nor, NULL, SPI_NOR_QUAD); ++ ret = of_property_read_bool(np, "m25p,fast-read"); ++ mode = (ret) ? SPI_NOR_FAST : SPI_NOR_QUAD; ++ /* Can we enable the DDR Quad Read? */ ++ ret = of_property_read_bool(np, "ddr-quad-read"); + if (ret) +- goto mutex_failed; ++ mode = SPI_NOR_DDR_QUAD; ++ ++ ret = spi_nor_scan(nor, NULL, mode); ++ if (ret) ++ continue; + + ret = mtd_device_register(mtd, NULL, 0); + if (ret) +- goto mutex_failed; ++ continue; + + /* Set the correct NOR size now. */ + if (q->nor_size == 0) { +@@ -1110,8 +1336,12 @@ static int fsl_qspi_probe(struct platform_device *pdev) + nor->page_size = q->devtype_data->txfifo; + + i++; ++ find_node++; + } + ++ if (find_node == 0) ++ goto mutex_failed; ++ + /* finish the rest init. */ + ret = fsl_qspi_nor_setup_last(q); + if (ret) +diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c +index 793d321d..190e0e45 100644 +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -40,6 +40,13 @@ + #define SPI_NOR_MAX_ID_LEN 6 + #define SPI_NOR_MAX_ADDR_WIDTH 4 + ++#define SPI_NOR_MICRON_WRITE_ENABLE 0x7f ++/* Added for S25FS-S family flash */ ++#define SPINOR_CONFIG_REG3_OFFSET 0x800004 ++#define CR3V_4KB_ERASE_UNABLE 0x8 ++#define SPINOR_S25FS_FAMILY_ID 0x81 ++ ++ + struct flash_info { + char *name; + +@@ -68,7 +75,8 @@ struct flash_info { + #define SECT_4K_PMC BIT(4) /* SPINOR_OP_BE_4K_PMC works uniformly */ + #define SPI_NOR_DUAL_READ BIT(5) /* Flash supports Dual Read */ + #define SPI_NOR_QUAD_READ BIT(6) /* Flash supports Quad Read */ +-#define USE_FSR BIT(7) /* use flag status register */ ++#define USE_FSR BIT(13) /* use flag status register */ ++#define SPI_NOR_DDR_QUAD_READ BIT(7) /* Flash supports DDR Quad Read */ + #define SPI_NOR_HAS_LOCK BIT(8) /* Flash supports lock/unlock via SR */ + #define SPI_NOR_HAS_TB BIT(9) /* + * Flash SR has Top/Bottom (TB) protect +@@ -85,9 +93,11 @@ struct flash_info { + * Use dedicated 4byte address op codes + * to support memory size above 128Mib. + */ ++#define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */ + }; + + #define JEDEC_MFR(info) ((info)->id[0]) ++#define EXT_ID(info) ((info)->id[5]) + + static const struct flash_info *spi_nor_match_id(const char *name); + +@@ -132,7 +142,7 @@ static int read_fsr(struct spi_nor *nor) + /* + * Read configuration register, returning its value in the + * location. Return the configuration register value. +- * Returns negative if error occured. ++ * Returns negative if error occurred. + */ + static int read_cr(struct spi_nor *nor) + { +@@ -160,6 +170,8 @@ static inline int spi_nor_read_dummy_cycles(struct spi_nor *nor) + case SPI_NOR_DUAL: + case SPI_NOR_QUAD: + return 8; ++ case SPI_NOR_DDR_QUAD: ++ return 6; + case SPI_NOR_NORMAL: + return 0; + } +@@ -961,6 +973,8 @@ static const struct flash_info spi_nor_ids[] = { + + /* ESMT */ + { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_LOCK) }, ++ { "f25l32qa", INFO(0x8c4116, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_LOCK) }, ++ { "f25l64qa", INFO(0x8c4117, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_LOCK) }, + + /* Everspin */ + { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, +@@ -1014,12 +1028,15 @@ static const struct flash_info spi_nor_ids[] = { + { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) }, + { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, + { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) }, ++ { "mx25u2033e", INFO(0xc22532, 0, 64 * 1024, 4, SECT_4K) }, ++ { "mx25u4035", INFO(0xc22533, 0, 64 * 1024, 8, SECT_4K) }, ++ { "mx25u8035", INFO(0xc22534, 0, 64 * 1024, 16, SECT_4K) }, + { "mx25u3235f", INFO(0xc22536, 0, 64 * 1024, 64, 0) }, + { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) }, + { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, + { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, + { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, +- { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) }, ++ { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K) }, + { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, + { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) }, + { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, +@@ -1033,10 +1050,11 @@ static const struct flash_info spi_nor_ids[] = { + { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, + { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, + { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) }, ++ { "n25q256ax1", INFO(0x20bb19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) }, + { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, + { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, +- { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, +- { "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, ++ { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, ++ { "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, + + /* PMC */ + { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) }, +@@ -1054,8 +1072,11 @@ static const struct flash_info spi_nor_ids[] = { + { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, + { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, + { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, +- { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, ++ { "s25fs256s1", INFO6(0x010219, 0x4d0181, 64 * 1024, 512, 0)}, ++ { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_QUAD_READ ++ | SPI_NOR_DDR_QUAD_READ) }, + { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, ++ { "s25fs512s", INFO6(0x010220, 0x4d0081, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)}, + { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) }, + { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) }, +@@ -1130,6 +1151,9 @@ static const struct flash_info spi_nor_ids[] = { + { "w25x80", INFO(0xef3014, 0, 64 * 1024, 16, SECT_4K) }, + { "w25x16", INFO(0xef3015, 0, 64 * 1024, 32, SECT_4K) }, + { "w25x32", INFO(0xef3016, 0, 64 * 1024, 64, SECT_4K) }, ++ { "w25q20cl", INFO(0xef4012, 0, 64 * 1024, 4, SECT_4K) }, ++ { "w25q20bw", INFO(0xef5012, 0, 64 * 1024, 4, SECT_4K) }, ++ { "w25q20ew", INFO(0xef6012, 0, 64 * 1024, 4, SECT_4K) }, + { "w25q32", INFO(0xef4016, 0, 64 * 1024, 64, SECT_4K) }, + { + "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, +@@ -1192,6 +1216,53 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) + id[0], id[1], id[2]); + return ERR_PTR(-ENODEV); + } ++/* ++ * The S25FS-S family physical sectors may be configured as a ++ * hybrid combination of eight 4-kB parameter sectors ++ * at the top or bottom of the address space with all ++ * but one of the remaining sectors being uniform size. ++ * The Parameter Sector Erase commands (20h or 21h) must ++ * be used to erase the 4-kB parameter sectors individually. ++ * The Sector (uniform sector) Erase commands (D8h or DCh) ++ * must be used to erase any of the remaining ++ * sectors, including the portion of highest or lowest address ++ * sector that is not overlaid by the parameter sectors. ++ * The uniform sector erase command has no effect on parameter sectors. ++ */ ++static int spansion_s25fs_disable_4kb_erase(struct spi_nor *nor) ++{ ++ struct fsl_qspi *q; ++ u32 cr3v_addr = SPINOR_CONFIG_REG3_OFFSET; ++ u8 cr3v = 0x0; ++ int ret = 0x0; ++ ++ q = nor->priv; ++ ++ nor->cmd_buf[2] = cr3v_addr >> 16; ++ nor->cmd_buf[1] = cr3v_addr >> 8; ++ nor->cmd_buf[0] = cr3v_addr >> 0; ++ ++ ret = nor->read_reg(nor, SPINOR_OP_SPANSION_RDAR, &cr3v, 1); ++ if (ret) ++ return ret; ++ if (cr3v & CR3V_4KB_ERASE_UNABLE) ++ return 0; ++ ret = nor->write_reg(nor, SPINOR_OP_WREN, NULL, 0); ++ if (ret) ++ return ret; ++ cr3v = CR3V_4KB_ERASE_UNABLE; ++ nor->program_opcode = SPINOR_OP_SPANSION_WRAR; ++ nor->write(nor, cr3v_addr, 1, &cr3v); ++ ++ ret = nor->read_reg(nor, SPINOR_OP_SPANSION_RDAR, &cr3v, 1); ++ if (ret) ++ return ret; ++ if (!(cr3v & CR3V_4KB_ERASE_UNABLE)) ++ return -EPERM; ++ ++ return 0; ++} ++ + + static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +@@ -1411,7 +1482,7 @@ static int macronix_quad_enable(struct spi_nor *nor) + * Write status Register and configuration register with 2 bytes + * The first byte will be written to the status register, while the + * second byte will be written to the configuration register. +- * Return negative if error occured. ++ * Return negative if error occurred. + */ + static int write_sr_cr(struct spi_nor *nor, u16 val) + { +@@ -1459,6 +1530,24 @@ static int spansion_quad_enable(struct spi_nor *nor) + return 0; + } + ++static int set_ddr_quad_mode(struct spi_nor *nor, const struct flash_info *info) ++{ ++ int status; ++ ++ switch (JEDEC_MFR(info)) { ++ case SNOR_MFR_SPANSION: ++ status = spansion_quad_enable(nor); ++ if (status) { ++ dev_err(nor->dev, "Spansion DDR quad-read not enabled\n"); ++ return status; ++ } ++ return status; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ + static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info) + { + int status; +@@ -1604,9 +1693,25 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) + write_sr(nor, 0); + spi_nor_wait_till_ready(nor); + } ++ if (JEDEC_MFR(info) == SNOR_MFR_MICRON) { ++ ret = read_sr(nor); ++ ret &= SPI_NOR_MICRON_WRITE_ENABLE; ++ ++ write_enable(nor); ++ write_sr(nor, ret); ++ } ++ ++ if (EXT_ID(info) == SPINOR_S25FS_FAMILY_ID) { ++ ret = spansion_s25fs_disable_4kb_erase(nor); ++ if (ret) ++ return ret; ++ } ++ + + if (!mtd->name) + mtd->name = dev_name(dev); ++ if (info->name) ++ nor->vendor = info->name; + mtd->priv = nor; + mtd->type = MTD_NORFLASH; + mtd->writesize = 1; +@@ -1639,6 +1744,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) + nor->flags |= SNOR_F_USE_FSR; + if (info->flags & SPI_NOR_HAS_TB) + nor->flags |= SNOR_F_HAS_SR_TB; ++ if (info->flags & NO_CHIP_ERASE) ++ nor->flags |= SNOR_F_NO_OP_CHIP_ERASE; + + #ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS + /* prefer "small sector" erase if possible */ +@@ -1676,9 +1783,15 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) + /* Some devices cannot do fast-read, no matter what DT tells us */ + if (info->flags & SPI_NOR_NO_FR) + nor->flash_read = SPI_NOR_NORMAL; +- +- /* Quad/Dual-read mode takes precedence over fast/normal */ +- if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) { ++ /* DDR Quad/Quad/Dual-read mode takes precedence over fast/normal */ ++ if (mode == SPI_NOR_DDR_QUAD && info->flags & SPI_NOR_DDR_QUAD_READ) { ++ ret = set_ddr_quad_mode(nor, info); ++ if (ret) { ++ dev_err(dev, "DDR quad mode not supported\n"); ++ return ret; ++ } ++ nor->flash_read = SPI_NOR_DDR_QUAD; ++ } else if (mode == SPI_NOR_QUAD && info->flags & SPI_NOR_QUAD_READ) { + ret = set_quad_mode(nor, info); + if (ret) { + dev_err(dev, "quad mode not supported\n"); +@@ -1691,6 +1804,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) + + /* Default commands */ + switch (nor->flash_read) { ++ case SPI_NOR_DDR_QUAD: ++ nor->read_opcode = SPINOR_OP_READ4_1_4_4_D; ++ break; + case SPI_NOR_QUAD: + nor->read_opcode = SPINOR_OP_READ_1_1_4; + break; +diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h +index f2a71803..5003ff64 100644 +--- a/include/linux/mtd/spi-nor.h ++++ b/include/linux/mtd/spi-nor.h +@@ -31,10 +31,10 @@ + + /* + * Note on opcode nomenclature: some opcodes have a format like +- * SPINOR_OP_FUNCTION{4,}_x_y_z. The numbers x, y, and z stand for the number ++ * SPINOR_OP_FUNCTION{4,}_x_y_z{_D}. The numbers x, y,and z stand for the number + * of I/O lines used for the opcode, address, and data (respectively). The + * FUNCTION has an optional suffix of '4', to represent an opcode which +- * requires a 4-byte (32-bit) address. ++ * requires a 4-byte (32-bit) address. The suffix of 'D' stands for the + */ + + /* Flash opcodes. */ +@@ -46,7 +46,9 @@ + #define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual Output SPI) */ + #define SPINOR_OP_READ_1_2_2 0xbb /* Read data bytes (Dual I/O SPI) */ + #define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad Output SPI) */ ++#define SPINOR_OP_READ_1_4_4_D 0xed /* Read data bytes (DDR Quad SPI) */ + #define SPINOR_OP_READ_1_4_4 0xeb /* Read data bytes (Quad I/O SPI) */ ++#define SPINOR_OP_READ4_1_4_4_D 0xee /* Read data bytes (DDR Quad SPI) */ + #define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */ + #define SPINOR_OP_PP_1_1_4 0x32 /* Quad page program */ + #define SPINOR_OP_PP_1_4_4 0x38 /* Quad page program */ +@@ -62,9 +64,11 @@ + /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ + #define SPINOR_OP_READ_4B 0x13 /* Read data bytes (low frequency) */ + #define SPINOR_OP_READ_FAST_4B 0x0c /* Read data bytes (high frequency) */ ++#define SPINOR_OP_READ4_FAST 0x0c /* Read data bytes (high frequency) */ + #define SPINOR_OP_READ_1_1_2_4B 0x3c /* Read data bytes (Dual Output SPI) */ + #define SPINOR_OP_READ_1_2_2_4B 0xbc /* Read data bytes (Dual I/O SPI) */ + #define SPINOR_OP_READ_1_1_4_4B 0x6c /* Read data bytes (Quad Output SPI) */ ++#define SPINOR_OP_READ4_1_1_4 0x6c /* Read data bytes (Quad SPI) */ + #define SPINOR_OP_READ_1_4_4_4B 0xec /* Read data bytes (Quad I/O SPI) */ + #define SPINOR_OP_PP_4B 0x12 /* Page program (up to 256 bytes) */ + #define SPINOR_OP_PP_1_1_4_4B 0x34 /* Quad page program */ +@@ -94,6 +98,10 @@ + /* Used for Spansion flashes only. */ + #define SPINOR_OP_BRWR 0x17 /* Bank register write */ + ++/* Used for Spansion S25FS-S family flash only. */ ++#define SPINOR_OP_SPANSION_RDAR 0x65 /* Read any device register */ ++#define SPINOR_OP_SPANSION_WRAR 0x71 /* Write any device register */ ++ + /* Used for Micron flashes only. */ + #define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */ + #define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */ +@@ -124,6 +132,7 @@ enum read_mode { + SPI_NOR_FAST, + SPI_NOR_DUAL, + SPI_NOR_QUAD, ++ SPI_NOR_DDR_QUAD, + }; + + #define SPI_NOR_MAX_CMD_SIZE 8 +@@ -189,6 +198,7 @@ struct spi_nor { + bool sst_write_second; + u32 flags; + u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE]; ++ char *vendor; + + int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops); + void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops); +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/402-mtd-support-layerscape.patch b/target/linux/layerscape/patches-4.9/402-mtd-support-layerscape.patch new file mode 100644 index 0000000000..e45d2635fd --- /dev/null +++ b/target/linux/layerscape/patches-4.9/402-mtd-support-layerscape.patch @@ -0,0 +1,412 @@ +From c0e4767d3b26f21e5043fe2d15a24a1958de766e Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 10:17:28 +0800 +Subject: [PATCH] mtd: support layerscape + +This is a integrated patch for layerscape ifc-nor-nand support. + +Signed-off-by: Alison Wang +Signed-off-by: Prabhakar Kushwaha +Signed-off-by: Yangbo Lu +--- + drivers/memory/Kconfig | 2 +- + drivers/memory/fsl_ifc.c | 263 ++++++++++++++++++++++++++++++++++++++++ + drivers/mtd/maps/physmap_of.c | 4 + + drivers/mtd/nand/Kconfig | 2 +- + drivers/mtd/nand/fsl_ifc_nand.c | 5 +- + include/linux/fsl_ifc.h | 7 ++ + 6 files changed, 280 insertions(+), 3 deletions(-) + +diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig +index 4b4c0c3c..820f5590 100644 +--- a/drivers/memory/Kconfig ++++ b/drivers/memory/Kconfig +@@ -115,7 +115,7 @@ config FSL_CORENET_CF + + config FSL_IFC + bool +- depends on FSL_SOC || ARCH_LAYERSCAPE ++ depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A + + config JZ4780_NEMC + bool "Ingenic JZ4780 SoC NEMC driver" +diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c +index 1b182b11..10d2a5f8 100644 +--- a/drivers/memory/fsl_ifc.c ++++ b/drivers/memory/fsl_ifc.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -37,6 +38,8 @@ + + struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev; + EXPORT_SYMBOL(fsl_ifc_ctrl_dev); ++#define FSL_IFC_V1_3_0 0x01030000 ++#define IFC_TIMEOUT_MSECS 1000 /* 1000ms */ + + /* + * convert_ifc_address - convert the base address +@@ -311,6 +314,261 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev) + return ret; + } + ++#ifdef CONFIG_PM_SLEEP ++/* save ifc registers */ ++static int fsl_ifc_suspend(struct device *dev) ++{ ++ struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(dev); ++ struct fsl_ifc_global __iomem *fcm = ctrl->gregs; ++ struct fsl_ifc_runtime __iomem *runtime = ctrl->rregs; ++ __be32 nand_evter_intr_en, cm_evter_intr_en, nor_evter_intr_en, ++ gpcm_evter_intr_en; ++ uint32_t ifc_bank, i; ++ ++ ctrl->saved_gregs = kzalloc(sizeof(struct fsl_ifc_global), GFP_KERNEL); ++ if (!ctrl->saved_gregs) ++ return -ENOMEM; ++ ctrl->saved_rregs = kzalloc(sizeof(struct fsl_ifc_runtime), GFP_KERNEL); ++ if (!ctrl->saved_rregs) ++ return -ENOMEM; ++ ++ cm_evter_intr_en = ifc_in32(&fcm->cm_evter_intr_en); ++ nand_evter_intr_en = ifc_in32(&runtime->ifc_nand.nand_evter_intr_en); ++ nor_evter_intr_en = ifc_in32(&runtime->ifc_nor.nor_evter_intr_en); ++ gpcm_evter_intr_en = ifc_in32(&runtime->ifc_gpcm.gpcm_evter_intr_en); ++ ++/* IFC interrupts disabled */ ++ ++ ifc_out32(0x0, &fcm->cm_evter_intr_en); ++ ifc_out32(0x0, &runtime->ifc_nand.nand_evter_intr_en); ++ ifc_out32(0x0, &runtime->ifc_nor.nor_evter_intr_en); ++ ifc_out32(0x0, &runtime->ifc_gpcm.gpcm_evter_intr_en); ++ ++ if (ctrl->saved_gregs) { ++ for (ifc_bank = 0; ifc_bank < FSL_IFC_BANK_COUNT; ifc_bank++) { ++ ctrl->saved_gregs->cspr_cs[ifc_bank].cspr_ext = ++ ifc_in32(&fcm->cspr_cs[ifc_bank].cspr_ext); ++ ctrl->saved_gregs->cspr_cs[ifc_bank].cspr = ++ ifc_in32(&fcm->cspr_cs[ifc_bank].cspr); ++ ctrl->saved_gregs->amask_cs[ifc_bank].amask = ++ ifc_in32(&fcm->amask_cs[ifc_bank].amask); ++ ctrl->saved_gregs->csor_cs[ifc_bank].csor_ext = ++ ifc_in32(&fcm->csor_cs[ifc_bank].csor_ext); ++ ctrl->saved_gregs->csor_cs[ifc_bank].csor = ++ ifc_in32(&fcm->csor_cs[ifc_bank].csor); ++ for (i = 0; i < 4; i++) { ++ ctrl->saved_gregs->ftim_cs[ifc_bank].ftim[i] = ++ ifc_in32( ++ &fcm->ftim_cs[ifc_bank].ftim[i]); ++ } ++ } ++ ++ ctrl->saved_gregs->rb_map = ifc_in32(&fcm->rb_map); ++ ctrl->saved_gregs->wb_map = ifc_in32(&fcm->wb_map); ++ ctrl->saved_gregs->ifc_gcr = ifc_in32(&fcm->ifc_gcr); ++ ctrl->saved_gregs->ddr_ccr_low = ifc_in32(&fcm->ddr_ccr_low); ++ ctrl->saved_gregs->cm_evter_en = ifc_in32(&fcm->cm_evter_en); ++ } ++ ++ if (ctrl->saved_rregs) { ++ /* IFC controller NAND machine registers */ ++ ctrl->saved_rregs->ifc_nand.ncfgr = ++ ifc_in32(&runtime->ifc_nand.ncfgr); ++ ctrl->saved_rregs->ifc_nand.nand_fcr0 = ++ ifc_in32(&runtime->ifc_nand.nand_fcr0); ++ ctrl->saved_rregs->ifc_nand.nand_fcr1 = ++ ifc_in32(&runtime->ifc_nand.nand_fcr1); ++ ctrl->saved_rregs->ifc_nand.row0 = ++ ifc_in32(&runtime->ifc_nand.row0); ++ ctrl->saved_rregs->ifc_nand.row1 = ++ ifc_in32(&runtime->ifc_nand.row1); ++ ctrl->saved_rregs->ifc_nand.col0 = ++ ifc_in32(&runtime->ifc_nand.col0); ++ ctrl->saved_rregs->ifc_nand.col1 = ++ ifc_in32(&runtime->ifc_nand.col1); ++ ctrl->saved_rregs->ifc_nand.row2 = ++ ifc_in32(&runtime->ifc_nand.row2); ++ ctrl->saved_rregs->ifc_nand.col2 = ++ ifc_in32(&runtime->ifc_nand.col2); ++ ctrl->saved_rregs->ifc_nand.row3 = ++ ifc_in32(&runtime->ifc_nand.row3); ++ ctrl->saved_rregs->ifc_nand.col3 = ++ ifc_in32(&runtime->ifc_nand.col3); ++ ++ ctrl->saved_rregs->ifc_nand.nand_fbcr = ++ ifc_in32(&runtime->ifc_nand.nand_fbcr); ++ ctrl->saved_rregs->ifc_nand.nand_fir0 = ++ ifc_in32(&runtime->ifc_nand.nand_fir0); ++ ctrl->saved_rregs->ifc_nand.nand_fir1 = ++ ifc_in32(&runtime->ifc_nand.nand_fir1); ++ ctrl->saved_rregs->ifc_nand.nand_fir2 = ++ ifc_in32(&runtime->ifc_nand.nand_fir2); ++ ctrl->saved_rregs->ifc_nand.nand_csel = ++ ifc_in32(&runtime->ifc_nand.nand_csel); ++ ctrl->saved_rregs->ifc_nand.nandseq_strt = ++ ifc_in32( ++ &runtime->ifc_nand.nandseq_strt); ++ ctrl->saved_rregs->ifc_nand.nand_evter_en = ++ ifc_in32( ++ &runtime->ifc_nand.nand_evter_en); ++ ctrl->saved_rregs->ifc_nand.nanndcr = ++ ifc_in32(&runtime->ifc_nand.nanndcr); ++ ctrl->saved_rregs->ifc_nand.nand_dll_lowcfg0 = ++ ifc_in32( ++ &runtime->ifc_nand.nand_dll_lowcfg0); ++ ctrl->saved_rregs->ifc_nand.nand_dll_lowcfg1 = ++ ifc_in32( ++ &runtime->ifc_nand.nand_dll_lowcfg1); ++ ++ /* IFC controller NOR machine registers */ ++ ctrl->saved_rregs->ifc_nor.nor_evter_en = ++ ifc_in32( ++ &runtime->ifc_nor.nor_evter_en); ++ ctrl->saved_rregs->ifc_nor.norcr = ++ ifc_in32(&runtime->ifc_nor.norcr); ++ ++ /* IFC controller GPCM Machine registers */ ++ ctrl->saved_rregs->ifc_gpcm.gpcm_evter_en = ++ ifc_in32( ++ &runtime->ifc_gpcm.gpcm_evter_en); ++ } ++ ++/* save the interrupt values */ ++ ctrl->saved_gregs->cm_evter_intr_en = cm_evter_intr_en; ++ ctrl->saved_rregs->ifc_nand.nand_evter_intr_en = nand_evter_intr_en; ++ ctrl->saved_rregs->ifc_nor.nor_evter_intr_en = nor_evter_intr_en; ++ ctrl->saved_rregs->ifc_gpcm.gpcm_evter_intr_en = gpcm_evter_intr_en; ++ ++ return 0; ++} ++ ++/* restore ifc registers */ ++static int fsl_ifc_resume(struct device *dev) ++{ ++ struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(dev); ++ struct fsl_ifc_global __iomem *fcm = ctrl->gregs; ++ struct fsl_ifc_runtime __iomem *runtime = ctrl->rregs; ++ struct fsl_ifc_global *savd_gregs = ctrl->saved_gregs; ++ struct fsl_ifc_runtime *savd_rregs = ctrl->saved_rregs; ++ uint32_t ver = 0, ncfgr, timeout, ifc_bank, i; ++ ++/* ++ * IFC interrupts disabled ++ */ ++ ifc_out32(0x0, &fcm->cm_evter_intr_en); ++ ifc_out32(0x0, &runtime->ifc_nand.nand_evter_intr_en); ++ ifc_out32(0x0, &runtime->ifc_nor.nor_evter_intr_en); ++ ifc_out32(0x0, &runtime->ifc_gpcm.gpcm_evter_intr_en); ++ ++ ++ if (ctrl->saved_gregs) { ++ for (ifc_bank = 0; ifc_bank < FSL_IFC_BANK_COUNT; ifc_bank++) { ++ ifc_out32(savd_gregs->cspr_cs[ifc_bank].cspr_ext, ++ &fcm->cspr_cs[ifc_bank].cspr_ext); ++ ifc_out32(savd_gregs->cspr_cs[ifc_bank].cspr, ++ &fcm->cspr_cs[ifc_bank].cspr); ++ ifc_out32(savd_gregs->amask_cs[ifc_bank].amask, ++ &fcm->amask_cs[ifc_bank].amask); ++ ifc_out32(savd_gregs->csor_cs[ifc_bank].csor_ext, ++ &fcm->csor_cs[ifc_bank].csor_ext); ++ ifc_out32(savd_gregs->csor_cs[ifc_bank].csor, ++ &fcm->csor_cs[ifc_bank].csor); ++ for (i = 0; i < 4; i++) { ++ ifc_out32(savd_gregs->ftim_cs[ifc_bank].ftim[i], ++ &fcm->ftim_cs[ifc_bank].ftim[i]); ++ } ++ } ++ ifc_out32(savd_gregs->rb_map, &fcm->rb_map); ++ ifc_out32(savd_gregs->wb_map, &fcm->wb_map); ++ ifc_out32(savd_gregs->ifc_gcr, &fcm->ifc_gcr); ++ ifc_out32(savd_gregs->ddr_ccr_low, &fcm->ddr_ccr_low); ++ ifc_out32(savd_gregs->cm_evter_en, &fcm->cm_evter_en); ++ } ++ ++ if (ctrl->saved_rregs) { ++ /* IFC controller NAND machine registers */ ++ ifc_out32(savd_rregs->ifc_nand.ncfgr, ++ &runtime->ifc_nand.ncfgr); ++ ifc_out32(savd_rregs->ifc_nand.nand_fcr0, ++ &runtime->ifc_nand.nand_fcr0); ++ ifc_out32(savd_rregs->ifc_nand.nand_fcr1, ++ &runtime->ifc_nand.nand_fcr1); ++ ifc_out32(savd_rregs->ifc_nand.row0, &runtime->ifc_nand.row0); ++ ifc_out32(savd_rregs->ifc_nand.row1, &runtime->ifc_nand.row1); ++ ifc_out32(savd_rregs->ifc_nand.col0, &runtime->ifc_nand.col0); ++ ifc_out32(savd_rregs->ifc_nand.col1, &runtime->ifc_nand.col1); ++ ifc_out32(savd_rregs->ifc_nand.row2, &runtime->ifc_nand.row2); ++ ifc_out32(savd_rregs->ifc_nand.col2, &runtime->ifc_nand.col2); ++ ifc_out32(savd_rregs->ifc_nand.row3, &runtime->ifc_nand.row3); ++ ifc_out32(savd_rregs->ifc_nand.col3, &runtime->ifc_nand.col3); ++ ifc_out32(savd_rregs->ifc_nand.nand_fbcr, ++ &runtime->ifc_nand.nand_fbcr); ++ ifc_out32(savd_rregs->ifc_nand.nand_fir0, ++ &runtime->ifc_nand.nand_fir0); ++ ifc_out32(savd_rregs->ifc_nand.nand_fir1, ++ &runtime->ifc_nand.nand_fir1); ++ ifc_out32(savd_rregs->ifc_nand.nand_fir2, ++ &runtime->ifc_nand.nand_fir2); ++ ifc_out32(savd_rregs->ifc_nand.nand_csel, ++ &runtime->ifc_nand.nand_csel); ++ ifc_out32(savd_rregs->ifc_nand.nandseq_strt, ++ &runtime->ifc_nand.nandseq_strt); ++ ifc_out32(savd_rregs->ifc_nand.nand_evter_en, ++ &runtime->ifc_nand.nand_evter_en); ++ ifc_out32(savd_rregs->ifc_nand.nanndcr, ++ &runtime->ifc_nand.nanndcr); ++ ifc_out32(savd_rregs->ifc_nand.nand_dll_lowcfg0, ++ &runtime->ifc_nand.nand_dll_lowcfg0); ++ ifc_out32(savd_rregs->ifc_nand.nand_dll_lowcfg1, ++ &runtime->ifc_nand.nand_dll_lowcfg1); ++ ++ /* IFC controller NOR machine registers */ ++ ifc_out32(savd_rregs->ifc_nor.nor_evter_en, ++ &runtime->ifc_nor.nor_evter_en); ++ ifc_out32(savd_rregs->ifc_nor.norcr, &runtime->ifc_nor.norcr); ++ ++ /* IFC controller GPCM Machine registers */ ++ ifc_out32(savd_rregs->ifc_gpcm.gpcm_evter_en, ++ &runtime->ifc_gpcm.gpcm_evter_en); ++ ++ /* IFC interrupts enabled */ ++ ifc_out32(ctrl->saved_gregs->cm_evter_intr_en, ++ &fcm->cm_evter_intr_en); ++ ifc_out32(ctrl->saved_rregs->ifc_nand.nand_evter_intr_en, ++ &runtime->ifc_nand.nand_evter_intr_en); ++ ifc_out32(ctrl->saved_rregs->ifc_nor.nor_evter_intr_en, ++ &runtime->ifc_nor.nor_evter_intr_en); ++ ifc_out32(ctrl->saved_rregs->ifc_gpcm.gpcm_evter_intr_en, ++ &runtime->ifc_gpcm.gpcm_evter_intr_en); ++ ++ kfree(ctrl->saved_gregs); ++ kfree(ctrl->saved_rregs); ++ ctrl->saved_gregs = NULL; ++ ctrl->saved_rregs = NULL; ++ } ++ ++ ver = ifc_in32(&fcm->ifc_rev); ++ ncfgr = ifc_in32(&runtime->ifc_nand.ncfgr); ++ if (ver >= FSL_IFC_V1_3_0) { ++ ++ ifc_out32(ncfgr | IFC_NAND_SRAM_INIT_EN, ++ &runtime->ifc_nand.ncfgr); ++ /* wait for SRAM_INIT bit to be clear or timeout */ ++ timeout = 10; ++ while ((ifc_in32(&runtime->ifc_nand.ncfgr) & ++ IFC_NAND_SRAM_INIT_EN) && timeout) { ++ mdelay(IFC_TIMEOUT_MSECS); ++ timeout--; ++ } ++ ++ if (!timeout) ++ dev_err(ctrl->dev, "Timeout waiting for IFC SRAM INIT"); ++ } ++ ++ return 0; ++} ++#endif /* CONFIG_PM_SLEEP */ ++ + static const struct of_device_id fsl_ifc_match[] = { + { + .compatible = "fsl,ifc", +@@ -318,10 +576,15 @@ static const struct of_device_id fsl_ifc_match[] = { + {}, + }; + ++static const struct dev_pm_ops ifc_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(fsl_ifc_suspend, fsl_ifc_resume) ++}; ++ + static struct platform_driver fsl_ifc_ctrl_driver = { + .driver = { + .name = "fsl-ifc", + .of_match_table = fsl_ifc_match, ++ .pm = &ifc_pm_ops, + }, + .probe = fsl_ifc_ctrl_probe, + .remove = fsl_ifc_ctrl_remove, +diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c +index 11d63046..38b90301 100644 +--- a/drivers/mtd/maps/physmap_of.c ++++ b/drivers/mtd/maps/physmap_of.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -209,6 +210,9 @@ static int of_flash_probe(struct platform_device *dev) + return err; + } + ++ if (of_property_read_bool(dp->parent, "big-endian")) ++ info->list[i].map.swap = CFI_BIG_ENDIAN; ++ + err = -ENOMEM; + info->list[i].map.virt = ioremap(info->list[i].map.phys, + info->list[i].map.size); +diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig +index b254090b..961f1aa1 100644 +--- a/drivers/mtd/nand/Kconfig ++++ b/drivers/mtd/nand/Kconfig +@@ -438,7 +438,7 @@ config MTD_NAND_FSL_ELBC + + config MTD_NAND_FSL_IFC + tristate "NAND support for Freescale IFC controller" +- depends on FSL_SOC || ARCH_LAYERSCAPE ++ depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A + select FSL_IFC + select MEMORY + help +diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c +index d1570f51..785e9ee0 100644 +--- a/drivers/mtd/nand/fsl_ifc_nand.c ++++ b/drivers/mtd/nand/fsl_ifc_nand.c +@@ -904,9 +904,12 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) + chip->ecc.algo = NAND_ECC_HAMMING; + } + +- if (ctrl->version == FSL_IFC_VERSION_1_1_0) ++ if (ctrl->version >= FSL_IFC_VERSION_1_1_0) + fsl_ifc_sram_init(priv); + ++ if (ctrl->version >= FSL_IFC_VERSION_2_0_0) ++ priv->bufnum_mask = (priv->bufnum_mask * 2) + 1; ++ + return 0; + } + +diff --git a/include/linux/fsl_ifc.h b/include/linux/fsl_ifc.h +index c332f0a4..a41d21b6 100644 +--- a/include/linux/fsl_ifc.h ++++ b/include/linux/fsl_ifc.h +@@ -274,6 +274,8 @@ + */ + /* Auto Boot Mode */ + #define IFC_NAND_NCFGR_BOOT 0x80000000 ++/* SRAM INIT EN */ ++#define IFC_NAND_SRAM_INIT_EN 0x20000000 + /* Addressing Mode-ROW0+n/COL0 */ + #define IFC_NAND_NCFGR_ADDR_MODE_RC0 0x00000000 + /* Addressing Mode-ROW0+n/COL0+n */ +@@ -861,6 +863,11 @@ struct fsl_ifc_ctrl { + u32 nand_stat; + wait_queue_head_t nand_wait; + bool little_endian; ++#ifdef CONFIG_PM_SLEEP ++ /*save regs when system goes to deep sleep*/ ++ struct fsl_ifc_global *saved_gregs; ++ struct fsl_ifc_runtime *saved_rregs; ++#endif + }; + + extern struct fsl_ifc_ctrl *fsl_ifc_ctrl_dev; +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/601-net-support-layerscape.patch b/target/linux/layerscape/patches-4.9/601-net-support-layerscape.patch new file mode 100644 index 0000000000..82e0a584b3 --- /dev/null +++ b/target/linux/layerscape/patches-4.9/601-net-support-layerscape.patch @@ -0,0 +1,2549 @@ +From 2ed7bff3d1f2fa6c5f6eff0b2bd98deaa3dc18b0 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 10:57:14 +0800 +Subject: [PATCH] net: support layerscape + +This is a integrated patch for layerscape net support. + +Signed-off-by: Madalin Bucur +Signed-off-by: Zhao Qiang +Signed-off-by: Camelia Groza +Signed-off-by: Madalin Bucur +Signed-off-by: Zhang Ying-22455 +Signed-off-by: Ramneek Mehresh +Signed-off-by: Jarod Wilson +Signed-off-by: Nikhil Badola +Signed-off-by: stephen hemminger +Signed-off-by: Arnd Bergmann +Signed-off-by: Yangbo Lu +--- + drivers/base/devres.c | 66 +++++++++++++++ + drivers/base/soc.c | 66 +++++++++++++++ + drivers/net/bonding/bond_main.c | 10 +-- + drivers/net/dummy.c | 5 +- + drivers/net/ethernet/amazon/ena/ena_netdev.c | 10 +-- + drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 6 +- + drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 4 +- + drivers/net/ethernet/atheros/alx/main.c | 6 +- + drivers/net/ethernet/broadcom/b44.c | 5 +- + drivers/net/ethernet/broadcom/bnx2.c | 5 +- + drivers/net/ethernet/broadcom/bnxt/bnxt.c | 6 +- + drivers/net/ethernet/broadcom/tg3.c | 8 +- + drivers/net/ethernet/brocade/bna/bnad.c | 6 +- + drivers/net/ethernet/calxeda/xgmac.c | 5 +- + drivers/net/ethernet/cavium/thunder/nicvf_main.c | 5 +- + drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 7 +- + drivers/net/ethernet/cisco/enic/enic_main.c | 8 +- + drivers/net/ethernet/ec_bhf.c | 4 +- + drivers/net/ethernet/emulex/benet/be_main.c | 5 +- + drivers/net/ethernet/hisilicon/hns/hns_enet.c | 6 +- + drivers/net/ethernet/ibm/ehea/ehea_main.c | 5 +- + drivers/net/ethernet/intel/e1000e/e1000.h | 4 +- + drivers/net/ethernet/intel/e1000e/netdev.c | 5 +- + drivers/net/ethernet/intel/fm10k/fm10k_netdev.c | 6 +- + drivers/net/ethernet/intel/i40e/i40e.h | 5 +- + drivers/net/ethernet/intel/i40e/i40e_main.c | 18 ++-- + drivers/net/ethernet/intel/igb/igb_main.c | 10 +-- + drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 7 +- + drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 6 +- + drivers/net/ethernet/marvell/mvneta.c | 4 +- + drivers/net/ethernet/marvell/mvpp2.c | 4 +- + drivers/net/ethernet/marvell/sky2.c | 6 +- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 6 +- + drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 4 +- + drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 3 +- + drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 4 +- + drivers/net/ethernet/mellanox/mlxsw/switchx2.c | 3 +- + drivers/net/ethernet/myricom/myri10ge/myri10ge.c | 9 +- + drivers/net/ethernet/neterion/vxge/vxge-main.c | 4 +- + .../net/ethernet/netronome/nfp/nfp_net_common.c | 6 +- + drivers/net/ethernet/nvidia/forcedeth.c | 4 +- + .../net/ethernet/qlogic/netxen/netxen_nic_main.c | 10 +-- + drivers/net/ethernet/qlogic/qede/qede_main.c | 7 +- + drivers/net/ethernet/qualcomm/emac/emac.c | 6 +- + drivers/net/ethernet/realtek/8139too.c | 9 +- + drivers/net/ethernet/realtek/r8169.c | 4 +- + drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c | 8 +- + drivers/net/ethernet/sfc/efx.c | 6 +- + drivers/net/ethernet/sun/niu.c | 6 +- + drivers/net/ethernet/synopsys/dwc_eth_qos.c | 4 +- + drivers/net/ethernet/tile/tilepro.c | 4 +- + drivers/net/ethernet/via/via-rhine.c | 8 +- + drivers/net/fjes/fjes_main.c | 7 +- + drivers/net/hyperv/netvsc_drv.c | 6 +- + drivers/net/ifb.c | 6 +- + drivers/net/ipvlan/ipvlan_main.c | 5 +- + drivers/net/loopback.c | 5 +- + drivers/net/macsec.c | 8 +- + drivers/net/macvlan.c | 5 +- + drivers/net/nlmon.c | 4 +- + drivers/net/ppp/ppp_generic.c | 4 +- + drivers/net/slip/slip.c | 3 +- + drivers/net/team/team.c | 3 +- + drivers/net/tun.c | 3 +- + drivers/net/veth.c | 6 +- + drivers/net/virtio_net.c | 6 +- + drivers/net/vmxnet3/vmxnet3_ethtool.c | 4 +- + drivers/net/vmxnet3/vmxnet3_int.h | 4 +- + drivers/net/vrf.c | 5 +- + drivers/net/xen-netfront.c | 6 +- + drivers/staging/netlogic/xlr_net.c | 10 +-- + include/linux/device.h | 19 +++++ + include/linux/fsl/svr.h | 97 ++++++++++++++++++++++ + include/linux/fsl_devices.h | 3 + + include/linux/netdev_features.h | 2 + + include/linux/netdevice.h | 12 ++- + include/linux/skbuff.h | 2 + + include/linux/sys_soc.h | 3 + + include/net/ip_tunnels.h | 4 +- + include/uapi/linux/if_ether.h | 1 + + net/8021q/vlan_dev.c | 5 +- + net/bridge/br_device.c | 6 +- + net/core/dev.c | 13 ++- + net/core/skbuff.c | 29 ++++++- + net/ipv4/ip_tunnel_core.c | 6 +- + net/l2tp/l2tp_eth.c | 6 +- + net/mac80211/iface.c | 4 +- + net/openvswitch/vport-internal_dev.c | 4 +- + net/sched/sch_generic.c | 7 ++ + net/sched/sch_teql.c | 5 +- + 90 files changed, 468 insertions(+), 298 deletions(-) + create mode 100644 include/linux/fsl/svr.h + +diff --git a/drivers/base/devres.c b/drivers/base/devres.c +index 8fc654f0..71d57702 100644 +--- a/drivers/base/devres.c ++++ b/drivers/base/devres.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + #include "base.h" + +@@ -985,3 +986,68 @@ void devm_free_pages(struct device *dev, unsigned long addr) + &devres)); + } + EXPORT_SYMBOL_GPL(devm_free_pages); ++ ++static void devm_percpu_release(struct device *dev, void *pdata) ++{ ++ void __percpu *p; ++ ++ p = *(void __percpu **)pdata; ++ free_percpu(p); ++} ++ ++static int devm_percpu_match(struct device *dev, void *data, void *p) ++{ ++ struct devres *devr = container_of(data, struct devres, data); ++ ++ return *(void **)devr->data == p; ++} ++ ++/** ++ * __devm_alloc_percpu - Resource-managed alloc_percpu ++ * @dev: Device to allocate per-cpu memory for ++ * @size: Size of per-cpu memory to allocate ++ * @align: Alignment of per-cpu memory to allocate ++ * ++ * Managed alloc_percpu. Per-cpu memory allocated with this function is ++ * automatically freed on driver detach. ++ * ++ * RETURNS: ++ * Pointer to allocated memory on success, NULL on failure. ++ */ ++void __percpu *__devm_alloc_percpu(struct device *dev, size_t size, ++ size_t align) ++{ ++ void *p; ++ void __percpu *pcpu; ++ ++ pcpu = __alloc_percpu(size, align); ++ if (!pcpu) ++ return NULL; ++ ++ p = devres_alloc(devm_percpu_release, sizeof(void *), GFP_KERNEL); ++ if (!p) { ++ free_percpu(pcpu); ++ return NULL; ++ } ++ ++ *(void __percpu **)p = pcpu; ++ ++ devres_add(dev, p); ++ ++ return pcpu; ++} ++EXPORT_SYMBOL_GPL(__devm_alloc_percpu); ++ ++/** ++ * devm_free_percpu - Resource-managed free_percpu ++ * @dev: Device this memory belongs to ++ * @pdata: Per-cpu memory to free ++ * ++ * Free memory allocated with devm_alloc_percpu(). ++ */ ++void devm_free_percpu(struct device *dev, void __percpu *pdata) ++{ ++ WARN_ON(devres_destroy(dev, devm_percpu_release, devm_percpu_match, ++ (void *)pdata)); ++} ++EXPORT_SYMBOL_GPL(devm_free_percpu); +diff --git a/drivers/base/soc.c b/drivers/base/soc.c +index b63f23e6..0c5cf872 100644 +--- a/drivers/base/soc.c ++++ b/drivers/base/soc.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + static DEFINE_IDA(soc_ida); + +@@ -159,3 +160,68 @@ static int __init soc_bus_register(void) + return bus_register(&soc_bus_type); + } + core_initcall(soc_bus_register); ++ ++static int soc_device_match_one(struct device *dev, void *arg) ++{ ++ struct soc_device *soc_dev = container_of(dev, struct soc_device, dev); ++ const struct soc_device_attribute *match = arg; ++ ++ if (match->machine && ++ !glob_match(match->machine, soc_dev->attr->machine)) ++ return 0; ++ ++ if (match->family && ++ !glob_match(match->family, soc_dev->attr->family)) ++ return 0; ++ ++ if (match->revision && ++ !glob_match(match->revision, soc_dev->attr->revision)) ++ return 0; ++ ++ if (match->soc_id && ++ !glob_match(match->soc_id, soc_dev->attr->soc_id)) ++ return 0; ++ ++ return 1; ++} ++ ++/* ++ * soc_device_match - identify the SoC in the machine ++ * @matches: zero-terminated array of possible matches ++ * ++ * returns the first matching entry of the argument array, or NULL ++ * if none of them match. ++ * ++ * This function is meant as a helper in place of of_match_node() ++ * in cases where either no device tree is available or the information ++ * in a device node is insufficient to identify a particular variant ++ * by its compatible strings or other properties. For new devices, ++ * the DT binding should always provide unique compatible strings ++ * that allow the use of of_match_node() instead. ++ * ++ * The calling function can use the .data entry of the ++ * soc_device_attribute to pass a structure or function pointer for ++ * each entry. ++ */ ++const struct soc_device_attribute *soc_device_match( ++ const struct soc_device_attribute *matches) ++{ ++ int ret = 0; ++ ++ if (!matches) ++ return NULL; ++ ++ while (!ret) { ++ if (!(matches->machine || matches->family || ++ matches->revision || matches->soc_id)) ++ break; ++ ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches, ++ soc_device_match_one); ++ if (!ret) ++ matches++; ++ else ++ return matches; ++ } ++ return NULL; ++} ++EXPORT_SYMBOL_GPL(soc_device_match); +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c +index 5fa36ebc..75ff184a 100644 +--- a/drivers/net/bonding/bond_main.c ++++ b/drivers/net/bonding/bond_main.c +@@ -211,8 +211,8 @@ static int lacp_fast; + + static int bond_init(struct net_device *bond_dev); + static void bond_uninit(struct net_device *bond_dev); +-static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev, +- struct rtnl_link_stats64 *stats); ++static void bond_get_stats(struct net_device *bond_dev, ++ struct rtnl_link_stats64 *stats); + static void bond_slave_arr_handler(struct work_struct *work); + static bool bond_time_in_interval(struct bonding *bond, unsigned long last_act, + int mod); +@@ -3336,8 +3336,8 @@ static void bond_fold_stats(struct rtnl_link_stats64 *_res, + } + } + +-static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev, +- struct rtnl_link_stats64 *stats) ++static void bond_get_stats(struct net_device *bond_dev, ++ struct rtnl_link_stats64 *stats) + { + struct bonding *bond = netdev_priv(bond_dev); + struct rtnl_link_stats64 temp; +@@ -3361,8 +3361,6 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev, + + memcpy(&bond->bond_stats, stats, sizeof(*stats)); + spin_unlock(&bond->stats_lock); +- +- return stats; + } + + static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd) +diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c +index 69fc8409..da5b10e0 100644 +--- a/drivers/net/dummy.c ++++ b/drivers/net/dummy.c +@@ -54,8 +54,8 @@ struct pcpu_dstats { + struct u64_stats_sync syncp; + }; + +-static struct rtnl_link_stats64 *dummy_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *stats) ++static void dummy_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + int i; + +@@ -73,7 +73,6 @@ static struct rtnl_link_stats64 *dummy_get_stats64(struct net_device *dev, + stats->tx_bytes += tbytes; + stats->tx_packets += tpackets; + } +- return stats; + } + + static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev) +diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c +index bfeaec5b..ddc281c4 100644 +--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c ++++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c +@@ -2172,19 +2172,19 @@ static void ena_config_debug_area(struct ena_adapter *adapter) + ena_com_delete_debug_area(adapter->ena_dev); + } + +-static struct rtnl_link_stats64 *ena_get_stats64(struct net_device *netdev, +- struct rtnl_link_stats64 *stats) ++static void ena_get_stats64(struct net_device *netdev, ++ struct rtnl_link_stats64 *stats) + { + struct ena_adapter *adapter = netdev_priv(netdev); + struct ena_admin_basic_stats ena_stats; + int rc; + + if (!test_bit(ENA_FLAG_DEV_UP, &adapter->flags)) +- return NULL; ++ return; + + rc = ena_com_get_dev_basic_stats(adapter->ena_dev, &ena_stats); + if (rc) +- return NULL; ++ return; + + stats->tx_bytes = ((u64)ena_stats.tx_bytes_high << 32) | + ena_stats.tx_bytes_low; +@@ -2211,8 +2211,6 @@ static struct rtnl_link_stats64 *ena_get_stats64(struct net_device *netdev, + + stats->rx_errors = 0; + stats->tx_errors = 0; +- +- return stats; + } + + static const struct net_device_ops ena_netdev_ops = { +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +index 1e4e8b24..5b413ee7 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +@@ -1542,8 +1542,8 @@ static void xgbe_tx_timeout(struct net_device *netdev) + schedule_work(&pdata->restart_work); + } + +-static struct rtnl_link_stats64 *xgbe_get_stats64(struct net_device *netdev, +- struct rtnl_link_stats64 *s) ++static void xgbe_get_stats64(struct net_device *netdev, ++ struct rtnl_link_stats64 *s) + { + struct xgbe_prv_data *pdata = netdev_priv(netdev); + struct xgbe_mmc_stats *pstats = &pdata->mmc_stats; +@@ -1569,8 +1569,6 @@ static struct rtnl_link_stats64 *xgbe_get_stats64(struct net_device *netdev, + s->tx_dropped = netdev->stats.tx_dropped; + + DBGPR("<--%s\n", __func__); +- +- return s; + } + + static int xgbe_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, +diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +index 8158d469..e62ca66b 100644 +--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c ++++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +@@ -1199,7 +1199,7 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev) + return ret; + } + +-static struct rtnl_link_stats64 *xgene_enet_get_stats64( ++static void xgene_enet_get_stats64( + struct net_device *ndev, + struct rtnl_link_stats64 *storage) + { +@@ -1230,8 +1230,6 @@ static struct rtnl_link_stats64 *xgene_enet_get_stats64( + } + } + memcpy(storage, stats, sizeof(struct rtnl_link_stats64)); +- +- return storage; + } + + static int xgene_enet_set_mac_address(struct net_device *ndev, void *addr) +diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c +index c0f84b73..3c5c8159 100644 +--- a/drivers/net/ethernet/atheros/alx/main.c ++++ b/drivers/net/ethernet/atheros/alx/main.c +@@ -1424,8 +1424,8 @@ static void alx_poll_controller(struct net_device *netdev) + } + #endif + +-static struct rtnl_link_stats64 *alx_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *net_stats) ++static void alx_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *net_stats) + { + struct alx_priv *alx = netdev_priv(dev); + struct alx_hw_stats *hw_stats = &alx->hw.stats; +@@ -1469,8 +1469,6 @@ static struct rtnl_link_stats64 *alx_get_stats64(struct net_device *dev, + net_stats->rx_packets = hw_stats->rx_ok + net_stats->rx_errors; + + spin_unlock(&alx->stats_lock); +- +- return net_stats; + } + + static const struct net_device_ops alx_netdev_ops = { +diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c +index 17aa33c5..55f124d7 100644 +--- a/drivers/net/ethernet/broadcom/b44.c ++++ b/drivers/net/ethernet/broadcom/b44.c +@@ -1677,8 +1677,8 @@ static int b44_close(struct net_device *dev) + return 0; + } + +-static struct rtnl_link_stats64 *b44_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *nstat) ++static void b44_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *nstat) + { + struct b44 *bp = netdev_priv(dev); + struct b44_hw_stats *hwstat = &bp->hw_stats; +@@ -1721,7 +1721,6 @@ static struct rtnl_link_stats64 *b44_get_stats64(struct net_device *dev, + #endif + } while (u64_stats_fetch_retry_irq(&hwstat->syncp, start)); + +- return nstat; + } + + static int __b44_load_mcast(struct b44 *bp, struct net_device *dev) +diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c +index 1f7034d7..c23dfcb9 100644 +--- a/drivers/net/ethernet/broadcom/bnx2.c ++++ b/drivers/net/ethernet/broadcom/bnx2.c +@@ -6828,13 +6828,13 @@ bnx2_save_stats(struct bnx2 *bp) + (unsigned long) (bp->stats_blk->ctr + \ + bp->temp_stats_blk->ctr) + +-static struct rtnl_link_stats64 * ++static void + bnx2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats) + { + struct bnx2 *bp = netdev_priv(dev); + + if (bp->stats_blk == NULL) +- return net_stats; ++ return; + + net_stats->rx_packets = + GET_64BIT_NET_STATS(stat_IfHCInUcastPkts) + +@@ -6898,7 +6898,6 @@ bnx2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats) + GET_32BIT_NET_STATS(stat_IfInMBUFDiscards) + + GET_32BIT_NET_STATS(stat_FwRxDrop); + +- return net_stats; + } + + /* All ethtool functions called with rtnl_lock */ +diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +index 20e569bd..d6c10783 100644 +--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c ++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c +@@ -5664,7 +5664,7 @@ static int bnxt_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) + return -EOPNOTSUPP; + } + +-static struct rtnl_link_stats64 * ++static void + bnxt_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + { + u32 i; +@@ -5673,7 +5673,7 @@ bnxt_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + memset(stats, 0, sizeof(struct rtnl_link_stats64)); + + if (!bp->bnapi) +- return stats; ++ return; + + /* TODO check if we need to synchronize with bnxt_close path */ + for (i = 0; i < bp->cp_nr_rings; i++) { +@@ -5720,8 +5720,6 @@ bnxt_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + stats->tx_fifo_errors = le64_to_cpu(tx->tx_fifo_underruns); + stats->tx_errors = le64_to_cpu(tx->tx_err); + } +- +- return stats; + } + + static bool bnxt_mc_list_updated(struct bnxt *bp, u32 *rx_mask) +diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c +index edae2dcc..4d45077e 100644 +--- a/drivers/net/ethernet/broadcom/tg3.c ++++ b/drivers/net/ethernet/broadcom/tg3.c +@@ -14145,8 +14145,8 @@ static const struct ethtool_ops tg3_ethtool_ops = { + .set_link_ksettings = tg3_set_link_ksettings, + }; + +-static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *stats) ++static void tg3_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + struct tg3 *tp = netdev_priv(dev); + +@@ -14154,13 +14154,11 @@ static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev, + if (!tp->hw_stats) { + *stats = tp->net_stats_prev; + spin_unlock_bh(&tp->lock); +- return stats; ++ return; + } + + tg3_get_nstats(tp, stats); + spin_unlock_bh(&tp->lock); +- +- return stats; + } + + static void tg3_set_rx_mode(struct net_device *dev) +diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c +index f42f672b..aa141609 100644 +--- a/drivers/net/ethernet/brocade/bna/bnad.c ++++ b/drivers/net/ethernet/brocade/bna/bnad.c +@@ -3111,7 +3111,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev) + * Used spin_lock to synchronize reading of stats structures, which + * is written by BNA under the same lock. + */ +-static struct rtnl_link_stats64 * ++static void + bnad_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) + { + struct bnad *bnad = netdev_priv(netdev); +@@ -3123,8 +3123,6 @@ bnad_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) + bnad_netdev_hwstats_fill(bnad, stats); + + spin_unlock_irqrestore(&bnad->bna_lock, flags); +- +- return stats; + } + + static void +@@ -3430,7 +3428,7 @@ static const struct net_device_ops bnad_netdev_ops = { + .ndo_open = bnad_open, + .ndo_stop = bnad_stop, + .ndo_start_xmit = bnad_start_xmit, +- .ndo_get_stats64 = bnad_get_stats64, ++ .ndo_get_stats64 = bnad_get_stats64, + .ndo_set_rx_mode = bnad_set_rx_mode, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = bnad_set_mac_address, +diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c +index 63efa0dc..ccb8fbd6 100644 +--- a/drivers/net/ethernet/calxeda/xgmac.c ++++ b/drivers/net/ethernet/calxeda/xgmac.c +@@ -1460,9 +1460,9 @@ static void xgmac_poll_controller(struct net_device *dev) + } + #endif + +-static struct rtnl_link_stats64 * ++static void + xgmac_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *storage) ++ struct rtnl_link_stats64 *storage) + { + struct xgmac_priv *priv = netdev_priv(dev); + void __iomem *base = priv->base; +@@ -1490,7 +1490,6 @@ xgmac_get_stats64(struct net_device *dev, + + writel(0, base + XGMAC_MMC_CTRL); + spin_unlock_bh(&priv->stats_lock); +- return storage; + } + + static int xgmac_set_mac_address(struct net_device *dev, void *p) +diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c +index 8a37012c..87709a9d 100644 +--- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c ++++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c +@@ -1423,8 +1423,8 @@ void nicvf_update_stats(struct nicvf *nic) + nicvf_update_sq_stats(nic, qidx); + } + +-static struct rtnl_link_stats64 *nicvf_get_stats64(struct net_device *netdev, +- struct rtnl_link_stats64 *stats) ++static void nicvf_get_stats64(struct net_device *netdev, ++ struct rtnl_link_stats64 *stats) + { + struct nicvf *nic = netdev_priv(netdev); + struct nicvf_hw_stats *hw_stats = &nic->hw_stats; +@@ -1440,7 +1440,6 @@ static struct rtnl_link_stats64 *nicvf_get_stats64(struct net_device *netdev, + stats->tx_packets = hw_stats->tx_frames; + stats->tx_dropped = hw_stats->tx_drops; + +- return stats; + } + + static void nicvf_tx_timeout(struct net_device *dev) +diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +index 0c2a32a3..c4244913 100644 +--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c ++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +@@ -2383,8 +2383,8 @@ int cxgb4_remove_server_filter(const struct net_device *dev, unsigned int stid, + } + EXPORT_SYMBOL(cxgb4_remove_server_filter); + +-static struct rtnl_link_stats64 *cxgb_get_stats(struct net_device *dev, +- struct rtnl_link_stats64 *ns) ++static void cxgb_get_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *ns) + { + struct port_stats stats; + struct port_info *p = netdev_priv(dev); +@@ -2397,7 +2397,7 @@ static struct rtnl_link_stats64 *cxgb_get_stats(struct net_device *dev, + spin_lock(&adapter->stats_lock); + if (!netif_device_present(dev)) { + spin_unlock(&adapter->stats_lock); +- return ns; ++ return; + } + t4_get_port_stats_offset(adapter, p->tx_chan, &stats, + &p->stats_base); +@@ -2431,7 +2431,6 @@ static struct rtnl_link_stats64 *cxgb_get_stats(struct net_device *dev, + ns->tx_errors = stats.tx_error_frames; + ns->rx_errors = stats.rx_symbol_err + stats.rx_fcs_err + + ns->rx_length_errors + stats.rx_len_err + ns->rx_fifo_errors; +- return ns; + } + + static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c +index 48f82ab6..662cc676 100644 +--- a/drivers/net/ethernet/cisco/enic/enic_main.c ++++ b/drivers/net/ethernet/cisco/enic/enic_main.c +@@ -680,8 +680,8 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb, + } + + /* dev_base_lock rwlock held, nominally process context */ +-static struct rtnl_link_stats64 *enic_get_stats(struct net_device *netdev, +- struct rtnl_link_stats64 *net_stats) ++static void enic_get_stats(struct net_device *netdev, ++ struct rtnl_link_stats64 *net_stats) + { + struct enic *enic = netdev_priv(netdev); + struct vnic_stats *stats; +@@ -693,7 +693,7 @@ static struct rtnl_link_stats64 *enic_get_stats(struct net_device *netdev, + * recorded stats. + */ + if (err == -ENOMEM) +- return net_stats; ++ return; + + net_stats->tx_packets = stats->tx.tx_frames_ok; + net_stats->tx_bytes = stats->tx.tx_bytes_ok; +@@ -707,8 +707,6 @@ static struct rtnl_link_stats64 *enic_get_stats(struct net_device *netdev, + net_stats->rx_over_errors = enic->rq_truncated_pkts; + net_stats->rx_crc_errors = enic->rq_bad_fcs; + net_stats->rx_dropped = stats->rx.rx_no_bufs + stats->rx.rx_drop; +- +- return net_stats; + } + + static int enic_mc_sync(struct net_device *netdev, const u8 *mc_addr) +diff --git a/drivers/net/ethernet/ec_bhf.c b/drivers/net/ethernet/ec_bhf.c +index f7b42483..2e7554c7 100644 +--- a/drivers/net/ethernet/ec_bhf.c ++++ b/drivers/net/ethernet/ec_bhf.c +@@ -458,7 +458,7 @@ static int ec_bhf_stop(struct net_device *net_dev) + return 0; + } + +-static struct rtnl_link_stats64 * ++static void + ec_bhf_get_stats(struct net_device *net_dev, + struct rtnl_link_stats64 *stats) + { +@@ -473,8 +473,6 @@ ec_bhf_get_stats(struct net_device *net_dev, + + stats->tx_bytes = priv->stat_tx_bytes; + stats->rx_bytes = priv->stat_rx_bytes; +- +- return stats; + } + + static const struct net_device_ops ec_bhf_netdev_ops = { +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 5626908f..59852304 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -646,8 +646,8 @@ void be_parse_stats(struct be_adapter *adapter) + } + } + +-static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev, +- struct rtnl_link_stats64 *stats) ++static void be_get_stats64(struct net_device *netdev, ++ struct rtnl_link_stats64 *stats) + { + struct be_adapter *adapter = netdev_priv(netdev); + struct be_drv_stats *drvs = &adapter->drv_stats; +@@ -711,7 +711,6 @@ static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev, + stats->rx_fifo_errors = drvs->rxpp_fifo_overflow_drop + + drvs->rx_input_fifo_overflow_drop + + drvs->rx_drops_no_pbuf; +- return stats; + } + + void be_link_status_update(struct be_adapter *adapter, u8 link_status) +diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c +index c06845b7..249bc6ad 100644 +--- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c ++++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c +@@ -1536,8 +1536,8 @@ void hns_nic_set_rx_mode(struct net_device *ndev) + hns_set_multicast_list(ndev); + } + +-struct rtnl_link_stats64 *hns_nic_get_stats64(struct net_device *ndev, +- struct rtnl_link_stats64 *stats) ++static void hns_nic_get_stats64(struct net_device *ndev, ++ struct rtnl_link_stats64 *stats) + { + int idx = 0; + u64 tx_bytes = 0; +@@ -1579,8 +1579,6 @@ struct rtnl_link_stats64 *hns_nic_get_stats64(struct net_device *ndev, + stats->tx_window_errors = ndev->stats.tx_window_errors; + stats->rx_compressed = ndev->stats.rx_compressed; + stats->tx_compressed = ndev->stats.tx_compressed; +- +- return stats; + } + + static u16 +diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c +index bd719e25..a2ff2783 100644 +--- a/drivers/net/ethernet/ibm/ehea/ehea_main.c ++++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c +@@ -328,8 +328,8 @@ static void ehea_update_bcmc_registrations(void) + spin_unlock_irqrestore(&ehea_bcmc_regs.lock, flags); + } + +-static struct rtnl_link_stats64 *ehea_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *stats) ++static void ehea_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + struct ehea_port *port = netdev_priv(dev); + u64 rx_packets = 0, tx_packets = 0, rx_bytes = 0, tx_bytes = 0; +@@ -352,7 +352,6 @@ static struct rtnl_link_stats64 *ehea_get_stats64(struct net_device *dev, + + stats->multicast = port->stats.multicast; + stats->rx_errors = port->stats.rx_errors; +- return stats; + } + + static void ehea_update_stats(struct work_struct *work) +diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h +index 879cca47..a29b12e8 100644 +--- a/drivers/net/ethernet/intel/e1000e/e1000.h ++++ b/drivers/net/ethernet/intel/e1000e/e1000.h +@@ -493,8 +493,8 @@ int e1000e_setup_rx_resources(struct e1000_ring *ring); + int e1000e_setup_tx_resources(struct e1000_ring *ring); + void e1000e_free_rx_resources(struct e1000_ring *ring); + void e1000e_free_tx_resources(struct e1000_ring *ring); +-struct rtnl_link_stats64 *e1000e_get_stats64(struct net_device *netdev, +- struct rtnl_link_stats64 *stats); ++void e1000e_get_stats64(struct net_device *netdev, ++ struct rtnl_link_stats64 *stats); + void e1000e_set_interrupt_capability(struct e1000_adapter *adapter); + void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter); + void e1000e_get_hw_control(struct e1000_adapter *adapter); +diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c +index 7017281b..49f3d868 100644 +--- a/drivers/net/ethernet/intel/e1000e/netdev.c ++++ b/drivers/net/ethernet/intel/e1000e/netdev.c +@@ -5920,8 +5920,8 @@ static void e1000_reset_task(struct work_struct *work) + * + * Returns the address of the device statistics structure. + **/ +-struct rtnl_link_stats64 *e1000e_get_stats64(struct net_device *netdev, +- struct rtnl_link_stats64 *stats) ++void e1000e_get_stats64(struct net_device *netdev, ++ struct rtnl_link_stats64 *stats) + { + struct e1000_adapter *adapter = netdev_priv(netdev); + +@@ -5958,7 +5958,6 @@ struct rtnl_link_stats64 *e1000e_get_stats64(struct net_device *netdev, + /* Tx Dropped needs to be maintained elsewhere */ + + spin_unlock(&adapter->stats64_lock); +- return stats; + } + + /** +diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +index 05629381..e97b6c49 100644 +--- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c ++++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +@@ -1128,8 +1128,8 @@ void fm10k_reset_rx_state(struct fm10k_intfc *interface) + * Returns 64bit statistics, for use in the ndo_get_stats64 callback. This + * function replaces fm10k_get_stats for kernels which support it. + */ +-static struct rtnl_link_stats64 *fm10k_get_stats64(struct net_device *netdev, +- struct rtnl_link_stats64 *stats) ++static void fm10k_get_stats64(struct net_device *netdev, ++ struct rtnl_link_stats64 *stats) + { + struct fm10k_intfc *interface = netdev_priv(netdev); + struct fm10k_ring *ring; +@@ -1174,8 +1174,6 @@ static struct rtnl_link_stats64 *fm10k_get_stats64(struct net_device *netdev, + + /* following stats updated by fm10k_service_task() */ + stats->rx_missed_errors = netdev->stats.rx_missed_errors; +- +- return stats; + } + + int fm10k_setup_tc(struct net_device *dev, u8 tc) +diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h +index 6d61e443..3cc0bf29 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e.h ++++ b/drivers/net/ethernet/intel/i40e/i40e.h +@@ -797,9 +797,8 @@ static inline void i40e_irq_dynamic_enable(struct i40e_vsi *vsi, int vector) + void i40e_irq_dynamic_disable_icr0(struct i40e_pf *pf); + void i40e_irq_dynamic_enable_icr0(struct i40e_pf *pf, bool clearpba); + #ifdef I40E_FCOE +-struct rtnl_link_stats64 *i40e_get_netdev_stats_struct( +- struct net_device *netdev, +- struct rtnl_link_stats64 *storage); ++void i40e_get_netdev_stats_struct(struct net_device *netdev, ++ struct rtnl_link_stats64 *storage); + int i40e_set_mac(struct net_device *netdev, void *p); + void i40e_set_rx_mode(struct net_device *netdev); + #endif +diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c +index 31c97e39..2f1554b3 100644 +--- a/drivers/net/ethernet/intel/i40e/i40e_main.c ++++ b/drivers/net/ethernet/intel/i40e/i40e_main.c +@@ -408,15 +408,11 @@ struct rtnl_link_stats64 *i40e_get_vsi_stats_struct(struct i40e_vsi *vsi) + * Returns the address of the device statistics structure. + * The statistics are actually updated from the service task. + **/ +-#ifdef I40E_FCOE +-struct rtnl_link_stats64 *i40e_get_netdev_stats_struct( +- struct net_device *netdev, +- struct rtnl_link_stats64 *stats) +-#else +-static struct rtnl_link_stats64 *i40e_get_netdev_stats_struct( +- struct net_device *netdev, +- struct rtnl_link_stats64 *stats) ++#ifndef I40E_FCOE ++static + #endif ++void i40e_get_netdev_stats_struct(struct net_device *netdev, ++ struct rtnl_link_stats64 *stats) + { + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_ring *tx_ring, *rx_ring; +@@ -425,10 +421,10 @@ static struct rtnl_link_stats64 *i40e_get_netdev_stats_struct( + int i; + + if (test_bit(__I40E_DOWN, &vsi->state)) +- return stats; ++ return; + + if (!vsi->tx_rings) +- return stats; ++ return; + + rcu_read_lock(); + for (i = 0; i < vsi->num_queue_pairs; i++) { +@@ -468,8 +464,6 @@ static struct rtnl_link_stats64 *i40e_get_netdev_stats_struct( + stats->rx_dropped = vsi_stats->rx_dropped; + stats->rx_crc_errors = vsi_stats->rx_crc_errors; + stats->rx_length_errors = vsi_stats->rx_length_errors; +- +- return stats; + } + + /** +diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c +index 9affd7c1..076ccfa4 100644 +--- a/drivers/net/ethernet/intel/igb/igb_main.c ++++ b/drivers/net/ethernet/intel/igb/igb_main.c +@@ -137,8 +137,8 @@ static void igb_update_phy_info(unsigned long); + static void igb_watchdog(unsigned long); + static void igb_watchdog_task(struct work_struct *); + static netdev_tx_t igb_xmit_frame(struct sk_buff *skb, struct net_device *); +-static struct rtnl_link_stats64 *igb_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *stats); ++static void igb_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats); + static int igb_change_mtu(struct net_device *, int); + static int igb_set_mac(struct net_device *, void *); + static void igb_set_uta(struct igb_adapter *adapter, bool set); +@@ -5386,8 +5386,8 @@ static void igb_reset_task(struct work_struct *work) + * @netdev: network interface device structure + * @stats: rtnl_link_stats64 pointer + **/ +-static struct rtnl_link_stats64 *igb_get_stats64(struct net_device *netdev, +- struct rtnl_link_stats64 *stats) ++static void igb_get_stats64(struct net_device *netdev, ++ struct rtnl_link_stats64 *stats) + { + struct igb_adapter *adapter = netdev_priv(netdev); + +@@ -5395,8 +5395,6 @@ static struct rtnl_link_stats64 *igb_get_stats64(struct net_device *netdev, + igb_update_stats(adapter, &adapter->stats64); + memcpy(stats, &adapter->stats64, sizeof(*stats)); + spin_unlock(&adapter->stats64_lock); +- +- return stats; + } + + /** +diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +index fee1f291..ee4f1cc2 100644 +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +@@ -8085,8 +8085,9 @@ static void ixgbe_netpoll(struct net_device *netdev) + } + + #endif +-static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev, +- struct rtnl_link_stats64 *stats) ++ ++static void ixgbe_get_stats64(struct net_device *netdev, ++ struct rtnl_link_stats64 *stats) + { + struct ixgbe_adapter *adapter = netdev_priv(netdev); + int i; +@@ -8124,13 +8125,13 @@ static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev, + } + } + rcu_read_unlock(); ++ + /* following stats updated by ixgbe_watchdog_task() */ + stats->multicast = netdev->stats.multicast; + stats->rx_errors = netdev->stats.rx_errors; + stats->rx_length_errors = netdev->stats.rx_length_errors; + stats->rx_crc_errors = netdev->stats.rx_crc_errors; + stats->rx_missed_errors = netdev->stats.rx_missed_errors; +- return stats; + } + + #ifdef CONFIG_IXGBE_DCB +diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +index cbf70fe4..3519769e 100644 +--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c ++++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +@@ -3880,8 +3880,8 @@ static void ixgbevf_shutdown(struct pci_dev *pdev) + ixgbevf_suspend(pdev, PMSG_SUSPEND); + } + +-static struct rtnl_link_stats64 *ixgbevf_get_stats(struct net_device *netdev, +- struct rtnl_link_stats64 *stats) ++static void ixgbevf_get_stats(struct net_device *netdev, ++ struct rtnl_link_stats64 *stats) + { + struct ixgbevf_adapter *adapter = netdev_priv(netdev); + unsigned int start; +@@ -3914,8 +3914,6 @@ static struct rtnl_link_stats64 *ixgbevf_get_stats(struct net_device *netdev, + stats->tx_bytes += bytes; + stats->tx_packets += packets; + } +- +- return stats; + } + + #define IXGBEVF_MAX_MAC_HDR_LEN 127 +diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c +index 707bc468..100f3af8 100644 +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -636,7 +636,7 @@ static void mvneta_mib_counters_clear(struct mvneta_port *pp) + } + + /* Get System Network Statistics */ +-static struct rtnl_link_stats64 * ++static void + mvneta_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) + { +@@ -670,8 +670,6 @@ mvneta_get_stats64(struct net_device *dev, + stats->rx_dropped = dev->stats.rx_dropped; + + stats->tx_dropped = dev->stats.tx_dropped; +- +- return stats; + } + + /* Rx descriptors helper methods */ +diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c +index 0a4e81a2..17032925 100644 +--- a/drivers/net/ethernet/marvell/mvpp2.c ++++ b/drivers/net/ethernet/marvell/mvpp2.c +@@ -5762,7 +5762,7 @@ static int mvpp2_change_mtu(struct net_device *dev, int mtu) + return err; + } + +-static struct rtnl_link_stats64 * ++static void + mvpp2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + { + struct mvpp2_port *port = netdev_priv(dev); +@@ -5794,8 +5794,6 @@ mvpp2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + stats->rx_errors = dev->stats.rx_errors; + stats->rx_dropped = dev->stats.rx_dropped; + stats->tx_dropped = dev->stats.tx_dropped; +- +- return stats; + } + + static int mvpp2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c +index 941c8e2c..cff8b633 100644 +--- a/drivers/net/ethernet/marvell/sky2.c ++++ b/drivers/net/ethernet/marvell/sky2.c +@@ -3898,8 +3898,8 @@ static void sky2_set_multicast(struct net_device *dev) + gma_write16(hw, port, GM_RX_CTRL, reg); + } + +-static struct rtnl_link_stats64 *sky2_get_stats(struct net_device *dev, +- struct rtnl_link_stats64 *stats) ++static void sky2_get_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_hw *hw = sky2->hw; +@@ -3939,8 +3939,6 @@ static struct rtnl_link_stats64 *sky2_get_stats(struct net_device *dev, + stats->rx_dropped = dev->stats.rx_dropped; + stats->rx_fifo_errors = dev->stats.rx_fifo_errors; + stats->tx_fifo_errors = dev->stats.tx_fifo_errors; +- +- return stats; + } + + /* Can have one global because blinking is controlled by +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index 4832223f..6d260da6 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -462,8 +462,8 @@ static void mtk_stats_update(struct mtk_eth *eth) + } + } + +-static struct rtnl_link_stats64 *mtk_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *storage) ++static void mtk_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *storage) + { + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_hw_stats *hw_stats = mac->hw_stats; +@@ -494,8 +494,6 @@ static struct rtnl_link_stats64 *mtk_get_stats64(struct net_device *dev, + storage->tx_errors = dev->stats.tx_errors; + storage->rx_dropped = dev->stats.rx_dropped; + storage->tx_dropped = dev->stats.tx_dropped; +- +- return storage; + } + + static inline int mtk_max_frag_size(int mtu) +diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +index d223e7cb..ebf5c7e5 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c ++++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +@@ -1316,7 +1316,7 @@ static void mlx4_en_tx_timeout(struct net_device *dev) + } + + +-static struct rtnl_link_stats64 * ++static void + mlx4_en_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + { + struct mlx4_en_priv *priv = netdev_priv(dev); +@@ -1324,8 +1324,6 @@ mlx4_en_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + spin_lock_bh(&priv->stats_lock); + netdev_stats_to_stats64(stats, &dev->stats); + spin_unlock_bh(&priv->stats_lock); +- +- return stats; + } + + static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +index 9d372293..582ba530 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +@@ -2647,7 +2647,7 @@ static int mlx5e_ndo_setup_tc(struct net_device *dev, u32 handle, + return mlx5e_setup_tc(dev, tc->tc); + } + +-struct rtnl_link_stats64 * ++static void + mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) + { + struct mlx5e_priv *priv = netdev_priv(dev); +@@ -2681,7 +2681,6 @@ mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) + stats->multicast = + VPORT_COUNTER_GET(vstats, received_eth_multicast.packets); + +- return stats; + } + + static void mlx5e_set_rx_mode(struct net_device *dev) +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +index 1806b1fc..cf21a83a 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +@@ -948,15 +948,13 @@ static void update_stats_cache(struct work_struct *work) + /* Return the stats from a cache that is updated periodically, + * as this function might get called in an atomic context. + */ +-static struct rtnl_link_stats64 * ++static void + mlxsw_sp_port_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) + { + struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); + + memcpy(stats, mlxsw_sp_port->hw_stats.cache, sizeof(*stats)); +- +- return stats; + } + + int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, +diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +index d548f0a5..6e9e7fa4 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +@@ -351,7 +351,7 @@ static int mlxsw_sx_port_change_mtu(struct net_device *dev, int mtu) + return 0; + } + +-static struct rtnl_link_stats64 * ++static void + mlxsw_sx_port_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) + { +@@ -380,7 +380,6 @@ mlxsw_sx_port_get_stats64(struct net_device *dev, + tx_dropped += p->tx_dropped; + } + stats->tx_dropped = tx_dropped; +- return stats; + } + + static const struct net_device_ops mlxsw_sx_port_netdev_ops = { +diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c +index 6d1a956e..d26745cc 100644 +--- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c ++++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c +@@ -378,8 +378,8 @@ static inline void put_be32(__be32 val, __be32 __iomem * p) + __raw_writel((__force __u32) val, (__force void __iomem *)p); + } + +-static struct rtnl_link_stats64 *myri10ge_get_stats(struct net_device *dev, +- struct rtnl_link_stats64 *stats); ++static void myri10ge_get_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *stats); + + static void set_fw_name(struct myri10ge_priv *mgp, char *name, bool allocated) + { +@@ -3119,8 +3119,8 @@ static netdev_tx_t myri10ge_sw_tso(struct sk_buff *skb, + return NETDEV_TX_OK; + } + +-static struct rtnl_link_stats64 *myri10ge_get_stats(struct net_device *dev, +- struct rtnl_link_stats64 *stats) ++static void myri10ge_get_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + const struct myri10ge_priv *mgp = netdev_priv(dev); + const struct myri10ge_slice_netstats *slice_stats; +@@ -3135,7 +3135,6 @@ static struct rtnl_link_stats64 *myri10ge_get_stats(struct net_device *dev, + stats->rx_dropped += slice_stats->rx_dropped; + stats->tx_dropped += slice_stats->tx_dropped; + } +- return stats; + } + + static void myri10ge_set_multicast_list(struct net_device *dev) +diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c +index e0993eba..9c27728f 100644 +--- a/drivers/net/ethernet/neterion/vxge/vxge-main.c ++++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c +@@ -3116,7 +3116,7 @@ static int vxge_change_mtu(struct net_device *dev, int new_mtu) + * @stats: pointer to struct rtnl_link_stats64 + * + */ +-static struct rtnl_link_stats64 * ++static void + vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats) + { + struct vxgedev *vdev = netdev_priv(dev); +@@ -3155,8 +3155,6 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats) + net_stats->tx_bytes += bytes; + net_stats->tx_errors += txstats->tx_errors; + } +- +- return net_stats; + } + + static enum vxge_hw_status vxge_timestamp_config(struct __vxge_hw_device *devh) +diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +index 4ca82bd8..55915cbd 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c ++++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +@@ -2400,8 +2400,8 @@ int nfp_net_set_ring_size(struct nfp_net *nn, u32 rxd_cnt, u32 txd_cnt) + return err; + } + +-static struct rtnl_link_stats64 *nfp_net_stat64(struct net_device *netdev, +- struct rtnl_link_stats64 *stats) ++static void nfp_net_stat64(struct net_device *netdev, ++ struct rtnl_link_stats64 *stats) + { + struct nfp_net *nn = netdev_priv(netdev); + int r; +@@ -2431,8 +2431,6 @@ static struct rtnl_link_stats64 *nfp_net_stat64(struct net_device *netdev, + stats->tx_bytes += data[1]; + stats->tx_errors += data[2]; + } +- +- return stats; + } + + static bool nfp_net_ebpf_capable(struct nfp_net *nn) +diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c +index 9b0d7f46..d7a07928 100644 +--- a/drivers/net/ethernet/nvidia/forcedeth.c ++++ b/drivers/net/ethernet/nvidia/forcedeth.c +@@ -1733,7 +1733,7 @@ static void nv_update_stats(struct net_device *dev) + * Called with read_lock(&dev_base_lock) held for read - + * only synchronized against unregister_netdevice. + */ +-static struct rtnl_link_stats64* ++static void + nv_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *storage) + __acquires(&netdev_priv(dev)->hwstats_lock) + __releases(&netdev_priv(dev)->hwstats_lock) +@@ -1793,8 +1793,6 @@ nv_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *storage) + + spin_unlock_bh(&np->hwstats_lock); + } +- +- return storage; + } + + /* +diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +index 7a0281a3..8bb16d64 100644 +--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c ++++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +@@ -90,8 +90,8 @@ static irqreturn_t netxen_msix_intr(int irq, void *data); + + static void netxen_free_ip_list(struct netxen_adapter *, bool); + static void netxen_restore_indev_addr(struct net_device *dev, unsigned long); +-static struct rtnl_link_stats64 *netxen_nic_get_stats(struct net_device *dev, +- struct rtnl_link_stats64 *stats); ++static void netxen_nic_get_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *stats); + static int netxen_nic_set_mac(struct net_device *netdev, void *p); + + /* PCI Device ID Table */ +@@ -2295,8 +2295,8 @@ static void netxen_tx_timeout_task(struct work_struct *work) + clear_bit(__NX_RESETTING, &adapter->state); + } + +-static struct rtnl_link_stats64 *netxen_nic_get_stats(struct net_device *netdev, +- struct rtnl_link_stats64 *stats) ++static void netxen_nic_get_stats(struct net_device *netdev, ++ struct rtnl_link_stats64 *stats) + { + struct netxen_adapter *adapter = netdev_priv(netdev); + +@@ -2306,8 +2306,6 @@ static struct rtnl_link_stats64 *netxen_nic_get_stats(struct net_device *netdev, + stats->tx_bytes = adapter->stats.txbytes; + stats->rx_dropped = adapter->stats.rxdropped; + stats->tx_dropped = adapter->stats.txdropped; +- +- return stats; + } + + static irqreturn_t netxen_intr(int irq, void *data) +diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c +index 85f46dbe..645507a9 100644 +--- a/drivers/net/ethernet/qlogic/qede/qede_main.c ++++ b/drivers/net/ethernet/qlogic/qede/qede_main.c +@@ -1803,9 +1803,8 @@ void qede_fill_by_demand_stats(struct qede_dev *edev) + edev->stats.tx_mac_ctrl_frames = stats.tx_mac_ctrl_frames; + } + +-static +-struct rtnl_link_stats64 *qede_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *stats) ++static void qede_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + struct qede_dev *edev = netdev_priv(dev); + +@@ -1835,8 +1834,6 @@ struct rtnl_link_stats64 *qede_get_stats64(struct net_device *dev, + stats->collisions = edev->stats.tx_total_collisions; + stats->rx_crc_errors = edev->stats.rx_crc_errors; + stats->rx_frame_errors = edev->stats.rx_align_errors; +- +- return stats; + } + + #ifdef CONFIG_QED_SRIOV +diff --git a/drivers/net/ethernet/qualcomm/emac/emac.c b/drivers/net/ethernet/qualcomm/emac/emac.c +index 57b35aea..babc1025 100644 +--- a/drivers/net/ethernet/qualcomm/emac/emac.c ++++ b/drivers/net/ethernet/qualcomm/emac/emac.c +@@ -319,8 +319,8 @@ static int emac_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) + } + + /* Provide network statistics info for the interface */ +-static struct rtnl_link_stats64 *emac_get_stats64(struct net_device *netdev, +- struct rtnl_link_stats64 *net_stats) ++static void emac_get_stats64(struct net_device *netdev, ++ struct rtnl_link_stats64 *net_stats) + { + struct emac_adapter *adpt = netdev_priv(netdev); + unsigned int addr = REG_MAC_RX_STATUS_BIN; +@@ -384,8 +384,6 @@ static struct rtnl_link_stats64 *emac_get_stats64(struct net_device *netdev, + net_stats->tx_window_errors = stats->tx_late_col; + + spin_unlock(&stats->lock); +- +- return net_stats; + } + + static const struct net_device_ops emac_netdev_ops = { +diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c +index da4c2d8a..5722e187 100644 +--- a/drivers/net/ethernet/realtek/8139too.c ++++ b/drivers/net/ethernet/realtek/8139too.c +@@ -653,9 +653,8 @@ static int rtl8139_poll(struct napi_struct *napi, int budget); + static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance); + static int rtl8139_close (struct net_device *dev); + static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd); +-static struct rtnl_link_stats64 *rtl8139_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 +- *stats); ++static void rtl8139_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats); + static void rtl8139_set_rx_mode (struct net_device *dev); + static void __set_rx_mode (struct net_device *dev); + static void rtl8139_hw_start (struct net_device *dev); +@@ -2521,7 +2520,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) + } + + +-static struct rtnl_link_stats64 * ++static void + rtl8139_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + { + struct rtl8139_private *tp = netdev_priv(dev); +@@ -2549,8 +2548,6 @@ rtl8139_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + stats->tx_packets = tp->tx_stats.packets; + stats->tx_bytes = tp->tx_stats.bytes; + } while (u64_stats_fetch_retry_irq(&tp->tx_stats.syncp, start)); +- +- return stats; + } + + /* Set or clear the multicast filter for this adaptor. +diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c +index 2c4350a1..ac7eab06 100644 +--- a/drivers/net/ethernet/realtek/r8169.c ++++ b/drivers/net/ethernet/realtek/r8169.c +@@ -7751,7 +7751,7 @@ static int rtl_open(struct net_device *dev) + goto out; + } + +-static struct rtnl_link_stats64 * ++static void + rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + { + struct rtl8169_private *tp = netdev_priv(dev); +@@ -7805,8 +7805,6 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + le16_to_cpu(tp->tc_offset.tx_aborted); + + pm_runtime_put_noidle(&pdev->dev); +- +- return stats; + } + + static void rtl8169_net_suspend(struct net_device *dev) +diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +index ea44a245..49196846 100644 +--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c ++++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c +@@ -1721,11 +1721,9 @@ static inline u64 sxgbe_get_stat64(void __iomem *ioaddr, int reg_lo, int reg_hi) + * This function is a driver entry point whenever ifconfig command gets + * executed to see device statistics. Statistics are number of + * bytes sent or received, errors occurred etc. +- * Return value: +- * This function returns various statistical information of device. + */ +-static struct rtnl_link_stats64 *sxgbe_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *stats) ++static void sxgbe_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + struct sxgbe_priv_data *priv = netdev_priv(dev); + void __iomem *ioaddr = priv->ioaddr; +@@ -1776,8 +1774,6 @@ static struct rtnl_link_stats64 *sxgbe_get_stats64(struct net_device *dev, + SXGBE_MMC_TXUFLWHI_GBCNT_REG); + writel(0, ioaddr + SXGBE_MMC_CTL_REG); + spin_unlock(&priv->stats_lock); +- +- return stats; + } + + /* sxgbe_set_features - entry point to set offload features of the device. +diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c +index 6b89e4a7..c6209dd4 100644 +--- a/drivers/net/ethernet/sfc/efx.c ++++ b/drivers/net/ethernet/sfc/efx.c +@@ -2232,16 +2232,14 @@ int efx_net_stop(struct net_device *net_dev) + } + + /* Context: process, dev_base_lock or RTNL held, non-blocking. */ +-static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev, +- struct rtnl_link_stats64 *stats) ++static void efx_net_stats(struct net_device *net_dev, ++ struct rtnl_link_stats64 *stats) + { + struct efx_nic *efx = netdev_priv(net_dev); + + spin_lock_bh(&efx->stats_lock); + efx->type->update_stats(efx, NULL, stats); + spin_unlock_bh(&efx->stats_lock); +- +- return stats; + } + + /* Context: netif_tx_lock held, BHs disabled. */ +diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c +index a2371aa1..680fc756 100644 +--- a/drivers/net/ethernet/sun/niu.c ++++ b/drivers/net/ethernet/sun/niu.c +@@ -6294,8 +6294,8 @@ static void niu_get_tx_stats(struct niu *np, + stats->tx_errors = errors; + } + +-static struct rtnl_link_stats64 *niu_get_stats(struct net_device *dev, +- struct rtnl_link_stats64 *stats) ++static void niu_get_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + struct niu *np = netdev_priv(dev); + +@@ -6303,8 +6303,6 @@ static struct rtnl_link_stats64 *niu_get_stats(struct net_device *dev, + niu_get_rx_stats(np, stats); + niu_get_tx_stats(np, stats); + } +- +- return stats; + } + + static void niu_load_hash_xmac(struct niu *np, u16 *hash) +diff --git a/drivers/net/ethernet/synopsys/dwc_eth_qos.c b/drivers/net/ethernet/synopsys/dwc_eth_qos.c +index 97d64bfe..bcacd08c 100644 +--- a/drivers/net/ethernet/synopsys/dwc_eth_qos.c ++++ b/drivers/net/ethernet/synopsys/dwc_eth_qos.c +@@ -2490,7 +2490,7 @@ static void dwceqos_read_mmc_counters(struct net_local *lp, u32 rx_mask, + dwceqos_read(lp, DWC_MMC_RXPACKETCOUNT_GB); + } + +-static struct rtnl_link_stats64* ++static void + dwceqos_get_stats64(struct net_device *ndev, struct rtnl_link_stats64 *s) + { + unsigned long flags; +@@ -2522,8 +2522,6 @@ dwceqos_get_stats64(struct net_device *ndev, struct rtnl_link_stats64 *s) + else + s->tx_errors = hwstats->txunderflowerror + + hwstats->txcarriererror; +- +- return s; + } + + static void +diff --git a/drivers/net/ethernet/tile/tilepro.c b/drivers/net/ethernet/tile/tilepro.c +index 4ef605a9..9cd7cd3c 100644 +--- a/drivers/net/ethernet/tile/tilepro.c ++++ b/drivers/net/ethernet/tile/tilepro.c +@@ -2047,8 +2047,8 @@ static int tile_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) + * + * Returns the address of the device statistics structure. + */ +-static struct rtnl_link_stats64 *tile_net_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *stats) ++static void tile_net_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + struct tile_net_priv *priv = netdev_priv(dev); + u64 rx_packets = 0, tx_packets = 0; +diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c +index 9d14731c..ae891364 100644 +--- a/drivers/net/ethernet/via/via-rhine.c ++++ b/drivers/net/ethernet/via/via-rhine.c +@@ -513,8 +513,8 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance); + static void rhine_tx(struct net_device *dev); + static int rhine_rx(struct net_device *dev, int limit); + static void rhine_set_rx_mode(struct net_device *dev); +-static struct rtnl_link_stats64 *rhine_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *stats); ++static void rhine_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats); + static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); + static const struct ethtool_ops netdev_ethtool_ops; + static int rhine_close(struct net_device *dev); +@@ -2222,7 +2222,7 @@ static void rhine_slow_event_task(struct work_struct *work) + mutex_unlock(&rp->task_lock); + } + +-static struct rtnl_link_stats64 * ++static void + rhine_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + { + struct rhine_private *rp = netdev_priv(dev); +@@ -2245,8 +2245,6 @@ rhine_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + stats->tx_packets = rp->tx_stats.packets; + stats->tx_bytes = rp->tx_stats.bytes; + } while (u64_stats_fetch_retry_irq(&rp->tx_stats.syncp, start)); +- +- return stats; + } + + static void rhine_set_rx_mode(struct net_device *dev) +diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c +index e46b1ebb..6b944caf 100644 +--- a/drivers/net/fjes/fjes_main.c ++++ b/drivers/net/fjes/fjes_main.c +@@ -56,8 +56,7 @@ static void fjes_raise_intr_rxdata_task(struct work_struct *); + static void fjes_tx_stall_task(struct work_struct *); + static void fjes_force_close_task(struct work_struct *); + static irqreturn_t fjes_intr(int, void*); +-static struct rtnl_link_stats64 * +-fjes_get_stats64(struct net_device *, struct rtnl_link_stats64 *); ++static void fjes_get_stats64(struct net_device *, struct rtnl_link_stats64 *); + static int fjes_change_mtu(struct net_device *, int); + static int fjes_vlan_rx_add_vid(struct net_device *, __be16 proto, u16); + static int fjes_vlan_rx_kill_vid(struct net_device *, __be16 proto, u16); +@@ -762,14 +761,12 @@ static void fjes_tx_retry(struct net_device *netdev) + netif_tx_wake_queue(queue); + } + +-static struct rtnl_link_stats64 * ++static void + fjes_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) + { + struct fjes_adapter *adapter = netdev_priv(netdev); + + memcpy(stats, &adapter->stats64, sizeof(struct rtnl_link_stats64)); +- +- return stats; + } + + static int fjes_change_mtu(struct net_device *netdev, int new_mtu) +diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c +index 36a04e18..48f20945 100644 +--- a/drivers/net/hyperv/netvsc_drv.c ++++ b/drivers/net/hyperv/netvsc_drv.c +@@ -918,8 +918,8 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) + return ret; + } + +-static struct rtnl_link_stats64 *netvsc_get_stats64(struct net_device *net, +- struct rtnl_link_stats64 *t) ++static void netvsc_get_stats64(struct net_device *net, ++ struct rtnl_link_stats64 *t) + { + struct net_device_context *ndev_ctx = netdev_priv(net); + int cpu; +@@ -957,8 +957,6 @@ static struct rtnl_link_stats64 *netvsc_get_stats64(struct net_device *net, + + t->rx_dropped = net->stats.rx_dropped; + t->rx_errors = net->stats.rx_errors; +- +- return t; + } + + static int netvsc_set_mac_addr(struct net_device *ndev, void *p) +diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c +index 66c0eeaf..082534e1 100644 +--- a/drivers/net/ifb.c ++++ b/drivers/net/ifb.c +@@ -129,8 +129,8 @@ static void ifb_ri_tasklet(unsigned long _txp) + + } + +-static struct rtnl_link_stats64 *ifb_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *stats) ++static void ifb_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + struct ifb_dev_private *dp = netdev_priv(dev); + struct ifb_q_private *txp = dp->tx_private; +@@ -157,8 +157,6 @@ static struct rtnl_link_stats64 *ifb_stats64(struct net_device *dev, + } + stats->rx_dropped = dev->stats.rx_dropped; + stats->tx_dropped = dev->stats.tx_dropped; +- +- return stats; + } + + static int ifb_dev_init(struct net_device *dev) +diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c +index dfbc4ef6..6629680d 100644 +--- a/drivers/net/ipvlan/ipvlan_main.c ++++ b/drivers/net/ipvlan/ipvlan_main.c +@@ -296,8 +296,8 @@ static void ipvlan_set_multicast_mac_filter(struct net_device *dev) + dev_mc_sync(ipvlan->phy_dev, dev); + } + +-static struct rtnl_link_stats64 *ipvlan_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *s) ++static void ipvlan_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *s) + { + struct ipvl_dev *ipvlan = netdev_priv(dev); + +@@ -334,7 +334,6 @@ static struct rtnl_link_stats64 *ipvlan_get_stats64(struct net_device *dev, + s->rx_dropped = rx_errs; + s->tx_dropped = tx_drps; + } +- return s; + } + + static int ipvlan_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid) +diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c +index 1b65f0f9..0254b2a9 100644 +--- a/drivers/net/loopback.c ++++ b/drivers/net/loopback.c +@@ -97,8 +97,8 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb, + return NETDEV_TX_OK; + } + +-static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *stats) ++static void loopback_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + u64 bytes = 0; + u64 packets = 0; +@@ -122,7 +122,6 @@ static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev, + stats->tx_packets = packets; + stats->rx_bytes = bytes; + stats->tx_bytes = bytes; +- return stats; + } + + static u32 always_on(struct net_device *dev) +diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c +index 2caac0c3..880ee985 100644 +--- a/drivers/net/macsec.c ++++ b/drivers/net/macsec.c +@@ -2899,13 +2899,13 @@ static int macsec_change_mtu(struct net_device *dev, int new_mtu) + return 0; + } + +-static struct rtnl_link_stats64 *macsec_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *s) ++static void macsec_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *s) + { + int cpu; + + if (!dev->tstats) +- return s; ++ return; + + for_each_possible_cpu(cpu) { + struct pcpu_sw_netstats *stats; +@@ -2929,8 +2929,6 @@ static struct rtnl_link_stats64 *macsec_get_stats64(struct net_device *dev, + + s->rx_dropped = dev->stats.rx_dropped; + s->tx_dropped = dev->stats.tx_dropped; +- +- return s; + } + + static int macsec_get_iflink(const struct net_device *dev) +diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c +index dc8ccac0..94576142 100644 +--- a/drivers/net/macvlan.c ++++ b/drivers/net/macvlan.c +@@ -857,8 +857,8 @@ static void macvlan_uninit(struct net_device *dev) + macvlan_port_destroy(port->dev); + } + +-static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *stats) ++static void macvlan_dev_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + struct macvlan_dev *vlan = netdev_priv(dev); + +@@ -895,7 +895,6 @@ static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev, + stats->rx_dropped = rx_errors; + stats->tx_dropped = tx_dropped; + } +- return stats; + } + + static int macvlan_vlan_rx_add_vid(struct net_device *dev, +diff --git a/drivers/net/nlmon.c b/drivers/net/nlmon.c +index 7b7c70e2..a0daed8a 100644 +--- a/drivers/net/nlmon.c ++++ b/drivers/net/nlmon.c +@@ -76,7 +76,7 @@ static int nlmon_close(struct net_device *dev) + return netlink_remove_tap(&nlmon->nt); + } + +-static struct rtnl_link_stats64 * ++static void + nlmon_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + { + int i; +@@ -104,8 +104,6 @@ nlmon_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + + stats->rx_bytes = bytes; + stats->tx_bytes = 0; +- +- return stats; + } + + static u32 always_on(struct net_device *dev) +diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c +index 96fa0e61..d3b17318 100644 +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -1312,7 +1312,7 @@ ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) + return err; + } + +-static struct rtnl_link_stats64* ++static void + ppp_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats64) + { + struct ppp *ppp = netdev_priv(dev); +@@ -1332,8 +1332,6 @@ ppp_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats64) + stats64->rx_dropped = dev->stats.rx_dropped; + stats64->tx_dropped = dev->stats.tx_dropped; + stats64->rx_length_errors = dev->stats.rx_length_errors; +- +- return stats64; + } + + static int ppp_dev_init(struct net_device *dev) +diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c +index 9ed6d1c1..c8c0c231 100644 +--- a/drivers/net/slip/slip.c ++++ b/drivers/net/slip/slip.c +@@ -571,7 +571,7 @@ static int sl_change_mtu(struct net_device *dev, int new_mtu) + + /* Netdevice get statistics request */ + +-static struct rtnl_link_stats64 * ++static void + sl_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + { + struct net_device_stats *devstats = &dev->stats; +@@ -602,7 +602,6 @@ sl_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + stats->collisions += comp->sls_o_misses; + } + #endif +- return stats; + } + + /* Netdevice register callback */ +diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c +index a380649b..95499313 100644 +--- a/drivers/net/team/team.c ++++ b/drivers/net/team/team.c +@@ -1798,7 +1798,7 @@ static int team_change_mtu(struct net_device *dev, int new_mtu) + return err; + } + +-static struct rtnl_link_stats64 * ++static void + team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + { + struct team *team = netdev_priv(dev); +@@ -1835,7 +1835,6 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + stats->rx_dropped = rx_dropped; + stats->tx_dropped = tx_dropped; + stats->rx_nohandler = rx_nohandler; +- return stats; + } + + static int team_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid) +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index a931b733..19fb25b1 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -983,7 +983,7 @@ static void tun_set_headroom(struct net_device *dev, int new_hr) + tun->align = new_hr; + } + +-static struct rtnl_link_stats64 * ++static void + tun_net_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + { + u32 rx_dropped = 0, tx_dropped = 0, rx_frame_errors = 0; +@@ -1017,7 +1017,6 @@ tun_net_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + stats->rx_dropped = rx_dropped; + stats->rx_frame_errors = rx_frame_errors; + stats->tx_dropped = tx_dropped; +- return stats; + } + + static const struct net_device_ops tun_netdev_ops = { +diff --git a/drivers/net/veth.c b/drivers/net/veth.c +index fbc853e6..e25aa62d 100644 +--- a/drivers/net/veth.c ++++ b/drivers/net/veth.c +@@ -161,8 +161,8 @@ static u64 veth_stats_one(struct pcpu_vstats *result, struct net_device *dev) + return atomic64_read(&priv->dropped); + } + +-static struct rtnl_link_stats64 *veth_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *tot) ++static void veth_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *tot) + { + struct veth_priv *priv = netdev_priv(dev); + struct net_device *peer; +@@ -180,8 +180,6 @@ static struct rtnl_link_stats64 *veth_get_stats64(struct net_device *dev, + tot->rx_packets = one.packets; + } + rcu_read_unlock(); +- +- return tot; + } + + /* fake multicast ability */ +diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c +index 1568aedd..15e87add 100644 +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -1017,8 +1017,8 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p) + return ret; + } + +-static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev, +- struct rtnl_link_stats64 *tot) ++static void virtnet_stats(struct net_device *dev, ++ struct rtnl_link_stats64 *tot) + { + struct virtnet_info *vi = netdev_priv(dev); + int cpu; +@@ -1051,8 +1051,6 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev, + tot->rx_dropped = dev->stats.rx_dropped; + tot->rx_length_errors = dev->stats.rx_length_errors; + tot->rx_frame_errors = dev->stats.rx_frame_errors; +- +- return tot; + } + + #ifdef CONFIG_NET_POLL_CONTROLLER +diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c +index aabc6ef3..f88ffafe 100644 +--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c ++++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c +@@ -113,7 +113,7 @@ vmxnet3_global_stats[] = { + }; + + +-struct rtnl_link_stats64 * ++void + vmxnet3_get_stats64(struct net_device *netdev, + struct rtnl_link_stats64 *stats) + { +@@ -160,8 +160,6 @@ vmxnet3_get_stats64(struct net_device *netdev, + stats->rx_dropped += drvRxStats->drop_total; + stats->multicast += devRxStats->mcastPktsRxOK; + } +- +- return stats; + } + + static int +diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h +index 7dc37a09..ec19df56 100644 +--- a/drivers/net/vmxnet3/vmxnet3_int.h ++++ b/drivers/net/vmxnet3/vmxnet3_int.h +@@ -466,8 +466,8 @@ vmxnet3_create_queues(struct vmxnet3_adapter *adapter, + + void vmxnet3_set_ethtool_ops(struct net_device *netdev); + +-struct rtnl_link_stats64 * +-vmxnet3_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats); ++void vmxnet3_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats); + + extern char vmxnet3_driver_name[]; + #endif +diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c +index 578bd500..499af07a 100644 +--- a/drivers/net/vrf.c ++++ b/drivers/net/vrf.c +@@ -79,8 +79,8 @@ static void vrf_tx_error(struct net_device *vrf_dev, struct sk_buff *skb) + kfree_skb(skb); + } + +-static struct rtnl_link_stats64 *vrf_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *stats) ++static void vrf_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + int i; + +@@ -104,7 +104,6 @@ static struct rtnl_link_stats64 *vrf_get_stats64(struct net_device *dev, + stats->rx_bytes += rbytes; + stats->rx_packets += rpkts; + } +- return stats; + } + + /* Local traffic destined to local address. Reinsert the packet to rx +diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c +index cd442e46..f87cae7e 100644 +--- a/drivers/net/xen-netfront.c ++++ b/drivers/net/xen-netfront.c +@@ -1081,8 +1081,8 @@ static int xennet_change_mtu(struct net_device *dev, int mtu) + return 0; + } + +-static struct rtnl_link_stats64 *xennet_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *tot) ++static void xennet_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *tot) + { + struct netfront_info *np = netdev_priv(dev); + int cpu; +@@ -1113,8 +1113,6 @@ static struct rtnl_link_stats64 *xennet_get_stats64(struct net_device *dev, + + tot->rx_errors = dev->stats.rx_errors; + tot->tx_dropped = dev->stats.tx_dropped; +- +- return tot; + } + + static void xennet_release_tx_bufs(struct netfront_queue *queue) +diff --git a/drivers/staging/netlogic/xlr_net.c b/drivers/staging/netlogic/xlr_net.c +index 552a7dcb..d7dea9d4 100644 +--- a/drivers/staging/netlogic/xlr_net.c ++++ b/drivers/staging/netlogic/xlr_net.c +@@ -395,14 +395,6 @@ static void xlr_stats(struct net_device *ndev, struct rtnl_link_stats64 *stats) + TX_DROP_FRAME_COUNTER); + } + +-static struct rtnl_link_stats64 *xlr_get_stats64(struct net_device *ndev, +- struct rtnl_link_stats64 *stats +- ) +-{ +- xlr_stats(ndev, stats); +- return stats; +-} +- + static const struct net_device_ops xlr_netdev_ops = { + .ndo_open = xlr_net_open, + .ndo_stop = xlr_net_stop, +@@ -410,7 +402,7 @@ static const struct net_device_ops xlr_netdev_ops = { + .ndo_select_queue = xlr_net_select_queue, + .ndo_set_mac_address = xlr_net_set_mac_addr, + .ndo_set_rx_mode = xlr_set_rx_mode, +- .ndo_get_stats64 = xlr_get_stats64, ++ .ndo_get_stats64 = xlr_stats, + }; + + /* +diff --git a/include/linux/device.h b/include/linux/device.h +index 8d732965..6d206930 100644 +--- a/include/linux/device.h ++++ b/include/linux/device.h +@@ -688,6 +688,25 @@ void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res); + int devm_add_action(struct device *dev, void (*action)(void *), void *data); + void devm_remove_action(struct device *dev, void (*action)(void *), void *data); + ++/** ++ * devm_alloc_percpu - Resource-managed alloc_percpu ++ * @dev: Device to allocate per-cpu memory for ++ * @type: Type to allocate per-cpu memory for ++ * ++ * Managed alloc_percpu. Per-cpu memory allocated with this function is ++ * automatically freed on driver detach. ++ * ++ * RETURNS: ++ * Pointer to allocated memory on success, NULL on failure. ++ */ ++#define devm_alloc_percpu(dev, type) \ ++ ((typeof(type) __percpu *)__devm_alloc_percpu((dev), sizeof(type), \ ++ __alignof__(type))) ++ ++void __percpu *__devm_alloc_percpu(struct device *dev, size_t size, ++ size_t align); ++void devm_free_percpu(struct device *dev, void __percpu *pdata); ++ + static inline int devm_add_action_or_reset(struct device *dev, + void (*action)(void *), void *data) + { +diff --git a/include/linux/fsl/svr.h b/include/linux/fsl/svr.h +new file mode 100644 +index 00000000..e95c8f43 +--- /dev/null ++++ b/include/linux/fsl/svr.h +@@ -0,0 +1,97 @@ ++/* ++ * MPC85xx cpu type detection ++ * ++ * Copyright 2011-2012 Freescale Semiconductor, Inc. ++ * ++ * This 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. ++ */ ++ ++#ifndef FSL_SVR_H ++#define FSL_SVR_H ++ ++#define SVR_REV(svr) ((svr) & 0xFF) /* SOC design resision */ ++#define SVR_MAJ(svr) (((svr) >> 4) & 0xF) /* Major revision field*/ ++#define SVR_MIN(svr) (((svr) >> 0) & 0xF) /* Minor revision field*/ ++ ++/* Some parts define SVR[0:23] as the SOC version */ ++#define SVR_SOC_VER(svr) (((svr) >> 8) & 0xFFF7FF) /* SOC Version fields */ ++ ++#define SVR_8533 0x803400 ++#define SVR_8535 0x803701 ++#define SVR_8536 0x803700 ++#define SVR_8540 0x803000 ++#define SVR_8541 0x807200 ++#define SVR_8543 0x803200 ++#define SVR_8544 0x803401 ++#define SVR_8545 0x803102 ++#define SVR_8547 0x803101 ++#define SVR_8548 0x803100 ++#define SVR_8555 0x807100 ++#define SVR_8560 0x807000 ++#define SVR_8567 0x807501 ++#define SVR_8568 0x807500 ++#define SVR_8569 0x808000 ++#define SVR_8572 0x80E000 ++#define SVR_P1010 0x80F100 ++#define SVR_P1011 0x80E500 ++#define SVR_P1012 0x80E501 ++#define SVR_P1013 0x80E700 ++#define SVR_P1014 0x80F101 ++#define SVR_P1017 0x80F700 ++#define SVR_P1020 0x80E400 ++#define SVR_P1021 0x80E401 ++#define SVR_P1022 0x80E600 ++#define SVR_P1023 0x80F600 ++#define SVR_P1024 0x80E402 ++#define SVR_P1025 0x80E403 ++#define SVR_P2010 0x80E300 ++#define SVR_P2020 0x80E200 ++#define SVR_P2040 0x821000 ++#define SVR_P2041 0x821001 ++#define SVR_P3041 0x821103 ++#define SVR_P4040 0x820100 ++#define SVR_P4080 0x820000 ++#define SVR_P5010 0x822100 ++#define SVR_P5020 0x822000 ++#define SVR_P5021 0X820500 ++#define SVR_P5040 0x820400 ++#define SVR_T4240 0x824000 ++#define SVR_T4120 0x824001 ++#define SVR_T4160 0x824100 ++#define SVR_T4080 0x824102 ++#define SVR_C291 0x850000 ++#define SVR_C292 0x850020 ++#define SVR_C293 0x850030 ++#define SVR_B4860 0X868000 ++#define SVR_G4860 0x868001 ++#define SVR_G4060 0x868003 ++#define SVR_B4440 0x868100 ++#define SVR_G4440 0x868101 ++#define SVR_B4420 0x868102 ++#define SVR_B4220 0x868103 ++#define SVR_T1040 0x852000 ++#define SVR_T1041 0x852001 ++#define SVR_T1042 0x852002 ++#define SVR_T1020 0x852100 ++#define SVR_T1021 0x852101 ++#define SVR_T1022 0x852102 ++#define SVR_T1023 0x854100 ++#define SVR_T1024 0x854000 ++#define SVR_T2080 0x853000 ++#define SVR_T2081 0x853100 ++ ++#define SVR_8610 0x80A000 ++#define SVR_8641 0x809000 ++#define SVR_8641D 0x809001 ++ ++#define SVR_9130 0x860001 ++#define SVR_9131 0x860000 ++#define SVR_9132 0x861000 ++#define SVR_9232 0x861400 ++ ++#define SVR_Unknown 0xFFFFFF ++ ++#endif +diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h +index f2912914..22308465 100644 +--- a/include/linux/fsl_devices.h ++++ b/include/linux/fsl_devices.h +@@ -99,7 +99,10 @@ struct fsl_usb2_platform_data { + unsigned suspended:1; + unsigned already_suspended:1; + unsigned has_fsl_erratum_a007792:1; ++ unsigned has_fsl_erratum_14:1; + unsigned has_fsl_erratum_a005275:1; ++ unsigned has_fsl_erratum_a006918:1; ++ unsigned has_fsl_erratum_a005697:1; + unsigned check_phy_clk_valid:1; + + /* register save area for suspend/resume */ +diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h +index 9c6c8ef2..90b4107e 100644 +--- a/include/linux/netdev_features.h ++++ b/include/linux/netdev_features.h +@@ -74,6 +74,7 @@ enum { + NETIF_F_BUSY_POLL_BIT, /* Busy poll */ + + NETIF_F_HW_TC_BIT, /* Offload TC infrastructure */ ++ NETIF_F_HW_ACCEL_MQ_BIT, /* Hardware-accelerated multiqueue */ + + /* + * Add your fresh new feature above and remember to update +@@ -136,6 +137,7 @@ enum { + #define NETIF_F_HW_L2FW_DOFFLOAD __NETIF_F(HW_L2FW_DOFFLOAD) + #define NETIF_F_BUSY_POLL __NETIF_F(BUSY_POLL) + #define NETIF_F_HW_TC __NETIF_F(HW_TC) ++#define NETIF_F_HW_ACCEL_MQ __NETIF_F(HW_ACCEL_MQ) + + #define for_each_netdev_feature(mask_addr, bit) \ + for_each_set_bit(bit, (unsigned long *)mask_addr, NETDEV_FEATURE_COUNT) +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index c3a1537c..67ef59d0 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -916,8 +916,8 @@ struct netdev_xdp { + * Callback used when the transmitter has not made any progress + * for dev->watchdog ticks. + * +- * struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev, +- * struct rtnl_link_stats64 *storage); ++ * void (*ndo_get_stats64)(struct net_device *dev, ++ * struct rtnl_link_stats64 *storage); + * struct net_device_stats* (*ndo_get_stats)(struct net_device *dev); + * Called when a user wants to get the network device usage + * statistics. Drivers must do one of the following: +@@ -1165,8 +1165,8 @@ struct net_device_ops { + struct neigh_parms *); + void (*ndo_tx_timeout) (struct net_device *dev); + +- struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev, +- struct rtnl_link_stats64 *storage); ++ void (*ndo_get_stats64)(struct net_device *dev, ++ struct rtnl_link_stats64 *storage); + bool (*ndo_has_offload_stats)(int attr_id); + int (*ndo_get_offload_stats)(int attr_id, + const struct net_device *dev, +@@ -1509,6 +1509,8 @@ enum netdev_priv_flags { + * @if_port: Selectable AUI, TP, ... + * @dma: DMA channel + * @mtu: Interface MTU value ++ * @min_mtu: Interface Minimum MTU value ++ * @max_mtu: Interface Maximum MTU value + * @type: Interface hardware type + * @hard_header_len: Maximum hardware header length. + * @min_header_len: Minimum hardware header length +@@ -1735,6 +1737,8 @@ struct net_device { + unsigned char dma; + + unsigned int mtu; ++ unsigned int min_mtu; ++ unsigned int max_mtu; + unsigned short type; + unsigned short hard_header_len; + unsigned short min_header_len; +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index 9a0c945e..06f33c98 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -903,6 +903,7 @@ void kfree_skb(struct sk_buff *skb); + void kfree_skb_list(struct sk_buff *segs); + void skb_tx_error(struct sk_buff *skb); + void consume_skb(struct sk_buff *skb); ++void skb_recycle(struct sk_buff *skb); + void __kfree_skb(struct sk_buff *skb); + extern struct kmem_cache *skbuff_head_cache; + +@@ -3057,6 +3058,7 @@ static inline void skb_free_datagram_locked(struct sock *sk, + } + int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags); + int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len); ++void copy_skb_header(struct sk_buff *new, const struct sk_buff *old); + int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len); + __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, + int len, __wsum csum); +diff --git a/include/linux/sys_soc.h b/include/linux/sys_soc.h +index 2739ccb6..9f5eb06f 100644 +--- a/include/linux/sys_soc.h ++++ b/include/linux/sys_soc.h +@@ -13,6 +13,7 @@ struct soc_device_attribute { + const char *family; + const char *revision; + const char *soc_id; ++ const void *data; + }; + + /** +@@ -34,4 +35,6 @@ void soc_device_unregister(struct soc_device *soc_dev); + */ + struct device *soc_device_to_device(struct soc_device *soc); + ++const struct soc_device_attribute *soc_device_match( ++ const struct soc_device_attribute *matches); + #endif /* __SOC_BUS_H */ +diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h +index 59557c07..876de4f9 100644 +--- a/include/net/ip_tunnels.h ++++ b/include/net/ip_tunnels.h +@@ -261,8 +261,8 @@ int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd); + int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict); + int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu); + +-struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *tot); ++void ip_tunnel_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *tot); + struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, + int link, __be16 flags, + __be32 remote, __be32 local, +diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h +index 51f38442..5c01afbf 100644 +--- a/include/uapi/linux/if_ether.h ++++ b/include/uapi/linux/if_ether.h +@@ -35,6 +35,7 @@ + #define ETH_DATA_LEN 1500 /* Max. octets in payload */ + #define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ + #define ETH_FCS_LEN 4 /* Octets in the FCS */ ++#define ETH_MIN_MTU 68 /* Min IPv4 MTU per RFC791 */ + + /* + * These are the defined Ethernet Protocol ID's. +diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c +index fbfacd51..ca3cf29b 100644 +--- a/net/8021q/vlan_dev.c ++++ b/net/8021q/vlan_dev.c +@@ -671,7 +671,8 @@ static int vlan_ethtool_get_ts_info(struct net_device *dev, + return 0; + } + +-static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) ++static void vlan_dev_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + struct vlan_pcpu_stats *p; + u32 rx_errors = 0, tx_dropped = 0; +@@ -702,8 +703,6 @@ static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, st + } + stats->rx_errors = rx_errors; + stats->tx_dropped = tx_dropped; +- +- return stats; + } + + #ifdef CONFIG_NET_POLL_CONTROLLER +diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c +index 5f5e28f2..73d66ae3 100644 +--- a/net/bridge/br_device.c ++++ b/net/bridge/br_device.c +@@ -156,8 +156,8 @@ static int br_dev_stop(struct net_device *dev) + return 0; + } + +-static struct rtnl_link_stats64 *br_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *stats) ++static void br_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + struct net_bridge *br = netdev_priv(dev); + struct pcpu_sw_netstats tmp, sum = { 0 }; +@@ -181,8 +181,6 @@ static struct rtnl_link_stats64 *br_get_stats64(struct net_device *dev, + stats->tx_packets = sum.tx_packets; + stats->rx_bytes = sum.rx_bytes; + stats->rx_packets = sum.rx_packets; +- +- return stats; + } + + static int br_change_mtu(struct net_device *dev, int new_mtu) +diff --git a/net/core/dev.c b/net/core/dev.c +index 912f40ac..17e16cf7 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -6600,9 +6600,18 @@ int dev_set_mtu(struct net_device *dev, int new_mtu) + if (new_mtu == dev->mtu) + return 0; + +- /* MTU must be positive. */ +- if (new_mtu < 0) ++ /* MTU must be positive, and in range */ ++ if (new_mtu < 0 || new_mtu < dev->min_mtu) { ++ net_err_ratelimited("%s: Invalid MTU %d requested, hw min %d\n", ++ dev->name, new_mtu, dev->min_mtu); + return -EINVAL; ++ } ++ ++ if (dev->max_mtu > 0 && new_mtu > dev->max_mtu) { ++ net_err_ratelimited("%s: Invalid MTU %d requested, hw max %d\n", ++ dev->name, new_mtu, dev->min_mtu); ++ return -EINVAL; ++ } + + if (!netif_device_present(dev)) + return -ENODEV; +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 7e7b7ce0..0f9c014a 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -842,6 +842,32 @@ void napi_consume_skb(struct sk_buff *skb, int budget) + } + EXPORT_SYMBOL(napi_consume_skb); + ++/** ++ * skb_recycle - clean up an skb for reuse ++ * @skb: buffer ++ * ++ * Recycles the skb to be reused as a receive buffer. This ++ * function does any necessary reference count dropping, and ++ * cleans up the skbuff as if it just came from __alloc_skb(). ++ */ ++void skb_recycle(struct sk_buff *skb) ++{ ++ struct skb_shared_info *shinfo; ++ u8 head_frag = skb->head_frag; ++ ++ skb_release_head_state(skb); ++ ++ shinfo = skb_shinfo(skb); ++ memset(shinfo, 0, offsetof(struct skb_shared_info, dataref)); ++ atomic_set(&shinfo->dataref, 1); ++ ++ memset(skb, 0, offsetof(struct sk_buff, tail)); ++ skb->data = skb->head + NET_SKB_PAD; ++ skb->head_frag = head_frag; ++ skb_reset_tail_pointer(skb); ++} ++EXPORT_SYMBOL(skb_recycle); ++ + /* Make sure a field is enclosed inside headers_start/headers_end section */ + #define CHECK_SKB_FIELD(field) \ + BUILD_BUG_ON(offsetof(struct sk_buff, field) < \ +@@ -1073,7 +1099,7 @@ static void skb_headers_offset_update(struct sk_buff *skb, int off) + skb->inner_mac_header += off; + } + +-static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) ++void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) + { + __copy_skb_header(new, old); + +@@ -1081,6 +1107,7 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) + skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs; + skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type; + } ++EXPORT_SYMBOL(copy_skb_header); + + static inline int skb_alloc_rx_flag(const struct sk_buff *skb) + { +diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c +index 0fd1976a..9d6c1009 100644 +--- a/net/ipv4/ip_tunnel_core.c ++++ b/net/ipv4/ip_tunnel_core.c +@@ -188,8 +188,8 @@ int iptunnel_handle_offloads(struct sk_buff *skb, + EXPORT_SYMBOL_GPL(iptunnel_handle_offloads); + + /* Often modified stats are per cpu, other are shared (netdev->stats) */ +-struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *tot) ++void ip_tunnel_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *tot) + { + int i; + +@@ -214,8 +214,6 @@ struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev, + tot->rx_bytes += rx_bytes; + tot->tx_bytes += tx_bytes; + } +- +- return tot; + } + EXPORT_SYMBOL_GPL(ip_tunnel_get_stats64); + +diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c +index eecc64e1..ce73136a 100644 +--- a/net/l2tp/l2tp_eth.c ++++ b/net/l2tp/l2tp_eth.c +@@ -106,8 +106,8 @@ static int l2tp_eth_dev_xmit(struct sk_buff *skb, struct net_device *dev) + return NETDEV_TX_OK; + } + +-static struct rtnl_link_stats64 *l2tp_eth_get_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *stats) ++static void l2tp_eth_get_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + struct l2tp_eth *priv = netdev_priv(dev); + +@@ -117,10 +117,8 @@ static struct rtnl_link_stats64 *l2tp_eth_get_stats64(struct net_device *dev, + stats->rx_bytes = atomic_long_read(&priv->rx_bytes); + stats->rx_packets = atomic_long_read(&priv->rx_packets); + stats->rx_errors = atomic_long_read(&priv->rx_errors); +- return stats; + } + +- + static const struct net_device_ops l2tp_eth_netdev_ops = { + .ndo_init = l2tp_eth_dev_init, + .ndo_uninit = l2tp_eth_dev_uninit, +diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c +index 37bec0f8..aee93423 100644 +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -1133,7 +1133,7 @@ static u16 ieee80211_netdev_select_queue(struct net_device *dev, + return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb); + } + +-static struct rtnl_link_stats64 * ++static void + ieee80211_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + { + int i; +@@ -1158,8 +1158,6 @@ ieee80211_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) + stats->rx_bytes += rx_bytes; + stats->tx_bytes += tx_bytes; + } +- +- return stats; + } + + static const struct net_device_ops ieee80211_dataif_ops = { +diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c +index e7da2902..95fd5744 100644 +--- a/net/openvswitch/vport-internal_dev.c ++++ b/net/openvswitch/vport-internal_dev.c +@@ -106,7 +106,7 @@ static void internal_dev_destructor(struct net_device *dev) + free_netdev(dev); + } + +-static struct rtnl_link_stats64 * ++static void + internal_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) + { + int i; +@@ -134,8 +134,6 @@ internal_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) + stats->tx_bytes += local_stats.tx_bytes; + stats->tx_packets += local_stats.tx_packets; + } +- +- return stats; + } + + static void internal_set_rx_headroom(struct net_device *dev, int new_hr) +diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c +index a62de9e4..5b287e1d 100644 +--- a/net/sched/sch_generic.c ++++ b/net/sched/sch_generic.c +@@ -309,6 +309,13 @@ static void dev_watchdog(unsigned long arg) + txq->trans_timeout++; + break; + } ++ ++ /* Devices with HW_ACCEL_MQ have multiple txqs ++ * but update only the first one's transmission ++ * timestamp so avoid checking the rest. ++ */ ++ if (dev->features & NETIF_F_HW_ACCEL_MQ) ++ break; + } + + if (some_queue_timedout) { +diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c +index 2cd9b447..5e25213e 100644 +--- a/net/sched/sch_teql.c ++++ b/net/sched/sch_teql.c +@@ -401,8 +401,8 @@ static int teql_master_close(struct net_device *dev) + return 0; + } + +-static struct rtnl_link_stats64 *teql_master_stats64(struct net_device *dev, +- struct rtnl_link_stats64 *stats) ++static void teql_master_stats64(struct net_device *dev, ++ struct rtnl_link_stats64 *stats) + { + struct teql_master *m = netdev_priv(dev); + +@@ -410,7 +410,6 @@ static struct rtnl_link_stats64 *teql_master_stats64(struct net_device *dev, + stats->tx_bytes = m->tx_bytes; + stats->tx_errors = m->tx_errors; + stats->tx_dropped = m->tx_dropped; +- return stats; + } + + static int teql_master_mtu(struct net_device *dev, int new_mtu) +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/701-sdk_dpaa-support-layerscape.patch b/target/linux/layerscape/patches-4.9/701-sdk_dpaa-support-layerscape.patch new file mode 100644 index 0000000000..67e09c5270 --- /dev/null +++ b/target/linux/layerscape/patches-4.9/701-sdk_dpaa-support-layerscape.patch @@ -0,0 +1,155005 @@ +From 6fe4518adbbbab0404958db4aa95673d60174881 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 11:58:03 +0800 +Subject: [PATCH] sdk_dpaa: support layerscape + +This is a integrated patch for layerscape dpaa1-sdk support. + +Signed-off-by: Camelia Groza +Signed-off-by: Zhao Qiang +Signed-off-by: Zhang Ying-22455 +Signed-off-by: Madalin Bucur +Signed-off-by: Yangbo Lu +--- + drivers/net/ethernet/freescale/sdk_dpaa/Kconfig | 173 + + drivers/net/ethernet/freescale/sdk_dpaa/Makefile | 46 + + .../net/ethernet/freescale/sdk_dpaa/dpaa_1588.c | 580 ++ + .../net/ethernet/freescale/sdk_dpaa/dpaa_1588.h | 138 + + .../net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.c | 180 + + .../net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.h | 43 + + drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c | 1213 ++++ + drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h | 698 ++ + .../ethernet/freescale/sdk_dpaa/dpaa_eth_base.c | 205 + + .../ethernet/freescale/sdk_dpaa/dpaa_eth_base.h | 49 + + .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c | 1992 +++++ + .../ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h | 237 + + .../ethernet/freescale/sdk_dpaa/dpaa_eth_common.c | 1811 +++++ + .../ethernet/freescale/sdk_dpaa/dpaa_eth_common.h | 225 + + .../ethernet/freescale/sdk_dpaa/dpaa_eth_proxy.c | 381 + + .../net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 1179 +++ + .../ethernet/freescale/sdk_dpaa/dpaa_eth_sysfs.c | 278 + + .../ethernet/freescale/sdk_dpaa/dpaa_eth_trace.h | 144 + + .../net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c | 544 ++ + drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ptp.c | 291 + + drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c | 907 +++ + drivers/net/ethernet/freescale/sdk_dpaa/mac.c | 489 ++ + drivers/net/ethernet/freescale/sdk_dpaa/mac.h | 135 + + .../net/ethernet/freescale/sdk_dpaa/offline_port.c | 848 +++ + .../net/ethernet/freescale/sdk_dpaa/offline_port.h | 59 + + drivers/net/ethernet/freescale/sdk_fman/Kconfig | 153 + + drivers/net/ethernet/freescale/sdk_fman/Makefile | 11 + + .../freescale/sdk_fman/Peripherals/FM/HC/Makefile | 15 + + .../freescale/sdk_fman/Peripherals/FM/HC/hc.c | 1232 ++++ + .../freescale/sdk_fman/Peripherals/FM/MAC/Makefile | 28 + + .../freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c | 1464 ++++ + .../freescale/sdk_fman/Peripherals/FM/MAC/dtsec.h | 228 + + .../sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.c | 97 + + .../sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.h | 42 + + .../freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c | 658 ++ + .../freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h | 225 + + .../sdk_fman/Peripherals/FM/MAC/fman_crc32.c | 119 + + .../sdk_fman/Peripherals/FM/MAC/fman_crc32.h | 43 + + .../sdk_fman/Peripherals/FM/MAC/fman_dtsec.c | 845 +++ + .../Peripherals/FM/MAC/fman_dtsec_mii_acc.c | 163 + + .../sdk_fman/Peripherals/FM/MAC/fman_memac.c | 511 ++ + .../Peripherals/FM/MAC/fman_memac_mii_acc.c | 213 + + .../sdk_fman/Peripherals/FM/MAC/fman_tgec.c | 367 + + .../freescale/sdk_fman/Peripherals/FM/MAC/memac.c | 1096 +++ + .../freescale/sdk_fman/Peripherals/FM/MAC/memac.h | 110 + + .../sdk_fman/Peripherals/FM/MAC/memac_mii_acc.c | 78 + + .../sdk_fman/Peripherals/FM/MAC/memac_mii_acc.h | 73 + + .../freescale/sdk_fman/Peripherals/FM/MAC/tgec.c | 975 +++ + .../freescale/sdk_fman/Peripherals/FM/MAC/tgec.h | 151 + + .../sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.c | 139 + + .../sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.h | 80 + + .../sdk_fman/Peripherals/FM/MACSEC/Makefile | 15 + + .../sdk_fman/Peripherals/FM/MACSEC/fm_macsec.c | 237 + + .../sdk_fman/Peripherals/FM/MACSEC/fm_macsec.h | 203 + + .../Peripherals/FM/MACSEC/fm_macsec_guest.c | 59 + + .../Peripherals/FM/MACSEC/fm_macsec_master.c | 1031 +++ + .../Peripherals/FM/MACSEC/fm_macsec_master.h | 479 ++ + .../Peripherals/FM/MACSEC/fm_macsec_secy.c | 883 +++ + .../Peripherals/FM/MACSEC/fm_macsec_secy.h | 144 + + .../freescale/sdk_fman/Peripherals/FM/Makefile | 23 + + .../freescale/sdk_fman/Peripherals/FM/Pcd/Makefile | 26 + + .../freescale/sdk_fman/Peripherals/FM/Pcd/crc64.h | 360 + + .../freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c | 7582 ++++++++++++++++++++ + .../freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.h | 399 + + .../freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c | 3242 +++++++++ + .../freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.h | 206 + + .../sdk_fman/Peripherals/FM/Pcd/fm_manip.c | 5571 ++++++++++++++ + .../sdk_fman/Peripherals/FM/Pcd/fm_manip.h | 555 ++ + .../freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.c | 2095 ++++++ + .../freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.h | 543 ++ + .../sdk_fman/Peripherals/FM/Pcd/fm_pcd_ipc.h | 280 + + .../sdk_fman/Peripherals/FM/Pcd/fm_plcr.c | 1847 +++++ + .../sdk_fman/Peripherals/FM/Pcd/fm_plcr.h | 165 + + .../freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.c | 423 ++ + .../freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.h | 316 + + .../sdk_fman/Peripherals/FM/Pcd/fm_replic.c | 984 +++ + .../sdk_fman/Peripherals/FM/Pcd/fm_replic.h | 101 + + .../sdk_fman/Peripherals/FM/Pcd/fman_kg.c | 888 +++ + .../sdk_fman/Peripherals/FM/Pcd/fman_prs.c | 129 + + .../sdk_fman/Peripherals/FM/Port/Makefile | 15 + + .../sdk_fman/Peripherals/FM/Port/fm_port.c | 6436 +++++++++++++++++ + .../sdk_fman/Peripherals/FM/Port/fm_port.h | 999 +++ + .../sdk_fman/Peripherals/FM/Port/fm_port_dsar.h | 494 ++ + .../sdk_fman/Peripherals/FM/Port/fm_port_im.c | 753 ++ + .../sdk_fman/Peripherals/FM/Port/fman_port.c | 1568 ++++ + .../freescale/sdk_fman/Peripherals/FM/Rtc/Makefile | 15 + + .../freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.c | 692 ++ + .../freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.h | 96 + + .../sdk_fman/Peripherals/FM/Rtc/fman_rtc.c | 334 + + .../freescale/sdk_fman/Peripherals/FM/SP/Makefile | 15 + + .../freescale/sdk_fman/Peripherals/FM/SP/fm_sp.c | 757 ++ + .../freescale/sdk_fman/Peripherals/FM/SP/fm_sp.h | 85 + + .../freescale/sdk_fman/Peripherals/FM/SP/fman_sp.c | 197 + + .../freescale/sdk_fman/Peripherals/FM/fm.c | 5216 ++++++++++++++ + .../freescale/sdk_fman/Peripherals/FM/fm.h | 648 ++ + .../freescale/sdk_fman/Peripherals/FM/fm_ipc.h | 465 ++ + .../freescale/sdk_fman/Peripherals/FM/fm_muram.c | 174 + + .../freescale/sdk_fman/Peripherals/FM/fman.c | 1398 ++++ + .../sdk_fman/Peripherals/FM/inc/fm_common.h | 1214 ++++ + .../freescale/sdk_fman/Peripherals/FM/inc/fm_hc.h | 93 + + .../sdk_fman/Peripherals/FM/inc/fm_sp_common.h | 117 + + .../net/ethernet/freescale/sdk_fman/etc/Makefile | 12 + + .../net/ethernet/freescale/sdk_fman/etc/error.c | 95 + + drivers/net/ethernet/freescale/sdk_fman/etc/list.c | 71 + + .../net/ethernet/freescale/sdk_fman/etc/memcpy.c | 620 ++ + drivers/net/ethernet/freescale/sdk_fman/etc/mm.c | 1155 +++ + drivers/net/ethernet/freescale/sdk_fman/etc/mm.h | 105 + + .../net/ethernet/freescale/sdk_fman/etc/sprint.c | 81 + + .../ethernet/freescale/sdk_fman/fmanv3h_dflags.h | 57 + + .../ethernet/freescale/sdk_fman/fmanv3l_dflags.h | 56 + + .../sdk_fman/inc/Peripherals/crc_mac_addr_ext.h | 364 + + .../freescale/sdk_fman/inc/Peripherals/dpaa_ext.h | 210 + + .../freescale/sdk_fman/inc/Peripherals/fm_ext.h | 1731 +++++ + .../sdk_fman/inc/Peripherals/fm_mac_ext.h | 859 +++ + .../sdk_fman/inc/Peripherals/fm_macsec_ext.h | 1271 ++++ + .../sdk_fman/inc/Peripherals/fm_muram_ext.h | 170 + + .../sdk_fman/inc/Peripherals/fm_pcd_ext.h | 3974 ++++++++++ + .../sdk_fman/inc/Peripherals/fm_port_ext.h | 2608 +++++++ + .../sdk_fman/inc/Peripherals/fm_rtc_ext.h | 619 ++ + .../sdk_fman/inc/Peripherals/fm_vsp_ext.h | 411 ++ + .../sdk_fman/inc/Peripherals/mii_acc_ext.h | 76 + + .../net/ethernet/freescale/sdk_fman/inc/core_ext.h | 90 + + .../freescale/sdk_fman/inc/cores/arm_ext.h | 55 + + .../freescale/sdk_fman/inc/cores/e500v2_ext.h | 476 ++ + .../freescale/sdk_fman/inc/cores/ppc_ext.h | 141 + + .../ethernet/freescale/sdk_fman/inc/ddr_std_ext.h | 77 + + .../ethernet/freescale/sdk_fman/inc/debug_ext.h | 233 + + .../ethernet/freescale/sdk_fman/inc/endian_ext.h | 447 ++ + .../net/ethernet/freescale/sdk_fman/inc/enet_ext.h | 205 + + .../ethernet/freescale/sdk_fman/inc/error_ext.h | 529 ++ + .../ethernet/freescale/sdk_fman/inc/etc/list_ext.h | 358 + + .../ethernet/freescale/sdk_fman/inc/etc/mem_ext.h | 318 + + .../freescale/sdk_fman/inc/etc/memcpy_ext.h | 208 + + .../ethernet/freescale/sdk_fman/inc/etc/mm_ext.h | 310 + + .../freescale/sdk_fman/inc/etc/sprint_ext.h | 118 + + .../sdk_fman/inc/flib/common/arch/ppc_access.h | 37 + + .../freescale/sdk_fman/inc/flib/common/general.h | 52 + + .../freescale/sdk_fman/inc/flib/fman_common.h | 78 + + .../freescale/sdk_fman/inc/flib/fsl_enet.h | 273 + + .../freescale/sdk_fman/inc/flib/fsl_fman.h | 825 +++ + .../freescale/sdk_fman/inc/flib/fsl_fman_dtsec.h | 1096 +++ + .../sdk_fman/inc/flib/fsl_fman_dtsec_mii_acc.h | 107 + + .../freescale/sdk_fman/inc/flib/fsl_fman_kg.h | 514 ++ + .../freescale/sdk_fman/inc/flib/fsl_fman_memac.h | 427 ++ + .../sdk_fman/inc/flib/fsl_fman_memac_mii_acc.h | 78 + + .../freescale/sdk_fman/inc/flib/fsl_fman_port.h | 593 ++ + .../freescale/sdk_fman/inc/flib/fsl_fman_prs.h | 102 + + .../freescale/sdk_fman/inc/flib/fsl_fman_rtc.h | 449 ++ + .../freescale/sdk_fman/inc/flib/fsl_fman_sp.h | 138 + + .../freescale/sdk_fman/inc/flib/fsl_fman_tgec.h | 479 ++ + .../integrations/FMANV3H/dpaa_integration_ext.h | 291 + + .../sdk_fman/inc/integrations/FMANV3H/part_ext.h | 71 + + .../integrations/FMANV3H/part_integration_ext.h | 304 + + .../integrations/FMANV3L/dpaa_integration_ext.h | 293 + + .../sdk_fman/inc/integrations/FMANV3L/part_ext.h | 59 + + .../integrations/FMANV3L/part_integration_ext.h | 304 + + .../inc/integrations/LS1043/dpaa_integration_ext.h | 291 + + .../sdk_fman/inc/integrations/LS1043/part_ext.h | 64 + + .../inc/integrations/LS1043/part_integration_ext.h | 185 + + .../inc/integrations/P1023/dpaa_integration_ext.h | 213 + + .../sdk_fman/inc/integrations/P1023/part_ext.h | 82 + + .../inc/integrations/P1023/part_integration_ext.h | 635 ++ + .../P3040_P4080_P5020/dpaa_integration_ext.h | 276 + + .../inc/integrations/P3040_P4080_P5020/part_ext.h | 83 + + .../P3040_P4080_P5020/part_integration_ext.h | 336 + + .../net/ethernet/freescale/sdk_fman/inc/math_ext.h | 100 + + .../net/ethernet/freescale/sdk_fman/inc/ncsw_ext.h | 435 ++ + .../net/ethernet/freescale/sdk_fman/inc/net_ext.h | 430 ++ + .../net/ethernet/freescale/sdk_fman/inc/std_ext.h | 48 + + .../ethernet/freescale/sdk_fman/inc/stdarg_ext.h | 49 + + .../ethernet/freescale/sdk_fman/inc/stdlib_ext.h | 162 + + .../ethernet/freescale/sdk_fman/inc/string_ext.h | 56 + + .../ethernet/freescale/sdk_fman/inc/types_ext.h | 62 + + .../ethernet/freescale/sdk_fman/inc/xx_common.h | 56 + + .../net/ethernet/freescale/sdk_fman/inc/xx_ext.h | 791 ++ + .../ethernet/freescale/sdk_fman/ls1043_dflags.h | 56 + + .../net/ethernet/freescale/sdk_fman/ncsw_config.mk | 53 + + .../net/ethernet/freescale/sdk_fman/p1023_dflags.h | 65 + + .../freescale/sdk_fman/p3040_4080_5020_dflags.h | 62 + + .../net/ethernet/freescale/sdk_fman/src/Makefile | 11 + + .../freescale/sdk_fman/src/inc/system/sys_ext.h | 118 + + .../freescale/sdk_fman/src/inc/system/sys_io_ext.h | 46 + + .../freescale/sdk_fman/src/inc/types_linux.h | 208 + + .../sdk_fman/src/inc/wrapper/fsl_fman_test.h | 84 + + .../sdk_fman/src/inc/wrapper/lnxwrp_exp_sym.h | 128 + + .../sdk_fman/src/inc/wrapper/lnxwrp_fm_ext.h | 163 + + .../sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h | 921 +++ + .../ethernet/freescale/sdk_fman/src/inc/xx/xx.h | 50 + + .../freescale/sdk_fman/src/system/Makefile | 10 + + .../freescale/sdk_fman/src/system/sys_io.c | 171 + + .../freescale/sdk_fman/src/wrapper/Makefile | 19 + + .../freescale/sdk_fman/src/wrapper/fman_test.c | 1665 +++++ + .../freescale/sdk_fman/src/wrapper/lnxwrp_fm.c | 2908 ++++++++ + .../freescale/sdk_fman/src/wrapper/lnxwrp_fm.h | 294 + + .../sdk_fman/src/wrapper/lnxwrp_fm_port.c | 1480 ++++ + .../sdk_fman/src/wrapper/lnxwrp_ioctls_fm.c | 4813 +++++++++++++ + .../sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c | 1297 ++++ + .../sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.h | 755 ++ + .../sdk_fman/src/wrapper/lnxwrp_resources.h | 121 + + .../sdk_fman/src/wrapper/lnxwrp_resources_ut.c | 191 + + .../sdk_fman/src/wrapper/lnxwrp_resources_ut.h | 144 + + .../sdk_fman/src/wrapper/lnxwrp_resources_ut.make | 28 + + .../freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.c | 60 + + .../freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.h | 60 + + .../sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c | 1855 +++++ + .../sdk_fman/src/wrapper/lnxwrp_sysfs_fm.h | 136 + + .../sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.c | 1268 ++++ + .../sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.h | 56 + + .../ethernet/freescale/sdk_fman/src/xx/Makefile | 18 + + .../freescale/sdk_fman/src/xx/module_strings.c | 46 + + .../freescale/sdk_fman/src/xx/xx_arm_linux.c | 905 +++ + .../ethernet/freescale/sdk_fman/src/xx/xx_linux.c | 918 +++ + drivers/staging/fsl_qbman/Kconfig | 228 + + drivers/staging/fsl_qbman/Makefile | 28 + + drivers/staging/fsl_qbman/bman_config.c | 720 ++ + drivers/staging/fsl_qbman/bman_debugfs.c | 119 + + drivers/staging/fsl_qbman/bman_driver.c | 575 ++ + drivers/staging/fsl_qbman/bman_high.c | 1145 +++ + drivers/staging/fsl_qbman/bman_low.h | 565 ++ + drivers/staging/fsl_qbman/bman_private.h | 166 + + drivers/staging/fsl_qbman/bman_test.c | 56 + + drivers/staging/fsl_qbman/bman_test.h | 44 + + drivers/staging/fsl_qbman/bman_test_high.c | 183 + + drivers/staging/fsl_qbman/bman_test_thresh.c | 196 + + drivers/staging/fsl_qbman/dpa_alloc.c | 706 ++ + drivers/staging/fsl_qbman/dpa_sys.h | 259 + + drivers/staging/fsl_qbman/dpa_sys_arm.h | 95 + + drivers/staging/fsl_qbman/dpa_sys_arm64.h | 102 + + drivers/staging/fsl_qbman/dpa_sys_ppc32.h | 70 + + drivers/staging/fsl_qbman/dpa_sys_ppc64.h | 79 + + drivers/staging/fsl_qbman/fsl_usdpaa.c | 1983 +++++ + drivers/staging/fsl_qbman/fsl_usdpaa_irq.c | 289 + + drivers/staging/fsl_qbman/qbman_driver.c | 88 + + drivers/staging/fsl_qbman/qman_config.c | 1224 ++++ + drivers/staging/fsl_qbman/qman_debugfs.c | 1594 ++++ + drivers/staging/fsl_qbman/qman_driver.c | 977 +++ + drivers/staging/fsl_qbman/qman_high.c | 5669 +++++++++++++++ + drivers/staging/fsl_qbman/qman_low.h | 1427 ++++ + drivers/staging/fsl_qbman/qman_private.h | 398 + + drivers/staging/fsl_qbman/qman_test.c | 57 + + drivers/staging/fsl_qbman/qman_test.h | 45 + + drivers/staging/fsl_qbman/qman_test_high.c | 216 + + drivers/staging/fsl_qbman/qman_test_hotpotato.c | 502 ++ + drivers/staging/fsl_qbman/qman_utility.c | 129 + + include/linux/fsl_bman.h | 532 ++ + include/linux/fsl_qman.h | 3888 ++++++++++ + include/linux/fsl_usdpaa.h | 372 + + include/uapi/linux/fmd/Kbuild | 5 + + include/uapi/linux/fmd/Peripherals/Kbuild | 4 + + include/uapi/linux/fmd/Peripherals/fm_ioctls.h | 628 ++ + include/uapi/linux/fmd/Peripherals/fm_pcd_ioctls.h | 3084 ++++++++ + .../uapi/linux/fmd/Peripherals/fm_port_ioctls.h | 948 +++ + .../uapi/linux/fmd/Peripherals/fm_test_ioctls.h | 208 + + include/uapi/linux/fmd/integrations/Kbuild | 1 + + .../linux/fmd/integrations/integration_ioctls.h | 56 + + include/uapi/linux/fmd/ioctls.h | 96 + + include/uapi/linux/fmd/net_ioctls.h | 430 ++ + 257 files changed, 152931 insertions(+) + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/Kconfig + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/Makefile + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.c + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.h + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.c + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.h + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.c + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.h + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_proxy.c + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sysfs.c + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_trace.h + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ptp.c + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/mac.c + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/mac.h + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/offline_port.c + create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/offline_port.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Kconfig + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Makefile + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/Makefile + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/hc.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/Makefile + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac.c + create mode 100755 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac_mii_acc.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_tgec.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/Makefile + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_guest.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Makefile + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/Makefile + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/crc64.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd_ipc.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_kg.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_prs.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/Makefile + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.h + create mode 100755 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_dsar.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_im.c + create mode 100755 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/Makefile + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.h + create mode 100755 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fman_rtc.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/Makefile + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.h + create mode 100755 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fman_sp.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_ipc.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_muram.c + create mode 100755 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_common.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_hc.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_sp_common.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/etc/Makefile + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/etc/error.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/etc/list.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/etc/memcpy.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/etc/mm.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/etc/mm.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/etc/sprint.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/fmanv3h_dflags.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/fmanv3l_dflags.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/crc_mac_addr_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/dpaa_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_mac_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_macsec_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_muram_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_pcd_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_port_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_rtc_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_vsp_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/mii_acc_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/core_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/cores/arm_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/cores/e500v2_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/cores/ppc_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/ddr_std_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/debug_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/endian_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/enet_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/error_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/etc/list_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/etc/mem_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/etc/memcpy_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/etc/mm_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/etc/sprint_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/arch/ppc_access.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/general.h + create mode 100755 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fman_common.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_enet.h + create mode 100755 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec_mii_acc.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_kg.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac.h + create mode 100755 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac_mii_acc.h + create mode 100755 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_port.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_prs.h + create mode 100755 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_rtc.h + create mode 100755 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_sp.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_tgec.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/dpaa_integration_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_integration_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/dpaa_integration_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_integration_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/dpaa_integration_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_integration_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/dpaa_integration_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_integration_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/dpaa_integration_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_integration_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/math_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/ncsw_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/net_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/std_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/stdarg_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/stdlib_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/string_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/types_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/xx_common.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/inc/xx_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/ls1043_dflags.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/p1023_dflags.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/p3040_4080_5020_dflags.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/Makefile + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_io_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/inc/types_linux.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/fsl_fman_test.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_exp_sym.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fm_ext.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/inc/xx/xx.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/system/Makefile + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/system/sys_io.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/Makefile + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/fman_test.c + create mode 100755 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.make + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.h + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/xx/Makefile + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/xx/module_strings.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_arm_linux.c + create mode 100644 drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_linux.c + create mode 100644 drivers/staging/fsl_qbman/Kconfig + create mode 100644 drivers/staging/fsl_qbman/Makefile + create mode 100644 drivers/staging/fsl_qbman/bman_config.c + create mode 100644 drivers/staging/fsl_qbman/bman_debugfs.c + create mode 100644 drivers/staging/fsl_qbman/bman_driver.c + create mode 100644 drivers/staging/fsl_qbman/bman_high.c + create mode 100644 drivers/staging/fsl_qbman/bman_low.h + create mode 100644 drivers/staging/fsl_qbman/bman_private.h + create mode 100644 drivers/staging/fsl_qbman/bman_test.c + create mode 100644 drivers/staging/fsl_qbman/bman_test.h + create mode 100644 drivers/staging/fsl_qbman/bman_test_high.c + create mode 100644 drivers/staging/fsl_qbman/bman_test_thresh.c + create mode 100644 drivers/staging/fsl_qbman/dpa_alloc.c + create mode 100644 drivers/staging/fsl_qbman/dpa_sys.h + create mode 100644 drivers/staging/fsl_qbman/dpa_sys_arm.h + create mode 100644 drivers/staging/fsl_qbman/dpa_sys_arm64.h + create mode 100644 drivers/staging/fsl_qbman/dpa_sys_ppc32.h + create mode 100644 drivers/staging/fsl_qbman/dpa_sys_ppc64.h + create mode 100644 drivers/staging/fsl_qbman/fsl_usdpaa.c + create mode 100644 drivers/staging/fsl_qbman/fsl_usdpaa_irq.c + create mode 100644 drivers/staging/fsl_qbman/qbman_driver.c + create mode 100644 drivers/staging/fsl_qbman/qman_config.c + create mode 100644 drivers/staging/fsl_qbman/qman_debugfs.c + create mode 100644 drivers/staging/fsl_qbman/qman_driver.c + create mode 100644 drivers/staging/fsl_qbman/qman_high.c + create mode 100644 drivers/staging/fsl_qbman/qman_low.h + create mode 100644 drivers/staging/fsl_qbman/qman_private.h + create mode 100644 drivers/staging/fsl_qbman/qman_test.c + create mode 100644 drivers/staging/fsl_qbman/qman_test.h + create mode 100644 drivers/staging/fsl_qbman/qman_test_high.c + create mode 100644 drivers/staging/fsl_qbman/qman_test_hotpotato.c + create mode 100644 drivers/staging/fsl_qbman/qman_utility.c + create mode 100644 include/linux/fsl_bman.h + create mode 100644 include/linux/fsl_qman.h + create mode 100644 include/linux/fsl_usdpaa.h + create mode 100644 include/uapi/linux/fmd/Kbuild + create mode 100644 include/uapi/linux/fmd/Peripherals/Kbuild + create mode 100644 include/uapi/linux/fmd/Peripherals/fm_ioctls.h + create mode 100644 include/uapi/linux/fmd/Peripherals/fm_pcd_ioctls.h + create mode 100644 include/uapi/linux/fmd/Peripherals/fm_port_ioctls.h + create mode 100644 include/uapi/linux/fmd/Peripherals/fm_test_ioctls.h + create mode 100644 include/uapi/linux/fmd/integrations/Kbuild + create mode 100644 include/uapi/linux/fmd/integrations/integration_ioctls.h + create mode 100644 include/uapi/linux/fmd/ioctls.h + create mode 100644 include/uapi/linux/fmd/net_ioctls.h + +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig b/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig +new file mode 100644 +index 00000000..92118b76 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig +@@ -0,0 +1,173 @@ ++menuconfig FSL_SDK_DPAA_ETH ++ tristate "DPAA Ethernet" ++ depends on (FSL_SOC || ARM64 || ARM) && FSL_SDK_BMAN && FSL_SDK_QMAN && FSL_SDK_FMAN && !FSL_DPAA_ETH ++ select PHYLIB ++ help ++ Data Path Acceleration Architecture Ethernet driver, ++ supporting the Freescale QorIQ chips. ++ Depends on Freescale Buffer Manager and Queue Manager ++ driver and Frame Manager Driver. ++ ++if FSL_SDK_DPAA_ETH ++ ++config FSL_DPAA_HOOKS ++ bool "DPAA Ethernet driver hooks" ++ ++config FSL_DPAA_CEETM ++ bool "DPAA CEETM QoS" ++ depends on NET_SCHED ++ default n ++ help ++ Enable QoS offloading support through the CEETM hardware block. ++ ++config FSL_DPAA_OFFLINE_PORTS ++ bool "Offline Ports support" ++ depends on FSL_SDK_DPAA_ETH ++ default y ++ help ++ The Offline Parsing / Host Command ports (short: OH ports, of Offline ports) provide ++ most of the functionality of the regular, online ports, except they receive their ++ frames from a core or an accelerator on the SoC, via QMan frame queues, ++ rather than directly from the network. ++ Offline ports are configured via PCD (Parse-Classify-Distribute) schemes, just like ++ any online FMan port. They deliver the processed frames to frame queues, according ++ to the applied PCD configurations. ++ ++ Choosing this feature will not impact the functionality and/or performance of the system, ++ so it is safe to have it. ++ ++config FSL_DPAA_ADVANCED_DRIVERS ++ bool "Advanced DPAA Ethernet drivers" ++ depends on FSL_SDK_DPAA_ETH ++ default y ++ help ++ Besides the standard DPAA Ethernet driver the DPAA Proxy initialization driver ++ is needed to support advanced scenarios. Select this to also build the advanced ++ drivers. ++ ++config FSL_DPAA_ETH_JUMBO_FRAME ++ bool "Optimize for jumbo frames" ++ default n ++ help ++ Optimize the DPAA Ethernet driver throughput for large frames ++ termination traffic (e.g. 4K and above). ++ NOTE: This option can only be used if FSL_FM_MAX_FRAME_SIZE ++ is set to 9600 bytes. ++ Using this option in combination with small frames increases ++ significantly the driver's memory footprint and may even deplete ++ the system memory. Also, the skb truesize is altered and messages ++ from the stack that warn against this are bypassed. ++ This option is not available on LS1043. ++ ++config FSL_DPAA_TS ++ bool "Linux compliant timestamping" ++ depends on FSL_SDK_DPAA_ETH ++ default n ++ help ++ Enable Linux API compliant timestamping support. ++ ++config FSL_DPAA_1588 ++ bool "IEEE 1588-compliant timestamping" ++ depends on FSL_SDK_DPAA_ETH ++ select FSL_DPAA_TS ++ default n ++ help ++ Enable IEEE1588 support code. ++ ++config FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE ++ bool "Use driver's Tx queue selection mechanism" ++ default y ++ depends on FSL_SDK_DPAA_ETH ++ help ++ The DPAA-Ethernet driver defines a ndo_select_queue() callback for optimal selection ++ of the egress FQ. That will override the XPS support for this netdevice. ++ If for whatever reason you want to be in control of the egress FQ-to-CPU selection and mapping, ++ or simply don't want to use the driver's ndo_select_queue() callback, then unselect this ++ and use the standard XPS support instead. ++ ++config FSL_DPAA_ETH_MAX_BUF_COUNT ++ int "Maximum nuber of buffers in private bpool" ++ depends on FSL_SDK_DPAA_ETH ++ range 64 2048 ++ default "128" ++ help ++ The maximum number of buffers to be by default allocated in the DPAA-Ethernet private port's ++ buffer pool. One needn't normally modify this, as it has probably been tuned for performance ++ already. This cannot be lower than DPAA_ETH_REFILL_THRESHOLD. ++ ++config FSL_DPAA_ETH_REFILL_THRESHOLD ++ int "Private bpool refill threshold" ++ depends on FSL_SDK_DPAA_ETH ++ range 32 FSL_DPAA_ETH_MAX_BUF_COUNT ++ default "80" ++ help ++ The DPAA-Ethernet driver will start replenishing buffer pools whose count ++ falls below this threshold. This must be related to DPAA_ETH_MAX_BUF_COUNT. One needn't normally ++ modify this value unless one has very specific performance reasons. ++ ++config FSL_DPAA_CS_THRESHOLD_1G ++ hex "Egress congestion threshold on 1G ports" ++ depends on FSL_SDK_DPAA_ETH ++ range 0x1000 0x10000000 ++ default "0x06000000" ++ help ++ The size in bytes of the egress Congestion State notification threshold on 1G ports. ++ The 1G dTSECs can quite easily be flooded by cores doing Tx in a tight loop ++ (e.g. by sending UDP datagrams at "while(1) speed"), ++ and the larger the frame size, the more acute the problem. ++ So we have to find a balance between these factors: ++ - avoiding the device staying congested for a prolonged time (risking ++ the netdev watchdog to fire - see also the tx_timeout module param); ++ - affecting performance of protocols such as TCP, which otherwise ++ behave well under the congestion notification mechanism; ++ - preventing the Tx cores from tightly-looping (as if the congestion ++ threshold was too low to be effective); ++ - running out of memory if the CS threshold is set too high. ++ ++config FSL_DPAA_CS_THRESHOLD_10G ++ hex "Egress congestion threshold on 10G ports" ++ depends on FSL_SDK_DPAA_ETH ++ range 0x1000 0x20000000 ++ default "0x10000000" ++ help ++ The size in bytes of the egress Congestion State notification threshold on 10G ports. ++ ++config FSL_DPAA_INGRESS_CS_THRESHOLD ++ hex "Ingress congestion threshold on FMan ports" ++ depends on FSL_SDK_DPAA_ETH ++ default "0x10000000" ++ help ++ The size in bytes of the ingress tail-drop threshold on FMan ports. ++ Traffic piling up above this value will be rejected by QMan and discarded by FMan. ++ ++config FSL_DPAA_ETH_DEBUGFS ++ bool "DPAA Ethernet debugfs interface" ++ depends on DEBUG_FS && FSL_SDK_DPAA_ETH ++ default y ++ help ++ This option compiles debugfs code for the DPAA Ethernet driver. ++ ++config FSL_DPAA_ETH_DEBUG ++ bool "DPAA Ethernet Debug Support" ++ depends on FSL_SDK_DPAA_ETH ++ default n ++ help ++ This option compiles debug code for the DPAA Ethernet driver. ++ ++config FSL_DPAA_DBG_LOOP ++ bool "DPAA Ethernet Debug loopback" ++ depends on FSL_DPAA_ETH_DEBUGFS && FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE ++ default n ++ help ++ This option allows to divert all received traffic on a certain interface A towards a ++ selected interface B. This option is used to benchmark the HW + Ethernet driver in ++ isolation from the Linux networking stack. The loops are controlled by debugfs entries, ++ one for each interface. By default all loops are disabled (target value is -1). I.e. to ++ change the loop setting for interface 4 and divert all received traffic to interface 5 ++ write Tx interface number in the receive interface debugfs file: ++ # cat /sys/kernel/debug/powerpc/fsl_dpa/eth4_loop ++ 4->-1 ++ # echo 5 > /sys/kernel/debug/powerpc/fsl_dpa/eth4_loop ++ # cat /sys/kernel/debug/powerpc/fsl_dpa/eth4_loop ++ 4->5 ++endif # FSL_SDK_DPAA_ETH +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/Makefile b/drivers/net/ethernet/freescale/sdk_dpaa/Makefile +new file mode 100644 +index 00000000..a0f4b190 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/Makefile +@@ -0,0 +1,46 @@ ++# ++# Makefile for the Freescale Ethernet controllers ++# ++ccflags-y += -DVERSION=\"\" ++# ++# Include netcomm SW specific definitions ++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk ++ ++ccflags-y += -I$(NET_DPA) ++ ++obj-$(CONFIG_FSL_SDK_DPAA_ETH) += fsl_mac.o fsl_dpa.o ++obj-$(CONFIG_PTP_1588_CLOCK_DPAA) += dpaa_ptp.o ++ ++fsl_dpa-objs += dpaa_ethtool.o dpaa_eth_sysfs.o dpaa_eth.o dpaa_eth_sg.o dpaa_eth_common.o ++ifeq ($(CONFIG_FSL_DPAA_DBG_LOOP),y) ++fsl_dpa-objs += dpaa_debugfs.o ++endif ++ifeq ($(CONFIG_FSL_DPAA_1588),y) ++fsl_dpa-objs += dpaa_1588.o ++endif ++ifeq ($(CONFIG_FSL_DPAA_CEETM),y) ++ccflags-y += -Idrivers/net/ethernet/freescale/sdk_fman/src/wrapper ++fsl_dpa-objs += dpaa_eth_ceetm.o ++endif ++ ++fsl_mac-objs += mac.o mac-api.o ++ ++# Advanced drivers ++ifeq ($(CONFIG_FSL_DPAA_ADVANCED_DRIVERS),y) ++obj-$(CONFIG_FSL_SDK_DPAA_ETH) += fsl_advanced.o ++obj-$(CONFIG_FSL_SDK_DPAA_ETH) += fsl_proxy.o ++ ++fsl_advanced-objs += dpaa_eth_base.o ++# suport for multiple drivers per kernel module comes in kernel 3.14 ++# so we are forced to generate several modules for the advanced drivers ++fsl_proxy-objs += dpaa_eth_proxy.o ++ ++ifeq ($(CONFIG_FSL_DPAA_OFFLINE_PORTS),y) ++obj-$(CONFIG_FSL_SDK_DPAA_ETH) += fsl_oh.o ++ ++fsl_oh-objs += offline_port.o ++endif ++endif ++ ++# Needed by the tracing framework ++CFLAGS_dpaa_eth.o := -I$(src) +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.c +new file mode 100644 +index 00000000..3bf8cbca +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.c +@@ -0,0 +1,580 @@ ++/* Copyright (C) 2011 Freescale Semiconductor, Inc. ++ * Copyright (C) 2009 IXXAT Automation, GmbH ++ * ++ * DPAA Ethernet Driver -- IEEE 1588 interface functionality ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "dpaa_eth.h" ++#include "dpaa_eth_common.h" ++#include "dpaa_1588.h" ++#include "mac.h" ++ ++static int dpa_ptp_init_circ(struct dpa_ptp_circ_buf *ptp_buf, u32 size) ++{ ++ struct circ_buf *circ_buf = &ptp_buf->circ_buf; ++ ++ circ_buf->buf = vmalloc(sizeof(struct dpa_ptp_data) * size); ++ if (!circ_buf->buf) ++ return 1; ++ ++ circ_buf->head = 0; ++ circ_buf->tail = 0; ++ ptp_buf->size = size; ++ spin_lock_init(&ptp_buf->ptp_lock); ++ ++ return 0; ++} ++ ++static void dpa_ptp_reset_circ(struct dpa_ptp_circ_buf *ptp_buf, u32 size) ++{ ++ struct circ_buf *circ_buf = &ptp_buf->circ_buf; ++ ++ circ_buf->head = 0; ++ circ_buf->tail = 0; ++ ptp_buf->size = size; ++} ++ ++static int dpa_ptp_insert(struct dpa_ptp_circ_buf *ptp_buf, ++ struct dpa_ptp_data *data) ++{ ++ struct circ_buf *circ_buf = &ptp_buf->circ_buf; ++ int size = ptp_buf->size; ++ struct dpa_ptp_data *tmp; ++ unsigned long flags; ++ int head, tail; ++ ++ spin_lock_irqsave(&ptp_buf->ptp_lock, flags); ++ ++ head = circ_buf->head; ++ tail = circ_buf->tail; ++ ++ if (CIRC_SPACE(head, tail, size) <= 0) ++ circ_buf->tail = (tail + 1) & (size - 1); ++ ++ tmp = (struct dpa_ptp_data *)(circ_buf->buf) + head; ++ memcpy(tmp, data, sizeof(struct dpa_ptp_data)); ++ ++ circ_buf->head = (head + 1) & (size - 1); ++ ++ spin_unlock_irqrestore(&ptp_buf->ptp_lock, flags); ++ ++ return 0; ++} ++ ++static int dpa_ptp_is_ident_match(struct dpa_ptp_ident *dst, ++ struct dpa_ptp_ident *src) ++{ ++ int ret; ++ ++ if ((dst->version != src->version) || (dst->msg_type != src->msg_type)) ++ return 0; ++ ++ if ((dst->netw_prot == src->netw_prot) ++ || src->netw_prot == DPA_PTP_PROT_DONTCARE) { ++ if (dst->seq_id != src->seq_id) ++ return 0; ++ ++ ret = memcmp(dst->snd_port_id, src->snd_port_id, ++ DPA_PTP_SOURCE_PORT_LENGTH); ++ if (ret) ++ return 0; ++ else ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int dpa_ptp_find_and_remove(struct dpa_ptp_circ_buf *ptp_buf, ++ struct dpa_ptp_ident *ident, ++ struct dpa_ptp_time *ts) ++{ ++ struct circ_buf *circ_buf = &ptp_buf->circ_buf; ++ int size = ptp_buf->size; ++ int head, tail, idx; ++ unsigned long flags; ++ struct dpa_ptp_data *tmp, *tmp2; ++ struct dpa_ptp_ident *tmp_ident; ++ ++ spin_lock_irqsave(&ptp_buf->ptp_lock, flags); ++ ++ head = circ_buf->head; ++ tail = idx = circ_buf->tail; ++ ++ if (CIRC_CNT(head, tail, size) == 0) { ++ spin_unlock_irqrestore(&ptp_buf->ptp_lock, flags); ++ return 1; ++ } ++ ++ while (idx != head) { ++ tmp = (struct dpa_ptp_data *)(circ_buf->buf) + idx; ++ tmp_ident = &tmp->ident; ++ if (dpa_ptp_is_ident_match(tmp_ident, ident)) ++ break; ++ idx = (idx + 1) & (size - 1); ++ } ++ ++ if (idx == head) { ++ spin_unlock_irqrestore(&ptp_buf->ptp_lock, flags); ++ return 1; ++ } ++ ++ ts->sec = tmp->ts.sec; ++ ts->nsec = tmp->ts.nsec; ++ ++ if (idx != tail) { ++ if (CIRC_CNT(idx, tail, size) > TS_ACCUMULATION_THRESHOLD) { ++ tail = circ_buf->tail = ++ (idx - TS_ACCUMULATION_THRESHOLD) & (size - 1); ++ } ++ ++ while (CIRC_CNT(idx, tail, size) > 0) { ++ tmp = (struct dpa_ptp_data *)(circ_buf->buf) + idx; ++ idx = (idx - 1) & (size - 1); ++ tmp2 = (struct dpa_ptp_data *)(circ_buf->buf) + idx; ++ *tmp = *tmp2; ++ } ++ } ++ circ_buf->tail = (tail + 1) & (size - 1); ++ ++ spin_unlock_irqrestore(&ptp_buf->ptp_lock, flags); ++ ++ return 0; ++} ++ ++/* Parse the PTP packets ++ * ++ * The PTP header can be found in an IPv4 packet, IPv6 patcket or in ++ * an IEEE802.3 ethernet frame. This function returns the position of ++ * the PTP packet or NULL if no PTP found ++ */ ++static u8 *dpa_ptp_parse_packet(struct sk_buff *skb, u16 *eth_type) ++{ ++ u8 *pos = skb->data + ETH_ALEN + ETH_ALEN; ++ u8 *ptp_loc = NULL; ++ u8 msg_type; ++ u32 access_len = ETH_ALEN + ETH_ALEN + DPA_ETYPE_LEN; ++ struct iphdr *iph; ++ struct udphdr *udph; ++ struct ipv6hdr *ipv6h; ++ ++ /* when we can receive S/G frames we need to check the data we want to ++ * access is in the linear skb buffer ++ */ ++ if (!pskb_may_pull(skb, access_len)) ++ return NULL; ++ ++ *eth_type = *((u16 *)pos); ++ ++ /* Check if inner tag is here */ ++ if (*eth_type == ETH_P_8021Q) { ++ access_len += DPA_VLAN_TAG_LEN; ++ ++ if (!pskb_may_pull(skb, access_len)) ++ return NULL; ++ ++ pos += DPA_VLAN_TAG_LEN; ++ *eth_type = *((u16 *)pos); ++ } ++ ++ pos += DPA_ETYPE_LEN; ++ ++ switch (*eth_type) { ++ /* Transport of PTP over Ethernet */ ++ case ETH_P_1588: ++ ptp_loc = pos; ++ ++ if (!pskb_may_pull(skb, access_len + PTP_OFFS_MSG_TYPE + 1)) ++ return NULL; ++ ++ msg_type = *((u8 *)(ptp_loc + PTP_OFFS_MSG_TYPE)) & 0xf; ++ if ((msg_type == PTP_MSGTYPE_SYNC) ++ || (msg_type == PTP_MSGTYPE_DELREQ) ++ || (msg_type == PTP_MSGTYPE_PDELREQ) ++ || (msg_type == PTP_MSGTYPE_PDELRESP)) ++ return ptp_loc; ++ break; ++ /* Transport of PTP over IPv4 */ ++ case ETH_P_IP: ++ iph = (struct iphdr *)pos; ++ access_len += sizeof(struct iphdr); ++ ++ if (!pskb_may_pull(skb, access_len)) ++ return NULL; ++ ++ if (ntohs(iph->protocol) != IPPROTO_UDP) ++ return NULL; ++ ++ access_len += iph->ihl * 4 - sizeof(struct iphdr) + ++ sizeof(struct udphdr); ++ ++ if (!pskb_may_pull(skb, access_len)) ++ return NULL; ++ ++ pos += iph->ihl * 4; ++ udph = (struct udphdr *)pos; ++ if (ntohs(udph->dest) != 319) ++ return NULL; ++ ptp_loc = pos + sizeof(struct udphdr); ++ break; ++ /* Transport of PTP over IPv6 */ ++ case ETH_P_IPV6: ++ ipv6h = (struct ipv6hdr *)pos; ++ ++ access_len += sizeof(struct ipv6hdr) + sizeof(struct udphdr); ++ ++ if (ntohs(ipv6h->nexthdr) != IPPROTO_UDP) ++ return NULL; ++ ++ pos += sizeof(struct ipv6hdr); ++ udph = (struct udphdr *)pos; ++ if (ntohs(udph->dest) != 319) ++ return NULL; ++ ptp_loc = pos + sizeof(struct udphdr); ++ break; ++ default: ++ break; ++ } ++ ++ return ptp_loc; ++} ++ ++static int dpa_ptp_store_stamp(const struct dpa_priv_s *priv, ++ struct sk_buff *skb, void *data, enum port_type rx_tx, ++ struct dpa_ptp_data *ptp_data) ++{ ++ u64 nsec; ++ u32 mod; ++ u8 *ptp_loc; ++ u16 eth_type; ++ ++ ptp_loc = dpa_ptp_parse_packet(skb, ð_type); ++ if (!ptp_loc) ++ return -EINVAL; ++ ++ switch (eth_type) { ++ case ETH_P_IP: ++ ptp_data->ident.netw_prot = DPA_PTP_PROT_IPV4; ++ break; ++ case ETH_P_IPV6: ++ ptp_data->ident.netw_prot = DPA_PTP_PROT_IPV6; ++ break; ++ case ETH_P_1588: ++ ptp_data->ident.netw_prot = DPA_PTP_PROT_802_3; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (!pskb_may_pull(skb, ptp_loc - skb->data + PTP_OFFS_SEQ_ID + 2)) ++ return -EINVAL; ++ ++ ptp_data->ident.version = *(ptp_loc + PTP_OFFS_VER_PTP) & 0xf; ++ ptp_data->ident.msg_type = *(ptp_loc + PTP_OFFS_MSG_TYPE) & 0xf; ++ ptp_data->ident.seq_id = *((u16 *)(ptp_loc + PTP_OFFS_SEQ_ID)); ++ memcpy(ptp_data->ident.snd_port_id, ptp_loc + PTP_OFFS_SRCPRTID, ++ DPA_PTP_SOURCE_PORT_LENGTH); ++ ++ nsec = dpa_get_timestamp_ns(priv, rx_tx, data); ++ mod = do_div(nsec, NANOSEC_PER_SECOND); ++ ptp_data->ts.sec = nsec; ++ ptp_data->ts.nsec = mod; ++ ++ return 0; ++} ++ ++void dpa_ptp_store_txstamp(const struct dpa_priv_s *priv, ++ struct sk_buff *skb, void *data) ++{ ++ struct dpa_ptp_tsu *tsu = priv->tsu; ++ struct dpa_ptp_data ptp_tx_data; ++ ++ if (dpa_ptp_store_stamp(priv, skb, data, TX, &ptp_tx_data)) ++ return; ++ ++ dpa_ptp_insert(&tsu->tx_timestamps, &ptp_tx_data); ++} ++ ++void dpa_ptp_store_rxstamp(const struct dpa_priv_s *priv, ++ struct sk_buff *skb, void *data) ++{ ++ struct dpa_ptp_tsu *tsu = priv->tsu; ++ struct dpa_ptp_data ptp_rx_data; ++ ++ if (dpa_ptp_store_stamp(priv, skb, data, RX, &ptp_rx_data)) ++ return; ++ ++ dpa_ptp_insert(&tsu->rx_timestamps, &ptp_rx_data); ++} ++ ++static uint8_t dpa_get_tx_timestamp(struct dpa_ptp_tsu *ptp_tsu, ++ struct dpa_ptp_ident *ident, ++ struct dpa_ptp_time *ts) ++{ ++ struct dpa_ptp_tsu *tsu = ptp_tsu; ++ struct dpa_ptp_time tmp; ++ int flag; ++ ++ flag = dpa_ptp_find_and_remove(&tsu->tx_timestamps, ident, &tmp); ++ if (!flag) { ++ ts->sec = tmp.sec; ++ ts->nsec = tmp.nsec; ++ return 0; ++ } ++ ++ return -1; ++} ++ ++static uint8_t dpa_get_rx_timestamp(struct dpa_ptp_tsu *ptp_tsu, ++ struct dpa_ptp_ident *ident, ++ struct dpa_ptp_time *ts) ++{ ++ struct dpa_ptp_tsu *tsu = ptp_tsu; ++ struct dpa_ptp_time tmp; ++ int flag; ++ ++ flag = dpa_ptp_find_and_remove(&tsu->rx_timestamps, ident, &tmp); ++ if (!flag) { ++ ts->sec = tmp.sec; ++ ts->nsec = tmp.nsec; ++ return 0; ++ } ++ ++ return -1; ++} ++ ++static void dpa_set_fiper_alarm(struct dpa_ptp_tsu *tsu, ++ struct dpa_ptp_time *cnt_time) ++{ ++ struct mac_device *mac_dev = tsu->dpa_priv->mac_dev; ++ u64 tmp, fiper; ++ ++ if (mac_dev->fm_rtc_disable) ++ mac_dev->fm_rtc_disable(get_fm_handle(tsu->dpa_priv->net_dev)); ++ ++ /* TMR_FIPER1 will pulse every second after ALARM1 expired */ ++ tmp = (u64)cnt_time->sec * NANOSEC_PER_SECOND + (u64)cnt_time->nsec; ++ fiper = NANOSEC_PER_SECOND - DPA_PTP_NOMINAL_FREQ_PERIOD_NS; ++ if (mac_dev->fm_rtc_set_alarm) ++ mac_dev->fm_rtc_set_alarm(get_fm_handle(tsu->dpa_priv->net_dev), ++ 0, tmp); ++ if (mac_dev->fm_rtc_set_fiper) ++ mac_dev->fm_rtc_set_fiper(get_fm_handle(tsu->dpa_priv->net_dev), ++ 0, fiper); ++ ++ if (mac_dev->fm_rtc_enable) ++ mac_dev->fm_rtc_enable(get_fm_handle(tsu->dpa_priv->net_dev)); ++} ++ ++static void dpa_get_curr_cnt(struct dpa_ptp_tsu *tsu, ++ struct dpa_ptp_time *curr_time) ++{ ++ struct mac_device *mac_dev = tsu->dpa_priv->mac_dev; ++ u64 tmp; ++ u32 mod; ++ ++ if (mac_dev->fm_rtc_get_cnt) ++ mac_dev->fm_rtc_get_cnt(get_fm_handle(tsu->dpa_priv->net_dev), ++ &tmp); ++ ++ mod = do_div(tmp, NANOSEC_PER_SECOND); ++ curr_time->sec = (u32)tmp; ++ curr_time->nsec = mod; ++} ++ ++static void dpa_set_1588cnt(struct dpa_ptp_tsu *tsu, ++ struct dpa_ptp_time *cnt_time) ++{ ++ struct mac_device *mac_dev = tsu->dpa_priv->mac_dev; ++ u64 tmp; ++ ++ tmp = (u64)cnt_time->sec * NANOSEC_PER_SECOND + (u64)cnt_time->nsec; ++ ++ if (mac_dev->fm_rtc_set_cnt) ++ mac_dev->fm_rtc_set_cnt(get_fm_handle(tsu->dpa_priv->net_dev), ++ tmp); ++ ++ /* Restart fiper two seconds later */ ++ cnt_time->sec += 2; ++ cnt_time->nsec = 0; ++ dpa_set_fiper_alarm(tsu, cnt_time); ++} ++ ++static void dpa_get_drift(struct dpa_ptp_tsu *tsu, u32 *addend) ++{ ++ struct mac_device *mac_dev = tsu->dpa_priv->mac_dev; ++ u32 drift; ++ ++ if (mac_dev->fm_rtc_get_drift) ++ mac_dev->fm_rtc_get_drift(get_fm_handle(tsu->dpa_priv->net_dev), ++ &drift); ++ ++ *addend = drift; ++} ++ ++static void dpa_set_drift(struct dpa_ptp_tsu *tsu, u32 addend) ++{ ++ struct mac_device *mac_dev = tsu->dpa_priv->mac_dev; ++ ++ if (mac_dev->fm_rtc_set_drift) ++ mac_dev->fm_rtc_set_drift(get_fm_handle(tsu->dpa_priv->net_dev), ++ addend); ++} ++ ++static void dpa_flush_timestamp(struct dpa_ptp_tsu *tsu) ++{ ++ dpa_ptp_reset_circ(&tsu->rx_timestamps, DEFAULT_PTP_RX_BUF_SZ); ++ dpa_ptp_reset_circ(&tsu->tx_timestamps, DEFAULT_PTP_TX_BUF_SZ); ++} ++ ++int dpa_ioctl_1588(struct net_device *dev, struct ifreq *ifr, int cmd) ++{ ++ struct dpa_priv_s *priv = netdev_priv(dev); ++ struct dpa_ptp_tsu *tsu = priv->tsu; ++ struct mac_device *mac_dev = priv->mac_dev; ++ struct dpa_ptp_data ptp_data; ++ struct dpa_ptp_data *ptp_data_user; ++ struct dpa_ptp_time act_time; ++ u32 addend; ++ int retval = 0; ++ ++ if (!tsu || !tsu->valid) ++ return -ENODEV; ++ ++ switch (cmd) { ++ case PTP_ENBL_TXTS_IOCTL: ++ tsu->hwts_tx_en_ioctl = 1; ++ if (mac_dev->fm_rtc_enable) ++ mac_dev->fm_rtc_enable(get_fm_handle(dev)); ++ if (mac_dev->ptp_enable) ++ mac_dev->ptp_enable(mac_dev->get_mac_handle(mac_dev)); ++ break; ++ case PTP_DSBL_TXTS_IOCTL: ++ tsu->hwts_tx_en_ioctl = 0; ++ if (mac_dev->fm_rtc_disable) ++ mac_dev->fm_rtc_disable(get_fm_handle(dev)); ++ if (mac_dev->ptp_disable) ++ mac_dev->ptp_disable(mac_dev->get_mac_handle(mac_dev)); ++ break; ++ case PTP_ENBL_RXTS_IOCTL: ++ tsu->hwts_rx_en_ioctl = 1; ++ break; ++ case PTP_DSBL_RXTS_IOCTL: ++ tsu->hwts_rx_en_ioctl = 0; ++ break; ++ case PTP_GET_RX_TIMESTAMP: ++ ptp_data_user = (struct dpa_ptp_data *)ifr->ifr_data; ++ if (copy_from_user(&ptp_data.ident, ++ &ptp_data_user->ident, sizeof(ptp_data.ident))) ++ return -EINVAL; ++ ++ if (dpa_get_rx_timestamp(tsu, &ptp_data.ident, &ptp_data.ts)) ++ return -EAGAIN; ++ ++ if (copy_to_user((void __user *)&ptp_data_user->ts, ++ &ptp_data.ts, sizeof(ptp_data.ts))) ++ return -EFAULT; ++ break; ++ case PTP_GET_TX_TIMESTAMP: ++ ptp_data_user = (struct dpa_ptp_data *)ifr->ifr_data; ++ if (copy_from_user(&ptp_data.ident, ++ &ptp_data_user->ident, sizeof(ptp_data.ident))) ++ return -EINVAL; ++ ++ if (dpa_get_tx_timestamp(tsu, &ptp_data.ident, &ptp_data.ts)) ++ return -EAGAIN; ++ ++ if (copy_to_user((void __user *)&ptp_data_user->ts, ++ &ptp_data.ts, sizeof(ptp_data.ts))) ++ return -EFAULT; ++ break; ++ case PTP_GET_TIME: ++ dpa_get_curr_cnt(tsu, &act_time); ++ if (copy_to_user(ifr->ifr_data, &act_time, sizeof(act_time))) ++ return -EFAULT; ++ break; ++ case PTP_SET_TIME: ++ if (copy_from_user(&act_time, ifr->ifr_data, sizeof(act_time))) ++ return -EINVAL; ++ dpa_set_1588cnt(tsu, &act_time); ++ break; ++ case PTP_GET_ADJ: ++ dpa_get_drift(tsu, &addend); ++ if (copy_to_user(ifr->ifr_data, &addend, sizeof(addend))) ++ return -EFAULT; ++ break; ++ case PTP_SET_ADJ: ++ if (copy_from_user(&addend, ifr->ifr_data, sizeof(addend))) ++ return -EINVAL; ++ dpa_set_drift(tsu, addend); ++ break; ++ case PTP_SET_FIPER_ALARM: ++ if (copy_from_user(&act_time, ifr->ifr_data, sizeof(act_time))) ++ return -EINVAL; ++ dpa_set_fiper_alarm(tsu, &act_time); ++ break; ++ case PTP_CLEANUP_TS: ++ dpa_flush_timestamp(tsu); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return retval; ++} ++ ++int dpa_ptp_init(struct dpa_priv_s *priv) ++{ ++ struct dpa_ptp_tsu *tsu; ++ ++ /* Allocate memory for PTP structure */ ++ tsu = kzalloc(sizeof(struct dpa_ptp_tsu), GFP_KERNEL); ++ if (!tsu) ++ return -ENOMEM; ++ ++ tsu->valid = TRUE; ++ tsu->dpa_priv = priv; ++ ++ dpa_ptp_init_circ(&tsu->rx_timestamps, DEFAULT_PTP_RX_BUF_SZ); ++ dpa_ptp_init_circ(&tsu->tx_timestamps, DEFAULT_PTP_TX_BUF_SZ); ++ ++ priv->tsu = tsu; ++ ++ return 0; ++} ++EXPORT_SYMBOL(dpa_ptp_init); ++ ++void dpa_ptp_cleanup(struct dpa_priv_s *priv) ++{ ++ struct dpa_ptp_tsu *tsu = priv->tsu; ++ ++ tsu->valid = FALSE; ++ vfree(tsu->rx_timestamps.circ_buf.buf); ++ vfree(tsu->tx_timestamps.circ_buf.buf); ++ ++ kfree(tsu); ++} ++EXPORT_SYMBOL(dpa_ptp_cleanup); +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.h b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.h +new file mode 100644 +index 00000000..73390168 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_1588.h +@@ -0,0 +1,138 @@ ++/* Copyright (C) 2011 Freescale Semiconductor, 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ */ ++#ifndef __DPAA_1588_H__ ++#define __DPAA_1588_H__ ++ ++#include ++#include ++#include ++#include ++ ++#define DEFAULT_PTP_RX_BUF_SZ 256 ++#define DEFAULT_PTP_TX_BUF_SZ 256 ++ ++/* 1588 private ioctl calls */ ++#define PTP_ENBL_TXTS_IOCTL SIOCDEVPRIVATE ++#define PTP_DSBL_TXTS_IOCTL (SIOCDEVPRIVATE + 1) ++#define PTP_ENBL_RXTS_IOCTL (SIOCDEVPRIVATE + 2) ++#define PTP_DSBL_RXTS_IOCTL (SIOCDEVPRIVATE + 3) ++#define PTP_GET_TX_TIMESTAMP (SIOCDEVPRIVATE + 4) ++#define PTP_GET_RX_TIMESTAMP (SIOCDEVPRIVATE + 5) ++#define PTP_SET_TIME (SIOCDEVPRIVATE + 6) ++#define PTP_GET_TIME (SIOCDEVPRIVATE + 7) ++#define PTP_SET_FIPER_ALARM (SIOCDEVPRIVATE + 8) ++#define PTP_SET_ADJ (SIOCDEVPRIVATE + 9) ++#define PTP_GET_ADJ (SIOCDEVPRIVATE + 10) ++#define PTP_CLEANUP_TS (SIOCDEVPRIVATE + 11) ++ ++/* PTP V2 message type */ ++enum { ++ PTP_MSGTYPE_SYNC = 0x0, ++ PTP_MSGTYPE_DELREQ = 0x1, ++ PTP_MSGTYPE_PDELREQ = 0x2, ++ PTP_MSGTYPE_PDELRESP = 0x3, ++ PTP_MSGTYPE_FLWUP = 0x8, ++ PTP_MSGTYPE_DELRESP = 0x9, ++ PTP_MSGTYPE_PDELRES_FLWUP = 0xA, ++ PTP_MSGTYPE_ANNOUNCE = 0xB, ++ PTP_MSGTYPE_SGNLNG = 0xC, ++ PTP_MSGTYPE_MNGMNT = 0xD, ++}; ++ ++/* Byte offset of data in the PTP V2 headers */ ++#define PTP_OFFS_MSG_TYPE 0 ++#define PTP_OFFS_VER_PTP 1 ++#define PTP_OFFS_MSG_LEN 2 ++#define PTP_OFFS_DOM_NMB 4 ++#define PTP_OFFS_FLAGS 6 ++#define PTP_OFFS_CORFIELD 8 ++#define PTP_OFFS_SRCPRTID 20 ++#define PTP_OFFS_SEQ_ID 30 ++#define PTP_OFFS_CTRL 32 ++#define PTP_OFFS_LOGMEAN 33 ++ ++#define PTP_IP_OFFS 14 ++#define PTP_UDP_OFFS 34 ++#define PTP_HEADER_OFFS 42 ++#define PTP_MSG_TYPE_OFFS (PTP_HEADER_OFFS + PTP_OFFS_MSG_TYPE) ++#define PTP_SPORT_ID_OFFS (PTP_HEADER_OFFS + PTP_OFFS_SRCPRTID) ++#define PTP_SEQ_ID_OFFS (PTP_HEADER_OFFS + PTP_OFFS_SEQ_ID) ++#define PTP_CTRL_OFFS (PTP_HEADER_OFFS + PTP_OFFS_CTRL) ++ ++/* 1588-2008 network protocol enumeration values */ ++#define DPA_PTP_PROT_IPV4 1 ++#define DPA_PTP_PROT_IPV6 2 ++#define DPA_PTP_PROT_802_3 3 ++#define DPA_PTP_PROT_DONTCARE 0xFFFF ++ ++#define DPA_PTP_SOURCE_PORT_LENGTH 10 ++#define DPA_PTP_HEADER_SZE 34 ++#define DPA_ETYPE_LEN 2 ++#define DPA_VLAN_TAG_LEN 4 ++#define NANOSEC_PER_SECOND 1000000000 ++ ++/* The threshold between the current found one and the oldest one */ ++#define TS_ACCUMULATION_THRESHOLD 50 ++ ++/* Struct needed to identify a timestamp */ ++struct dpa_ptp_ident { ++ u8 version; ++ u8 msg_type; ++ u16 netw_prot; ++ u16 seq_id; ++ u8 snd_port_id[DPA_PTP_SOURCE_PORT_LENGTH]; ++}; ++ ++/* Timestamp format in 1588-2008 */ ++struct dpa_ptp_time { ++ u64 sec; /* just 48 bit used */ ++ u32 nsec; ++}; ++ ++/* needed for timestamp data over ioctl */ ++struct dpa_ptp_data { ++ struct dpa_ptp_ident ident; ++ struct dpa_ptp_time ts; ++}; ++ ++struct dpa_ptp_circ_buf { ++ struct circ_buf circ_buf; ++ u32 size; ++ spinlock_t ptp_lock; ++}; ++ ++/* PTP TSU control structure */ ++struct dpa_ptp_tsu { ++ struct dpa_priv_s *dpa_priv; ++ bool valid; ++ struct dpa_ptp_circ_buf rx_timestamps; ++ struct dpa_ptp_circ_buf tx_timestamps; ++ ++ /* HW timestamping over ioctl enabled flag */ ++ int hwts_tx_en_ioctl; ++ int hwts_rx_en_ioctl; ++}; ++ ++extern int dpa_ptp_init(struct dpa_priv_s *priv); ++extern void dpa_ptp_cleanup(struct dpa_priv_s *priv); ++extern void dpa_ptp_store_txstamp(const struct dpa_priv_s *priv, ++ struct sk_buff *skb, void *data); ++extern void dpa_ptp_store_rxstamp(const struct dpa_priv_s *priv, ++ struct sk_buff *skb, void *data); ++extern int dpa_ioctl_1588(struct net_device *dev, struct ifreq *ifr, int cmd); ++#endif +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.c +new file mode 100644 +index 00000000..25d9f5f1 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.c +@@ -0,0 +1,180 @@ ++/* Copyright 2008-2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include /* struct qm_mcr_querycgr */ ++#include ++#include "dpaa_debugfs.h" ++#include "dpaa_eth.h" /* struct dpa_priv_s, dpa_percpu_priv_s, dpa_bp */ ++ ++#define DPA_DEBUGFS_DESCRIPTION "FSL DPAA Ethernet debugfs entries" ++#define DPA_ETH_DEBUGFS_ROOT "fsl_dpa" ++ ++static struct dentry *dpa_debugfs_root; ++ ++static int __cold dpa_debugfs_loop_open(struct inode *inode, struct file *file); ++static ssize_t dpa_loop_write(struct file *f, ++ const char __user *buf, size_t count, loff_t *off); ++ ++static const struct file_operations dpa_debugfs_lp_fops = { ++ .open = dpa_debugfs_loop_open, ++ .write = dpa_loop_write, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static int dpa_debugfs_loop_show(struct seq_file *file, void *offset) ++{ ++ struct dpa_priv_s *priv; ++ ++ BUG_ON(offset == NULL); ++ ++ priv = netdev_priv((struct net_device *)file->private); ++ seq_printf(file, "%d->%d\n", priv->loop_id, priv->loop_to); ++ ++ return 0; ++} ++ ++static int user_input_convert(const char __user *user_buf, size_t count, ++ long *val) ++{ ++ char buf[12]; ++ ++ if (count > sizeof(buf) - 1) ++ return -EINVAL; ++ if (copy_from_user(buf, user_buf, count)) ++ return -EFAULT; ++ buf[count] = '\0'; ++ if (kstrtol(buf, 0, val)) ++ return -EINVAL; ++ return 0; ++} ++ ++static ssize_t dpa_loop_write(struct file *f, ++ const char __user *buf, size_t count, loff_t *off) ++{ ++ struct dpa_priv_s *priv; ++ struct net_device *netdev; ++ struct seq_file *sf; ++ int ret; ++ long val; ++ ++ ret = user_input_convert(buf, count, &val); ++ if (ret) ++ return ret; ++ ++ sf = (struct seq_file *)f->private_data; ++ netdev = (struct net_device *)sf->private; ++ priv = netdev_priv(netdev); ++ ++ priv->loop_to = ((val < 0) || (val > 20)) ? -1 : val; ++ ++ return count; ++} ++ ++static int __cold dpa_debugfs_loop_open(struct inode *inode, struct file *file) ++{ ++ int _errno; ++ const struct net_device *net_dev; ++ ++ _errno = single_open(file, dpa_debugfs_loop_show, inode->i_private); ++ if (unlikely(_errno < 0)) { ++ net_dev = (struct net_device *)inode->i_private; ++ ++ if (netif_msg_drv((struct dpa_priv_s *)netdev_priv(net_dev))) ++ netdev_err(net_dev, "single_open() = %d\n", ++ _errno); ++ } ++ ++ return _errno; ++} ++ ++ ++int dpa_netdev_debugfs_create(struct net_device *net_dev) ++{ ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ static int cnt; ++ char loop_file_name[100]; ++ ++ if (unlikely(dpa_debugfs_root == NULL)) { ++ pr_err(KBUILD_MODNAME ": %s:%hu:%s(): \t%s\n", ++ KBUILD_BASENAME".c", __LINE__, __func__, ++ "root debugfs missing, possible module ordering issue"); ++ return -ENOMEM; ++ } ++ ++ sprintf(loop_file_name, "eth%d_loop", ++cnt); ++ priv->debugfs_loop_file = debugfs_create_file(loop_file_name, ++ S_IRUGO, ++ dpa_debugfs_root, ++ net_dev, ++ &dpa_debugfs_lp_fops); ++ if (unlikely(priv->debugfs_loop_file == NULL)) { ++ netdev_err(net_dev, "debugfs_create_file(%s/%s)", ++ dpa_debugfs_root->d_iname, ++ loop_file_name); ++ ++ return -ENOMEM; ++ } ++ return 0; ++} ++ ++void dpa_netdev_debugfs_remove(struct net_device *net_dev) ++{ ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ ++ debugfs_remove(priv->debugfs_loop_file); ++} ++ ++int __init dpa_debugfs_module_init(void) ++{ ++ int _errno = 0; ++ ++ pr_info(KBUILD_MODNAME ": " DPA_DEBUGFS_DESCRIPTION "\n"); ++ ++ dpa_debugfs_root = debugfs_create_dir(DPA_ETH_DEBUGFS_ROOT, NULL); ++ ++ if (unlikely(dpa_debugfs_root == NULL)) { ++ _errno = -ENOMEM; ++ pr_err(KBUILD_MODNAME ": %s:%hu:%s():\n", ++ KBUILD_BASENAME".c", __LINE__, __func__); ++ pr_err("\tdebugfs_create_dir(%s/"KBUILD_MODNAME") = %d\n", ++ DPA_ETH_DEBUGFS_ROOT, _errno); ++ } ++ ++ return _errno; ++} ++ ++void __exit dpa_debugfs_module_exit(void) ++{ ++ debugfs_remove(dpa_debugfs_root); ++} +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.h b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.h +new file mode 100644 +index 00000000..63d35427 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_debugfs.h +@@ -0,0 +1,43 @@ ++/* Copyright 2008-2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef DPAA_DEBUGFS_H_ ++#define DPAA_DEBUGFS_H_ ++ ++#include ++#include /* struct dentry needed in dpaa_eth.h */ ++ ++int dpa_netdev_debugfs_create(struct net_device *net_dev); ++void dpa_netdev_debugfs_remove(struct net_device *net_dev); ++int __init dpa_debugfs_module_init(void); ++void __exit dpa_debugfs_module_exit(void); ++ ++#endif /* DPAA_DEBUGFS_H_ */ +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c +new file mode 100644 +index 00000000..7026f916 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.c +@@ -0,0 +1,1213 @@ ++/* Copyright 2008-2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG ++#define pr_fmt(fmt) \ ++ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \ ++ KBUILD_BASENAME".c", __LINE__, __func__ ++#else ++#define pr_fmt(fmt) \ ++ KBUILD_MODNAME ": " fmt ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* arp_hdr_len() */ ++#include /* VLAN_HLEN */ ++#include /* struct icmphdr */ ++#include /* struct iphdr */ ++#include /* struct ipv6hdr */ ++#include /* struct udphdr */ ++#include /* struct tcphdr */ ++#include /* net_ratelimit() */ ++#include /* ETH_P_IP and ETH_P_IPV6 */ ++#include ++#include ++#include ++#include ++#ifdef CONFIG_SOC_BUS ++#include /* soc_device_match */ ++#endif ++ ++#include "fsl_fman.h" ++#include "fm_ext.h" ++#include "fm_port_ext.h" ++ ++#include "mac.h" ++#include "dpaa_eth.h" ++#include "dpaa_eth_common.h" ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++#include "dpaa_debugfs.h" ++#endif /* CONFIG_FSL_DPAA_DBG_LOOP */ ++ ++/* CREATE_TRACE_POINTS only needs to be defined once. Other dpa files ++ * using trace events only need to #include ++ */ ++#define CREATE_TRACE_POINTS ++#include "dpaa_eth_trace.h" ++ ++#define DPA_NAPI_WEIGHT 64 ++ ++/* Valid checksum indication */ ++#define DPA_CSUM_VALID 0xFFFF ++ ++#define DPA_DESCRIPTION "FSL DPAA Ethernet driver" ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++MODULE_AUTHOR("Andy Fleming "); ++ ++MODULE_DESCRIPTION(DPA_DESCRIPTION); ++ ++static uint8_t debug = -1; ++module_param(debug, byte, S_IRUGO); ++MODULE_PARM_DESC(debug, "Module/Driver verbosity level"); ++ ++/* This has to work in tandem with the DPA_CS_THRESHOLD_xxx values. */ ++static uint16_t tx_timeout = 1000; ++module_param(tx_timeout, ushort, S_IRUGO); ++MODULE_PARM_DESC(tx_timeout, "The Tx timeout in ms"); ++ ++static const char rtx[][3] = { ++ [RX] = "RX", ++ [TX] = "TX" ++}; ++ ++#ifndef CONFIG_PPC ++bool dpaa_errata_a010022; ++EXPORT_SYMBOL(dpaa_errata_a010022); ++#endif ++ ++/* BM */ ++ ++#define DPAA_ETH_MAX_PAD (L1_CACHE_BYTES * 8) ++ ++static uint8_t dpa_priv_common_bpid; ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++struct net_device *dpa_loop_netdevs[20]; ++#endif ++ ++#ifdef CONFIG_PM ++ ++static int dpaa_suspend(struct device *dev) ++{ ++ struct net_device *net_dev; ++ struct dpa_priv_s *priv; ++ struct mac_device *mac_dev; ++ int err = 0; ++ ++ net_dev = dev_get_drvdata(dev); ++ ++ if (net_dev->flags & IFF_UP) { ++ priv = netdev_priv(net_dev); ++ mac_dev = priv->mac_dev; ++ ++ if (priv->wol & DPAA_WOL_MAGIC) { ++ err = priv->mac_dev->set_wol(mac_dev->port_dev[RX], ++ priv->mac_dev->get_mac_handle(mac_dev), true); ++ if (err) { ++ netdev_err(net_dev, "set_wol() = %d\n", err); ++ goto set_wol_failed; ++ } ++ } ++ ++ err = fm_port_suspend(mac_dev->port_dev[RX]); ++ if (err) { ++ netdev_err(net_dev, "fm_port_suspend(RX) = %d\n", err); ++ goto rx_port_suspend_failed; ++ } ++ ++ err = fm_port_suspend(mac_dev->port_dev[TX]); ++ if (err) { ++ netdev_err(net_dev, "fm_port_suspend(TX) = %d\n", err); ++ goto tx_port_suspend_failed; ++ } ++ } ++ ++ return 0; ++ ++tx_port_suspend_failed: ++ fm_port_resume(mac_dev->port_dev[RX]); ++rx_port_suspend_failed: ++ if (priv->wol & DPAA_WOL_MAGIC) { ++ priv->mac_dev->set_wol(mac_dev->port_dev[RX], ++ priv->mac_dev->get_mac_handle(mac_dev), false); ++ } ++set_wol_failed: ++ return err; ++} ++ ++static int dpaa_resume(struct device *dev) ++{ ++ struct net_device *net_dev; ++ struct dpa_priv_s *priv; ++ struct mac_device *mac_dev; ++ int err = 0; ++ ++ net_dev = dev_get_drvdata(dev); ++ ++ if (net_dev->flags & IFF_UP) { ++ priv = netdev_priv(net_dev); ++ mac_dev = priv->mac_dev; ++ ++ err = fm_mac_resume(mac_dev->get_mac_handle(mac_dev)); ++ if (err) { ++ netdev_err(net_dev, "fm_mac_resume = %d\n", err); ++ goto resume_failed; ++ } ++ ++ err = fm_port_resume(mac_dev->port_dev[TX]); ++ if (err) { ++ netdev_err(net_dev, "fm_port_resume(TX) = %d\n", err); ++ goto resume_failed; ++ } ++ ++ err = fm_port_resume(mac_dev->port_dev[RX]); ++ if (err) { ++ netdev_err(net_dev, "fm_port_resume(RX) = %d\n", err); ++ goto resume_failed; ++ } ++ ++ if (priv->wol & DPAA_WOL_MAGIC) { ++ err = priv->mac_dev->set_wol(mac_dev->port_dev[RX], ++ priv->mac_dev->get_mac_handle(mac_dev), false); ++ if (err) { ++ netdev_err(net_dev, "set_wol() = %d\n", err); ++ goto resume_failed; ++ } ++ } ++ } ++ ++ return 0; ++ ++resume_failed: ++ return err; ++} ++ ++static const struct dev_pm_ops dpaa_pm_ops = { ++ .suspend = dpaa_suspend, ++ .resume = dpaa_resume, ++}; ++ ++#define DPAA_PM_OPS (&dpaa_pm_ops) ++ ++#else /* CONFIG_PM */ ++ ++#define DPAA_PM_OPS NULL ++ ++#endif /* CONFIG_PM */ ++ ++/* Checks whether the checksum field in Parse Results array is valid ++ * (equals 0xFFFF) and increments the .cse counter otherwise ++ */ ++static inline void ++dpa_csum_validation(const struct dpa_priv_s *priv, ++ struct dpa_percpu_priv_s *percpu_priv, ++ const struct qm_fd *fd) ++{ ++ dma_addr_t addr = qm_fd_addr(fd); ++ struct dpa_bp *dpa_bp = priv->dpa_bp; ++ void *frm = phys_to_virt(addr); ++ fm_prs_result_t *parse_result; ++ ++ if (unlikely(!frm)) ++ return; ++ ++ dma_sync_single_for_cpu(dpa_bp->dev, addr, DPA_RX_PRIV_DATA_SIZE + ++ DPA_PARSE_RESULTS_SIZE, DMA_BIDIRECTIONAL); ++ ++ parse_result = (fm_prs_result_t *)(frm + DPA_RX_PRIV_DATA_SIZE); ++ ++ if (parse_result->cksum != DPA_CSUM_VALID) ++ percpu_priv->rx_errors.cse++; ++} ++ ++static void _dpa_rx_error(struct net_device *net_dev, ++ const struct dpa_priv_s *priv, ++ struct dpa_percpu_priv_s *percpu_priv, ++ const struct qm_fd *fd, ++ u32 fqid) ++{ ++ /* limit common, possibly innocuous Rx FIFO Overflow errors' ++ * interference with zero-loss convergence benchmark results. ++ */ ++ if (likely(fd->status & FM_FD_STAT_ERR_PHYSICAL)) ++ pr_warn_once("fsl-dpa: non-zero error counters in fman statistics (sysfs)\n"); ++ else ++ if (netif_msg_hw(priv) && net_ratelimit()) ++ netdev_dbg(net_dev, "Err FD status = 0x%08x\n", ++ fd->status & FM_FD_STAT_RX_ERRORS); ++#ifdef CONFIG_FSL_DPAA_HOOKS ++ if (dpaa_eth_hooks.rx_error && ++ dpaa_eth_hooks.rx_error(net_dev, fd, fqid) == DPAA_ETH_STOLEN) ++ /* it's up to the hook to perform resource cleanup */ ++ return; ++#endif ++ percpu_priv->stats.rx_errors++; ++ ++ if (fd->status & FM_PORT_FRM_ERR_DMA) ++ percpu_priv->rx_errors.dme++; ++ if (fd->status & FM_PORT_FRM_ERR_PHYSICAL) ++ percpu_priv->rx_errors.fpe++; ++ if (fd->status & FM_PORT_FRM_ERR_SIZE) ++ percpu_priv->rx_errors.fse++; ++ if (fd->status & FM_PORT_FRM_ERR_PRS_HDR_ERR) ++ percpu_priv->rx_errors.phe++; ++ if (fd->status & FM_FD_STAT_L4CV) ++ dpa_csum_validation(priv, percpu_priv, fd); ++ ++ dpa_fd_release(net_dev, fd); ++} ++ ++static void _dpa_tx_error(struct net_device *net_dev, ++ const struct dpa_priv_s *priv, ++ struct dpa_percpu_priv_s *percpu_priv, ++ const struct qm_fd *fd, ++ u32 fqid) ++{ ++ struct sk_buff *skb; ++ ++ if (netif_msg_hw(priv) && net_ratelimit()) ++ netdev_warn(net_dev, "FD status = 0x%08x\n", ++ fd->status & FM_FD_STAT_TX_ERRORS); ++#ifdef CONFIG_FSL_DPAA_HOOKS ++ if (dpaa_eth_hooks.tx_error && ++ dpaa_eth_hooks.tx_error(net_dev, fd, fqid) == DPAA_ETH_STOLEN) ++ /* now the hook must ensure proper cleanup */ ++ return; ++#endif ++ percpu_priv->stats.tx_errors++; ++ ++ /* If we intended the buffers from this frame to go into the bpools ++ * when the FMan transmit was done, we need to put it in manually. ++ */ ++ if (fd->bpid != 0xff) { ++ dpa_fd_release(net_dev, fd); ++ return; ++ } ++ ++ skb = _dpa_cleanup_tx_fd(priv, fd); ++ dev_kfree_skb(skb); ++} ++ ++/* Helper function to factor out frame validation logic on all Rx paths. Its ++ * purpose is to extract from the Parse Results structure information about ++ * the integrity of the frame, its checksum, the length of the parsed headers ++ * and whether the frame is suitable for GRO. ++ * ++ * Assumes no parser errors, since any error frame is dropped before this ++ * function is called. ++ * ++ * @skb will have its ip_summed field overwritten; ++ * @use_gro will only be written with 0, if the frame is definitely not ++ * GRO-able; otherwise, it will be left unchanged; ++ * @hdr_size will be written with a safe value, at least the size of the ++ * headers' length. ++ */ ++void __hot _dpa_process_parse_results(const fm_prs_result_t *parse_results, ++ const struct qm_fd *fd, ++ struct sk_buff *skb, int *use_gro) ++{ ++ if (fd->status & FM_FD_STAT_L4CV) { ++ /* The parser has run and performed L4 checksum validation. ++ * We know there were no parser errors (and implicitly no ++ * L4 csum error), otherwise we wouldn't be here. ++ */ ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ ++ /* Don't go through GRO for certain types of traffic that ++ * we know are not GRO-able, such as dgram-based protocols. ++ * In the worst-case scenarios, such as small-pkt terminating ++ * UDP, the extra GRO processing would be overkill. ++ * ++ * The only protocol the Parser supports that is also GRO-able ++ * is currently TCP. ++ */ ++ if (!fm_l4_frame_is_tcp(parse_results)) ++ *use_gro = 0; ++ ++ return; ++ } ++ ++ /* We're here because either the parser didn't run or the L4 checksum ++ * was not verified. This may include the case of a UDP frame with ++ * checksum zero or an L4 proto other than TCP/UDP ++ */ ++ skb->ip_summed = CHECKSUM_NONE; ++ ++ /* Bypass GRO for unknown traffic or if no PCDs are applied */ ++ *use_gro = 0; ++} ++ ++int dpaa_eth_poll(struct napi_struct *napi, int budget) ++{ ++ struct dpa_napi_portal *np = ++ container_of(napi, struct dpa_napi_portal, napi); ++ ++ int cleaned = qman_p_poll_dqrr(np->p, budget); ++ ++ if (cleaned < budget) { ++ int tmp; ++ napi_complete(napi); ++ tmp = qman_p_irqsource_add(np->p, QM_PIRQ_DQRI); ++ DPA_BUG_ON(tmp); ++ } ++ ++ return cleaned; ++} ++EXPORT_SYMBOL(dpaa_eth_poll); ++ ++static void __hot _dpa_tx_conf(struct net_device *net_dev, ++ const struct dpa_priv_s *priv, ++ struct dpa_percpu_priv_s *percpu_priv, ++ const struct qm_fd *fd, ++ u32 fqid) ++{ ++ struct sk_buff *skb; ++ ++ /* do we need the timestamp for the error frames? */ ++ ++ if (unlikely(fd->status & FM_FD_STAT_TX_ERRORS) != 0) { ++ if (netif_msg_hw(priv) && net_ratelimit()) ++ netdev_warn(net_dev, "FD status = 0x%08x\n", ++ fd->status & FM_FD_STAT_TX_ERRORS); ++ ++ percpu_priv->stats.tx_errors++; ++ } ++ ++ /* hopefully we need not get the timestamp before the hook */ ++#ifdef CONFIG_FSL_DPAA_HOOKS ++ if (dpaa_eth_hooks.tx_confirm && dpaa_eth_hooks.tx_confirm(net_dev, ++ fd, fqid) == DPAA_ETH_STOLEN) ++ /* it's the hook that must now perform cleanup */ ++ return; ++#endif ++ /* This might not perfectly reflect the reality, if the core dequeuing ++ * the Tx confirmation is different from the one that did the enqueue, ++ * but at least it'll show up in the total count. ++ */ ++ percpu_priv->tx_confirm++; ++ ++ skb = _dpa_cleanup_tx_fd(priv, fd); ++ ++ dev_kfree_skb(skb); ++} ++ ++enum qman_cb_dqrr_result ++priv_rx_error_dqrr(struct qman_portal *portal, ++ struct qman_fq *fq, ++ const struct qm_dqrr_entry *dq) ++{ ++ struct net_device *net_dev; ++ struct dpa_priv_s *priv; ++ struct dpa_percpu_priv_s *percpu_priv; ++ int *count_ptr; ++ ++ net_dev = ((struct dpa_fq *)fq)->net_dev; ++ priv = netdev_priv(net_dev); ++ ++ percpu_priv = raw_cpu_ptr(priv->percpu_priv); ++ count_ptr = raw_cpu_ptr(priv->dpa_bp->percpu_count); ++ ++ if (dpaa_eth_napi_schedule(percpu_priv, portal)) ++ return qman_cb_dqrr_stop; ++ ++ if (unlikely(dpaa_eth_refill_bpools(priv->dpa_bp, count_ptr))) ++ /* Unable to refill the buffer pool due to insufficient ++ * system memory. Just release the frame back into the pool, ++ * otherwise we'll soon end up with an empty buffer pool. ++ */ ++ dpa_fd_release(net_dev, &dq->fd); ++ else ++ _dpa_rx_error(net_dev, priv, percpu_priv, &dq->fd, fq->fqid); ++ ++ return qman_cb_dqrr_consume; ++} ++ ++ ++enum qman_cb_dqrr_result __hot ++priv_rx_default_dqrr(struct qman_portal *portal, ++ struct qman_fq *fq, ++ const struct qm_dqrr_entry *dq) ++{ ++ struct net_device *net_dev; ++ struct dpa_priv_s *priv; ++ struct dpa_percpu_priv_s *percpu_priv; ++ int *count_ptr; ++ struct dpa_bp *dpa_bp; ++ ++ net_dev = ((struct dpa_fq *)fq)->net_dev; ++ priv = netdev_priv(net_dev); ++ dpa_bp = priv->dpa_bp; ++ ++ /* Trace the Rx fd */ ++ trace_dpa_rx_fd(net_dev, fq, &dq->fd); ++ ++ /* IRQ handler, non-migratable; safe to use raw_cpu_ptr here */ ++ percpu_priv = raw_cpu_ptr(priv->percpu_priv); ++ count_ptr = raw_cpu_ptr(dpa_bp->percpu_count); ++ ++ if (unlikely(dpaa_eth_napi_schedule(percpu_priv, portal))) ++ return qman_cb_dqrr_stop; ++ ++ /* Vale of plenty: make sure we didn't run out of buffers */ ++ ++ if (unlikely(dpaa_eth_refill_bpools(dpa_bp, count_ptr))) ++ /* Unable to refill the buffer pool due to insufficient ++ * system memory. Just release the frame back into the pool, ++ * otherwise we'll soon end up with an empty buffer pool. ++ */ ++ dpa_fd_release(net_dev, &dq->fd); ++ else ++ _dpa_rx(net_dev, portal, priv, percpu_priv, &dq->fd, fq->fqid, ++ count_ptr); ++ ++ return qman_cb_dqrr_consume; ++} ++ ++enum qman_cb_dqrr_result ++priv_tx_conf_error_dqrr(struct qman_portal *portal, ++ struct qman_fq *fq, ++ const struct qm_dqrr_entry *dq) ++{ ++ struct net_device *net_dev; ++ struct dpa_priv_s *priv; ++ struct dpa_percpu_priv_s *percpu_priv; ++ ++ net_dev = ((struct dpa_fq *)fq)->net_dev; ++ priv = netdev_priv(net_dev); ++ ++ percpu_priv = raw_cpu_ptr(priv->percpu_priv); ++ ++ if (dpaa_eth_napi_schedule(percpu_priv, portal)) ++ return qman_cb_dqrr_stop; ++ ++ _dpa_tx_error(net_dev, priv, percpu_priv, &dq->fd, fq->fqid); ++ ++ return qman_cb_dqrr_consume; ++} ++ ++enum qman_cb_dqrr_result __hot ++priv_tx_conf_default_dqrr(struct qman_portal *portal, ++ struct qman_fq *fq, ++ const struct qm_dqrr_entry *dq) ++{ ++ struct net_device *net_dev; ++ struct dpa_priv_s *priv; ++ struct dpa_percpu_priv_s *percpu_priv; ++ ++ net_dev = ((struct dpa_fq *)fq)->net_dev; ++ priv = netdev_priv(net_dev); ++ ++ /* Trace the fd */ ++ trace_dpa_tx_conf_fd(net_dev, fq, &dq->fd); ++ ++ /* Non-migratable context, safe to use raw_cpu_ptr */ ++ percpu_priv = raw_cpu_ptr(priv->percpu_priv); ++ ++ if (dpaa_eth_napi_schedule(percpu_priv, portal)) ++ return qman_cb_dqrr_stop; ++ ++ _dpa_tx_conf(net_dev, priv, percpu_priv, &dq->fd, fq->fqid); ++ ++ return qman_cb_dqrr_consume; ++} ++ ++void priv_ern(struct qman_portal *portal, ++ struct qman_fq *fq, ++ const struct qm_mr_entry *msg) ++{ ++ struct net_device *net_dev; ++ const struct dpa_priv_s *priv; ++ struct sk_buff *skb; ++ struct dpa_percpu_priv_s *percpu_priv; ++ struct qm_fd fd = msg->ern.fd; ++ ++ net_dev = ((struct dpa_fq *)fq)->net_dev; ++ priv = netdev_priv(net_dev); ++ /* Non-migratable context, safe to use raw_cpu_ptr */ ++ percpu_priv = raw_cpu_ptr(priv->percpu_priv); ++ ++ percpu_priv->stats.tx_dropped++; ++ percpu_priv->stats.tx_fifo_errors++; ++ count_ern(percpu_priv, msg); ++ ++ /* If we intended this buffer to go into the pool ++ * when the FM was done, we need to put it in ++ * manually. ++ */ ++ if (msg->ern.fd.bpid != 0xff) { ++ dpa_fd_release(net_dev, &fd); ++ return; ++ } ++ ++ skb = _dpa_cleanup_tx_fd(priv, &fd); ++ dev_kfree_skb_any(skb); ++} ++ ++const struct dpa_fq_cbs_t private_fq_cbs = { ++ .rx_defq = { .cb = { .dqrr = priv_rx_default_dqrr } }, ++ .tx_defq = { .cb = { .dqrr = priv_tx_conf_default_dqrr } }, ++ .rx_errq = { .cb = { .dqrr = priv_rx_error_dqrr } }, ++ .tx_errq = { .cb = { .dqrr = priv_tx_conf_error_dqrr } }, ++ .egress_ern = { .cb = { .ern = priv_ern } } ++}; ++EXPORT_SYMBOL(private_fq_cbs); ++ ++static void dpaa_eth_napi_enable(struct dpa_priv_s *priv) ++{ ++ struct dpa_percpu_priv_s *percpu_priv; ++ int i, j; ++ ++ for_each_possible_cpu(i) { ++ percpu_priv = per_cpu_ptr(priv->percpu_priv, i); ++ ++ for (j = 0; j < qman_portal_max; j++) ++ napi_enable(&percpu_priv->np[j].napi); ++ } ++} ++ ++static void dpaa_eth_napi_disable(struct dpa_priv_s *priv) ++{ ++ struct dpa_percpu_priv_s *percpu_priv; ++ int i, j; ++ ++ for_each_possible_cpu(i) { ++ percpu_priv = per_cpu_ptr(priv->percpu_priv, i); ++ ++ for (j = 0; j < qman_portal_max; j++) ++ napi_disable(&percpu_priv->np[j].napi); ++ } ++} ++ ++static int __cold dpa_eth_priv_start(struct net_device *net_dev) ++{ ++ int err; ++ struct dpa_priv_s *priv; ++ ++ priv = netdev_priv(net_dev); ++ ++ dpaa_eth_napi_enable(priv); ++ ++ err = dpa_start(net_dev); ++ if (err < 0) ++ dpaa_eth_napi_disable(priv); ++ ++ return err; ++} ++ ++ ++ ++static int __cold dpa_eth_priv_stop(struct net_device *net_dev) ++{ ++ int _errno; ++ struct dpa_priv_s *priv; ++ ++ _errno = dpa_stop(net_dev); ++ /* Allow NAPI to consume any frame still in the Rx/TxConfirm ++ * ingress queues. This is to avoid a race between the current ++ * context and ksoftirqd which could leave NAPI disabled while ++ * in fact there's still Rx traffic to be processed. ++ */ ++ usleep_range(5000, 10000); ++ ++ priv = netdev_priv(net_dev); ++ dpaa_eth_napi_disable(priv); ++ ++ return _errno; ++} ++ ++#ifdef CONFIG_NET_POLL_CONTROLLER ++static void dpaa_eth_poll_controller(struct net_device *net_dev) ++{ ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ struct dpa_percpu_priv_s *percpu_priv = ++ raw_cpu_ptr(priv->percpu_priv); ++ struct qman_portal *p; ++ const struct qman_portal_config *pc; ++ struct dpa_napi_portal *np; ++ ++ p = (struct qman_portal *)qman_get_affine_portal(smp_processor_id()); ++ pc = qman_p_get_portal_config(p); ++ np = &percpu_priv->np[pc->index]; ++ ++ qman_p_irqsource_remove(np->p, QM_PIRQ_DQRI); ++ qman_p_poll_dqrr(np->p, np->napi.weight); ++ qman_p_irqsource_add(np->p, QM_PIRQ_DQRI); ++} ++#endif ++ ++static const struct net_device_ops dpa_private_ops = { ++ .ndo_open = dpa_eth_priv_start, ++ .ndo_start_xmit = dpa_tx, ++ .ndo_stop = dpa_eth_priv_stop, ++ .ndo_tx_timeout = dpa_timeout, ++ .ndo_get_stats64 = dpa_get_stats64, ++ .ndo_set_mac_address = dpa_set_mac_address, ++ .ndo_validate_addr = eth_validate_addr, ++#ifdef CONFIG_FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE ++ .ndo_select_queue = dpa_select_queue, ++#endif ++ .ndo_change_mtu = dpa_change_mtu, ++ .ndo_set_rx_mode = dpa_set_rx_mode, ++ .ndo_init = dpa_ndo_init, ++ .ndo_set_features = dpa_set_features, ++ .ndo_fix_features = dpa_fix_features, ++ .ndo_do_ioctl = dpa_ioctl, ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ .ndo_poll_controller = dpaa_eth_poll_controller, ++#endif ++}; ++ ++static int dpa_private_napi_add(struct net_device *net_dev) ++{ ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ struct dpa_percpu_priv_s *percpu_priv; ++ int i, cpu; ++ ++ for_each_possible_cpu(cpu) { ++ percpu_priv = per_cpu_ptr(priv->percpu_priv, cpu); ++ ++ percpu_priv->np = devm_kzalloc(net_dev->dev.parent, ++ qman_portal_max * sizeof(struct dpa_napi_portal), ++ GFP_KERNEL); ++ ++ if (unlikely(percpu_priv->np == NULL)) { ++ dev_err(net_dev->dev.parent, "devm_kzalloc() failed\n"); ++ return -ENOMEM; ++ } ++ ++ for (i = 0; i < qman_portal_max; i++) ++ netif_napi_add(net_dev, &percpu_priv->np[i].napi, ++ dpaa_eth_poll, DPA_NAPI_WEIGHT); ++ } ++ ++ return 0; ++} ++ ++void dpa_private_napi_del(struct net_device *net_dev) ++{ ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ struct dpa_percpu_priv_s *percpu_priv; ++ int i, cpu; ++ ++ for_each_possible_cpu(cpu) { ++ percpu_priv = per_cpu_ptr(priv->percpu_priv, cpu); ++ ++ if (percpu_priv->np) { ++ for (i = 0; i < qman_portal_max; i++) ++ netif_napi_del(&percpu_priv->np[i].napi); ++ ++ devm_kfree(net_dev->dev.parent, percpu_priv->np); ++ } ++ } ++} ++EXPORT_SYMBOL(dpa_private_napi_del); ++ ++static int dpa_private_netdev_init(struct net_device *net_dev) ++{ ++ int i; ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ struct dpa_percpu_priv_s *percpu_priv; ++ const uint8_t *mac_addr; ++ ++ /* Although we access another CPU's private data here ++ * we do it at initialization so it is safe ++ */ ++ for_each_possible_cpu(i) { ++ percpu_priv = per_cpu_ptr(priv->percpu_priv, i); ++ percpu_priv->net_dev = net_dev; ++ } ++ ++ net_dev->netdev_ops = &dpa_private_ops; ++ mac_addr = priv->mac_dev->addr; ++ ++ net_dev->mem_start = priv->mac_dev->res->start; ++ net_dev->mem_end = priv->mac_dev->res->end; ++ ++ net_dev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | ++ NETIF_F_LLTX); ++ ++ /* Advertise S/G and HIGHDMA support for private interfaces */ ++ net_dev->hw_features |= NETIF_F_SG | NETIF_F_HIGHDMA; ++ /* Recent kernels enable GSO automatically, if ++ * we declare NETIF_F_SG. For conformity, we'll ++ * still declare GSO explicitly. ++ */ ++ net_dev->features |= NETIF_F_GSO; ++ ++ /* Advertise GRO support */ ++ net_dev->features |= NETIF_F_GRO; ++ ++ /* Advertise NETIF_F_HW_ACCEL_MQ to avoid Tx timeout warnings */ ++ net_dev->features |= NETIF_F_HW_ACCEL_MQ; ++ ++ return dpa_netdev_init(net_dev, mac_addr, tx_timeout); ++} ++ ++static struct dpa_bp * __cold ++dpa_priv_bp_probe(struct device *dev) ++{ ++ struct dpa_bp *dpa_bp; ++ ++ dpa_bp = devm_kzalloc(dev, sizeof(*dpa_bp), GFP_KERNEL); ++ if (unlikely(dpa_bp == NULL)) { ++ dev_err(dev, "devm_kzalloc() failed\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ dpa_bp->percpu_count = devm_alloc_percpu(dev, *dpa_bp->percpu_count); ++ dpa_bp->target_count = CONFIG_FSL_DPAA_ETH_MAX_BUF_COUNT; ++ ++ dpa_bp->seed_cb = dpa_bp_priv_seed; ++ dpa_bp->free_buf_cb = _dpa_bp_free_pf; ++ ++ return dpa_bp; ++} ++ ++/* Place all ingress FQs (Rx Default, Rx Error, PCD FQs) in a dedicated CGR. ++ * We won't be sending congestion notifications to FMan; for now, we just use ++ * this CGR to generate enqueue rejections to FMan in order to drop the frames ++ * before they reach our ingress queues and eat up memory. ++ */ ++static int dpaa_eth_priv_ingress_cgr_init(struct dpa_priv_s *priv) ++{ ++ struct qm_mcc_initcgr initcgr; ++ u32 cs_th; ++ int err; ++ ++ err = qman_alloc_cgrid(&priv->ingress_cgr.cgrid); ++ if (err < 0) { ++ pr_err("Error %d allocating CGR ID\n", err); ++ goto out_error; ++ } ++ ++ /* Enable CS TD, but disable Congestion State Change Notifications. */ ++ initcgr.we_mask = QM_CGR_WE_CS_THRES; ++ initcgr.cgr.cscn_en = QM_CGR_EN; ++ cs_th = CONFIG_FSL_DPAA_INGRESS_CS_THRESHOLD; ++ qm_cgr_cs_thres_set64(&initcgr.cgr.cs_thres, cs_th, 1); ++ ++ initcgr.we_mask |= QM_CGR_WE_CSTD_EN; ++ initcgr.cgr.cstd_en = QM_CGR_EN; ++ ++ /* This is actually a hack, because this CGR will be associated with ++ * our affine SWP. However, we'll place our ingress FQs in it. ++ */ ++ err = qman_create_cgr(&priv->ingress_cgr, QMAN_CGR_FLAG_USE_INIT, ++ &initcgr); ++ if (err < 0) { ++ pr_err("Error %d creating ingress CGR with ID %d\n", err, ++ priv->ingress_cgr.cgrid); ++ qman_release_cgrid(priv->ingress_cgr.cgrid); ++ goto out_error; ++ } ++ pr_debug("Created ingress CGR %d for netdev with hwaddr %pM\n", ++ priv->ingress_cgr.cgrid, priv->mac_dev->addr); ++ ++ /* struct qman_cgr allows special cgrid values (i.e. outside the 0..255 ++ * range), but we have no common initialization path between the ++ * different variants of the DPAA Eth driver, so we do it here rather ++ * than modifying every other variant than "private Eth". ++ */ ++ priv->use_ingress_cgr = true; ++ ++out_error: ++ return err; ++} ++ ++static int dpa_priv_bp_create(struct net_device *net_dev, struct dpa_bp *dpa_bp, ++ size_t count) ++{ ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ int i; ++ ++ if (netif_msg_probe(priv)) ++ dev_dbg(net_dev->dev.parent, ++ "Using private BM buffer pools\n"); ++ ++ priv->bp_count = count; ++ ++ for (i = 0; i < count; i++) { ++ int err; ++ err = dpa_bp_alloc(&dpa_bp[i]); ++ if (err < 0) { ++ dpa_bp_free(priv); ++ priv->dpa_bp = NULL; ++ return err; ++ } ++ ++ priv->dpa_bp = &dpa_bp[i]; ++ } ++ ++ dpa_priv_common_bpid = priv->dpa_bp->bpid; ++ return 0; ++} ++ ++static const struct of_device_id dpa_match[]; ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++static int dpa_new_loop_id(void) ++{ ++ static int if_id; ++ ++ return if_id++; ++} ++#endif ++ ++static int ++dpaa_eth_priv_probe(struct platform_device *_of_dev) ++{ ++ int err = 0, i, channel; ++ struct device *dev; ++ struct device_node *dpa_node; ++ struct dpa_bp *dpa_bp; ++ size_t count = 1; ++ struct net_device *net_dev = NULL; ++ struct dpa_priv_s *priv = NULL; ++ struct dpa_percpu_priv_s *percpu_priv; ++ struct fm_port_fqs port_fqs; ++ struct dpa_buffer_layout_s *buf_layout = NULL; ++ struct mac_device *mac_dev; ++ ++ dev = &_of_dev->dev; ++ ++ dpa_node = dev->of_node; ++ ++ if (!of_device_is_available(dpa_node)) ++ return -ENODEV; ++ ++ /* Get the buffer pools assigned to this interface; ++ * run only once the default pool probing code ++ */ ++ dpa_bp = (dpa_bpid2pool(dpa_priv_common_bpid)) ? : ++ dpa_priv_bp_probe(dev); ++ if (IS_ERR(dpa_bp)) ++ return PTR_ERR(dpa_bp); ++ ++ /* Allocate this early, so we can store relevant information in ++ * the private area (needed by 1588 code in dpa_mac_probe) ++ */ ++ net_dev = alloc_etherdev_mq(sizeof(*priv), DPAA_ETH_TX_QUEUES); ++ if (!net_dev) { ++ dev_err(dev, "alloc_etherdev_mq() failed\n"); ++ goto alloc_etherdev_mq_failed; ++ } ++ ++ /* Do this here, so we can be verbose early */ ++ SET_NETDEV_DEV(net_dev, dev); ++ dev_set_drvdata(dev, net_dev); ++ ++ priv = netdev_priv(net_dev); ++ priv->net_dev = net_dev; ++ strcpy(priv->if_type, "private"); ++ ++ priv->msg_enable = netif_msg_init(debug, -1); ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++ priv->loop_id = dpa_new_loop_id(); ++ priv->loop_to = -1; /* disabled by default */ ++ dpa_loop_netdevs[priv->loop_id] = net_dev; ++#endif ++ ++ mac_dev = dpa_mac_probe(_of_dev); ++ if (IS_ERR(mac_dev) || !mac_dev) { ++ err = PTR_ERR(mac_dev); ++ goto mac_probe_failed; ++ } ++ ++ /* We have physical ports, so we need to establish ++ * the buffer layout. ++ */ ++ buf_layout = devm_kzalloc(dev, 2 * sizeof(*buf_layout), ++ GFP_KERNEL); ++ if (!buf_layout) { ++ dev_err(dev, "devm_kzalloc() failed\n"); ++ goto alloc_failed; ++ } ++ dpa_set_buffers_layout(mac_dev, buf_layout); ++ ++ /* For private ports, need to compute the size of the default ++ * buffer pool, based on FMan port buffer layout;also update ++ * the maximum buffer size for private ports if necessary ++ */ ++ dpa_bp->size = dpa_bp_size(&buf_layout[RX]); ++ ++#ifdef CONFIG_FSL_DPAA_ETH_JUMBO_FRAME ++ /* We only want to use jumbo frame optimization if we actually have ++ * L2 MAX FRM set for jumbo frames as well. ++ */ ++#ifndef CONFIG_PPC ++ if (likely(!dpaa_errata_a010022)) ++#endif ++ if(fm_get_max_frm() < 9600) ++ dev_warn(dev, ++ "Invalid configuration: if jumbo frames support is on, FSL_FM_MAX_FRAME_SIZE should be set to 9600\n"); ++#endif ++ ++ INIT_LIST_HEAD(&priv->dpa_fq_list); ++ ++ memset(&port_fqs, 0, sizeof(port_fqs)); ++ ++ err = dpa_fq_probe_mac(dev, &priv->dpa_fq_list, &port_fqs, true, RX); ++ if (!err) ++ err = dpa_fq_probe_mac(dev, &priv->dpa_fq_list, ++ &port_fqs, true, TX); ++ ++ if (err < 0) ++ goto fq_probe_failed; ++ ++ /* bp init */ ++ ++ err = dpa_priv_bp_create(net_dev, dpa_bp, count); ++ ++ if (err < 0) ++ goto bp_create_failed; ++ ++ priv->mac_dev = mac_dev; ++ ++ channel = dpa_get_channel(); ++ ++ if (channel < 0) { ++ err = channel; ++ goto get_channel_failed; ++ } ++ ++ priv->channel = (uint16_t)channel; ++ dpaa_eth_add_channel(priv->channel); ++ ++ dpa_fq_setup(priv, &private_fq_cbs, priv->mac_dev->port_dev[TX]); ++ ++ /* Create a congestion group for this netdev, with ++ * dynamically-allocated CGR ID. ++ * Must be executed after probing the MAC, but before ++ * assigning the egress FQs to the CGRs. ++ */ ++ err = dpaa_eth_cgr_init(priv); ++ if (err < 0) { ++ dev_err(dev, "Error initializing CGR\n"); ++ goto tx_cgr_init_failed; ++ } ++ err = dpaa_eth_priv_ingress_cgr_init(priv); ++ if (err < 0) { ++ dev_err(dev, "Error initializing ingress CGR\n"); ++ goto rx_cgr_init_failed; ++ } ++ ++ /* Add the FQs to the interface, and make them active */ ++ err = dpa_fqs_init(dev, &priv->dpa_fq_list, false); ++ if (err < 0) ++ goto fq_alloc_failed; ++ ++ priv->buf_layout = buf_layout; ++ priv->tx_headroom = dpa_get_headroom(&priv->buf_layout[TX]); ++ priv->rx_headroom = dpa_get_headroom(&priv->buf_layout[RX]); ++ ++ /* All real interfaces need their ports initialized */ ++ dpaa_eth_init_ports(mac_dev, dpa_bp, count, &port_fqs, ++ buf_layout, dev); ++ ++#ifdef CONFIG_FMAN_PFC ++ for (i = 0; i < CONFIG_FMAN_PFC_COS_COUNT; i++) { ++ err = fm_port_set_pfc_priorities_mapping_to_qman_wq( ++ mac_dev->port_dev[TX], i, i); ++ if (unlikely(err != 0)) { ++ dev_err(dev, "Error maping PFC %u to WQ %u\n", i, i); ++ goto pfc_mapping_failed; ++ } ++ } ++#endif ++ ++ priv->percpu_priv = devm_alloc_percpu(dev, *priv->percpu_priv); ++ ++ if (priv->percpu_priv == NULL) { ++ dev_err(dev, "devm_alloc_percpu() failed\n"); ++ err = -ENOMEM; ++ goto alloc_percpu_failed; ++ } ++ for_each_possible_cpu(i) { ++ percpu_priv = per_cpu_ptr(priv->percpu_priv, i); ++ memset(percpu_priv, 0, sizeof(*percpu_priv)); ++ } ++ ++ /* Initialize NAPI */ ++ err = dpa_private_napi_add(net_dev); ++ ++ if (err < 0) ++ goto napi_add_failed; ++ ++ err = dpa_private_netdev_init(net_dev); ++ ++ if (err < 0) ++ goto netdev_init_failed; ++ ++ dpaa_eth_sysfs_init(&net_dev->dev); ++ ++#ifdef CONFIG_PM ++ device_set_wakeup_capable(dev, true); ++#endif ++ ++ pr_info("fsl_dpa: Probed interface %s\n", net_dev->name); ++ ++ return 0; ++ ++netdev_init_failed: ++napi_add_failed: ++ dpa_private_napi_del(net_dev); ++alloc_percpu_failed: ++#ifdef CONFIG_FMAN_PFC ++pfc_mapping_failed: ++#endif ++ dpa_fq_free(dev, &priv->dpa_fq_list); ++fq_alloc_failed: ++ qman_delete_cgr_safe(&priv->ingress_cgr); ++ qman_release_cgrid(priv->ingress_cgr.cgrid); ++rx_cgr_init_failed: ++ qman_delete_cgr_safe(&priv->cgr_data.cgr); ++ qman_release_cgrid(priv->cgr_data.cgr.cgrid); ++tx_cgr_init_failed: ++get_channel_failed: ++ dpa_bp_free(priv); ++bp_create_failed: ++fq_probe_failed: ++alloc_failed: ++mac_probe_failed: ++ dev_set_drvdata(dev, NULL); ++ free_netdev(net_dev); ++alloc_etherdev_mq_failed: ++ if (atomic_read(&dpa_bp->refs) == 0) ++ devm_kfree(dev, dpa_bp); ++ ++ return err; ++} ++ ++static const struct of_device_id dpa_match[] = { ++ { ++ .compatible = "fsl,dpa-ethernet" ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, dpa_match); ++ ++static struct platform_driver dpa_driver = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = dpa_match, ++ .owner = THIS_MODULE, ++ .pm = DPAA_PM_OPS, ++ }, ++ .probe = dpaa_eth_priv_probe, ++ .remove = dpa_remove ++}; ++ ++#ifndef CONFIG_PPC ++static bool __init __cold soc_has_errata_a010022(void) ++{ ++#ifdef CONFIG_SOC_BUS ++ const struct soc_device_attribute soc_msi_matches[] = { ++ { .family = "QorIQ LS1043A", ++ .data = NULL }, ++ { }, ++ }; ++ ++ if (soc_device_match(soc_msi_matches)) ++ return true; ++ ++ return false; ++#else ++ return true; /* cannot identify SoC */ ++#endif ++} ++#endif ++ ++static int __init __cold dpa_load(void) ++{ ++ int _errno; ++ ++ pr_info(DPA_DESCRIPTION "\n"); ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++ dpa_debugfs_module_init(); ++#endif /* CONFIG_FSL_DPAA_DBG_LOOP */ ++ ++ /* initialise dpaa_eth mirror values */ ++ dpa_rx_extra_headroom = fm_get_rx_extra_headroom(); ++ dpa_max_frm = fm_get_max_frm(); ++ dpa_num_cpus = num_possible_cpus(); ++ ++#ifndef CONFIG_PPC ++ /* Detect if the current SoC requires the 4K alignment workaround */ ++ dpaa_errata_a010022 = soc_has_errata_a010022(); ++#endif ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++ memset(dpa_loop_netdevs, 0, sizeof(dpa_loop_netdevs)); ++#endif ++ ++ _errno = platform_driver_register(&dpa_driver); ++ if (unlikely(_errno < 0)) { ++ pr_err(KBUILD_MODNAME ++ ": %s:%hu:%s(): platform_driver_register() = %d\n", ++ KBUILD_BASENAME".c", __LINE__, __func__, _errno); ++ } ++ ++ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", ++ KBUILD_BASENAME".c", __func__); ++ ++ return _errno; ++} ++module_init(dpa_load); ++ ++static void __exit __cold dpa_unload(void) ++{ ++ pr_debug(KBUILD_MODNAME ": -> %s:%s()\n", ++ KBUILD_BASENAME".c", __func__); ++ ++ platform_driver_unregister(&dpa_driver); ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++ dpa_debugfs_module_exit(); ++#endif /* CONFIG_FSL_DPAA_DBG_LOOP */ ++ ++ /* Only one channel is used and needs to be relased after all ++ * interfaces are removed ++ */ ++ dpa_release_channel(); ++ ++ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", ++ KBUILD_BASENAME".c", __func__); ++} ++module_exit(dpa_unload); +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h +new file mode 100644 +index 00000000..b1703bc1 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h +@@ -0,0 +1,698 @@ ++/* Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __DPA_H ++#define __DPA_H ++ ++#include ++#include /* struct qman_fq */ ++ ++#include "fm_ext.h" ++#include "dpaa_eth_trace.h" ++ ++extern int dpa_rx_extra_headroom; ++extern int dpa_max_frm; ++extern int dpa_num_cpus; ++ ++#define dpa_get_rx_extra_headroom() dpa_rx_extra_headroom ++#define dpa_get_max_frm() dpa_max_frm ++ ++#define dpa_get_max_mtu() \ ++ (dpa_get_max_frm() - (VLAN_ETH_HLEN + ETH_FCS_LEN)) ++ ++#define __hot ++ ++/* Simple enum of FQ types - used for array indexing */ ++enum port_type {RX, TX}; ++ ++/* TODO: This structure should be renamed & moved to the FMD wrapper */ ++struct dpa_buffer_layout_s { ++ uint16_t priv_data_size; ++ bool parse_results; ++ bool time_stamp; ++ bool hash_results; ++ uint8_t manip_extra_space; ++ uint16_t data_align; ++}; ++ ++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG ++#define DPA_BUG_ON(cond) BUG_ON(cond) ++#else ++#define DPA_BUG_ON(cond) ++#endif ++ ++#define DPA_TX_PRIV_DATA_SIZE 16 ++#define DPA_PARSE_RESULTS_SIZE sizeof(fm_prs_result_t) ++#define DPA_TIME_STAMP_SIZE 8 ++#define DPA_HASH_RESULTS_SIZE 8 ++#define DPA_RX_PRIV_DATA_SIZE (DPA_TX_PRIV_DATA_SIZE + \ ++ dpa_get_rx_extra_headroom()) ++ ++#define FM_FD_STAT_RX_ERRORS \ ++ (FM_PORT_FRM_ERR_DMA | FM_PORT_FRM_ERR_PHYSICAL | \ ++ FM_PORT_FRM_ERR_SIZE | FM_PORT_FRM_ERR_CLS_DISCARD | \ ++ FM_PORT_FRM_ERR_EXTRACTION | FM_PORT_FRM_ERR_NO_SCHEME | \ ++ FM_PORT_FRM_ERR_ILL_PLCR | FM_PORT_FRM_ERR_PRS_TIMEOUT | \ ++ FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | FM_PORT_FRM_ERR_PRS_HDR_ERR) ++ ++#define FM_FD_STAT_TX_ERRORS \ ++ (FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT | \ ++ FM_PORT_FRM_ERR_LENGTH | FM_PORT_FRM_ERR_DMA) ++ ++#ifndef CONFIG_FSL_DPAA_ETH_JUMBO_FRAME ++/* The raw buffer size must be cacheline aligned. ++ * Normally we use 2K buffers. ++ */ ++#define DPA_BP_RAW_SIZE 2048 ++#else ++/* For jumbo frame optimizations, use buffers large enough to accommodate ++ * 9.6K frames, FD maximum offset, skb sh_info overhead and some extra ++ * space to account for further alignments. ++ */ ++#define DPA_MAX_FRM_SIZE 9600 ++#ifdef CONFIG_PPC ++#define DPA_BP_RAW_SIZE \ ++ ((DPA_MAX_FRM_SIZE + DPA_MAX_FD_OFFSET + \ ++ sizeof(struct skb_shared_info) + 128) & ~(SMP_CACHE_BYTES - 1)) ++#else /* CONFIG_PPC */ ++#define DPA_BP_RAW_SIZE ((unlikely(dpaa_errata_a010022)) ? 2048 : \ ++ ((DPA_MAX_FRM_SIZE + DPA_MAX_FD_OFFSET + \ ++ sizeof(struct skb_shared_info) + 128) & ~(SMP_CACHE_BYTES - 1))) ++#endif /* CONFIG_PPC */ ++#endif /* CONFIG_FSL_DPAA_ETH_JUMBO_FRAME */ ++ ++/* This is what FMan is ever allowed to use. ++ * FMan-DMA requires 16-byte alignment for Rx buffers, but SKB_DATA_ALIGN is ++ * even stronger (SMP_CACHE_BYTES-aligned), so we just get away with that, ++ * via SKB_WITH_OVERHEAD(). We can't rely on netdev_alloc_frag() giving us ++ * half-page-aligned buffers (can we?), so we reserve some more space ++ * for start-of-buffer alignment. ++ */ ++#define dpa_bp_size(buffer_layout) (SKB_WITH_OVERHEAD(DPA_BP_RAW_SIZE) - \ ++ SMP_CACHE_BYTES) ++/* We must ensure that skb_shinfo is always cacheline-aligned. */ ++#define DPA_SKB_SIZE(size) ((size) & ~(SMP_CACHE_BYTES - 1)) ++ ++/* Maximum size of a buffer for which recycling is allowed. ++ * We need an upper limit such that forwarded skbs that get reallocated on Tx ++ * aren't allowed to grow unboundedly. On the other hand, we need to make sure ++ * that skbs allocated by us will not fail to be recycled due to their size. ++ * ++ * For a requested size, the kernel allocator provides the next power of two ++ * sized block, which the stack will use as is, regardless of the actual size ++ * it required; since we must accommodate at most 9.6K buffers (L2 maximum ++ * supported frame size), set the recycling upper limit to 16K. ++ */ ++#define DPA_RECYCLE_MAX_SIZE 16384 ++ ++#if defined(CONFIG_FSL_SDK_FMAN_TEST) ++/*TODO: temporary for fman pcd testing */ ++#define FMAN_PCD_TESTS_MAX_NUM_RANGES 20 ++#endif ++ ++#define DPAA_ETH_FQ_DELTA 0x10000 ++ ++#define DPAA_ETH_PCD_FQ_BASE(device_addr) \ ++ (((device_addr) & 0x1fffff) >> 6) ++ ++#define DPAA_ETH_PCD_FQ_HI_PRIO_BASE(device_addr) \ ++ (DPAA_ETH_FQ_DELTA + DPAA_ETH_PCD_FQ_BASE(device_addr)) ++ ++/* Largest value that the FQD's OAL field can hold. ++ * This is DPAA-1.x specific. ++ * TODO: This rather belongs in fsl_qman.h ++ */ ++#define FSL_QMAN_MAX_OAL 127 ++ ++/* Maximum offset value for a contig or sg FD (represented on 9 bits) */ ++#define DPA_MAX_FD_OFFSET ((1 << 9) - 1) ++ ++/* Default alignment for start of data in an Rx FD */ ++#define DPA_FD_DATA_ALIGNMENT 16 ++ ++/* Values for the L3R field of the FM Parse Results ++ */ ++/* L3 Type field: First IP Present IPv4 */ ++#define FM_L3_PARSE_RESULT_IPV4 0x8000 ++/* L3 Type field: First IP Present IPv6 */ ++#define FM_L3_PARSE_RESULT_IPV6 0x4000 ++ ++/* Values for the L4R field of the FM Parse Results ++ * See $8.8.4.7.20 - L4 HXS - L4 Results from DPAA-Rev2 Reference Manual. ++ */ ++/* L4 Type field: UDP */ ++#define FM_L4_PARSE_RESULT_UDP 0x40 ++/* L4 Type field: TCP */ ++#define FM_L4_PARSE_RESULT_TCP 0x20 ++/* FD status field indicating whether the FM Parser has attempted to validate ++ * the L4 csum of the frame. ++ * Note that having this bit set doesn't necessarily imply that the checksum ++ * is valid. One would have to check the parse results to find that out. ++ */ ++#define FM_FD_STAT_L4CV 0x00000004 ++ ++ ++#define FM_FD_STAT_ERR_PHYSICAL FM_PORT_FRM_ERR_PHYSICAL ++ ++/* Check if the parsed frame was found to be a TCP segment. ++ * ++ * @parse_result_ptr must be of type (fm_prs_result_t *). ++ */ ++#define fm_l4_frame_is_tcp(parse_result_ptr) \ ++ ((parse_result_ptr)->l4r & FM_L4_PARSE_RESULT_TCP) ++ ++/* number of Tx queues to FMan */ ++#ifdef CONFIG_FMAN_PFC ++#define DPAA_ETH_TX_QUEUES (NR_CPUS * CONFIG_FMAN_PFC_COS_COUNT) ++#else ++#define DPAA_ETH_TX_QUEUES NR_CPUS ++#endif ++ ++#define DPAA_ETH_RX_QUEUES 128 ++ ++/* Convenience macros for storing/retrieving the skb back-pointers. They must ++ * accommodate both recycling and confirmation paths - i.e. cases when the buf ++ * was allocated by ourselves, respectively by the stack. In the former case, ++ * we could store the skb at negative offset; in the latter case, we can't, ++ * so we'll use 0 as offset. ++ * ++ * NB: @off is an offset from a (struct sk_buff **) pointer! ++ */ ++#define DPA_WRITE_SKB_PTR(skb, skbh, addr, off) \ ++{ \ ++ skbh = (struct sk_buff **)addr; \ ++ *(skbh + (off)) = skb; \ ++} ++#define DPA_READ_SKB_PTR(skb, skbh, addr, off) \ ++{ \ ++ skbh = (struct sk_buff **)addr; \ ++ skb = *(skbh + (off)); \ ++} ++ ++#ifdef CONFIG_PM ++/* Magic Packet wakeup */ ++#define DPAA_WOL_MAGIC 0x00000001 ++#endif ++ ++#if defined(CONFIG_FSL_SDK_FMAN_TEST) ++struct pcd_range { ++ uint32_t base; ++ uint32_t count; ++}; ++#endif ++ ++/* More detailed FQ types - used for fine-grained WQ assignments */ ++enum dpa_fq_type { ++ FQ_TYPE_RX_DEFAULT = 1, /* Rx Default FQs */ ++ FQ_TYPE_RX_ERROR, /* Rx Error FQs */ ++ FQ_TYPE_RX_PCD, /* User-defined PCDs */ ++ FQ_TYPE_TX, /* "Real" Tx FQs */ ++ FQ_TYPE_TX_CONFIRM, /* Tx default Conf FQ (actually an Rx FQ) */ ++ FQ_TYPE_TX_CONF_MQ, /* Tx conf FQs (one for each Tx FQ) */ ++ FQ_TYPE_TX_ERROR, /* Tx Error FQs (these are actually Rx FQs) */ ++ FQ_TYPE_RX_PCD_HI_PRIO, /* User-defined high-priority PCDs */ ++}; ++ ++struct dpa_fq { ++ struct qman_fq fq_base; ++ struct list_head list; ++ struct net_device *net_dev; ++ bool init; ++ uint32_t fqid; ++ uint32_t flags; ++ uint16_t channel; ++ uint8_t wq; ++ enum dpa_fq_type fq_type; ++}; ++ ++struct dpa_fq_cbs_t { ++ struct qman_fq rx_defq; ++ struct qman_fq tx_defq; ++ struct qman_fq rx_errq; ++ struct qman_fq tx_errq; ++ struct qman_fq egress_ern; ++}; ++ ++struct fqid_cell { ++ uint32_t start; ++ uint32_t count; ++}; ++ ++struct dpa_bp { ++ struct bman_pool *pool; ++ uint8_t bpid; ++ struct device *dev; ++ union { ++ /* The buffer pools used for the private ports are initialized ++ * with target_count buffers for each CPU; at runtime the ++ * number of buffers per CPU is constantly brought back to this ++ * level ++ */ ++ int target_count; ++ /* The configured value for the number of buffers in the pool, ++ * used for shared port buffer pools ++ */ ++ int config_count; ++ }; ++ size_t size; ++ bool seed_pool; ++ /* physical address of the contiguous memory used by the pool to store ++ * the buffers ++ */ ++ dma_addr_t paddr; ++ /* virtual address of the contiguous memory used by the pool to store ++ * the buffers ++ */ ++ void __iomem *vaddr; ++ /* current number of buffers in the bpool alloted to this CPU */ ++ int __percpu *percpu_count; ++ atomic_t refs; ++ /* some bpools need to be seeded before use by this cb */ ++ int (*seed_cb)(struct dpa_bp *); ++ /* some bpools need to be emptied before freeing; this cb is used ++ * for freeing of individual buffers taken from the pool ++ */ ++ void (*free_buf_cb)(void *addr); ++}; ++ ++struct dpa_rx_errors { ++ u64 dme; /* DMA Error */ ++ u64 fpe; /* Frame Physical Error */ ++ u64 fse; /* Frame Size Error */ ++ u64 phe; /* Header Error */ ++ u64 cse; /* Checksum Validation Error */ ++}; ++ ++/* Counters for QMan ERN frames - one counter per rejection code */ ++struct dpa_ern_cnt { ++ u64 cg_tdrop; /* Congestion group taildrop */ ++ u64 wred; /* WRED congestion */ ++ u64 err_cond; /* Error condition */ ++ u64 early_window; /* Order restoration, frame too early */ ++ u64 late_window; /* Order restoration, frame too late */ ++ u64 fq_tdrop; /* FQ taildrop */ ++ u64 fq_retired; /* FQ is retired */ ++ u64 orp_zero; /* ORP disabled */ ++}; ++ ++struct dpa_napi_portal { ++ struct napi_struct napi; ++ struct qman_portal *p; ++}; ++ ++struct dpa_percpu_priv_s { ++ struct net_device *net_dev; ++ struct dpa_napi_portal *np; ++ u64 in_interrupt; ++ u64 tx_returned; ++ u64 tx_confirm; ++ /* fragmented (non-linear) skbuffs received from the stack */ ++ u64 tx_frag_skbuffs; ++ /* number of S/G frames received */ ++ u64 rx_sg; ++ ++ struct rtnl_link_stats64 stats; ++ struct dpa_rx_errors rx_errors; ++ struct dpa_ern_cnt ern_cnt; ++}; ++ ++struct dpa_priv_s { ++ struct dpa_percpu_priv_s __percpu *percpu_priv; ++ struct dpa_bp *dpa_bp; ++ /* Store here the needed Tx headroom for convenience and speed ++ * (even though it can be computed based on the fields of buf_layout) ++ */ ++ uint16_t tx_headroom; ++ struct net_device *net_dev; ++ struct mac_device *mac_dev; ++ struct qman_fq *egress_fqs[DPAA_ETH_TX_QUEUES]; ++ struct qman_fq *conf_fqs[DPAA_ETH_TX_QUEUES]; ++ ++ size_t bp_count; ++ ++ uint16_t channel; /* "fsl,qman-channel-id" */ ++ struct list_head dpa_fq_list; ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++ struct dentry *debugfs_loop_file; ++#endif ++ ++ uint32_t msg_enable; /* net_device message level */ ++#ifdef CONFIG_FSL_DPAA_1588 ++ struct dpa_ptp_tsu *tsu; ++#endif ++ ++#if defined(CONFIG_FSL_SDK_FMAN_TEST) ++/* TODO: this is temporary until pcd support is implemented in dpaa */ ++ int priv_pcd_num_ranges; ++ struct pcd_range priv_pcd_ranges[FMAN_PCD_TESTS_MAX_NUM_RANGES]; ++#endif ++ ++ struct { ++ /** ++ * All egress queues to a given net device belong to one ++ * (and the same) congestion group. ++ */ ++ struct qman_cgr cgr; ++ /* If congested, when it began. Used for performance stats. */ ++ u32 congestion_start_jiffies; ++ /* Number of jiffies the Tx port was congested. */ ++ u32 congested_jiffies; ++ /** ++ * Counter for the number of times the CGR ++ * entered congestion state ++ */ ++ u32 cgr_congested_count; ++ } cgr_data; ++ /* Use a per-port CGR for ingress traffic. */ ++ bool use_ingress_cgr; ++ struct qman_cgr ingress_cgr; ++ ++#ifdef CONFIG_FSL_DPAA_TS ++ bool ts_tx_en; /* Tx timestamping enabled */ ++ bool ts_rx_en; /* Rx timestamping enabled */ ++#endif /* CONFIG_FSL_DPAA_TS */ ++ ++ struct dpa_buffer_layout_s *buf_layout; ++ uint16_t rx_headroom; ++ char if_type[30]; ++ ++ void *peer; ++#ifdef CONFIG_PM ++ u32 wol; ++#endif ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++ int loop_id; ++ int loop_to; ++#endif ++#ifdef CONFIG_FSL_DPAA_CEETM ++ bool ceetm_en; /* CEETM QoS enabled */ ++#endif ++}; ++ ++struct fm_port_fqs { ++ struct dpa_fq *tx_defq; ++ struct dpa_fq *tx_errq; ++ struct dpa_fq *rx_defq; ++ struct dpa_fq *rx_errq; ++}; ++ ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++extern struct net_device *dpa_loop_netdevs[20]; ++#endif ++ ++/* functions with different implementation for SG and non-SG: */ ++int dpa_bp_priv_seed(struct dpa_bp *dpa_bp); ++int dpaa_eth_refill_bpools(struct dpa_bp *dpa_bp, int *count_ptr); ++void __hot _dpa_rx(struct net_device *net_dev, ++ struct qman_portal *portal, ++ const struct dpa_priv_s *priv, ++ struct dpa_percpu_priv_s *percpu_priv, ++ const struct qm_fd *fd, ++ u32 fqid, ++ int *count_ptr); ++int __hot dpa_tx(struct sk_buff *skb, struct net_device *net_dev); ++int __hot dpa_tx_extended(struct sk_buff *skb, struct net_device *net_dev, ++ struct qman_fq *egress_fq, struct qman_fq *conf_fq); ++struct sk_buff *_dpa_cleanup_tx_fd(const struct dpa_priv_s *priv, ++ const struct qm_fd *fd); ++void __hot _dpa_process_parse_results(const fm_prs_result_t *parse_results, ++ const struct qm_fd *fd, ++ struct sk_buff *skb, ++ int *use_gro); ++#ifndef CONFIG_FSL_DPAA_TS ++bool dpa_skb_is_recyclable(struct sk_buff *skb); ++bool dpa_buf_is_recyclable(struct sk_buff *skb, ++ uint32_t min_size, ++ uint16_t min_offset, ++ unsigned char **new_buf_start); ++#endif ++int __hot skb_to_contig_fd(struct dpa_priv_s *priv, ++ struct sk_buff *skb, struct qm_fd *fd, ++ int *count_ptr, int *offset); ++int __hot skb_to_sg_fd(struct dpa_priv_s *priv, ++ struct sk_buff *skb, struct qm_fd *fd); ++int __cold __attribute__((nonnull)) ++ _dpa_fq_free(struct device *dev, struct qman_fq *fq); ++ ++/* Turn on HW checksum computation for this outgoing frame. ++ * If the current protocol is not something we support in this regard ++ * (or if the stack has already computed the SW checksum), we do nothing. ++ * ++ * Returns 0 if all goes well (or HW csum doesn't apply), and a negative value ++ * otherwise. ++ * ++ * Note that this function may modify the fd->cmd field and the skb data buffer ++ * (the Parse Results area). ++ */ ++int dpa_enable_tx_csum(struct dpa_priv_s *priv, ++ struct sk_buff *skb, struct qm_fd *fd, char *parse_results); ++ ++static inline int dpaa_eth_napi_schedule(struct dpa_percpu_priv_s *percpu_priv, ++ struct qman_portal *portal) ++{ ++ /* In case of threaded ISR for RT enable kernel, ++ * in_irq() does not return appropriate value, so use ++ * in_serving_softirq to distinguish softirq or irq context. ++ */ ++ if (unlikely(in_irq() || !in_serving_softirq())) { ++ /* Disable QMan IRQ and invoke NAPI */ ++ int ret = qman_p_irqsource_remove(portal, QM_PIRQ_DQRI); ++ if (likely(!ret)) { ++ const struct qman_portal_config *pc = ++ qman_p_get_portal_config(portal); ++ struct dpa_napi_portal *np = ++ &percpu_priv->np[pc->index]; ++ ++ np->p = portal; ++ napi_schedule(&np->napi); ++ percpu_priv->in_interrupt++; ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++static inline ssize_t __const __must_check __attribute__((nonnull)) ++dpa_fd_length(const struct qm_fd *fd) ++{ ++ return fd->length20; ++} ++ ++static inline ssize_t __const __must_check __attribute__((nonnull)) ++dpa_fd_offset(const struct qm_fd *fd) ++{ ++ return fd->offset; ++} ++ ++/* Verifies if the skb length is below the interface MTU */ ++static inline int dpa_check_rx_mtu(struct sk_buff *skb, int mtu) ++{ ++ if (unlikely(skb->len > mtu)) ++ if ((skb->protocol != htons(ETH_P_8021Q)) ++ || (skb->len > mtu + 4)) ++ return -1; ++ ++ return 0; ++} ++ ++static inline uint16_t dpa_get_headroom(struct dpa_buffer_layout_s *bl) ++{ ++ uint16_t headroom; ++ /* The frame headroom must accommodate: ++ * - the driver private data area ++ * - parse results, hash results, timestamp if selected ++ * - manip extra space ++ * If either hash results or time stamp are selected, both will ++ * be copied to/from the frame headroom, as TS is located between PR and ++ * HR in the IC and IC copy size has a granularity of 16bytes ++ * (see description of FMBM_RICP and FMBM_TICP registers in DPAARM) ++ * ++ * Also make sure the headroom is a multiple of data_align bytes ++ */ ++ headroom = (uint16_t)(bl->priv_data_size + ++ (bl->parse_results ? DPA_PARSE_RESULTS_SIZE : 0) + ++ (bl->hash_results || bl->time_stamp ? ++ DPA_TIME_STAMP_SIZE + DPA_HASH_RESULTS_SIZE : 0) + ++ bl->manip_extra_space); ++ ++ return bl->data_align ? ALIGN(headroom, bl->data_align) : headroom; ++} ++ ++int fm_mac_dump_regs(struct mac_device *h_dev, char *buf, int n); ++int fm_mac_dump_rx_stats(struct mac_device *h_dev, char *buf, int n); ++int fm_mac_dump_tx_stats(struct mac_device *h_dev, char *buf, int n); ++ ++void dpaa_eth_sysfs_remove(struct device *dev); ++void dpaa_eth_sysfs_init(struct device *dev); ++int dpaa_eth_poll(struct napi_struct *napi, int budget); ++ ++void dpa_private_napi_del(struct net_device *net_dev); ++ ++/* Equivalent to a memset(0), but works faster */ ++static inline void clear_fd(struct qm_fd *fd) ++{ ++ fd->opaque_addr = 0; ++ fd->opaque = 0; ++ fd->cmd = 0; ++} ++ ++static inline int _dpa_tx_fq_to_id(const struct dpa_priv_s *priv, ++ struct qman_fq *tx_fq) ++{ ++ int i; ++ ++ for (i = 0; i < DPAA_ETH_TX_QUEUES; i++) ++ if (priv->egress_fqs[i] == tx_fq) ++ return i; ++ ++ return -EINVAL; ++} ++ ++static inline int __hot dpa_xmit(struct dpa_priv_s *priv, ++ struct rtnl_link_stats64 *percpu_stats, ++ struct qm_fd *fd, struct qman_fq *egress_fq, ++ struct qman_fq *conf_fq) ++{ ++ int err, i; ++ ++ if (fd->bpid == 0xff) ++ fd->cmd |= qman_fq_fqid(conf_fq); ++ ++ /* Trace this Tx fd */ ++ trace_dpa_tx_fd(priv->net_dev, egress_fq, fd); ++ ++ for (i = 0; i < 100000; i++) { ++ err = qman_enqueue(egress_fq, fd, 0); ++ if (err != -EBUSY) ++ break; ++ } ++ ++ if (unlikely(err < 0)) { ++ /* TODO differentiate b/w -EBUSY (EQCR full) and other codes? */ ++ percpu_stats->tx_errors++; ++ percpu_stats->tx_fifo_errors++; ++ return err; ++ } ++ ++ percpu_stats->tx_packets++; ++ percpu_stats->tx_bytes += dpa_fd_length(fd); ++ ++ return 0; ++} ++ ++/* Use multiple WQs for FQ assignment: ++ * - Tx Confirmation queues go to WQ1. ++ * - Rx Default, Tx and PCD queues go to WQ3 (no differentiation between ++ * Rx and Tx traffic, or between Rx Default and Rx PCD frames). ++ * - Rx Error and Tx Error queues go to WQ2 (giving them a better chance ++ * to be scheduled, in case there are many more FQs in WQ3). ++ * This ensures that Tx-confirmed buffers are timely released. In particular, ++ * it avoids congestion on the Tx Confirm FQs, which can pile up PFDRs if they ++ * are greatly outnumbered by other FQs in the system (usually PCDs), while ++ * dequeue scheduling is round-robin. ++ */ ++static inline void _dpa_assign_wq(struct dpa_fq *fq) ++{ ++ switch (fq->fq_type) { ++ case FQ_TYPE_TX_CONFIRM: ++ case FQ_TYPE_TX_CONF_MQ: ++ fq->wq = 1; ++ break; ++ case FQ_TYPE_RX_DEFAULT: ++ case FQ_TYPE_TX: ++ fq->wq = 3; ++ break; ++ case FQ_TYPE_RX_ERROR: ++ case FQ_TYPE_TX_ERROR: ++ case FQ_TYPE_RX_PCD_HI_PRIO: ++ fq->wq = 2; ++ break; ++ case FQ_TYPE_RX_PCD: ++ fq->wq = 5; ++ break; ++ default: ++ WARN(1, "Invalid FQ type %d for FQID %d!\n", ++ fq->fq_type, fq->fqid); ++ } ++} ++ ++#ifdef CONFIG_FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE ++/* Use in lieu of skb_get_queue_mapping() */ ++#ifdef CONFIG_FMAN_PFC ++#define dpa_get_queue_mapping(skb) \ ++ (((skb)->priority < CONFIG_FMAN_PFC_COS_COUNT) ? \ ++ ((skb)->priority * dpa_num_cpus + smp_processor_id()) : \ ++ ((CONFIG_FMAN_PFC_COS_COUNT - 1) * \ ++ dpa_num_cpus + smp_processor_id())); ++ ++#else ++#define dpa_get_queue_mapping(skb) \ ++ raw_smp_processor_id() ++#endif ++#else ++/* Use the queue selected by XPS */ ++#define dpa_get_queue_mapping(skb) \ ++ skb_get_queue_mapping(skb) ++#endif ++ ++#ifdef CONFIG_PTP_1588_CLOCK_DPAA ++struct ptp_priv_s { ++ struct device_node *node; ++ struct platform_device *of_dev; ++ struct ptp_clock *clock; ++ struct mac_device *mac_dev; ++}; ++extern struct ptp_priv_s ptp_priv; ++#endif ++ ++static inline void _dpa_bp_free_pf(void *addr) ++{ ++ put_page(virt_to_head_page(addr)); ++} ++ ++/* LS1043A SoC has a HW issue regarding FMan DMA transactions; The issue ++ * manifests itself at high traffic rates when frames cross 4K memory ++ * boundaries or when they are not aligned to 16 bytes; For the moment, we ++ * use a SW workaround to avoid frames larger than 4K or that exceed 4K ++ * alignments and to realign the frames to 16 bytes. ++ */ ++ ++#ifndef CONFIG_PPC ++extern bool dpaa_errata_a010022; /* SoC affected by A010022 errata */ ++#define NONREC_MARK 0x01 ++#define HAS_DMA_ISSUE(start, size) \ ++ (((uintptr_t)(start) + (size)) > \ ++ (((uintptr_t)(start) + 0x1000) & ~0xFFF)) ++#endif /* !CONFIG_PPC */ ++ ++#endif /* __DPA_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.c +new file mode 100644 +index 00000000..507e77c3 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.c +@@ -0,0 +1,205 @@ ++/* Copyright 2008-2013 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG ++#define pr_fmt(fmt) \ ++ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \ ++ KBUILD_BASENAME".c", __LINE__, __func__ ++#else ++#define pr_fmt(fmt) \ ++ KBUILD_MODNAME ": " fmt ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "dpaa_eth.h" ++#include "dpaa_eth_common.h" ++#include "dpaa_eth_base.h" ++ ++#define DPA_DESCRIPTION "FSL DPAA Advanced drivers:" ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++uint8_t advanced_debug = -1; ++module_param(advanced_debug, byte, S_IRUGO); ++MODULE_PARM_DESC(advanced_debug, "Module/Driver verbosity level"); ++EXPORT_SYMBOL(advanced_debug); ++ ++static int dpa_bp_cmp(const void *dpa_bp0, const void *dpa_bp1) ++{ ++ return ((struct dpa_bp *)dpa_bp0)->size - ++ ((struct dpa_bp *)dpa_bp1)->size; ++} ++ ++struct dpa_bp * __cold __must_check /* __attribute__((nonnull)) */ ++dpa_bp_probe(struct platform_device *_of_dev, size_t *count) ++{ ++ int i, lenp, na, ns, err; ++ struct device *dev; ++ struct device_node *dev_node; ++ const __be32 *bpool_cfg; ++ struct dpa_bp *dpa_bp; ++ u32 bpid; ++ ++ dev = &_of_dev->dev; ++ ++ *count = of_count_phandle_with_args(dev->of_node, ++ "fsl,bman-buffer-pools", NULL); ++ if (*count < 1) { ++ dev_err(dev, "missing fsl,bman-buffer-pools device tree entry\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ dpa_bp = devm_kzalloc(dev, *count * sizeof(*dpa_bp), GFP_KERNEL); ++ if (dpa_bp == NULL) { ++ dev_err(dev, "devm_kzalloc() failed\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ dev_node = of_find_node_by_path("/"); ++ if (unlikely(dev_node == NULL)) { ++ dev_err(dev, "of_find_node_by_path(/) failed\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ na = of_n_addr_cells(dev_node); ++ ns = of_n_size_cells(dev_node); ++ ++ for (i = 0; i < *count; i++) { ++ of_node_put(dev_node); ++ ++ dev_node = of_parse_phandle(dev->of_node, ++ "fsl,bman-buffer-pools", i); ++ if (dev_node == NULL) { ++ dev_err(dev, "of_find_node_by_phandle() failed\n"); ++ return ERR_PTR(-EFAULT); ++ } ++ ++ if (unlikely(!of_device_is_compatible(dev_node, "fsl,bpool"))) { ++ dev_err(dev, ++ "!of_device_is_compatible(%s, fsl,bpool)\n", ++ dev_node->full_name); ++ dpa_bp = ERR_PTR(-EINVAL); ++ goto _return_of_node_put; ++ } ++ ++ err = of_property_read_u32(dev_node, "fsl,bpid", &bpid); ++ if (err) { ++ dev_err(dev, "Cannot find buffer pool ID in the device tree\n"); ++ dpa_bp = ERR_PTR(-EINVAL); ++ goto _return_of_node_put; ++ } ++ dpa_bp[i].bpid = (uint8_t)bpid; ++ ++ bpool_cfg = of_get_property(dev_node, "fsl,bpool-ethernet-cfg", ++ &lenp); ++ if (bpool_cfg && (lenp == (2 * ns + na) * sizeof(*bpool_cfg))) { ++ const uint32_t *seed_pool; ++ ++ dpa_bp[i].config_count = ++ (int)of_read_number(bpool_cfg, ns); ++ dpa_bp[i].size = ++ (size_t)of_read_number(bpool_cfg + ns, ns); ++ dpa_bp[i].paddr = ++ of_read_number(bpool_cfg + 2 * ns, na); ++ ++ seed_pool = of_get_property(dev_node, ++ "fsl,bpool-ethernet-seeds", &lenp); ++ dpa_bp[i].seed_pool = !!seed_pool; ++ ++ } else { ++ dev_err(dev, ++ "Missing/invalid fsl,bpool-ethernet-cfg device tree entry for node %s\n", ++ dev_node->full_name); ++ dpa_bp = ERR_PTR(-EINVAL); ++ goto _return_of_node_put; ++ } ++ } ++ ++ sort(dpa_bp, *count, sizeof(*dpa_bp), dpa_bp_cmp, NULL); ++ ++ return dpa_bp; ++ ++_return_of_node_put: ++ if (dev_node) ++ of_node_put(dev_node); ++ ++ return dpa_bp; ++} ++EXPORT_SYMBOL(dpa_bp_probe); ++ ++int dpa_bp_create(struct net_device *net_dev, struct dpa_bp *dpa_bp, ++ size_t count) ++{ ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ int i; ++ ++ priv->dpa_bp = dpa_bp; ++ priv->bp_count = count; ++ ++ for (i = 0; i < count; i++) { ++ int err; ++ err = dpa_bp_alloc(&dpa_bp[i]); ++ if (err < 0) { ++ dpa_bp_free(priv); ++ priv->dpa_bp = NULL; ++ return err; ++ } ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(dpa_bp_create); ++ ++static int __init __cold dpa_advanced_load(void) ++{ ++ pr_info(DPA_DESCRIPTION "\n"); ++ ++ return 0; ++} ++module_init(dpa_advanced_load); ++ ++static void __exit __cold dpa_advanced_unload(void) ++{ ++ pr_debug(KBUILD_MODNAME ": -> %s:%s()\n", ++ KBUILD_BASENAME".c", __func__); ++ ++} ++module_exit(dpa_advanced_unload); +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.h b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.h +new file mode 100644 +index 00000000..6ec68c3c +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_base.h +@@ -0,0 +1,49 @@ ++/* Copyright 2008-2013 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __DPAA_ETH_BASE_H ++#define __DPAA_ETH_BASE_H ++ ++#include /* struct net_device */ ++#include /* struct bm_buffer */ ++#include /* struct platform_device */ ++#include /* struct hwtstamp_config */ ++ ++extern uint8_t advanced_debug; ++extern const struct dpa_fq_cbs_t shared_fq_cbs; ++extern int __hot dpa_shared_tx(struct sk_buff *skb, struct net_device *net_dev); ++ ++struct dpa_bp * __cold __must_check /* __attribute__((nonnull)) */ ++dpa_bp_probe(struct platform_device *_of_dev, size_t *count); ++int dpa_bp_create(struct net_device *net_dev, struct dpa_bp *dpa_bp, ++ size_t count); ++ ++#endif /* __DPAA_ETH_BASE_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c +new file mode 100644 +index 00000000..cac613b7 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.c +@@ -0,0 +1,1992 @@ ++/* Copyright 2008-2016 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include "dpaa_eth_ceetm.h" ++ ++#define DPA_CEETM_DESCRIPTION "FSL DPAA CEETM qdisc" ++ ++const struct nla_policy ceetm_policy[TCA_CEETM_MAX + 1] = { ++ [TCA_CEETM_COPT] = { .len = sizeof(struct tc_ceetm_copt) }, ++ [TCA_CEETM_QOPS] = { .len = sizeof(struct tc_ceetm_qopt) }, ++}; ++ ++struct Qdisc_ops ceetm_qdisc_ops; ++ ++/* Obtain the DCP and the SP ids from the FMan port */ ++static void get_dcp_and_sp(struct net_device *dev, enum qm_dc_portal *dcp_id, ++ unsigned int *sp_id) ++{ ++ uint32_t channel; ++ t_LnxWrpFmPortDev *port_dev; ++ struct dpa_priv_s *dpa_priv = netdev_priv(dev); ++ struct mac_device *mac_dev = dpa_priv->mac_dev; ++ ++ port_dev = (t_LnxWrpFmPortDev *)mac_dev->port_dev[TX]; ++ channel = port_dev->txCh; ++ ++ *sp_id = channel & CHANNEL_SP_MASK; ++ pr_debug(KBUILD_BASENAME " : FM sub-portal ID %d\n", *sp_id); ++ ++ if (channel < DCP0_MAX_CHANNEL) { ++ *dcp_id = qm_dc_portal_fman0; ++ pr_debug(KBUILD_BASENAME " : DCP ID 0\n"); ++ } else { ++ *dcp_id = qm_dc_portal_fman1; ++ pr_debug(KBUILD_BASENAME " : DCP ID 1\n"); ++ } ++} ++ ++/* Enqueue Rejection Notification callback */ ++static void ceetm_ern(struct qman_portal *portal, struct qman_fq *fq, ++ const struct qm_mr_entry *msg) ++{ ++ struct net_device *net_dev; ++ struct ceetm_class *cls; ++ struct ceetm_class_stats *cstats = NULL; ++ const struct dpa_priv_s *dpa_priv; ++ struct dpa_percpu_priv_s *dpa_percpu_priv; ++ struct sk_buff *skb; ++ struct qm_fd fd = msg->ern.fd; ++ ++ net_dev = ((struct ceetm_fq *)fq)->net_dev; ++ dpa_priv = netdev_priv(net_dev); ++ dpa_percpu_priv = raw_cpu_ptr(dpa_priv->percpu_priv); ++ ++ /* Increment DPA counters */ ++ dpa_percpu_priv->stats.tx_dropped++; ++ dpa_percpu_priv->stats.tx_fifo_errors++; ++ ++ /* Increment CEETM counters */ ++ cls = ((struct ceetm_fq *)fq)->ceetm_cls; ++ switch (cls->type) { ++ case CEETM_PRIO: ++ cstats = this_cpu_ptr(cls->prio.cstats); ++ break; ++ case CEETM_WBFS: ++ cstats = this_cpu_ptr(cls->wbfs.cstats); ++ break; ++ } ++ ++ if (cstats) ++ cstats->ern_drop_count++; ++ ++ if (fd.bpid != 0xff) { ++ dpa_fd_release(net_dev, &fd); ++ return; ++ } ++ ++ skb = _dpa_cleanup_tx_fd(dpa_priv, &fd); ++ dev_kfree_skb_any(skb); ++} ++ ++/* Congestion State Change Notification callback */ ++static void ceetm_cscn(struct qm_ceetm_ccg *ccg, void *cb_ctx, int congested) ++{ ++ struct ceetm_fq *ceetm_fq = (struct ceetm_fq *)cb_ctx; ++ struct dpa_priv_s *dpa_priv = netdev_priv(ceetm_fq->net_dev); ++ struct ceetm_class *cls = ceetm_fq->ceetm_cls; ++ struct ceetm_class_stats *cstats = NULL; ++ ++ switch (cls->type) { ++ case CEETM_PRIO: ++ cstats = this_cpu_ptr(cls->prio.cstats); ++ break; ++ case CEETM_WBFS: ++ cstats = this_cpu_ptr(cls->wbfs.cstats); ++ break; ++ } ++ ++ if (congested) { ++ dpa_priv->cgr_data.congestion_start_jiffies = jiffies; ++ netif_tx_stop_all_queues(dpa_priv->net_dev); ++ dpa_priv->cgr_data.cgr_congested_count++; ++ if (cstats) ++ cstats->congested_count++; ++ } else { ++ dpa_priv->cgr_data.congested_jiffies += ++ (jiffies - dpa_priv->cgr_data.congestion_start_jiffies); ++ netif_tx_wake_all_queues(dpa_priv->net_dev); ++ } ++} ++ ++/* Allocate a ceetm fq */ ++static int ceetm_alloc_fq(struct ceetm_fq **fq, struct net_device *dev, ++ struct ceetm_class *cls) ++{ ++ *fq = kzalloc(sizeof(**fq), GFP_KERNEL); ++ if (!*fq) ++ return -ENOMEM; ++ ++ (*fq)->net_dev = dev; ++ (*fq)->ceetm_cls = cls; ++ return 0; ++} ++ ++/* Configure a ceetm Class Congestion Group */ ++static int ceetm_config_ccg(struct qm_ceetm_ccg **ccg, ++ struct qm_ceetm_channel *channel, unsigned int id, ++ struct ceetm_fq *fq, struct dpa_priv_s *dpa_priv) ++{ ++ int err; ++ u32 cs_th; ++ u16 ccg_mask; ++ struct qm_ceetm_ccg_params ccg_params; ++ ++ err = qman_ceetm_ccg_claim(ccg, channel, id, ceetm_cscn, fq); ++ if (err) ++ return err; ++ ++ /* Configure the count mode (frames/bytes), enable congestion state ++ * notifications, configure the congestion entry and exit thresholds, ++ * enable tail-drop, configure the tail-drop mode, and set the ++ * overhead accounting limit ++ */ ++ ccg_mask = QM_CCGR_WE_MODE | ++ QM_CCGR_WE_CSCN_EN | ++ QM_CCGR_WE_CS_THRES_IN | QM_CCGR_WE_CS_THRES_OUT | ++ QM_CCGR_WE_TD_EN | QM_CCGR_WE_TD_MODE | ++ QM_CCGR_WE_OAL; ++ ++ ccg_params.mode = 0; /* count bytes */ ++ ccg_params.cscn_en = 1; /* generate notifications */ ++ ccg_params.td_en = 1; /* enable tail-drop */ ++ ccg_params.td_mode = 0; /* tail-drop on congestion state */ ++ ccg_params.oal = (signed char)(min(sizeof(struct sk_buff) + ++ dpa_priv->tx_headroom, (size_t)FSL_QMAN_MAX_OAL)); ++ ++ /* Set the congestion state thresholds according to the link speed */ ++ if (dpa_priv->mac_dev->if_support & SUPPORTED_10000baseT_Full) ++ cs_th = CONFIG_FSL_DPAA_CS_THRESHOLD_10G; ++ else ++ cs_th = CONFIG_FSL_DPAA_CS_THRESHOLD_1G; ++ ++ qm_cgr_cs_thres_set64(&ccg_params.cs_thres_in, cs_th, 1); ++ qm_cgr_cs_thres_set64(&ccg_params.cs_thres_out, ++ cs_th * CEETM_CCGR_RATIO, 1); ++ ++ err = qman_ceetm_ccg_set(*ccg, ccg_mask, &ccg_params); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++/* Configure a ceetm Logical Frame Queue */ ++static int ceetm_config_lfq(struct qm_ceetm_cq *cq, struct ceetm_fq *fq, ++ struct qm_ceetm_lfq **lfq) ++{ ++ int err; ++ u64 context_a; ++ u32 context_b; ++ ++ err = qman_ceetm_lfq_claim(lfq, cq); ++ if (err) ++ return err; ++ ++ /* Get the former contexts in order to preserve context B */ ++ err = qman_ceetm_lfq_get_context(*lfq, &context_a, &context_b); ++ if (err) ++ return err; ++ ++ context_a = CEETM_CONTEXT_A; ++ err = qman_ceetm_lfq_set_context(*lfq, context_a, context_b); ++ if (err) ++ return err; ++ ++ (*lfq)->ern = ceetm_ern; ++ ++ err = qman_ceetm_create_fq(*lfq, &fq->fq); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++/* Configure a prio ceetm class */ ++static int ceetm_config_prio_cls(struct ceetm_class *cls, ++ struct net_device *dev, ++ struct qm_ceetm_channel *channel, ++ unsigned int id) ++{ ++ int err; ++ struct dpa_priv_s *dpa_priv = netdev_priv(dev); ++ ++ err = ceetm_alloc_fq(&cls->prio.fq, dev, cls); ++ if (err) ++ return err; ++ ++ /* Claim and configure the CCG */ ++ err = ceetm_config_ccg(&cls->prio.ccg, channel, id, cls->prio.fq, ++ dpa_priv); ++ if (err) ++ return err; ++ ++ /* Claim and configure the CQ */ ++ err = qman_ceetm_cq_claim(&cls->prio.cq, channel, id, cls->prio.ccg); ++ if (err) ++ return err; ++ ++ if (cls->shaped) { ++ err = qman_ceetm_channel_set_cq_cr_eligibility(channel, id, 1); ++ if (err) ++ return err; ++ ++ err = qman_ceetm_channel_set_cq_er_eligibility(channel, id, 1); ++ if (err) ++ return err; ++ } ++ ++ /* Claim and configure a LFQ */ ++ err = ceetm_config_lfq(cls->prio.cq, cls->prio.fq, &cls->prio.lfq); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++/* Configure a wbfs ceetm class */ ++static int ceetm_config_wbfs_cls(struct ceetm_class *cls, ++ struct net_device *dev, ++ struct qm_ceetm_channel *channel, ++ unsigned int id, int type) ++{ ++ int err; ++ struct dpa_priv_s *dpa_priv = netdev_priv(dev); ++ ++ err = ceetm_alloc_fq(&cls->wbfs.fq, dev, cls); ++ if (err) ++ return err; ++ ++ /* Claim and configure the CCG */ ++ err = ceetm_config_ccg(&cls->wbfs.ccg, channel, id, cls->wbfs.fq, ++ dpa_priv); ++ if (err) ++ return err; ++ ++ /* Claim and configure the CQ */ ++ if (type == WBFS_GRP_B) ++ err = qman_ceetm_cq_claim_B(&cls->wbfs.cq, channel, id, ++ cls->wbfs.ccg); ++ else ++ err = qman_ceetm_cq_claim_A(&cls->wbfs.cq, channel, id, ++ cls->wbfs.ccg); ++ if (err) ++ return err; ++ ++ /* Configure the CQ weight: real number multiplied by 100 to get rid ++ * of the fraction ++ */ ++ err = qman_ceetm_set_queue_weight_in_ratio(cls->wbfs.cq, ++ cls->wbfs.weight * 100); ++ if (err) ++ return err; ++ ++ /* Claim and configure a LFQ */ ++ err = ceetm_config_lfq(cls->wbfs.cq, cls->wbfs.fq, &cls->wbfs.lfq); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++/* Find class in qdisc hash table using given handle */ ++static inline struct ceetm_class *ceetm_find(u32 handle, struct Qdisc *sch) ++{ ++ struct ceetm_qdisc *priv = qdisc_priv(sch); ++ struct Qdisc_class_common *clc; ++ ++ pr_debug(KBUILD_BASENAME " : %s : find class %X in qdisc %X\n", ++ __func__, handle, sch->handle); ++ ++ clc = qdisc_class_find(&priv->clhash, handle); ++ return clc ? container_of(clc, struct ceetm_class, common) : NULL; ++} ++ ++/* Insert a class in the qdisc's class hash */ ++static void ceetm_link_class(struct Qdisc *sch, ++ struct Qdisc_class_hash *clhash, ++ struct Qdisc_class_common *common) ++{ ++ sch_tree_lock(sch); ++ qdisc_class_hash_insert(clhash, common); ++ sch_tree_unlock(sch); ++ qdisc_class_hash_grow(sch, clhash); ++} ++ ++/* Destroy a ceetm class */ ++static void ceetm_cls_destroy(struct Qdisc *sch, struct ceetm_class *cl) ++{ ++ if (!cl) ++ return; ++ ++ pr_debug(KBUILD_BASENAME " : %s : destroy class %X from under %X\n", ++ __func__, cl->common.classid, sch->handle); ++ ++ switch (cl->type) { ++ case CEETM_ROOT: ++ if (cl->root.child) { ++ qdisc_destroy(cl->root.child); ++ cl->root.child = NULL; ++ } ++ ++ if (cl->root.ch && qman_ceetm_channel_release(cl->root.ch)) ++ pr_err(KBUILD_BASENAME ++ " : %s : error releasing the channel %d\n", ++ __func__, cl->root.ch->idx); ++ ++ break; ++ ++ case CEETM_PRIO: ++ if (cl->prio.child) { ++ qdisc_destroy(cl->prio.child); ++ cl->prio.child = NULL; ++ } ++ ++ if (cl->prio.lfq && qman_ceetm_lfq_release(cl->prio.lfq)) ++ pr_err(KBUILD_BASENAME ++ " : %s : error releasing the LFQ %d\n", ++ __func__, cl->prio.lfq->idx); ++ ++ if (cl->prio.cq && qman_ceetm_cq_release(cl->prio.cq)) ++ pr_err(KBUILD_BASENAME ++ " : %s : error releasing the CQ %d\n", ++ __func__, cl->prio.cq->idx); ++ ++ if (cl->prio.ccg && qman_ceetm_ccg_release(cl->prio.ccg)) ++ pr_err(KBUILD_BASENAME ++ " : %s : error releasing the CCG %d\n", ++ __func__, cl->prio.ccg->idx); ++ ++ kfree(cl->prio.fq); ++ ++ if (cl->prio.cstats) ++ free_percpu(cl->prio.cstats); ++ ++ break; ++ ++ case CEETM_WBFS: ++ if (cl->wbfs.lfq && qman_ceetm_lfq_release(cl->wbfs.lfq)) ++ pr_err(KBUILD_BASENAME ++ " : %s : error releasing the LFQ %d\n", ++ __func__, cl->wbfs.lfq->idx); ++ ++ if (cl->wbfs.cq && qman_ceetm_cq_release(cl->wbfs.cq)) ++ pr_err(KBUILD_BASENAME ++ " : %s : error releasing the CQ %d\n", ++ __func__, cl->wbfs.cq->idx); ++ ++ if (cl->wbfs.ccg && qman_ceetm_ccg_release(cl->wbfs.ccg)) ++ pr_err(KBUILD_BASENAME ++ " : %s : error releasing the CCG %d\n", ++ __func__, cl->wbfs.ccg->idx); ++ ++ kfree(cl->wbfs.fq); ++ ++ if (cl->wbfs.cstats) ++ free_percpu(cl->wbfs.cstats); ++ } ++ ++ tcf_destroy_chain(&cl->filter_list); ++ kfree(cl); ++} ++ ++/* Destroy a ceetm qdisc */ ++static void ceetm_destroy(struct Qdisc *sch) ++{ ++ unsigned int ntx, i; ++ struct hlist_node *next; ++ struct ceetm_class *cl; ++ struct ceetm_qdisc *priv = qdisc_priv(sch); ++ struct net_device *dev = qdisc_dev(sch); ++ ++ pr_debug(KBUILD_BASENAME " : %s : destroy qdisc %X\n", ++ __func__, sch->handle); ++ ++ /* All filters need to be removed before destroying the classes */ ++ tcf_destroy_chain(&priv->filter_list); ++ ++ for (i = 0; i < priv->clhash.hashsize; i++) { ++ hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode) ++ tcf_destroy_chain(&cl->filter_list); ++ } ++ ++ for (i = 0; i < priv->clhash.hashsize; i++) { ++ hlist_for_each_entry_safe(cl, next, &priv->clhash.hash[i], ++ common.hnode) ++ ceetm_cls_destroy(sch, cl); ++ } ++ ++ qdisc_class_hash_destroy(&priv->clhash); ++ ++ switch (priv->type) { ++ case CEETM_ROOT: ++ dpa_disable_ceetm(dev); ++ ++ if (priv->root.lni && qman_ceetm_lni_release(priv->root.lni)) ++ pr_err(KBUILD_BASENAME ++ " : %s : error releasing the LNI %d\n", ++ __func__, priv->root.lni->idx); ++ ++ if (priv->root.sp && qman_ceetm_sp_release(priv->root.sp)) ++ pr_err(KBUILD_BASENAME ++ " : %s : error releasing the SP %d\n", ++ __func__, priv->root.sp->idx); ++ ++ if (priv->root.qstats) ++ free_percpu(priv->root.qstats); ++ ++ if (!priv->root.qdiscs) ++ break; ++ ++ /* Remove the pfifo qdiscs */ ++ for (ntx = 0; ntx < dev->num_tx_queues; ntx++) ++ if (priv->root.qdiscs[ntx]) ++ qdisc_destroy(priv->root.qdiscs[ntx]); ++ ++ kfree(priv->root.qdiscs); ++ break; ++ ++ case CEETM_PRIO: ++ if (priv->prio.parent) ++ priv->prio.parent->root.child = NULL; ++ break; ++ ++ case CEETM_WBFS: ++ if (priv->wbfs.parent) ++ priv->wbfs.parent->prio.child = NULL; ++ break; ++ } ++} ++ ++static int ceetm_dump(struct Qdisc *sch, struct sk_buff *skb) ++{ ++ struct Qdisc *qdisc; ++ unsigned int ntx, i; ++ struct nlattr *nest; ++ struct tc_ceetm_qopt qopt; ++ struct ceetm_qdisc_stats *qstats; ++ struct net_device *dev = qdisc_dev(sch); ++ struct ceetm_qdisc *priv = qdisc_priv(sch); ++ ++ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle); ++ ++ sch_tree_lock(sch); ++ memset(&qopt, 0, sizeof(qopt)); ++ qopt.type = priv->type; ++ qopt.shaped = priv->shaped; ++ ++ switch (priv->type) { ++ case CEETM_ROOT: ++ /* Gather statistics from the underlying pfifo qdiscs */ ++ sch->q.qlen = 0; ++ memset(&sch->bstats, 0, sizeof(sch->bstats)); ++ memset(&sch->qstats, 0, sizeof(sch->qstats)); ++ ++ for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { ++ qdisc = netdev_get_tx_queue(dev, ntx)->qdisc_sleeping; ++ sch->q.qlen += qdisc->q.qlen; ++ sch->bstats.bytes += qdisc->bstats.bytes; ++ sch->bstats.packets += qdisc->bstats.packets; ++ sch->qstats.qlen += qdisc->qstats.qlen; ++ sch->qstats.backlog += qdisc->qstats.backlog; ++ sch->qstats.drops += qdisc->qstats.drops; ++ sch->qstats.requeues += qdisc->qstats.requeues; ++ sch->qstats.overlimits += qdisc->qstats.overlimits; ++ } ++ ++ for_each_online_cpu(i) { ++ qstats = per_cpu_ptr(priv->root.qstats, i); ++ sch->qstats.drops += qstats->drops; ++ } ++ ++ qopt.rate = priv->root.rate; ++ qopt.ceil = priv->root.ceil; ++ qopt.overhead = priv->root.overhead; ++ break; ++ ++ case CEETM_PRIO: ++ qopt.qcount = priv->prio.qcount; ++ break; ++ ++ case CEETM_WBFS: ++ qopt.qcount = priv->wbfs.qcount; ++ qopt.cr = priv->wbfs.cr; ++ qopt.er = priv->wbfs.er; ++ break; ++ ++ default: ++ pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__); ++ sch_tree_unlock(sch); ++ return -EINVAL; ++ } ++ ++ nest = nla_nest_start(skb, TCA_OPTIONS); ++ if (!nest) ++ goto nla_put_failure; ++ if (nla_put(skb, TCA_CEETM_QOPS, sizeof(qopt), &qopt)) ++ goto nla_put_failure; ++ nla_nest_end(skb, nest); ++ ++ sch_tree_unlock(sch); ++ return skb->len; ++ ++nla_put_failure: ++ sch_tree_unlock(sch); ++ nla_nest_cancel(skb, nest); ++ return -EMSGSIZE; ++} ++ ++/* Configure a root ceetm qdisc */ ++static int ceetm_init_root(struct Qdisc *sch, struct ceetm_qdisc *priv, ++ struct tc_ceetm_qopt *qopt) ++{ ++ struct netdev_queue *dev_queue; ++ struct Qdisc *qdisc; ++ enum qm_dc_portal dcp_id; ++ unsigned int i, sp_id, parent_id; ++ int err; ++ u64 bps; ++ struct qm_ceetm_sp *sp; ++ struct qm_ceetm_lni *lni; ++ struct net_device *dev = qdisc_dev(sch); ++ struct dpa_priv_s *dpa_priv = netdev_priv(dev); ++ struct mac_device *mac_dev = dpa_priv->mac_dev; ++ ++ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle); ++ ++ /* Validate inputs */ ++ if (sch->parent != TC_H_ROOT) { ++ pr_err("CEETM: a root ceetm qdisc can not be attached to a class\n"); ++ tcf_destroy_chain(&priv->filter_list); ++ qdisc_class_hash_destroy(&priv->clhash); ++ return -EINVAL; ++ } ++ ++ if (!mac_dev) { ++ pr_err("CEETM: the interface is lacking a mac\n"); ++ err = -EINVAL; ++ goto err_init_root; ++ } ++ ++ /* pre-allocate underlying pfifo qdiscs */ ++ priv->root.qdiscs = kcalloc(dev->num_tx_queues, ++ sizeof(priv->root.qdiscs[0]), ++ GFP_KERNEL); ++ if (!priv->root.qdiscs) { ++ err = -ENOMEM; ++ goto err_init_root; ++ } ++ ++ for (i = 0; i < dev->num_tx_queues; i++) { ++ dev_queue = netdev_get_tx_queue(dev, i); ++ parent_id = TC_H_MAKE(TC_H_MAJ(sch->handle), ++ TC_H_MIN(i + PFIFO_MIN_OFFSET)); ++ ++ qdisc = qdisc_create_dflt(dev_queue, &pfifo_qdisc_ops, ++ parent_id); ++ if (!qdisc) { ++ err = -ENOMEM; ++ goto err_init_root; ++ } ++ ++ priv->root.qdiscs[i] = qdisc; ++ qdisc->flags |= TCQ_F_ONETXQUEUE; ++ } ++ ++ sch->flags |= TCQ_F_MQROOT; ++ ++ priv->root.qstats = alloc_percpu(struct ceetm_qdisc_stats); ++ if (!priv->root.qstats) { ++ pr_err(KBUILD_BASENAME " : %s : alloc_percpu() failed\n", ++ __func__); ++ err = -ENOMEM; ++ goto err_init_root; ++ } ++ ++ priv->shaped = qopt->shaped; ++ priv->root.rate = qopt->rate; ++ priv->root.ceil = qopt->ceil; ++ priv->root.overhead = qopt->overhead; ++ ++ /* Claim the SP */ ++ get_dcp_and_sp(dev, &dcp_id, &sp_id); ++ err = qman_ceetm_sp_claim(&sp, dcp_id, sp_id); ++ if (err) { ++ pr_err(KBUILD_BASENAME " : %s : failed to claim the SP\n", ++ __func__); ++ goto err_init_root; ++ } ++ ++ priv->root.sp = sp; ++ ++ /* Claim the LNI - will use the same id as the SP id since SPs 0-7 ++ * are connected to the TX FMan ports ++ */ ++ err = qman_ceetm_lni_claim(&lni, dcp_id, sp_id); ++ if (err) { ++ pr_err(KBUILD_BASENAME " : %s : failed to claim the LNI\n", ++ __func__); ++ goto err_init_root; ++ } ++ ++ priv->root.lni = lni; ++ ++ err = qman_ceetm_sp_set_lni(sp, lni); ++ if (err) { ++ pr_err(KBUILD_BASENAME " : %s : failed to link the SP and LNI\n", ++ __func__); ++ goto err_init_root; ++ } ++ ++ lni->sp = sp; ++ ++ /* Configure the LNI shaper */ ++ if (priv->shaped) { ++ err = qman_ceetm_lni_enable_shaper(lni, 1, priv->root.overhead); ++ if (err) { ++ pr_err(KBUILD_BASENAME " : %s : failed to configure the LNI shaper\n", ++ __func__); ++ goto err_init_root; ++ } ++ ++ bps = priv->root.rate << 3; /* Bps -> bps */ ++ err = qman_ceetm_lni_set_commit_rate_bps(lni, bps, dev->mtu); ++ if (err) { ++ pr_err(KBUILD_BASENAME " : %s : failed to configure the LNI shaper\n", ++ __func__); ++ goto err_init_root; ++ } ++ ++ bps = priv->root.ceil << 3; /* Bps -> bps */ ++ err = qman_ceetm_lni_set_excess_rate_bps(lni, bps, dev->mtu); ++ if (err) { ++ pr_err(KBUILD_BASENAME " : %s : failed to configure the LNI shaper\n", ++ __func__); ++ goto err_init_root; ++ } ++ } ++ ++ /* TODO default configuration */ ++ ++ dpa_enable_ceetm(dev); ++ return 0; ++ ++err_init_root: ++ ceetm_destroy(sch); ++ return err; ++} ++ ++/* Configure a prio ceetm qdisc */ ++static int ceetm_init_prio(struct Qdisc *sch, struct ceetm_qdisc *priv, ++ struct tc_ceetm_qopt *qopt) ++{ ++ int err; ++ unsigned int i; ++ struct ceetm_class *parent_cl, *child_cl; ++ struct Qdisc *parent_qdisc; ++ struct net_device *dev = qdisc_dev(sch); ++ ++ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle); ++ ++ if (sch->parent == TC_H_ROOT) { ++ pr_err("CEETM: a prio ceetm qdisc can not be root\n"); ++ err = -EINVAL; ++ goto err_init_prio; ++ } ++ ++ parent_qdisc = qdisc_lookup(dev, TC_H_MAJ(sch->parent)); ++ if (strcmp(parent_qdisc->ops->id, ceetm_qdisc_ops.id)) { ++ pr_err("CEETM: a ceetm qdisc can not be attached to other qdisc/class types\n"); ++ err = -EINVAL; ++ goto err_init_prio; ++ } ++ ++ /* Obtain the parent root ceetm_class */ ++ parent_cl = ceetm_find(sch->parent, parent_qdisc); ++ ++ if (!parent_cl || parent_cl->type != CEETM_ROOT) { ++ pr_err("CEETM: a prio ceetm qdiscs can be added only under a root ceetm class\n"); ++ err = -EINVAL; ++ goto err_init_prio; ++ } ++ ++ priv->prio.parent = parent_cl; ++ parent_cl->root.child = sch; ++ ++ priv->shaped = parent_cl->shaped; ++ priv->prio.qcount = qopt->qcount; ++ ++ /* Create and configure qcount child classes */ ++ for (i = 0; i < priv->prio.qcount; i++) { ++ child_cl = kzalloc(sizeof(*child_cl), GFP_KERNEL); ++ if (!child_cl) { ++ pr_err(KBUILD_BASENAME " : %s : kzalloc() failed\n", ++ __func__); ++ err = -ENOMEM; ++ goto err_init_prio; ++ } ++ ++ child_cl->prio.cstats = alloc_percpu(struct ceetm_class_stats); ++ if (!child_cl->prio.cstats) { ++ pr_err(KBUILD_BASENAME " : %s : alloc_percpu() failed\n", ++ __func__); ++ err = -ENOMEM; ++ goto err_init_prio_cls; ++ } ++ ++ child_cl->common.classid = TC_H_MAKE(sch->handle, (i + 1)); ++ child_cl->refcnt = 1; ++ child_cl->parent = sch; ++ child_cl->type = CEETM_PRIO; ++ child_cl->shaped = priv->shaped; ++ child_cl->prio.child = NULL; ++ ++ /* All shaped CQs have CR and ER enabled by default */ ++ child_cl->prio.cr = child_cl->shaped; ++ child_cl->prio.er = child_cl->shaped; ++ child_cl->prio.fq = NULL; ++ child_cl->prio.cq = NULL; ++ ++ /* Configure the corresponding hardware CQ */ ++ err = ceetm_config_prio_cls(child_cl, dev, ++ parent_cl->root.ch, i); ++ if (err) { ++ pr_err(KBUILD_BASENAME " : %s : failed to configure the ceetm prio class %X\n", ++ __func__, child_cl->common.classid); ++ goto err_init_prio_cls; ++ } ++ ++ /* Add class handle in Qdisc */ ++ ceetm_link_class(sch, &priv->clhash, &child_cl->common); ++ pr_debug(KBUILD_BASENAME " : %s : added ceetm prio class %X associated with CQ %d and CCG %d\n", ++ __func__, child_cl->common.classid, ++ child_cl->prio.cq->idx, child_cl->prio.ccg->idx); ++ } ++ ++ return 0; ++ ++err_init_prio_cls: ++ ceetm_cls_destroy(sch, child_cl); ++err_init_prio: ++ ceetm_destroy(sch); ++ return err; ++} ++ ++/* Configure a wbfs ceetm qdisc */ ++static int ceetm_init_wbfs(struct Qdisc *sch, struct ceetm_qdisc *priv, ++ struct tc_ceetm_qopt *qopt) ++{ ++ int err, group_b, small_group; ++ unsigned int i, id, prio_a, prio_b; ++ struct ceetm_class *parent_cl, *child_cl, *root_cl; ++ struct Qdisc *parent_qdisc; ++ struct ceetm_qdisc *parent_priv; ++ struct qm_ceetm_channel *channel; ++ struct net_device *dev = qdisc_dev(sch); ++ ++ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle); ++ ++ /* Validate inputs */ ++ if (sch->parent == TC_H_ROOT) { ++ pr_err("CEETM: a wbfs ceetm qdiscs can not be root\n"); ++ err = -EINVAL; ++ goto err_init_wbfs; ++ } ++ ++ /* Obtain the parent prio ceetm qdisc */ ++ parent_qdisc = qdisc_lookup(dev, TC_H_MAJ(sch->parent)); ++ if (strcmp(parent_qdisc->ops->id, ceetm_qdisc_ops.id)) { ++ pr_err("CEETM: a ceetm qdisc can not be attached to other qdisc/class types\n"); ++ err = -EINVAL; ++ goto err_init_wbfs; ++ } ++ ++ /* Obtain the parent prio ceetm class */ ++ parent_cl = ceetm_find(sch->parent, parent_qdisc); ++ parent_priv = qdisc_priv(parent_qdisc); ++ ++ if (!parent_cl || parent_cl->type != CEETM_PRIO) { ++ pr_err("CEETM: a wbfs ceetm qdiscs can be added only under a prio ceetm class\n"); ++ err = -EINVAL; ++ goto err_init_wbfs; ++ } ++ ++ if (!qopt->qcount || !qopt->qweight[0]) { ++ pr_err("CEETM: qcount and qweight are mandatory for a wbfs ceetm qdisc\n"); ++ err = -EINVAL; ++ goto err_init_wbfs; ++ } ++ ++ priv->shaped = parent_cl->shaped; ++ ++ if (!priv->shaped && (qopt->cr || qopt->er)) { ++ pr_err("CEETM: CR/ER can be enabled only for shaped wbfs ceetm qdiscs\n"); ++ err = -EINVAL; ++ goto err_init_wbfs; ++ } ++ ++ if (priv->shaped && !(qopt->cr || qopt->er)) { ++ pr_err("CEETM: either CR or ER must be enabled for shaped wbfs ceetm qdiscs\n"); ++ err = -EINVAL; ++ goto err_init_wbfs; ++ } ++ ++ /* Obtain the parent root ceetm class */ ++ root_cl = parent_priv->prio.parent; ++ if ((root_cl->root.wbfs_grp_a && root_cl->root.wbfs_grp_b) || ++ root_cl->root.wbfs_grp_large) { ++ pr_err("CEETM: no more wbfs classes are available\n"); ++ err = -EINVAL; ++ goto err_init_wbfs; ++ } ++ ++ if ((root_cl->root.wbfs_grp_a || root_cl->root.wbfs_grp_b) && ++ qopt->qcount == CEETM_MAX_WBFS_QCOUNT) { ++ pr_err("CEETM: only %d wbfs classes are available\n", ++ CEETM_MIN_WBFS_QCOUNT); ++ err = -EINVAL; ++ goto err_init_wbfs; ++ } ++ ++ priv->wbfs.parent = parent_cl; ++ parent_cl->prio.child = sch; ++ ++ priv->wbfs.qcount = qopt->qcount; ++ priv->wbfs.cr = qopt->cr; ++ priv->wbfs.er = qopt->er; ++ ++ channel = root_cl->root.ch; ++ ++ /* Configure the hardware wbfs channel groups */ ++ if (priv->wbfs.qcount == CEETM_MAX_WBFS_QCOUNT) { ++ /* Configure the large group A */ ++ priv->wbfs.group_type = WBFS_GRP_LARGE; ++ small_group = false; ++ group_b = false; ++ prio_a = TC_H_MIN(parent_cl->common.classid) - 1; ++ prio_b = prio_a; ++ ++ } else if (root_cl->root.wbfs_grp_a) { ++ /* Configure the group B */ ++ priv->wbfs.group_type = WBFS_GRP_B; ++ ++ err = qman_ceetm_channel_get_group(channel, &small_group, ++ &prio_a, &prio_b); ++ if (err) { ++ pr_err(KBUILD_BASENAME " : %s : failed to get group details\n", ++ __func__); ++ goto err_init_wbfs; ++ } ++ ++ small_group = true; ++ group_b = true; ++ prio_b = TC_H_MIN(parent_cl->common.classid) - 1; ++ /* If group A isn't configured, configure it as group B */ ++ prio_a = prio_a ? : prio_b; ++ ++ } else { ++ /* Configure the small group A */ ++ priv->wbfs.group_type = WBFS_GRP_A; ++ ++ err = qman_ceetm_channel_get_group(channel, &small_group, ++ &prio_a, &prio_b); ++ if (err) { ++ pr_err(KBUILD_BASENAME " : %s : failed to get group details\n", ++ __func__); ++ goto err_init_wbfs; ++ } ++ ++ small_group = true; ++ group_b = false; ++ prio_a = TC_H_MIN(parent_cl->common.classid) - 1; ++ /* If group B isn't configured, configure it as group A */ ++ prio_b = prio_b ? : prio_a; ++ } ++ ++ err = qman_ceetm_channel_set_group(channel, small_group, prio_a, ++ prio_b); ++ if (err) ++ goto err_init_wbfs; ++ ++ if (priv->shaped) { ++ err = qman_ceetm_channel_set_group_cr_eligibility(channel, ++ group_b, ++ priv->wbfs.cr); ++ if (err) { ++ pr_err(KBUILD_BASENAME " : %s : failed to set group CR eligibility\n", ++ __func__); ++ goto err_init_wbfs; ++ } ++ ++ err = qman_ceetm_channel_set_group_er_eligibility(channel, ++ group_b, ++ priv->wbfs.er); ++ if (err) { ++ pr_err(KBUILD_BASENAME " : %s : failed to set group ER eligibility\n", ++ __func__); ++ goto err_init_wbfs; ++ } ++ } ++ ++ /* Create qcount child classes */ ++ for (i = 0; i < priv->wbfs.qcount; i++) { ++ child_cl = kzalloc(sizeof(*child_cl), GFP_KERNEL); ++ if (!child_cl) { ++ pr_err(KBUILD_BASENAME " : %s : kzalloc() failed\n", ++ __func__); ++ err = -ENOMEM; ++ goto err_init_wbfs; ++ } ++ ++ child_cl->wbfs.cstats = alloc_percpu(struct ceetm_class_stats); ++ if (!child_cl->wbfs.cstats) { ++ pr_err(KBUILD_BASENAME " : %s : alloc_percpu() failed\n", ++ __func__); ++ err = -ENOMEM; ++ goto err_init_wbfs_cls; ++ } ++ ++ child_cl->common.classid = TC_H_MAKE(sch->handle, (i + 1)); ++ child_cl->refcnt = 1; ++ child_cl->parent = sch; ++ child_cl->type = CEETM_WBFS; ++ child_cl->shaped = priv->shaped; ++ child_cl->wbfs.fq = NULL; ++ child_cl->wbfs.cq = NULL; ++ child_cl->wbfs.weight = qopt->qweight[i]; ++ ++ if (priv->wbfs.group_type == WBFS_GRP_B) ++ id = WBFS_GRP_B_OFFSET + i; ++ else ++ id = WBFS_GRP_A_OFFSET + i; ++ ++ err = ceetm_config_wbfs_cls(child_cl, dev, channel, id, ++ priv->wbfs.group_type); ++ if (err) { ++ pr_err(KBUILD_BASENAME " : %s : failed to configure the ceetm wbfs class %X\n", ++ __func__, child_cl->common.classid); ++ goto err_init_wbfs_cls; ++ } ++ ++ /* Add class handle in Qdisc */ ++ ceetm_link_class(sch, &priv->clhash, &child_cl->common); ++ pr_debug(KBUILD_BASENAME " : %s : added ceetm wbfs class %X associated with CQ %d and CCG %d\n", ++ __func__, child_cl->common.classid, ++ child_cl->wbfs.cq->idx, child_cl->wbfs.ccg->idx); ++ } ++ ++ /* Signal the root class that a group has been configured */ ++ switch (priv->wbfs.group_type) { ++ case WBFS_GRP_LARGE: ++ root_cl->root.wbfs_grp_large = true; ++ break; ++ case WBFS_GRP_A: ++ root_cl->root.wbfs_grp_a = true; ++ break; ++ case WBFS_GRP_B: ++ root_cl->root.wbfs_grp_b = true; ++ break; ++ } ++ ++ return 0; ++ ++err_init_wbfs_cls: ++ ceetm_cls_destroy(sch, child_cl); ++err_init_wbfs: ++ ceetm_destroy(sch); ++ return err; ++} ++ ++/* Configure a generic ceetm qdisc */ ++static int ceetm_init(struct Qdisc *sch, struct nlattr *opt) ++{ ++ struct tc_ceetm_qopt *qopt; ++ struct nlattr *tb[TCA_CEETM_QOPS + 1]; ++ int ret; ++ struct ceetm_qdisc *priv = qdisc_priv(sch); ++ struct net_device *dev = qdisc_dev(sch); ++ ++ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle); ++ ++ if (!netif_is_multiqueue(dev)) ++ return -EOPNOTSUPP; ++ ++ if (!opt) { ++ pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__); ++ return -EINVAL; ++ } ++ ++ ret = nla_parse_nested(tb, TCA_CEETM_QOPS, opt, ceetm_policy); ++ if (ret < 0) { ++ pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__); ++ return ret; ++ } ++ ++ if (!tb[TCA_CEETM_QOPS]) { ++ pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__); ++ return -EINVAL; ++ } ++ ++ if (TC_H_MIN(sch->handle)) { ++ pr_err("CEETM: a qdisc should not have a minor\n"); ++ return -EINVAL; ++ } ++ ++ qopt = nla_data(tb[TCA_CEETM_QOPS]); ++ ++ /* Initialize the class hash list. Each qdisc has its own class hash */ ++ ret = qdisc_class_hash_init(&priv->clhash); ++ if (ret < 0) { ++ pr_err(KBUILD_BASENAME " : %s : qdisc_class_hash_init failed\n", ++ __func__); ++ return ret; ++ } ++ ++ priv->type = qopt->type; ++ ++ switch (priv->type) { ++ case CEETM_ROOT: ++ ret = ceetm_init_root(sch, priv, qopt); ++ break; ++ case CEETM_PRIO: ++ ret = ceetm_init_prio(sch, priv, qopt); ++ break; ++ case CEETM_WBFS: ++ ret = ceetm_init_wbfs(sch, priv, qopt); ++ break; ++ default: ++ pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__); ++ ceetm_destroy(sch); ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++/* Edit a root ceetm qdisc */ ++static int ceetm_change_root(struct Qdisc *sch, struct ceetm_qdisc *priv, ++ struct net_device *dev, ++ struct tc_ceetm_qopt *qopt) ++{ ++ int err = 0; ++ u64 bps; ++ ++ if (priv->shaped != (bool)qopt->shaped) { ++ pr_err("CEETM: qdisc %X is %s\n", sch->handle, ++ priv->shaped ? "shaped" : "unshaped"); ++ return -EINVAL; ++ } ++ ++ /* Nothing to modify for unshaped qdiscs */ ++ if (!priv->shaped) ++ return 0; ++ ++ /* Configure the LNI shaper */ ++ if (priv->root.overhead != qopt->overhead) { ++ err = qman_ceetm_lni_enable_shaper(priv->root.lni, 1, ++ qopt->overhead); ++ if (err) ++ goto change_err; ++ priv->root.overhead = qopt->overhead; ++ } ++ ++ if (priv->root.rate != qopt->rate) { ++ bps = qopt->rate << 3; /* Bps -> bps */ ++ err = qman_ceetm_lni_set_commit_rate_bps(priv->root.lni, bps, ++ dev->mtu); ++ if (err) ++ goto change_err; ++ priv->root.rate = qopt->rate; ++ } ++ ++ if (priv->root.ceil != qopt->ceil) { ++ bps = qopt->ceil << 3; /* Bps -> bps */ ++ err = qman_ceetm_lni_set_excess_rate_bps(priv->root.lni, bps, ++ dev->mtu); ++ if (err) ++ goto change_err; ++ priv->root.ceil = qopt->ceil; ++ } ++ ++ return 0; ++ ++change_err: ++ pr_err(KBUILD_BASENAME " : %s : failed to configure the root ceetm qdisc %X\n", ++ __func__, sch->handle); ++ return err; ++} ++ ++/* Edit a wbfs ceetm qdisc */ ++static int ceetm_change_wbfs(struct Qdisc *sch, struct ceetm_qdisc *priv, ++ struct tc_ceetm_qopt *qopt) ++{ ++ int err; ++ bool group_b; ++ struct qm_ceetm_channel *channel; ++ struct ceetm_class *prio_class, *root_class; ++ struct ceetm_qdisc *prio_qdisc; ++ ++ if (qopt->qcount) { ++ pr_err("CEETM: the qcount can not be modified\n"); ++ return -EINVAL; ++ } ++ ++ if (qopt->qweight[0]) { ++ pr_err("CEETM: the qweight can be modified through the wbfs classes\n"); ++ return -EINVAL; ++ } ++ ++ if (!priv->shaped && (qopt->cr || qopt->er)) { ++ pr_err("CEETM: CR/ER can be enabled only for shaped wbfs ceetm qdiscs\n"); ++ return -EINVAL; ++ } ++ ++ if (priv->shaped && !(qopt->cr || qopt->er)) { ++ pr_err("CEETM: either CR or ER must be enabled for shaped wbfs ceetm qdiscs\n"); ++ return -EINVAL; ++ } ++ ++ /* Nothing to modify for unshaped qdiscs */ ++ if (!priv->shaped) ++ return 0; ++ ++ prio_class = priv->wbfs.parent; ++ prio_qdisc = qdisc_priv(prio_class->parent); ++ root_class = prio_qdisc->prio.parent; ++ channel = root_class->root.ch; ++ group_b = priv->wbfs.group_type == WBFS_GRP_B; ++ ++ if (qopt->cr != priv->wbfs.cr) { ++ err = qman_ceetm_channel_set_group_cr_eligibility(channel, ++ group_b, ++ qopt->cr); ++ if (err) ++ goto change_err; ++ priv->wbfs.cr = qopt->cr; ++ } ++ ++ if (qopt->er != priv->wbfs.er) { ++ err = qman_ceetm_channel_set_group_er_eligibility(channel, ++ group_b, ++ qopt->er); ++ if (err) ++ goto change_err; ++ priv->wbfs.er = qopt->er; ++ } ++ ++ return 0; ++ ++change_err: ++ pr_err(KBUILD_BASENAME " : %s : failed to configure the wbfs ceetm qdisc %X\n", ++ __func__, sch->handle); ++ return err; ++} ++ ++/* Edit a ceetm qdisc */ ++static int ceetm_change(struct Qdisc *sch, struct nlattr *opt) ++{ ++ struct tc_ceetm_qopt *qopt; ++ struct nlattr *tb[TCA_CEETM_QOPS + 1]; ++ int ret; ++ struct ceetm_qdisc *priv = qdisc_priv(sch); ++ struct net_device *dev = qdisc_dev(sch); ++ ++ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle); ++ ++ ret = nla_parse_nested(tb, TCA_CEETM_QOPS, opt, ceetm_policy); ++ if (ret < 0) { ++ pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__); ++ return ret; ++ } ++ ++ if (!tb[TCA_CEETM_QOPS]) { ++ pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__); ++ return -EINVAL; ++ } ++ ++ if (TC_H_MIN(sch->handle)) { ++ pr_err("CEETM: a qdisc should not have a minor\n"); ++ return -EINVAL; ++ } ++ ++ qopt = nla_data(tb[TCA_CEETM_QOPS]); ++ ++ if (priv->type != qopt->type) { ++ pr_err("CEETM: qdisc %X is not of the provided type\n", ++ sch->handle); ++ return -EINVAL; ++ } ++ ++ switch (priv->type) { ++ case CEETM_ROOT: ++ ret = ceetm_change_root(sch, priv, dev, qopt); ++ break; ++ case CEETM_PRIO: ++ pr_err("CEETM: prio qdiscs can not be modified\n"); ++ ret = -EINVAL; ++ break; ++ case CEETM_WBFS: ++ ret = ceetm_change_wbfs(sch, priv, qopt); ++ break; ++ default: ++ pr_err(KBUILD_BASENAME " : %s : invalid qdisc\n", __func__); ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++/* Attach the underlying pfifo qdiscs */ ++static void ceetm_attach(struct Qdisc *sch) ++{ ++ struct net_device *dev = qdisc_dev(sch); ++ struct ceetm_qdisc *priv = qdisc_priv(sch); ++ struct Qdisc *qdisc, *old_qdisc; ++ unsigned int i; ++ ++ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle); ++ ++ for (i = 0; i < dev->num_tx_queues; i++) { ++ qdisc = priv->root.qdiscs[i]; ++ old_qdisc = dev_graft_qdisc(qdisc->dev_queue, qdisc); ++ if (old_qdisc) ++ qdisc_destroy(old_qdisc); ++ } ++} ++ ++static unsigned long ceetm_cls_get(struct Qdisc *sch, u32 classid) ++{ ++ struct ceetm_class *cl; ++ ++ pr_debug(KBUILD_BASENAME " : %s : classid %X from qdisc %X\n", ++ __func__, classid, sch->handle); ++ cl = ceetm_find(classid, sch); ++ ++ if (cl) ++ cl->refcnt++; /* Will decrement in put() */ ++ return (unsigned long)cl; ++} ++ ++static void ceetm_cls_put(struct Qdisc *sch, unsigned long arg) ++{ ++ struct ceetm_class *cl = (struct ceetm_class *)arg; ++ ++ pr_debug(KBUILD_BASENAME " : %s : classid %X from qdisc %X\n", ++ __func__, cl->common.classid, sch->handle); ++ cl->refcnt--; ++ ++ if (cl->refcnt == 0) ++ ceetm_cls_destroy(sch, cl); ++} ++ ++static int ceetm_cls_change_root(struct ceetm_class *cl, ++ struct tc_ceetm_copt *copt, ++ struct net_device *dev) ++{ ++ int err; ++ u64 bps; ++ ++ if ((bool)copt->shaped != cl->shaped) { ++ pr_err("CEETM: class %X is %s\n", cl->common.classid, ++ cl->shaped ? "shaped" : "unshaped"); ++ return -EINVAL; ++ } ++ ++ if (cl->shaped && cl->root.rate != copt->rate) { ++ bps = copt->rate << 3; /* Bps -> bps */ ++ err = qman_ceetm_channel_set_commit_rate_bps(cl->root.ch, bps, ++ dev->mtu); ++ if (err) ++ goto change_cls_err; ++ cl->root.rate = copt->rate; ++ } ++ ++ if (cl->shaped && cl->root.ceil != copt->ceil) { ++ bps = copt->ceil << 3; /* Bps -> bps */ ++ err = qman_ceetm_channel_set_excess_rate_bps(cl->root.ch, bps, ++ dev->mtu); ++ if (err) ++ goto change_cls_err; ++ cl->root.ceil = copt->ceil; ++ } ++ ++ if (!cl->shaped && cl->root.tbl != copt->tbl) { ++ err = qman_ceetm_channel_set_weight(cl->root.ch, copt->tbl); ++ if (err) ++ goto change_cls_err; ++ cl->root.tbl = copt->tbl; ++ } ++ ++ return 0; ++ ++change_cls_err: ++ pr_err(KBUILD_BASENAME " : %s : failed to configure the ceetm root class %X\n", ++ __func__, cl->common.classid); ++ return err; ++} ++ ++static int ceetm_cls_change_prio(struct ceetm_class *cl, ++ struct tc_ceetm_copt *copt) ++{ ++ int err; ++ ++ if (!cl->shaped && (copt->cr || copt->er)) { ++ pr_err("CEETM: only shaped classes can have CR and ER enabled\n"); ++ return -EINVAL; ++ } ++ ++ if (cl->prio.cr != (bool)copt->cr) { ++ err = qman_ceetm_channel_set_cq_cr_eligibility( ++ cl->prio.cq->parent, ++ cl->prio.cq->idx, ++ copt->cr); ++ if (err) ++ goto change_cls_err; ++ cl->prio.cr = copt->cr; ++ } ++ ++ if (cl->prio.er != (bool)copt->er) { ++ err = qman_ceetm_channel_set_cq_er_eligibility( ++ cl->prio.cq->parent, ++ cl->prio.cq->idx, ++ copt->er); ++ if (err) ++ goto change_cls_err; ++ cl->prio.er = copt->er; ++ } ++ ++ return 0; ++ ++change_cls_err: ++ pr_err(KBUILD_BASENAME " : %s : failed to configure the ceetm prio class %X\n", ++ __func__, cl->common.classid); ++ return err; ++} ++ ++static int ceetm_cls_change_wbfs(struct ceetm_class *cl, ++ struct tc_ceetm_copt *copt) ++{ ++ int err; ++ ++ if (copt->weight != cl->wbfs.weight) { ++ /* Configure the CQ weight: real number multiplied by 100 to ++ * get rid of the fraction ++ */ ++ err = qman_ceetm_set_queue_weight_in_ratio(cl->wbfs.cq, ++ copt->weight * 100); ++ ++ if (err) { ++ pr_err(KBUILD_BASENAME " : %s : failed to configure the ceetm wbfs class %X\n", ++ __func__, cl->common.classid); ++ return err; ++ } ++ ++ cl->wbfs.weight = copt->weight; ++ } ++ ++ return 0; ++} ++ ++/* Add a ceetm root class or configure a ceetm root/prio/wbfs class */ ++static int ceetm_cls_change(struct Qdisc *sch, u32 classid, u32 parentid, ++ struct nlattr **tca, unsigned long *arg) ++{ ++ int err; ++ u64 bps; ++ struct ceetm_qdisc *priv; ++ struct ceetm_class *cl = (struct ceetm_class *)*arg; ++ struct nlattr *opt = tca[TCA_OPTIONS]; ++ struct nlattr *tb[__TCA_CEETM_MAX]; ++ struct tc_ceetm_copt *copt; ++ struct qm_ceetm_channel *channel; ++ struct net_device *dev = qdisc_dev(sch); ++ ++ pr_debug(KBUILD_BASENAME " : %s : classid %X under qdisc %X\n", ++ __func__, classid, sch->handle); ++ ++ if (strcmp(sch->ops->id, ceetm_qdisc_ops.id)) { ++ pr_err("CEETM: a ceetm class can not be attached to other qdisc/class types\n"); ++ return -EINVAL; ++ } ++ ++ priv = qdisc_priv(sch); ++ ++ if (!opt) { ++ pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__); ++ return -EINVAL; ++ } ++ ++ if (!cl && sch->handle != parentid) { ++ pr_err("CEETM: classes can be attached to the root ceetm qdisc only\n"); ++ return -EINVAL; ++ } ++ ++ if (!cl && priv->type != CEETM_ROOT) { ++ pr_err("CEETM: only root ceetm classes can be attached to the root ceetm qdisc\n"); ++ return -EINVAL; ++ } ++ ++ err = nla_parse_nested(tb, TCA_CEETM_COPT, opt, ceetm_policy); ++ if (err < 0) { ++ pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__); ++ return -EINVAL; ++ } ++ ++ if (!tb[TCA_CEETM_COPT]) { ++ pr_err(KBUILD_BASENAME " : %s : tc error\n", __func__); ++ return -EINVAL; ++ } ++ ++ if (TC_H_MIN(classid) >= PFIFO_MIN_OFFSET) { ++ pr_err("CEETM: only minors 0x01 to 0x20 can be used for ceetm root classes\n"); ++ return -EINVAL; ++ } ++ ++ copt = nla_data(tb[TCA_CEETM_COPT]); ++ ++ /* Configure an existing ceetm class */ ++ if (cl) { ++ if (copt->type != cl->type) { ++ pr_err("CEETM: class %X is not of the provided type\n", ++ cl->common.classid); ++ return -EINVAL; ++ } ++ ++ switch (copt->type) { ++ case CEETM_ROOT: ++ return ceetm_cls_change_root(cl, copt, dev); ++ ++ case CEETM_PRIO: ++ return ceetm_cls_change_prio(cl, copt); ++ ++ case CEETM_WBFS: ++ return ceetm_cls_change_wbfs(cl, copt); ++ ++ default: ++ pr_err(KBUILD_BASENAME " : %s : invalid class\n", ++ __func__); ++ return -EINVAL; ++ } ++ } ++ ++ /* Add a new root ceetm class */ ++ if (copt->type != CEETM_ROOT) { ++ pr_err("CEETM: only root ceetm classes can be attached to the root ceetm qdisc\n"); ++ return -EINVAL; ++ } ++ ++ if (copt->shaped && !priv->shaped) { ++ pr_err("CEETM: can not add a shaped ceetm root class under an unshaped ceetm root qdisc\n"); ++ return -EINVAL; ++ } ++ ++ cl = kzalloc(sizeof(*cl), GFP_KERNEL); ++ if (!cl) ++ return -ENOMEM; ++ ++ cl->type = copt->type; ++ cl->shaped = copt->shaped; ++ cl->root.rate = copt->rate; ++ cl->root.ceil = copt->ceil; ++ cl->root.tbl = copt->tbl; ++ ++ cl->common.classid = classid; ++ cl->refcnt = 1; ++ cl->parent = sch; ++ cl->root.child = NULL; ++ cl->root.wbfs_grp_a = false; ++ cl->root.wbfs_grp_b = false; ++ cl->root.wbfs_grp_large = false; ++ ++ /* Claim a CEETM channel */ ++ err = qman_ceetm_channel_claim(&channel, priv->root.lni); ++ if (err) { ++ pr_err(KBUILD_BASENAME " : %s : failed to claim a channel\n", ++ __func__); ++ goto claim_err; ++ } ++ ++ cl->root.ch = channel; ++ ++ if (cl->shaped) { ++ /* Configure the channel shaper */ ++ err = qman_ceetm_channel_enable_shaper(channel, 1); ++ if (err) ++ goto channel_err; ++ ++ bps = cl->root.rate << 3; /* Bps -> bps */ ++ err = qman_ceetm_channel_set_commit_rate_bps(channel, bps, ++ dev->mtu); ++ if (err) ++ goto channel_err; ++ ++ bps = cl->root.ceil << 3; /* Bps -> bps */ ++ err = qman_ceetm_channel_set_excess_rate_bps(channel, bps, ++ dev->mtu); ++ if (err) ++ goto channel_err; ++ ++ } else { ++ /* Configure the uFQ algorithm */ ++ err = qman_ceetm_channel_set_weight(channel, cl->root.tbl); ++ if (err) ++ goto channel_err; ++ } ++ ++ /* Add class handle in Qdisc */ ++ ceetm_link_class(sch, &priv->clhash, &cl->common); ++ ++ pr_debug(KBUILD_BASENAME " : %s : configured class %X associated with channel %d\n", ++ __func__, classid, channel->idx); ++ *arg = (unsigned long)cl; ++ return 0; ++ ++channel_err: ++ pr_err(KBUILD_BASENAME " : %s : failed to configure the channel %d\n", ++ __func__, channel->idx); ++ if (qman_ceetm_channel_release(channel)) ++ pr_err(KBUILD_BASENAME " : %s : failed to release the channel %d\n", ++ __func__, channel->idx); ++claim_err: ++ kfree(cl); ++ return err; ++} ++ ++static void ceetm_cls_walk(struct Qdisc *sch, struct qdisc_walker *arg) ++{ ++ struct ceetm_qdisc *priv = qdisc_priv(sch); ++ struct ceetm_class *cl; ++ unsigned int i; ++ ++ pr_debug(KBUILD_BASENAME " : %s : qdisc %X\n", __func__, sch->handle); ++ ++ if (arg->stop) ++ return; ++ ++ for (i = 0; i < priv->clhash.hashsize; i++) { ++ hlist_for_each_entry(cl, &priv->clhash.hash[i], common.hnode) { ++ if (arg->count < arg->skip) { ++ arg->count++; ++ continue; ++ } ++ if (arg->fn(sch, (unsigned long)cl, arg) < 0) { ++ arg->stop = 1; ++ return; ++ } ++ arg->count++; ++ } ++ } ++} ++ ++static int ceetm_cls_dump(struct Qdisc *sch, unsigned long arg, ++ struct sk_buff *skb, struct tcmsg *tcm) ++{ ++ struct ceetm_class *cl = (struct ceetm_class *)arg; ++ struct nlattr *nest; ++ struct tc_ceetm_copt copt; ++ ++ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", ++ __func__, cl->common.classid, sch->handle); ++ ++ sch_tree_lock(sch); ++ ++ tcm->tcm_parent = ((struct Qdisc *)cl->parent)->handle; ++ tcm->tcm_handle = cl->common.classid; ++ ++ memset(&copt, 0, sizeof(copt)); ++ ++ copt.shaped = cl->shaped; ++ copt.type = cl->type; ++ ++ switch (cl->type) { ++ case CEETM_ROOT: ++ if (cl->root.child) ++ tcm->tcm_info = cl->root.child->handle; ++ ++ copt.rate = cl->root.rate; ++ copt.ceil = cl->root.ceil; ++ copt.tbl = cl->root.tbl; ++ break; ++ ++ case CEETM_PRIO: ++ if (cl->prio.child) ++ tcm->tcm_info = cl->prio.child->handle; ++ ++ copt.cr = cl->prio.cr; ++ copt.er = cl->prio.er; ++ break; ++ ++ case CEETM_WBFS: ++ copt.weight = cl->wbfs.weight; ++ break; ++ } ++ ++ nest = nla_nest_start(skb, TCA_OPTIONS); ++ if (!nest) ++ goto nla_put_failure; ++ if (nla_put(skb, TCA_CEETM_COPT, sizeof(copt), &copt)) ++ goto nla_put_failure; ++ nla_nest_end(skb, nest); ++ sch_tree_unlock(sch); ++ return skb->len; ++ ++nla_put_failure: ++ sch_tree_unlock(sch); ++ nla_nest_cancel(skb, nest); ++ return -EMSGSIZE; ++} ++ ++static int ceetm_cls_delete(struct Qdisc *sch, unsigned long arg) ++{ ++ struct ceetm_qdisc *priv = qdisc_priv(sch); ++ struct ceetm_class *cl = (struct ceetm_class *)arg; ++ ++ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", ++ __func__, cl->common.classid, sch->handle); ++ ++ sch_tree_lock(sch); ++ qdisc_class_hash_remove(&priv->clhash, &cl->common); ++ cl->refcnt--; ++ ++ /* The refcnt should be at least 1 since we have incremented it in ++ * get(). Will decrement again in put() where we will call destroy() ++ * to actually free the memory if it reaches 0. ++ */ ++ WARN_ON(cl->refcnt == 0); ++ ++ sch_tree_unlock(sch); ++ return 0; ++} ++ ++/* Get the class' child qdisc, if any */ ++static struct Qdisc *ceetm_cls_leaf(struct Qdisc *sch, unsigned long arg) ++{ ++ struct ceetm_class *cl = (struct ceetm_class *)arg; ++ ++ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", ++ __func__, cl->common.classid, sch->handle); ++ ++ switch (cl->type) { ++ case CEETM_ROOT: ++ return cl->root.child; ++ ++ case CEETM_PRIO: ++ return cl->prio.child; ++ } ++ ++ return NULL; ++} ++ ++static int ceetm_cls_graft(struct Qdisc *sch, unsigned long arg, ++ struct Qdisc *new, struct Qdisc **old) ++{ ++ if (new && strcmp(new->ops->id, ceetm_qdisc_ops.id)) { ++ pr_err("CEETM: only ceetm qdiscs can be attached to ceetm classes\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++static int ceetm_cls_dump_stats(struct Qdisc *sch, unsigned long arg, ++ struct gnet_dump *d) ++{ ++ unsigned int i; ++ struct ceetm_class *cl = (struct ceetm_class *)arg; ++ struct gnet_stats_basic_packed tmp_bstats; ++ struct ceetm_class_stats *cstats = NULL; ++ struct qm_ceetm_cq *cq = NULL; ++ struct tc_ceetm_xstats xstats; ++ ++ memset(&xstats, 0, sizeof(xstats)); ++ memset(&tmp_bstats, 0, sizeof(tmp_bstats)); ++ ++ switch (cl->type) { ++ case CEETM_ROOT: ++ return 0; ++ case CEETM_PRIO: ++ cq = cl->prio.cq; ++ break; ++ case CEETM_WBFS: ++ cq = cl->wbfs.cq; ++ break; ++ } ++ ++ for_each_online_cpu(i) { ++ switch (cl->type) { ++ case CEETM_PRIO: ++ cstats = per_cpu_ptr(cl->prio.cstats, i); ++ break; ++ case CEETM_WBFS: ++ cstats = per_cpu_ptr(cl->wbfs.cstats, i); ++ break; ++ } ++ ++ if (cstats) { ++ xstats.ern_drop_count += cstats->ern_drop_count; ++ xstats.congested_count += cstats->congested_count; ++ tmp_bstats.bytes += cstats->bstats.bytes; ++ tmp_bstats.packets += cstats->bstats.packets; ++ } ++ } ++ ++ if (gnet_stats_copy_basic(qdisc_root_sleeping_running(sch), ++ d, NULL, &tmp_bstats) < 0) ++ return -1; ++ ++ if (cq && qman_ceetm_cq_get_dequeue_statistics(cq, 0, ++ &xstats.frame_count, ++ &xstats.byte_count)) ++ return -1; ++ ++ return gnet_stats_copy_app(d, &xstats, sizeof(xstats)); ++} ++ ++static struct tcf_proto **ceetm_tcf_chain(struct Qdisc *sch, unsigned long arg) ++{ ++ struct ceetm_qdisc *priv = qdisc_priv(sch); ++ struct ceetm_class *cl = (struct ceetm_class *)arg; ++ struct tcf_proto **fl = cl ? &cl->filter_list : &priv->filter_list; ++ ++ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__, ++ cl ? cl->common.classid : 0, sch->handle); ++ return fl; ++} ++ ++static unsigned long ceetm_tcf_bind(struct Qdisc *sch, unsigned long parent, ++ u32 classid) ++{ ++ struct ceetm_class *cl = ceetm_find(classid, sch); ++ ++ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__, ++ cl ? cl->common.classid : 0, sch->handle); ++ return (unsigned long)cl; ++} ++ ++static void ceetm_tcf_unbind(struct Qdisc *sch, unsigned long arg) ++{ ++ struct ceetm_class *cl = (struct ceetm_class *)arg; ++ ++ pr_debug(KBUILD_BASENAME " : %s : class %X under qdisc %X\n", __func__, ++ cl ? cl->common.classid : 0, sch->handle); ++} ++ ++const struct Qdisc_class_ops ceetm_cls_ops = { ++ .graft = ceetm_cls_graft, ++ .leaf = ceetm_cls_leaf, ++ .get = ceetm_cls_get, ++ .put = ceetm_cls_put, ++ .change = ceetm_cls_change, ++ .delete = ceetm_cls_delete, ++ .walk = ceetm_cls_walk, ++ .tcf_chain = ceetm_tcf_chain, ++ .bind_tcf = ceetm_tcf_bind, ++ .unbind_tcf = ceetm_tcf_unbind, ++ .dump = ceetm_cls_dump, ++ .dump_stats = ceetm_cls_dump_stats, ++}; ++ ++struct Qdisc_ops ceetm_qdisc_ops __read_mostly = { ++ .id = "ceetm", ++ .priv_size = sizeof(struct ceetm_qdisc), ++ .cl_ops = &ceetm_cls_ops, ++ .init = ceetm_init, ++ .destroy = ceetm_destroy, ++ .change = ceetm_change, ++ .dump = ceetm_dump, ++ .attach = ceetm_attach, ++ .owner = THIS_MODULE, ++}; ++ ++/* Run the filters and classifiers attached to the qdisc on the provided skb */ ++static struct ceetm_class *ceetm_classify(struct sk_buff *skb, ++ struct Qdisc *sch, int *qerr, ++ bool *act_drop) ++{ ++ struct ceetm_qdisc *priv = qdisc_priv(sch); ++ struct ceetm_class *cl = NULL, *wbfs_cl; ++ struct tcf_result res; ++ struct tcf_proto *tcf; ++ int result; ++ ++ *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; ++ tcf = priv->filter_list; ++ while (tcf && (result = tc_classify(skb, tcf, &res, false)) >= 0) { ++#ifdef CONFIG_NET_CLS_ACT ++ switch (result) { ++ case TC_ACT_QUEUED: ++ case TC_ACT_STOLEN: ++ *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN; ++ case TC_ACT_SHOT: ++ /* No valid class found due to action */ ++ *act_drop = true; ++ return NULL; ++ } ++#endif ++ cl = (void *)res.class; ++ if (!cl) { ++ if (res.classid == sch->handle) { ++ /* The filter leads to the qdisc */ ++ /* TODO default qdisc */ ++ return NULL; ++ } ++ ++ cl = ceetm_find(res.classid, sch); ++ if (!cl) ++ /* The filter leads to an invalid class */ ++ break; ++ } ++ ++ /* The class might have its own filters attached */ ++ tcf = cl->filter_list; ++ } ++ ++ if (!cl) { ++ /* No valid class found */ ++ /* TODO default qdisc */ ++ return NULL; ++ } ++ ++ switch (cl->type) { ++ case CEETM_ROOT: ++ if (cl->root.child) { ++ /* Run the prio qdisc classifiers */ ++ return ceetm_classify(skb, cl->root.child, qerr, ++ act_drop); ++ } else { ++ /* The root class does not have a child prio qdisc */ ++ /* TODO default qdisc */ ++ return NULL; ++ } ++ case CEETM_PRIO: ++ if (cl->prio.child) { ++ /* If filters lead to a wbfs class, return it. ++ * Otherwise, return the prio class ++ */ ++ wbfs_cl = ceetm_classify(skb, cl->prio.child, qerr, ++ act_drop); ++ /* A NULL result might indicate either an erroneous ++ * filter, or no filters at all. We will assume the ++ * latter ++ */ ++ return wbfs_cl ? : cl; ++ } ++ } ++ ++ /* For wbfs and childless prio classes, return the class directly */ ++ return cl; ++} ++ ++int __hot ceetm_tx(struct sk_buff *skb, struct net_device *net_dev) ++{ ++ int ret; ++ bool act_drop = false; ++ struct Qdisc *sch = net_dev->qdisc; ++ struct ceetm_class *cl; ++ struct dpa_priv_s *priv_dpa; ++ struct qman_fq *egress_fq, *conf_fq; ++ struct ceetm_qdisc *priv = qdisc_priv(sch); ++ struct ceetm_qdisc_stats *qstats = this_cpu_ptr(priv->root.qstats); ++ struct ceetm_class_stats *cstats; ++ const int queue_mapping = dpa_get_queue_mapping(skb); ++ spinlock_t *root_lock = qdisc_lock(sch); ++ ++ spin_lock(root_lock); ++ cl = ceetm_classify(skb, sch, &ret, &act_drop); ++ spin_unlock(root_lock); ++ ++#ifdef CONFIG_NET_CLS_ACT ++ if (act_drop) { ++ if (ret & __NET_XMIT_BYPASS) ++ qstats->drops++; ++ goto drop; ++ } ++#endif ++ /* TODO default class */ ++ if (unlikely(!cl)) { ++ qstats->drops++; ++ goto drop; ++ } ++ ++ priv_dpa = netdev_priv(net_dev); ++ conf_fq = priv_dpa->conf_fqs[queue_mapping]; ++ ++ /* Choose the proper tx fq and update the basic stats (bytes and ++ * packets sent by the class) ++ */ ++ switch (cl->type) { ++ case CEETM_PRIO: ++ egress_fq = &cl->prio.fq->fq; ++ cstats = this_cpu_ptr(cl->prio.cstats); ++ break; ++ case CEETM_WBFS: ++ egress_fq = &cl->wbfs.fq->fq; ++ cstats = this_cpu_ptr(cl->wbfs.cstats); ++ break; ++ default: ++ qstats->drops++; ++ goto drop; ++ } ++ ++ bstats_update(&cstats->bstats, skb); ++ return dpa_tx_extended(skb, net_dev, egress_fq, conf_fq); ++ ++drop: ++ dev_kfree_skb_any(skb); ++ return NET_XMIT_SUCCESS; ++} ++ ++static int __init ceetm_register(void) ++{ ++ int _errno = 0; ++ ++ pr_info(KBUILD_MODNAME ": " DPA_CEETM_DESCRIPTION "\n"); ++ ++ _errno = register_qdisc(&ceetm_qdisc_ops); ++ if (unlikely(_errno)) ++ pr_err(KBUILD_MODNAME ++ ": %s:%hu:%s(): register_qdisc() = %d\n", ++ KBUILD_BASENAME ".c", __LINE__, __func__, _errno); ++ ++ return _errno; ++} ++ ++static void __exit ceetm_unregister(void) ++{ ++ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", ++ KBUILD_BASENAME ".c", __func__); ++ ++ unregister_qdisc(&ceetm_qdisc_ops); ++} ++ ++module_init(ceetm_register); ++module_exit(ceetm_unregister); +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h +new file mode 100644 +index 00000000..63cc3475 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_ceetm.h +@@ -0,0 +1,237 @@ ++/* Copyright 2008-2016 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __DPAA_ETH_CEETM_H ++#define __DPAA_ETH_CEETM_H ++ ++#include ++#include ++#include ++#include ++ ++#include "mac.h" ++#include "dpaa_eth_common.h" ++ ++/* Mask to determine the sub-portal id from a channel number */ ++#define CHANNEL_SP_MASK 0x1f ++/* The number of the last channel that services DCP0, connected to FMan 0. ++ * Value validated for B4 and T series platforms. ++ */ ++#define DCP0_MAX_CHANNEL 0x80f ++/* A2V=1 - field A2 is valid ++ * A0V=1 - field A0 is valid - enables frame confirmation ++ * OVOM=1 - override operation mode bits with values from A2 ++ * EBD=1 - external buffers are deallocated at the end of the FMan flow ++ * NL=0 - the BMI releases all the internal buffers ++ */ ++#define CEETM_CONTEXT_A 0x1a00000080000000 ++/* The ratio between the superior and inferior congestion state thresholds. The ++ * lower threshold is set to 7/8 of the superior one (as the default for WQ ++ * scheduling). ++ */ ++#define CEETM_CCGR_RATIO 0.875 ++/* For functional purposes, there are num_tx_queues pfifo qdiscs through which ++ * frames reach the driver. Their handles start from 1:21. Handles 1:1 to 1:20 ++ * are reserved for the maximum 32 CEETM channels (majors and minors are in ++ * hex). ++ */ ++#define PFIFO_MIN_OFFSET 0x21 ++ ++/* A maximum of 8 CQs can be linked to a CQ channel or to a WBFS scheduler. */ ++#define CEETM_MAX_PRIO_QCOUNT 8 ++#define CEETM_MAX_WBFS_QCOUNT 8 ++#define CEETM_MIN_WBFS_QCOUNT 4 ++ ++/* The id offsets of the CQs belonging to WBFS groups (ids 8-11/15 for group A ++ * and/or 12-15 for group B). ++ */ ++#define WBFS_GRP_A_OFFSET 8 ++#define WBFS_GRP_B_OFFSET 12 ++ ++#define WBFS_GRP_A 1 ++#define WBFS_GRP_B 2 ++#define WBFS_GRP_LARGE 3 ++ ++enum { ++ TCA_CEETM_UNSPEC, ++ TCA_CEETM_COPT, ++ TCA_CEETM_QOPS, ++ __TCA_CEETM_MAX, ++}; ++ ++/* CEETM configuration types */ ++enum { ++ CEETM_ROOT = 1, ++ CEETM_PRIO, ++ CEETM_WBFS ++}; ++ ++#define TCA_CEETM_MAX (__TCA_CEETM_MAX - 1) ++extern const struct nla_policy ceetm_policy[TCA_CEETM_MAX + 1]; ++ ++struct ceetm_class; ++struct ceetm_qdisc_stats; ++struct ceetm_class_stats; ++ ++struct ceetm_fq { ++ struct qman_fq fq; ++ struct net_device *net_dev; ++ struct ceetm_class *ceetm_cls; ++}; ++ ++struct root_q { ++ struct Qdisc **qdiscs; ++ __u16 overhead; ++ __u32 rate; ++ __u32 ceil; ++ struct qm_ceetm_sp *sp; ++ struct qm_ceetm_lni *lni; ++ struct ceetm_qdisc_stats __percpu *qstats; ++}; ++ ++struct prio_q { ++ __u16 qcount; ++ struct ceetm_class *parent; ++}; ++ ++struct wbfs_q { ++ __u16 qcount; ++ int group_type; ++ struct ceetm_class *parent; ++ __u16 cr; ++ __u16 er; ++}; ++ ++struct ceetm_qdisc { ++ int type; /* LNI/CHNL/WBFS */ ++ bool shaped; ++ union { ++ struct root_q root; ++ struct prio_q prio; ++ struct wbfs_q wbfs; ++ }; ++ struct Qdisc_class_hash clhash; ++ struct tcf_proto *filter_list; /* qdisc attached filters */ ++}; ++ ++/* CEETM Qdisc configuration parameters */ ++struct tc_ceetm_qopt { ++ __u32 type; ++ __u16 shaped; ++ __u16 qcount; ++ __u16 overhead; ++ __u32 rate; ++ __u32 ceil; ++ __u16 cr; ++ __u16 er; ++ __u8 qweight[CEETM_MAX_WBFS_QCOUNT]; ++}; ++ ++struct root_c { ++ unsigned int rate; ++ unsigned int ceil; ++ unsigned int tbl; ++ bool wbfs_grp_a; ++ bool wbfs_grp_b; ++ bool wbfs_grp_large; ++ struct Qdisc *child; ++ struct qm_ceetm_channel *ch; ++}; ++ ++struct prio_c { ++ bool cr; ++ bool er; ++ struct ceetm_fq *fq; /* Hardware FQ instance Handle */ ++ struct qm_ceetm_lfq *lfq; ++ struct qm_ceetm_cq *cq; /* Hardware Class Queue instance Handle */ ++ struct qm_ceetm_ccg *ccg; ++ /* only one wbfs can be linked to one priority CQ */ ++ struct Qdisc *child; ++ struct ceetm_class_stats __percpu *cstats; ++}; ++ ++struct wbfs_c { ++ __u8 weight; /* The weight of the class between 1 and 248 */ ++ struct ceetm_fq *fq; /* Hardware FQ instance Handle */ ++ struct qm_ceetm_lfq *lfq; ++ struct qm_ceetm_cq *cq; /* Hardware Class Queue instance Handle */ ++ struct qm_ceetm_ccg *ccg; ++ struct ceetm_class_stats __percpu *cstats; ++}; ++ ++struct ceetm_class { ++ struct Qdisc_class_common common; ++ int refcnt; /* usage count of this class */ ++ struct tcf_proto *filter_list; /* class attached filters */ ++ struct Qdisc *parent; ++ bool shaped; ++ int type; /* ROOT/PRIO/WBFS */ ++ union { ++ struct root_c root; ++ struct prio_c prio; ++ struct wbfs_c wbfs; ++ }; ++}; ++ ++/* CEETM Class configuration parameters */ ++struct tc_ceetm_copt { ++ __u32 type; ++ __u16 shaped; ++ __u32 rate; ++ __u32 ceil; ++ __u16 tbl; ++ __u16 cr; ++ __u16 er; ++ __u8 weight; ++}; ++ ++/* CEETM stats */ ++struct ceetm_qdisc_stats { ++ __u32 drops; ++}; ++ ++struct ceetm_class_stats { ++ /* Software counters */ ++ struct gnet_stats_basic_packed bstats; ++ __u32 ern_drop_count; ++ __u32 congested_count; ++}; ++ ++struct tc_ceetm_xstats { ++ __u32 ern_drop_count; ++ __u32 congested_count; ++ /* Hardware counters */ ++ __u64 frame_count; ++ __u64 byte_count; ++}; ++ ++int __hot ceetm_tx(struct sk_buff *skb, struct net_device *net_dev); ++#endif +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c +new file mode 100644 +index 00000000..fbe61da2 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c +@@ -0,0 +1,1811 @@ ++/* Copyright 2008-2013 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* vlan_eth_hdr */ ++#include "dpaa_eth.h" ++#include "dpaa_eth_common.h" ++#ifdef CONFIG_FSL_DPAA_1588 ++#include "dpaa_1588.h" ++#endif ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++#include "dpaa_debugfs.h" ++#endif /* CONFIG_FSL_DPAA_DBG_LOOP */ ++#include "mac.h" ++ ++/* Size in bytes of the FQ taildrop threshold */ ++#define DPA_FQ_TD 0x200000 ++ ++#ifdef CONFIG_PTP_1588_CLOCK_DPAA ++struct ptp_priv_s ptp_priv; ++#endif ++ ++static struct dpa_bp *dpa_bp_array[64]; ++ ++int dpa_max_frm; ++EXPORT_SYMBOL(dpa_max_frm); ++ ++int dpa_rx_extra_headroom; ++EXPORT_SYMBOL(dpa_rx_extra_headroom); ++ ++int dpa_num_cpus = NR_CPUS; ++ ++static const struct fqid_cell tx_confirm_fqids[] = { ++ {0, DPAA_ETH_TX_QUEUES} ++}; ++ ++static struct fqid_cell default_fqids[][3] = { ++ [RX] = { {0, 1}, {0, 1}, {0, DPAA_ETH_RX_QUEUES} }, ++ [TX] = { {0, 1}, {0, 1}, {0, DPAA_ETH_TX_QUEUES} } ++}; ++ ++static const char fsl_qman_frame_queues[][25] = { ++ [RX] = "fsl,qman-frame-queues-rx", ++ [TX] = "fsl,qman-frame-queues-tx" ++}; ++#ifdef CONFIG_FSL_DPAA_HOOKS ++/* A set of callbacks for hooking into the fastpath at different points. */ ++struct dpaa_eth_hooks_s dpaa_eth_hooks; ++EXPORT_SYMBOL(dpaa_eth_hooks); ++/* This function should only be called on the probe paths, since it makes no ++ * effort to guarantee consistency of the destination hooks structure. ++ */ ++void fsl_dpaa_eth_set_hooks(struct dpaa_eth_hooks_s *hooks) ++{ ++ if (hooks) ++ dpaa_eth_hooks = *hooks; ++ else ++ pr_err("NULL pointer to hooks!\n"); ++} ++EXPORT_SYMBOL(fsl_dpaa_eth_set_hooks); ++#endif ++ ++int dpa_netdev_init(struct net_device *net_dev, ++ const uint8_t *mac_addr, ++ uint16_t tx_timeout) ++{ ++ int err; ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ struct device *dev = net_dev->dev.parent; ++ ++ net_dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; ++ ++ net_dev->features |= net_dev->hw_features; ++ net_dev->vlan_features = net_dev->features; ++ ++ memcpy(net_dev->perm_addr, mac_addr, net_dev->addr_len); ++ memcpy(net_dev->dev_addr, mac_addr, net_dev->addr_len); ++ ++ net_dev->ethtool_ops = &dpa_ethtool_ops; ++ ++ net_dev->needed_headroom = priv->tx_headroom; ++ net_dev->watchdog_timeo = msecs_to_jiffies(tx_timeout); ++ ++ err = register_netdev(net_dev); ++ if (err < 0) { ++ dev_err(dev, "register_netdev() = %d\n", err); ++ return err; ++ } ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++ /* create debugfs entry for this net_device */ ++ err = dpa_netdev_debugfs_create(net_dev); ++ if (err) { ++ unregister_netdev(net_dev); ++ return err; ++ } ++#endif /* CONFIG_FSL_DPAA_DBG_LOOP */ ++ ++ return 0; ++} ++EXPORT_SYMBOL(dpa_netdev_init); ++ ++int __cold dpa_start(struct net_device *net_dev) ++{ ++ int err, i; ++ struct dpa_priv_s *priv; ++ struct mac_device *mac_dev; ++ ++ priv = netdev_priv(net_dev); ++ mac_dev = priv->mac_dev; ++ ++ err = mac_dev->init_phy(net_dev, priv->mac_dev); ++ if (err < 0) { ++ if (netif_msg_ifup(priv)) ++ netdev_err(net_dev, "init_phy() = %d\n", err); ++ return err; ++ } ++ ++ for_each_port_device(i, mac_dev->port_dev) { ++ err = fm_port_enable(mac_dev->port_dev[i]); ++ if (err) ++ goto mac_start_failed; ++ } ++ ++ err = priv->mac_dev->start(mac_dev); ++ if (err < 0) { ++ if (netif_msg_ifup(priv)) ++ netdev_err(net_dev, "mac_dev->start() = %d\n", err); ++ goto mac_start_failed; ++ } ++ ++ netif_tx_start_all_queues(net_dev); ++ ++ return 0; ++ ++mac_start_failed: ++ for_each_port_device(i, mac_dev->port_dev) ++ fm_port_disable(mac_dev->port_dev[i]); ++ ++ return err; ++} ++EXPORT_SYMBOL(dpa_start); ++ ++int __cold dpa_stop(struct net_device *net_dev) ++{ ++ int _errno, i, err; ++ struct dpa_priv_s *priv; ++ struct mac_device *mac_dev; ++ ++ priv = netdev_priv(net_dev); ++ mac_dev = priv->mac_dev; ++ ++ netif_tx_stop_all_queues(net_dev); ++ /* Allow the Fman (Tx) port to process in-flight frames before we ++ * try switching it off. ++ */ ++ usleep_range(5000, 10000); ++ ++ _errno = mac_dev->stop(mac_dev); ++ if (unlikely(_errno < 0)) ++ if (netif_msg_ifdown(priv)) ++ netdev_err(net_dev, "mac_dev->stop() = %d\n", ++ _errno); ++ ++ for_each_port_device(i, mac_dev->port_dev) { ++ err = fm_port_disable(mac_dev->port_dev[i]); ++ _errno = err ? err : _errno; ++ } ++ ++ if (mac_dev->phy_dev) ++ phy_disconnect(mac_dev->phy_dev); ++ mac_dev->phy_dev = NULL; ++ ++ return _errno; ++} ++EXPORT_SYMBOL(dpa_stop); ++ ++void __cold dpa_timeout(struct net_device *net_dev) ++{ ++ const struct dpa_priv_s *priv; ++ struct dpa_percpu_priv_s *percpu_priv; ++ ++ priv = netdev_priv(net_dev); ++ percpu_priv = raw_cpu_ptr(priv->percpu_priv); ++ ++ if (netif_msg_timer(priv)) ++ netdev_crit(net_dev, "Transmit timeout!\n"); ++ ++ percpu_priv->stats.tx_errors++; ++} ++EXPORT_SYMBOL(dpa_timeout); ++ ++/* net_device */ ++ ++/** ++ * @param net_dev the device for which statistics are calculated ++ * @param stats the function fills this structure with the device's statistics ++ * @return the address of the structure containing the statistics ++ * ++ * Calculates the statistics for the given device by adding the statistics ++ * collected by each CPU. ++ */ ++void __cold ++dpa_get_stats64(struct net_device *net_dev, ++ struct rtnl_link_stats64 *stats) ++{ ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ u64 *cpustats; ++ u64 *netstats = (u64 *)stats; ++ int i, j; ++ struct dpa_percpu_priv_s *percpu_priv; ++ int numstats = sizeof(struct rtnl_link_stats64) / sizeof(u64); ++ ++ for_each_possible_cpu(i) { ++ percpu_priv = per_cpu_ptr(priv->percpu_priv, i); ++ ++ cpustats = (u64 *)&percpu_priv->stats; ++ ++ for (j = 0; j < numstats; j++) ++ netstats[j] += cpustats[j]; ++ } ++} ++EXPORT_SYMBOL(dpa_get_stats64); ++ ++int dpa_change_mtu(struct net_device *net_dev, int new_mtu) ++{ ++ const int max_mtu = dpa_get_max_mtu(); ++ ++ /* Make sure we don't exceed the Ethernet controller's MAXFRM */ ++ if (new_mtu < 68 || new_mtu > max_mtu) { ++ netdev_err(net_dev, "Invalid L3 mtu %d (must be between %d and %d).\n", ++ new_mtu, 68, max_mtu); ++ return -EINVAL; ++ } ++ net_dev->mtu = new_mtu; ++ ++ return 0; ++} ++EXPORT_SYMBOL(dpa_change_mtu); ++ ++/* .ndo_init callback */ ++int dpa_ndo_init(struct net_device *net_dev) ++{ ++ /* If fsl_fm_max_frm is set to a higher value than the all-common 1500, ++ * we choose conservatively and let the user explicitly set a higher ++ * MTU via ifconfig. Otherwise, the user may end up with different MTUs ++ * in the same LAN. ++ * If on the other hand fsl_fm_max_frm has been chosen below 1500, ++ * start with the maximum allowed. ++ */ ++ int init_mtu = min(dpa_get_max_mtu(), ETH_DATA_LEN); ++ ++ pr_debug("Setting initial MTU on net device: %d\n", init_mtu); ++ net_dev->mtu = init_mtu; ++ ++ return 0; ++} ++EXPORT_SYMBOL(dpa_ndo_init); ++ ++int dpa_set_features(struct net_device *dev, netdev_features_t features) ++{ ++ /* Not much to do here for now */ ++ dev->features = features; ++ return 0; ++} ++EXPORT_SYMBOL(dpa_set_features); ++ ++netdev_features_t dpa_fix_features(struct net_device *dev, ++ netdev_features_t features) ++{ ++ netdev_features_t unsupported_features = 0; ++ ++ /* In theory we should never be requested to enable features that ++ * we didn't set in netdev->features and netdev->hw_features at probe ++ * time, but double check just to be on the safe side. ++ * We don't support enabling Rx csum through ethtool yet ++ */ ++ unsupported_features |= NETIF_F_RXCSUM; ++ ++ features &= ~unsupported_features; ++ ++ return features; ++} ++EXPORT_SYMBOL(dpa_fix_features); ++ ++#ifdef CONFIG_FSL_DPAA_TS ++u64 dpa_get_timestamp_ns(const struct dpa_priv_s *priv, enum port_type rx_tx, ++ const void *data) ++{ ++ u64 *ts, ns; ++ ++ ts = fm_port_get_buffer_time_stamp(priv->mac_dev->port_dev[rx_tx], ++ data); ++ ++ if (!ts || *ts == 0) ++ return 0; ++ ++ be64_to_cpus(ts); ++ ++ /* multiple DPA_PTP_NOMINAL_FREQ_PERIOD_NS for case of non power of 2 */ ++ ns = *ts << DPA_PTP_NOMINAL_FREQ_PERIOD_SHIFT; ++ ++ return ns; ++} ++ ++int dpa_get_ts(const struct dpa_priv_s *priv, enum port_type rx_tx, ++ struct skb_shared_hwtstamps *shhwtstamps, const void *data) ++{ ++ u64 ns; ++ ++ ns = dpa_get_timestamp_ns(priv, rx_tx, data); ++ ++ if (ns == 0) ++ return -EINVAL; ++ ++ memset(shhwtstamps, 0, sizeof(*shhwtstamps)); ++ shhwtstamps->hwtstamp = ns_to_ktime(ns); ++ ++ return 0; ++} ++ ++static void dpa_ts_tx_enable(struct net_device *dev) ++{ ++ struct dpa_priv_s *priv = netdev_priv(dev); ++ struct mac_device *mac_dev = priv->mac_dev; ++ ++ if (mac_dev->fm_rtc_enable) ++ mac_dev->fm_rtc_enable(get_fm_handle(dev)); ++ if (mac_dev->ptp_enable) ++ mac_dev->ptp_enable(mac_dev->get_mac_handle(mac_dev)); ++ ++ priv->ts_tx_en = true; ++} ++ ++static void dpa_ts_tx_disable(struct net_device *dev) ++{ ++ struct dpa_priv_s *priv = netdev_priv(dev); ++ ++#if 0 ++/* the RTC might be needed by the Rx Ts, cannot disable here ++ * no separate ptp_disable API for Rx/Tx, cannot disable here ++ */ ++ struct mac_device *mac_dev = priv->mac_dev; ++ ++ if (mac_dev->fm_rtc_disable) ++ mac_dev->fm_rtc_disable(get_fm_handle(dev)); ++ ++ if (mac_dev->ptp_disable) ++ mac_dev->ptp_disable(mac_dev->get_mac_handle(mac_dev)); ++#endif ++ ++ priv->ts_tx_en = false; ++} ++ ++static void dpa_ts_rx_enable(struct net_device *dev) ++{ ++ struct dpa_priv_s *priv = netdev_priv(dev); ++ struct mac_device *mac_dev = priv->mac_dev; ++ ++ if (mac_dev->fm_rtc_enable) ++ mac_dev->fm_rtc_enable(get_fm_handle(dev)); ++ if (mac_dev->ptp_enable) ++ mac_dev->ptp_enable(mac_dev->get_mac_handle(mac_dev)); ++ ++ priv->ts_rx_en = true; ++} ++ ++static void dpa_ts_rx_disable(struct net_device *dev) ++{ ++ struct dpa_priv_s *priv = netdev_priv(dev); ++ ++#if 0 ++/* the RTC might be needed by the Tx Ts, cannot disable here ++ * no separate ptp_disable API for Rx/Tx, cannot disable here ++ */ ++ struct mac_device *mac_dev = priv->mac_dev; ++ ++ if (mac_dev->fm_rtc_disable) ++ mac_dev->fm_rtc_disable(get_fm_handle(dev)); ++ ++ if (mac_dev->ptp_disable) ++ mac_dev->ptp_disable(mac_dev->get_mac_handle(mac_dev)); ++#endif ++ ++ priv->ts_rx_en = false; ++} ++ ++static int dpa_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++{ ++ struct hwtstamp_config config; ++ ++ if (copy_from_user(&config, rq->ifr_data, sizeof(config))) ++ return -EFAULT; ++ ++ switch (config.tx_type) { ++ case HWTSTAMP_TX_OFF: ++ dpa_ts_tx_disable(dev); ++ break; ++ case HWTSTAMP_TX_ON: ++ dpa_ts_tx_enable(dev); ++ break; ++ default: ++ return -ERANGE; ++ } ++ ++ if (config.rx_filter == HWTSTAMP_FILTER_NONE) ++ dpa_ts_rx_disable(dev); ++ else { ++ dpa_ts_rx_enable(dev); ++ /* TS is set for all frame types, not only those requested */ ++ config.rx_filter = HWTSTAMP_FILTER_ALL; ++ } ++ ++ return copy_to_user(rq->ifr_data, &config, sizeof(config)) ? ++ -EFAULT : 0; ++} ++#endif /* CONFIG_FSL_DPAA_TS */ ++ ++int dpa_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++{ ++#ifdef CONFIG_FSL_DPAA_1588 ++ struct dpa_priv_s *priv = netdev_priv(dev); ++#endif ++ int ret = 0; ++ ++ /* at least one timestamping feature must be enabled */ ++#ifdef CONFIG_FSL_DPAA_TS ++ if (!netif_running(dev)) ++#endif ++ return -EINVAL; ++ ++#ifdef CONFIG_FSL_DPAA_TS ++ if (cmd == SIOCSHWTSTAMP) ++ return dpa_ts_ioctl(dev, rq, cmd); ++#endif /* CONFIG_FSL_DPAA_TS */ ++ ++#ifdef CONFIG_FSL_DPAA_1588 ++ if ((cmd >= PTP_ENBL_TXTS_IOCTL) && (cmd <= PTP_CLEANUP_TS)) { ++ if (priv->tsu && priv->tsu->valid) ++ ret = dpa_ioctl_1588(dev, rq, cmd); ++ else ++ ret = -ENODEV; ++ } ++#endif ++ ++ return ret; ++} ++EXPORT_SYMBOL(dpa_ioctl); ++ ++int __cold dpa_remove(struct platform_device *of_dev) ++{ ++ int err; ++ struct device *dev; ++ struct net_device *net_dev; ++ struct dpa_priv_s *priv; ++ ++ dev = &of_dev->dev; ++ net_dev = dev_get_drvdata(dev); ++ ++ priv = netdev_priv(net_dev); ++ ++ dpaa_eth_sysfs_remove(dev); ++ ++ dev_set_drvdata(dev, NULL); ++ unregister_netdev(net_dev); ++ ++ err = dpa_fq_free(dev, &priv->dpa_fq_list); ++ ++ qman_delete_cgr_safe(&priv->ingress_cgr); ++ qman_release_cgrid(priv->ingress_cgr.cgrid); ++ qman_delete_cgr_safe(&priv->cgr_data.cgr); ++ qman_release_cgrid(priv->cgr_data.cgr.cgrid); ++ ++ dpa_private_napi_del(net_dev); ++ ++ dpa_bp_free(priv); ++ ++ if (priv->buf_layout) ++ devm_kfree(dev, priv->buf_layout); ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++ /* remove debugfs entry for this net_device */ ++ dpa_netdev_debugfs_remove(net_dev); ++#endif /* CONFIG_FSL_DPAA_DBG_LOOP */ ++ ++#ifdef CONFIG_FSL_DPAA_1588 ++ if (priv->tsu && priv->tsu->valid) ++ dpa_ptp_cleanup(priv); ++#endif ++ ++ free_netdev(net_dev); ++ ++ return err; ++} ++EXPORT_SYMBOL(dpa_remove); ++ ++struct mac_device * __cold __must_check ++__attribute__((nonnull)) ++dpa_mac_probe(struct platform_device *_of_dev) ++{ ++ struct device *dpa_dev, *dev; ++ struct device_node *mac_node; ++ struct platform_device *of_dev; ++ struct mac_device *mac_dev; ++#ifdef CONFIG_FSL_DPAA_1588 ++ int lenp; ++ const phandle *phandle_prop; ++ struct net_device *net_dev = NULL; ++ struct dpa_priv_s *priv = NULL; ++ struct device_node *timer_node; ++#endif ++ dpa_dev = &_of_dev->dev; ++ ++ mac_node = of_parse_phandle(_of_dev->dev.of_node, "fsl,fman-mac", 0); ++ if (unlikely(mac_node == NULL)) { ++ dev_err(dpa_dev, "Cannot find MAC device device tree node\n"); ++ return ERR_PTR(-EFAULT); ++ } ++ ++ of_dev = of_find_device_by_node(mac_node); ++ if (unlikely(of_dev == NULL)) { ++ dev_err(dpa_dev, "of_find_device_by_node(%s) failed\n", ++ mac_node->full_name); ++ of_node_put(mac_node); ++ return ERR_PTR(-EINVAL); ++ } ++ of_node_put(mac_node); ++ ++ dev = &of_dev->dev; ++ ++ mac_dev = dev_get_drvdata(dev); ++ if (unlikely(mac_dev == NULL)) { ++ dev_err(dpa_dev, "dev_get_drvdata(%s) failed\n", ++ dev_name(dev)); ++ return ERR_PTR(-EINVAL); ++ } ++ ++#ifdef CONFIG_FSL_DPAA_1588 ++ phandle_prop = of_get_property(mac_node, "ptp-timer", &lenp); ++ if (phandle_prop && ((mac_dev->phy_if != PHY_INTERFACE_MODE_SGMII) || ++ ((mac_dev->phy_if == PHY_INTERFACE_MODE_SGMII) && ++ (mac_dev->speed == SPEED_1000)))) { ++ timer_node = of_find_node_by_phandle(*phandle_prop); ++ if (timer_node) ++ net_dev = dev_get_drvdata(dpa_dev); ++ if (timer_node && net_dev) { ++ priv = netdev_priv(net_dev); ++ if (!dpa_ptp_init(priv)) ++ dev_info(dev, "%s: ptp 1588 is initialized.\n", ++ mac_node->full_name); ++ } ++ } ++#endif ++ ++#ifdef CONFIG_PTP_1588_CLOCK_DPAA ++ if ((mac_dev->phy_if != PHY_INTERFACE_MODE_SGMII) || ++ ((mac_dev->phy_if == PHY_INTERFACE_MODE_SGMII) && ++ (mac_dev->speed == SPEED_1000))) { ++ ptp_priv.node = of_parse_phandle(mac_node, "ptp-timer", 0); ++ if (ptp_priv.node) { ++ ptp_priv.of_dev = of_find_device_by_node(ptp_priv.node); ++ if (unlikely(ptp_priv.of_dev == NULL)) { ++ dev_err(dpa_dev, ++ "Cannot find device represented by timer_node\n"); ++ of_node_put(ptp_priv.node); ++ return ERR_PTR(-EINVAL); ++ } ++ ptp_priv.mac_dev = mac_dev; ++ } ++ } ++#endif ++ return mac_dev; ++} ++EXPORT_SYMBOL(dpa_mac_probe); ++ ++int dpa_set_mac_address(struct net_device *net_dev, void *addr) ++{ ++ const struct dpa_priv_s *priv; ++ int _errno; ++ struct mac_device *mac_dev; ++ ++ priv = netdev_priv(net_dev); ++ ++ _errno = eth_mac_addr(net_dev, addr); ++ if (_errno < 0) { ++ if (netif_msg_drv(priv)) ++ netdev_err(net_dev, ++ "eth_mac_addr() = %d\n", ++ _errno); ++ return _errno; ++ } ++ ++ mac_dev = priv->mac_dev; ++ ++ _errno = mac_dev->change_addr(mac_dev->get_mac_handle(mac_dev), ++ net_dev->dev_addr); ++ if (_errno < 0) { ++ if (netif_msg_drv(priv)) ++ netdev_err(net_dev, ++ "mac_dev->change_addr() = %d\n", ++ _errno); ++ return _errno; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(dpa_set_mac_address); ++ ++void dpa_set_rx_mode(struct net_device *net_dev) ++{ ++ int _errno; ++ const struct dpa_priv_s *priv; ++ ++ priv = netdev_priv(net_dev); ++ ++ if (!!(net_dev->flags & IFF_PROMISC) != priv->mac_dev->promisc) { ++ priv->mac_dev->promisc = !priv->mac_dev->promisc; ++ _errno = priv->mac_dev->set_promisc( ++ priv->mac_dev->get_mac_handle(priv->mac_dev), ++ priv->mac_dev->promisc); ++ if (unlikely(_errno < 0) && netif_msg_drv(priv)) ++ netdev_err(net_dev, ++ "mac_dev->set_promisc() = %d\n", ++ _errno); ++ } ++ ++ _errno = priv->mac_dev->set_multi(net_dev, priv->mac_dev); ++ if (unlikely(_errno < 0) && netif_msg_drv(priv)) ++ netdev_err(net_dev, "mac_dev->set_multi() = %d\n", _errno); ++} ++EXPORT_SYMBOL(dpa_set_rx_mode); ++ ++void dpa_set_buffers_layout(struct mac_device *mac_dev, ++ struct dpa_buffer_layout_s *layout) ++{ ++ struct fm_port_params params; ++ ++ /* Rx */ ++ layout[RX].priv_data_size = (uint16_t)DPA_RX_PRIV_DATA_SIZE; ++ layout[RX].parse_results = true; ++ layout[RX].hash_results = true; ++#ifdef CONFIG_FSL_DPAA_TS ++ layout[RX].time_stamp = true; ++#endif ++ fm_port_get_buff_layout_ext_params(mac_dev->port_dev[RX], ¶ms); ++ layout[RX].manip_extra_space = params.manip_extra_space; ++ /* a value of zero for data alignment means "don't care", so align to ++ * a non-zero value to prevent FMD from using its own default ++ */ ++ layout[RX].data_align = params.data_align ? : DPA_FD_DATA_ALIGNMENT; ++ ++ /* Tx */ ++ layout[TX].priv_data_size = DPA_TX_PRIV_DATA_SIZE; ++ layout[TX].parse_results = true; ++ layout[TX].hash_results = true; ++#ifdef CONFIG_FSL_DPAA_TS ++ layout[TX].time_stamp = true; ++#endif ++ fm_port_get_buff_layout_ext_params(mac_dev->port_dev[TX], ¶ms); ++ layout[TX].manip_extra_space = params.manip_extra_space; ++ layout[TX].data_align = params.data_align ? : DPA_FD_DATA_ALIGNMENT; ++} ++EXPORT_SYMBOL(dpa_set_buffers_layout); ++ ++int __attribute__((nonnull)) ++dpa_bp_alloc(struct dpa_bp *dpa_bp) ++{ ++ int err; ++ struct bman_pool_params bp_params; ++ struct platform_device *pdev; ++ ++ if (dpa_bp->size == 0 || dpa_bp->config_count == 0) { ++ pr_err("Buffer pool is not properly initialized! Missing size or initial number of buffers"); ++ return -EINVAL; ++ } ++ ++ memset(&bp_params, 0, sizeof(struct bman_pool_params)); ++#ifdef CONFIG_FMAN_PFC ++ bp_params.flags = BMAN_POOL_FLAG_THRESH; ++ bp_params.thresholds[0] = bp_params.thresholds[2] = ++ CONFIG_FSL_DPAA_ETH_REFILL_THRESHOLD; ++ bp_params.thresholds[1] = bp_params.thresholds[3] = ++ CONFIG_FSL_DPAA_ETH_MAX_BUF_COUNT; ++#endif ++ ++ /* If the pool is already specified, we only create one per bpid */ ++ if (dpa_bpid2pool_use(dpa_bp->bpid)) ++ return 0; ++ ++ if (dpa_bp->bpid == 0) ++ bp_params.flags |= BMAN_POOL_FLAG_DYNAMIC_BPID; ++ else ++ bp_params.bpid = dpa_bp->bpid; ++ ++ dpa_bp->pool = bman_new_pool(&bp_params); ++ if (unlikely(dpa_bp->pool == NULL)) { ++ pr_err("bman_new_pool() failed\n"); ++ return -ENODEV; ++ } ++ ++ dpa_bp->bpid = (uint8_t)bman_get_params(dpa_bp->pool)->bpid; ++ ++ pdev = platform_device_register_simple("dpaa_eth_bpool", ++ dpa_bp->bpid, NULL, 0); ++ if (IS_ERR(pdev)) { ++ pr_err("platform_device_register_simple() failed\n"); ++ err = PTR_ERR(pdev); ++ goto pdev_register_failed; ++ } ++ { ++ struct dma_map_ops *ops = get_dma_ops(&pdev->dev); ++ ops->dma_supported = NULL; ++ } ++ err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); ++ if (err) { ++ pr_err("dma_coerce_mask_and_coherent() failed\n"); ++ goto pdev_mask_failed; ++ } ++#ifdef CONFIG_FMAN_ARM ++ /* force coherency */ ++ pdev->dev.archdata.dma_coherent = true; ++ arch_setup_dma_ops(&pdev->dev, 0, 0, NULL, true); ++#endif ++ ++ dpa_bp->dev = &pdev->dev; ++ ++ if (dpa_bp->seed_cb) { ++ err = dpa_bp->seed_cb(dpa_bp); ++ if (err) ++ goto pool_seed_failed; ++ } ++ ++ dpa_bpid2pool_map(dpa_bp->bpid, dpa_bp); ++ ++ return 0; ++ ++pool_seed_failed: ++pdev_mask_failed: ++ platform_device_unregister(pdev); ++pdev_register_failed: ++ bman_free_pool(dpa_bp->pool); ++ ++ return err; ++} ++EXPORT_SYMBOL(dpa_bp_alloc); ++ ++void dpa_bp_drain(struct dpa_bp *bp) ++{ ++ int ret, num = 8; ++ ++ do { ++ struct bm_buffer bmb[8]; ++ int i; ++ ++ ret = bman_acquire(bp->pool, bmb, num, 0); ++ if (ret < 0) { ++ if (num == 8) { ++ /* we have less than 8 buffers left; ++ * drain them one by one ++ */ ++ num = 1; ++ ret = 1; ++ continue; ++ } else { ++ /* Pool is fully drained */ ++ break; ++ } ++ } ++ ++ for (i = 0; i < num; i++) { ++ dma_addr_t addr = bm_buf_addr(&bmb[i]); ++ ++ dma_unmap_single(bp->dev, addr, bp->size, ++ DMA_BIDIRECTIONAL); ++ ++ bp->free_buf_cb(phys_to_virt(addr)); ++ } ++ } while (ret > 0); ++} ++EXPORT_SYMBOL(dpa_bp_drain); ++ ++static void __cold __attribute__((nonnull)) ++_dpa_bp_free(struct dpa_bp *dpa_bp) ++{ ++ struct dpa_bp *bp = dpa_bpid2pool(dpa_bp->bpid); ++ ++ /* the mapping between bpid and dpa_bp is done very late in the ++ * allocation procedure; if something failed before the mapping, the bp ++ * was not configured, therefore we don't need the below instructions ++ */ ++ if (!bp) ++ return; ++ ++ if (!atomic_dec_and_test(&bp->refs)) ++ return; ++ ++ if (bp->free_buf_cb) ++ dpa_bp_drain(bp); ++ ++ dpa_bp_array[bp->bpid] = NULL; ++ bman_free_pool(bp->pool); ++ ++ if (bp->dev) ++ platform_device_unregister(to_platform_device(bp->dev)); ++} ++ ++void __cold __attribute__((nonnull)) ++dpa_bp_free(struct dpa_priv_s *priv) ++{ ++ int i; ++ ++ if (priv->dpa_bp) ++ for (i = 0; i < priv->bp_count; i++) ++ _dpa_bp_free(&priv->dpa_bp[i]); ++} ++EXPORT_SYMBOL(dpa_bp_free); ++ ++struct dpa_bp *dpa_bpid2pool(int bpid) ++{ ++ return dpa_bp_array[bpid]; ++} ++EXPORT_SYMBOL(dpa_bpid2pool); ++ ++void dpa_bpid2pool_map(int bpid, struct dpa_bp *dpa_bp) ++{ ++ dpa_bp_array[bpid] = dpa_bp; ++ atomic_set(&dpa_bp->refs, 1); ++} ++ ++bool dpa_bpid2pool_use(int bpid) ++{ ++ if (dpa_bpid2pool(bpid)) { ++ atomic_inc(&dpa_bp_array[bpid]->refs); ++ return true; ++ } ++ ++ return false; ++} ++ ++#ifdef CONFIG_FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE ++u16 dpa_select_queue(struct net_device *net_dev, struct sk_buff *skb, ++ void *accel_priv, select_queue_fallback_t fallback) ++{ ++ return dpa_get_queue_mapping(skb); ++} ++EXPORT_SYMBOL(dpa_select_queue); ++#endif ++ ++struct dpa_fq *dpa_fq_alloc(struct device *dev, ++ u32 fq_start, ++ u32 fq_count, ++ struct list_head *list, ++ enum dpa_fq_type fq_type) ++{ ++ int i; ++ struct dpa_fq *dpa_fq; ++ ++ dpa_fq = devm_kzalloc(dev, sizeof(*dpa_fq) * fq_count, GFP_KERNEL); ++ if (dpa_fq == NULL) ++ return NULL; ++ ++ for (i = 0; i < fq_count; i++) { ++ dpa_fq[i].fq_type = fq_type; ++ if (fq_type == FQ_TYPE_RX_PCD_HI_PRIO) ++ dpa_fq[i].fqid = fq_start ? ++ DPAA_ETH_FQ_DELTA + fq_start + i : 0; ++ else ++ dpa_fq[i].fqid = fq_start ? fq_start + i : 0; ++ ++ list_add_tail(&dpa_fq[i].list, list); ++ } ++ ++#ifdef CONFIG_FMAN_PFC ++ if (fq_type == FQ_TYPE_TX) ++ for (i = 0; i < fq_count; i++) ++ dpa_fq[i].wq = i / dpa_num_cpus; ++ else ++#endif ++ for (i = 0; i < fq_count; i++) ++ _dpa_assign_wq(dpa_fq + i); ++ ++ return dpa_fq; ++} ++EXPORT_SYMBOL(dpa_fq_alloc); ++ ++/* Probing of FQs for MACful ports */ ++int dpa_fq_probe_mac(struct device *dev, struct list_head *list, ++ struct fm_port_fqs *port_fqs, ++ bool alloc_tx_conf_fqs, ++ enum port_type ptype) ++{ ++ struct fqid_cell *fqids = NULL; ++ const void *fqids_off = NULL; ++ struct dpa_fq *dpa_fq = NULL; ++ struct device_node *np = dev->of_node; ++ int num_ranges; ++ int i, lenp; ++ ++ if (ptype == TX && alloc_tx_conf_fqs) { ++ if (!dpa_fq_alloc(dev, tx_confirm_fqids->start, ++ tx_confirm_fqids->count, list, ++ FQ_TYPE_TX_CONF_MQ)) ++ goto fq_alloc_failed; ++ } ++ ++ fqids_off = of_get_property(np, fsl_qman_frame_queues[ptype], &lenp); ++ if (fqids_off == NULL) { ++ /* No dts definition, so use the defaults. */ ++ fqids = default_fqids[ptype]; ++ num_ranges = 3; ++ } else { ++ num_ranges = lenp / sizeof(*fqids); ++ ++ fqids = devm_kzalloc(dev, sizeof(*fqids) * num_ranges, ++ GFP_KERNEL); ++ if (fqids == NULL) ++ goto fqids_alloc_failed; ++ ++ /* convert to CPU endianess */ ++ for (i = 0; i < num_ranges; i++) { ++ fqids[i].start = be32_to_cpup(fqids_off + ++ i * sizeof(*fqids)); ++ fqids[i].count = be32_to_cpup(fqids_off + ++ i * sizeof(*fqids) + sizeof(__be32)); ++ } ++ } ++ ++ for (i = 0; i < num_ranges; i++) { ++ switch (i) { ++ case 0: ++ /* The first queue is the error queue */ ++ if (fqids[i].count != 1) ++ goto invalid_error_queue; ++ ++ dpa_fq = dpa_fq_alloc(dev, fqids[i].start, ++ fqids[i].count, list, ++ ptype == RX ? ++ FQ_TYPE_RX_ERROR : ++ FQ_TYPE_TX_ERROR); ++ if (dpa_fq == NULL) ++ goto fq_alloc_failed; ++ ++ if (ptype == RX) ++ port_fqs->rx_errq = &dpa_fq[0]; ++ else ++ port_fqs->tx_errq = &dpa_fq[0]; ++ break; ++ case 1: ++ /* the second queue is the default queue */ ++ if (fqids[i].count != 1) ++ goto invalid_default_queue; ++ ++ dpa_fq = dpa_fq_alloc(dev, fqids[i].start, ++ fqids[i].count, list, ++ ptype == RX ? ++ FQ_TYPE_RX_DEFAULT : ++ FQ_TYPE_TX_CONFIRM); ++ if (dpa_fq == NULL) ++ goto fq_alloc_failed; ++ ++ if (ptype == RX) ++ port_fqs->rx_defq = &dpa_fq[0]; ++ else ++ port_fqs->tx_defq = &dpa_fq[0]; ++ break; ++ default: ++ /* all subsequent queues are either RX* PCD or Tx */ ++ if (ptype == RX) { ++ if (!dpa_fq_alloc(dev, fqids[i].start, ++ fqids[i].count, list, ++ FQ_TYPE_RX_PCD) || ++ !dpa_fq_alloc(dev, fqids[i].start, ++ fqids[i].count, list, ++ FQ_TYPE_RX_PCD_HI_PRIO)) ++ goto fq_alloc_failed; ++ } else { ++ if (!dpa_fq_alloc(dev, fqids[i].start, ++ fqids[i].count, list, ++ FQ_TYPE_TX)) ++ goto fq_alloc_failed; ++ } ++ break; ++ } ++ } ++ ++ return 0; ++ ++fq_alloc_failed: ++fqids_alloc_failed: ++ dev_err(dev, "Cannot allocate memory for frame queues\n"); ++ return -ENOMEM; ++ ++invalid_default_queue: ++invalid_error_queue: ++ dev_err(dev, "Too many default or error queues\n"); ++ return -EINVAL; ++} ++EXPORT_SYMBOL(dpa_fq_probe_mac); ++ ++static u32 rx_pool_channel; ++static DEFINE_SPINLOCK(rx_pool_channel_init); ++ ++int dpa_get_channel(void) ++{ ++ spin_lock(&rx_pool_channel_init); ++ if (!rx_pool_channel) { ++ u32 pool; ++ int ret = qman_alloc_pool(&pool); ++ if (!ret) ++ rx_pool_channel = pool; ++ } ++ spin_unlock(&rx_pool_channel_init); ++ if (!rx_pool_channel) ++ return -ENOMEM; ++ return rx_pool_channel; ++} ++EXPORT_SYMBOL(dpa_get_channel); ++ ++void dpa_release_channel(void) ++{ ++ qman_release_pool(rx_pool_channel); ++} ++EXPORT_SYMBOL(dpa_release_channel); ++ ++void dpaa_eth_add_channel(u16 channel) ++{ ++ const cpumask_t *cpus = qman_affine_cpus(); ++ u32 pool = QM_SDQCR_CHANNELS_POOL_CONV(channel); ++ int cpu; ++ struct qman_portal *portal; ++ ++ for_each_cpu(cpu, cpus) { ++ portal = (struct qman_portal *)qman_get_affine_portal(cpu); ++ qman_p_static_dequeue_add(portal, pool); ++ } ++} ++EXPORT_SYMBOL(dpaa_eth_add_channel); ++ ++/** ++ * Congestion group state change notification callback. ++ * Stops the device's egress queues while they are congested and ++ * wakes them upon exiting congested state. ++ * Also updates some CGR-related stats. ++ */ ++static void dpaa_eth_cgscn(struct qman_portal *qm, struct qman_cgr *cgr, ++ ++ int congested) ++{ ++ struct dpa_priv_s *priv = (struct dpa_priv_s *)container_of(cgr, ++ struct dpa_priv_s, cgr_data.cgr); ++ ++ if (congested) { ++ priv->cgr_data.congestion_start_jiffies = jiffies; ++ netif_tx_stop_all_queues(priv->net_dev); ++ priv->cgr_data.cgr_congested_count++; ++ } else { ++ priv->cgr_data.congested_jiffies += ++ (jiffies - priv->cgr_data.congestion_start_jiffies); ++ netif_tx_wake_all_queues(priv->net_dev); ++ } ++} ++ ++int dpaa_eth_cgr_init(struct dpa_priv_s *priv) ++{ ++ struct qm_mcc_initcgr initcgr; ++ u32 cs_th; ++ int err; ++ ++ err = qman_alloc_cgrid(&priv->cgr_data.cgr.cgrid); ++ if (err < 0) { ++ pr_err("Error %d allocating CGR ID\n", err); ++ goto out_error; ++ } ++ priv->cgr_data.cgr.cb = dpaa_eth_cgscn; ++ ++ /* Enable Congestion State Change Notifications and CS taildrop */ ++ initcgr.we_mask = QM_CGR_WE_CSCN_EN | QM_CGR_WE_CS_THRES; ++ initcgr.cgr.cscn_en = QM_CGR_EN; ++ ++ /* Set different thresholds based on the MAC speed. ++ * TODO: this may turn suboptimal if the MAC is reconfigured at a speed ++ * lower than its max, e.g. if a dTSEC later negotiates a 100Mbps link. ++ * In such cases, we ought to reconfigure the threshold, too. ++ */ ++ if (priv->mac_dev->if_support & SUPPORTED_10000baseT_Full) ++ cs_th = CONFIG_FSL_DPAA_CS_THRESHOLD_10G; ++ else ++ cs_th = CONFIG_FSL_DPAA_CS_THRESHOLD_1G; ++ qm_cgr_cs_thres_set64(&initcgr.cgr.cs_thres, cs_th, 1); ++ ++ initcgr.we_mask |= QM_CGR_WE_CSTD_EN; ++ initcgr.cgr.cstd_en = QM_CGR_EN; ++ ++ err = qman_create_cgr(&priv->cgr_data.cgr, QMAN_CGR_FLAG_USE_INIT, ++ &initcgr); ++ if (err < 0) { ++ pr_err("Error %d creating CGR with ID %d\n", err, ++ priv->cgr_data.cgr.cgrid); ++ qman_release_cgrid(priv->cgr_data.cgr.cgrid); ++ goto out_error; ++ } ++ pr_debug("Created CGR %d for netdev with hwaddr %pM on QMan channel %d\n", ++ priv->cgr_data.cgr.cgrid, priv->mac_dev->addr, ++ priv->cgr_data.cgr.chan); ++ ++out_error: ++ return err; ++} ++EXPORT_SYMBOL(dpaa_eth_cgr_init); ++ ++static inline void dpa_setup_ingress(const struct dpa_priv_s *priv, ++ struct dpa_fq *fq, ++ const struct qman_fq *template) ++{ ++ fq->fq_base = *template; ++ fq->net_dev = priv->net_dev; ++ ++ fq->flags = QMAN_FQ_FLAG_NO_ENQUEUE; ++ fq->channel = priv->channel; ++} ++ ++static inline void dpa_setup_egress(const struct dpa_priv_s *priv, ++ struct dpa_fq *fq, ++ struct fm_port *port, ++ const struct qman_fq *template) ++{ ++ fq->fq_base = *template; ++ fq->net_dev = priv->net_dev; ++ ++ if (port) { ++ fq->flags = QMAN_FQ_FLAG_TO_DCPORTAL; ++ fq->channel = (uint16_t)fm_get_tx_port_channel(port); ++ } else { ++ fq->flags = QMAN_FQ_FLAG_NO_MODIFY; ++ } ++} ++ ++void dpa_fq_setup(struct dpa_priv_s *priv, const struct dpa_fq_cbs_t *fq_cbs, ++ struct fm_port *tx_port) ++{ ++ struct dpa_fq *fq; ++ uint16_t portals[NR_CPUS]; ++ int cpu, portal_cnt = 0, num_portals = 0; ++ uint32_t pcd_fqid, pcd_fqid_hi_prio; ++ const cpumask_t *affine_cpus = qman_affine_cpus(); ++ int egress_cnt = 0, conf_cnt = 0; ++ ++ /* Prepare for PCD FQs init */ ++ for_each_cpu(cpu, affine_cpus) ++ portals[num_portals++] = qman_affine_channel(cpu); ++ if (num_portals == 0) ++ dev_err(priv->net_dev->dev.parent, ++ "No Qman software (affine) channels found"); ++ ++ pcd_fqid = (priv->mac_dev) ? ++ DPAA_ETH_PCD_FQ_BASE(priv->mac_dev->res->start) : 0; ++ pcd_fqid_hi_prio = (priv->mac_dev) ? ++ DPAA_ETH_PCD_FQ_HI_PRIO_BASE(priv->mac_dev->res->start) : 0; ++ ++ /* Initialize each FQ in the list */ ++ list_for_each_entry(fq, &priv->dpa_fq_list, list) { ++ switch (fq->fq_type) { ++ case FQ_TYPE_RX_DEFAULT: ++ BUG_ON(!priv->mac_dev); ++ dpa_setup_ingress(priv, fq, &fq_cbs->rx_defq); ++ break; ++ case FQ_TYPE_RX_ERROR: ++ BUG_ON(!priv->mac_dev); ++ dpa_setup_ingress(priv, fq, &fq_cbs->rx_errq); ++ break; ++ case FQ_TYPE_RX_PCD: ++ /* For MACless we can't have dynamic Rx queues */ ++ BUG_ON(!priv->mac_dev && !fq->fqid); ++ dpa_setup_ingress(priv, fq, &fq_cbs->rx_defq); ++ if (!fq->fqid) ++ fq->fqid = pcd_fqid++; ++ fq->channel = portals[portal_cnt]; ++ portal_cnt = (portal_cnt + 1) % num_portals; ++ break; ++ case FQ_TYPE_RX_PCD_HI_PRIO: ++ /* For MACless we can't have dynamic Hi Pri Rx queues */ ++ BUG_ON(!priv->mac_dev && !fq->fqid); ++ dpa_setup_ingress(priv, fq, &fq_cbs->rx_defq); ++ if (!fq->fqid) ++ fq->fqid = pcd_fqid_hi_prio++; ++ fq->channel = portals[portal_cnt]; ++ portal_cnt = (portal_cnt + 1) % num_portals; ++ break; ++ case FQ_TYPE_TX: ++ dpa_setup_egress(priv, fq, tx_port, ++ &fq_cbs->egress_ern); ++ /* If we have more Tx queues than the number of cores, ++ * just ignore the extra ones. ++ */ ++ if (egress_cnt < DPAA_ETH_TX_QUEUES) ++ priv->egress_fqs[egress_cnt++] = &fq->fq_base; ++ break; ++ case FQ_TYPE_TX_CONFIRM: ++ BUG_ON(!priv->mac_dev); ++ dpa_setup_ingress(priv, fq, &fq_cbs->tx_defq); ++ break; ++ case FQ_TYPE_TX_CONF_MQ: ++ BUG_ON(!priv->mac_dev); ++ dpa_setup_ingress(priv, fq, &fq_cbs->tx_defq); ++ priv->conf_fqs[conf_cnt++] = &fq->fq_base; ++ break; ++ case FQ_TYPE_TX_ERROR: ++ BUG_ON(!priv->mac_dev); ++ dpa_setup_ingress(priv, fq, &fq_cbs->tx_errq); ++ break; ++ default: ++ dev_warn(priv->net_dev->dev.parent, ++ "Unknown FQ type detected!\n"); ++ break; ++ } ++ } ++ ++ /* The number of Tx queues may be smaller than the number of cores, if ++ * the Tx queue range is specified in the device tree instead of being ++ * dynamically allocated. ++ * Make sure all CPUs receive a corresponding Tx queue. ++ */ ++ while (egress_cnt < DPAA_ETH_TX_QUEUES) { ++ list_for_each_entry(fq, &priv->dpa_fq_list, list) { ++ if (fq->fq_type != FQ_TYPE_TX) ++ continue; ++ priv->egress_fqs[egress_cnt++] = &fq->fq_base; ++ if (egress_cnt == DPAA_ETH_TX_QUEUES) ++ break; ++ } ++ } ++} ++EXPORT_SYMBOL(dpa_fq_setup); ++ ++int dpa_fq_init(struct dpa_fq *dpa_fq, bool td_enable) ++{ ++ int _errno; ++ const struct dpa_priv_s *priv; ++ struct device *dev; ++ struct qman_fq *fq; ++ struct qm_mcc_initfq initfq; ++ struct qman_fq *confq; ++ int queue_id; ++ ++ priv = netdev_priv(dpa_fq->net_dev); ++ dev = dpa_fq->net_dev->dev.parent; ++ ++ if (dpa_fq->fqid == 0) ++ dpa_fq->flags |= QMAN_FQ_FLAG_DYNAMIC_FQID; ++ ++ dpa_fq->init = !(dpa_fq->flags & QMAN_FQ_FLAG_NO_MODIFY); ++ ++ _errno = qman_create_fq(dpa_fq->fqid, dpa_fq->flags, &dpa_fq->fq_base); ++ if (_errno) { ++ dev_err(dev, "qman_create_fq() failed\n"); ++ return _errno; ++ } ++ fq = &dpa_fq->fq_base; ++ ++ if (dpa_fq->init) { ++ memset(&initfq, 0, sizeof(initfq)); ++ ++ initfq.we_mask = QM_INITFQ_WE_FQCTRL; ++ /* FIXME: why would we want to keep an empty FQ in cache? */ ++ initfq.fqd.fq_ctrl = QM_FQCTRL_PREFERINCACHE; ++ ++ /* Try to reduce the number of portal interrupts for ++ * Tx Confirmation FQs. ++ */ ++ if (dpa_fq->fq_type == FQ_TYPE_TX_CONFIRM) ++ initfq.fqd.fq_ctrl |= QM_FQCTRL_HOLDACTIVE; ++ ++ /* FQ placement */ ++ initfq.we_mask |= QM_INITFQ_WE_DESTWQ; ++ ++ initfq.fqd.dest.channel = dpa_fq->channel; ++ initfq.fqd.dest.wq = dpa_fq->wq; ++ ++ /* Put all egress queues in a congestion group of their own. ++ * Sensu stricto, the Tx confirmation queues are Rx FQs, ++ * rather than Tx - but they nonetheless account for the ++ * memory footprint on behalf of egress traffic. We therefore ++ * place them in the netdev's CGR, along with the Tx FQs. ++ */ ++ if (dpa_fq->fq_type == FQ_TYPE_TX || ++ dpa_fq->fq_type == FQ_TYPE_TX_CONFIRM || ++ dpa_fq->fq_type == FQ_TYPE_TX_CONF_MQ) { ++ initfq.we_mask |= QM_INITFQ_WE_CGID; ++ initfq.fqd.fq_ctrl |= QM_FQCTRL_CGE; ++ initfq.fqd.cgid = (uint8_t)priv->cgr_data.cgr.cgrid; ++ /* Set a fixed overhead accounting, in an attempt to ++ * reduce the impact of fixed-size skb shells and the ++ * driver's needed headroom on system memory. This is ++ * especially the case when the egress traffic is ++ * composed of small datagrams. ++ * Unfortunately, QMan's OAL value is capped to an ++ * insufficient value, but even that is better than ++ * no overhead accounting at all. ++ */ ++ initfq.we_mask |= QM_INITFQ_WE_OAC; ++ initfq.fqd.oac_init.oac = QM_OAC_CG; ++ initfq.fqd.oac_init.oal = ++ (signed char)(min(sizeof(struct sk_buff) + ++ priv->tx_headroom, (size_t)FSL_QMAN_MAX_OAL)); ++ } ++ ++ if (td_enable) { ++ initfq.we_mask |= QM_INITFQ_WE_TDTHRESH; ++ qm_fqd_taildrop_set(&initfq.fqd.td, ++ DPA_FQ_TD, 1); ++ initfq.fqd.fq_ctrl = QM_FQCTRL_TDE; ++ } ++ ++ /* Configure the Tx confirmation queue, now that we know ++ * which Tx queue it pairs with. ++ */ ++ if (dpa_fq->fq_type == FQ_TYPE_TX) { ++ queue_id = _dpa_tx_fq_to_id(priv, &dpa_fq->fq_base); ++ if (queue_id >= 0) { ++ confq = priv->conf_fqs[queue_id]; ++ if (confq) { ++ initfq.we_mask |= QM_INITFQ_WE_CONTEXTA; ++ /* ContextA: OVOM=1 (use contextA2 bits instead of ICAD) ++ * A2V=1 (contextA A2 field is valid) ++ * A0V=1 (contextA A0 field is valid) ++ * B0V=1 (contextB field is valid) ++ * ContextA A2: EBD=1 (deallocate buffers inside FMan) ++ * ContextB B0(ASPID): 0 (absolute Virtual Storage ID) ++ */ ++ initfq.fqd.context_a.hi = 0x1e000000; ++ initfq.fqd.context_a.lo = 0x80000000; ++ } ++ } ++ } ++ ++ /* Put all *private* ingress queues in our "ingress CGR". */ ++ if (priv->use_ingress_cgr && ++ (dpa_fq->fq_type == FQ_TYPE_RX_DEFAULT || ++ dpa_fq->fq_type == FQ_TYPE_RX_ERROR || ++ dpa_fq->fq_type == FQ_TYPE_RX_PCD || ++ dpa_fq->fq_type == FQ_TYPE_RX_PCD_HI_PRIO)) { ++ initfq.we_mask |= QM_INITFQ_WE_CGID; ++ initfq.fqd.fq_ctrl |= QM_FQCTRL_CGE; ++ initfq.fqd.cgid = (uint8_t)priv->ingress_cgr.cgrid; ++ /* Set a fixed overhead accounting, just like for the ++ * egress CGR. ++ */ ++ initfq.we_mask |= QM_INITFQ_WE_OAC; ++ initfq.fqd.oac_init.oac = QM_OAC_CG; ++ initfq.fqd.oac_init.oal = ++ (signed char)(min(sizeof(struct sk_buff) + ++ priv->tx_headroom, (size_t)FSL_QMAN_MAX_OAL)); ++ } ++ ++ /* Initialization common to all ingress queues */ ++ if (dpa_fq->flags & QMAN_FQ_FLAG_NO_ENQUEUE) { ++ initfq.we_mask |= QM_INITFQ_WE_CONTEXTA; ++ initfq.fqd.fq_ctrl |= ++ QM_FQCTRL_CTXASTASHING | QM_FQCTRL_AVOIDBLOCK; ++ initfq.fqd.context_a.stashing.exclusive = ++ QM_STASHING_EXCL_DATA | QM_STASHING_EXCL_CTX | ++ QM_STASHING_EXCL_ANNOTATION; ++ initfq.fqd.context_a.stashing.data_cl = 2; ++ initfq.fqd.context_a.stashing.annotation_cl = 1; ++ initfq.fqd.context_a.stashing.context_cl = ++ DIV_ROUND_UP(sizeof(struct qman_fq), 64); ++ } ++ ++ _errno = qman_init_fq(fq, QMAN_INITFQ_FLAG_SCHED, &initfq); ++ if (_errno < 0) { ++ if (DPA_RX_PCD_HI_PRIO_FQ_INIT_FAIL(dpa_fq, _errno)) { ++ dpa_fq->init = 0; ++ } else { ++ dev_err(dev, "qman_init_fq(%u) = %d\n", ++ qman_fq_fqid(fq), _errno); ++ qman_destroy_fq(fq, 0); ++ } ++ return _errno; ++ } ++ } ++ ++ dpa_fq->fqid = qman_fq_fqid(fq); ++ ++ return 0; ++} ++EXPORT_SYMBOL(dpa_fq_init); ++ ++int __cold __attribute__((nonnull)) ++_dpa_fq_free(struct device *dev, struct qman_fq *fq) ++{ ++ int _errno, __errno; ++ struct dpa_fq *dpa_fq; ++ const struct dpa_priv_s *priv; ++ ++ _errno = 0; ++ ++ dpa_fq = container_of(fq, struct dpa_fq, fq_base); ++ priv = netdev_priv(dpa_fq->net_dev); ++ ++ if (dpa_fq->init) { ++ _errno = qman_retire_fq(fq, NULL); ++ if (unlikely(_errno < 0) && netif_msg_drv(priv)) ++ dev_err(dev, "qman_retire_fq(%u) = %d\n", ++ qman_fq_fqid(fq), _errno); ++ ++ __errno = qman_oos_fq(fq); ++ if (unlikely(__errno < 0) && netif_msg_drv(priv)) { ++ dev_err(dev, "qman_oos_fq(%u) = %d\n", ++ qman_fq_fqid(fq), __errno); ++ if (_errno >= 0) ++ _errno = __errno; ++ } ++ } ++ ++ qman_destroy_fq(fq, 0); ++ list_del(&dpa_fq->list); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(_dpa_fq_free); ++ ++int __cold __attribute__((nonnull)) ++dpa_fq_free(struct device *dev, struct list_head *list) ++{ ++ int _errno, __errno; ++ struct dpa_fq *dpa_fq, *tmp; ++ ++ _errno = 0; ++ list_for_each_entry_safe(dpa_fq, tmp, list, list) { ++ __errno = _dpa_fq_free(dev, (struct qman_fq *)dpa_fq); ++ if (unlikely(__errno < 0) && _errno >= 0) ++ _errno = __errno; ++ } ++ ++ return _errno; ++} ++EXPORT_SYMBOL(dpa_fq_free); ++ ++int dpa_fqs_init(struct device *dev, struct list_head *list, bool td_enable) ++{ ++ int _errno, __errno; ++ struct dpa_fq *dpa_fq, *tmp; ++ static bool print_msg __read_mostly; ++ ++ _errno = 0; ++ print_msg = true; ++ list_for_each_entry_safe(dpa_fq, tmp, list, list) { ++ __errno = dpa_fq_init(dpa_fq, td_enable); ++ if (unlikely(__errno < 0) && _errno >= 0) { ++ if (DPA_RX_PCD_HI_PRIO_FQ_INIT_FAIL(dpa_fq, __errno)) { ++ if (print_msg) { ++ dev_warn(dev, ++ "Skip RX PCD High Priority FQs initialization\n"); ++ print_msg = false; ++ } ++ if (_dpa_fq_free(dev, (struct qman_fq *)dpa_fq)) ++ dev_warn(dev, ++ "Error freeing frame queues\n"); ++ } else { ++ _errno = __errno; ++ break; ++ } ++ } ++ } ++ ++ return _errno; ++} ++EXPORT_SYMBOL(dpa_fqs_init); ++static void ++dpaa_eth_init_tx_port(struct fm_port *port, struct dpa_fq *errq, ++ struct dpa_fq *defq, struct dpa_buffer_layout_s *buf_layout) ++{ ++ struct fm_port_params tx_port_param; ++ bool frag_enabled = false; ++ ++ memset(&tx_port_param, 0, sizeof(tx_port_param)); ++ dpaa_eth_init_port(tx, port, tx_port_param, errq->fqid, defq->fqid, ++ buf_layout, frag_enabled); ++} ++ ++static void ++dpaa_eth_init_rx_port(struct fm_port *port, struct dpa_bp *bp, size_t count, ++ struct dpa_fq *errq, struct dpa_fq *defq, ++ struct dpa_buffer_layout_s *buf_layout) ++{ ++ struct fm_port_params rx_port_param; ++ int i; ++ bool frag_enabled = false; ++ ++ memset(&rx_port_param, 0, sizeof(rx_port_param)); ++ count = min(ARRAY_SIZE(rx_port_param.pool_param), count); ++ rx_port_param.num_pools = (uint8_t)count; ++ for (i = 0; i < count; i++) { ++ if (i >= rx_port_param.num_pools) ++ break; ++ rx_port_param.pool_param[i].id = bp[i].bpid; ++ rx_port_param.pool_param[i].size = (uint16_t)bp[i].size; ++ } ++ ++ dpaa_eth_init_port(rx, port, rx_port_param, errq->fqid, defq->fqid, ++ buf_layout, frag_enabled); ++} ++ ++#if defined(CONFIG_FSL_SDK_FMAN_TEST) ++/* Defined as weak, to be implemented by fman pcd tester. */ ++int dpa_alloc_pcd_fqids(struct device *, uint32_t, uint8_t, uint32_t *) ++__attribute__((weak)); ++ ++int dpa_free_pcd_fqids(struct device *, uint32_t) __attribute__((weak)); ++#else ++int dpa_alloc_pcd_fqids(struct device *, uint32_t, uint8_t, uint32_t *); ++ ++int dpa_free_pcd_fqids(struct device *, uint32_t); ++ ++#endif /* CONFIG_FSL_SDK_FMAN_TEST */ ++ ++ ++int dpa_alloc_pcd_fqids(struct device *dev, uint32_t num, ++ uint8_t alignment, uint32_t *base_fqid) ++{ ++ dev_crit(dev, "callback not implemented!\n"); ++ ++ return 0; ++} ++ ++int dpa_free_pcd_fqids(struct device *dev, uint32_t base_fqid) ++{ ++ ++ dev_crit(dev, "callback not implemented!\n"); ++ ++ return 0; ++} ++ ++void dpaa_eth_init_ports(struct mac_device *mac_dev, ++ struct dpa_bp *bp, size_t count, ++ struct fm_port_fqs *port_fqs, ++ struct dpa_buffer_layout_s *buf_layout, ++ struct device *dev) ++{ ++ struct fm_port_pcd_param rx_port_pcd_param; ++ struct fm_port *rxport = mac_dev->port_dev[RX]; ++ struct fm_port *txport = mac_dev->port_dev[TX]; ++ ++ dpaa_eth_init_tx_port(txport, port_fqs->tx_errq, ++ port_fqs->tx_defq, &buf_layout[TX]); ++ dpaa_eth_init_rx_port(rxport, bp, count, port_fqs->rx_errq, ++ port_fqs->rx_defq, &buf_layout[RX]); ++ ++ rx_port_pcd_param.cba = dpa_alloc_pcd_fqids; ++ rx_port_pcd_param.cbf = dpa_free_pcd_fqids; ++ rx_port_pcd_param.dev = dev; ++ fm_port_pcd_bind(rxport, &rx_port_pcd_param); ++} ++EXPORT_SYMBOL(dpaa_eth_init_ports); ++ ++void dpa_release_sgt(struct qm_sg_entry *sgt) ++{ ++ struct dpa_bp *dpa_bp; ++ struct bm_buffer bmb[DPA_BUFF_RELEASE_MAX]; ++ uint8_t i = 0, j; ++ ++ memset(bmb, 0, DPA_BUFF_RELEASE_MAX * sizeof(struct bm_buffer)); ++ ++ do { ++ dpa_bp = dpa_bpid2pool(qm_sg_entry_get_bpid(&sgt[i])); ++ DPA_BUG_ON(!dpa_bp); ++ ++ j = 0; ++ do { ++ DPA_BUG_ON(qm_sg_entry_get_ext(&sgt[i])); ++ bm_buffer_set64(&bmb[j], qm_sg_addr(&sgt[i])); ++ ++ j++; i++; ++ } while (j < ARRAY_SIZE(bmb) && ++ !qm_sg_entry_get_final(&sgt[i-1]) && ++ qm_sg_entry_get_bpid(&sgt[i-1]) == ++ qm_sg_entry_get_bpid(&sgt[i])); ++ ++ while (bman_release(dpa_bp->pool, bmb, j, 0)) ++ cpu_relax(); ++ } while (!qm_sg_entry_get_final(&sgt[i-1])); ++} ++EXPORT_SYMBOL(dpa_release_sgt); ++ ++void __attribute__((nonnull)) ++dpa_fd_release(const struct net_device *net_dev, const struct qm_fd *fd) ++{ ++ struct qm_sg_entry *sgt; ++ struct dpa_bp *dpa_bp; ++ struct bm_buffer bmb; ++ dma_addr_t addr; ++ void *vaddr; ++ ++ bmb.opaque = 0; ++ bm_buffer_set64(&bmb, qm_fd_addr(fd)); ++ ++ dpa_bp = dpa_bpid2pool(fd->bpid); ++ DPA_BUG_ON(!dpa_bp); ++ ++ if (fd->format == qm_fd_sg) { ++ vaddr = phys_to_virt(qm_fd_addr(fd)); ++ sgt = vaddr + dpa_fd_offset(fd); ++ ++ dma_unmap_single(dpa_bp->dev, qm_fd_addr(fd), dpa_bp->size, ++ DMA_BIDIRECTIONAL); ++ ++ dpa_release_sgt(sgt); ++ addr = dma_map_single(dpa_bp->dev, vaddr, dpa_bp->size, ++ DMA_BIDIRECTIONAL); ++ if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) { ++ dev_err(dpa_bp->dev, "DMA mapping failed"); ++ return; ++ } ++ bm_buffer_set64(&bmb, addr); ++ } ++ ++ while (bman_release(dpa_bp->pool, &bmb, 1, 0)) ++ cpu_relax(); ++} ++EXPORT_SYMBOL(dpa_fd_release); ++ ++void count_ern(struct dpa_percpu_priv_s *percpu_priv, ++ const struct qm_mr_entry *msg) ++{ ++ switch (msg->ern.rc & QM_MR_RC_MASK) { ++ case QM_MR_RC_CGR_TAILDROP: ++ percpu_priv->ern_cnt.cg_tdrop++; ++ break; ++ case QM_MR_RC_WRED: ++ percpu_priv->ern_cnt.wred++; ++ break; ++ case QM_MR_RC_ERROR: ++ percpu_priv->ern_cnt.err_cond++; ++ break; ++ case QM_MR_RC_ORPWINDOW_EARLY: ++ percpu_priv->ern_cnt.early_window++; ++ break; ++ case QM_MR_RC_ORPWINDOW_LATE: ++ percpu_priv->ern_cnt.late_window++; ++ break; ++ case QM_MR_RC_FQ_TAILDROP: ++ percpu_priv->ern_cnt.fq_tdrop++; ++ break; ++ case QM_MR_RC_ORPWINDOW_RETIRED: ++ percpu_priv->ern_cnt.fq_retired++; ++ break; ++ case QM_MR_RC_ORP_ZERO: ++ percpu_priv->ern_cnt.orp_zero++; ++ break; ++ } ++} ++EXPORT_SYMBOL(count_ern); ++ ++/** ++ * Turn on HW checksum computation for this outgoing frame. ++ * If the current protocol is not something we support in this regard ++ * (or if the stack has already computed the SW checksum), we do nothing. ++ * ++ * Returns 0 if all goes well (or HW csum doesn't apply), and a negative value ++ * otherwise. ++ * ++ * Note that this function may modify the fd->cmd field and the skb data buffer ++ * (the Parse Results area). ++ */ ++int dpa_enable_tx_csum(struct dpa_priv_s *priv, ++ struct sk_buff *skb, struct qm_fd *fd, char *parse_results) ++{ ++ fm_prs_result_t *parse_result; ++ struct iphdr *iph; ++ struct ipv6hdr *ipv6h = NULL; ++ u8 l4_proto; ++ u16 ethertype = ntohs(skb->protocol); ++ int retval = 0; ++ ++ if (skb->ip_summed != CHECKSUM_PARTIAL) ++ return 0; ++ ++ /* Note: L3 csum seems to be already computed in sw, but we can't choose ++ * L4 alone from the FM configuration anyway. ++ */ ++ ++ /* Fill in some fields of the Parse Results array, so the FMan ++ * can find them as if they came from the FMan Parser. ++ */ ++ parse_result = (fm_prs_result_t *)parse_results; ++ ++ /* If we're dealing with VLAN, get the real Ethernet type */ ++ if (ethertype == ETH_P_8021Q) { ++ /* We can't always assume the MAC header is set correctly ++ * by the stack, so reset to beginning of skb->data ++ */ ++ skb_reset_mac_header(skb); ++ ethertype = ntohs(vlan_eth_hdr(skb)->h_vlan_encapsulated_proto); ++ } ++ ++ /* Fill in the relevant L3 parse result fields ++ * and read the L4 protocol type ++ */ ++ switch (ethertype) { ++ case ETH_P_IP: ++ parse_result->l3r = cpu_to_be16(FM_L3_PARSE_RESULT_IPV4); ++ iph = ip_hdr(skb); ++ DPA_BUG_ON(iph == NULL); ++ l4_proto = iph->protocol; ++ break; ++ case ETH_P_IPV6: ++ parse_result->l3r = cpu_to_be16(FM_L3_PARSE_RESULT_IPV6); ++ ipv6h = ipv6_hdr(skb); ++ DPA_BUG_ON(ipv6h == NULL); ++ l4_proto = ipv6h->nexthdr; ++ break; ++ default: ++ /* We shouldn't even be here */ ++ if (netif_msg_tx_err(priv) && net_ratelimit()) ++ netdev_alert(priv->net_dev, ++ "Can't compute HW csum for L3 proto 0x%x\n", ++ ntohs(skb->protocol)); ++ retval = -EIO; ++ goto return_error; ++ } ++ ++ /* Fill in the relevant L4 parse result fields */ ++ switch (l4_proto) { ++ case IPPROTO_UDP: ++ parse_result->l4r = FM_L4_PARSE_RESULT_UDP; ++ break; ++ case IPPROTO_TCP: ++ parse_result->l4r = FM_L4_PARSE_RESULT_TCP; ++ break; ++ default: ++ /* This can as well be a BUG() */ ++ if (netif_msg_tx_err(priv) && net_ratelimit()) ++ netdev_alert(priv->net_dev, ++ "Can't compute HW csum for L4 proto 0x%x\n", ++ l4_proto); ++ retval = -EIO; ++ goto return_error; ++ } ++ ++ /* At index 0 is IPOffset_1 as defined in the Parse Results */ ++ parse_result->ip_off[0] = (uint8_t)skb_network_offset(skb); ++ parse_result->l4_off = (uint8_t)skb_transport_offset(skb); ++ ++ /* Enable L3 (and L4, if TCP or UDP) HW checksum. */ ++ fd->cmd |= FM_FD_CMD_RPD | FM_FD_CMD_DTC; ++ ++ /* On P1023 and similar platforms fd->cmd interpretation could ++ * be disabled by setting CONTEXT_A bit ICMD; currently this bit ++ * is not set so we do not need to check; in the future, if/when ++ * using context_a we need to check this bit ++ */ ++ ++return_error: ++ return retval; ++} ++EXPORT_SYMBOL(dpa_enable_tx_csum); ++ ++#ifdef CONFIG_FSL_DPAA_CEETM ++void dpa_enable_ceetm(struct net_device *dev) ++{ ++ struct dpa_priv_s *priv = netdev_priv(dev); ++ priv->ceetm_en = true; ++} ++EXPORT_SYMBOL(dpa_enable_ceetm); ++ ++void dpa_disable_ceetm(struct net_device *dev) ++{ ++ struct dpa_priv_s *priv = netdev_priv(dev); ++ priv->ceetm_en = false; ++} ++EXPORT_SYMBOL(dpa_disable_ceetm); ++#endif +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h +new file mode 100644 +index 00000000..41db4302 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.h +@@ -0,0 +1,225 @@ ++/* Copyright 2008-2013 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __DPAA_ETH_COMMON_H ++#define __DPAA_ETH_COMMON_H ++ ++#include /* struct net_device */ ++#include /* struct bm_buffer */ ++#include /* struct platform_device */ ++#include /* struct hwtstamp_config */ ++ ++#include "dpaa_eth.h" ++#include "lnxwrp_fsl_fman.h" ++ ++#define dpaa_eth_init_port(type, port, param, errq_id, defq_id, buf_layout,\ ++ frag_enabled) \ ++{ \ ++ param.errq = errq_id; \ ++ param.defq = defq_id; \ ++ param.priv_data_size = buf_layout->priv_data_size; \ ++ param.parse_results = buf_layout->parse_results; \ ++ param.hash_results = buf_layout->hash_results; \ ++ param.frag_enable = frag_enabled; \ ++ param.time_stamp = buf_layout->time_stamp; \ ++ param.manip_extra_space = buf_layout->manip_extra_space; \ ++ param.data_align = buf_layout->data_align; \ ++ fm_set_##type##_port_params(port, ¶m); \ ++} ++ ++#define DPA_SGT_MAX_ENTRIES 16 /* maximum number of entries in SG Table */ ++ ++#define DPA_SGT_ENTRIES_THRESHOLD DPA_SGT_MAX_ENTRIES ++ ++#define DPA_BUFF_RELEASE_MAX 8 /* maximum number of buffers released at once */ ++ ++#define DPA_RX_PCD_HI_PRIO_FQ_INIT_FAIL(dpa_fq, _errno) \ ++ (((dpa_fq)->fq_type == FQ_TYPE_RX_PCD_HI_PRIO) && \ ++ (_errno == -EIO)) ++/* return codes for the dpaa-eth hooks */ ++enum dpaa_eth_hook_result { ++ /* fd/skb was retained by the hook. ++ * ++ * On the Rx path, this means the Ethernet driver will _not_ ++ * deliver the skb to the stack. Instead, the hook implementation ++ * is expected to properly dispose of the skb. ++ * ++ * On the Tx path, the Ethernet driver's dpa_tx() function will ++ * immediately return NETDEV_TX_OK. The hook implementation is expected ++ * to free the skb. *DO*NOT* release it to BMan, or enqueue it to FMan, ++ * unless you know exactly what you're doing! ++ * ++ * On the confirmation/error paths, the Ethernet driver will _not_ ++ * perform any fd cleanup, nor update the interface statistics. ++ */ ++ DPAA_ETH_STOLEN, ++ /* fd/skb was returned to the Ethernet driver for regular processing. ++ * The hook is not allowed to, for instance, reallocate the skb (as if ++ * by linearizing, copying, cloning or reallocating the headroom). ++ */ ++ DPAA_ETH_CONTINUE ++}; ++ ++typedef enum dpaa_eth_hook_result (*dpaa_eth_ingress_hook_t)( ++ struct sk_buff *skb, struct net_device *net_dev, u32 fqid); ++typedef enum dpaa_eth_hook_result (*dpaa_eth_egress_hook_t)( ++ struct sk_buff *skb, struct net_device *net_dev); ++typedef enum dpaa_eth_hook_result (*dpaa_eth_confirm_hook_t)( ++ struct net_device *net_dev, const struct qm_fd *fd, u32 fqid); ++ ++/* used in napi related functions */ ++extern u16 qman_portal_max; ++ ++/* from dpa_ethtool.c */ ++extern const struct ethtool_ops dpa_ethtool_ops; ++ ++#ifdef CONFIG_FSL_DPAA_HOOKS ++/* Various hooks used for unit-testing and/or fastpath optimizations. ++ * Currently only one set of such hooks is supported. ++ */ ++struct dpaa_eth_hooks_s { ++ /* Invoked on the Tx private path, immediately after receiving the skb ++ * from the stack. ++ */ ++ dpaa_eth_egress_hook_t tx; ++ ++ /* Invoked on the Rx private path, right before passing the skb ++ * up the stack. At that point, the packet's protocol id has already ++ * been set. The skb's data pointer is now at the L3 header, and ++ * skb->mac_header points to the L2 header. skb->len has been adjusted ++ * to be the length of L3+payload (i.e., the length of the ++ * original frame minus the L2 header len). ++ * For more details on what the skb looks like, see eth_type_trans(). ++ */ ++ dpaa_eth_ingress_hook_t rx_default; ++ ++ /* Driver hook for the Rx error private path. */ ++ dpaa_eth_confirm_hook_t rx_error; ++ /* Driver hook for the Tx confirmation private path. */ ++ dpaa_eth_confirm_hook_t tx_confirm; ++ /* Driver hook for the Tx error private path. */ ++ dpaa_eth_confirm_hook_t tx_error; ++}; ++ ++void fsl_dpaa_eth_set_hooks(struct dpaa_eth_hooks_s *hooks); ++ ++extern struct dpaa_eth_hooks_s dpaa_eth_hooks; ++#endif ++ ++int dpa_netdev_init(struct net_device *net_dev, ++ const uint8_t *mac_addr, ++ uint16_t tx_timeout); ++int __cold dpa_start(struct net_device *net_dev); ++int __cold dpa_stop(struct net_device *net_dev); ++void __cold dpa_timeout(struct net_device *net_dev); ++void __cold ++dpa_get_stats64(struct net_device *net_dev, ++ struct rtnl_link_stats64 *stats); ++int dpa_change_mtu(struct net_device *net_dev, int new_mtu); ++int dpa_ndo_init(struct net_device *net_dev); ++int dpa_set_features(struct net_device *dev, netdev_features_t features); ++netdev_features_t dpa_fix_features(struct net_device *dev, ++ netdev_features_t features); ++#ifdef CONFIG_FSL_DPAA_TS ++u64 dpa_get_timestamp_ns(const struct dpa_priv_s *priv, ++ enum port_type rx_tx, const void *data); ++/* Updates the skb shared hw timestamp from the hardware timestamp */ ++int dpa_get_ts(const struct dpa_priv_s *priv, enum port_type rx_tx, ++ struct skb_shared_hwtstamps *shhwtstamps, const void *data); ++#endif /* CONFIG_FSL_DPAA_TS */ ++int dpa_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); ++int __cold dpa_remove(struct platform_device *of_dev); ++struct mac_device * __cold __must_check ++__attribute__((nonnull)) dpa_mac_probe(struct platform_device *_of_dev); ++int dpa_set_mac_address(struct net_device *net_dev, void *addr); ++void dpa_set_rx_mode(struct net_device *net_dev); ++void dpa_set_buffers_layout(struct mac_device *mac_dev, ++ struct dpa_buffer_layout_s *layout); ++int __attribute__((nonnull)) ++dpa_bp_alloc(struct dpa_bp *dpa_bp); ++void __cold __attribute__((nonnull)) ++dpa_bp_free(struct dpa_priv_s *priv); ++struct dpa_bp *dpa_bpid2pool(int bpid); ++void dpa_bpid2pool_map(int bpid, struct dpa_bp *dpa_bp); ++bool dpa_bpid2pool_use(int bpid); ++void dpa_bp_drain(struct dpa_bp *bp); ++#ifdef CONFIG_FSL_DPAA_ETH_USE_NDO_SELECT_QUEUE ++u16 dpa_select_queue(struct net_device *net_dev, struct sk_buff *skb, ++ void *accel_priv, select_queue_fallback_t fallback); ++#endif ++struct dpa_fq *dpa_fq_alloc(struct device *dev, ++ u32 fq_start, ++ u32 fq_count, ++ struct list_head *list, ++ enum dpa_fq_type fq_type); ++int dpa_fq_probe_mac(struct device *dev, struct list_head *list, ++ struct fm_port_fqs *port_fqs, ++ bool tx_conf_fqs_per_core, ++ enum port_type ptype); ++int dpa_get_channel(void); ++void dpa_release_channel(void); ++void dpaa_eth_add_channel(u16 channel); ++int dpaa_eth_cgr_init(struct dpa_priv_s *priv); ++void dpa_fq_setup(struct dpa_priv_s *priv, const struct dpa_fq_cbs_t *fq_cbs, ++ struct fm_port *tx_port); ++int dpa_fq_init(struct dpa_fq *dpa_fq, bool td_enable); ++int dpa_fqs_init(struct device *dev, struct list_head *list, bool td_enable); ++int __cold __attribute__((nonnull)) ++dpa_fq_free(struct device *dev, struct list_head *list); ++void dpaa_eth_init_ports(struct mac_device *mac_dev, ++ struct dpa_bp *bp, size_t count, ++ struct fm_port_fqs *port_fqs, ++ struct dpa_buffer_layout_s *buf_layout, ++ struct device *dev); ++void dpa_release_sgt(struct qm_sg_entry *sgt); ++void __attribute__((nonnull)) ++dpa_fd_release(const struct net_device *net_dev, const struct qm_fd *fd); ++void count_ern(struct dpa_percpu_priv_s *percpu_priv, ++ const struct qm_mr_entry *msg); ++int dpa_enable_tx_csum(struct dpa_priv_s *priv, ++ struct sk_buff *skb, struct qm_fd *fd, char *parse_results); ++#ifdef CONFIG_FSL_DPAA_CEETM ++void dpa_enable_ceetm(struct net_device *dev); ++void dpa_disable_ceetm(struct net_device *dev); ++#endif ++struct proxy_device { ++ struct mac_device *mac_dev; ++}; ++ ++/* mac device control functions exposed by proxy interface*/ ++int dpa_proxy_start(struct net_device *net_dev); ++int dpa_proxy_stop(struct proxy_device *proxy_dev, struct net_device *net_dev); ++int dpa_proxy_set_mac_address(struct proxy_device *proxy_dev, ++ struct net_device *net_dev); ++int dpa_proxy_set_rx_mode(struct proxy_device *proxy_dev, ++ struct net_device *net_dev); ++ ++#endif /* __DPAA_ETH_COMMON_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_proxy.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_proxy.c +new file mode 100644 +index 00000000..994d38cd +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_proxy.c +@@ -0,0 +1,381 @@ ++/* Copyright 2008-2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG ++#define pr_fmt(fmt) \ ++ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \ ++ KBUILD_BASENAME".c", __LINE__, __func__ ++#else ++#define pr_fmt(fmt) \ ++ KBUILD_MODNAME ": " fmt ++#endif ++ ++#include ++#include ++#include ++#include "dpaa_eth.h" ++#include "dpaa_eth_common.h" ++#include "dpaa_eth_base.h" ++#include "lnxwrp_fsl_fman.h" /* fm_get_rx_extra_headroom(), fm_get_max_frm() */ ++#include "mac.h" ++ ++#define DPA_DESCRIPTION "FSL DPAA Proxy initialization driver" ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++MODULE_DESCRIPTION(DPA_DESCRIPTION); ++ ++static int __cold dpa_eth_proxy_remove(struct platform_device *of_dev); ++#ifdef CONFIG_PM ++ ++static int proxy_suspend(struct device *dev) ++{ ++ struct proxy_device *proxy_dev = dev_get_drvdata(dev); ++ struct mac_device *mac_dev = proxy_dev->mac_dev; ++ int err = 0; ++ ++ err = fm_port_suspend(mac_dev->port_dev[RX]); ++ if (err) ++ goto port_suspend_failed; ++ ++ err = fm_port_suspend(mac_dev->port_dev[TX]); ++ if (err) ++ err = fm_port_resume(mac_dev->port_dev[RX]); ++ ++port_suspend_failed: ++ return err; ++} ++ ++static int proxy_resume(struct device *dev) ++{ ++ struct proxy_device *proxy_dev = dev_get_drvdata(dev); ++ struct mac_device *mac_dev = proxy_dev->mac_dev; ++ int err = 0; ++ ++ err = fm_port_resume(mac_dev->port_dev[TX]); ++ if (err) ++ goto port_resume_failed; ++ ++ err = fm_port_resume(mac_dev->port_dev[RX]); ++ if (err) ++ err = fm_port_suspend(mac_dev->port_dev[TX]); ++ ++port_resume_failed: ++ return err; ++} ++ ++static const struct dev_pm_ops proxy_pm_ops = { ++ .suspend = proxy_suspend, ++ .resume = proxy_resume, ++}; ++ ++#define PROXY_PM_OPS (&proxy_pm_ops) ++ ++#else /* CONFIG_PM */ ++ ++#define PROXY_PM_OPS NULL ++ ++#endif /* CONFIG_PM */ ++ ++static int dpaa_eth_proxy_probe(struct platform_device *_of_dev) ++{ ++ int err = 0, i; ++ struct device *dev; ++ struct device_node *dpa_node; ++ struct dpa_bp *dpa_bp; ++ struct list_head proxy_fq_list; ++ size_t count; ++ struct fm_port_fqs port_fqs; ++ struct dpa_buffer_layout_s *buf_layout = NULL; ++ struct mac_device *mac_dev; ++ struct proxy_device *proxy_dev; ++ ++ dev = &_of_dev->dev; ++ ++ dpa_node = dev->of_node; ++ ++ if (!of_device_is_available(dpa_node)) ++ return -ENODEV; ++ ++ /* Get the buffer pools assigned to this interface */ ++ dpa_bp = dpa_bp_probe(_of_dev, &count); ++ if (IS_ERR(dpa_bp)) ++ return PTR_ERR(dpa_bp); ++ ++ mac_dev = dpa_mac_probe(_of_dev); ++ if (IS_ERR(mac_dev)) ++ return PTR_ERR(mac_dev); ++ ++ proxy_dev = devm_kzalloc(dev, sizeof(*proxy_dev), GFP_KERNEL); ++ if (!proxy_dev) { ++ dev_err(dev, "devm_kzalloc() failed\n"); ++ return -ENOMEM; ++ } ++ ++ proxy_dev->mac_dev = mac_dev; ++ dev_set_drvdata(dev, proxy_dev); ++ ++ /* We have physical ports, so we need to establish ++ * the buffer layout. ++ */ ++ buf_layout = devm_kzalloc(dev, 2 * sizeof(*buf_layout), ++ GFP_KERNEL); ++ if (!buf_layout) { ++ dev_err(dev, "devm_kzalloc() failed\n"); ++ return -ENOMEM; ++ } ++ dpa_set_buffers_layout(mac_dev, buf_layout); ++ ++ INIT_LIST_HEAD(&proxy_fq_list); ++ ++ memset(&port_fqs, 0, sizeof(port_fqs)); ++ ++ err = dpa_fq_probe_mac(dev, &proxy_fq_list, &port_fqs, true, RX); ++ if (!err) ++ err = dpa_fq_probe_mac(dev, &proxy_fq_list, &port_fqs, true, ++ TX); ++ if (err < 0) { ++ devm_kfree(dev, buf_layout); ++ return err; ++ } ++ ++ /* Proxy initializer - Just configures the MAC on behalf of ++ * another partition. ++ */ ++ dpaa_eth_init_ports(mac_dev, dpa_bp, count, &port_fqs, ++ buf_layout, dev); ++ ++ /* Proxy interfaces need to be started, and the allocated ++ * memory freed ++ */ ++ devm_kfree(dev, buf_layout); ++ devm_kfree(dev, dpa_bp); ++ ++ /* Free FQ structures */ ++ devm_kfree(dev, port_fqs.rx_defq); ++ devm_kfree(dev, port_fqs.rx_errq); ++ devm_kfree(dev, port_fqs.tx_defq); ++ devm_kfree(dev, port_fqs.tx_errq); ++ ++ for_each_port_device(i, mac_dev->port_dev) { ++ err = fm_port_enable(mac_dev->port_dev[i]); ++ if (err) ++ goto port_enable_fail; ++ } ++ ++ dev_info(dev, "probed MAC device with MAC address: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n", ++ mac_dev->addr[0], mac_dev->addr[1], mac_dev->addr[2], ++ mac_dev->addr[3], mac_dev->addr[4], mac_dev->addr[5]); ++ ++ return 0; /* Proxy interface initialization ended */ ++ ++port_enable_fail: ++ for_each_port_device(i, mac_dev->port_dev) ++ fm_port_disable(mac_dev->port_dev[i]); ++ dpa_eth_proxy_remove(_of_dev); ++ ++ return err; ++} ++ ++int dpa_proxy_set_mac_address(struct proxy_device *proxy_dev, ++ struct net_device *net_dev) ++{ ++ struct mac_device *mac_dev; ++ int _errno; ++ ++ mac_dev = proxy_dev->mac_dev; ++ ++ _errno = mac_dev->change_addr(mac_dev->get_mac_handle(mac_dev), ++ net_dev->dev_addr); ++ if (_errno < 0) ++ return _errno; ++ ++ return 0; ++} ++EXPORT_SYMBOL(dpa_proxy_set_mac_address); ++ ++int dpa_proxy_set_rx_mode(struct proxy_device *proxy_dev, ++ struct net_device *net_dev) ++{ ++ struct mac_device *mac_dev = proxy_dev->mac_dev; ++ int _errno; ++ ++ if (!!(net_dev->flags & IFF_PROMISC) != mac_dev->promisc) { ++ mac_dev->promisc = !mac_dev->promisc; ++ _errno = mac_dev->set_promisc(mac_dev->get_mac_handle(mac_dev), ++ mac_dev->promisc); ++ if (unlikely(_errno < 0)) ++ netdev_err(net_dev, "mac_dev->set_promisc() = %d\n", ++ _errno); ++ } ++ ++ _errno = mac_dev->set_multi(net_dev, mac_dev); ++ if (unlikely(_errno < 0)) ++ return _errno; ++ ++ return 0; ++} ++EXPORT_SYMBOL(dpa_proxy_set_rx_mode); ++ ++int dpa_proxy_start(struct net_device *net_dev) ++{ ++ struct mac_device *mac_dev; ++ const struct dpa_priv_s *priv; ++ struct proxy_device *proxy_dev; ++ int _errno; ++ int i; ++ ++ priv = netdev_priv(net_dev); ++ proxy_dev = (struct proxy_device *)priv->peer; ++ mac_dev = proxy_dev->mac_dev; ++ ++ _errno = mac_dev->init_phy(net_dev, mac_dev); ++ if (_errno < 0) { ++ if (netif_msg_drv(priv)) ++ netdev_err(net_dev, "init_phy() = %d\n", ++ _errno); ++ return _errno; ++ } ++ ++ for_each_port_device(i, mac_dev->port_dev) { ++ _errno = fm_port_enable(mac_dev->port_dev[i]); ++ if (_errno) ++ goto port_enable_fail; ++ } ++ ++ _errno = mac_dev->start(mac_dev); ++ if (_errno < 0) { ++ if (netif_msg_drv(priv)) ++ netdev_err(net_dev, "mac_dev->start() = %d\n", ++ _errno); ++ goto port_enable_fail; ++ } ++ ++ return _errno; ++ ++port_enable_fail: ++ for_each_port_device(i, mac_dev->port_dev) ++ fm_port_disable(mac_dev->port_dev[i]); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(dpa_proxy_start); ++ ++int dpa_proxy_stop(struct proxy_device *proxy_dev, struct net_device *net_dev) ++{ ++ struct mac_device *mac_dev = proxy_dev->mac_dev; ++ const struct dpa_priv_s *priv = netdev_priv(net_dev); ++ int _errno, i, err; ++ ++ _errno = mac_dev->stop(mac_dev); ++ if (_errno < 0) { ++ if (netif_msg_drv(priv)) ++ netdev_err(net_dev, "mac_dev->stop() = %d\n", ++ _errno); ++ return _errno; ++ } ++ ++ for_each_port_device(i, mac_dev->port_dev) { ++ err = fm_port_disable(mac_dev->port_dev[i]); ++ _errno = err ? err : _errno; ++ } ++ ++ if (mac_dev->phy_dev) ++ phy_disconnect(mac_dev->phy_dev); ++ mac_dev->phy_dev = NULL; ++ ++ return _errno; ++} ++EXPORT_SYMBOL(dpa_proxy_stop); ++ ++static int __cold dpa_eth_proxy_remove(struct platform_device *of_dev) ++{ ++ struct device *dev = &of_dev->dev; ++ struct proxy_device *proxy_dev = dev_get_drvdata(dev); ++ ++ kfree(proxy_dev); ++ ++ dev_set_drvdata(dev, NULL); ++ ++ return 0; ++} ++ ++static const struct of_device_id dpa_proxy_match[] = { ++ { ++ .compatible = "fsl,dpa-ethernet-init" ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, dpa_proxy_match); ++ ++static struct platform_driver dpa_proxy_driver = { ++ .driver = { ++ .name = KBUILD_MODNAME "-proxy", ++ .of_match_table = dpa_proxy_match, ++ .owner = THIS_MODULE, ++ .pm = PROXY_PM_OPS, ++ }, ++ .probe = dpaa_eth_proxy_probe, ++ .remove = dpa_eth_proxy_remove ++}; ++ ++static int __init __cold dpa_proxy_load(void) ++{ ++ int _errno; ++ ++ pr_info(DPA_DESCRIPTION "\n"); ++ ++ /* Initialize dpaa_eth mirror values */ ++ dpa_rx_extra_headroom = fm_get_rx_extra_headroom(); ++ dpa_max_frm = fm_get_max_frm(); ++ ++ _errno = platform_driver_register(&dpa_proxy_driver); ++ if (unlikely(_errno < 0)) { ++ pr_err(KBUILD_MODNAME ++ ": %s:%hu:%s(): platform_driver_register() = %d\n", ++ KBUILD_BASENAME".c", __LINE__, __func__, _errno); ++ } ++ ++ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", ++ KBUILD_BASENAME".c", __func__); ++ ++ return _errno; ++} ++module_init(dpa_proxy_load); ++ ++static void __exit __cold dpa_proxy_unload(void) ++{ ++ platform_driver_unregister(&dpa_proxy_driver); ++ ++ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", ++ KBUILD_BASENAME".c", __func__); ++} ++module_exit(dpa_proxy_unload); +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c +new file mode 100644 +index 00000000..11b47e8c +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c +@@ -0,0 +1,1179 @@ ++/* Copyright 2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG ++#define pr_fmt(fmt) \ ++ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \ ++ KBUILD_BASENAME".c", __LINE__, __func__ ++#else ++#define pr_fmt(fmt) \ ++ KBUILD_MODNAME ": " fmt ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "dpaa_eth.h" ++#include "dpaa_eth_common.h" ++#ifdef CONFIG_FSL_DPAA_1588 ++#include "dpaa_1588.h" ++#endif ++#ifdef CONFIG_FSL_DPAA_CEETM ++#include "dpaa_eth_ceetm.h" ++#endif ++ ++/* DMA map and add a page frag back into the bpool. ++ * @vaddr fragment must have been allocated with netdev_alloc_frag(), ++ * specifically for fitting into @dpa_bp. ++ */ ++static void dpa_bp_recycle_frag(struct dpa_bp *dpa_bp, unsigned long vaddr, ++ int *count_ptr) ++{ ++ struct bm_buffer bmb; ++ dma_addr_t addr; ++ ++ bmb.opaque = 0; ++ ++ addr = dma_map_single(dpa_bp->dev, (void *)vaddr, dpa_bp->size, ++ DMA_BIDIRECTIONAL); ++ if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) { ++ dev_err(dpa_bp->dev, "DMA mapping failed"); ++ return; ++ } ++ ++ bm_buffer_set64(&bmb, addr); ++ ++ while (bman_release(dpa_bp->pool, &bmb, 1, 0)) ++ cpu_relax(); ++ ++ (*count_ptr)++; ++} ++ ++static int _dpa_bp_add_8_bufs(const struct dpa_bp *dpa_bp) ++{ ++ struct bm_buffer bmb[8]; ++ void *new_buf; ++ dma_addr_t addr; ++ uint8_t i; ++ struct device *dev = dpa_bp->dev; ++ struct sk_buff *skb, **skbh; ++ ++ memset(bmb, 0, sizeof(struct bm_buffer) * 8); ++ ++ for (i = 0; i < 8; i++) { ++ /* We'll prepend the skb back-pointer; can't use the DPA ++ * priv space, because FMan will overwrite it (from offset 0) ++ * if it ends up being the second, third, etc. fragment ++ * in a S/G frame. ++ * ++ * We only need enough space to store a pointer, but allocate ++ * an entire cacheline for performance reasons. ++ */ ++#ifndef CONFIG_PPC ++ if (unlikely(dpaa_errata_a010022)) { ++ struct page *new_page = alloc_page(GFP_ATOMIC); ++ if (unlikely(!new_page)) ++ goto netdev_alloc_failed; ++ new_buf = page_address(new_page); ++ } ++ else ++#endif ++ new_buf = netdev_alloc_frag(SMP_CACHE_BYTES + DPA_BP_RAW_SIZE); ++ ++ if (unlikely(!new_buf)) ++ goto netdev_alloc_failed; ++ new_buf = PTR_ALIGN(new_buf + SMP_CACHE_BYTES, SMP_CACHE_BYTES); ++ ++ skb = build_skb(new_buf, DPA_SKB_SIZE(dpa_bp->size) + ++ SKB_DATA_ALIGN(sizeof(struct skb_shared_info))); ++ if (unlikely(!skb)) { ++ put_page(virt_to_head_page(new_buf)); ++ goto build_skb_failed; ++ } ++ DPA_WRITE_SKB_PTR(skb, skbh, new_buf, -1); ++ ++ addr = dma_map_single(dev, new_buf, ++ dpa_bp->size, DMA_BIDIRECTIONAL); ++ if (unlikely(dma_mapping_error(dev, addr))) ++ goto dma_map_failed; ++ ++ bm_buffer_set64(&bmb[i], addr); ++ } ++ ++release_bufs: ++ /* Release the buffers. In case bman is busy, keep trying ++ * until successful. bman_release() is guaranteed to succeed ++ * in a reasonable amount of time ++ */ ++ while (unlikely(bman_release(dpa_bp->pool, bmb, i, 0))) ++ cpu_relax(); ++ return i; ++ ++dma_map_failed: ++ kfree_skb(skb); ++ ++build_skb_failed: ++netdev_alloc_failed: ++ net_err_ratelimited("dpa_bp_add_8_bufs() failed\n"); ++ WARN_ONCE(1, "Memory allocation failure on Rx\n"); ++ ++ bm_buffer_set64(&bmb[i], 0); ++ /* Avoid releasing a completely null buffer; bman_release() requires ++ * at least one buffer. ++ */ ++ if (likely(i)) ++ goto release_bufs; ++ ++ return 0; ++} ++ ++/* Cold path wrapper over _dpa_bp_add_8_bufs(). */ ++static void dpa_bp_add_8_bufs(const struct dpa_bp *dpa_bp, int cpu) ++{ ++ int *count_ptr = per_cpu_ptr(dpa_bp->percpu_count, cpu); ++ *count_ptr += _dpa_bp_add_8_bufs(dpa_bp); ++} ++ ++int dpa_bp_priv_seed(struct dpa_bp *dpa_bp) ++{ ++ int i; ++ ++ /* Give each CPU an allotment of "config_count" buffers */ ++ for_each_possible_cpu(i) { ++ int j; ++ ++ /* Although we access another CPU's counters here ++ * we do it at boot time so it is safe ++ */ ++ for (j = 0; j < dpa_bp->config_count; j += 8) ++ dpa_bp_add_8_bufs(dpa_bp, i); ++ } ++ return 0; ++} ++EXPORT_SYMBOL(dpa_bp_priv_seed); ++ ++/* Add buffers/(pages) for Rx processing whenever bpool count falls below ++ * REFILL_THRESHOLD. ++ */ ++int dpaa_eth_refill_bpools(struct dpa_bp *dpa_bp, int *countptr) ++{ ++ int count = *countptr; ++ int new_bufs; ++ ++ if (unlikely(count < CONFIG_FSL_DPAA_ETH_REFILL_THRESHOLD)) { ++ do { ++ new_bufs = _dpa_bp_add_8_bufs(dpa_bp); ++ if (unlikely(!new_bufs)) { ++ /* Avoid looping forever if we've temporarily ++ * run out of memory. We'll try again at the ++ * next NAPI cycle. ++ */ ++ break; ++ } ++ count += new_bufs; ++ } while (count < CONFIG_FSL_DPAA_ETH_MAX_BUF_COUNT); ++ ++ *countptr = count; ++ if (unlikely(count < CONFIG_FSL_DPAA_ETH_MAX_BUF_COUNT)) ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(dpaa_eth_refill_bpools); ++ ++/* Cleanup function for outgoing frame descriptors that were built on Tx path, ++ * either contiguous frames or scatter/gather ones. ++ * Skb freeing is not handled here. ++ * ++ * This function may be called on error paths in the Tx function, so guard ++ * against cases when not all fd relevant fields were filled in. ++ * ++ * Return the skb backpointer, since for S/G frames the buffer containing it ++ * gets freed here. ++ */ ++struct sk_buff *_dpa_cleanup_tx_fd(const struct dpa_priv_s *priv, ++ const struct qm_fd *fd) ++{ ++ const struct qm_sg_entry *sgt; ++ int i; ++ struct dpa_bp *dpa_bp = priv->dpa_bp; ++ dma_addr_t addr = qm_fd_addr(fd); ++ dma_addr_t sg_addr; ++ struct sk_buff **skbh; ++ struct sk_buff *skb = NULL; ++ const enum dma_data_direction dma_dir = DMA_TO_DEVICE; ++ int nr_frags; ++ int sg_len; ++ ++ /* retrieve skb back pointer */ ++ DPA_READ_SKB_PTR(skb, skbh, phys_to_virt(addr), 0); ++ ++ if (unlikely(fd->format == qm_fd_sg)) { ++ nr_frags = skb_shinfo(skb)->nr_frags; ++ dma_unmap_single(dpa_bp->dev, addr, dpa_fd_offset(fd) + ++ sizeof(struct qm_sg_entry) * (1 + nr_frags), ++ dma_dir); ++ ++ /* The sgt buffer has been allocated with netdev_alloc_frag(), ++ * it's from lowmem. ++ */ ++ sgt = phys_to_virt(addr + dpa_fd_offset(fd)); ++#ifdef CONFIG_FSL_DPAA_1588 ++ if (priv->tsu && priv->tsu->valid && ++ priv->tsu->hwts_tx_en_ioctl) ++ dpa_ptp_store_txstamp(priv, skb, (void *)skbh); ++#endif ++#ifdef CONFIG_FSL_DPAA_TS ++ if (unlikely(priv->ts_tx_en && ++ skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { ++ struct skb_shared_hwtstamps shhwtstamps; ++ ++ dpa_get_ts(priv, TX, &shhwtstamps, (void *)skbh); ++ skb_tstamp_tx(skb, &shhwtstamps); ++ } ++#endif /* CONFIG_FSL_DPAA_TS */ ++ ++ /* sgt[0] is from lowmem, was dma_map_single()-ed */ ++ sg_addr = qm_sg_addr(&sgt[0]); ++ sg_len = qm_sg_entry_get_len(&sgt[0]); ++ dma_unmap_single(dpa_bp->dev, sg_addr, sg_len, dma_dir); ++ ++ /* remaining pages were mapped with dma_map_page() */ ++ for (i = 1; i <= nr_frags; i++) { ++ DPA_BUG_ON(qm_sg_entry_get_ext(&sgt[i])); ++ sg_addr = qm_sg_addr(&sgt[i]); ++ sg_len = qm_sg_entry_get_len(&sgt[i]); ++ dma_unmap_page(dpa_bp->dev, sg_addr, sg_len, dma_dir); ++ } ++ ++ /* Free the page frag that we allocated on Tx */ ++ put_page(virt_to_head_page(sgt)); ++ } else { ++ dma_unmap_single(dpa_bp->dev, addr, ++ skb_tail_pointer(skb) - (u8 *)skbh, dma_dir); ++#ifdef CONFIG_FSL_DPAA_TS ++ /* get the timestamp for non-SG frames */ ++#ifdef CONFIG_FSL_DPAA_1588 ++ if (priv->tsu && priv->tsu->valid && ++ priv->tsu->hwts_tx_en_ioctl) ++ dpa_ptp_store_txstamp(priv, skb, (void *)skbh); ++#endif ++ if (unlikely(priv->ts_tx_en && ++ skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { ++ struct skb_shared_hwtstamps shhwtstamps; ++ ++ dpa_get_ts(priv, TX, &shhwtstamps, (void *)skbh); ++ skb_tstamp_tx(skb, &shhwtstamps); ++ } ++#endif ++ } ++ ++ return skb; ++} ++EXPORT_SYMBOL(_dpa_cleanup_tx_fd); ++ ++#ifndef CONFIG_FSL_DPAA_TS ++bool dpa_skb_is_recyclable(struct sk_buff *skb) ++{ ++#ifndef CONFIG_PPC ++ /* Do no recycle skbs realigned by the errata workaround */ ++ if (unlikely(dpaa_errata_a010022) && skb->mark == NONREC_MARK) ++ return false; ++#endif ++ ++ /* No recycling possible if skb buffer is kmalloc'ed */ ++ if (skb->head_frag == 0) ++ return false; ++ ++ /* or if it's an userspace buffer */ ++ if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) ++ return false; ++ ++ /* or if it's cloned or shared */ ++ if (skb_shared(skb) || skb_cloned(skb) || ++ skb->fclone != SKB_FCLONE_UNAVAILABLE) ++ return false; ++ ++ return true; ++} ++EXPORT_SYMBOL(dpa_skb_is_recyclable); ++ ++bool dpa_buf_is_recyclable(struct sk_buff *skb, ++ uint32_t min_size, ++ uint16_t min_offset, ++ unsigned char **new_buf_start) ++{ ++ unsigned char *new; ++ ++ /* In order to recycle a buffer, the following conditions must be met: ++ * - buffer size no less than the buffer pool size ++ * - buffer size no higher than an upper limit (to avoid moving too much ++ * system memory to the buffer pools) ++ * - buffer address aligned to cacheline bytes ++ * - offset of data from start of buffer no lower than a minimum value ++ * - offset of data from start of buffer no higher than a maximum value ++ */ ++ new = min(skb_end_pointer(skb) - min_size, skb->data - min_offset); ++ ++ /* left align to the nearest cacheline */ ++ new = (unsigned char *)((unsigned long)new & ~(SMP_CACHE_BYTES - 1)); ++ ++ if (likely(new >= skb->head && ++ new >= (skb->data - DPA_MAX_FD_OFFSET) && ++ skb_end_pointer(skb) - new <= DPA_RECYCLE_MAX_SIZE)) { ++ *new_buf_start = new; ++ return true; ++ } ++ ++ return false; ++} ++EXPORT_SYMBOL(dpa_buf_is_recyclable); ++#endif ++ ++/* Build a linear skb around the received buffer. ++ * We are guaranteed there is enough room at the end of the data buffer to ++ * accommodate the shared info area of the skb. ++ */ ++static struct sk_buff *__hot contig_fd_to_skb(const struct dpa_priv_s *priv, ++ const struct qm_fd *fd, int *use_gro) ++{ ++ dma_addr_t addr = qm_fd_addr(fd); ++ ssize_t fd_off = dpa_fd_offset(fd); ++ void *vaddr; ++ const fm_prs_result_t *parse_results; ++ struct sk_buff *skb = NULL, **skbh; ++ ++ vaddr = phys_to_virt(addr); ++ DPA_BUG_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES)); ++ ++ /* Retrieve the skb and adjust data and tail pointers, to make sure ++ * forwarded skbs will have enough space on Tx if extra headers ++ * are added. ++ */ ++ DPA_READ_SKB_PTR(skb, skbh, vaddr, -1); ++ ++#ifdef CONFIG_FSL_DPAA_ETH_JUMBO_FRAME ++ /* When using jumbo Rx buffers, we risk having frames dropped due to ++ * the socket backlog reaching its maximum allowed size. ++ * Use the frame length for the skb truesize instead of the buffer ++ * size, as this is the size of the data that actually gets copied to ++ * userspace. ++ * The stack may increase the payload. In this case, it will want to ++ * warn us that the frame length is larger than the truesize. We ++ * bypass the warning. ++ */ ++#ifndef CONFIG_PPC ++ /* We do not support Jumbo frames on LS1043 and thus we edit ++ * the skb truesize only when the 4k errata is not present. ++ */ ++ if (likely(!dpaa_errata_a010022)) ++#endif ++ skb->truesize = SKB_TRUESIZE(dpa_fd_length(fd)); ++#endif ++ ++ DPA_BUG_ON(fd_off != priv->rx_headroom); ++ skb_reserve(skb, fd_off); ++ skb_put(skb, dpa_fd_length(fd)); ++ ++ /* Peek at the parse results for csum validation */ ++ parse_results = (const fm_prs_result_t *)(vaddr + ++ DPA_RX_PRIV_DATA_SIZE); ++ _dpa_process_parse_results(parse_results, fd, skb, use_gro); ++ ++#ifdef CONFIG_FSL_DPAA_1588 ++ if (priv->tsu && priv->tsu->valid && priv->tsu->hwts_rx_en_ioctl) ++ dpa_ptp_store_rxstamp(priv, skb, vaddr); ++#endif ++#ifdef CONFIG_FSL_DPAA_TS ++ if (priv->ts_rx_en) ++ dpa_get_ts(priv, RX, skb_hwtstamps(skb), vaddr); ++#endif /* CONFIG_FSL_DPAA_TS */ ++ ++ return skb; ++} ++ ++ ++/* Build an skb with the data of the first S/G entry in the linear portion and ++ * the rest of the frame as skb fragments. ++ * ++ * The page fragment holding the S/G Table is recycled here. ++ */ ++static struct sk_buff *__hot sg_fd_to_skb(const struct dpa_priv_s *priv, ++ const struct qm_fd *fd, int *use_gro, ++ int *count_ptr) ++{ ++ const struct qm_sg_entry *sgt; ++ dma_addr_t addr = qm_fd_addr(fd); ++ ssize_t fd_off = dpa_fd_offset(fd); ++ dma_addr_t sg_addr; ++ void *vaddr, *sg_vaddr; ++ struct dpa_bp *dpa_bp; ++ struct page *page, *head_page; ++ int frag_offset, frag_len; ++ int page_offset; ++ int i; ++ const fm_prs_result_t *parse_results; ++ struct sk_buff *skb = NULL, *skb_tmp, **skbh; ++ ++ vaddr = phys_to_virt(addr); ++ DPA_BUG_ON(!IS_ALIGNED((unsigned long)vaddr, SMP_CACHE_BYTES)); ++ ++ dpa_bp = priv->dpa_bp; ++ /* Iterate through the SGT entries and add data buffers to the skb */ ++ sgt = vaddr + fd_off; ++ for (i = 0; i < DPA_SGT_MAX_ENTRIES; i++) { ++ /* Extension bit is not supported */ ++ DPA_BUG_ON(qm_sg_entry_get_ext(&sgt[i])); ++ ++ /* We use a single global Rx pool */ ++ DPA_BUG_ON(dpa_bp != ++ dpa_bpid2pool(qm_sg_entry_get_bpid(&sgt[i]))); ++ ++ sg_addr = qm_sg_addr(&sgt[i]); ++ sg_vaddr = phys_to_virt(sg_addr); ++ DPA_BUG_ON(!IS_ALIGNED((unsigned long)sg_vaddr, ++ SMP_CACHE_BYTES)); ++ ++ dma_unmap_single(dpa_bp->dev, sg_addr, dpa_bp->size, ++ DMA_BIDIRECTIONAL); ++ if (i == 0) { ++ DPA_READ_SKB_PTR(skb, skbh, sg_vaddr, -1); ++ DPA_BUG_ON(skb->head != sg_vaddr); ++#ifdef CONFIG_FSL_DPAA_1588 ++ if (priv->tsu && priv->tsu->valid && ++ priv->tsu->hwts_rx_en_ioctl) ++ dpa_ptp_store_rxstamp(priv, skb, vaddr); ++#endif ++#ifdef CONFIG_FSL_DPAA_TS ++ if (priv->ts_rx_en) ++ dpa_get_ts(priv, RX, skb_hwtstamps(skb), vaddr); ++#endif /* CONFIG_FSL_DPAA_TS */ ++ ++ /* In the case of a SG frame, FMan stores the Internal ++ * Context in the buffer containing the sgt. ++ * Inspect the parse results before anything else. ++ */ ++ parse_results = (const fm_prs_result_t *)(vaddr + ++ DPA_RX_PRIV_DATA_SIZE); ++ _dpa_process_parse_results(parse_results, fd, skb, ++ use_gro); ++ ++ /* Make sure forwarded skbs will have enough space ++ * on Tx, if extra headers are added. ++ */ ++ DPA_BUG_ON(fd_off != priv->rx_headroom); ++ skb_reserve(skb, fd_off); ++ skb_put(skb, qm_sg_entry_get_len(&sgt[i])); ++ } else { ++ /* Not the first S/G entry; all data from buffer will ++ * be added in an skb fragment; fragment index is offset ++ * by one since first S/G entry was incorporated in the ++ * linear part of the skb. ++ * ++ * Caution: 'page' may be a tail page. ++ */ ++ DPA_READ_SKB_PTR(skb_tmp, skbh, sg_vaddr, -1); ++ page = virt_to_page(sg_vaddr); ++ head_page = virt_to_head_page(sg_vaddr); ++ ++ /* Free (only) the skbuff shell because its data buffer ++ * is already a frag in the main skb. ++ */ ++ get_page(head_page); ++ dev_kfree_skb(skb_tmp); ++ ++ /* Compute offset in (possibly tail) page */ ++ page_offset = ((unsigned long)sg_vaddr & ++ (PAGE_SIZE - 1)) + ++ (page_address(page) - page_address(head_page)); ++ /* page_offset only refers to the beginning of sgt[i]; ++ * but the buffer itself may have an internal offset. ++ */ ++ frag_offset = qm_sg_entry_get_offset(&sgt[i]) + ++ page_offset; ++ frag_len = qm_sg_entry_get_len(&sgt[i]); ++ /* skb_add_rx_frag() does no checking on the page; if ++ * we pass it a tail page, we'll end up with ++ * bad page accounting and eventually with segafults. ++ */ ++ skb_add_rx_frag(skb, i - 1, head_page, frag_offset, ++ frag_len, dpa_bp->size); ++ } ++ /* Update the pool count for the current {cpu x bpool} */ ++ (*count_ptr)--; ++ ++ if (qm_sg_entry_get_final(&sgt[i])) ++ break; ++ } ++ WARN_ONCE(i == DPA_SGT_MAX_ENTRIES, "No final bit on SGT\n"); ++ ++ /* recycle the SGT fragment */ ++ DPA_BUG_ON(dpa_bp != dpa_bpid2pool(fd->bpid)); ++ dpa_bp_recycle_frag(dpa_bp, (unsigned long)vaddr, count_ptr); ++ return skb; ++} ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++static inline int dpa_skb_loop(const struct dpa_priv_s *priv, ++ struct sk_buff *skb) ++{ ++ if (unlikely(priv->loop_to < 0)) ++ return 0; /* loop disabled by default */ ++ ++ skb_push(skb, ETH_HLEN); /* compensate for eth_type_trans */ ++ dpa_tx(skb, dpa_loop_netdevs[priv->loop_to]); ++ ++ return 1; /* Frame Tx on the selected interface */ ++} ++#endif ++ ++void __hot _dpa_rx(struct net_device *net_dev, ++ struct qman_portal *portal, ++ const struct dpa_priv_s *priv, ++ struct dpa_percpu_priv_s *percpu_priv, ++ const struct qm_fd *fd, ++ u32 fqid, ++ int *count_ptr) ++{ ++ struct dpa_bp *dpa_bp; ++ struct sk_buff *skb; ++ dma_addr_t addr = qm_fd_addr(fd); ++ u32 fd_status = fd->status; ++ unsigned int skb_len; ++ struct rtnl_link_stats64 *percpu_stats = &percpu_priv->stats; ++ int use_gro = net_dev->features & NETIF_F_GRO; ++ ++ if (unlikely(fd_status & FM_FD_STAT_RX_ERRORS) != 0) { ++ if (netif_msg_hw(priv) && net_ratelimit()) ++ netdev_warn(net_dev, "FD status = 0x%08x\n", ++ fd_status & FM_FD_STAT_RX_ERRORS); ++ ++ percpu_stats->rx_errors++; ++ goto _release_frame; ++ } ++ ++ dpa_bp = priv->dpa_bp; ++ DPA_BUG_ON(dpa_bp != dpa_bpid2pool(fd->bpid)); ++ ++ /* prefetch the first 64 bytes of the frame or the SGT start */ ++ dma_unmap_single(dpa_bp->dev, addr, dpa_bp->size, DMA_BIDIRECTIONAL); ++ prefetch(phys_to_virt(addr) + dpa_fd_offset(fd)); ++ ++ /* The only FD types that we may receive are contig and S/G */ ++ DPA_BUG_ON((fd->format != qm_fd_contig) && (fd->format != qm_fd_sg)); ++ ++ if (likely(fd->format == qm_fd_contig)) { ++#ifdef CONFIG_FSL_DPAA_HOOKS ++ /* Execute the Rx processing hook, if it exists. */ ++ if (dpaa_eth_hooks.rx_default && ++ dpaa_eth_hooks.rx_default((void *)fd, net_dev, ++ fqid) == DPAA_ETH_STOLEN) { ++ /* won't count the rx bytes in */ ++ return; ++ } ++#endif ++ skb = contig_fd_to_skb(priv, fd, &use_gro); ++ } else { ++ skb = sg_fd_to_skb(priv, fd, &use_gro, count_ptr); ++ percpu_priv->rx_sg++; ++ } ++ ++ /* Account for either the contig buffer or the SGT buffer (depending on ++ * which case we were in) having been removed from the pool. ++ */ ++ (*count_ptr)--; ++ skb->protocol = eth_type_trans(skb, net_dev); ++ ++ /* IP Reassembled frames are allowed to be larger than MTU */ ++ if (unlikely(dpa_check_rx_mtu(skb, net_dev->mtu) && ++ !(fd_status & FM_FD_IPR))) { ++ percpu_stats->rx_dropped++; ++ goto drop_bad_frame; ++ } ++ ++ skb_len = skb->len; ++ ++#ifdef CONFIG_FSL_DPAA_DBG_LOOP ++ if (dpa_skb_loop(priv, skb)) { ++ percpu_stats->rx_packets++; ++ percpu_stats->rx_bytes += skb_len; ++ return; ++ } ++#endif ++ ++ if (use_gro) { ++ gro_result_t gro_result; ++ const struct qman_portal_config *pc = ++ qman_p_get_portal_config(portal); ++ struct dpa_napi_portal *np = &percpu_priv->np[pc->index]; ++ ++ np->p = portal; ++ gro_result = napi_gro_receive(&np->napi, skb); ++ /* If frame is dropped by the stack, rx_dropped counter is ++ * incremented automatically, so no need for us to update it ++ */ ++ if (unlikely(gro_result == GRO_DROP)) ++ goto packet_dropped; ++ } else if (unlikely(netif_receive_skb(skb) == NET_RX_DROP)) ++ goto packet_dropped; ++ ++ percpu_stats->rx_packets++; ++ percpu_stats->rx_bytes += skb_len; ++ ++packet_dropped: ++ return; ++ ++drop_bad_frame: ++ dev_kfree_skb(skb); ++ return; ++ ++_release_frame: ++ dpa_fd_release(net_dev, fd); ++} ++ ++int __hot skb_to_contig_fd(struct dpa_priv_s *priv, ++ struct sk_buff *skb, struct qm_fd *fd, ++ int *count_ptr, int *offset) ++{ ++ struct sk_buff **skbh; ++ dma_addr_t addr; ++ struct dpa_bp *dpa_bp = priv->dpa_bp; ++ struct net_device *net_dev = priv->net_dev; ++ int err; ++ enum dma_data_direction dma_dir; ++ unsigned char *buffer_start; ++ int dma_map_size; ++ ++#ifndef CONFIG_FSL_DPAA_TS ++ /* Check recycling conditions; only if timestamp support is not ++ * enabled, otherwise we need the fd back on tx confirmation ++ */ ++ ++ /* We can recycle the buffer if: ++ * - the pool is not full ++ * - the buffer meets the skb recycling conditions ++ * - the buffer meets our own (size, offset, align) conditions ++ */ ++ if (likely((*count_ptr < dpa_bp->target_count) && ++ dpa_skb_is_recyclable(skb) && ++ dpa_buf_is_recyclable(skb, dpa_bp->size, ++ priv->tx_headroom, &buffer_start))) { ++ /* Buffer is recyclable; use the new start address ++ * and set fd parameters and DMA mapping direction ++ */ ++ fd->bpid = dpa_bp->bpid; ++ DPA_BUG_ON(skb->data - buffer_start > DPA_MAX_FD_OFFSET); ++ fd->offset = (uint16_t)(skb->data - buffer_start); ++ dma_dir = DMA_BIDIRECTIONAL; ++ dma_map_size = dpa_bp->size; ++ ++ DPA_WRITE_SKB_PTR(skb, skbh, buffer_start, -1); ++ *offset = skb_headroom(skb) - fd->offset; ++ } else ++#endif ++ { ++ /* Not recyclable. ++ * We are guaranteed to have at least tx_headroom bytes ++ * available, so just use that for offset. ++ */ ++ fd->bpid = 0xff; ++ buffer_start = skb->data - priv->tx_headroom; ++ fd->offset = priv->tx_headroom; ++ dma_dir = DMA_TO_DEVICE; ++ dma_map_size = skb_tail_pointer(skb) - buffer_start; ++ ++ /* The buffer will be Tx-confirmed, but the TxConf cb must ++ * necessarily look at our Tx private data to retrieve the ++ * skbuff. (In short: can't use DPA_WRITE_SKB_PTR() here.) ++ */ ++ DPA_WRITE_SKB_PTR(skb, skbh, buffer_start, 0); ++ } ++ ++ /* Enable L3/L4 hardware checksum computation. ++ * ++ * We must do this before dma_map_single(DMA_TO_DEVICE), because we may ++ * need to write into the skb. ++ */ ++ err = dpa_enable_tx_csum(priv, skb, fd, ++ ((char *)skbh) + DPA_TX_PRIV_DATA_SIZE); ++ if (unlikely(err < 0)) { ++ if (netif_msg_tx_err(priv) && net_ratelimit()) ++ netdev_err(net_dev, "HW csum error: %d\n", err); ++ return err; ++ } ++ ++ /* Fill in the rest of the FD fields */ ++ fd->format = qm_fd_contig; ++ fd->length20 = skb->len; ++ fd->cmd |= FM_FD_CMD_FCO; ++ ++ /* Map the entire buffer size that may be seen by FMan, but no more */ ++ addr = dma_map_single(dpa_bp->dev, skbh, dma_map_size, dma_dir); ++ if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) { ++ if (netif_msg_tx_err(priv) && net_ratelimit()) ++ netdev_err(net_dev, "dma_map_single() failed\n"); ++ return -EINVAL; ++ } ++ qm_fd_addr_set64(fd, addr); ++ ++ return 0; ++} ++EXPORT_SYMBOL(skb_to_contig_fd); ++ ++#ifndef CONFIG_PPC ++/* Verify the conditions that trigger the A010022 errata: data unaligned to ++ * 16 bytes and 4K memory address crossings. ++ */ ++static bool a010022_check_skb(struct sk_buff *skb, struct dpa_priv_s *priv) ++{ ++ int nr_frags, i = 0; ++ skb_frag_t *frag; ++ ++ /* Check if the headroom is aligned */ ++ if (((uintptr_t)skb->data - priv->tx_headroom) % ++ priv->buf_layout[TX].data_align != 0) ++ return true; ++ ++ /* Check if the headroom crosses a boundary */ ++ if (HAS_DMA_ISSUE(skb->head, skb_headroom(skb))) ++ return true; ++ ++ /* Check if the non-paged data crosses a boundary */ ++ if (HAS_DMA_ISSUE(skb->data, skb_headlen(skb))) ++ return true; ++ ++ /* Check if the entire linear skb crosses a boundary */ ++ if (HAS_DMA_ISSUE(skb->head, skb_end_offset(skb))) ++ return true; ++ ++ nr_frags = skb_shinfo(skb)->nr_frags; ++ ++ while (i < nr_frags) { ++ frag = &skb_shinfo(skb)->frags[i]; ++ ++ /* Check if a paged fragment crosses a boundary from its ++ * offset to its end. ++ */ ++ if (HAS_DMA_ISSUE(frag->page_offset, frag->size)) ++ return true; ++ ++ i++; ++ } ++ ++ return false; ++} ++ ++/* Realign the skb by copying its contents at the start of a newly allocated ++ * page. Build a new skb around the new buffer and release the old one. ++ * A performance drop should be expected. ++ */ ++static struct sk_buff *a010022_realign_skb(struct sk_buff *skb, ++ struct dpa_priv_s *priv) ++{ ++ int trans_offset = skb_transport_offset(skb); ++ int net_offset = skb_network_offset(skb); ++ struct sk_buff *nskb = NULL; ++ int nsize, headroom; ++ struct page *npage; ++ void *npage_addr; ++ ++ /* Guarantee the minimum required headroom */ ++ if (skb_headroom(skb) >= priv->tx_headroom) ++ headroom = skb_headroom(skb); ++ else ++ headroom = priv->tx_headroom; ++ ++ npage = alloc_page(GFP_ATOMIC); ++ if (unlikely(!npage)) { ++ WARN_ONCE(1, "Memory allocation failure\n"); ++ return NULL; ++ } ++ npage_addr = page_address(npage); ++ ++ /* For the new skb we only need the old one's data (both non-paged and ++ * paged) and a headroom large enough to fit our private info. We can ++ * skip the old tailroom. ++ * ++ * Make sure the new linearized buffer will not exceed a page's size. ++ */ ++ nsize = headroom + skb->len + ++ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); ++ if (unlikely(nsize > 4096)) ++ goto err; ++ ++ nskb = build_skb(npage_addr, nsize); ++ if (unlikely(!nskb)) ++ goto err; ++ ++ /* Reserve only the needed headroom in order to guarantee the data's ++ * alignment. ++ * Code borrowed and adapted from skb_copy(). ++ */ ++ skb_reserve(nskb, priv->tx_headroom); ++ skb_put(nskb, skb->len); ++ if (skb_copy_bits(skb, 0, nskb->data, skb->len)) { ++ WARN_ONCE(1, "skb parsing failure\n"); ++ goto err; ++ } ++ copy_skb_header(nskb, skb); ++ ++#ifdef CONFIG_FSL_DPAA_TS ++ /* Copy relevant timestamp info from the old skb to the new */ ++ if (priv->ts_tx_en) { ++ skb_shinfo(nskb)->tx_flags = skb_shinfo(skb)->tx_flags; ++ skb_shinfo(nskb)->hwtstamps = skb_shinfo(skb)->hwtstamps; ++ skb_shinfo(nskb)->tskey = skb_shinfo(skb)->tskey; ++ if (skb->sk) ++ skb_set_owner_w(nskb, skb->sk); ++ } ++#endif ++ /* We move the headroom when we align it so we have to reset the ++ * network and transport header offsets relative to the new data ++ * pointer. The checksum offload relies on these offsets. ++ */ ++ skb_set_network_header(nskb, net_offset); ++ skb_set_transport_header(nskb, trans_offset); ++ ++ /* We don't want the buffer to be recycled so we mark it accordingly */ ++ nskb->mark = NONREC_MARK; ++ ++ dev_kfree_skb(skb); ++ return nskb; ++ ++err: ++ if (nskb) ++ dev_kfree_skb(nskb); ++ put_page(npage); ++ return NULL; ++} ++#endif ++ ++int __hot skb_to_sg_fd(struct dpa_priv_s *priv, ++ struct sk_buff *skb, struct qm_fd *fd) ++{ ++ struct dpa_bp *dpa_bp = priv->dpa_bp; ++ dma_addr_t addr; ++ dma_addr_t sg_addr; ++ struct sk_buff **skbh; ++ struct net_device *net_dev = priv->net_dev; ++ int sg_len, sgt_size; ++ int err; ++ ++ struct qm_sg_entry *sgt; ++ void *sgt_buf; ++ skb_frag_t *frag; ++ int i = 0, j = 0; ++ int nr_frags; ++ const enum dma_data_direction dma_dir = DMA_TO_DEVICE; ++ ++ nr_frags = skb_shinfo(skb)->nr_frags; ++ fd->format = qm_fd_sg; ++ ++ sgt_size = sizeof(struct qm_sg_entry) * (1 + nr_frags); ++ ++ /* Get a page frag to store the SGTable, or a full page if the errata ++ * is in place and we need to avoid crossing a 4k boundary. ++ */ ++#ifndef CONFIG_PPC ++ if (unlikely(dpaa_errata_a010022)) ++ sgt_buf = page_address(alloc_page(GFP_ATOMIC)); ++ else ++#endif ++ sgt_buf = netdev_alloc_frag(priv->tx_headroom + sgt_size); ++ if (unlikely(!sgt_buf)) { ++ dev_err(dpa_bp->dev, "netdev_alloc_frag() failed\n"); ++ return -ENOMEM; ++ } ++ ++ /* it seems that the memory allocator does not zero the allocated mem */ ++ memset(sgt_buf, 0, priv->tx_headroom + sgt_size); ++ ++ /* Enable L3/L4 hardware checksum computation. ++ * ++ * We must do this before dma_map_single(DMA_TO_DEVICE), because we may ++ * need to write into the skb. ++ */ ++ err = dpa_enable_tx_csum(priv, skb, fd, ++ sgt_buf + DPA_TX_PRIV_DATA_SIZE); ++ if (unlikely(err < 0)) { ++ if (netif_msg_tx_err(priv) && net_ratelimit()) ++ netdev_err(net_dev, "HW csum error: %d\n", err); ++ goto csum_failed; ++ } ++ ++ /* Assign the data from skb->data to the first SG list entry */ ++ sgt = (struct qm_sg_entry *)(sgt_buf + priv->tx_headroom); ++ sg_len = skb_headlen(skb); ++ qm_sg_entry_set_bpid(&sgt[0], 0xff); ++ qm_sg_entry_set_offset(&sgt[0], 0); ++ qm_sg_entry_set_len(&sgt[0], sg_len); ++ qm_sg_entry_set_ext(&sgt[0], 0); ++ qm_sg_entry_set_final(&sgt[0], 0); ++ ++ addr = dma_map_single(dpa_bp->dev, skb->data, sg_len, dma_dir); ++ if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) { ++ dev_err(dpa_bp->dev, "DMA mapping failed"); ++ err = -EINVAL; ++ goto sg0_map_failed; ++ } ++ ++ qm_sg_entry_set64(&sgt[0], addr); ++ ++ /* populate the rest of SGT entries */ ++ for (i = 1; i <= nr_frags; i++) { ++ frag = &skb_shinfo(skb)->frags[i - 1]; ++ qm_sg_entry_set_bpid(&sgt[i], 0xff); ++ qm_sg_entry_set_offset(&sgt[i], 0); ++ qm_sg_entry_set_len(&sgt[i], frag->size); ++ qm_sg_entry_set_ext(&sgt[i], 0); ++ ++ if (i == nr_frags) ++ qm_sg_entry_set_final(&sgt[i], 1); ++ else ++ qm_sg_entry_set_final(&sgt[i], 0); ++ ++ DPA_BUG_ON(!skb_frag_page(frag)); ++ addr = skb_frag_dma_map(dpa_bp->dev, frag, 0, frag->size, ++ dma_dir); ++ if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) { ++ dev_err(dpa_bp->dev, "DMA mapping failed"); ++ err = -EINVAL; ++ goto sg_map_failed; ++ } ++ ++ /* keep the offset in the address */ ++ qm_sg_entry_set64(&sgt[i], addr); ++ } ++ ++ fd->length20 = skb->len; ++ fd->offset = priv->tx_headroom; ++ ++ /* DMA map the SGT page */ ++ DPA_WRITE_SKB_PTR(skb, skbh, sgt_buf, 0); ++ addr = dma_map_single(dpa_bp->dev, sgt_buf, ++ priv->tx_headroom + sgt_size, ++ dma_dir); ++ ++ if (unlikely(dma_mapping_error(dpa_bp->dev, addr))) { ++ dev_err(dpa_bp->dev, "DMA mapping failed"); ++ err = -EINVAL; ++ goto sgt_map_failed; ++ } ++ ++ qm_fd_addr_set64(fd, addr); ++ fd->bpid = 0xff; ++ fd->cmd |= FM_FD_CMD_FCO; ++ ++ return 0; ++ ++sgt_map_failed: ++sg_map_failed: ++ for (j = 0; j < i; j++) { ++ sg_addr = qm_sg_addr(&sgt[j]); ++ dma_unmap_page(dpa_bp->dev, sg_addr, ++ qm_sg_entry_get_len(&sgt[j]), dma_dir); ++ } ++sg0_map_failed: ++csum_failed: ++ put_page(virt_to_head_page(sgt_buf)); ++ ++ return err; ++} ++EXPORT_SYMBOL(skb_to_sg_fd); ++ ++int __hot dpa_tx(struct sk_buff *skb, struct net_device *net_dev) ++{ ++ struct dpa_priv_s *priv; ++ const int queue_mapping = dpa_get_queue_mapping(skb); ++ struct qman_fq *egress_fq, *conf_fq; ++ ++#ifdef CONFIG_FSL_DPAA_HOOKS ++ /* If there is a Tx hook, run it. */ ++ if (dpaa_eth_hooks.tx && ++ dpaa_eth_hooks.tx(skb, net_dev) == DPAA_ETH_STOLEN) ++ /* won't update any Tx stats */ ++ return NETDEV_TX_OK; ++#endif ++ ++ priv = netdev_priv(net_dev); ++ ++#ifdef CONFIG_FSL_DPAA_CEETM ++ if (priv->ceetm_en) ++ return ceetm_tx(skb, net_dev); ++#endif ++ ++ egress_fq = priv->egress_fqs[queue_mapping]; ++ conf_fq = priv->conf_fqs[queue_mapping]; ++ ++ return dpa_tx_extended(skb, net_dev, egress_fq, conf_fq); ++} ++ ++int __hot dpa_tx_extended(struct sk_buff *skb, struct net_device *net_dev, ++ struct qman_fq *egress_fq, struct qman_fq *conf_fq) ++{ ++ struct dpa_priv_s *priv; ++ struct qm_fd fd; ++ struct dpa_percpu_priv_s *percpu_priv; ++ struct rtnl_link_stats64 *percpu_stats; ++ int err = 0; ++ bool nonlinear; ++ int *countptr, offset = 0; ++ ++ priv = netdev_priv(net_dev); ++ /* Non-migratable context, safe to use raw_cpu_ptr */ ++ percpu_priv = raw_cpu_ptr(priv->percpu_priv); ++ percpu_stats = &percpu_priv->stats; ++ countptr = raw_cpu_ptr(priv->dpa_bp->percpu_count); ++ ++ clear_fd(&fd); ++ ++#ifndef CONFIG_PPC ++ if (unlikely(dpaa_errata_a010022) && a010022_check_skb(skb, priv)) { ++ skb = a010022_realign_skb(skb, priv); ++ if (!skb) ++ goto skb_to_fd_failed; ++ } ++#endif ++ ++ nonlinear = skb_is_nonlinear(skb); ++ ++#ifdef CONFIG_FSL_DPAA_1588 ++ if (priv->tsu && priv->tsu->valid && priv->tsu->hwts_tx_en_ioctl) ++ fd.cmd |= FM_FD_CMD_UPD; ++#endif ++#ifdef CONFIG_FSL_DPAA_TS ++ if (unlikely(priv->ts_tx_en && ++ skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) ++ fd.cmd |= FM_FD_CMD_UPD; ++ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; ++#endif /* CONFIG_FSL_DPAA_TS */ ++ ++ /* MAX_SKB_FRAGS is larger than our DPA_SGT_MAX_ENTRIES; make sure ++ * we don't feed FMan with more fragments than it supports. ++ * Btw, we're using the first sgt entry to store the linear part of ++ * the skb, so we're one extra frag short. ++ */ ++ if (nonlinear && ++ likely(skb_shinfo(skb)->nr_frags < DPA_SGT_MAX_ENTRIES)) { ++ /* Just create a S/G fd based on the skb */ ++ err = skb_to_sg_fd(priv, skb, &fd); ++ percpu_priv->tx_frag_skbuffs++; ++ } else { ++ /* Make sure we have enough headroom to accommodate private ++ * data, parse results, etc. Normally this shouldn't happen if ++ * we're here via the standard kernel stack. ++ */ ++ if (unlikely(skb_headroom(skb) < priv->tx_headroom)) { ++ struct sk_buff *skb_new; ++ ++ skb_new = skb_realloc_headroom(skb, priv->tx_headroom); ++ if (unlikely(!skb_new)) { ++ dev_kfree_skb(skb); ++ percpu_stats->tx_errors++; ++ return NETDEV_TX_OK; ++ } ++ dev_kfree_skb(skb); ++ skb = skb_new; ++ } ++ ++ /* We're going to store the skb backpointer at the beginning ++ * of the data buffer, so we need a privately owned skb ++ */ ++ ++ /* Code borrowed from skb_unshare(). */ ++ if (skb_cloned(skb)) { ++ struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); ++ kfree_skb(skb); ++ skb = nskb; ++#ifndef CONFIG_PPC ++ if (unlikely(dpaa_errata_a010022) && ++ a010022_check_skb(skb, priv)) { ++ skb = a010022_realign_skb(skb, priv); ++ if (!skb) ++ goto skb_to_fd_failed; ++ } ++#endif ++ /* skb_copy() has now linearized the skbuff. */ ++ } else if (unlikely(nonlinear)) { ++ /* We are here because the egress skb contains ++ * more fragments than we support. In this case, ++ * we have no choice but to linearize it ourselves. ++ */ ++ err = __skb_linearize(skb); ++ } ++ if (unlikely(!skb || err < 0)) ++ /* Common out-of-memory error path */ ++ goto enomem; ++ ++ err = skb_to_contig_fd(priv, skb, &fd, countptr, &offset); ++ } ++ if (unlikely(err < 0)) ++ goto skb_to_fd_failed; ++ ++ if (fd.bpid != 0xff) { ++ skb_recycle(skb); ++ /* skb_recycle() reserves NET_SKB_PAD as skb headroom, ++ * but we need the skb to look as if returned by build_skb(). ++ * We need to manually adjust the tailptr as well. ++ */ ++ skb->data = skb->head + offset; ++ skb_reset_tail_pointer(skb); ++ ++ (*countptr)++; ++ percpu_priv->tx_returned++; ++ } ++ ++ if (unlikely(dpa_xmit(priv, percpu_stats, &fd, egress_fq, conf_fq) < 0)) ++ goto xmit_failed; ++ ++ netif_trans_update(net_dev); ++ return NETDEV_TX_OK; ++ ++xmit_failed: ++ if (fd.bpid != 0xff) { ++ (*countptr)--; ++ percpu_priv->tx_returned--; ++ dpa_fd_release(net_dev, &fd); ++ percpu_stats->tx_errors++; ++ return NETDEV_TX_OK; ++ } ++ _dpa_cleanup_tx_fd(priv, &fd); ++skb_to_fd_failed: ++enomem: ++ percpu_stats->tx_errors++; ++ dev_kfree_skb(skb); ++ return NETDEV_TX_OK; ++} ++EXPORT_SYMBOL(dpa_tx_extended); +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sysfs.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sysfs.c +new file mode 100644 +index 00000000..3542d0b2 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sysfs.c +@@ -0,0 +1,278 @@ ++/* Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "dpaa_eth.h" ++#include "mac.h" /* struct mac_device */ ++#ifdef CONFIG_FSL_DPAA_1588 ++#include "dpaa_1588.h" ++#endif ++ ++static ssize_t dpaa_eth_show_addr(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev)); ++ struct mac_device *mac_dev = priv->mac_dev; ++ ++ if (mac_dev) ++ return sprintf(buf, "%llx", ++ (unsigned long long)mac_dev->res->start); ++ else ++ return sprintf(buf, "none"); ++} ++ ++static ssize_t dpaa_eth_show_type(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev)); ++ ssize_t res = 0; ++ ++ if (priv) ++ res = sprintf(buf, "%s", priv->if_type); ++ ++ return res; ++} ++ ++static ssize_t dpaa_eth_show_fqids(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev)); ++ ssize_t bytes = 0; ++ int i = 0; ++ char *str; ++ struct dpa_fq *fq; ++ struct dpa_fq *tmp; ++ struct dpa_fq *prev = NULL; ++ u32 first_fqid = 0; ++ u32 last_fqid = 0; ++ char *prevstr = NULL; ++ ++ list_for_each_entry_safe(fq, tmp, &priv->dpa_fq_list, list) { ++ switch (fq->fq_type) { ++ case FQ_TYPE_RX_DEFAULT: ++ str = "Rx default"; ++ break; ++ case FQ_TYPE_RX_ERROR: ++ str = "Rx error"; ++ break; ++ case FQ_TYPE_RX_PCD: ++ str = "Rx PCD"; ++ break; ++ case FQ_TYPE_TX_CONFIRM: ++ str = "Tx default confirmation"; ++ break; ++ case FQ_TYPE_TX_CONF_MQ: ++ str = "Tx confirmation (mq)"; ++ break; ++ case FQ_TYPE_TX_ERROR: ++ str = "Tx error"; ++ break; ++ case FQ_TYPE_TX: ++ str = "Tx"; ++ break; ++ case FQ_TYPE_RX_PCD_HI_PRIO: ++ str ="Rx PCD High Priority"; ++ break; ++ default: ++ str = "Unknown"; ++ } ++ ++ if (prev && (abs(fq->fqid - prev->fqid) != 1 || ++ str != prevstr)) { ++ if (last_fqid == first_fqid) ++ bytes += sprintf(buf + bytes, ++ "%s: %d\n", prevstr, prev->fqid); ++ else ++ bytes += sprintf(buf + bytes, ++ "%s: %d - %d\n", prevstr, ++ first_fqid, last_fqid); ++ } ++ ++ if (prev && abs(fq->fqid - prev->fqid) == 1 && str == prevstr) ++ last_fqid = fq->fqid; ++ else ++ first_fqid = last_fqid = fq->fqid; ++ ++ prev = fq; ++ prevstr = str; ++ i++; ++ } ++ ++ if (prev) { ++ if (last_fqid == first_fqid) ++ bytes += sprintf(buf + bytes, "%s: %d\n", prevstr, ++ prev->fqid); ++ else ++ bytes += sprintf(buf + bytes, "%s: %d - %d\n", prevstr, ++ first_fqid, last_fqid); ++ } ++ ++ return bytes; ++} ++ ++static ssize_t dpaa_eth_show_bpids(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ ssize_t bytes = 0; ++ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev)); ++ struct dpa_bp *dpa_bp = priv->dpa_bp; ++ int i = 0; ++ ++ for (i = 0; i < priv->bp_count; i++) ++ bytes += snprintf(buf + bytes, PAGE_SIZE, "%u\n", ++ dpa_bp[i].bpid); ++ ++ return bytes; ++} ++ ++static ssize_t dpaa_eth_show_mac_regs(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev)); ++ struct mac_device *mac_dev = priv->mac_dev; ++ int n = 0; ++ ++ if (mac_dev) ++ n = fm_mac_dump_regs(mac_dev, buf, n); ++ else ++ return sprintf(buf, "no mac registers\n"); ++ ++ return n; ++} ++ ++static ssize_t dpaa_eth_show_mac_rx_stats(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev)); ++ struct mac_device *mac_dev = priv->mac_dev; ++ int n = 0; ++ ++ if (mac_dev) ++ n = fm_mac_dump_rx_stats(mac_dev, buf, n); ++ else ++ return sprintf(buf, "no mac rx stats\n"); ++ ++ return n; ++} ++ ++static ssize_t dpaa_eth_show_mac_tx_stats(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev)); ++ struct mac_device *mac_dev = priv->mac_dev; ++ int n = 0; ++ ++ if (mac_dev) ++ n = fm_mac_dump_tx_stats(mac_dev, buf, n); ++ else ++ return sprintf(buf, "no mac tx stats\n"); ++ ++ return n; ++} ++ ++#ifdef CONFIG_FSL_DPAA_1588 ++static ssize_t dpaa_eth_show_ptp_1588(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev)); ++ ++ if (priv->tsu && priv->tsu->valid) ++ return sprintf(buf, "1\n"); ++ else ++ return sprintf(buf, "0\n"); ++} ++ ++static ssize_t dpaa_eth_set_ptp_1588(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct dpa_priv_s *priv = netdev_priv(to_net_dev(dev)); ++ unsigned int num; ++ unsigned long flags; ++ ++ if (kstrtouint(buf, 0, &num) < 0) ++ return -EINVAL; ++ ++ local_irq_save(flags); ++ ++ if (num) { ++ if (priv->tsu) ++ priv->tsu->valid = TRUE; ++ } else { ++ if (priv->tsu) ++ priv->tsu->valid = FALSE; ++ } ++ ++ local_irq_restore(flags); ++ ++ return count; ++} ++#endif ++ ++static struct device_attribute dpaa_eth_attrs[] = { ++ __ATTR(device_addr, S_IRUGO, dpaa_eth_show_addr, NULL), ++ __ATTR(device_type, S_IRUGO, dpaa_eth_show_type, NULL), ++ __ATTR(fqids, S_IRUGO, dpaa_eth_show_fqids, NULL), ++ __ATTR(bpids, S_IRUGO, dpaa_eth_show_bpids, NULL), ++ __ATTR(mac_regs, S_IRUGO, dpaa_eth_show_mac_regs, NULL), ++ __ATTR(mac_rx_stats, S_IRUGO, dpaa_eth_show_mac_rx_stats, NULL), ++ __ATTR(mac_tx_stats, S_IRUGO, dpaa_eth_show_mac_tx_stats, NULL), ++#ifdef CONFIG_FSL_DPAA_1588 ++ __ATTR(ptp_1588, S_IRUGO | S_IWUSR, dpaa_eth_show_ptp_1588, ++ dpaa_eth_set_ptp_1588), ++#endif ++}; ++ ++void dpaa_eth_sysfs_init(struct device *dev) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(dpaa_eth_attrs); i++) ++ if (device_create_file(dev, &dpaa_eth_attrs[i])) { ++ dev_err(dev, "Error creating sysfs file\n"); ++ while (i > 0) ++ device_remove_file(dev, &dpaa_eth_attrs[--i]); ++ return; ++ } ++} ++EXPORT_SYMBOL(dpaa_eth_sysfs_init); ++ ++void dpaa_eth_sysfs_remove(struct device *dev) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(dpaa_eth_attrs); i++) ++ device_remove_file(dev, &dpaa_eth_attrs[i]); ++} +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_trace.h b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_trace.h +new file mode 100644 +index 00000000..30069ef9 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_trace.h +@@ -0,0 +1,144 @@ ++/* Copyright 2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#undef TRACE_SYSTEM ++#define TRACE_SYSTEM dpaa_eth ++ ++#if !defined(_DPAA_ETH_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) ++#define _DPAA_ETH_TRACE_H ++ ++#include ++#include ++#include "dpaa_eth.h" ++#include ++ ++#define fd_format_name(format) { qm_fd_##format, #format } ++#define fd_format_list \ ++ fd_format_name(contig), \ ++ fd_format_name(sg) ++#define TR_FMT "[%s] fqid=%d, fd: addr=0x%llx, format=%s, off=%u, len=%u," \ ++ " status=0x%08x" ++ ++/* This is used to declare a class of events. ++ * individual events of this type will be defined below. ++ */ ++ ++/* Store details about a frame descriptor and the FQ on which it was ++ * transmitted/received. ++ */ ++DECLARE_EVENT_CLASS(dpaa_eth_fd, ++ /* Trace function prototype */ ++ TP_PROTO(struct net_device *netdev, ++ struct qman_fq *fq, ++ const struct qm_fd *fd), ++ ++ /* Repeat argument list here */ ++ TP_ARGS(netdev, fq, fd), ++ ++ /* A structure containing the relevant information we want to record. ++ * Declare name and type for each normal element, name, type and size ++ * for arrays. Use __string for variable length strings. ++ */ ++ TP_STRUCT__entry( ++ __field(u32, fqid) ++ __field(u64, fd_addr) ++ __field(u8, fd_format) ++ __field(u16, fd_offset) ++ __field(u32, fd_length) ++ __field(u32, fd_status) ++ __string(name, netdev->name) ++ ), ++ ++ /* The function that assigns values to the above declared fields */ ++ TP_fast_assign( ++ __entry->fqid = fq->fqid; ++ __entry->fd_addr = qm_fd_addr_get64(fd); ++ __entry->fd_format = fd->format; ++ __entry->fd_offset = dpa_fd_offset(fd); ++ __entry->fd_length = dpa_fd_length(fd); ++ __entry->fd_status = fd->status; ++ __assign_str(name, netdev->name); ++ ), ++ ++ /* This is what gets printed when the trace event is triggered */ ++ /* TODO: print the status using __print_flags() */ ++ TP_printk(TR_FMT, ++ __get_str(name), __entry->fqid, __entry->fd_addr, ++ __print_symbolic(__entry->fd_format, fd_format_list), ++ __entry->fd_offset, __entry->fd_length, __entry->fd_status) ++); ++ ++/* Now declare events of the above type. Format is: ++ * DEFINE_EVENT(class, name, proto, args), with proto and args same as for class ++ */ ++ ++/* Tx (egress) fd */ ++DEFINE_EVENT(dpaa_eth_fd, dpa_tx_fd, ++ ++ TP_PROTO(struct net_device *netdev, ++ struct qman_fq *fq, ++ const struct qm_fd *fd), ++ ++ TP_ARGS(netdev, fq, fd) ++); ++ ++/* Rx fd */ ++DEFINE_EVENT(dpaa_eth_fd, dpa_rx_fd, ++ ++ TP_PROTO(struct net_device *netdev, ++ struct qman_fq *fq, ++ const struct qm_fd *fd), ++ ++ TP_ARGS(netdev, fq, fd) ++); ++ ++/* Tx confirmation fd */ ++DEFINE_EVENT(dpaa_eth_fd, dpa_tx_conf_fd, ++ ++ TP_PROTO(struct net_device *netdev, ++ struct qman_fq *fq, ++ const struct qm_fd *fd), ++ ++ TP_ARGS(netdev, fq, fd) ++); ++ ++/* If only one event of a certain type needs to be declared, use TRACE_EVENT(). ++ * The syntax is the same as for DECLARE_EVENT_CLASS(). ++ */ ++ ++#endif /* _DPAA_ETH_TRACE_H */ ++ ++/* This must be outside ifdef _DPAA_ETH_TRACE_H */ ++#undef TRACE_INCLUDE_PATH ++#define TRACE_INCLUDE_PATH . ++#undef TRACE_INCLUDE_FILE ++#define TRACE_INCLUDE_FILE dpaa_eth_trace ++#include +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c +new file mode 100644 +index 00000000..4b784662 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethtool.c +@@ -0,0 +1,544 @@ ++/* Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG ++#define pr_fmt(fmt) \ ++ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \ ++ KBUILD_BASENAME".c", __LINE__, __func__ ++#else ++#define pr_fmt(fmt) \ ++ KBUILD_MODNAME ": " fmt ++#endif ++ ++#include ++ ++#include "dpaa_eth.h" ++#include "mac.h" /* struct mac_device */ ++#include "dpaa_eth_common.h" ++ ++static const char dpa_stats_percpu[][ETH_GSTRING_LEN] = { ++ "interrupts", ++ "rx packets", ++ "tx packets", ++ "tx recycled", ++ "tx confirm", ++ "tx S/G", ++ "rx S/G", ++ "tx error", ++ "rx error", ++ "bp count" ++}; ++ ++static char dpa_stats_global[][ETH_GSTRING_LEN] = { ++ /* dpa rx errors */ ++ "rx dma error", ++ "rx frame physical error", ++ "rx frame size error", ++ "rx header error", ++ "rx csum error", ++ ++ /* demultiplexing errors */ ++ "qman cg_tdrop", ++ "qman wred", ++ "qman error cond", ++ "qman early window", ++ "qman late window", ++ "qman fq tdrop", ++ "qman fq retired", ++ "qman orp disabled", ++ ++ /* congestion related stats */ ++ "congestion time (ms)", ++ "entered congestion", ++ "congested (0/1)" ++}; ++ ++#define DPA_STATS_PERCPU_LEN ARRAY_SIZE(dpa_stats_percpu) ++#define DPA_STATS_GLOBAL_LEN ARRAY_SIZE(dpa_stats_global) ++ ++static int __cold dpa_get_settings(struct net_device *net_dev, ++ struct ethtool_cmd *et_cmd) ++{ ++ int _errno; ++ struct dpa_priv_s *priv; ++ ++ priv = netdev_priv(net_dev); ++ ++ if (priv->mac_dev == NULL) { ++ netdev_info(net_dev, "This is a MAC-less interface\n"); ++ return -ENODEV; ++ } ++ if (unlikely(priv->mac_dev->phy_dev == NULL)) { ++ netdev_dbg(net_dev, "phy device not initialized\n"); ++ return 0; ++ } ++ ++ _errno = phy_ethtool_gset(priv->mac_dev->phy_dev, et_cmd); ++ if (unlikely(_errno < 0)) ++ netdev_err(net_dev, "phy_ethtool_gset() = %d\n", _errno); ++ ++ return _errno; ++} ++ ++static int __cold dpa_set_settings(struct net_device *net_dev, ++ struct ethtool_cmd *et_cmd) ++{ ++ int _errno; ++ struct dpa_priv_s *priv; ++ ++ priv = netdev_priv(net_dev); ++ ++ if (priv->mac_dev == NULL) { ++ netdev_info(net_dev, "This is a MAC-less interface\n"); ++ return -ENODEV; ++ } ++ if (unlikely(priv->mac_dev->phy_dev == NULL)) { ++ netdev_err(net_dev, "phy device not initialized\n"); ++ return -ENODEV; ++ } ++ ++ _errno = phy_ethtool_sset(priv->mac_dev->phy_dev, et_cmd); ++ if (unlikely(_errno < 0)) ++ netdev_err(net_dev, "phy_ethtool_sset() = %d\n", _errno); ++ ++ return _errno; ++} ++ ++static void __cold dpa_get_drvinfo(struct net_device *net_dev, ++ struct ethtool_drvinfo *drvinfo) ++{ ++ int _errno; ++ ++ strncpy(drvinfo->driver, KBUILD_MODNAME, ++ sizeof(drvinfo->driver) - 1)[sizeof(drvinfo->driver)-1] = 0; ++ _errno = snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), ++ "%X", 0); ++ ++ if (unlikely(_errno >= sizeof(drvinfo->fw_version))) { ++ /* Truncated output */ ++ netdev_notice(net_dev, "snprintf() = %d\n", _errno); ++ } else if (unlikely(_errno < 0)) { ++ netdev_warn(net_dev, "snprintf() = %d\n", _errno); ++ memset(drvinfo->fw_version, 0, sizeof(drvinfo->fw_version)); ++ } ++ strncpy(drvinfo->bus_info, dev_name(net_dev->dev.parent->parent), ++ sizeof(drvinfo->bus_info)-1)[sizeof(drvinfo->bus_info)-1] = 0; ++} ++ ++static uint32_t __cold dpa_get_msglevel(struct net_device *net_dev) ++{ ++ return ((struct dpa_priv_s *)netdev_priv(net_dev))->msg_enable; ++} ++ ++static void __cold dpa_set_msglevel(struct net_device *net_dev, ++ uint32_t msg_enable) ++{ ++ ((struct dpa_priv_s *)netdev_priv(net_dev))->msg_enable = msg_enable; ++} ++ ++static int __cold dpa_nway_reset(struct net_device *net_dev) ++{ ++ int _errno; ++ struct dpa_priv_s *priv; ++ ++ priv = netdev_priv(net_dev); ++ ++ if (priv->mac_dev == NULL) { ++ netdev_info(net_dev, "This is a MAC-less interface\n"); ++ return -ENODEV; ++ } ++ if (unlikely(priv->mac_dev->phy_dev == NULL)) { ++ netdev_err(net_dev, "phy device not initialized\n"); ++ return -ENODEV; ++ } ++ ++ _errno = 0; ++ if (priv->mac_dev->phy_dev->autoneg) { ++ _errno = phy_start_aneg(priv->mac_dev->phy_dev); ++ if (unlikely(_errno < 0)) ++ netdev_err(net_dev, "phy_start_aneg() = %d\n", ++ _errno); ++ } ++ ++ return _errno; ++} ++ ++static void __cold dpa_get_pauseparam(struct net_device *net_dev, ++ struct ethtool_pauseparam *epause) ++{ ++ struct dpa_priv_s *priv; ++ struct mac_device *mac_dev; ++ struct phy_device *phy_dev; ++ ++ priv = netdev_priv(net_dev); ++ mac_dev = priv->mac_dev; ++ ++ if (mac_dev == NULL) { ++ netdev_info(net_dev, "This is a MAC-less interface\n"); ++ return; ++ } ++ ++ phy_dev = mac_dev->phy_dev; ++ if (unlikely(phy_dev == NULL)) { ++ netdev_err(net_dev, "phy device not initialized\n"); ++ return; ++ } ++ ++ epause->autoneg = mac_dev->autoneg_pause; ++ epause->rx_pause = mac_dev->rx_pause_active; ++ epause->tx_pause = mac_dev->tx_pause_active; ++} ++ ++static int __cold dpa_set_pauseparam(struct net_device *net_dev, ++ struct ethtool_pauseparam *epause) ++{ ++ struct dpa_priv_s *priv; ++ struct mac_device *mac_dev; ++ struct phy_device *phy_dev; ++ int _errno; ++ u32 newadv, oldadv; ++ bool rx_pause, tx_pause; ++ ++ priv = netdev_priv(net_dev); ++ mac_dev = priv->mac_dev; ++ ++ if (mac_dev == NULL) { ++ netdev_info(net_dev, "This is a MAC-less interface\n"); ++ return -ENODEV; ++ } ++ ++ phy_dev = mac_dev->phy_dev; ++ if (unlikely(phy_dev == NULL)) { ++ netdev_err(net_dev, "phy device not initialized\n"); ++ return -ENODEV; ++ } ++ ++ if (!(phy_dev->supported & SUPPORTED_Pause) || ++ (!(phy_dev->supported & SUPPORTED_Asym_Pause) && ++ (epause->rx_pause != epause->tx_pause))) ++ return -EINVAL; ++ ++ /* The MAC should know how to handle PAUSE frame autonegotiation before ++ * adjust_link is triggered by a forced renegotiation of sym/asym PAUSE ++ * settings. ++ */ ++ mac_dev->autoneg_pause = !!epause->autoneg; ++ mac_dev->rx_pause_req = !!epause->rx_pause; ++ mac_dev->tx_pause_req = !!epause->tx_pause; ++ ++ /* Determine the sym/asym advertised PAUSE capabilities from the desired ++ * rx/tx pause settings. ++ */ ++ newadv = 0; ++ if (epause->rx_pause) ++ newadv = ADVERTISED_Pause | ADVERTISED_Asym_Pause; ++ if (epause->tx_pause) ++ newadv |= ADVERTISED_Asym_Pause; ++ ++ oldadv = phy_dev->advertising & ++ (ADVERTISED_Pause | ADVERTISED_Asym_Pause); ++ ++ /* If there are differences between the old and the new advertised ++ * values, restart PHY autonegotiation and advertise the new values. ++ */ ++ if (oldadv != newadv) { ++ phy_dev->advertising &= ~(ADVERTISED_Pause ++ | ADVERTISED_Asym_Pause); ++ phy_dev->advertising |= newadv; ++ if (phy_dev->autoneg) { ++ _errno = phy_start_aneg(phy_dev); ++ if (unlikely(_errno < 0)) ++ netdev_err(net_dev, "phy_start_aneg() = %d\n", ++ _errno); ++ } ++ } ++ ++ get_pause_cfg(mac_dev, &rx_pause, &tx_pause); ++ _errno = set_mac_active_pause(mac_dev, rx_pause, tx_pause); ++ if (unlikely(_errno < 0)) ++ netdev_err(net_dev, "set_mac_active_pause() = %d\n", _errno); ++ ++ return _errno; ++} ++ ++#ifdef CONFIG_PM ++static void dpa_get_wol(struct net_device *net_dev, struct ethtool_wolinfo *wol) ++{ ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ ++ wol->supported = 0; ++ wol->wolopts = 0; ++ ++ if (!priv->wol || !device_can_wakeup(net_dev->dev.parent)) ++ return; ++ ++ if (priv->wol & DPAA_WOL_MAGIC) { ++ wol->supported = WAKE_MAGIC; ++ wol->wolopts = WAKE_MAGIC; ++ } ++} ++ ++static int dpa_set_wol(struct net_device *net_dev, struct ethtool_wolinfo *wol) ++{ ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ ++ if (priv->mac_dev == NULL) { ++ netdev_info(net_dev, "This is a MAC-less interface\n"); ++ return -ENODEV; ++ } ++ ++ if (unlikely(priv->mac_dev->phy_dev == NULL)) { ++ netdev_dbg(net_dev, "phy device not initialized\n"); ++ return -ENODEV; ++ } ++ ++ if (!device_can_wakeup(net_dev->dev.parent) || ++ (wol->wolopts & ~WAKE_MAGIC)) ++ return -EOPNOTSUPP; ++ ++ priv->wol = 0; ++ ++ if (wol->wolopts & WAKE_MAGIC) { ++ priv->wol = DPAA_WOL_MAGIC; ++ device_set_wakeup_enable(net_dev->dev.parent, 1); ++ } else { ++ device_set_wakeup_enable(net_dev->dev.parent, 0); ++ } ++ ++ return 0; ++} ++#endif ++ ++static int dpa_get_eee(struct net_device *net_dev, struct ethtool_eee *et_eee) ++{ ++ struct dpa_priv_s *priv; ++ ++ priv = netdev_priv(net_dev); ++ if (priv->mac_dev == NULL) { ++ netdev_info(net_dev, "This is a MAC-less interface\n"); ++ return -ENODEV; ++ } ++ ++ if (unlikely(priv->mac_dev->phy_dev == NULL)) { ++ netdev_err(net_dev, "phy device not initialized\n"); ++ return -ENODEV; ++ } ++ ++ return phy_ethtool_get_eee(priv->mac_dev->phy_dev, et_eee); ++} ++ ++static int dpa_set_eee(struct net_device *net_dev, struct ethtool_eee *et_eee) ++{ ++ struct dpa_priv_s *priv; ++ ++ priv = netdev_priv(net_dev); ++ if (priv->mac_dev == NULL) { ++ netdev_info(net_dev, "This is a MAC-less interface\n"); ++ return -ENODEV; ++ } ++ ++ if (unlikely(priv->mac_dev->phy_dev == NULL)) { ++ netdev_err(net_dev, "phy device not initialized\n"); ++ return -ENODEV; ++ } ++ ++ return phy_ethtool_set_eee(priv->mac_dev->phy_dev, et_eee); ++} ++ ++static int dpa_get_sset_count(struct net_device *net_dev, int type) ++{ ++ unsigned int total_stats, num_stats; ++ ++ num_stats = num_online_cpus() + 1; ++ total_stats = num_stats * DPA_STATS_PERCPU_LEN + DPA_STATS_GLOBAL_LEN; ++ ++ switch (type) { ++ case ETH_SS_STATS: ++ return total_stats; ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static void copy_stats(struct dpa_percpu_priv_s *percpu_priv, int num_cpus, ++ int crr_cpu, u64 bp_count, u64 *data) ++{ ++ int num_stat_values = num_cpus + 1; ++ int crr_stat = 0; ++ ++ /* update current CPU's stats and also add them to the total values */ ++ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->in_interrupt; ++ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->in_interrupt; ++ ++ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->stats.rx_packets; ++ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->stats.rx_packets; ++ ++ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->stats.tx_packets; ++ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->stats.tx_packets; ++ ++ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->tx_returned; ++ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->tx_returned; ++ ++ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->tx_confirm; ++ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->tx_confirm; ++ ++ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->tx_frag_skbuffs; ++ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->tx_frag_skbuffs; ++ ++ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->rx_sg; ++ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->rx_sg; ++ ++ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->stats.tx_errors; ++ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->stats.tx_errors; ++ ++ data[crr_stat * num_stat_values + crr_cpu] = percpu_priv->stats.rx_errors; ++ data[crr_stat++ * num_stat_values + num_cpus] += percpu_priv->stats.rx_errors; ++ ++ data[crr_stat * num_stat_values + crr_cpu] = bp_count; ++ data[crr_stat++ * num_stat_values + num_cpus] += bp_count; ++} ++ ++static void dpa_get_ethtool_stats(struct net_device *net_dev, ++ struct ethtool_stats *stats, u64 *data) ++{ ++ u64 bp_count, cg_time, cg_num, cg_status; ++ struct dpa_percpu_priv_s *percpu_priv; ++ struct qm_mcr_querycgr query_cgr; ++ struct dpa_rx_errors rx_errors; ++ struct dpa_ern_cnt ern_cnt; ++ struct dpa_priv_s *priv; ++ unsigned int num_cpus, offset; ++ struct dpa_bp *dpa_bp; ++ int total_stats, i; ++ ++ total_stats = dpa_get_sset_count(net_dev, ETH_SS_STATS); ++ priv = netdev_priv(net_dev); ++ dpa_bp = priv->dpa_bp; ++ num_cpus = num_online_cpus(); ++ bp_count = 0; ++ ++ memset(&rx_errors, 0, sizeof(struct dpa_rx_errors)); ++ memset(&ern_cnt, 0, sizeof(struct dpa_ern_cnt)); ++ memset(data, 0, total_stats * sizeof(u64)); ++ ++ for_each_online_cpu(i) { ++ percpu_priv = per_cpu_ptr(priv->percpu_priv, i); ++ ++ if (dpa_bp->percpu_count) ++ bp_count = *(per_cpu_ptr(dpa_bp->percpu_count, i)); ++ ++ rx_errors.dme += percpu_priv->rx_errors.dme; ++ rx_errors.fpe += percpu_priv->rx_errors.fpe; ++ rx_errors.fse += percpu_priv->rx_errors.fse; ++ rx_errors.phe += percpu_priv->rx_errors.phe; ++ rx_errors.cse += percpu_priv->rx_errors.cse; ++ ++ ern_cnt.cg_tdrop += percpu_priv->ern_cnt.cg_tdrop; ++ ern_cnt.wred += percpu_priv->ern_cnt.wred; ++ ern_cnt.err_cond += percpu_priv->ern_cnt.err_cond; ++ ern_cnt.early_window += percpu_priv->ern_cnt.early_window; ++ ern_cnt.late_window += percpu_priv->ern_cnt.late_window; ++ ern_cnt.fq_tdrop += percpu_priv->ern_cnt.fq_tdrop; ++ ern_cnt.fq_retired += percpu_priv->ern_cnt.fq_retired; ++ ern_cnt.orp_zero += percpu_priv->ern_cnt.orp_zero; ++ ++ copy_stats(percpu_priv, num_cpus, i, bp_count, data); ++ } ++ ++ offset = (num_cpus + 1) * DPA_STATS_PERCPU_LEN; ++ memcpy(data + offset, &rx_errors, sizeof(struct dpa_rx_errors)); ++ ++ offset += sizeof(struct dpa_rx_errors) / sizeof(u64); ++ memcpy(data + offset, &ern_cnt, sizeof(struct dpa_ern_cnt)); ++ ++ /* gather congestion related counters */ ++ cg_num = 0; ++ cg_status = 0; ++ cg_time = jiffies_to_msecs(priv->cgr_data.congested_jiffies); ++ if (qman_query_cgr(&priv->cgr_data.cgr, &query_cgr) == 0) { ++ cg_num = priv->cgr_data.cgr_congested_count; ++ cg_status = query_cgr.cgr.cs; ++ ++ /* reset congestion stats (like QMan API does */ ++ priv->cgr_data.congested_jiffies = 0; ++ priv->cgr_data.cgr_congested_count = 0; ++ } ++ ++ offset += sizeof(struct dpa_ern_cnt) / sizeof(u64); ++ data[offset++] = cg_time; ++ data[offset++] = cg_num; ++ data[offset++] = cg_status; ++} ++ ++static void dpa_get_strings(struct net_device *net_dev, u32 stringset, u8 *data) ++{ ++ unsigned int i, j, num_cpus, size; ++ char stat_string_cpu[ETH_GSTRING_LEN]; ++ u8 *strings; ++ ++ strings = data; ++ num_cpus = num_online_cpus(); ++ size = DPA_STATS_GLOBAL_LEN * ETH_GSTRING_LEN; ++ ++ for (i = 0; i < DPA_STATS_PERCPU_LEN; i++) { ++ for (j = 0; j < num_cpus; j++) { ++ snprintf(stat_string_cpu, ETH_GSTRING_LEN, "%s [CPU %d]", dpa_stats_percpu[i], j); ++ memcpy(strings, stat_string_cpu, ETH_GSTRING_LEN); ++ strings += ETH_GSTRING_LEN; ++ } ++ snprintf(stat_string_cpu, ETH_GSTRING_LEN, "%s [TOTAL]", dpa_stats_percpu[i]); ++ memcpy(strings, stat_string_cpu, ETH_GSTRING_LEN); ++ strings += ETH_GSTRING_LEN; ++ } ++ memcpy(strings, dpa_stats_global, size); ++} ++ ++const struct ethtool_ops dpa_ethtool_ops = { ++ .get_settings = dpa_get_settings, ++ .set_settings = dpa_set_settings, ++ .get_drvinfo = dpa_get_drvinfo, ++ .get_msglevel = dpa_get_msglevel, ++ .set_msglevel = dpa_set_msglevel, ++ .nway_reset = dpa_nway_reset, ++ .get_pauseparam = dpa_get_pauseparam, ++ .set_pauseparam = dpa_set_pauseparam, ++ .self_test = NULL, /* TODO invoke the cold-boot unit-test? */ ++ .get_link = ethtool_op_get_link, ++ .get_eee = dpa_get_eee, ++ .set_eee = dpa_set_eee, ++ .get_sset_count = dpa_get_sset_count, ++ .get_ethtool_stats = dpa_get_ethtool_stats, ++ .get_strings = dpa_get_strings, ++#ifdef CONFIG_PM ++ .get_wol = dpa_get_wol, ++ .set_wol = dpa_set_wol, ++#endif ++}; +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ptp.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ptp.c +new file mode 100644 +index 00000000..f54a3d67 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ptp.c +@@ -0,0 +1,291 @@ ++/* ++ * DPAA Ethernet Driver -- PTP 1588 clock using the dTSEC ++ * ++ * Author: Yangbo Lu ++ * ++ * Copyright 2014 Freescale Semiconductor, 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "dpaa_eth.h" ++#include "mac.h" ++ ++static struct mac_device *mac_dev; ++static u32 freqCompensation; ++ ++/* Bit definitions for the TMR_CTRL register */ ++#define ALM1P (1<<31) /* Alarm1 output polarity */ ++#define ALM2P (1<<30) /* Alarm2 output polarity */ ++#define FS (1<<28) /* FIPER start indication */ ++#define PP1L (1<<27) /* Fiper1 pulse loopback mode enabled. */ ++#define PP2L (1<<26) /* Fiper2 pulse loopback mode enabled. */ ++#define TCLK_PERIOD_SHIFT (16) /* 1588 timer reference clock period. */ ++#define TCLK_PERIOD_MASK (0x3ff) ++#define RTPE (1<<15) /* Record Tx Timestamp to PAL Enable. */ ++#define FRD (1<<14) /* FIPER Realignment Disable */ ++#define ESFDP (1<<11) /* External Tx/Rx SFD Polarity. */ ++#define ESFDE (1<<10) /* External Tx/Rx SFD Enable. */ ++#define ETEP2 (1<<9) /* External trigger 2 edge polarity */ ++#define ETEP1 (1<<8) /* External trigger 1 edge polarity */ ++#define COPH (1<<7) /* Generated clock output phase. */ ++#define CIPH (1<<6) /* External oscillator input clock phase */ ++#define TMSR (1<<5) /* Timer soft reset. */ ++#define BYP (1<<3) /* Bypass drift compensated clock */ ++#define TE (1<<2) /* 1588 timer enable. */ ++#define CKSEL_SHIFT (0) /* 1588 Timer reference clock source */ ++#define CKSEL_MASK (0x3) ++ ++/* Bit definitions for the TMR_TEVENT register */ ++#define ETS2 (1<<25) /* External trigger 2 timestamp sampled */ ++#define ETS1 (1<<24) /* External trigger 1 timestamp sampled */ ++#define ALM2 (1<<17) /* Current time = alarm time register 2 */ ++#define ALM1 (1<<16) /* Current time = alarm time register 1 */ ++#define PP1 (1<<7) /* periodic pulse generated on FIPER1 */ ++#define PP2 (1<<6) /* periodic pulse generated on FIPER2 */ ++#define PP3 (1<<5) /* periodic pulse generated on FIPER3 */ ++ ++/* Bit definitions for the TMR_TEMASK register */ ++#define ETS2EN (1<<25) /* External trigger 2 timestamp enable */ ++#define ETS1EN (1<<24) /* External trigger 1 timestamp enable */ ++#define ALM2EN (1<<17) /* Timer ALM2 event enable */ ++#define ALM1EN (1<<16) /* Timer ALM1 event enable */ ++#define PP1EN (1<<7) /* Periodic pulse event 1 enable */ ++#define PP2EN (1<<6) /* Periodic pulse event 2 enable */ ++ ++/* Bit definitions for the TMR_PEVENT register */ ++#define TXP2 (1<<9) /* PTP transmitted timestamp im TXTS2 */ ++#define TXP1 (1<<8) /* PTP transmitted timestamp in TXTS1 */ ++#define RXP (1<<0) /* PTP frame has been received */ ++ ++/* Bit definitions for the TMR_PEMASK register */ ++#define TXP2EN (1<<9) /* Transmit PTP packet event 2 enable */ ++#define TXP1EN (1<<8) /* Transmit PTP packet event 1 enable */ ++#define RXPEN (1<<0) /* Receive PTP packet event enable */ ++ ++/* Bit definitions for the TMR_STAT register */ ++#define STAT_VEC_SHIFT (0) /* Timer general purpose status vector */ ++#define STAT_VEC_MASK (0x3f) ++ ++/* Bit definitions for the TMR_PRSC register */ ++#define PRSC_OCK_SHIFT (0) /* Output clock division/prescale factor. */ ++#define PRSC_OCK_MASK (0xffff) ++ ++ ++#define N_EXT_TS 2 ++ ++static void set_alarm(void) ++{ ++ u64 ns; ++ ++ if (mac_dev->fm_rtc_get_cnt) ++ mac_dev->fm_rtc_get_cnt(mac_dev->fm_dev, &ns); ++ ns += 1500000000ULL; ++ ns = div_u64(ns, 1000000000UL) * 1000000000ULL; ++ ns -= DPA_PTP_NOMINAL_FREQ_PERIOD_NS; ++ if (mac_dev->fm_rtc_set_alarm) ++ mac_dev->fm_rtc_set_alarm(mac_dev->fm_dev, 0, ns); ++} ++ ++static void set_fipers(void) ++{ ++ u64 fiper; ++ ++ if (mac_dev->fm_rtc_disable) ++ mac_dev->fm_rtc_disable(mac_dev->fm_dev); ++ ++ set_alarm(); ++ fiper = 1000000000ULL - DPA_PTP_NOMINAL_FREQ_PERIOD_NS; ++ if (mac_dev->fm_rtc_set_fiper) ++ mac_dev->fm_rtc_set_fiper(mac_dev->fm_dev, 0, fiper); ++ ++ if (mac_dev->fm_rtc_enable) ++ mac_dev->fm_rtc_enable(mac_dev->fm_dev); ++} ++ ++/* PTP clock operations */ ++ ++static int ptp_dpa_adjfreq(struct ptp_clock_info *ptp, s32 ppb) ++{ ++ u64 adj; ++ u32 diff, tmr_add; ++ int neg_adj = 0; ++ ++ if (ppb < 0) { ++ neg_adj = 1; ++ ppb = -ppb; ++ } ++ ++ tmr_add = freqCompensation; ++ adj = tmr_add; ++ adj *= ppb; ++ diff = div_u64(adj, 1000000000ULL); ++ ++ tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff; ++ ++ if (mac_dev->fm_rtc_set_drift) ++ mac_dev->fm_rtc_set_drift(mac_dev->fm_dev, tmr_add); ++ ++ return 0; ++} ++ ++static int ptp_dpa_adjtime(struct ptp_clock_info *ptp, s64 delta) ++{ ++ s64 now; ++ ++ if (mac_dev->fm_rtc_get_cnt) ++ mac_dev->fm_rtc_get_cnt(mac_dev->fm_dev, &now); ++ ++ now += delta; ++ ++ if (mac_dev->fm_rtc_set_cnt) ++ mac_dev->fm_rtc_set_cnt(mac_dev->fm_dev, now); ++ set_fipers(); ++ ++ return 0; ++} ++ ++static int ptp_dpa_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) ++{ ++ u64 ns; ++ u32 remainder; ++ ++ if (mac_dev->fm_rtc_get_cnt) ++ mac_dev->fm_rtc_get_cnt(mac_dev->fm_dev, &ns); ++ ++ ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder); ++ ts->tv_nsec = remainder; ++ return 0; ++} ++ ++static int ptp_dpa_settime(struct ptp_clock_info *ptp, ++ const struct timespec64 *ts) ++{ ++ u64 ns; ++ ++ ns = ts->tv_sec * 1000000000ULL; ++ ns += ts->tv_nsec; ++ ++ if (mac_dev->fm_rtc_set_cnt) ++ mac_dev->fm_rtc_set_cnt(mac_dev->fm_dev, ns); ++ set_fipers(); ++ return 0; ++} ++ ++static int ptp_dpa_enable(struct ptp_clock_info *ptp, ++ struct ptp_clock_request *rq, int on) ++{ ++ u32 bit; ++ ++ switch (rq->type) { ++ case PTP_CLK_REQ_EXTTS: ++ switch (rq->extts.index) { ++ case 0: ++ bit = ETS1EN; ++ break; ++ case 1: ++ bit = ETS2EN; ++ break; ++ default: ++ return -EINVAL; ++ } ++ if (on) { ++ if (mac_dev->fm_rtc_enable_interrupt) ++ mac_dev->fm_rtc_enable_interrupt( ++ mac_dev->fm_dev, bit); ++ } else { ++ if (mac_dev->fm_rtc_disable_interrupt) ++ mac_dev->fm_rtc_disable_interrupt( ++ mac_dev->fm_dev, bit); ++ } ++ return 0; ++ ++ case PTP_CLK_REQ_PPS: ++ if (on) { ++ if (mac_dev->fm_rtc_enable_interrupt) ++ mac_dev->fm_rtc_enable_interrupt( ++ mac_dev->fm_dev, PP1EN); ++ } else { ++ if (mac_dev->fm_rtc_disable_interrupt) ++ mac_dev->fm_rtc_disable_interrupt( ++ mac_dev->fm_dev, PP1EN); ++ } ++ return 0; ++ ++ default: ++ break; ++ } ++ ++ return -EOPNOTSUPP; ++} ++ ++static struct ptp_clock_info ptp_dpa_caps = { ++ .owner = THIS_MODULE, ++ .name = "dpaa clock", ++ .max_adj = 512000, ++ .n_alarm = 0, ++ .n_ext_ts = N_EXT_TS, ++ .n_per_out = 0, ++ .pps = 1, ++ .adjfreq = ptp_dpa_adjfreq, ++ .adjtime = ptp_dpa_adjtime, ++ .gettime64 = ptp_dpa_gettime, ++ .settime64 = ptp_dpa_settime, ++ .enable = ptp_dpa_enable, ++}; ++ ++static int __init __cold dpa_ptp_load(void) ++{ ++ struct device *ptp_dev; ++ struct timespec64 now; ++ struct ptp_clock *clock = ptp_priv.clock; ++ int dpa_phc_index; ++ int err; ++ ++ if (!(ptp_priv.of_dev && ptp_priv.mac_dev)) ++ return -ENODEV; ++ ++ ptp_dev = &ptp_priv.of_dev->dev; ++ mac_dev = ptp_priv.mac_dev; ++ ++ if (mac_dev->fm_rtc_get_drift) ++ mac_dev->fm_rtc_get_drift(mac_dev->fm_dev, &freqCompensation); ++ ++ getnstimeofday64(&now); ++ ptp_dpa_settime(&ptp_dpa_caps, &now); ++ ++ clock = ptp_clock_register(&ptp_dpa_caps, ptp_dev); ++ if (IS_ERR(clock)) { ++ err = PTR_ERR(clock); ++ return err; ++ } ++ dpa_phc_index = ptp_clock_index(clock); ++ return 0; ++} ++module_init(dpa_ptp_load); ++ ++static void __exit __cold dpa_ptp_unload(void) ++{ ++ struct ptp_clock *clock = ptp_priv.clock; ++ ++ if (mac_dev->fm_rtc_disable_interrupt) ++ mac_dev->fm_rtc_disable_interrupt(mac_dev->fm_dev, 0xffffffff); ++ ptp_clock_unregister(clock); ++} ++module_exit(dpa_ptp_unload); +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c b/drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c +new file mode 100644 +index 00000000..2c5652d9 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/mac-api.c +@@ -0,0 +1,907 @@ ++/* Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG ++#define pr_fmt(fmt) \ ++ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \ ++ KBUILD_BASENAME".c", __LINE__, __func__ ++#else ++#define pr_fmt(fmt) \ ++ KBUILD_MODNAME ": " fmt ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "dpaa_eth.h" ++#include "mac.h" ++#include "lnxwrp_fsl_fman.h" ++ ++#include "error_ext.h" /* GET_ERROR_TYPE, E_OK */ ++ ++#include "fsl_fman_dtsec.h" ++#include "fsl_fman_tgec.h" ++#include "fsl_fman_memac.h" ++#include "../sdk_fman/src/wrapper/lnxwrp_sysfs_fm.h" ++ ++#define MAC_DESCRIPTION "FSL FMan MAC API based driver" ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++ ++MODULE_AUTHOR("Emil Medve "); ++ ++MODULE_DESCRIPTION(MAC_DESCRIPTION); ++ ++struct mac_priv_s { ++ struct fm_mac_dev *fm_mac; ++}; ++ ++const char *mac_driver_description __initconst = MAC_DESCRIPTION; ++const size_t mac_sizeof_priv[] = { ++ [DTSEC] = sizeof(struct mac_priv_s), ++ [XGMAC] = sizeof(struct mac_priv_s), ++ [MEMAC] = sizeof(struct mac_priv_s) ++}; ++ ++static const enet_mode_t _100[] = { ++ [PHY_INTERFACE_MODE_MII] = e_ENET_MODE_MII_100, ++ [PHY_INTERFACE_MODE_RMII] = e_ENET_MODE_RMII_100 ++}; ++ ++static const enet_mode_t _1000[] = { ++ [PHY_INTERFACE_MODE_GMII] = e_ENET_MODE_GMII_1000, ++ [PHY_INTERFACE_MODE_SGMII] = e_ENET_MODE_SGMII_1000, ++ [PHY_INTERFACE_MODE_QSGMII] = e_ENET_MODE_QSGMII_1000, ++ [PHY_INTERFACE_MODE_TBI] = e_ENET_MODE_TBI_1000, ++ [PHY_INTERFACE_MODE_RGMII] = e_ENET_MODE_RGMII_1000, ++ [PHY_INTERFACE_MODE_RGMII_ID] = e_ENET_MODE_RGMII_1000, ++ [PHY_INTERFACE_MODE_RGMII_RXID] = e_ENET_MODE_RGMII_1000, ++ [PHY_INTERFACE_MODE_RGMII_TXID] = e_ENET_MODE_RGMII_1000, ++ [PHY_INTERFACE_MODE_RTBI] = e_ENET_MODE_RTBI_1000 ++}; ++ ++static enet_mode_t __cold __attribute__((nonnull)) ++macdev2enetinterface(const struct mac_device *mac_dev) ++{ ++ switch (mac_dev->max_speed) { ++ case SPEED_100: ++ return _100[mac_dev->phy_if]; ++ case SPEED_1000: ++ return _1000[mac_dev->phy_if]; ++ case SPEED_2500: ++ return e_ENET_MODE_SGMII_2500; ++ case SPEED_10000: ++ return e_ENET_MODE_XGMII_10000; ++ default: ++ return e_ENET_MODE_MII_100; ++ } ++} ++ ++static void mac_exception(handle_t _mac_dev, e_FmMacExceptions exception) ++{ ++ struct mac_device *mac_dev; ++ ++ mac_dev = (struct mac_device *)_mac_dev; ++ ++ if (e_FM_MAC_EX_10G_RX_FIFO_OVFL == exception) { ++ /* don't flag RX FIFO after the first */ ++ fm_mac_set_exception(mac_dev->get_mac_handle(mac_dev), ++ e_FM_MAC_EX_10G_RX_FIFO_OVFL, false); ++ dev_err(mac_dev->dev, "10G MAC got RX FIFO Error = %x\n", ++ exception); ++ } ++ ++ dev_dbg(mac_dev->dev, "%s:%s() -> %d\n", KBUILD_BASENAME".c", __func__, ++ exception); ++} ++ ++static int __cold init(struct mac_device *mac_dev) ++{ ++ int _errno; ++ struct mac_priv_s *priv; ++ t_FmMacParams param; ++ uint32_t version; ++ ++ priv = macdev_priv(mac_dev); ++ ++ param.baseAddr = (typeof(param.baseAddr))(uintptr_t)devm_ioremap( ++ mac_dev->dev, mac_dev->res->start, 0x2000); ++ param.enetMode = macdev2enetinterface(mac_dev); ++ memcpy(¶m.addr, mac_dev->addr, min(sizeof(param.addr), ++ sizeof(mac_dev->addr))); ++ param.macId = mac_dev->cell_index; ++ param.h_Fm = (handle_t)mac_dev->fm; ++ param.mdioIrq = NO_IRQ; ++ param.f_Exception = mac_exception; ++ param.f_Event = mac_exception; ++ param.h_App = mac_dev; ++ ++ priv->fm_mac = fm_mac_config(¶m); ++ if (unlikely(priv->fm_mac == NULL)) { ++ _errno = -EINVAL; ++ goto _return; ++ } ++ ++ fm_mac_set_handle(mac_dev->fm_dev, priv->fm_mac, ++ (macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) ? ++ param.macId : param.macId + FM_MAX_NUM_OF_1G_MACS); ++ ++ _errno = fm_mac_config_max_frame_length(priv->fm_mac, ++ fm_get_max_frm()); ++ if (unlikely(_errno < 0)) ++ goto _return_fm_mac_free; ++ ++ if (macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) { ++ /* 10G always works with pad and CRC */ ++ _errno = fm_mac_config_pad_and_crc(priv->fm_mac, true); ++ if (unlikely(_errno < 0)) ++ goto _return_fm_mac_free; ++ ++ _errno = fm_mac_config_half_duplex(priv->fm_mac, ++ mac_dev->half_duplex); ++ if (unlikely(_errno < 0)) ++ goto _return_fm_mac_free; ++ } else { ++ _errno = fm_mac_config_reset_on_init(priv->fm_mac, true); ++ if (unlikely(_errno < 0)) ++ goto _return_fm_mac_free; ++ } ++ ++ _errno = fm_mac_init(priv->fm_mac); ++ if (unlikely(_errno < 0)) ++ goto _return_fm_mac_free; ++ ++#ifndef CONFIG_FMAN_MIB_CNT_OVF_IRQ_EN ++ /* For 1G MAC, disable by default the MIB counters overflow interrupt */ ++ if (macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) { ++ _errno = fm_mac_set_exception(mac_dev->get_mac_handle(mac_dev), ++ e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL, FALSE); ++ if (unlikely(_errno < 0)) ++ goto _return_fm_mac_free; ++ } ++#endif /* !CONFIG_FMAN_MIB_CNT_OVF_IRQ_EN */ ++ ++ /* For 10G MAC, disable Tx ECC exception */ ++ if (macdev2enetinterface(mac_dev) == e_ENET_MODE_XGMII_10000) { ++ _errno = fm_mac_set_exception(mac_dev->get_mac_handle(mac_dev), ++ e_FM_MAC_EX_10G_1TX_ECC_ER, FALSE); ++ if (unlikely(_errno < 0)) ++ goto _return_fm_mac_free; ++ } ++ ++ _errno = fm_mac_get_version(priv->fm_mac, &version); ++ if (unlikely(_errno < 0)) ++ goto _return_fm_mac_free; ++ ++ dev_info(mac_dev->dev, "FMan %s version: 0x%08x\n", ++ ((macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) ? ++ "dTSEC" : "XGEC"), version); ++ ++ goto _return; ++ ++ ++_return_fm_mac_free: ++ fm_mac_free(mac_dev->get_mac_handle(mac_dev)); ++ ++_return: ++ return _errno; ++} ++ ++static int __cold memac_init(struct mac_device *mac_dev) ++{ ++ int _errno; ++ struct mac_priv_s *priv; ++ t_FmMacParams param; ++ ++ priv = macdev_priv(mac_dev); ++ ++ param.baseAddr = (typeof(param.baseAddr))(uintptr_t)devm_ioremap( ++ mac_dev->dev, mac_dev->res->start, 0x2000); ++ param.enetMode = macdev2enetinterface(mac_dev); ++ memcpy(¶m.addr, mac_dev->addr, sizeof(mac_dev->addr)); ++ param.macId = mac_dev->cell_index; ++ param.h_Fm = (handle_t)mac_dev->fm; ++ param.mdioIrq = NO_IRQ; ++ param.f_Exception = mac_exception; ++ param.f_Event = mac_exception; ++ param.h_App = mac_dev; ++ ++ priv->fm_mac = fm_mac_config(¶m); ++ if (unlikely(priv->fm_mac == NULL)) { ++ _errno = -EINVAL; ++ goto _return; ++ } ++ ++ fm_mac_set_handle(mac_dev->fm_dev, priv->fm_mac, ++ (macdev2enetinterface(mac_dev) != e_ENET_MODE_XGMII_10000) ? ++ param.macId : param.macId + FM_MAX_NUM_OF_1G_MACS); ++ ++ _errno = fm_mac_config_max_frame_length(priv->fm_mac, fm_get_max_frm()); ++ if (unlikely(_errno < 0)) ++ goto _return_fm_mac_free; ++ ++ _errno = fm_mac_config_reset_on_init(priv->fm_mac, true); ++ if (unlikely(_errno < 0)) ++ goto _return_fm_mac_free; ++ ++ _errno = fm_mac_init(priv->fm_mac); ++ if (unlikely(_errno < 0)) ++ goto _return_fm_mac_free; ++ ++ dev_info(mac_dev->dev, "FMan MEMAC\n"); ++ ++ goto _return; ++ ++_return_fm_mac_free: ++ fm_mac_free(priv->fm_mac); ++ ++_return: ++ return _errno; ++} ++ ++static int __cold start(struct mac_device *mac_dev) ++{ ++ int _errno; ++ struct phy_device *phy_dev = mac_dev->phy_dev; ++ ++ _errno = fm_mac_enable(mac_dev->get_mac_handle(mac_dev)); ++ ++ if (!_errno && phy_dev) ++ phy_start(phy_dev); ++ ++ return _errno; ++} ++ ++static int __cold stop(struct mac_device *mac_dev) ++{ ++ if (mac_dev->phy_dev) ++ phy_stop(mac_dev->phy_dev); ++ ++ return fm_mac_disable(mac_dev->get_mac_handle(mac_dev)); ++} ++ ++static int __cold set_multi(struct net_device *net_dev, ++ struct mac_device *mac_dev) ++{ ++ struct mac_priv_s *mac_priv; ++ struct mac_address *old_addr, *tmp; ++ struct netdev_hw_addr *ha; ++ int _errno; ++ ++ mac_priv = macdev_priv(mac_dev); ++ ++ /* Clear previous address list */ ++ list_for_each_entry_safe(old_addr, tmp, &mac_dev->mc_addr_list, list) { ++ _errno = fm_mac_remove_hash_mac_addr(mac_priv->fm_mac, ++ (t_EnetAddr *)old_addr->addr); ++ if (_errno < 0) ++ return _errno; ++ ++ list_del(&old_addr->list); ++ kfree(old_addr); ++ } ++ ++ /* Add all the addresses from the new list */ ++ netdev_for_each_mc_addr(ha, net_dev) { ++ _errno = fm_mac_add_hash_mac_addr(mac_priv->fm_mac, ++ (t_EnetAddr *)ha->addr); ++ if (_errno < 0) ++ return _errno; ++ ++ tmp = kmalloc(sizeof(struct mac_address), GFP_ATOMIC); ++ if (!tmp) { ++ dev_err(mac_dev->dev, "Out of memory\n"); ++ return -ENOMEM; ++ } ++ memcpy(tmp->addr, ha->addr, ETH_ALEN); ++ list_add(&tmp->list, &mac_dev->mc_addr_list); ++ } ++ return 0; ++} ++ ++/* Avoid redundant calls to FMD, if the MAC driver already contains the desired ++ * active PAUSE settings. Otherwise, the new active settings should be reflected ++ * in FMan. ++ */ ++int set_mac_active_pause(struct mac_device *mac_dev, bool rx, bool tx) ++{ ++ struct fm_mac_dev *fm_mac_dev = mac_dev->get_mac_handle(mac_dev); ++ int _errno = 0; ++ ++ if (unlikely(rx != mac_dev->rx_pause_active)) { ++ _errno = fm_mac_set_rx_pause_frames(fm_mac_dev, rx); ++ if (likely(_errno == 0)) ++ mac_dev->rx_pause_active = rx; ++ } ++ ++ if (unlikely(tx != mac_dev->tx_pause_active)) { ++ _errno = fm_mac_set_tx_pause_frames(fm_mac_dev, tx); ++ if (likely(_errno == 0)) ++ mac_dev->tx_pause_active = tx; ++ } ++ ++ return _errno; ++} ++EXPORT_SYMBOL(set_mac_active_pause); ++ ++/* Determine the MAC RX/TX PAUSE frames settings based on PHY ++ * autonegotiation or values set by eththool. ++ */ ++void get_pause_cfg(struct mac_device *mac_dev, bool *rx_pause, bool *tx_pause) ++{ ++ struct phy_device *phy_dev = mac_dev->phy_dev; ++ u16 lcl_adv, rmt_adv; ++ u8 flowctrl; ++ ++ *rx_pause = *tx_pause = false; ++ ++ if (!phy_dev->duplex) ++ return; ++ ++ /* If PAUSE autonegotiation is disabled, the TX/RX PAUSE settings ++ * are those set by ethtool. ++ */ ++ if (!mac_dev->autoneg_pause) { ++ *rx_pause = mac_dev->rx_pause_req; ++ *tx_pause = mac_dev->tx_pause_req; ++ return; ++ } ++ ++ /* Else if PAUSE autonegotiation is enabled, the TX/RX PAUSE ++ * settings depend on the result of the link negotiation. ++ */ ++ ++ /* get local capabilities */ ++ lcl_adv = 0; ++ if (phy_dev->advertising & ADVERTISED_Pause) ++ lcl_adv |= ADVERTISE_PAUSE_CAP; ++ if (phy_dev->advertising & ADVERTISED_Asym_Pause) ++ lcl_adv |= ADVERTISE_PAUSE_ASYM; ++ ++ /* get link partner capabilities */ ++ rmt_adv = 0; ++ if (phy_dev->pause) ++ rmt_adv |= LPA_PAUSE_CAP; ++ if (phy_dev->asym_pause) ++ rmt_adv |= LPA_PAUSE_ASYM; ++ ++ /* Calculate TX/RX settings based on local and peer advertised ++ * symmetric/asymmetric PAUSE capabilities. ++ */ ++ flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); ++ if (flowctrl & FLOW_CTRL_RX) ++ *rx_pause = true; ++ if (flowctrl & FLOW_CTRL_TX) ++ *tx_pause = true; ++} ++EXPORT_SYMBOL(get_pause_cfg); ++ ++static void adjust_link_void(struct net_device *net_dev) ++{ ++} ++ ++static void adjust_link(struct net_device *net_dev) ++{ ++ struct dpa_priv_s *priv = netdev_priv(net_dev); ++ struct mac_device *mac_dev = priv->mac_dev; ++ struct phy_device *phy_dev = mac_dev->phy_dev; ++ struct fm_mac_dev *fm_mac_dev; ++ bool rx_pause, tx_pause; ++ int _errno; ++ ++ fm_mac_dev = mac_dev->get_mac_handle(mac_dev); ++ fm_mac_adjust_link(fm_mac_dev, phy_dev->link, phy_dev->speed, ++ phy_dev->duplex); ++ ++ get_pause_cfg(mac_dev, &rx_pause, &tx_pause); ++ _errno = set_mac_active_pause(mac_dev, rx_pause, tx_pause); ++ if (unlikely(_errno < 0)) ++ netdev_err(net_dev, "set_mac_active_pause() = %d\n", _errno); ++} ++ ++/* Initializes driver's PHY state, and attaches to the PHY. ++ * Returns 0 on success. ++ */ ++static int dtsec_init_phy(struct net_device *net_dev, ++ struct mac_device *mac_dev) ++{ ++ struct phy_device *phy_dev; ++ ++ if (of_phy_is_fixed_link(mac_dev->phy_node)) ++ phy_dev = of_phy_attach(net_dev, mac_dev->phy_node, ++ 0, mac_dev->phy_if); ++ else ++ phy_dev = of_phy_connect(net_dev, mac_dev->phy_node, ++ &adjust_link, 0, mac_dev->phy_if); ++ if (unlikely(phy_dev == NULL) || IS_ERR(phy_dev)) { ++ netdev_err(net_dev, "Could not connect to PHY %s\n", ++ mac_dev->phy_node ? ++ mac_dev->phy_node->full_name : ++ mac_dev->fixed_bus_id); ++ return phy_dev == NULL ? -ENODEV : PTR_ERR(phy_dev); ++ } ++ ++ /* Remove any features not supported by the controller */ ++ phy_dev->supported &= mac_dev->if_support; ++ /* Enable the symmetric and asymmetric PAUSE frame advertisements, ++ * as most of the PHY drivers do not enable them by default. ++ */ ++ phy_dev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); ++ phy_dev->advertising = phy_dev->supported; ++ ++ mac_dev->phy_dev = phy_dev; ++ ++ return 0; ++} ++ ++static int xgmac_init_phy(struct net_device *net_dev, ++ struct mac_device *mac_dev) ++{ ++ struct phy_device *phy_dev; ++ ++ if (of_phy_is_fixed_link(mac_dev->phy_node)) ++ phy_dev = of_phy_attach(net_dev, mac_dev->phy_node, ++ 0, mac_dev->phy_if); ++ else ++ phy_dev = of_phy_connect(net_dev, mac_dev->phy_node, ++ &adjust_link_void, 0, mac_dev->phy_if); ++ if (unlikely(phy_dev == NULL) || IS_ERR(phy_dev)) { ++ netdev_err(net_dev, "Could not attach to PHY %s\n", ++ mac_dev->phy_node ? ++ mac_dev->phy_node->full_name : ++ mac_dev->fixed_bus_id); ++ return phy_dev == NULL ? -ENODEV : PTR_ERR(phy_dev); ++ } ++ ++ phy_dev->supported &= mac_dev->if_support; ++ /* Enable the symmetric and asymmetric PAUSE frame advertisements, ++ * as most of the PHY drivers do not enable them by default. ++ */ ++ phy_dev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); ++ phy_dev->advertising = phy_dev->supported; ++ ++ mac_dev->phy_dev = phy_dev; ++ ++ return 0; ++} ++ ++static int memac_init_phy(struct net_device *net_dev, ++ struct mac_device *mac_dev) ++{ ++ struct phy_device *phy_dev; ++ ++ if ((macdev2enetinterface(mac_dev) == e_ENET_MODE_XGMII_10000) || ++ (macdev2enetinterface(mac_dev) == e_ENET_MODE_SGMII_2500) || ++ of_phy_is_fixed_link(mac_dev->phy_node)) { ++ phy_dev = of_phy_connect(net_dev, mac_dev->phy_node, ++ &adjust_link_void, 0, ++ mac_dev->phy_if); ++ } else { ++ phy_dev = of_phy_connect(net_dev, mac_dev->phy_node, ++ &adjust_link, 0, mac_dev->phy_if); ++ } ++ ++ if (unlikely(phy_dev == NULL) || IS_ERR(phy_dev)) { ++ netdev_err(net_dev, "Could not connect to PHY %s\n", ++ mac_dev->phy_node ? ++ mac_dev->phy_node->full_name : ++ mac_dev->fixed_bus_id); ++ return phy_dev == NULL ? -ENODEV : PTR_ERR(phy_dev); ++ } ++ ++ /* Remove any features not supported by the controller */ ++ phy_dev->supported &= mac_dev->if_support; ++ /* Enable the symmetric and asymmetric PAUSE frame advertisements, ++ * as most of the PHY drivers do not enable them by default. ++ */ ++ phy_dev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); ++ phy_dev->advertising = phy_dev->supported; ++ ++ mac_dev->phy_dev = phy_dev; ++ ++ return 0; ++} ++ ++static int __cold uninit(struct fm_mac_dev *fm_mac_dev) ++{ ++ int _errno, __errno; ++ ++ _errno = fm_mac_disable(fm_mac_dev); ++ __errno = fm_mac_free(fm_mac_dev); ++ ++ if (unlikely(__errno < 0)) ++ _errno = __errno; ++ ++ return _errno; ++} ++ ++static struct fm_mac_dev *get_mac_handle(struct mac_device *mac_dev) ++{ ++ const struct mac_priv_s *priv; ++ priv = macdev_priv(mac_dev); ++ return priv->fm_mac; ++} ++ ++static int dtsec_dump_regs(struct mac_device *h_mac, char *buf, int nn) ++{ ++ struct dtsec_regs *p_mm = (struct dtsec_regs *) h_mac->vaddr; ++ int i = 0, n = nn; ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ ++ FM_DMP_TITLE(buf, n, p_mm, "FM MAC - DTSEC-%d", h_mac->cell_index); ++ ++ FM_DMP_V32(buf, n, p_mm, tsec_id); ++ FM_DMP_V32(buf, n, p_mm, tsec_id2); ++ FM_DMP_V32(buf, n, p_mm, ievent); ++ FM_DMP_V32(buf, n, p_mm, imask); ++ FM_DMP_V32(buf, n, p_mm, ecntrl); ++ FM_DMP_V32(buf, n, p_mm, ptv); ++ FM_DMP_V32(buf, n, p_mm, tmr_ctrl); ++ FM_DMP_V32(buf, n, p_mm, tmr_pevent); ++ FM_DMP_V32(buf, n, p_mm, tmr_pemask); ++ FM_DMP_V32(buf, n, p_mm, tctrl); ++ FM_DMP_V32(buf, n, p_mm, rctrl); ++ FM_DMP_V32(buf, n, p_mm, maccfg1); ++ FM_DMP_V32(buf, n, p_mm, maccfg2); ++ FM_DMP_V32(buf, n, p_mm, ipgifg); ++ FM_DMP_V32(buf, n, p_mm, hafdup); ++ FM_DMP_V32(buf, n, p_mm, maxfrm); ++ ++ FM_DMP_V32(buf, n, p_mm, macstnaddr1); ++ FM_DMP_V32(buf, n, p_mm, macstnaddr2); ++ ++ for (i = 0; i < 7; ++i) { ++ FM_DMP_V32(buf, n, p_mm, macaddr[i].exact_match1); ++ FM_DMP_V32(buf, n, p_mm, macaddr[i].exact_match2); ++ } ++ ++ FM_DMP_V32(buf, n, p_mm, car1); ++ FM_DMP_V32(buf, n, p_mm, car2); ++ ++ return n; ++} ++ ++static int xgmac_dump_regs(struct mac_device *h_mac, char *buf, int nn) ++{ ++ struct tgec_regs *p_mm = (struct tgec_regs *) h_mac->vaddr; ++ int n = nn; ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ FM_DMP_TITLE(buf, n, p_mm, "FM MAC - TGEC -%d", h_mac->cell_index); ++ ++ FM_DMP_V32(buf, n, p_mm, tgec_id); ++ FM_DMP_V32(buf, n, p_mm, command_config); ++ FM_DMP_V32(buf, n, p_mm, mac_addr_0); ++ FM_DMP_V32(buf, n, p_mm, mac_addr_1); ++ FM_DMP_V32(buf, n, p_mm, maxfrm); ++ FM_DMP_V32(buf, n, p_mm, pause_quant); ++ FM_DMP_V32(buf, n, p_mm, rx_fifo_sections); ++ FM_DMP_V32(buf, n, p_mm, tx_fifo_sections); ++ FM_DMP_V32(buf, n, p_mm, rx_fifo_almost_f_e); ++ FM_DMP_V32(buf, n, p_mm, tx_fifo_almost_f_e); ++ FM_DMP_V32(buf, n, p_mm, hashtable_ctrl); ++ FM_DMP_V32(buf, n, p_mm, mdio_cfg_status); ++ FM_DMP_V32(buf, n, p_mm, mdio_command); ++ FM_DMP_V32(buf, n, p_mm, mdio_data); ++ FM_DMP_V32(buf, n, p_mm, mdio_regaddr); ++ FM_DMP_V32(buf, n, p_mm, status); ++ FM_DMP_V32(buf, n, p_mm, tx_ipg_len); ++ FM_DMP_V32(buf, n, p_mm, mac_addr_2); ++ FM_DMP_V32(buf, n, p_mm, mac_addr_3); ++ FM_DMP_V32(buf, n, p_mm, rx_fifo_ptr_rd); ++ FM_DMP_V32(buf, n, p_mm, rx_fifo_ptr_wr); ++ FM_DMP_V32(buf, n, p_mm, tx_fifo_ptr_rd); ++ FM_DMP_V32(buf, n, p_mm, tx_fifo_ptr_wr); ++ FM_DMP_V32(buf, n, p_mm, imask); ++ FM_DMP_V32(buf, n, p_mm, ievent); ++ ++ return n; ++} ++ ++static int memac_dump_regs(struct mac_device *h_mac, char *buf, int nn) ++{ ++ struct memac_regs *p_mm = (struct memac_regs *) h_mac->vaddr; ++ int i = 0, n = nn; ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ FM_DMP_TITLE(buf, n, p_mm, "FM MAC - MEMAC -%d", h_mac->cell_index); ++ ++ FM_DMP_V32(buf, n, p_mm, command_config); ++ FM_DMP_V32(buf, n, p_mm, mac_addr0.mac_addr_l); ++ FM_DMP_V32(buf, n, p_mm, mac_addr0.mac_addr_u); ++ FM_DMP_V32(buf, n, p_mm, maxfrm); ++ FM_DMP_V32(buf, n, p_mm, hashtable_ctrl); ++ FM_DMP_V32(buf, n, p_mm, ievent); ++ FM_DMP_V32(buf, n, p_mm, tx_ipg_length); ++ FM_DMP_V32(buf, n, p_mm, imask); ++ ++ for (i = 0; i < 4; ++i) ++ FM_DMP_V32(buf, n, p_mm, pause_quanta[i]); ++ ++ for (i = 0; i < 4; ++i) ++ FM_DMP_V32(buf, n, p_mm, pause_thresh[i]); ++ ++ FM_DMP_V32(buf, n, p_mm, rx_pause_status); ++ ++ for (i = 0; i < MEMAC_NUM_OF_PADDRS; ++i) { ++ FM_DMP_V32(buf, n, p_mm, mac_addr[i].mac_addr_l); ++ FM_DMP_V32(buf, n, p_mm, mac_addr[i].mac_addr_u); ++ } ++ ++ FM_DMP_V32(buf, n, p_mm, lpwake_timer); ++ FM_DMP_V32(buf, n, p_mm, sleep_timer); ++ FM_DMP_V32(buf, n, p_mm, statn_config); ++ FM_DMP_V32(buf, n, p_mm, if_mode); ++ FM_DMP_V32(buf, n, p_mm, if_status); ++ FM_DMP_V32(buf, n, p_mm, hg_config); ++ FM_DMP_V32(buf, n, p_mm, hg_pause_quanta); ++ FM_DMP_V32(buf, n, p_mm, hg_pause_thresh); ++ FM_DMP_V32(buf, n, p_mm, hgrx_pause_status); ++ FM_DMP_V32(buf, n, p_mm, hg_fifos_status); ++ FM_DMP_V32(buf, n, p_mm, rhm); ++ FM_DMP_V32(buf, n, p_mm, thm); ++ ++ return n; ++} ++ ++static int memac_dump_regs_rx(struct mac_device *h_mac, char *buf, int nn) ++{ ++ struct memac_regs *p_mm = (struct memac_regs *) h_mac->vaddr; ++ int n = nn; ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ FM_DMP_TITLE(buf, n, p_mm, "FM MAC - MEMAC -%d Rx stats", h_mac->cell_index); ++ ++ /* Rx Statistics Counter */ ++ FM_DMP_V32(buf, n, p_mm, reoct_l); ++ FM_DMP_V32(buf, n, p_mm, reoct_u); ++ FM_DMP_V32(buf, n, p_mm, roct_l); ++ FM_DMP_V32(buf, n, p_mm, roct_u); ++ FM_DMP_V32(buf, n, p_mm, raln_l); ++ FM_DMP_V32(buf, n, p_mm, raln_u); ++ FM_DMP_V32(buf, n, p_mm, rxpf_l); ++ FM_DMP_V32(buf, n, p_mm, rxpf_u); ++ FM_DMP_V32(buf, n, p_mm, rfrm_l); ++ FM_DMP_V32(buf, n, p_mm, rfrm_u); ++ FM_DMP_V32(buf, n, p_mm, rfcs_l); ++ FM_DMP_V32(buf, n, p_mm, rfcs_u); ++ FM_DMP_V32(buf, n, p_mm, rvlan_l); ++ FM_DMP_V32(buf, n, p_mm, rvlan_u); ++ FM_DMP_V32(buf, n, p_mm, rerr_l); ++ FM_DMP_V32(buf, n, p_mm, rerr_u); ++ FM_DMP_V32(buf, n, p_mm, ruca_l); ++ FM_DMP_V32(buf, n, p_mm, ruca_u); ++ FM_DMP_V32(buf, n, p_mm, rmca_l); ++ FM_DMP_V32(buf, n, p_mm, rmca_u); ++ FM_DMP_V32(buf, n, p_mm, rbca_l); ++ FM_DMP_V32(buf, n, p_mm, rbca_u); ++ FM_DMP_V32(buf, n, p_mm, rdrp_l); ++ FM_DMP_V32(buf, n, p_mm, rdrp_u); ++ FM_DMP_V32(buf, n, p_mm, rpkt_l); ++ FM_DMP_V32(buf, n, p_mm, rpkt_u); ++ FM_DMP_V32(buf, n, p_mm, rund_l); ++ FM_DMP_V32(buf, n, p_mm, rund_u); ++ FM_DMP_V32(buf, n, p_mm, r64_l); ++ FM_DMP_V32(buf, n, p_mm, r64_u); ++ FM_DMP_V32(buf, n, p_mm, r127_l); ++ FM_DMP_V32(buf, n, p_mm, r127_u); ++ FM_DMP_V32(buf, n, p_mm, r255_l); ++ FM_DMP_V32(buf, n, p_mm, r255_u); ++ FM_DMP_V32(buf, n, p_mm, r511_l); ++ FM_DMP_V32(buf, n, p_mm, r511_u); ++ FM_DMP_V32(buf, n, p_mm, r1023_l); ++ FM_DMP_V32(buf, n, p_mm, r1023_u); ++ FM_DMP_V32(buf, n, p_mm, r1518_l); ++ FM_DMP_V32(buf, n, p_mm, r1518_u); ++ FM_DMP_V32(buf, n, p_mm, r1519x_l); ++ FM_DMP_V32(buf, n, p_mm, r1519x_u); ++ FM_DMP_V32(buf, n, p_mm, rovr_l); ++ FM_DMP_V32(buf, n, p_mm, rovr_u); ++ FM_DMP_V32(buf, n, p_mm, rjbr_l); ++ FM_DMP_V32(buf, n, p_mm, rjbr_u); ++ FM_DMP_V32(buf, n, p_mm, rfrg_l); ++ FM_DMP_V32(buf, n, p_mm, rfrg_u); ++ FM_DMP_V32(buf, n, p_mm, rcnp_l); ++ FM_DMP_V32(buf, n, p_mm, rcnp_u); ++ FM_DMP_V32(buf, n, p_mm, rdrntp_l); ++ FM_DMP_V32(buf, n, p_mm, rdrntp_u); ++ ++ return n; ++} ++ ++static int memac_dump_regs_tx(struct mac_device *h_mac, char *buf, int nn) ++{ ++ struct memac_regs *p_mm = (struct memac_regs *) h_mac->vaddr; ++ int n = nn; ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ FM_DMP_TITLE(buf, n, p_mm, "FM MAC - MEMAC -%d Tx stats", h_mac->cell_index); ++ ++ ++ /* Tx Statistics Counter */ ++ FM_DMP_V32(buf, n, p_mm, teoct_l); ++ FM_DMP_V32(buf, n, p_mm, teoct_u); ++ FM_DMP_V32(buf, n, p_mm, toct_l); ++ FM_DMP_V32(buf, n, p_mm, toct_u); ++ FM_DMP_V32(buf, n, p_mm, txpf_l); ++ FM_DMP_V32(buf, n, p_mm, txpf_u); ++ FM_DMP_V32(buf, n, p_mm, tfrm_l); ++ FM_DMP_V32(buf, n, p_mm, tfrm_u); ++ FM_DMP_V32(buf, n, p_mm, tfcs_l); ++ FM_DMP_V32(buf, n, p_mm, tfcs_u); ++ FM_DMP_V32(buf, n, p_mm, tvlan_l); ++ FM_DMP_V32(buf, n, p_mm, tvlan_u); ++ FM_DMP_V32(buf, n, p_mm, terr_l); ++ FM_DMP_V32(buf, n, p_mm, terr_u); ++ FM_DMP_V32(buf, n, p_mm, tuca_l); ++ FM_DMP_V32(buf, n, p_mm, tuca_u); ++ FM_DMP_V32(buf, n, p_mm, tmca_l); ++ FM_DMP_V32(buf, n, p_mm, tmca_u); ++ FM_DMP_V32(buf, n, p_mm, tbca_l); ++ FM_DMP_V32(buf, n, p_mm, tbca_u); ++ FM_DMP_V32(buf, n, p_mm, tpkt_l); ++ FM_DMP_V32(buf, n, p_mm, tpkt_u); ++ FM_DMP_V32(buf, n, p_mm, tund_l); ++ FM_DMP_V32(buf, n, p_mm, tund_u); ++ FM_DMP_V32(buf, n, p_mm, t64_l); ++ FM_DMP_V32(buf, n, p_mm, t64_u); ++ FM_DMP_V32(buf, n, p_mm, t127_l); ++ FM_DMP_V32(buf, n, p_mm, t127_u); ++ FM_DMP_V32(buf, n, p_mm, t255_l); ++ FM_DMP_V32(buf, n, p_mm, t255_u); ++ FM_DMP_V32(buf, n, p_mm, t511_l); ++ FM_DMP_V32(buf, n, p_mm, t511_u); ++ FM_DMP_V32(buf, n, p_mm, t1023_l); ++ FM_DMP_V32(buf, n, p_mm, t1023_u); ++ FM_DMP_V32(buf, n, p_mm, t1518_l); ++ FM_DMP_V32(buf, n, p_mm, t1518_u); ++ FM_DMP_V32(buf, n, p_mm, t1519x_l); ++ FM_DMP_V32(buf, n, p_mm, t1519x_u); ++ FM_DMP_V32(buf, n, p_mm, tcnp_l); ++ FM_DMP_V32(buf, n, p_mm, tcnp_u); ++ ++ return n; ++} ++ ++int fm_mac_dump_regs(struct mac_device *h_mac, char *buf, int nn) ++{ ++ int n = nn; ++ ++ n = h_mac->dump_mac_regs(h_mac, buf, n); ++ ++ return n; ++} ++EXPORT_SYMBOL(fm_mac_dump_regs); ++ ++int fm_mac_dump_rx_stats(struct mac_device *h_mac, char *buf, int nn) ++{ ++ int n = nn; ++ ++ if(h_mac->dump_mac_rx_stats) ++ n = h_mac->dump_mac_rx_stats(h_mac, buf, n); ++ ++ return n; ++} ++EXPORT_SYMBOL(fm_mac_dump_rx_stats); ++ ++int fm_mac_dump_tx_stats(struct mac_device *h_mac, char *buf, int nn) ++{ ++ int n = nn; ++ ++ if(h_mac->dump_mac_tx_stats) ++ n = h_mac->dump_mac_tx_stats(h_mac, buf, n); ++ ++ return n; ++} ++EXPORT_SYMBOL(fm_mac_dump_tx_stats); ++ ++static void __cold setup_dtsec(struct mac_device *mac_dev) ++{ ++ mac_dev->init_phy = dtsec_init_phy; ++ mac_dev->init = init; ++ mac_dev->start = start; ++ mac_dev->stop = stop; ++ mac_dev->set_promisc = fm_mac_set_promiscuous; ++ mac_dev->change_addr = fm_mac_modify_mac_addr; ++ mac_dev->set_multi = set_multi; ++ mac_dev->uninit = uninit; ++ mac_dev->ptp_enable = fm_mac_enable_1588_time_stamp; ++ mac_dev->ptp_disable = fm_mac_disable_1588_time_stamp; ++ mac_dev->get_mac_handle = get_mac_handle; ++ mac_dev->set_tx_pause = fm_mac_set_tx_pause_frames; ++ mac_dev->set_rx_pause = fm_mac_set_rx_pause_frames; ++ mac_dev->fm_rtc_enable = fm_rtc_enable; ++ mac_dev->fm_rtc_disable = fm_rtc_disable; ++ mac_dev->fm_rtc_get_cnt = fm_rtc_get_cnt; ++ mac_dev->fm_rtc_set_cnt = fm_rtc_set_cnt; ++ mac_dev->fm_rtc_get_drift = fm_rtc_get_drift; ++ mac_dev->fm_rtc_set_drift = fm_rtc_set_drift; ++ mac_dev->fm_rtc_set_alarm = fm_rtc_set_alarm; ++ mac_dev->fm_rtc_set_fiper = fm_rtc_set_fiper; ++ mac_dev->set_wol = fm_mac_set_wol; ++ mac_dev->dump_mac_regs = dtsec_dump_regs; ++} ++ ++static void __cold setup_xgmac(struct mac_device *mac_dev) ++{ ++ mac_dev->init_phy = xgmac_init_phy; ++ mac_dev->init = init; ++ mac_dev->start = start; ++ mac_dev->stop = stop; ++ mac_dev->set_promisc = fm_mac_set_promiscuous; ++ mac_dev->change_addr = fm_mac_modify_mac_addr; ++ mac_dev->set_multi = set_multi; ++ mac_dev->uninit = uninit; ++ mac_dev->get_mac_handle = get_mac_handle; ++ mac_dev->set_tx_pause = fm_mac_set_tx_pause_frames; ++ mac_dev->set_rx_pause = fm_mac_set_rx_pause_frames; ++ mac_dev->set_wol = fm_mac_set_wol; ++ mac_dev->dump_mac_regs = xgmac_dump_regs; ++} ++ ++static void __cold setup_memac(struct mac_device *mac_dev) ++{ ++ mac_dev->init_phy = memac_init_phy; ++ mac_dev->init = memac_init; ++ mac_dev->start = start; ++ mac_dev->stop = stop; ++ mac_dev->set_promisc = fm_mac_set_promiscuous; ++ mac_dev->change_addr = fm_mac_modify_mac_addr; ++ mac_dev->set_multi = set_multi; ++ mac_dev->uninit = uninit; ++ mac_dev->get_mac_handle = get_mac_handle; ++ mac_dev->set_tx_pause = fm_mac_set_tx_pause_frames; ++ mac_dev->set_rx_pause = fm_mac_set_rx_pause_frames; ++ mac_dev->fm_rtc_enable = fm_rtc_enable; ++ mac_dev->fm_rtc_disable = fm_rtc_disable; ++ mac_dev->fm_rtc_get_cnt = fm_rtc_get_cnt; ++ mac_dev->fm_rtc_set_cnt = fm_rtc_set_cnt; ++ mac_dev->fm_rtc_get_drift = fm_rtc_get_drift; ++ mac_dev->fm_rtc_set_drift = fm_rtc_set_drift; ++ mac_dev->fm_rtc_set_alarm = fm_rtc_set_alarm; ++ mac_dev->fm_rtc_set_fiper = fm_rtc_set_fiper; ++ mac_dev->set_wol = fm_mac_set_wol; ++ mac_dev->dump_mac_regs = memac_dump_regs; ++ mac_dev->dump_mac_rx_stats = memac_dump_regs_rx; ++ mac_dev->dump_mac_tx_stats = memac_dump_regs_tx; ++} ++ ++void (*const mac_setup[])(struct mac_device *mac_dev) = { ++ [DTSEC] = setup_dtsec, ++ [XGMAC] = setup_xgmac, ++ [MEMAC] = setup_memac ++}; +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/mac.c b/drivers/net/ethernet/freescale/sdk_dpaa/mac.c +new file mode 100644 +index 00000000..60133b02 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/mac.c +@@ -0,0 +1,489 @@ ++/* Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG ++#define pr_fmt(fmt) \ ++ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \ ++ KBUILD_BASENAME".c", __LINE__, __func__ ++#else ++#define pr_fmt(fmt) \ ++ KBUILD_MODNAME ": " fmt ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "lnxwrp_fm_ext.h" ++ ++#include "mac.h" ++ ++#define DTSEC_SUPPORTED \ ++ (SUPPORTED_10baseT_Half \ ++ | SUPPORTED_10baseT_Full \ ++ | SUPPORTED_100baseT_Half \ ++ | SUPPORTED_100baseT_Full \ ++ | SUPPORTED_Autoneg \ ++ | SUPPORTED_Pause \ ++ | SUPPORTED_Asym_Pause \ ++ | SUPPORTED_MII) ++ ++static const char phy_str[][11] = { ++ [PHY_INTERFACE_MODE_MII] = "mii", ++ [PHY_INTERFACE_MODE_GMII] = "gmii", ++ [PHY_INTERFACE_MODE_SGMII] = "sgmii", ++ [PHY_INTERFACE_MODE_QSGMII] = "qsgmii", ++ [PHY_INTERFACE_MODE_TBI] = "tbi", ++ [PHY_INTERFACE_MODE_RMII] = "rmii", ++ [PHY_INTERFACE_MODE_RGMII] = "rgmii", ++ [PHY_INTERFACE_MODE_RGMII_ID] = "rgmii-id", ++ [PHY_INTERFACE_MODE_RGMII_RXID] = "rgmii-rxid", ++ [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid", ++ [PHY_INTERFACE_MODE_RTBI] = "rtbi", ++ [PHY_INTERFACE_MODE_XGMII] = "xgmii", ++ [PHY_INTERFACE_MODE_SGMII_2500] = "sgmii-2500", ++}; ++ ++static phy_interface_t __pure __attribute__((nonnull)) str2phy(const char *str) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(phy_str); i++) ++ if (strcmp(str, phy_str[i]) == 0) ++ return (phy_interface_t)i; ++ ++ return PHY_INTERFACE_MODE_MII; ++} ++ ++static const uint16_t phy2speed[] = { ++ [PHY_INTERFACE_MODE_MII] = SPEED_100, ++ [PHY_INTERFACE_MODE_GMII] = SPEED_1000, ++ [PHY_INTERFACE_MODE_SGMII] = SPEED_1000, ++ [PHY_INTERFACE_MODE_QSGMII] = SPEED_1000, ++ [PHY_INTERFACE_MODE_TBI] = SPEED_1000, ++ [PHY_INTERFACE_MODE_RMII] = SPEED_100, ++ [PHY_INTERFACE_MODE_RGMII] = SPEED_1000, ++ [PHY_INTERFACE_MODE_RGMII_ID] = SPEED_1000, ++ [PHY_INTERFACE_MODE_RGMII_RXID] = SPEED_1000, ++ [PHY_INTERFACE_MODE_RGMII_TXID] = SPEED_1000, ++ [PHY_INTERFACE_MODE_RTBI] = SPEED_1000, ++ [PHY_INTERFACE_MODE_XGMII] = SPEED_10000, ++ [PHY_INTERFACE_MODE_SGMII_2500] = SPEED_2500, ++}; ++ ++static struct mac_device * __cold ++alloc_macdev(struct device *dev, size_t sizeof_priv, ++ void (*setup)(struct mac_device *mac_dev)) ++{ ++ struct mac_device *mac_dev; ++ ++ mac_dev = devm_kzalloc(dev, sizeof(*mac_dev) + sizeof_priv, GFP_KERNEL); ++ if (unlikely(mac_dev == NULL)) ++ mac_dev = ERR_PTR(-ENOMEM); ++ else { ++ mac_dev->dev = dev; ++ dev_set_drvdata(dev, mac_dev); ++ setup(mac_dev); ++ } ++ ++ return mac_dev; ++} ++ ++static int __cold free_macdev(struct mac_device *mac_dev) ++{ ++ dev_set_drvdata(mac_dev->dev, NULL); ++ ++ return mac_dev->uninit(mac_dev->get_mac_handle(mac_dev)); ++} ++ ++static const struct of_device_id mac_match[] = { ++ [DTSEC] = { ++ .compatible = "fsl,fman-1g-mac" ++ }, ++ [XGMAC] = { ++ .compatible = "fsl,fman-10g-mac" ++ }, ++ [MEMAC] = { ++ .compatible = "fsl,fman-memac" ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, mac_match); ++ ++static int __cold mac_probe(struct platform_device *_of_dev) ++{ ++ int _errno, i; ++ struct device *dev; ++ struct device_node *mac_node, *dev_node; ++ struct mac_device *mac_dev; ++ struct platform_device *of_dev; ++ struct resource res; ++ const uint8_t *mac_addr; ++ const char *char_prop; ++ int nph; ++ u32 cell_index; ++ const struct of_device_id *match; ++ ++ dev = &_of_dev->dev; ++ mac_node = dev->of_node; ++ ++ match = of_match_device(mac_match, dev); ++ if (!match) ++ return -EINVAL; ++ ++ for (i = 0; i < ARRAY_SIZE(mac_match) - 1 && match != mac_match + i; ++ i++) ++ ; ++ BUG_ON(i >= ARRAY_SIZE(mac_match) - 1); ++ ++ mac_dev = alloc_macdev(dev, mac_sizeof_priv[i], mac_setup[i]); ++ if (IS_ERR(mac_dev)) { ++ _errno = PTR_ERR(mac_dev); ++ dev_err(dev, "alloc_macdev() = %d\n", _errno); ++ goto _return; ++ } ++ ++ INIT_LIST_HEAD(&mac_dev->mc_addr_list); ++ ++ /* Get the FM node */ ++ dev_node = of_get_parent(mac_node); ++ if (unlikely(dev_node == NULL)) { ++ dev_err(dev, "of_get_parent(%s) failed\n", ++ mac_node->full_name); ++ _errno = -EINVAL; ++ goto _return_dev_set_drvdata; ++ } ++ ++ of_dev = of_find_device_by_node(dev_node); ++ if (unlikely(of_dev == NULL)) { ++ dev_err(dev, "of_find_device_by_node(%s) failed\n", ++ dev_node->full_name); ++ _errno = -EINVAL; ++ goto _return_of_node_put; ++ } ++ ++ mac_dev->fm_dev = fm_bind(&of_dev->dev); ++ if (unlikely(mac_dev->fm_dev == NULL)) { ++ dev_err(dev, "fm_bind(%s) failed\n", dev_node->full_name); ++ _errno = -ENODEV; ++ goto _return_of_node_put; ++ } ++ ++ mac_dev->fm = (void *)fm_get_handle(mac_dev->fm_dev); ++ of_node_put(dev_node); ++ ++ /* Get the address of the memory mapped registers */ ++ _errno = of_address_to_resource(mac_node, 0, &res); ++ if (unlikely(_errno < 0)) { ++ dev_err(dev, "of_address_to_resource(%s) = %d\n", ++ mac_node->full_name, _errno); ++ goto _return_dev_set_drvdata; ++ } ++ ++ mac_dev->res = __devm_request_region( ++ dev, ++ fm_get_mem_region(mac_dev->fm_dev), ++ res.start, res.end + 1 - res.start, "mac"); ++ if (unlikely(mac_dev->res == NULL)) { ++ dev_err(dev, "__devm_request_mem_region(mac) failed\n"); ++ _errno = -EBUSY; ++ goto _return_dev_set_drvdata; ++ } ++ ++ mac_dev->vaddr = devm_ioremap(dev, mac_dev->res->start, ++ mac_dev->res->end + 1 ++ - mac_dev->res->start); ++ if (unlikely(mac_dev->vaddr == NULL)) { ++ dev_err(dev, "devm_ioremap() failed\n"); ++ _errno = -EIO; ++ goto _return_dev_set_drvdata; ++ } ++ ++#define TBIPA_OFFSET 0x1c ++#define TBIPA_DEFAULT_ADDR 5 /* override if used as external PHY addr. */ ++ mac_dev->tbi_node = of_parse_phandle(mac_node, "tbi-handle", 0); ++ if (mac_dev->tbi_node) { ++ u32 tbiaddr = TBIPA_DEFAULT_ADDR; ++ const __be32 *tbi_reg; ++ void __iomem *addr; ++ ++ tbi_reg = of_get_property(mac_dev->tbi_node, "reg", NULL); ++ if (tbi_reg) ++ tbiaddr = be32_to_cpup(tbi_reg); ++ addr = mac_dev->vaddr + TBIPA_OFFSET; ++ /* TODO: out_be32 does not exist on ARM */ ++ out_be32(addr, tbiaddr); ++ } ++ ++ if (!of_device_is_available(mac_node)) { ++ devm_iounmap(dev, mac_dev->vaddr); ++ __devm_release_region(dev, fm_get_mem_region(mac_dev->fm_dev), ++ res.start, res.end + 1 - res.start); ++ fm_unbind(mac_dev->fm_dev); ++ devm_kfree(dev, mac_dev); ++ dev_set_drvdata(dev, NULL); ++ return -ENODEV; ++ } ++ ++ /* Get the cell-index */ ++ _errno = of_property_read_u32(mac_node, "cell-index", &cell_index); ++ if (unlikely(_errno)) { ++ dev_err(dev, "Cannot read cell-index of mac node %s from device tree\n", ++ mac_node->full_name); ++ goto _return_dev_set_drvdata; ++ } ++ mac_dev->cell_index = (uint8_t)cell_index; ++ if (mac_dev->cell_index >= 8) ++ mac_dev->cell_index -= 8; ++ ++ /* Get the MAC address */ ++ mac_addr = of_get_mac_address(mac_node); ++ if (unlikely(mac_addr == NULL)) { ++ dev_err(dev, "of_get_mac_address(%s) failed\n", ++ mac_node->full_name); ++ _errno = -EINVAL; ++ goto _return_dev_set_drvdata; ++ } ++ memcpy(mac_dev->addr, mac_addr, sizeof(mac_dev->addr)); ++ ++ /* Verify the number of port handles */ ++ nph = of_count_phandle_with_args(mac_node, "fsl,fman-ports", NULL); ++ if (unlikely(nph < 0)) { ++ dev_err(dev, "Cannot read port handles of mac node %s from device tree\n", ++ mac_node->full_name); ++ _errno = nph; ++ goto _return_dev_set_drvdata; ++ } ++ ++ if (nph != ARRAY_SIZE(mac_dev->port_dev)) { ++ dev_err(dev, "Not supported number of port handles of mac node %s from device tree\n", ++ mac_node->full_name); ++ _errno = -EINVAL; ++ goto _return_dev_set_drvdata; ++ } ++ ++ for_each_port_device(i, mac_dev->port_dev) { ++ dev_node = of_parse_phandle(mac_node, "fsl,fman-ports", i); ++ if (unlikely(dev_node == NULL)) { ++ dev_err(dev, "Cannot find port node referenced by mac node %s from device tree\n", ++ mac_node->full_name); ++ _errno = -EINVAL; ++ goto _return_of_node_put; ++ } ++ ++ of_dev = of_find_device_by_node(dev_node); ++ if (unlikely(of_dev == NULL)) { ++ dev_err(dev, "of_find_device_by_node(%s) failed\n", ++ dev_node->full_name); ++ _errno = -EINVAL; ++ goto _return_of_node_put; ++ } ++ ++ mac_dev->port_dev[i] = fm_port_bind(&of_dev->dev); ++ if (unlikely(mac_dev->port_dev[i] == NULL)) { ++ dev_err(dev, "dev_get_drvdata(%s) failed\n", ++ dev_node->full_name); ++ _errno = -EINVAL; ++ goto _return_of_node_put; ++ } ++ of_node_put(dev_node); ++ } ++ ++ /* Get the PHY connection type */ ++ _errno = of_property_read_string(mac_node, "phy-connection-type", ++ &char_prop); ++ if (unlikely(_errno)) { ++ dev_warn(dev, ++ "Cannot read PHY connection type of mac node %s from device tree. Defaulting to MII\n", ++ mac_node->full_name); ++ mac_dev->phy_if = PHY_INTERFACE_MODE_MII; ++ } else ++ mac_dev->phy_if = str2phy(char_prop); ++ ++ mac_dev->link = false; ++ mac_dev->half_duplex = false; ++ mac_dev->speed = phy2speed[mac_dev->phy_if]; ++ mac_dev->max_speed = mac_dev->speed; ++ mac_dev->if_support = DTSEC_SUPPORTED; ++ /* We don't support half-duplex in SGMII mode */ ++ if (strstr(char_prop, "sgmii") || strstr(char_prop, "qsgmii") || ++ strstr(char_prop, "sgmii-2500")) ++ mac_dev->if_support &= ~(SUPPORTED_10baseT_Half | ++ SUPPORTED_100baseT_Half); ++ ++ /* Gigabit support (no half-duplex) */ ++ if (mac_dev->max_speed == SPEED_1000 || ++ mac_dev->max_speed == SPEED_2500) ++ mac_dev->if_support |= SUPPORTED_1000baseT_Full; ++ ++ /* The 10G interface only supports one mode */ ++ if (strstr(char_prop, "xgmii")) ++ mac_dev->if_support = SUPPORTED_10000baseT_Full; ++ ++ /* Get the rest of the PHY information */ ++ mac_dev->phy_node = of_parse_phandle(mac_node, "phy-handle", 0); ++ if (!mac_dev->phy_node) { ++ struct phy_device *phy; ++ ++ if (!of_phy_is_fixed_link(mac_node)) { ++ dev_err(dev, "Wrong PHY information of mac node %s\n", ++ mac_node->full_name); ++ goto _return_dev_set_drvdata; ++ } ++ ++ _errno = of_phy_register_fixed_link(mac_node); ++ if (_errno) ++ goto _return_dev_set_drvdata; ++ ++ mac_dev->fixed_link = devm_kzalloc(mac_dev->dev, ++ sizeof(*mac_dev->fixed_link), ++ GFP_KERNEL); ++ if (!mac_dev->fixed_link) ++ goto _return_dev_set_drvdata; ++ ++ mac_dev->phy_node = of_node_get(mac_node); ++ phy = of_phy_find_device(mac_dev->phy_node); ++ if (!phy) ++ goto _return_dev_set_drvdata; ++ ++ mac_dev->fixed_link->link = phy->link; ++ mac_dev->fixed_link->speed = phy->speed; ++ mac_dev->fixed_link->duplex = phy->duplex; ++ mac_dev->fixed_link->pause = phy->pause; ++ mac_dev->fixed_link->asym_pause = phy->asym_pause; ++ } ++ ++ _errno = mac_dev->init(mac_dev); ++ if (unlikely(_errno < 0)) { ++ dev_err(dev, "mac_dev->init() = %d\n", _errno); ++ goto _return_dev_set_drvdata; ++ } ++ ++ /* pause frame autonegotiation enabled*/ ++ mac_dev->autoneg_pause = true; ++ ++ /* by intializing the values to false, force FMD to enable PAUSE frames ++ * on RX and TX ++ */ ++ mac_dev->rx_pause_req = mac_dev->tx_pause_req = true; ++ mac_dev->rx_pause_active = mac_dev->tx_pause_active = false; ++ _errno = set_mac_active_pause(mac_dev, true, true); ++ if (unlikely(_errno < 0)) ++ dev_err(dev, "set_mac_active_pause() = %d\n", _errno); ++ ++ dev_info(dev, ++ "FMan MAC address: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n", ++ mac_dev->addr[0], mac_dev->addr[1], mac_dev->addr[2], ++ mac_dev->addr[3], mac_dev->addr[4], mac_dev->addr[5]); ++ ++ goto _return; ++ ++_return_of_node_put: ++ of_node_put(dev_node); ++_return_dev_set_drvdata: ++ dev_set_drvdata(dev, NULL); ++_return: ++ return _errno; ++} ++ ++static int __cold mac_remove(struct platform_device *of_dev) ++{ ++ int i, _errno; ++ struct device *dev; ++ struct mac_device *mac_dev; ++ ++ dev = &of_dev->dev; ++ mac_dev = (struct mac_device *)dev_get_drvdata(dev); ++ ++ for_each_port_device(i, mac_dev->port_dev) ++ fm_port_unbind(mac_dev->port_dev[i]); ++ ++ fm_unbind(mac_dev->fm_dev); ++ ++ _errno = free_macdev(mac_dev); ++ ++ return _errno; ++} ++ ++static struct platform_driver mac_driver = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = mac_match, ++ .owner = THIS_MODULE, ++ }, ++ .probe = mac_probe, ++ .remove = mac_remove ++}; ++ ++static int __init __cold mac_load(void) ++{ ++ int _errno; ++ ++ pr_debug(KBUILD_MODNAME ": -> %s:%s()\n", ++ KBUILD_BASENAME".c", __func__); ++ ++ pr_info(KBUILD_MODNAME ": %s\n", mac_driver_description); ++ ++ _errno = platform_driver_register(&mac_driver); ++ if (unlikely(_errno < 0)) { ++ pr_err(KBUILD_MODNAME ": %s:%hu:%s(): platform_driver_register() = %d\n", ++ KBUILD_BASENAME".c", __LINE__, __func__, _errno); ++ goto _return; ++ } ++ ++ goto _return; ++ ++_return: ++ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", ++ KBUILD_BASENAME".c", __func__); ++ ++ return _errno; ++} ++module_init(mac_load); ++ ++static void __exit __cold mac_unload(void) ++{ ++ pr_debug(KBUILD_MODNAME ": -> %s:%s()\n", ++ KBUILD_BASENAME".c", __func__); ++ ++ platform_driver_unregister(&mac_driver); ++ ++ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", ++ KBUILD_BASENAME".c", __func__); ++} ++module_exit(mac_unload); +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/mac.h b/drivers/net/ethernet/freescale/sdk_dpaa/mac.h +new file mode 100644 +index 00000000..b5288f2a +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/mac.h +@@ -0,0 +1,135 @@ ++/* Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __MAC_H ++#define __MAC_H ++ ++#include /* struct device, BUS_ID_SIZE */ ++#include /* ETH_ALEN */ ++#include /* phy_interface_t, struct phy_device */ ++#include ++ ++#include "lnxwrp_fsl_fman.h" /* struct port_device */ ++ ++enum {DTSEC, XGMAC, MEMAC}; ++ ++struct mac_device { ++ struct device *dev; ++ void *priv; ++ uint8_t cell_index; ++ struct resource *res; ++ void __iomem *vaddr; ++ uint8_t addr[ETH_ALEN]; ++ bool promisc; ++ ++ struct fm *fm_dev; ++ struct fm_port *port_dev[2]; ++ ++ phy_interface_t phy_if; ++ u32 if_support; ++ bool link; ++ bool half_duplex; ++ uint16_t speed; ++ uint16_t max_speed; ++ struct device_node *phy_node; ++ char fixed_bus_id[MII_BUS_ID_SIZE + 3]; ++ struct device_node *tbi_node; ++ struct phy_device *phy_dev; ++ void *fm; ++ /* List of multicast addresses */ ++ struct list_head mc_addr_list; ++ struct fixed_phy_status *fixed_link; ++ ++ bool autoneg_pause; ++ bool rx_pause_req; ++ bool tx_pause_req; ++ bool rx_pause_active; ++ bool tx_pause_active; ++ ++ struct fm_mac_dev *(*get_mac_handle)(struct mac_device *mac_dev); ++ int (*init_phy)(struct net_device *net_dev, struct mac_device *mac_dev); ++ int (*init)(struct mac_device *mac_dev); ++ int (*start)(struct mac_device *mac_dev); ++ int (*stop)(struct mac_device *mac_dev); ++ int (*set_promisc)(struct fm_mac_dev *fm_mac_dev, bool enable); ++ int (*change_addr)(struct fm_mac_dev *fm_mac_dev, uint8_t *addr); ++ int (*set_multi)(struct net_device *net_dev, ++ struct mac_device *mac_dev); ++ int (*uninit)(struct fm_mac_dev *fm_mac_dev); ++ int (*ptp_enable)(struct fm_mac_dev *fm_mac_dev); ++ int (*ptp_disable)(struct fm_mac_dev *fm_mac_dev); ++ int (*set_rx_pause)(struct fm_mac_dev *fm_mac_dev, bool en); ++ int (*set_tx_pause)(struct fm_mac_dev *fm_mac_dev, bool en); ++ int (*fm_rtc_enable)(struct fm *fm_dev); ++ int (*fm_rtc_disable)(struct fm *fm_dev); ++ int (*fm_rtc_get_cnt)(struct fm *fm_dev, uint64_t *ts); ++ int (*fm_rtc_set_cnt)(struct fm *fm_dev, uint64_t ts); ++ int (*fm_rtc_get_drift)(struct fm *fm_dev, uint32_t *drift); ++ int (*fm_rtc_set_drift)(struct fm *fm_dev, uint32_t drift); ++ int (*fm_rtc_set_alarm)(struct fm *fm_dev, uint32_t id, uint64_t time); ++ int (*fm_rtc_set_fiper)(struct fm *fm_dev, uint32_t id, ++ uint64_t fiper); ++#ifdef CONFIG_PTP_1588_CLOCK_DPAA ++ int (*fm_rtc_enable_interrupt)(struct fm *fm_dev, uint32_t events); ++ int (*fm_rtc_disable_interrupt)(struct fm *fm_dev, uint32_t events); ++#endif ++ int (*set_wol)(struct fm_port *port, struct fm_mac_dev *fm_mac_dev, ++ bool en); ++ int (*dump_mac_regs)(struct mac_device *h_mac, char *buf, int nn); ++ int (*dump_mac_rx_stats)(struct mac_device *h_mac, char *buf, int nn); ++ int (*dump_mac_tx_stats)(struct mac_device *h_mac, char *buf, int nn); ++}; ++ ++struct mac_address { ++ uint8_t addr[ETH_ALEN]; ++ struct list_head list; ++}; ++ ++#define get_fm_handle(net_dev) \ ++ (((struct dpa_priv_s *)netdev_priv(net_dev))->mac_dev->fm_dev) ++ ++#define for_each_port_device(i, port_dev) \ ++ for (i = 0; i < ARRAY_SIZE(port_dev); i++) ++ ++static inline __attribute((nonnull)) void *macdev_priv( ++ const struct mac_device *mac_dev) ++{ ++ return (void *)mac_dev + sizeof(*mac_dev); ++} ++ ++extern const char *mac_driver_description; ++extern const size_t mac_sizeof_priv[]; ++extern void (*const mac_setup[])(struct mac_device *mac_dev); ++ ++int set_mac_active_pause(struct mac_device *mac_dev, bool rx, bool tx); ++void get_pause_cfg(struct mac_device *mac_dev, bool *rx_pause, bool *tx_pause); ++ ++#endif /* __MAC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/offline_port.c b/drivers/net/ethernet/freescale/sdk_dpaa/offline_port.c +new file mode 100644 +index 00000000..fb084af5 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/offline_port.c +@@ -0,0 +1,848 @@ ++/* Copyright 2011-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* Offline Parsing / Host Command port driver for FSL QorIQ FMan. ++ * Validates device-tree configuration and sets up the offline ports. ++ */ ++ ++#ifdef CONFIG_FSL_DPAA_ETH_DEBUG ++#define pr_fmt(fmt) \ ++ KBUILD_MODNAME ": %s:%hu:%s() " fmt, \ ++ KBUILD_BASENAME".c", __LINE__, __func__ ++#else ++#define pr_fmt(fmt) \ ++ KBUILD_MODNAME ": " fmt ++#endif ++ ++ ++#include ++#include ++#include ++#include ++ ++#include "offline_port.h" ++#include "dpaa_eth.h" ++#include "dpaa_eth_common.h" ++ ++#define OH_MOD_DESCRIPTION "FSL FMan Offline Parsing port driver" ++/* Manip extra space and data alignment for fragmentation */ ++#define FRAG_MANIP_SPACE 128 ++#define FRAG_DATA_ALIGN 64 ++ ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("Bogdan Hamciuc "); ++MODULE_DESCRIPTION(OH_MOD_DESCRIPTION); ++ ++ ++static const struct of_device_id oh_port_match_table[] = { ++ { ++ .compatible = "fsl,dpa-oh" ++ }, ++ { ++ .compatible = "fsl,dpa-oh-shared" ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, oh_port_match_table); ++ ++#ifdef CONFIG_PM ++ ++static int oh_suspend(struct device *dev) ++{ ++ struct dpa_oh_config_s *oh_config; ++ ++ oh_config = dev_get_drvdata(dev); ++ return fm_port_suspend(oh_config->oh_port); ++} ++ ++static int oh_resume(struct device *dev) ++{ ++ struct dpa_oh_config_s *oh_config; ++ ++ oh_config = dev_get_drvdata(dev); ++ return fm_port_resume(oh_config->oh_port); ++} ++ ++static const struct dev_pm_ops oh_pm_ops = { ++ .suspend = oh_suspend, ++ .resume = oh_resume, ++}; ++ ++#define OH_PM_OPS (&oh_pm_ops) ++ ++#else /* CONFIG_PM */ ++ ++#define OH_PM_OPS NULL ++ ++#endif /* CONFIG_PM */ ++ ++/* Creates Frame Queues */ ++static uint32_t oh_fq_create(struct qman_fq *fq, ++ uint32_t fq_id, uint16_t channel, ++ uint16_t wq_id) ++{ ++ struct qm_mcc_initfq fq_opts; ++ uint32_t create_flags, init_flags; ++ uint32_t ret = 0; ++ ++ if (fq == NULL) ++ return 1; ++ ++ /* Set flags for FQ create */ ++ create_flags = QMAN_FQ_FLAG_LOCKED | QMAN_FQ_FLAG_TO_DCPORTAL; ++ ++ /* Create frame queue */ ++ ret = qman_create_fq(fq_id, create_flags, fq); ++ if (ret != 0) ++ return 1; ++ ++ /* Set flags for FQ init */ ++ init_flags = QMAN_INITFQ_FLAG_SCHED; ++ ++ /* Set FQ init options. Specify destination WQ ID and channel */ ++ fq_opts.we_mask = QM_INITFQ_WE_DESTWQ; ++ fq_opts.fqd.dest.wq = wq_id; ++ fq_opts.fqd.dest.channel = channel; ++ ++ /* Initialize frame queue */ ++ ret = qman_init_fq(fq, init_flags, &fq_opts); ++ if (ret != 0) { ++ qman_destroy_fq(fq, 0); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static void dump_fq(struct device *dev, int fqid, uint16_t channel) ++{ ++ if (channel) { ++ /* display fqs with a valid (!= 0) destination channel */ ++ dev_info(dev, "FQ ID:%d Channel ID:%d\n", fqid, channel); ++ } ++} ++ ++static void dump_fq_duple(struct device *dev, struct qman_fq *fqs, ++ int fqs_count, uint16_t channel_id) ++{ ++ int i; ++ for (i = 0; i < fqs_count; i++) ++ dump_fq(dev, (fqs + i)->fqid, channel_id); ++} ++ ++static void dump_oh_config(struct device *dev, struct dpa_oh_config_s *conf) ++{ ++ struct list_head *fq_list; ++ struct fq_duple *fqd; ++ int i; ++ ++ dev_info(dev, "Default egress frame queue: %d\n", conf->default_fqid); ++ dev_info(dev, "Default error frame queue: %d\n", conf->error_fqid); ++ ++ /* TX queues (old initialization) */ ++ dev_info(dev, "Initialized queues:"); ++ for (i = 0; i < conf->egress_cnt; i++) ++ dump_fq_duple(dev, conf->egress_fqs, conf->egress_cnt, ++ conf->channel); ++ ++ /* initialized ingress queues */ ++ list_for_each(fq_list, &conf->fqs_ingress_list) { ++ fqd = list_entry(fq_list, struct fq_duple, fq_list); ++ dump_fq_duple(dev, fqd->fqs, fqd->fqs_count, fqd->channel_id); ++ } ++ ++ /* initialized egress queues */ ++ list_for_each(fq_list, &conf->fqs_egress_list) { ++ fqd = list_entry(fq_list, struct fq_duple, fq_list); ++ dump_fq_duple(dev, fqd->fqs, fqd->fqs_count, fqd->channel_id); ++ } ++} ++ ++/* Destroys Frame Queues */ ++static void oh_fq_destroy(struct qman_fq *fq) ++{ ++ int _errno = 0; ++ ++ _errno = qman_retire_fq(fq, NULL); ++ if (unlikely(_errno < 0)) ++ pr_err(KBUILD_MODNAME": %s:%hu:%s(): qman_retire_fq(%u)=%d\n", ++ KBUILD_BASENAME".c", __LINE__, __func__, ++ qman_fq_fqid(fq), _errno); ++ ++ _errno = qman_oos_fq(fq); ++ if (unlikely(_errno < 0)) { ++ pr_err(KBUILD_MODNAME": %s:%hu:%s(): qman_oos_fq(%u)=%d\n", ++ KBUILD_BASENAME".c", __LINE__, __func__, ++ qman_fq_fqid(fq), _errno); ++ } ++ ++ qman_destroy_fq(fq, 0); ++} ++ ++/* Allocation code for the OH port's PCD frame queues */ ++static int __cold oh_alloc_pcd_fqids(struct device *dev, ++ uint32_t num, ++ uint8_t alignment, ++ uint32_t *base_fqid) ++{ ++ dev_crit(dev, "callback not implemented!\n"); ++ BUG(); ++ ++ return 0; ++} ++ ++static int __cold oh_free_pcd_fqids(struct device *dev, uint32_t base_fqid) ++{ ++ dev_crit(dev, "callback not implemented!\n"); ++ BUG(); ++ ++ return 0; ++} ++ ++static void oh_set_buffer_layout(struct fm_port *port, ++ struct dpa_buffer_layout_s *layout) ++{ ++ struct fm_port_params params; ++ ++ layout->priv_data_size = DPA_TX_PRIV_DATA_SIZE; ++ layout->parse_results = true; ++ layout->hash_results = true; ++ layout->time_stamp = false; ++ ++ fm_port_get_buff_layout_ext_params(port, ¶ms); ++ layout->manip_extra_space = params.manip_extra_space; ++ layout->data_align = params.data_align; ++} ++ ++static int ++oh_port_probe(struct platform_device *_of_dev) ++{ ++ struct device *dpa_oh_dev; ++ struct device_node *dpa_oh_node; ++ int lenp, _errno = 0, fq_idx, duple_idx; ++ int n_size, i, j, ret, duples_count; ++ struct platform_device *oh_of_dev; ++ struct device_node *oh_node, *bpool_node = NULL, *root_node; ++ struct device *oh_dev; ++ struct dpa_oh_config_s *oh_config = NULL; ++ const __be32 *oh_all_queues; ++ const __be32 *channel_ids; ++ const __be32 *oh_tx_queues; ++ uint32_t queues_count; ++ uint32_t crt_fqid_base; ++ uint32_t crt_fq_count; ++ bool frag_enabled = false; ++ struct fm_port_params oh_port_tx_params; ++ struct fm_port_pcd_param oh_port_pcd_params; ++ struct dpa_buffer_layout_s buf_layout; ++ ++ /* True if the current partition owns the OH port. */ ++ bool init_oh_port; ++ ++ const struct of_device_id *match; ++ int crt_ext_pools_count; ++ u32 ext_pool_size; ++ u32 port_id; ++ u32 channel_id; ++ ++ int channel_ids_count; ++ int channel_idx; ++ struct fq_duple *fqd; ++ struct list_head *fq_list, *fq_list_tmp; ++ ++ const __be32 *bpool_cfg; ++ uint32_t bpid; ++ ++ memset(&oh_port_tx_params, 0, sizeof(oh_port_tx_params)); ++ dpa_oh_dev = &_of_dev->dev; ++ dpa_oh_node = dpa_oh_dev->of_node; ++ BUG_ON(dpa_oh_node == NULL); ++ ++ match = of_match_device(oh_port_match_table, dpa_oh_dev); ++ if (!match) ++ return -EINVAL; ++ ++ dev_dbg(dpa_oh_dev, "Probing OH port...\n"); ++ ++ /* Find the referenced OH node */ ++ oh_node = of_parse_phandle(dpa_oh_node, "fsl,fman-oh-port", 0); ++ if (oh_node == NULL) { ++ dev_err(dpa_oh_dev, ++ "Can't find OH node referenced from node %s\n", ++ dpa_oh_node->full_name); ++ return -EINVAL; ++ } ++ dev_info(dpa_oh_dev, "Found OH node handle compatible with %s\n", ++ match->compatible); ++ ++ _errno = of_property_read_u32(oh_node, "cell-index", &port_id); ++ if (_errno) { ++ dev_err(dpa_oh_dev, "No port id found in node %s\n", ++ dpa_oh_node->full_name); ++ goto return_kfree; ++ } ++ ++ _errno = of_property_read_u32(oh_node, "fsl,qman-channel-id", ++ &channel_id); ++ if (_errno) { ++ dev_err(dpa_oh_dev, "No channel id found in node %s\n", ++ dpa_oh_node->full_name); ++ goto return_kfree; ++ } ++ ++ oh_of_dev = of_find_device_by_node(oh_node); ++ BUG_ON(oh_of_dev == NULL); ++ oh_dev = &oh_of_dev->dev; ++ ++ /* The OH port must be initialized exactly once. ++ * The following scenarios are of interest: ++ * - the node is Linux-private (will always initialize it); ++ * - the node is shared between two Linux partitions ++ * (only one of them will initialize it); ++ * - the node is shared between a Linux and a LWE partition ++ * (Linux will initialize it) - "fsl,dpa-oh-shared" ++ */ ++ ++ /* Check if the current partition owns the OH port ++ * and ought to initialize it. It may be the case that we leave this ++ * to another (also Linux) partition. ++ */ ++ init_oh_port = strcmp(match->compatible, "fsl,dpa-oh-shared"); ++ ++ /* If we aren't the "owner" of the OH node, we're done here. */ ++ if (!init_oh_port) { ++ dev_dbg(dpa_oh_dev, ++ "Not owning the shared OH port %s, will not initialize it.\n", ++ oh_node->full_name); ++ of_node_put(oh_node); ++ return 0; ++ } ++ ++ /* Allocate OH dev private data */ ++ oh_config = devm_kzalloc(dpa_oh_dev, sizeof(*oh_config), GFP_KERNEL); ++ if (oh_config == NULL) { ++ dev_err(dpa_oh_dev, ++ "Can't allocate private data for OH node %s referenced from node %s!\n", ++ oh_node->full_name, dpa_oh_node->full_name); ++ _errno = -ENOMEM; ++ goto return_kfree; ++ } ++ ++ INIT_LIST_HEAD(&oh_config->fqs_ingress_list); ++ INIT_LIST_HEAD(&oh_config->fqs_egress_list); ++ ++ /* FQs that enter OH port */ ++ lenp = 0; ++ oh_all_queues = of_get_property(dpa_oh_node, ++ "fsl,qman-frame-queues-ingress", &lenp); ++ if (lenp % (2 * sizeof(*oh_all_queues))) { ++ dev_warn(dpa_oh_dev, ++ "Wrong ingress queues format for OH node %s referenced from node %s!\n", ++ oh_node->full_name, dpa_oh_node->full_name); ++ /* just ignore the last unpaired value */ ++ } ++ ++ duples_count = lenp / (2 * sizeof(*oh_all_queues)); ++ dev_err(dpa_oh_dev, "Allocating %d ingress frame queues duples\n", ++ duples_count); ++ for (duple_idx = 0; duple_idx < duples_count; duple_idx++) { ++ crt_fqid_base = be32_to_cpu(oh_all_queues[2 * duple_idx]); ++ crt_fq_count = be32_to_cpu(oh_all_queues[2 * duple_idx + 1]); ++ ++ fqd = devm_kzalloc(dpa_oh_dev, ++ sizeof(struct fq_duple), GFP_KERNEL); ++ if (!fqd) { ++ dev_err(dpa_oh_dev, "Can't allocate structures for ingress frame queues for OH node %s referenced from node %s!\n", ++ oh_node->full_name, ++ dpa_oh_node->full_name); ++ _errno = -ENOMEM; ++ goto return_kfree; ++ } ++ ++ fqd->fqs = devm_kzalloc(dpa_oh_dev, ++ crt_fq_count * sizeof(struct qman_fq), ++ GFP_KERNEL); ++ if (!fqd->fqs) { ++ dev_err(dpa_oh_dev, "Can't allocate structures for ingress frame queues for OH node %s referenced from node %s!\n", ++ oh_node->full_name, ++ dpa_oh_node->full_name); ++ _errno = -ENOMEM; ++ goto return_kfree; ++ } ++ ++ for (j = 0; j < crt_fq_count; j++) ++ (fqd->fqs + j)->fqid = crt_fqid_base + j; ++ fqd->fqs_count = crt_fq_count; ++ fqd->channel_id = (uint16_t)channel_id; ++ list_add(&fqd->fq_list, &oh_config->fqs_ingress_list); ++ } ++ ++ /* create the ingress queues */ ++ list_for_each(fq_list, &oh_config->fqs_ingress_list) { ++ fqd = list_entry(fq_list, struct fq_duple, fq_list); ++ ++ for (j = 0; j < fqd->fqs_count; j++) { ++ ret = oh_fq_create(fqd->fqs + j, ++ (fqd->fqs + j)->fqid, ++ fqd->channel_id, 3); ++ if (ret != 0) { ++ dev_err(dpa_oh_dev, "Unable to create ingress frame queue %d for OH node %s referenced from node %s!\n", ++ (fqd->fqs + j)->fqid, ++ oh_node->full_name, ++ dpa_oh_node->full_name); ++ _errno = -EINVAL; ++ goto return_kfree; ++ } ++ } ++ } ++ ++ /* FQs that exit OH port */ ++ lenp = 0; ++ oh_all_queues = of_get_property(dpa_oh_node, ++ "fsl,qman-frame-queues-egress", &lenp); ++ if (lenp % (2 * sizeof(*oh_all_queues))) { ++ dev_warn(dpa_oh_dev, ++ "Wrong egress queues format for OH node %s referenced from node %s!\n", ++ oh_node->full_name, dpa_oh_node->full_name); ++ /* just ignore the last unpaired value */ ++ } ++ ++ duples_count = lenp / (2 * sizeof(*oh_all_queues)); ++ dev_dbg(dpa_oh_dev, "Allocating %d egress frame queues duples\n", ++ duples_count); ++ for (duple_idx = 0; duple_idx < duples_count; duple_idx++) { ++ crt_fqid_base = be32_to_cpu(oh_all_queues[2 * duple_idx]); ++ crt_fq_count = be32_to_cpu(oh_all_queues[2 * duple_idx + 1]); ++ ++ fqd = devm_kzalloc(dpa_oh_dev, ++ sizeof(struct fq_duple), GFP_KERNEL); ++ if (!fqd) { ++ dev_err(dpa_oh_dev, "Can't allocate structures for egress frame queues for OH node %s referenced from node %s!\n", ++ oh_node->full_name, ++ dpa_oh_node->full_name); ++ _errno = -ENOMEM; ++ goto return_kfree; ++ } ++ ++ fqd->fqs = devm_kzalloc(dpa_oh_dev, ++ crt_fq_count * sizeof(struct qman_fq), ++ GFP_KERNEL); ++ if (!fqd->fqs) { ++ dev_err(dpa_oh_dev, ++ "Can't allocate structures for egress frame queues for OH node %s referenced from node %s!\n", ++ oh_node->full_name, ++ dpa_oh_node->full_name); ++ _errno = -ENOMEM; ++ goto return_kfree; ++ } ++ ++ for (j = 0; j < crt_fq_count; j++) ++ (fqd->fqs + j)->fqid = crt_fqid_base + j; ++ fqd->fqs_count = crt_fq_count; ++ /* channel ID is specified in another attribute */ ++ fqd->channel_id = 0; ++ list_add_tail(&fqd->fq_list, &oh_config->fqs_egress_list); ++ ++ /* allocate the queue */ ++ ++ } ++ ++ /* channel_ids for FQs that exit OH port */ ++ lenp = 0; ++ channel_ids = of_get_property(dpa_oh_node, ++ "fsl,qman-channel-ids-egress", &lenp); ++ ++ channel_ids_count = lenp / (sizeof(*channel_ids)); ++ if (channel_ids_count != duples_count) { ++ dev_warn(dpa_oh_dev, ++ "Not all egress queues have a channel id for OH node %s referenced from node %s!\n", ++ oh_node->full_name, dpa_oh_node->full_name); ++ /* just ignore the queues that do not have a Channel ID */ ++ } ++ ++ channel_idx = 0; ++ list_for_each(fq_list, &oh_config->fqs_egress_list) { ++ if (channel_idx + 1 > channel_ids_count) ++ break; ++ fqd = list_entry(fq_list, struct fq_duple, fq_list); ++ fqd->channel_id = ++ (uint16_t)be32_to_cpu(channel_ids[channel_idx++]); ++ } ++ ++ /* create egress queues */ ++ list_for_each(fq_list, &oh_config->fqs_egress_list) { ++ fqd = list_entry(fq_list, struct fq_duple, fq_list); ++ ++ if (fqd->channel_id == 0) { ++ /* missing channel id in dts */ ++ continue; ++ } ++ ++ for (j = 0; j < fqd->fqs_count; j++) { ++ ret = oh_fq_create(fqd->fqs + j, ++ (fqd->fqs + j)->fqid, ++ fqd->channel_id, 3); ++ if (ret != 0) { ++ dev_err(dpa_oh_dev, "Unable to create egress frame queue %d for OH node %s referenced from node %s!\n", ++ (fqd->fqs + j)->fqid, ++ oh_node->full_name, ++ dpa_oh_node->full_name); ++ _errno = -EINVAL; ++ goto return_kfree; ++ } ++ } ++ } ++ ++ /* Read FQ ids/nums for the DPA OH node */ ++ oh_all_queues = of_get_property(dpa_oh_node, ++ "fsl,qman-frame-queues-oh", &lenp); ++ if (oh_all_queues == NULL) { ++ dev_err(dpa_oh_dev, ++ "No frame queues have been defined for OH node %s referenced from node %s\n", ++ oh_node->full_name, dpa_oh_node->full_name); ++ _errno = -EINVAL; ++ goto return_kfree; ++ } ++ ++ /* Check that the OH error and default FQs are there */ ++ BUG_ON(lenp % (2 * sizeof(*oh_all_queues))); ++ queues_count = lenp / (2 * sizeof(*oh_all_queues)); ++ if (queues_count != 2) { ++ dev_err(dpa_oh_dev, ++ "Error and Default queues must be defined for OH node %s referenced from node %s\n", ++ oh_node->full_name, dpa_oh_node->full_name); ++ _errno = -EINVAL; ++ goto return_kfree; ++ } ++ ++ /* Read the FQIDs defined for this OH port */ ++ dev_dbg(dpa_oh_dev, "Reading %d queues...\n", queues_count); ++ fq_idx = 0; ++ ++ /* Error FQID - must be present */ ++ crt_fqid_base = be32_to_cpu(oh_all_queues[fq_idx++]); ++ crt_fq_count = be32_to_cpu(oh_all_queues[fq_idx++]); ++ if (crt_fq_count != 1) { ++ dev_err(dpa_oh_dev, ++ "Only 1 Error FQ allowed in OH node %s referenced from node %s (read: %d FQIDs).\n", ++ oh_node->full_name, dpa_oh_node->full_name, ++ crt_fq_count); ++ _errno = -EINVAL; ++ goto return_kfree; ++ } ++ oh_config->error_fqid = crt_fqid_base; ++ dev_dbg(dpa_oh_dev, "Read Error FQID 0x%x for OH port %s.\n", ++ oh_config->error_fqid, oh_node->full_name); ++ ++ /* Default FQID - must be present */ ++ crt_fqid_base = be32_to_cpu(oh_all_queues[fq_idx++]); ++ crt_fq_count = be32_to_cpu(oh_all_queues[fq_idx++]); ++ if (crt_fq_count != 1) { ++ dev_err(dpa_oh_dev, ++ "Only 1 Default FQ allowed in OH node %s referenced from %s (read: %d FQIDs).\n", ++ oh_node->full_name, dpa_oh_node->full_name, ++ crt_fq_count); ++ _errno = -EINVAL; ++ goto return_kfree; ++ } ++ oh_config->default_fqid = crt_fqid_base; ++ dev_dbg(dpa_oh_dev, "Read Default FQID 0x%x for OH port %s.\n", ++ oh_config->default_fqid, oh_node->full_name); ++ ++ /* TX FQID - presence is optional */ ++ oh_tx_queues = of_get_property(dpa_oh_node, "fsl,qman-frame-queues-tx", ++ &lenp); ++ if (oh_tx_queues == NULL) { ++ dev_dbg(dpa_oh_dev, ++ "No tx queues have been defined for OH node %s referenced from node %s\n", ++ oh_node->full_name, dpa_oh_node->full_name); ++ goto config_port; ++ } ++ ++ /* Check that queues-tx has only a base and a count defined */ ++ BUG_ON(lenp % (2 * sizeof(*oh_tx_queues))); ++ queues_count = lenp / (2 * sizeof(*oh_tx_queues)); ++ if (queues_count != 1) { ++ dev_err(dpa_oh_dev, ++ "TX queues must be defined in only one tuple for OH node %s referenced from node %s\n", ++ oh_node->full_name, dpa_oh_node->full_name); ++ _errno = -EINVAL; ++ goto return_kfree; ++ } ++ ++ fq_idx = 0; ++ crt_fqid_base = be32_to_cpu(oh_tx_queues[fq_idx++]); ++ crt_fq_count = be32_to_cpu(oh_tx_queues[fq_idx++]); ++ oh_config->egress_cnt = crt_fq_count; ++ ++ /* Allocate TX queues */ ++ dev_dbg(dpa_oh_dev, "Allocating %d queues for TX...\n", crt_fq_count); ++ oh_config->egress_fqs = devm_kzalloc(dpa_oh_dev, ++ crt_fq_count * sizeof(struct qman_fq), GFP_KERNEL); ++ if (oh_config->egress_fqs == NULL) { ++ dev_err(dpa_oh_dev, ++ "Can't allocate private data for TX queues for OH node %s referenced from node %s!\n", ++ oh_node->full_name, dpa_oh_node->full_name); ++ _errno = -ENOMEM; ++ goto return_kfree; ++ } ++ ++ /* Create TX queues */ ++ for (i = 0; i < crt_fq_count; i++) { ++ ret = oh_fq_create(oh_config->egress_fqs + i, ++ crt_fqid_base + i, (uint16_t)channel_id, 3); ++ if (ret != 0) { ++ dev_err(dpa_oh_dev, ++ "Unable to create TX frame queue %d for OH node %s referenced from node %s!\n", ++ crt_fqid_base + i, oh_node->full_name, ++ dpa_oh_node->full_name); ++ _errno = -EINVAL; ++ goto return_kfree; ++ } ++ } ++ ++config_port: ++ /* Get a handle to the fm_port so we can set ++ * its configuration params ++ */ ++ oh_config->oh_port = fm_port_bind(oh_dev); ++ if (oh_config->oh_port == NULL) { ++ dev_err(dpa_oh_dev, "NULL drvdata from fm port dev %s!\n", ++ oh_node->full_name); ++ _errno = -EINVAL; ++ goto return_kfree; ++ } ++ ++ oh_set_buffer_layout(oh_config->oh_port, &buf_layout); ++ ++ /* read the pool handlers */ ++ crt_ext_pools_count = of_count_phandle_with_args(dpa_oh_node, ++ "fsl,bman-buffer-pools", NULL); ++ if (crt_ext_pools_count <= 0) { ++ dev_info(dpa_oh_dev, ++ "OH port %s has no buffer pool. Fragmentation will not be enabled\n", ++ oh_node->full_name); ++ goto init_port; ++ } ++ ++ /* used for reading ext_pool_size*/ ++ root_node = of_find_node_by_path("/"); ++ if (root_node == NULL) { ++ dev_err(dpa_oh_dev, "of_find_node_by_path(/) failed\n"); ++ _errno = -EINVAL; ++ goto return_kfree; ++ } ++ ++ n_size = of_n_size_cells(root_node); ++ of_node_put(root_node); ++ ++ dev_dbg(dpa_oh_dev, "OH port number of pools = %d\n", ++ crt_ext_pools_count); ++ ++ oh_port_tx_params.num_pools = (uint8_t)crt_ext_pools_count; ++ ++ for (i = 0; i < crt_ext_pools_count; i++) { ++ bpool_node = of_parse_phandle(dpa_oh_node, ++ "fsl,bman-buffer-pools", i); ++ if (bpool_node == NULL) { ++ dev_err(dpa_oh_dev, "Invalid Buffer pool node\n"); ++ _errno = -EINVAL; ++ goto return_kfree; ++ } ++ ++ _errno = of_property_read_u32(bpool_node, "fsl,bpid", &bpid); ++ if (_errno) { ++ dev_err(dpa_oh_dev, "Invalid Buffer Pool ID\n"); ++ _errno = -EINVAL; ++ goto return_kfree; ++ } ++ ++ oh_port_tx_params.pool_param[i].id = (uint8_t)bpid; ++ dev_dbg(dpa_oh_dev, "OH port bpool id = %u\n", bpid); ++ ++ bpool_cfg = of_get_property(bpool_node, ++ "fsl,bpool-ethernet-cfg", &lenp); ++ if (bpool_cfg == NULL) { ++ dev_err(dpa_oh_dev, "Invalid Buffer pool config params\n"); ++ _errno = -EINVAL; ++ goto return_kfree; ++ } ++ ++ ext_pool_size = of_read_number(bpool_cfg + n_size, n_size); ++ oh_port_tx_params.pool_param[i].size = (uint16_t)ext_pool_size; ++ dev_dbg(dpa_oh_dev, "OH port bpool size = %u\n", ++ ext_pool_size); ++ of_node_put(bpool_node); ++ ++ } ++ ++ if (buf_layout.data_align != FRAG_DATA_ALIGN || ++ buf_layout.manip_extra_space != FRAG_MANIP_SPACE) ++ goto init_port; ++ ++ frag_enabled = true; ++ dev_info(dpa_oh_dev, "IP Fragmentation enabled for OH port %d", ++ port_id); ++ ++init_port: ++ of_node_put(oh_node); ++ /* Set Tx params */ ++ dpaa_eth_init_port(tx, oh_config->oh_port, oh_port_tx_params, ++ oh_config->error_fqid, oh_config->default_fqid, (&buf_layout), ++ frag_enabled); ++ /* Set PCD params */ ++ oh_port_pcd_params.cba = oh_alloc_pcd_fqids; ++ oh_port_pcd_params.cbf = oh_free_pcd_fqids; ++ oh_port_pcd_params.dev = dpa_oh_dev; ++ fm_port_pcd_bind(oh_config->oh_port, &oh_port_pcd_params); ++ ++ dev_set_drvdata(dpa_oh_dev, oh_config); ++ ++ /* Enable the OH port */ ++ _errno = fm_port_enable(oh_config->oh_port); ++ if (_errno) ++ goto return_kfree; ++ ++ dev_info(dpa_oh_dev, "OH port %s enabled.\n", oh_node->full_name); ++ ++ /* print of all referenced & created queues */ ++ dump_oh_config(dpa_oh_dev, oh_config); ++ ++ return 0; ++ ++return_kfree: ++ if (bpool_node) ++ of_node_put(bpool_node); ++ if (oh_node) ++ of_node_put(oh_node); ++ if (oh_config && oh_config->egress_fqs) ++ devm_kfree(dpa_oh_dev, oh_config->egress_fqs); ++ ++ list_for_each_safe(fq_list, fq_list_tmp, &oh_config->fqs_ingress_list) { ++ fqd = list_entry(fq_list, struct fq_duple, fq_list); ++ list_del(fq_list); ++ devm_kfree(dpa_oh_dev, fqd->fqs); ++ devm_kfree(dpa_oh_dev, fqd); ++ } ++ ++ list_for_each_safe(fq_list, fq_list_tmp, &oh_config->fqs_egress_list) { ++ fqd = list_entry(fq_list, struct fq_duple, fq_list); ++ list_del(fq_list); ++ devm_kfree(dpa_oh_dev, fqd->fqs); ++ devm_kfree(dpa_oh_dev, fqd); ++ } ++ ++ devm_kfree(dpa_oh_dev, oh_config); ++ return _errno; ++} ++ ++static int __cold oh_port_remove(struct platform_device *_of_dev) ++{ ++ int _errno = 0, i; ++ struct dpa_oh_config_s *oh_config; ++ ++ pr_info("Removing OH port...\n"); ++ ++ oh_config = dev_get_drvdata(&_of_dev->dev); ++ if (oh_config == NULL) { ++ pr_err(KBUILD_MODNAME ++ ": %s:%hu:%s(): No OH config in device private data!\n", ++ KBUILD_BASENAME".c", __LINE__, __func__); ++ _errno = -ENODEV; ++ goto return_error; ++ } ++ ++ if (oh_config->egress_fqs) ++ for (i = 0; i < oh_config->egress_cnt; i++) ++ oh_fq_destroy(oh_config->egress_fqs + i); ++ ++ if (oh_config->oh_port == NULL) { ++ pr_err(KBUILD_MODNAME ++ ": %s:%hu:%s(): No fm port in device private data!\n", ++ KBUILD_BASENAME".c", __LINE__, __func__); ++ _errno = -EINVAL; ++ goto free_egress_fqs; ++ } ++ ++ _errno = fm_port_disable(oh_config->oh_port); ++ ++free_egress_fqs: ++ if (oh_config->egress_fqs) ++ devm_kfree(&_of_dev->dev, oh_config->egress_fqs); ++ devm_kfree(&_of_dev->dev, oh_config); ++ dev_set_drvdata(&_of_dev->dev, NULL); ++ ++return_error: ++ return _errno; ++} ++ ++static struct platform_driver oh_port_driver = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .of_match_table = oh_port_match_table, ++ .owner = THIS_MODULE, ++ .pm = OH_PM_OPS, ++ }, ++ .probe = oh_port_probe, ++ .remove = oh_port_remove ++}; ++ ++static int __init __cold oh_port_load(void) ++{ ++ int _errno; ++ ++ pr_info(OH_MOD_DESCRIPTION "\n"); ++ ++ _errno = platform_driver_register(&oh_port_driver); ++ if (_errno < 0) { ++ pr_err(KBUILD_MODNAME ++ ": %s:%hu:%s(): platform_driver_register() = %d\n", ++ KBUILD_BASENAME".c", __LINE__, __func__, _errno); ++ } ++ ++ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", ++ KBUILD_BASENAME".c", __func__); ++ return _errno; ++} ++module_init(oh_port_load); ++ ++static void __exit __cold oh_port_unload(void) ++{ ++ pr_debug(KBUILD_MODNAME ": -> %s:%s()\n", ++ KBUILD_BASENAME".c", __func__); ++ ++ platform_driver_unregister(&oh_port_driver); ++ ++ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n", ++ KBUILD_BASENAME".c", __func__); ++} ++module_exit(oh_port_unload); +diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/offline_port.h b/drivers/net/ethernet/freescale/sdk_dpaa/offline_port.h +new file mode 100644 +index 00000000..432ee88d +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_dpaa/offline_port.h +@@ -0,0 +1,59 @@ ++/* Copyright 2011 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __OFFLINE_PORT_H ++#define __OFFLINE_PORT_H ++ ++struct fm_port; ++struct qman_fq; ++ ++/* fqs are defined in duples (base_fq, fq_count) */ ++struct fq_duple { ++ struct qman_fq *fqs; ++ int fqs_count; ++ uint16_t channel_id; ++ struct list_head fq_list; ++}; ++ ++/* OH port configuration */ ++struct dpa_oh_config_s { ++ uint32_t error_fqid; ++ uint32_t default_fqid; ++ struct fm_port *oh_port; ++ uint32_t egress_cnt; ++ struct qman_fq *egress_fqs; ++ uint16_t channel; ++ ++ struct list_head fqs_ingress_list; ++ struct list_head fqs_egress_list; ++}; ++ ++#endif /* __OFFLINE_PORT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Kconfig b/drivers/net/ethernet/freescale/sdk_fman/Kconfig +new file mode 100644 +index 00000000..d98c0989 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Kconfig +@@ -0,0 +1,153 @@ ++menu "Frame Manager support" ++ ++menuconfig FSL_SDK_FMAN ++ bool "Freescale Frame Manager (datapath) support - SDK driver" ++ depends on (FSL_SOC || ARM64 || ARM) && FSL_SDK_BMAN && FSL_SDK_QMAN && !FSL_FMAN ++ default y ++ ---help--- ++ If unsure, say Y. ++ ++if FSL_SDK_FMAN ++ ++config FSL_SDK_FMAN_TEST ++ bool "FMan test module" ++ default n ++ select FSL_DPAA_HOOKS ++ ---help--- ++ This option compiles test code for FMan. ++ ++menu "FMAN Processor support" ++choice ++ depends on FSL_SDK_FMAN ++ prompt "Processor Type" ++ ++config FMAN_ARM ++ bool "LS1043" ++ depends on ARM64 || ARM ++ ---help--- ++ Choose "LS1043" for the ARM platforms: ++ LS1043 ++ ++config FMAN_P3040_P4080_P5020 ++ bool "P3040 P4080 5020" ++ ++config FMAN_P1023 ++ bool "P1023" ++ ++config FMAN_V3H ++ bool "FmanV3H" ++ ---help--- ++ Choose "FmanV3H" for Fman rev3H: ++ B4860, T4240, T4160, etc ++ ++config FMAN_V3L ++ bool "FmanV3L" ++ ---help--- ++ Choose "FmanV3L" for Fman rev3L: ++ T1040, T1042, T1020, T1022, T1023, T1024, etc ++ ++endchoice ++endmenu ++ ++config FMAN_MIB_CNT_OVF_IRQ_EN ++ bool "Enable the dTSEC MIB counters overflow interrupt" ++ default n ++ ---help--- ++ Enable the dTSEC MIB counters overflow interrupt to get ++ accurate MIB counters values. Enabled it compensates ++ for the counters overflow but reduces performance and ++ triggers error messages in HV setups. ++ ++config FSL_FM_MAX_FRAME_SIZE ++ int "Maximum L2 frame size" ++ depends on FSL_SDK_FMAN ++ range 64 9600 ++ default "1522" ++ help ++ Configure this in relation to the maximum possible MTU of your ++ network configuration. In particular, one would need to ++ increase this value in order to use jumbo frames. ++ FSL_FM_MAX_FRAME_SIZE must accommodate the Ethernet FCS (4 bytes) ++ and one ETH+VLAN header (18 bytes), to a total of 22 bytes in ++ excess of the desired L3 MTU. ++ ++ Note that having too large a FSL_FM_MAX_FRAME_SIZE (much larger ++ than the actual MTU) may lead to buffer exhaustion, especially ++ in the case of badly fragmented datagrams on the Rx path. ++ Conversely, having a FSL_FM_MAX_FRAME_SIZE smaller than the actual ++ MTU will lead to frames being dropped. ++ ++ This can be overridden by specifying "fsl_fm_max_frm" in ++ the kernel bootargs: ++ * in Hypervisor-based scenarios, by adding a "chosen" node ++ with the "bootargs" property specifying ++ "fsl_fm_max_frm="; ++ * in non-Hypervisor-based scenarios, via u-boot's env, by ++ modifying the "bootargs" env variable. ++ ++config FSL_FM_RX_EXTRA_HEADROOM ++ int "Add extra headroom at beginning of data buffers" ++ depends on FSL_SDK_FMAN ++ range 16 384 ++ default "64" ++ help ++ Configure this to tell the Frame Manager to reserve some extra ++ space at the beginning of a data buffer on the receive path, ++ before Internal Context fields are copied. This is in addition ++ to the private data area already reserved for driver internal ++ use. The provided value must be a multiple of 16. ++ ++ This setting can be overridden by specifying ++ "fsl_fm_rx_extra_headroom" in the kernel bootargs: ++ * in Hypervisor-based scenarios, by adding a "chosen" node ++ with the "bootargs" property specifying ++ "fsl_fm_rx_extra_headroom="; ++ * in non-Hypervisor-based scenarios, via u-boot's env, by ++ modifying the "bootargs" env variable. ++ ++config FMAN_PFC ++ bool "FMan PFC support (EXPERIMENTAL)" ++ depends on ( FMAN_V3H || FMAN_V3L || FMAN_ARM) && FSL_SDK_FMAN ++ default n ++ help ++ This option enables PFC support on FMan v3 ports. ++ Data Center Bridging defines Classes of Service that are ++ flow-controlled using PFC pause frames. ++ ++if FMAN_PFC ++config FMAN_PFC_COS_COUNT ++ int "Number of PFC Classes of Service" ++ depends on FMAN_PFC && FSL_SDK_FMAN ++ range 1 4 ++ default "3" ++ help ++ The number of Classes of Service controlled by PFC. ++ ++config FMAN_PFC_QUANTA_0 ++ int "The pause quanta for PFC CoS 0" ++ depends on FMAN_PFC && FSL_SDK_FMAN ++ range 0 65535 ++ default "65535" ++ ++config FMAN_PFC_QUANTA_1 ++ int "The pause quanta for PFC CoS 1" ++ depends on FMAN_PFC && FSL_SDK_FMAN ++ range 0 65535 ++ default "65535" ++ ++config FMAN_PFC_QUANTA_2 ++ int "The pause quanta for PFC CoS 2" ++ depends on FMAN_PFC && FSL_SDK_FMAN ++ range 0 65535 ++ default "65535" ++ ++config FMAN_PFC_QUANTA_3 ++ int "The pause quanta for PFC CoS 3" ++ depends on FMAN_PFC && FSL_SDK_FMAN ++ range 0 65535 ++ default "65535" ++endif ++ ++endif # FSL_SDK_FMAN ++ ++endmenu +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Makefile +new file mode 100644 +index 00000000..25ce7e6a +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Makefile +@@ -0,0 +1,11 @@ ++# ++# Makefile for the Freescale Ethernet controllers ++# ++ccflags-y += -DVERSION=\"\" ++# ++#Include netcomm SW specific definitions ++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk ++# ++obj-y += etc/ ++obj-y += Peripherals/FM/ ++obj-y += src/ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/Makefile +new file mode 100644 +index 00000000..d0e76727 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/Makefile +@@ -0,0 +1,15 @@ ++# ++# Makefile for the Freescale Ethernet controllers ++# ++ccflags-y += -DVERSION=\"\" ++# ++#Include netcomm SW specific definitions ++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk ++ ++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc ++ ++ccflags-y += -I$(NCSW_FM_INC) ++ ++obj-y += fsl-ncsw-Hc.o ++ ++fsl-ncsw-Hc-objs := hc.o +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/hc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/hc.c +new file mode 100644 +index 00000000..363c8f95 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/hc.c +@@ -0,0 +1,1232 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "sprint_ext.h" ++#include "string_ext.h" ++ ++#include "fm_common.h" ++#include "fm_hc.h" ++ ++ ++/**************************************************************************//** ++ @Description defaults ++*//***************************************************************************/ ++#define DEFAULT_dataMemId 0 ++ ++#define HC_HCOR_OPCODE_PLCR_PRFL 0x0 ++#define HC_HCOR_OPCODE_KG_SCM 0x1 ++#define HC_HCOR_OPCODE_SYNC 0x2 ++#define HC_HCOR_OPCODE_CC 0x3 ++#define HC_HCOR_OPCODE_CC_AGE_MASK 0x4 ++#define HC_HCOR_OPCODE_CC_CAPWAP_REASSM_TIMEOUT 0x5 ++#define HC_HCOR_OPCODE_CC_REASSM_TIMEOUT 0x10 ++#define HC_HCOR_OPCODE_CC_IP_FRAG_INITIALIZATION 0x11 ++#define HC_HCOR_OPCODE_CC_UPDATE_WITH_AGING 0x13 ++#define HC_HCOR_ACTION_REG_REASSM_TIMEOUT_ACTIVE_SHIFT 24 ++#define HC_HCOR_EXTRA_REG_REASSM_TIMEOUT_TSBS_SHIFT 24 ++#define HC_HCOR_EXTRA_REG_CC_AGING_ADD 0x80000000 ++#define HC_HCOR_EXTRA_REG_CC_AGING_REMOVE 0x40000000 ++#define HC_HCOR_EXTRA_REG_CC_AGING_CHANGE_MASK 0xC0000000 ++#define HC_HCOR_EXTRA_REG_CC_REMOVE_INDX_SHIFT 24 ++#define HC_HCOR_EXTRA_REG_CC_REMOVE_INDX_MASK 0x1F000000 ++#define HC_HCOR_ACTION_REG_REASSM_TIMEOUT_RES_SHIFT 16 ++#define HC_HCOR_ACTION_REG_REASSM_TIMEOUT_RES_MASK 0xF ++#define HC_HCOR_ACTION_REG_IP_FRAG_SCRATCH_POOL_CMD_SHIFT 24 ++#define HC_HCOR_ACTION_REG_IP_FRAG_SCRATCH_POOL_BPID 16 ++ ++#define HC_HCOR_GBL 0x20000000 ++ ++#define HC_HCOR_KG_SCHEME_COUNTER 0x00000400 ++ ++#if (DPAA_VERSION == 10) ++#define HC_HCOR_KG_SCHEME_REGS_MASK 0xFFFFF800 ++#else ++#define HC_HCOR_KG_SCHEME_REGS_MASK 0xFFFFFE00 ++#endif /* (DPAA_VERSION == 10) */ ++ ++#define SIZE_OF_HC_FRAME_PORT_REGS (sizeof(t_HcFrame)-sizeof(struct fman_kg_scheme_regs)+sizeof(t_FmPcdKgPortRegs)) ++#define SIZE_OF_HC_FRAME_SCHEME_REGS sizeof(t_HcFrame) ++#define SIZE_OF_HC_FRAME_PROFILES_REGS (sizeof(t_HcFrame)-sizeof(struct fman_kg_scheme_regs)+sizeof(t_FmPcdPlcrProfileRegs)) ++#define SIZE_OF_HC_FRAME_PROFILE_CNT (sizeof(t_HcFrame)-sizeof(t_FmPcdPlcrProfileRegs)+sizeof(uint32_t)) ++#define SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC 16 ++ ++#define HC_CMD_POOL_SIZE (INTG_MAX_NUM_OF_CORES) ++ ++#define BUILD_FD(len) \ ++do { \ ++ memset(&fmFd, 0, sizeof(t_DpaaFD)); \ ++ DPAA_FD_SET_ADDR(&fmFd, p_HcFrame); \ ++ DPAA_FD_SET_OFFSET(&fmFd, 0); \ ++ DPAA_FD_SET_LENGTH(&fmFd, len); \ ++} while (0) ++ ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(push,1) ++#endif /* defined(__MWERKS__) && ... */ ++ ++typedef struct t_FmPcdKgPortRegs { ++ volatile uint32_t spReg; ++ volatile uint32_t cppReg; ++} t_FmPcdKgPortRegs; ++ ++typedef struct t_HcFrame { ++ volatile uint32_t opcode; ++ volatile uint32_t actionReg; ++ volatile uint32_t extraReg; ++ volatile uint32_t commandSequence; ++ union { ++ struct fman_kg_scheme_regs schemeRegs; ++ struct fman_kg_scheme_regs schemeRegsWithoutCounter; ++ t_FmPcdPlcrProfileRegs profileRegs; ++ volatile uint32_t singleRegForWrite; /* for writing SP, CPP, profile counter */ ++ t_FmPcdKgPortRegs portRegsForRead; ++ volatile uint32_t clsPlanEntries[CLS_PLAN_NUM_PER_GRP]; ++ t_FmPcdCcCapwapReassmTimeoutParams ccCapwapReassmTimeout; ++ t_FmPcdCcReassmTimeoutParams ccReassmTimeout; ++ } hcSpecificData; ++} t_HcFrame; ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(pop) ++#endif /* defined(__MWERKS__) && ... */ ++ ++ ++typedef struct t_FmHc { ++ t_Handle h_FmPcd; ++ t_Handle h_HcPortDev; ++ t_FmPcdQmEnqueueCallback *f_QmEnqueue; /**< A callback for enqueuing frames to the QM */ ++ t_Handle h_QmArg; /**< A handle to the QM module */ ++ uint8_t dataMemId; /**< Memory partition ID for data buffers */ ++ ++ uint32_t seqNum[HC_CMD_POOL_SIZE]; /* FIFO of seqNum to use when ++ taking buffer */ ++ uint32_t nextSeqNumLocation; /* seqNum location in seqNum[] for next buffer */ ++ volatile bool enqueued[HC_CMD_POOL_SIZE]; /* HC is active - frame is enqueued ++ and not confirmed yet */ ++ t_HcFrame *p_Frm[HC_CMD_POOL_SIZE]; ++} t_FmHc; ++ ++ ++static t_Error FillBufPool(t_FmHc *p_FmHc) ++{ ++ uint32_t i; ++ ++ ASSERT_COND(p_FmHc); ++ ++ for (i = 0; i < HC_CMD_POOL_SIZE; i++) ++ { ++#ifdef FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 ++ p_FmHc->p_Frm[i] = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + (16 - (sizeof(t_FmHc) % 16))), ++ p_FmHc->dataMemId, ++ 16); ++#else ++ p_FmHc->p_Frm[i] = (t_HcFrame *)XX_MallocSmart(sizeof(t_HcFrame), ++ p_FmHc->dataMemId, ++ 16); ++#endif /* FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 */ ++ if (!p_FmHc->p_Frm[i]) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM HC frames!")); ++ } ++ ++ /* Initialize FIFO of seqNum to use during GetBuf */ ++ for (i = 0; i < HC_CMD_POOL_SIZE; i++) ++ { ++ p_FmHc->seqNum[i] = i; ++ } ++ p_FmHc->nextSeqNumLocation = 0; ++ ++ return E_OK; ++} ++ ++static __inline__ t_HcFrame * GetBuf(t_FmHc *p_FmHc, uint32_t *p_SeqNum) ++{ ++ uint32_t intFlags; ++ ++ ASSERT_COND(p_FmHc); ++ ++ intFlags = FmPcdLock(p_FmHc->h_FmPcd); ++ ++ if (p_FmHc->nextSeqNumLocation == HC_CMD_POOL_SIZE) ++ { ++ /* No more buffers */ ++ FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); ++ return NULL; ++ } ++ ++ *p_SeqNum = p_FmHc->seqNum[p_FmHc->nextSeqNumLocation]; ++ p_FmHc->nextSeqNumLocation++; ++ ++ FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); ++ return p_FmHc->p_Frm[*p_SeqNum]; ++} ++ ++static __inline__ void PutBuf(t_FmHc *p_FmHc, t_HcFrame *p_Buf, uint32_t seqNum) ++{ ++ uint32_t intFlags; ++ ++ UNUSED(p_Buf); ++ ++ intFlags = FmPcdLock(p_FmHc->h_FmPcd); ++ ASSERT_COND(p_FmHc->nextSeqNumLocation); ++ p_FmHc->nextSeqNumLocation--; ++ p_FmHc->seqNum[p_FmHc->nextSeqNumLocation] = seqNum; ++ FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); ++} ++ ++static __inline__ t_Error EnQFrm(t_FmHc *p_FmHc, t_DpaaFD *p_FmFd, uint32_t seqNum) ++{ ++ t_Error err = E_OK; ++ uint32_t intFlags; ++ uint32_t timeout=100; ++ ++ intFlags = FmPcdLock(p_FmHc->h_FmPcd); ++ ASSERT_COND(!p_FmHc->enqueued[seqNum]); ++ p_FmHc->enqueued[seqNum] = TRUE; ++ FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); ++ DBG(TRACE, ("Send Hc, SeqNum %d, buff@0x%x, fd offset 0x%x", ++ seqNum, ++ DPAA_FD_GET_ADDR(p_FmFd), ++ DPAA_FD_GET_OFFSET(p_FmFd))); ++ err = p_FmHc->f_QmEnqueue(p_FmHc->h_QmArg, (void *)p_FmFd); ++ if (err) ++ RETURN_ERROR(MINOR, err, ("HC enqueue failed")); ++ ++ while (p_FmHc->enqueued[seqNum] && --timeout) ++ XX_UDelay(100); ++ ++ if (!timeout) ++ RETURN_ERROR(MINOR, E_TIMEOUT, ("HC Callback, timeout exceeded")); ++ ++ return err; ++} ++ ++ ++t_Handle FmHcConfigAndInit(t_FmHcParams *p_FmHcParams) ++{ ++ t_FmHc *p_FmHc; ++ t_FmPortParams fmPortParam; ++ t_Error err; ++ ++ p_FmHc = (t_FmHc *)XX_Malloc(sizeof(t_FmHc)); ++ if (!p_FmHc) ++ { ++ REPORT_ERROR(MINOR, E_NO_MEMORY, ("HC obj")); ++ return NULL; ++ } ++ memset(p_FmHc,0,sizeof(t_FmHc)); ++ ++ p_FmHc->h_FmPcd = p_FmHcParams->h_FmPcd; ++ p_FmHc->f_QmEnqueue = p_FmHcParams->params.f_QmEnqueue; ++ p_FmHc->h_QmArg = p_FmHcParams->params.h_QmArg; ++ p_FmHc->dataMemId = DEFAULT_dataMemId; ++ ++ err = FillBufPool(p_FmHc); ++ if (err != E_OK) ++ { ++ REPORT_ERROR(MAJOR, err, NO_MSG); ++ FmHcFree(p_FmHc); ++ return NULL; ++ } ++ ++ if (!FmIsMaster(p_FmHcParams->h_Fm)) ++ return (t_Handle)p_FmHc; ++ ++ memset(&fmPortParam, 0, sizeof(fmPortParam)); ++ fmPortParam.baseAddr = p_FmHcParams->params.portBaseAddr; ++ fmPortParam.portType = e_FM_PORT_TYPE_OH_HOST_COMMAND; ++ fmPortParam.portId = p_FmHcParams->params.portId; ++ fmPortParam.liodnBase = p_FmHcParams->params.liodnBase; ++ fmPortParam.h_Fm = p_FmHcParams->h_Fm; ++ ++ fmPortParam.specificParams.nonRxParams.errFqid = p_FmHcParams->params.errFqid; ++ fmPortParam.specificParams.nonRxParams.dfltFqid = p_FmHcParams->params.confFqid; ++ fmPortParam.specificParams.nonRxParams.qmChannel = p_FmHcParams->params.qmChannel; ++ ++ p_FmHc->h_HcPortDev = FM_PORT_Config(&fmPortParam); ++ if (!p_FmHc->h_HcPortDev) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_HANDLE, ("FM HC port!")); ++ XX_Free(p_FmHc); ++ return NULL; ++ } ++ ++ err = FM_PORT_ConfigMaxFrameLength(p_FmHc->h_HcPortDev, ++ (uint16_t)sizeof(t_HcFrame)); ++ ++ if (err != E_OK) ++ { ++ REPORT_ERROR(MAJOR, err, ("FM HC port init!")); ++ FmHcFree(p_FmHc); ++ return NULL; ++ } ++ ++ /* final init */ ++ err = FM_PORT_Init(p_FmHc->h_HcPortDev); ++ if (err != E_OK) ++ { ++ REPORT_ERROR(MAJOR, err, ("FM HC port init!")); ++ FmHcFree(p_FmHc); ++ return NULL; ++ } ++ ++ err = FM_PORT_Enable(p_FmHc->h_HcPortDev); ++ if (err != E_OK) ++ { ++ REPORT_ERROR(MAJOR, err, ("FM HC port enable!")); ++ FmHcFree(p_FmHc); ++ return NULL; ++ } ++ ++ return (t_Handle)p_FmHc; ++} ++ ++void FmHcFree(t_Handle h_FmHc) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ int i; ++ ++ if (!p_FmHc) ++ return; ++ ++ for (i=0; ip_Frm[i]) ++ XX_FreeSmart(p_FmHc->p_Frm[i]); ++ else ++ break; ++ ++ if (p_FmHc->h_HcPortDev) ++ FM_PORT_Free(p_FmHc->h_HcPortDev); ++ ++ XX_Free(p_FmHc); ++} ++ ++/*****************************************************************************/ ++t_Error FmHcSetFramesDataMemory(t_Handle h_FmHc, ++ uint8_t memId) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ int i; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmHc, E_INVALID_HANDLE); ++ ++ p_FmHc->dataMemId = memId; ++ ++ for (i=0; ip_Frm[i]) ++ XX_FreeSmart(p_FmHc->p_Frm[i]); ++ ++ return FillBufPool(p_FmHc); ++} ++ ++void FmHcTxConf(t_Handle h_FmHc, t_DpaaFD *p_Fd) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ t_HcFrame *p_HcFrame; ++ uint32_t intFlags; ++ ++ ASSERT_COND(p_FmHc); ++ ++ intFlags = FmPcdLock(p_FmHc->h_FmPcd); ++ p_HcFrame = (t_HcFrame *)PTR_MOVE(DPAA_FD_GET_ADDR(p_Fd), DPAA_FD_GET_OFFSET(p_Fd)); ++ ++ DBG(TRACE, ("Hc Conf, SeqNum %d, FD@0x%x, fd offset 0x%x", ++ p_HcFrame->commandSequence, DPAA_FD_GET_ADDR(p_Fd), DPAA_FD_GET_OFFSET(p_Fd))); ++ ++ if (!(p_FmHc->enqueued[p_HcFrame->commandSequence])) ++ REPORT_ERROR(MINOR, E_INVALID_FRAME, ("Not an Host-Command frame received!")); ++ else ++ p_FmHc->enqueued[p_HcFrame->commandSequence] = FALSE; ++ FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); ++} ++ ++t_Error FmHcPcdKgSetScheme(t_Handle h_FmHc, ++ t_Handle h_Scheme, ++ struct fman_kg_scheme_regs *p_SchemeRegs, ++ bool updateCounter) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ t_Error err = E_OK; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ uint8_t physicalSchemeId; ++ uint32_t seqNum; ++ ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ ++ physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme); ++ ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); ++ p_HcFrame->actionReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, updateCounter); ++ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK; ++ memcpy(&p_HcFrame->hcSpecificData.schemeRegs, p_SchemeRegs, sizeof(struct fman_kg_scheme_regs)); ++ if (!updateCounter) ++ { ++ p_HcFrame->hcSpecificData.schemeRegs.kgse_dv0 = p_SchemeRegs->kgse_dv0; ++ p_HcFrame->hcSpecificData.schemeRegs.kgse_dv1 = p_SchemeRegs->kgse_dv1; ++ p_HcFrame->hcSpecificData.schemeRegs.kgse_ccbs = p_SchemeRegs->kgse_ccbs; ++ p_HcFrame->hcSpecificData.schemeRegs.kgse_mv = p_SchemeRegs->kgse_mv; ++ } ++ p_HcFrame->commandSequence = seqNum; ++ ++ BUILD_FD(sizeof(t_HcFrame)); ++ ++ err = EnQFrm(p_FmHc, &fmFd, seqNum); ++ ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ return E_OK; ++} ++ ++t_Error FmHcPcdKgDeleteScheme(t_Handle h_FmHc, t_Handle h_Scheme) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ t_Error err = E_OK; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ uint8_t physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme); ++ uint32_t seqNum; ++ ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); ++ p_HcFrame->actionReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, TRUE); ++ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK; ++ memset(&p_HcFrame->hcSpecificData.schemeRegs, 0, sizeof(struct fman_kg_scheme_regs)); ++ p_HcFrame->commandSequence = seqNum; ++ ++ BUILD_FD(sizeof(t_HcFrame)); ++ ++ err = EnQFrm(p_FmHc, &fmFd, seqNum); ++ ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ return E_OK; ++} ++ ++t_Error FmHcPcdKgCcGetSetParams(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t requiredAction, uint32_t value) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ t_Error err = E_OK; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ uint8_t relativeSchemeId; ++ uint8_t physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme); ++ uint32_t tmpReg32 = 0; ++ uint32_t seqNum; ++ ++ /* Scheme is locked by calling routine */ ++ /* WARNING - this lock will not be efficient if other HC routine will attempt to change ++ * "kgse_mode" or "kgse_om" without locking scheme ! ++ */ ++ ++ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmHc->h_FmPcd, physicalSchemeId); ++ if ( relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) ++ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); ++ ++ if (!FmPcdKgGetRequiredActionFlag(p_FmHc->h_FmPcd, relativeSchemeId) || ++ !(FmPcdKgGetRequiredAction(p_FmHc->h_FmPcd, relativeSchemeId) & requiredAction)) ++ { ++ if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) && ++ (FmPcdKgGetNextEngine(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_PLCR)) ++ { ++ if ((FmPcdKgIsDirectPlcr(p_FmHc->h_FmPcd, relativeSchemeId) == FALSE) || ++ (FmPcdKgIsDistrOnPlcrProfile(p_FmHc->h_FmPcd, relativeSchemeId) == TRUE)) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("In this situation PP can not be with distribution and has to be shared")); ++ err = FmPcdPlcrCcGetSetParams(p_FmHc->h_FmPcd, FmPcdKgGetRelativeProfileId(p_FmHc->h_FmPcd, relativeSchemeId), requiredAction); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ else /* From here we deal with KG-Schemes only */ ++ { ++ /* Pre change general code */ ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); ++ p_HcFrame->actionReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); ++ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK; ++ p_HcFrame->commandSequence = seqNum; ++ BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); ++ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) ++ { ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ /* specific change */ ++ if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) && ++ ((FmPcdKgGetNextEngine(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_DONE) && ++ (FmPcdKgGetDoneAction(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_ENQ_FRAME))) ++ { ++ tmpReg32 = p_HcFrame->hcSpecificData.schemeRegs.kgse_mode; ++ ASSERT_COND(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)); ++ p_HcFrame->hcSpecificData.schemeRegs.kgse_mode = tmpReg32 | NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; ++ } ++ ++ if ((requiredAction & UPDATE_KG_NIA_CC_WA) && ++ (FmPcdKgGetNextEngine(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_CC)) ++ { ++ tmpReg32 = p_HcFrame->hcSpecificData.schemeRegs.kgse_mode; ++ ASSERT_COND(tmpReg32 & (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC)); ++ tmpReg32 &= ~NIA_FM_CTL_AC_CC; ++ p_HcFrame->hcSpecificData.schemeRegs.kgse_mode = tmpReg32 | NIA_FM_CTL_AC_PRE_CC; ++ } ++ ++ if (requiredAction & UPDATE_KG_OPT_MODE) ++ p_HcFrame->hcSpecificData.schemeRegs.kgse_om = value; ++ ++ if (requiredAction & UPDATE_KG_NIA) ++ { ++ tmpReg32 = p_HcFrame->hcSpecificData.schemeRegs.kgse_mode; ++ tmpReg32 &= ~(NIA_ENG_MASK | NIA_AC_MASK); ++ tmpReg32 |= value; ++ p_HcFrame->hcSpecificData.schemeRegs.kgse_mode = tmpReg32; ++ } ++ ++ /* Post change general code */ ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); ++ p_HcFrame->actionReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE); ++ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK; ++ ++ BUILD_FD(sizeof(t_HcFrame)); ++ err = EnQFrm(p_FmHc, &fmFd, seqNum); ++ ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ } ++ ++ return E_OK; ++} ++ ++uint32_t FmHcPcdKgGetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ t_Error err; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ uint32_t retVal; ++ uint8_t relativeSchemeId; ++ uint8_t physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme); ++ uint32_t seqNum; ++ ++ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmHc->h_FmPcd, physicalSchemeId); ++ if ( relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) ++ { ++ REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); ++ return 0; ++ } ++ ++ /* first read scheme and check that it is valid */ ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ { ++ REPORT_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ return 0; ++ } ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); ++ p_HcFrame->actionReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); ++ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK; ++ p_HcFrame->commandSequence = seqNum; ++ ++ BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); ++ ++ err = EnQFrm(p_FmHc, &fmFd, seqNum); ++ if (err != E_OK) ++ { ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ REPORT_ERROR(MINOR, err, NO_MSG); ++ return 0; ++ } ++ ++ if (!FmPcdKgHwSchemeIsValid(p_HcFrame->hcSpecificData.schemeRegs.kgse_mode)) ++ { ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is invalid")); ++ return 0; ++ } ++ ++ retVal = p_HcFrame->hcSpecificData.schemeRegs.kgse_spc; ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ ++ return retVal; ++} ++ ++t_Error FmHcPcdKgSetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t value) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ t_Error err = E_OK; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ uint8_t relativeSchemeId, physicalSchemeId; ++ uint32_t seqNum; ++ ++ physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme); ++ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmHc->h_FmPcd, physicalSchemeId); ++ if ( relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) ++ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); ++ ++ /* first read scheme and check that it is valid */ ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); ++ p_HcFrame->actionReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, TRUE); ++ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_COUNTER; ++ /* write counter */ ++ p_HcFrame->hcSpecificData.singleRegForWrite = value; ++ p_HcFrame->commandSequence = seqNum; ++ ++ BUILD_FD(sizeof(t_HcFrame)); ++ ++ err = EnQFrm(p_FmHc, &fmFd, seqNum); ++ ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ return err; ++} ++ ++t_Error FmHcPcdKgSetClsPlan(t_Handle h_FmHc, t_FmPcdKgInterModuleClsPlanSet *p_Set) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ uint8_t i, idx; ++ uint32_t seqNum; ++ t_Error err = E_OK; ++ ++ ASSERT_COND(p_FmHc); ++ ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ ++ for (i = p_Set->baseEntry; i < (p_Set->baseEntry+p_Set->numOfClsPlanEntries); i+=8) ++ { ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); ++ p_HcFrame->actionReg = FmPcdKgBuildWriteClsPlanBlockActionReg((uint8_t)(i / CLS_PLAN_NUM_PER_GRP)); ++ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK; ++ ++ idx = (uint8_t)(i - p_Set->baseEntry); ++ ASSERT_COND(idx < FM_PCD_MAX_NUM_OF_CLS_PLANS); ++ memcpy(&p_HcFrame->hcSpecificData.clsPlanEntries, &p_Set->vectors[idx], CLS_PLAN_NUM_PER_GRP*sizeof(uint32_t)); ++ p_HcFrame->commandSequence = seqNum; ++ ++ BUILD_FD(sizeof(t_HcFrame)); ++ ++ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) ++ { ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ } ++ ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ return err; ++} ++ ++t_Error FmHcPcdKgDeleteClsPlan(t_Handle h_FmHc, uint8_t grpId) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet; ++ ++ p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet)); ++ if (!p_ClsPlanSet) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Classification plan set")); ++ ++ memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet)); ++ ++ p_ClsPlanSet->baseEntry = FmPcdKgGetClsPlanGrpBase(p_FmHc->h_FmPcd, grpId); ++ p_ClsPlanSet->numOfClsPlanEntries = FmPcdKgGetClsPlanGrpSize(p_FmHc->h_FmPcd, grpId); ++ ASSERT_COND(p_ClsPlanSet->numOfClsPlanEntries <= FM_PCD_MAX_NUM_OF_CLS_PLANS); ++ ++ if (FmHcPcdKgSetClsPlan(p_FmHc, p_ClsPlanSet) != E_OK) ++ { ++ XX_Free(p_ClsPlanSet); ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ } ++ ++ XX_Free(p_ClsPlanSet); ++ FmPcdKgDestroyClsPlanGrp(p_FmHc->h_FmPcd, grpId); ++ ++ return E_OK; ++} ++ ++t_Error FmHcPcdCcCapwapTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcCapwapReassmTimeoutParams *p_CcCapwapReassmTimeoutParams ) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ t_Error err; ++ uint32_t seqNum; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0); ++ ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC_CAPWAP_REASSM_TIMEOUT); ++ memcpy(&p_HcFrame->hcSpecificData.ccCapwapReassmTimeout, p_CcCapwapReassmTimeoutParams, sizeof(t_FmPcdCcCapwapReassmTimeoutParams)); ++ p_HcFrame->commandSequence = seqNum; ++ BUILD_FD(sizeof(t_HcFrame)); ++ ++ err = EnQFrm(p_FmHc, &fmFd, seqNum); ++ ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ return err; ++} ++ ++t_Error FmHcPcdCcIpFragScratchPollCmd(t_Handle h_FmHc, bool fill, t_FmPcdCcFragScratchPoolCmdParams *p_FmPcdCcFragScratchPoolCmdParams) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ t_Error err; ++ uint32_t seqNum; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0); ++ ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC_IP_FRAG_INITIALIZATION); ++ p_HcFrame->actionReg = (uint32_t)(((fill == TRUE) ? 0 : 1) << HC_HCOR_ACTION_REG_IP_FRAG_SCRATCH_POOL_CMD_SHIFT); ++ p_HcFrame->actionReg |= p_FmPcdCcFragScratchPoolCmdParams->bufferPoolId << HC_HCOR_ACTION_REG_IP_FRAG_SCRATCH_POOL_BPID; ++ if (fill == TRUE) ++ { ++ p_HcFrame->extraReg = p_FmPcdCcFragScratchPoolCmdParams->numOfBuffers; ++ } ++ p_HcFrame->commandSequence = seqNum; ++ ++ BUILD_FD(sizeof(t_HcFrame)); ++ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) ++ { ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ p_FmPcdCcFragScratchPoolCmdParams->numOfBuffers = p_HcFrame->extraReg; ++ ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ return E_OK; ++} ++ ++t_Error FmHcPcdCcTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcReassmTimeoutParams *p_CcReassmTimeoutParams, uint8_t *p_Result) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ t_Error err; ++ uint32_t seqNum; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0); ++ ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC_REASSM_TIMEOUT); ++ p_HcFrame->actionReg = (uint32_t)((p_CcReassmTimeoutParams->activate ? 0 : 1) << HC_HCOR_ACTION_REG_REASSM_TIMEOUT_ACTIVE_SHIFT); ++ p_HcFrame->extraReg = (p_CcReassmTimeoutParams->tsbs << HC_HCOR_EXTRA_REG_REASSM_TIMEOUT_TSBS_SHIFT) | p_CcReassmTimeoutParams->iprcpt; ++ p_HcFrame->commandSequence = seqNum; ++ ++ BUILD_FD(sizeof(t_HcFrame)); ++ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) ++ { ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ *p_Result = (uint8_t) ++ ((p_HcFrame->actionReg >> HC_HCOR_ACTION_REG_REASSM_TIMEOUT_RES_SHIFT) & HC_HCOR_ACTION_REG_REASSM_TIMEOUT_RES_MASK); ++ ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ return E_OK; ++} ++ ++t_Error FmHcPcdPlcrCcGetSetParams(t_Handle h_FmHc,uint16_t absoluteProfileId, uint32_t requiredAction) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ t_Error err; ++ uint32_t tmpReg32 = 0; ++ uint32_t requiredActionTmp, requiredActionFlag; ++ uint32_t seqNum; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0); ++ ++ /* Profile is locked by calling routine */ ++ /* WARNING - this lock will not be efficient if other HC routine will attempt to change ++ * "fmpl_pegnia" "fmpl_peynia" or "fmpl_pernia" without locking Profile ! ++ */ ++ ++ requiredActionTmp = FmPcdPlcrGetRequiredAction(p_FmHc->h_FmPcd, absoluteProfileId); ++ requiredActionFlag = FmPcdPlcrGetRequiredActionFlag(p_FmHc->h_FmPcd, absoluteProfileId); ++ ++ if (!requiredActionFlag || !(requiredActionTmp & requiredAction)) ++ { ++ if (requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) ++ { ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ /* first read scheme and check that it is valid */ ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); ++ p_HcFrame->actionReg = FmPcdPlcrBuildReadPlcrActionReg(absoluteProfileId); ++ p_HcFrame->extraReg = 0x00008000; ++ p_HcFrame->commandSequence = seqNum; ++ ++ BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); ++ ++ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) ++ { ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ tmpReg32 = p_HcFrame->hcSpecificData.profileRegs.fmpl_pegnia; ++ if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) ++ { ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); ++ } ++ ++ tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; ++ ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); ++ p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId); ++ p_HcFrame->actionReg |= FmPcdPlcrBuildNiaProfileReg(TRUE, FALSE, FALSE); ++ p_HcFrame->extraReg = 0x00008000; ++ p_HcFrame->hcSpecificData.singleRegForWrite = tmpReg32; ++ ++ BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT); ++ ++ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) ++ { ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ tmpReg32 = p_HcFrame->hcSpecificData.profileRegs.fmpl_peynia; ++ if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) ++ { ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); ++ } ++ ++ tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; ++ ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); ++ p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId); ++ p_HcFrame->actionReg |= FmPcdPlcrBuildNiaProfileReg(FALSE, TRUE, FALSE); ++ p_HcFrame->extraReg = 0x00008000; ++ p_HcFrame->hcSpecificData.singleRegForWrite = tmpReg32; ++ ++ BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT); ++ ++ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) ++ { ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ tmpReg32 = p_HcFrame->hcSpecificData.profileRegs.fmpl_pernia; ++ if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) ++ { ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); ++ } ++ ++ tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; ++ ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); ++ p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId); ++ p_HcFrame->actionReg |= FmPcdPlcrBuildNiaProfileReg(FALSE, FALSE, TRUE); ++ p_HcFrame->extraReg = 0x00008000; ++ p_HcFrame->hcSpecificData.singleRegForWrite = tmpReg32; ++ ++ BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT); ++ ++ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) ++ { ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ } ++ } ++ ++ return E_OK; ++} ++ ++t_Error FmHcPcdPlcrSetProfile(t_Handle h_FmHc, t_Handle h_Profile, t_FmPcdPlcrProfileRegs *p_PlcrRegs) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ t_Error err = E_OK; ++ uint16_t profileIndx; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ uint32_t seqNum; ++ ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ ++ profileIndx = FmPcdPlcrProfileGetAbsoluteId(h_Profile); ++ ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); ++ p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionRegs(profileIndx); ++ p_HcFrame->extraReg = 0x00008000; ++ memcpy(&p_HcFrame->hcSpecificData.profileRegs, p_PlcrRegs, sizeof(t_FmPcdPlcrProfileRegs)); ++ p_HcFrame->commandSequence = seqNum; ++ ++ BUILD_FD(sizeof(t_HcFrame)); ++ ++ err = EnQFrm(p_FmHc, &fmFd, seqNum); ++ ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ return E_OK; ++} ++ ++t_Error FmHcPcdPlcrDeleteProfile(t_Handle h_FmHc, t_Handle h_Profile) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ uint16_t absoluteProfileId = FmPcdPlcrProfileGetAbsoluteId(h_Profile); ++ t_Error err = E_OK; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ uint32_t seqNum; ++ ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); ++ p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId); ++ p_HcFrame->actionReg |= 0x00008000; ++ p_HcFrame->extraReg = 0x00008000; ++ memset(&p_HcFrame->hcSpecificData.profileRegs, 0, sizeof(t_FmPcdPlcrProfileRegs)); ++ p_HcFrame->commandSequence = seqNum; ++ ++ BUILD_FD(sizeof(t_HcFrame)); ++ ++ err = EnQFrm(p_FmHc, &fmFd, seqNum); ++ ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ return E_OK; ++} ++ ++t_Error FmHcPcdPlcrSetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter, uint32_t value) ++{ ++ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ uint16_t absoluteProfileId = FmPcdPlcrProfileGetAbsoluteId(h_Profile); ++ t_Error err = E_OK; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ uint32_t seqNum; ++ ++ /* first read scheme and check that it is valid */ ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); ++ p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId); ++ p_HcFrame->actionReg |= FmPcdPlcrBuildCounterProfileReg(counter); ++ p_HcFrame->extraReg = 0x00008000; ++ p_HcFrame->hcSpecificData.singleRegForWrite = value; ++ p_HcFrame->commandSequence = seqNum; ++ ++ BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT); ++ ++ err = EnQFrm(p_FmHc, &fmFd, seqNum); ++ ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ return E_OK; ++} ++ ++uint32_t FmHcPcdPlcrGetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ uint16_t absoluteProfileId = FmPcdPlcrProfileGetAbsoluteId(h_Profile); ++ t_Error err; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ uint32_t retVal = 0; ++ uint32_t seqNum; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0); ++ ++ /* first read scheme and check that it is valid */ ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ { ++ REPORT_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ return 0; ++ } ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); ++ p_HcFrame->actionReg = FmPcdPlcrBuildReadPlcrActionReg(absoluteProfileId); ++ p_HcFrame->extraReg = 0x00008000; ++ p_HcFrame->commandSequence = seqNum; ++ ++ BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); ++ ++ err = EnQFrm(p_FmHc, &fmFd, seqNum); ++ if (err != E_OK) ++ { ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ REPORT_ERROR(MINOR, err, NO_MSG); ++ return 0; ++ } ++ ++ switch (counter) ++ { ++ case e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER: ++ retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_pegpc; ++ break; ++ case e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER: ++ retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_peypc; ++ break; ++ case e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER: ++ retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_perpc; ++ break; ++ case e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER: ++ retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_perypc; ++ break; ++ case e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER: ++ retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_perrpc; ++ break; ++ default: ++ REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ return retVal; ++} ++ ++t_Error FmHcKgWriteSp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t spReg, bool add) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ t_Error err = E_OK; ++ uint32_t seqNum; ++ ++ ASSERT_COND(p_FmHc); ++ ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ /* first read SP register */ ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); ++ p_HcFrame->actionReg = FmPcdKgBuildReadPortSchemeBindActionReg(hardwarePortId); ++ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK; ++ p_HcFrame->commandSequence = seqNum; ++ ++ BUILD_FD(SIZE_OF_HC_FRAME_PORT_REGS); ++ ++ if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) ++ { ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ /* spReg is the first reg, so we can use it both for read and for write */ ++ if (add) ++ p_HcFrame->hcSpecificData.portRegsForRead.spReg |= spReg; ++ else ++ p_HcFrame->hcSpecificData.portRegsForRead.spReg &= ~spReg; ++ ++ p_HcFrame->actionReg = FmPcdKgBuildWritePortSchemeBindActionReg(hardwarePortId); ++ ++ BUILD_FD(sizeof(t_HcFrame)); ++ ++ err = EnQFrm(p_FmHc, &fmFd, seqNum); ++ ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ return E_OK; ++} ++ ++t_Error FmHcKgWriteCpp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t cppReg) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ t_Error err = E_OK; ++ uint32_t seqNum; ++ ++ ASSERT_COND(p_FmHc); ++ ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ /* first read SP register */ ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); ++ p_HcFrame->actionReg = FmPcdKgBuildWritePortClsPlanBindActionReg(hardwarePortId); ++ p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK; ++ p_HcFrame->hcSpecificData.singleRegForWrite = cppReg; ++ p_HcFrame->commandSequence = seqNum; ++ ++ BUILD_FD(sizeof(t_HcFrame)); ++ ++ err = EnQFrm(p_FmHc, &fmFd, seqNum); ++ ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ return E_OK; ++} ++ ++t_Error FmHcPcdCcDoDynamicChange(t_Handle h_FmHc, uint32_t oldAdAddrOffset, uint32_t newAdAddrOffset) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ t_Error err = E_OK; ++ uint32_t seqNum; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmHc, E_INVALID_HANDLE); ++ ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC); ++ p_HcFrame->actionReg = newAdAddrOffset; ++ p_HcFrame->actionReg |= 0xc0000000; ++ p_HcFrame->extraReg = oldAdAddrOffset; ++ p_HcFrame->commandSequence = seqNum; ++ ++ BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); ++ ++ err = EnQFrm(p_FmHc, &fmFd, seqNum); ++ ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ return E_OK; ++} ++ ++t_Error FmHcPcdSync(t_Handle h_FmHc) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ t_HcFrame *p_HcFrame; ++ t_DpaaFD fmFd; ++ t_Error err = E_OK; ++ uint32_t seqNum; ++ ++ ASSERT_COND(p_FmHc); ++ ++ p_HcFrame = GetBuf(p_FmHc, &seqNum); ++ if (!p_HcFrame) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); ++ memset(p_HcFrame, 0, sizeof(t_HcFrame)); ++ /* first read SP register */ ++ p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_SYNC); ++ p_HcFrame->actionReg = 0; ++ p_HcFrame->extraReg = 0; ++ p_HcFrame->commandSequence = seqNum; ++ ++ BUILD_FD(sizeof(t_HcFrame)); ++ ++ err = EnQFrm(p_FmHc, &fmFd, seqNum); ++ ++ PutBuf(p_FmHc, p_HcFrame, seqNum); ++ ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ return E_OK; ++} ++ ++t_Handle FmHcGetPort(t_Handle h_FmHc) ++{ ++ t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; ++ return p_FmHc->h_HcPortDev; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/Makefile +new file mode 100644 +index 00000000..f6b090da +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/Makefile +@@ -0,0 +1,28 @@ ++# ++# Makefile for the Freescale Ethernet controllers ++# ++ccflags-y += -DVERSION=\"\" ++# ++#Include netcomm SW specific definitions ++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk ++ ++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc ++ ++ccflags-y += -I$(NCSW_FM_INC) ++ ++obj-y += fsl-ncsw-MAC.o ++ ++fsl-ncsw-MAC-objs := dtsec.o dtsec_mii_acc.o fm_mac.o tgec.o tgec_mii_acc.o \ ++ fman_dtsec.o fman_dtsec_mii_acc.o fman_memac.o \ ++ fman_tgec.o fman_crc32.o ++ ++ifeq ($(CONFIG_FMAN_V3H),y) ++fsl-ncsw-MAC-objs += memac.o memac_mii_acc.o fman_memac_mii_acc.o ++endif ++ifeq ($(CONFIG_FMAN_V3L),y) ++fsl-ncsw-MAC-objs += memac.o memac_mii_acc.o fman_memac_mii_acc.o ++endif ++ifeq ($(CONFIG_FMAN_ARM),y) ++fsl-ncsw-MAC-objs += memac.o memac_mii_acc.o fman_memac_mii_acc.o ++endif ++ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c +new file mode 100644 +index 00000000..f853825f +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c +@@ -0,0 +1,1464 @@ ++/* ++ * Copyright 2008-2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/****************************************************************************** ++ @File dtsec.c ++ ++ @Description FMan dTSEC driver ++*//***************************************************************************/ ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "string_ext.h" ++#include "xx_ext.h" ++#include "endian_ext.h" ++#include "debug_ext.h" ++#include "crc_mac_addr_ext.h" ++ ++#include "fm_common.h" ++#include "dtsec.h" ++#include "fsl_fman_dtsec.h" ++#include "fsl_fman_dtsec_mii_acc.h" ++ ++/*****************************************************************************/ ++/* Internal routines */ ++/*****************************************************************************/ ++ ++static t_Error CheckInitParameters(t_Dtsec *p_Dtsec) ++{ ++ if (ENET_SPEED_FROM_MODE(p_Dtsec->enetMode) >= e_ENET_SPEED_10000) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 1G MAC driver only supports 1G or lower speeds")); ++ if (p_Dtsec->macId >= FM_MAX_NUM_OF_1G_MACS) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("macId can not be greater than the number of 1G MACs")); ++ if (p_Dtsec->addr == 0) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet MAC Must have a valid MAC Address")); ++ if ((ENET_SPEED_FROM_MODE(p_Dtsec->enetMode) >= e_ENET_SPEED_1000) && ++ p_Dtsec->p_DtsecDriverParam->halfdup_on) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet MAC 1G can't work in half duplex")); ++ if (p_Dtsec->p_DtsecDriverParam->halfdup_on && (p_Dtsec->p_DtsecDriverParam)->loopback) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("LoopBack is not supported in halfDuplex mode")); ++#ifdef FM_RX_PREAM_4_ERRATA_DTSEC_A001 ++ if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev <= 6) /* fixed for rev3 */ ++ if (p_Dtsec->p_DtsecDriverParam->rx_preamble) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("preambleRxEn")); ++#endif /* FM_RX_PREAM_4_ERRATA_DTSEC_A001 */ ++ if (((p_Dtsec->p_DtsecDriverParam)->tx_preamble || (p_Dtsec->p_DtsecDriverParam)->rx_preamble) &&( (p_Dtsec->p_DtsecDriverParam)->preamble_len != 0x7)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Preamble length should be 0x7 bytes")); ++ if ((p_Dtsec->p_DtsecDriverParam)->halfdup_on && ++ (p_Dtsec->p_DtsecDriverParam->tx_time_stamp_en || p_Dtsec->p_DtsecDriverParam->rx_time_stamp_en)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dTSEC in half duplex mode has to be with 1588 timeStamping diable")); ++ if ((p_Dtsec->p_DtsecDriverParam)->rx_flow && (p_Dtsec->p_DtsecDriverParam)->rx_ctrl_acc ) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Receive control frame are not passed to the system memory so it can not be accept ")); ++ if ((p_Dtsec->p_DtsecDriverParam)->rx_prepend > MAX_PACKET_ALIGNMENT) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("packetAlignmentPadding can't be greater than %d ",MAX_PACKET_ALIGNMENT )); ++ if (((p_Dtsec->p_DtsecDriverParam)->non_back_to_back_ipg1 > MAX_INTER_PACKET_GAP) || ++ ((p_Dtsec->p_DtsecDriverParam)->non_back_to_back_ipg2 > MAX_INTER_PACKET_GAP) || ++ ((p_Dtsec->p_DtsecDriverParam)->back_to_back_ipg > MAX_INTER_PACKET_GAP)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inter packet gap can't be greater than %d ",MAX_INTER_PACKET_GAP )); ++ if ((p_Dtsec->p_DtsecDriverParam)->halfdup_alt_backoff_val > MAX_INTER_PALTERNATE_BEB) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("alternateBackoffVal can't be greater than %d ",MAX_INTER_PALTERNATE_BEB )); ++ if ((p_Dtsec->p_DtsecDriverParam)->halfdup_retransmit > MAX_RETRANSMISSION) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("maxRetransmission can't be greater than %d ",MAX_RETRANSMISSION )); ++ if ((p_Dtsec->p_DtsecDriverParam)->halfdup_coll_window > MAX_COLLISION_WINDOW) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("collisionWindow can't be greater than %d ",MAX_COLLISION_WINDOW )); ++ ++ /* If Auto negotiation process is disabled, need to */ ++ /* Set up the PHY using the MII Management Interface */ ++ if (p_Dtsec->p_DtsecDriverParam->tbipa > MAX_PHYS) ++ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ("PHY address (should be 0-%d)", MAX_PHYS)); ++ if (!p_Dtsec->f_Exception) ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("uninitialized f_Exception")); ++ if (!p_Dtsec->f_Event) ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("uninitialized f_Event")); ++ ++#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002 ++ if (p_Dtsec->p_DtsecDriverParam->rx_len_check) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("LengthCheck!")); ++#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */ ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static uint32_t GetMacAddrHashCode(uint64_t ethAddr) ++{ ++ uint32_t crc; ++ ++ /* CRC calculation */ ++ GET_MAC_ADDR_CRC(ethAddr, crc); ++ ++ crc = GetMirror32(crc); ++ ++ return crc; ++} ++ ++/* ......................................................................... */ ++ ++static void UpdateStatistics(t_Dtsec *p_Dtsec) ++{ ++ uint32_t car1, car2; ++ ++ fman_dtsec_get_clear_carry_regs(p_Dtsec->p_MemMap, &car1, &car2); ++ ++ if (car1) ++ { ++ if (car1 & CAR1_TR64) ++ p_Dtsec->internalStatistics.tr64 += VAL22BIT; ++ if (car1 & CAR1_TR127) ++ p_Dtsec->internalStatistics.tr127 += VAL22BIT; ++ if (car1 & CAR1_TR255) ++ p_Dtsec->internalStatistics.tr255 += VAL22BIT; ++ if (car1 & CAR1_TR511) ++ p_Dtsec->internalStatistics.tr511 += VAL22BIT; ++ if (car1 & CAR1_TRK1) ++ p_Dtsec->internalStatistics.tr1k += VAL22BIT; ++ if (car1 & CAR1_TRMAX) ++ p_Dtsec->internalStatistics.trmax += VAL22BIT; ++ if (car1 & CAR1_TRMGV) ++ p_Dtsec->internalStatistics.trmgv += VAL22BIT; ++ if (car1 & CAR1_RBYT) ++ p_Dtsec->internalStatistics.rbyt += (uint64_t)VAL32BIT; ++ if (car1 & CAR1_RPKT) ++ p_Dtsec->internalStatistics.rpkt += VAL22BIT; ++ if (car1 & CAR1_RMCA) ++ p_Dtsec->internalStatistics.rmca += VAL22BIT; ++ if (car1 & CAR1_RBCA) ++ p_Dtsec->internalStatistics.rbca += VAL22BIT; ++ if (car1 & CAR1_RXPF) ++ p_Dtsec->internalStatistics.rxpf += VAL16BIT; ++ if (car1 & CAR1_RALN) ++ p_Dtsec->internalStatistics.raln += VAL16BIT; ++ if (car1 & CAR1_RFLR) ++ p_Dtsec->internalStatistics.rflr += VAL16BIT; ++ if (car1 & CAR1_RCDE) ++ p_Dtsec->internalStatistics.rcde += VAL16BIT; ++ if (car1 & CAR1_RCSE) ++ p_Dtsec->internalStatistics.rcse += VAL16BIT; ++ if (car1 & CAR1_RUND) ++ p_Dtsec->internalStatistics.rund += VAL16BIT; ++ if (car1 & CAR1_ROVR) ++ p_Dtsec->internalStatistics.rovr += VAL16BIT; ++ if (car1 & CAR1_RFRG) ++ p_Dtsec->internalStatistics.rfrg += VAL16BIT; ++ if (car1 & CAR1_RJBR) ++ p_Dtsec->internalStatistics.rjbr += VAL16BIT; ++ if (car1 & CAR1_RDRP) ++ p_Dtsec->internalStatistics.rdrp += VAL16BIT; ++ } ++ if (car2) ++ { ++ if (car2 & CAR2_TFCS) ++ p_Dtsec->internalStatistics.tfcs += VAL12BIT; ++ if (car2 & CAR2_TBYT) ++ p_Dtsec->internalStatistics.tbyt += (uint64_t)VAL32BIT; ++ if (car2 & CAR2_TPKT) ++ p_Dtsec->internalStatistics.tpkt += VAL22BIT; ++ if (car2 & CAR2_TMCA) ++ p_Dtsec->internalStatistics.tmca += VAL22BIT; ++ if (car2 & CAR2_TBCA) ++ p_Dtsec->internalStatistics.tbca += VAL22BIT; ++ if (car2 & CAR2_TXPF) ++ p_Dtsec->internalStatistics.txpf += VAL16BIT; ++ if (car2 & CAR2_TDRP) ++ p_Dtsec->internalStatistics.tdrp += VAL16BIT; ++ } ++} ++ ++/* .............................................................................. */ ++ ++static uint16_t DtsecGetMaxFrameLength(t_Handle h_Dtsec) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_VALUE(p_Dtsec, E_INVALID_HANDLE, 0); ++ SANITY_CHECK_RETURN_VALUE(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE, 0); ++ ++ return fman_dtsec_get_max_frame_len(p_Dtsec->p_MemMap); ++} ++ ++/* .............................................................................. */ ++ ++static void DtsecIsr(t_Handle h_Dtsec) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ uint32_t event; ++ struct dtsec_regs *p_DtsecMemMap = p_Dtsec->p_MemMap; ++ ++ /* do not handle MDIO events */ ++ event = fman_dtsec_get_event(p_DtsecMemMap, (uint32_t)(~(DTSEC_IMASK_MMRDEN | DTSEC_IMASK_MMWREN))); ++ ++ event &= fman_dtsec_get_interrupt_mask(p_DtsecMemMap); ++ ++ fman_dtsec_ack_event(p_DtsecMemMap, event); ++ ++ if (event & DTSEC_IMASK_BREN) ++ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_BAB_RX); ++ if (event & DTSEC_IMASK_RXCEN) ++ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_RX_CTL); ++ if (event & DTSEC_IMASK_MSROEN) ++ UpdateStatistics(p_Dtsec); ++ if (event & DTSEC_IMASK_GTSCEN) ++ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET); ++ if (event & DTSEC_IMASK_BTEN) ++ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_BAB_TX); ++ if (event & DTSEC_IMASK_TXCEN) ++ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_CTL); ++ if (event & DTSEC_IMASK_TXEEN) ++ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_ERR); ++ if (event & DTSEC_IMASK_LCEN) ++ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_LATE_COL); ++ if (event & DTSEC_IMASK_CRLEN) ++ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_COL_RET_LMT); ++ if (event & DTSEC_IMASK_XFUNEN) ++ { ++#ifdef FM_TX_LOCKUP_ERRATA_DTSEC6 ++ if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2) ++ { ++ uint32_t tpkt1, tmpReg1, tpkt2, tmpReg2, i; ++ /* a. Write 0x00E0_0C00 to DTSEC_ID */ ++ /* This is a read only regidter */ ++ ++ /* b. Read and save the value of TPKT */ ++ tpkt1 = GET_UINT32(p_DtsecMemMap->tpkt); ++ ++ /* c. Read the register at dTSEC address offset 0x32C */ ++ tmpReg1 = GET_UINT32(*(uint32_t*)((uint8_t*)p_DtsecMemMap + 0x32c)); ++ ++ /* d. Compare bits [9:15] to bits [25:31] of the register at address offset 0x32C. */ ++ if ((tmpReg1 & 0x007F0000) != (tmpReg1 & 0x0000007F)) ++ { ++ /* If they are not equal, save the value of this register and wait for at least ++ * MAXFRM*16 ns */ ++ XX_UDelay((uint32_t)(MIN(DtsecGetMaxFrameLength(p_Dtsec)*16/1000, 1))); ++ } ++ ++ /* e. Read and save TPKT again and read the register at dTSEC address offset ++ 0x32C again*/ ++ tpkt2 = GET_UINT32(p_DtsecMemMap->tpkt); ++ tmpReg2 = GET_UINT32(*(uint32_t*)((uint8_t*)p_DtsecMemMap + 0x32c)); ++ ++ /* f. Compare the value of TPKT saved in step b to value read in step e. Also ++ compare bits [9:15] of the register at offset 0x32C saved in step d to the value ++ of bits [9:15] saved in step e. If the two registers values are unchanged, then ++ the transmit portion of the dTSEC controller is locked up and the user should ++ proceed to the recover sequence. */ ++ if ((tpkt1 == tpkt2) && ((tmpReg1 & 0x007F0000) == (tmpReg2 & 0x007F0000))) ++ { ++ /* recover sequence */ ++ ++ /* a.Write a 1 to RCTRL[GRS]*/ ++ ++ WRITE_UINT32(p_DtsecMemMap->rctrl, GET_UINT32(p_DtsecMemMap->rctrl) | RCTRL_GRS); ++ ++ /* b.Wait until IEVENT[GRSC]=1, or at least 100 us has elapsed. */ ++ for (i = 0 ; i < 100 ; i++ ) ++ { ++ if (GET_UINT32(p_DtsecMemMap->ievent) & DTSEC_IMASK_GRSCEN) ++ break; ++ XX_UDelay(1); ++ } ++ if (GET_UINT32(p_DtsecMemMap->ievent) & DTSEC_IMASK_GRSCEN) ++ WRITE_UINT32(p_DtsecMemMap->ievent, DTSEC_IMASK_GRSCEN); ++ else ++ DBG(INFO,("Rx lockup due to dTSEC Tx lockup")); ++ ++ /* c.Write a 1 to bit n of FM_RSTC (offset 0x0CC of FPM)*/ ++ FmResetMac(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MAC_1G, p_Dtsec->fmMacControllerDriver.macId); ++ ++ /* d.Wait 4 Tx clocks (32 ns) */ ++ XX_UDelay(1); ++ ++ /* e.Write a 0 to bit n of FM_RSTC. */ ++ /* cleared by FMAN */ ++ } ++ } ++#endif /* FM_TX_LOCKUP_ERRATA_DTSEC6 */ ++ ++ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_FIFO_UNDRN); ++ } ++ if (event & DTSEC_IMASK_MAGEN) ++ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_MAG_PCKT); ++ if (event & DTSEC_IMASK_GRSCEN) ++ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET); ++ if (event & DTSEC_IMASK_TDPEEN) ++ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_DATA_ERR); ++ if (event & DTSEC_IMASK_RDPEEN) ++ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_RX_DATA_ERR); ++ ++ /* - masked interrupts */ ++ ASSERT_COND(!(event & DTSEC_IMASK_ABRTEN)); ++ ASSERT_COND(!(event & DTSEC_IMASK_IFERREN)); ++} ++ ++static void DtsecMdioIsr(t_Handle h_Dtsec) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ uint32_t event; ++ struct dtsec_regs *p_DtsecMemMap = p_Dtsec->p_MemMap; ++ ++ event = GET_UINT32(p_DtsecMemMap->ievent); ++ /* handle only MDIO events */ ++ event &= (DTSEC_IMASK_MMRDEN | DTSEC_IMASK_MMWREN); ++ if (event) ++ { ++ event &= GET_UINT32(p_DtsecMemMap->imask); ++ ++ WRITE_UINT32(p_DtsecMemMap->ievent, event); ++ ++ if (event & DTSEC_IMASK_MMRDEN) ++ p_Dtsec->f_Event(p_Dtsec->h_App, e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET); ++ if (event & DTSEC_IMASK_MMWREN) ++ p_Dtsec->f_Event(p_Dtsec->h_App, e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET); ++ } ++} ++ ++static void Dtsec1588Isr(t_Handle h_Dtsec) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ uint32_t event; ++ struct dtsec_regs *p_DtsecMemMap = p_Dtsec->p_MemMap; ++ ++ if (p_Dtsec->ptpTsuEnabled) ++ { ++ event = fman_dtsec_check_and_clear_tmr_event(p_DtsecMemMap); ++ ++ if (event) ++ { ++ ASSERT_COND(event & TMR_PEVENT_TSRE); ++ p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_1588_TS_RX_ERR); ++ } ++ } ++} ++ ++/* ........................................................................... */ ++ ++static void FreeInitResources(t_Dtsec *p_Dtsec) ++{ ++ if (p_Dtsec->mdioIrq != NO_IRQ) ++ { ++ XX_DisableIntr(p_Dtsec->mdioIrq); ++ XX_FreeIntr(p_Dtsec->mdioIrq); ++ } ++ FmUnregisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Dtsec->macId, e_FM_INTR_TYPE_ERR); ++ FmUnregisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Dtsec->macId, e_FM_INTR_TYPE_NORMAL); ++ ++ /* release the driver's group hash table */ ++ FreeHashTable(p_Dtsec->p_MulticastAddrHash); ++ p_Dtsec->p_MulticastAddrHash = NULL; ++ ++ /* release the driver's individual hash table */ ++ FreeHashTable(p_Dtsec->p_UnicastAddrHash); ++ p_Dtsec->p_UnicastAddrHash = NULL; ++} ++ ++/* ........................................................................... */ ++ ++static t_Error GracefulStop(t_Dtsec *p_Dtsec, e_CommMode mode) ++{ ++ struct dtsec_regs *p_MemMap; ++ ++ ASSERT_COND(p_Dtsec); ++ ++ p_MemMap = p_Dtsec->p_MemMap; ++ ASSERT_COND(p_MemMap); ++ ++ /* Assert the graceful transmit stop bit */ ++ if (mode & e_COMM_MODE_RX) ++ { ++ fman_dtsec_stop_rx(p_MemMap); ++ ++#ifdef FM_GRS_ERRATA_DTSEC_A002 ++ if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2) ++ XX_UDelay(100); ++#else /* FM_GRS_ERRATA_DTSEC_A002 */ ++#ifdef FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839 ++ XX_UDelay(10); ++#endif /* FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839 */ ++#endif /* FM_GRS_ERRATA_DTSEC_A002 */ ++ } ++ ++ if (mode & e_COMM_MODE_TX) ++#if defined(FM_GTS_ERRATA_DTSEC_A004) || defined(FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012) ++ if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2) ++ DBG(INFO, ("GTS not supported due to DTSEC_A004 errata.")); ++#else /* not defined(FM_GTS_ERRATA_DTSEC_A004) ||... */ ++#ifdef FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014 ++ DBG(INFO, ("GTS not supported due to DTSEC_A0014 errata.")); ++#else /* FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014 */ ++ fman_dtsec_stop_tx(p_MemMap); ++#endif /* FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014 */ ++#endif /* defined(FM_GTS_ERRATA_DTSEC_A004) ||... */ ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error GracefulRestart(t_Dtsec *p_Dtsec, e_CommMode mode) ++{ ++ struct dtsec_regs *p_MemMap; ++ ++ ASSERT_COND(p_Dtsec); ++ p_MemMap = p_Dtsec->p_MemMap; ++ ASSERT_COND(p_MemMap); ++ ++ /* clear the graceful receive stop bit */ ++ if (mode & e_COMM_MODE_TX) ++ fman_dtsec_start_tx(p_MemMap); ++ ++ if (mode & e_COMM_MODE_RX) ++ fman_dtsec_start_rx(p_MemMap); ++ ++ return E_OK; ++} ++ ++ ++/*****************************************************************************/ ++/* dTSEC Configs modification functions */ ++/*****************************************************************************/ ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecConfigLoopback(t_Handle h_Dtsec, bool newVal) ++{ ++ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ p_Dtsec->p_DtsecDriverParam->loopback = newVal; ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecConfigMaxFrameLength(t_Handle h_Dtsec, uint16_t newVal) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ p_Dtsec->p_DtsecDriverParam->maximum_frame = newVal; ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecConfigPadAndCrc(t_Handle h_Dtsec, bool newVal) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ p_Dtsec->p_DtsecDriverParam->tx_pad_crc = newVal; ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecConfigHalfDuplex(t_Handle h_Dtsec, bool newVal) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ p_Dtsec->p_DtsecDriverParam->halfdup_on = newVal; ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecConfigTbiPhyAddr(t_Handle h_Dtsec, uint8_t newVal) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ p_Dtsec->p_DtsecDriverParam->tbi_phy_addr = newVal; ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecConfigLengthCheck(t_Handle h_Dtsec, bool newVal) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ p_Dtsec->p_DtsecDriverParam->rx_len_check = newVal; ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecConfigException(t_Handle h_Dtsec, e_FmMacExceptions exception, bool enable) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ uint32_t bitMask = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ if (exception != e_FM_MAC_EX_1G_1588_TS_RX_ERR) ++ { ++ GET_EXCEPTION_FLAG(bitMask, exception); ++ if (bitMask) ++ { ++ if (enable) ++ p_Dtsec->exceptions |= bitMask; ++ else ++ p_Dtsec->exceptions &= ~bitMask; ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); ++ } ++ else ++ { ++ if (!p_Dtsec->ptpTsuEnabled) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exception valid for 1588 only")); ++ ++ if (enable) ++ p_Dtsec->enTsuErrExeption = TRUE; ++ else ++ p_Dtsec->enTsuErrExeption = FALSE; ++ } ++ ++ return E_OK; ++} ++ ++ ++/*****************************************************************************/ ++/* dTSEC Run Time API functions */ ++/*****************************************************************************/ ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecEnable(t_Handle h_Dtsec, e_CommMode mode) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ fman_dtsec_enable(p_Dtsec->p_MemMap, ++ (bool)!!(mode & e_COMM_MODE_RX), ++ (bool)!!(mode & e_COMM_MODE_TX)); ++ ++ GracefulRestart(p_Dtsec, mode); ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecDisable (t_Handle h_Dtsec, e_CommMode mode) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ GracefulStop(p_Dtsec, mode); ++ ++ fman_dtsec_disable(p_Dtsec->p_MemMap, ++ (bool)!!(mode & e_COMM_MODE_RX), ++ (bool)!!(mode & e_COMM_MODE_TX)); ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecSetTxPauseFrames(t_Handle h_Dtsec, ++ uint8_t priority, ++ uint16_t pauseTime, ++ uint16_t threshTime) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ UNUSED(priority);UNUSED(threshTime); ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++#ifdef FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 ++ if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2) ++ if (0 < pauseTime && pauseTime <= 320) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, ++ ("This pause-time value of %d is illegal due to errata dTSEC-A003!" ++ " value should be greater than 320.")); ++#endif /* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 */ ++ ++ fman_dtsec_set_tx_pause_frames(p_Dtsec->p_MemMap, pauseTime); ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++/* backward compatibility. will be removed in the future. */ ++static t_Error DtsecTxMacPause(t_Handle h_Dtsec, uint16_t pauseTime) ++{ ++ return DtsecSetTxPauseFrames(h_Dtsec, 0, pauseTime, 0); ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecRxIgnoreMacPause(t_Handle h_Dtsec, bool en) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ bool accept_pause = !en; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ fman_dtsec_handle_rx_pause(p_Dtsec->p_MemMap, accept_pause); ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecEnable1588TimeStamp(t_Handle h_Dtsec) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ p_Dtsec->ptpTsuEnabled = TRUE; ++ fman_dtsec_set_ts(p_Dtsec->p_MemMap, TRUE); ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecDisable1588TimeStamp(t_Handle h_Dtsec) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ p_Dtsec->ptpTsuEnabled = FALSE; ++ fman_dtsec_set_ts(p_Dtsec->p_MemMap, FALSE); ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecGetStatistics(t_Handle h_Dtsec, t_FmMacStatistics *p_Statistics) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ struct dtsec_regs *p_DtsecMemMap; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_Statistics, E_NULL_POINTER); ++ ++ p_DtsecMemMap = p_Dtsec->p_MemMap; ++ ++ if (p_Dtsec->statisticsLevel == e_FM_MAC_NONE_STATISTICS) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Statistics disabled")); ++ ++ memset(p_Statistics, 0xff, sizeof(t_FmMacStatistics)); ++ ++ if (p_Dtsec->statisticsLevel == e_FM_MAC_FULL_STATISTICS) ++ { ++ p_Statistics->eStatPkts64 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR64) ++ + p_Dtsec->internalStatistics.tr64; ++ p_Statistics->eStatPkts65to127 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR127) ++ + p_Dtsec->internalStatistics.tr127; ++ p_Statistics->eStatPkts128to255 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR255) ++ + p_Dtsec->internalStatistics.tr255; ++ p_Statistics->eStatPkts256to511 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR511) ++ + p_Dtsec->internalStatistics.tr511; ++ p_Statistics->eStatPkts512to1023 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR1K) ++ + p_Dtsec->internalStatistics.tr1k; ++ p_Statistics->eStatPkts1024to1518 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TRMAX) ++ + p_Dtsec->internalStatistics.trmax; ++ p_Statistics->eStatPkts1519to1522 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TRMGV) ++ + p_Dtsec->internalStatistics.trmgv; ++ ++ /* MIB II */ ++ p_Statistics->ifInOctets = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RBYT) ++ + p_Dtsec->internalStatistics.rbyt; ++ p_Statistics->ifInPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RPKT) ++ + p_Dtsec->internalStatistics.rpkt; ++ p_Statistics->ifInUcastPkts = 0; ++ p_Statistics->ifInMcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RMCA) ++ + p_Dtsec->internalStatistics.rmca; ++ p_Statistics->ifInBcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RBCA) ++ + p_Dtsec->internalStatistics.rbca; ++ p_Statistics->ifOutOctets = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TBYT) ++ + p_Dtsec->internalStatistics.tbyt; ++ p_Statistics->ifOutPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TPKT) ++ + p_Dtsec->internalStatistics.tpkt; ++ p_Statistics->ifOutUcastPkts = 0; ++ p_Statistics->ifOutMcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TMCA) ++ + p_Dtsec->internalStatistics.tmca; ++ p_Statistics->ifOutBcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TBCA) ++ + p_Dtsec->internalStatistics.tbca; ++ } ++ ++ p_Statistics->eStatFragments = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RFRG) ++ + p_Dtsec->internalStatistics.rfrg; ++ p_Statistics->eStatJabbers = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RJBR) ++ + p_Dtsec->internalStatistics.rjbr; ++ p_Statistics->eStatsDropEvents = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RDRP) ++ + p_Dtsec->internalStatistics.rdrp; ++ p_Statistics->eStatCRCAlignErrors = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RALN) ++ + p_Dtsec->internalStatistics.raln; ++ p_Statistics->eStatUndersizePkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RUND) ++ + p_Dtsec->internalStatistics.rund; ++ p_Statistics->eStatOversizePkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_ROVR) ++ + p_Dtsec->internalStatistics.rovr; ++ p_Statistics->reStatPause = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RXPF) ++ + p_Dtsec->internalStatistics.rxpf; ++ p_Statistics->teStatPause = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TXPF) ++ + p_Dtsec->internalStatistics.txpf; ++ p_Statistics->ifInDiscards = p_Statistics->eStatsDropEvents; ++ p_Statistics->ifInErrors = p_Statistics->eStatsDropEvents + p_Statistics->eStatCRCAlignErrors ++ + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RFLR) + p_Dtsec->internalStatistics.rflr ++ + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RCDE) + p_Dtsec->internalStatistics.rcde ++ + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RCSE) + p_Dtsec->internalStatistics.rcse; ++ ++ p_Statistics->ifOutDiscards = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TDRP) ++ + p_Dtsec->internalStatistics.tdrp; ++ p_Statistics->ifOutErrors = p_Statistics->ifOutDiscards /**< Number of frames transmitted with error: */ ++ + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_TFCS) ++ + p_Dtsec->internalStatistics.tfcs; ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecModifyMacAddress (t_Handle h_Dtsec, t_EnetAddr *p_EnetAddr) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ /* Initialize MAC Station Address registers (1 & 2) */ ++ /* Station address have to be swapped (big endian to little endian */ ++ p_Dtsec->addr = ENET_ADDR_TO_UINT64(*p_EnetAddr); ++ fman_dtsec_set_mac_address(p_Dtsec->p_MemMap, (uint8_t *)(*p_EnetAddr)); ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecResetCounters (t_Handle h_Dtsec) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ /* clear HW counters */ ++ fman_dtsec_reset_stat(p_Dtsec->p_MemMap); ++ ++ /* clear SW counters holding carries */ ++ memset(&p_Dtsec->internalStatistics, 0, sizeof(t_InternalStatistics)); ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecAddExactMatchMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *) h_Dtsec; ++ uint64_t ethAddr; ++ uint8_t paddrNum; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); ++ ++ if (ethAddr & GROUP_ADDRESS) ++ /* Multicast address has no effect in PADDR */ ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Multicast address")); ++ ++ /* Make sure no PADDR contains this address */ ++ for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++) ++ if (p_Dtsec->indAddrRegUsed[paddrNum]) ++ if (p_Dtsec->paddr[paddrNum] == ethAddr) ++ RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG); ++ ++ /* Find first unused PADDR */ ++ for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++) ++ if (!(p_Dtsec->indAddrRegUsed[paddrNum])) ++ { ++ /* mark this PADDR as used */ ++ p_Dtsec->indAddrRegUsed[paddrNum] = TRUE; ++ /* store address */ ++ p_Dtsec->paddr[paddrNum] = ethAddr; ++ ++ /* put in hardware */ ++ fman_dtsec_add_addr_in_paddr(p_Dtsec->p_MemMap, (uint64_t)PTR_TO_UINT(ðAddr), paddrNum); ++ p_Dtsec->numOfIndAddrInRegs++; ++ ++ return E_OK; ++ } ++ ++ /* No free PADDR */ ++ RETURN_ERROR(MAJOR, E_FULL, NO_MSG); ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecDelExactMatchMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *) h_Dtsec; ++ uint64_t ethAddr; ++ uint8_t paddrNum; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); ++ ++ /* Find used PADDR containing this address */ ++ for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++) ++ { ++ if ((p_Dtsec->indAddrRegUsed[paddrNum]) && ++ (p_Dtsec->paddr[paddrNum] == ethAddr)) ++ { ++ /* mark this PADDR as not used */ ++ p_Dtsec->indAddrRegUsed[paddrNum] = FALSE; ++ /* clear in hardware */ ++ fman_dtsec_clear_addr_in_paddr(p_Dtsec->p_MemMap, paddrNum); ++ p_Dtsec->numOfIndAddrInRegs--; ++ ++ return E_OK; ++ } ++ } ++ ++ RETURN_ERROR(MAJOR, E_NOT_FOUND, NO_MSG); ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecAddHashMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ t_EthHashEntry *p_HashEntry; ++ uint64_t ethAddr; ++ int32_t bucket; ++ uint32_t crc; ++ bool mcast, ghtx; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); ++ ++ ghtx = (bool)((fman_dtsec_get_rctrl(p_Dtsec->p_MemMap) & RCTRL_GHTX) ? TRUE : FALSE); ++ mcast = (bool)((ethAddr & MAC_GROUP_ADDRESS) ? TRUE : FALSE); ++ ++ if (ghtx && !mcast) /* Cannot handle unicast mac addr when GHTX is on */ ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Could not compute hash bucket")); ++ ++ crc = GetMacAddrHashCode(ethAddr); ++ ++ /* considering the 9 highest order bits in crc H[8:0]: ++ * if ghtx = 0 H[8:6] (highest order 3 bits) identify the hash register ++ * and H[5:1] (next 5 bits) identify the hash bit ++ * if ghts = 1 H[8:5] (highest order 4 bits) identify the hash register ++ * and H[4:0] (next 5 bits) identify the hash bit. ++ * ++ * In bucket index output the low 5 bits identify the hash register bit, ++ * while the higher 4 bits identify the hash register ++ */ ++ ++ if (ghtx) ++ bucket = (int32_t)((crc >> 23) & 0x1ff); ++ else { ++ bucket = (int32_t)((crc >> 24) & 0xff); ++ /* if !ghtx and mcast the bit must be set in gaddr instead of igaddr. */ ++ if (mcast) ++ bucket += 0x100; ++ } ++ ++ fman_dtsec_set_bucket(p_Dtsec->p_MemMap, bucket, TRUE); ++ ++ /* Create element to be added to the driver hash table */ ++ p_HashEntry = (t_EthHashEntry *)XX_Malloc(sizeof(t_EthHashEntry)); ++ p_HashEntry->addr = ethAddr; ++ INIT_LIST(&p_HashEntry->node); ++ ++ if (ethAddr & MAC_GROUP_ADDRESS) ++ /* Group Address */ ++ LIST_AddToTail(&(p_HashEntry->node), &(p_Dtsec->p_MulticastAddrHash->p_Lsts[bucket])); ++ else ++ LIST_AddToTail(&(p_HashEntry->node), &(p_Dtsec->p_UnicastAddrHash->p_Lsts[bucket])); ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecDelHashMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ t_List *p_Pos; ++ t_EthHashEntry *p_HashEntry = NULL; ++ uint64_t ethAddr; ++ int32_t bucket; ++ uint32_t crc; ++ bool mcast, ghtx; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); ++ ++ ghtx = (bool)((fman_dtsec_get_rctrl(p_Dtsec->p_MemMap) & RCTRL_GHTX) ? TRUE : FALSE); ++ mcast = (bool)((ethAddr & MAC_GROUP_ADDRESS) ? TRUE : FALSE); ++ ++ if (ghtx && !mcast) /* Cannot handle unicast mac addr when GHTX is on */ ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Could not compute hash bucket")); ++ ++ crc = GetMacAddrHashCode(ethAddr); ++ ++ if (ghtx) ++ bucket = (int32_t)((crc >> 23) & 0x1ff); ++ else { ++ bucket = (int32_t)((crc >> 24) & 0xff); ++ /* if !ghtx and mcast the bit must be set in gaddr instead of igaddr. */ ++ if (mcast) ++ bucket += 0x100; ++ } ++ ++ if (ethAddr & MAC_GROUP_ADDRESS) ++ { ++ /* Group Address */ ++ LIST_FOR_EACH(p_Pos, &(p_Dtsec->p_MulticastAddrHash->p_Lsts[bucket])) ++ { ++ p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos); ++ if (p_HashEntry->addr == ethAddr) ++ { ++ LIST_DelAndInit(&p_HashEntry->node); ++ XX_Free(p_HashEntry); ++ break; ++ } ++ } ++ if (LIST_IsEmpty(&p_Dtsec->p_MulticastAddrHash->p_Lsts[bucket])) ++ fman_dtsec_set_bucket(p_Dtsec->p_MemMap, bucket, FALSE); ++ } ++ else ++ { ++ /* Individual Address */ ++ LIST_FOR_EACH(p_Pos, &(p_Dtsec->p_UnicastAddrHash->p_Lsts[bucket])) ++ { ++ p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos); ++ if (p_HashEntry->addr == ethAddr) ++ { ++ LIST_DelAndInit(&p_HashEntry->node); ++ XX_Free(p_HashEntry); ++ break; ++ } ++ } ++ if (LIST_IsEmpty(&p_Dtsec->p_UnicastAddrHash->p_Lsts[bucket])) ++ fman_dtsec_set_bucket(p_Dtsec->p_MemMap, bucket, FALSE); ++ } ++ ++ /* address does not exist */ ++ ASSERT_COND(p_HashEntry != NULL); ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecSetPromiscuous(t_Handle h_Dtsec, bool newVal) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ fman_dtsec_set_uc_promisc(p_Dtsec->p_MemMap, newVal); ++ fman_dtsec_set_mc_promisc(p_Dtsec->p_MemMap, newVal); ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecSetStatistics(t_Handle h_Dtsec, e_FmMacStatisticsLevel statisticsLevel) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ p_Dtsec->statisticsLevel = statisticsLevel; ++ ++ err = (t_Error)fman_dtsec_set_stat_level(p_Dtsec->p_MemMap, ++ (enum dtsec_stat_level)statisticsLevel); ++ if (err != E_OK) ++ return err; ++ ++ switch (statisticsLevel) ++ { ++ case (e_FM_MAC_NONE_STATISTICS): ++ p_Dtsec->exceptions &= ~DTSEC_IMASK_MSROEN; ++ break; ++ case (e_FM_MAC_PARTIAL_STATISTICS): ++ p_Dtsec->exceptions |= DTSEC_IMASK_MSROEN; ++ break; ++ case (e_FM_MAC_FULL_STATISTICS): ++ p_Dtsec->exceptions |= DTSEC_IMASK_MSROEN; ++ break; ++ default: ++ RETURN_ERROR(MINOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecSetWakeOnLan(t_Handle h_Dtsec, bool en) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ fman_dtsec_set_wol(p_Dtsec->p_MemMap, en); ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecAdjustLink(t_Handle h_Dtsec, e_EnetSpeed speed, bool fullDuplex) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ int err; ++ enum enet_interface enet_interface; ++ enum enet_speed enet_speed; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ p_Dtsec->enetMode = MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode), speed); ++ enet_interface = (enum enet_interface) ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode); ++ enet_speed = (enum enet_speed) ENET_SPEED_FROM_MODE(p_Dtsec->enetMode); ++ p_Dtsec->halfDuplex = !fullDuplex; ++ ++ err = fman_dtsec_adjust_link(p_Dtsec->p_MemMap, enet_interface, enet_speed, fullDuplex); ++ ++ if (err == -EINVAL) ++ RETURN_ERROR(MAJOR, E_CONFLICT, ("Ethernet interface does not support Half Duplex mode")); ++ ++ return (t_Error)err; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecRestartAutoneg(t_Handle h_Dtsec) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ uint16_t tmpReg16; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ DTSEC_MII_ReadPhyReg(p_Dtsec, p_Dtsec->tbi_phy_addr, 0, &tmpReg16); ++ ++ tmpReg16 &= ~( PHY_CR_SPEED0 | PHY_CR_SPEED1 ); ++ tmpReg16 |= (PHY_CR_ANE | PHY_CR_RESET_AN | PHY_CR_FULLDUPLEX | PHY_CR_SPEED1); ++ ++ DTSEC_MII_WritePhyReg(p_Dtsec, p_Dtsec->tbi_phy_addr, 0, tmpReg16); ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecGetId(t_Handle h_Dtsec, uint32_t *macId) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ *macId = p_Dtsec->macId; ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecGetVersion(t_Handle h_Dtsec, uint32_t *macVersion) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ *macVersion = fman_dtsec_get_revision(p_Dtsec->p_MemMap); ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecSetException(t_Handle h_Dtsec, e_FmMacExceptions exception, bool enable) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ uint32_t bitMask = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ ++ if (exception != e_FM_MAC_EX_1G_1588_TS_RX_ERR) ++ { ++ GET_EXCEPTION_FLAG(bitMask, exception); ++ if (bitMask) ++ { ++ if (enable) ++ p_Dtsec->exceptions |= bitMask; ++ else ++ p_Dtsec->exceptions &= ~bitMask; ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); ++ ++ if (enable) ++ fman_dtsec_enable_interrupt(p_Dtsec->p_MemMap, bitMask); ++ else ++ fman_dtsec_disable_interrupt(p_Dtsec->p_MemMap, bitMask); ++ } ++ else ++ { ++ if (!p_Dtsec->ptpTsuEnabled) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exception valid for 1588 only")); ++ ++ if (enable) ++ { ++ p_Dtsec->enTsuErrExeption = TRUE; ++ fman_dtsec_enable_tmr_interrupt(p_Dtsec->p_MemMap); ++ } ++ else ++ { ++ p_Dtsec->enTsuErrExeption = FALSE; ++ fman_dtsec_disable_tmr_interrupt(p_Dtsec->p_MemMap); ++ } ++ } ++ ++ return E_OK; ++} ++ ++ ++/*****************************************************************************/ ++/* dTSEC Init & Free API */ ++/*****************************************************************************/ ++ ++/* .............................................................................. */ ++ ++static t_Error DtsecInit(t_Handle h_Dtsec) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ struct dtsec_cfg *p_DtsecDriverParam; ++ t_Error err; ++ uint16_t maxFrmLn; ++ enum enet_interface enet_interface; ++ enum enet_speed enet_speed; ++ t_EnetAddr ethAddr; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec->fmMacControllerDriver.h_Fm, E_INVALID_HANDLE); ++ ++ FM_GetRevision(p_Dtsec->fmMacControllerDriver.h_Fm, &p_Dtsec->fmMacControllerDriver.fmRevInfo); ++ CHECK_INIT_PARAMETERS(p_Dtsec, CheckInitParameters); ++ ++ p_DtsecDriverParam = p_Dtsec->p_DtsecDriverParam; ++ p_Dtsec->halfDuplex = p_DtsecDriverParam->halfdup_on; ++ ++ enet_interface = (enum enet_interface)ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode); ++ enet_speed = (enum enet_speed)ENET_SPEED_FROM_MODE(p_Dtsec->enetMode); ++ MAKE_ENET_ADDR_FROM_UINT64(p_Dtsec->addr, ethAddr); ++ ++ err = (t_Error)fman_dtsec_init(p_Dtsec->p_MemMap, ++ p_DtsecDriverParam, ++ enet_interface, ++ enet_speed, ++ (uint8_t*)ethAddr, ++ p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev, ++ p_Dtsec->fmMacControllerDriver.fmRevInfo.minorRev, ++ p_Dtsec->exceptions); ++ if (err) ++ { ++ FreeInitResources(p_Dtsec); ++ RETURN_ERROR(MAJOR, err, ("This DTSEC version does not support the required i/f mode")); ++ } ++ ++ if (ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode) == e_ENET_IF_SGMII) ++ { ++ uint16_t tmpReg16; ++ ++ /* Configure the TBI PHY Control Register */ ++ tmpReg16 = PHY_TBICON_CLK_SEL | PHY_TBICON_SRESET; ++ DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 17, tmpReg16); ++ ++ tmpReg16 = PHY_TBICON_CLK_SEL; ++ DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 17, tmpReg16); ++ ++ tmpReg16 = (PHY_CR_PHY_RESET | PHY_CR_ANE | PHY_CR_FULLDUPLEX | PHY_CR_SPEED1); ++ DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 0, tmpReg16); ++ ++ if (p_Dtsec->enetMode & ENET_IF_SGMII_BASEX) ++ tmpReg16 = PHY_TBIANA_1000X; ++ else ++ tmpReg16 = PHY_TBIANA_SGMII; ++ DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 4, tmpReg16); ++ ++ tmpReg16 = (PHY_CR_ANE | PHY_CR_RESET_AN | PHY_CR_FULLDUPLEX | PHY_CR_SPEED1); ++ ++ DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 0, tmpReg16); ++ } ++ ++ /* Max Frame Length */ ++ maxFrmLn = fman_dtsec_get_max_frame_len(p_Dtsec->p_MemMap); ++ err = FmSetMacMaxFrame(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MAC_1G, ++ p_Dtsec->fmMacControllerDriver.macId, maxFrmLn); ++ if (err) ++ RETURN_ERROR(MINOR,err, NO_MSG); ++ ++ p_Dtsec->p_MulticastAddrHash = AllocHashTable(EXTENDED_HASH_TABLE_SIZE); ++ if (!p_Dtsec->p_MulticastAddrHash) { ++ FreeInitResources(p_Dtsec); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MC hash table is FAILED")); ++ } ++ ++ p_Dtsec->p_UnicastAddrHash = AllocHashTable(HASH_TABLE_SIZE); ++ if (!p_Dtsec->p_UnicastAddrHash) ++ { ++ FreeInitResources(p_Dtsec); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("UC hash table is FAILED")); ++ } ++ ++ /* register err intr handler for dtsec to FPM (err)*/ ++ FmRegisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, ++ e_FM_MOD_1G_MAC, ++ p_Dtsec->macId, ++ e_FM_INTR_TYPE_ERR, ++ DtsecIsr, ++ p_Dtsec); ++ /* register 1588 intr handler for TMR to FPM (normal)*/ ++ FmRegisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, ++ e_FM_MOD_1G_MAC, ++ p_Dtsec->macId, ++ e_FM_INTR_TYPE_NORMAL, ++ Dtsec1588Isr, ++ p_Dtsec); ++ /* register normal intr handler for dtsec to main interrupt controller. */ ++ if (p_Dtsec->mdioIrq != NO_IRQ) ++ { ++ XX_SetIntr(p_Dtsec->mdioIrq, DtsecMdioIsr, p_Dtsec); ++ XX_EnableIntr(p_Dtsec->mdioIrq); ++ } ++ ++ XX_Free(p_DtsecDriverParam); ++ p_Dtsec->p_DtsecDriverParam = NULL; ++ ++ err = DtsecSetStatistics(h_Dtsec, e_FM_MAC_FULL_STATISTICS); ++ if (err) ++ { ++ FreeInitResources(p_Dtsec); ++ RETURN_ERROR(MAJOR, err, ("Undefined statistics level")); ++ } ++ ++ return E_OK; ++} ++ ++/* ........................................................................... */ ++ ++static t_Error DtsecFree(t_Handle h_Dtsec) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ ++ if (p_Dtsec->p_DtsecDriverParam) ++ { ++ /* Called after config */ ++ XX_Free(p_Dtsec->p_DtsecDriverParam); ++ p_Dtsec->p_DtsecDriverParam = NULL; ++ } ++ else ++ /* Called after init */ ++ FreeInitResources(p_Dtsec); ++ ++ XX_Free(p_Dtsec); ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static void InitFmMacControllerDriver(t_FmMacControllerDriver *p_FmMacControllerDriver) ++{ ++ p_FmMacControllerDriver->f_FM_MAC_Init = DtsecInit; ++ p_FmMacControllerDriver->f_FM_MAC_Free = DtsecFree; ++ ++ p_FmMacControllerDriver->f_FM_MAC_SetStatistics = DtsecSetStatistics; ++ p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback = DtsecConfigLoopback; ++ p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength = DtsecConfigMaxFrameLength; ++ ++ p_FmMacControllerDriver->f_FM_MAC_ConfigWan = NULL; /* Not supported on dTSEC */ ++ ++ p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc = DtsecConfigPadAndCrc; ++ p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex = DtsecConfigHalfDuplex; ++ p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck = DtsecConfigLengthCheck; ++ p_FmMacControllerDriver->f_FM_MAC_ConfigTbiPhyAddr = DtsecConfigTbiPhyAddr; ++ p_FmMacControllerDriver->f_FM_MAC_ConfigException = DtsecConfigException; ++ p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit = NULL; ++ ++ p_FmMacControllerDriver->f_FM_MAC_Enable = DtsecEnable; ++ p_FmMacControllerDriver->f_FM_MAC_Disable = DtsecDisable; ++ p_FmMacControllerDriver->f_FM_MAC_Resume = NULL; ++ ++ p_FmMacControllerDriver->f_FM_MAC_SetException = DtsecSetException; ++ ++ p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous = DtsecSetPromiscuous; ++ p_FmMacControllerDriver->f_FM_MAC_AdjustLink = DtsecAdjustLink; ++ p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan = DtsecSetWakeOnLan; ++ p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg = DtsecRestartAutoneg; ++ ++ p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp = DtsecEnable1588TimeStamp; ++ p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp = DtsecDisable1588TimeStamp; ++ ++ p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames = DtsecTxMacPause; ++ p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames = DtsecSetTxPauseFrames; ++ p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames = DtsecRxIgnoreMacPause; ++ ++ p_FmMacControllerDriver->f_FM_MAC_ResetCounters = DtsecResetCounters; ++ p_FmMacControllerDriver->f_FM_MAC_GetStatistics = DtsecGetStatistics; ++ ++ p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr = DtsecModifyMacAddress; ++ p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr = DtsecAddHashMacAddress; ++ p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr = DtsecDelHashMacAddress; ++ p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr = DtsecAddExactMatchMacAddress; ++ p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr = DtsecDelExactMatchMacAddress; ++ p_FmMacControllerDriver->f_FM_MAC_GetId = DtsecGetId; ++ p_FmMacControllerDriver->f_FM_MAC_GetVersion = DtsecGetVersion; ++ p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength = DtsecGetMaxFrameLength; ++ ++ p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg = DTSEC_MII_WritePhyReg; ++ p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg = DTSEC_MII_ReadPhyReg; ++ ++} ++ ++ ++/*****************************************************************************/ ++/* dTSEC Config Main Entry */ ++/*****************************************************************************/ ++ ++/* .............................................................................. */ ++ ++t_Handle DTSEC_Config(t_FmMacParams *p_FmMacParam) ++{ ++ t_Dtsec *p_Dtsec; ++ struct dtsec_cfg *p_DtsecDriverParam; ++ uintptr_t baseAddr; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_NULL_POINTER, NULL); ++ ++ baseAddr = p_FmMacParam->baseAddr; ++ ++ /* allocate memory for the UCC GETH data structure. */ ++ p_Dtsec = (t_Dtsec *)XX_Malloc(sizeof(t_Dtsec)); ++ if (!p_Dtsec) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("dTSEC driver structure")); ++ return NULL; ++ } ++ memset(p_Dtsec, 0, sizeof(t_Dtsec)); ++ InitFmMacControllerDriver(&p_Dtsec->fmMacControllerDriver); ++ ++ /* allocate memory for the dTSEC driver parameters data structure. */ ++ p_DtsecDriverParam = (struct dtsec_cfg *) XX_Malloc(sizeof(struct dtsec_cfg)); ++ if (!p_DtsecDriverParam) ++ { ++ XX_Free(p_Dtsec); ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("dTSEC driver parameters")); ++ return NULL; ++ } ++ memset(p_DtsecDriverParam, 0, sizeof(struct dtsec_cfg)); ++ ++ /* Plant parameter structure pointer */ ++ p_Dtsec->p_DtsecDriverParam = p_DtsecDriverParam; ++ ++ fman_dtsec_defconfig(p_DtsecDriverParam); ++ ++ p_Dtsec->p_MemMap = (struct dtsec_regs *)UINT_TO_PTR(baseAddr); ++ p_Dtsec->p_MiiMemMap = (struct dtsec_mii_reg *)UINT_TO_PTR(baseAddr + DTSEC_TO_MII_OFFSET); ++ p_Dtsec->addr = ENET_ADDR_TO_UINT64(p_FmMacParam->addr); ++ p_Dtsec->enetMode = p_FmMacParam->enetMode; ++ p_Dtsec->macId = p_FmMacParam->macId; ++ p_Dtsec->exceptions = DEFAULT_exceptions; ++ p_Dtsec->mdioIrq = p_FmMacParam->mdioIrq; ++ p_Dtsec->f_Exception = p_FmMacParam->f_Exception; ++ p_Dtsec->f_Event = p_FmMacParam->f_Event; ++ p_Dtsec->h_App = p_FmMacParam->h_App; ++ p_Dtsec->ptpTsuEnabled = p_Dtsec->p_DtsecDriverParam->ptp_tsu_en; ++ p_Dtsec->enTsuErrExeption = p_Dtsec->p_DtsecDriverParam->ptp_exception_en; ++ p_Dtsec->tbi_phy_addr = p_Dtsec->p_DtsecDriverParam->tbi_phy_addr; ++ ++ return p_Dtsec; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.h +new file mode 100644 +index 00000000..c26f40cc +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.h +@@ -0,0 +1,228 @@ ++/* ++ * Copyright 2008-2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/****************************************************************************** ++ @File dtsec.h ++ ++ @Description FM dTSEC ... ++*//***************************************************************************/ ++#ifndef __DTSEC_H ++#define __DTSEC_H ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "list_ext.h" ++#include "enet_ext.h" ++ ++#include "dtsec_mii_acc.h" ++#include "fm_mac.h" ++ ++ ++#define DEFAULT_exceptions \ ++ ((uint32_t)(DTSEC_IMASK_BREN | \ ++ DTSEC_IMASK_RXCEN | \ ++ DTSEC_IMASK_BTEN | \ ++ DTSEC_IMASK_TXCEN | \ ++ DTSEC_IMASK_TXEEN | \ ++ DTSEC_IMASK_ABRTEN | \ ++ DTSEC_IMASK_LCEN | \ ++ DTSEC_IMASK_CRLEN | \ ++ DTSEC_IMASK_XFUNEN | \ ++ DTSEC_IMASK_IFERREN | \ ++ DTSEC_IMASK_MAGEN | \ ++ DTSEC_IMASK_TDPEEN | \ ++ DTSEC_IMASK_RDPEEN)) ++ ++#define GET_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \ ++ case e_FM_MAC_EX_1G_BAB_RX: \ ++ bitMask = DTSEC_IMASK_BREN; break; \ ++ case e_FM_MAC_EX_1G_RX_CTL: \ ++ bitMask = DTSEC_IMASK_RXCEN; break; \ ++ case e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET: \ ++ bitMask = DTSEC_IMASK_GTSCEN ; break; \ ++ case e_FM_MAC_EX_1G_BAB_TX: \ ++ bitMask = DTSEC_IMASK_BTEN ; break; \ ++ case e_FM_MAC_EX_1G_TX_CTL: \ ++ bitMask = DTSEC_IMASK_TXCEN ; break; \ ++ case e_FM_MAC_EX_1G_TX_ERR: \ ++ bitMask = DTSEC_IMASK_TXEEN ; break; \ ++ case e_FM_MAC_EX_1G_LATE_COL: \ ++ bitMask = DTSEC_IMASK_LCEN ; break; \ ++ case e_FM_MAC_EX_1G_COL_RET_LMT: \ ++ bitMask = DTSEC_IMASK_CRLEN ; break; \ ++ case e_FM_MAC_EX_1G_TX_FIFO_UNDRN: \ ++ bitMask = DTSEC_IMASK_XFUNEN ; break; \ ++ case e_FM_MAC_EX_1G_MAG_PCKT: \ ++ bitMask = DTSEC_IMASK_MAGEN ; break; \ ++ case e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET: \ ++ bitMask = DTSEC_IMASK_MMRDEN; break; \ ++ case e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET: \ ++ bitMask = DTSEC_IMASK_MMWREN ; break; \ ++ case e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET: \ ++ bitMask = DTSEC_IMASK_GRSCEN; break; \ ++ case e_FM_MAC_EX_1G_TX_DATA_ERR: \ ++ bitMask = DTSEC_IMASK_TDPEEN; break; \ ++ case e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL: \ ++ bitMask = DTSEC_IMASK_MSROEN ; break; \ ++ default: bitMask = 0;break;} ++ ++ ++#define MAX_PACKET_ALIGNMENT 31 ++#define MAX_INTER_PACKET_GAP 0x7f ++#define MAX_INTER_PALTERNATE_BEB 0x0f ++#define MAX_RETRANSMISSION 0x0f ++#define MAX_COLLISION_WINDOW 0x03ff ++ ++ ++/********************* From mac ext ******************************************/ ++typedef uint32_t t_ErrorDisable; ++ ++#define ERROR_DISABLE_TRANSMIT 0x00400000 ++#define ERROR_DISABLE_LATE_COLLISION 0x00040000 ++#define ERROR_DISABLE_COLLISION_RETRY_LIMIT 0x00020000 ++#define ERROR_DISABLE_TxFIFO_UNDERRUN 0x00010000 ++#define ERROR_DISABLE_TxABORT 0x00008000 ++#define ERROR_DISABLE_INTERFACE 0x00004000 ++#define ERROR_DISABLE_TxDATA_PARITY 0x00000002 ++#define ERROR_DISABLE_RxDATA_PARITY 0x00000001 ++ ++/*****************************************************************************/ ++#define DTSEC_NUM_OF_PADDRS 15 /* number of pattern match registers (entries) */ ++ ++#define GROUP_ADDRESS 0x0000010000000000LL /* Group address bit indication */ ++ ++#define HASH_TABLE_SIZE 256 /* Hash table size (= 32 bits * 8 regs) */ ++ ++#define HASH_TABLE_SIZE 256 /* Hash table size (32 bits * 8 regs) */ ++#define EXTENDED_HASH_TABLE_SIZE 512 /* Extended Hash table size (32 bits * 16 regs) */ ++ ++#define DTSEC_TO_MII_OFFSET 0x1000 /* number of pattern match registers (entries) */ ++ ++#define MAX_PHYS 32 /* maximum number of phys */ ++ ++#define VAL32BIT 0x100000000LL ++#define VAL22BIT 0x00400000 ++#define VAL16BIT 0x00010000 ++#define VAL12BIT 0x00001000 ++ ++/* CAR1/2 bits */ ++#define CAR1_TR64 0x80000000 ++#define CAR1_TR127 0x40000000 ++#define CAR1_TR255 0x20000000 ++#define CAR1_TR511 0x10000000 ++#define CAR1_TRK1 0x08000000 ++#define CAR1_TRMAX 0x04000000 ++#define CAR1_TRMGV 0x02000000 ++ ++#define CAR1_RBYT 0x00010000 ++#define CAR1_RPKT 0x00008000 ++#define CAR1_RMCA 0x00002000 ++#define CAR1_RBCA 0x00001000 ++#define CAR1_RXPF 0x00000400 ++#define CAR1_RALN 0x00000100 ++#define CAR1_RFLR 0x00000080 ++#define CAR1_RCDE 0x00000040 ++#define CAR1_RCSE 0x00000020 ++#define CAR1_RUND 0x00000010 ++#define CAR1_ROVR 0x00000008 ++#define CAR1_RFRG 0x00000004 ++#define CAR1_RJBR 0x00000002 ++#define CAR1_RDRP 0x00000001 ++ ++#define CAR2_TFCS 0x00040000 ++#define CAR2_TBYT 0x00002000 ++#define CAR2_TPKT 0x00001000 ++#define CAR2_TMCA 0x00000800 ++#define CAR2_TBCA 0x00000400 ++#define CAR2_TXPF 0x00000200 ++#define CAR2_TDRP 0x00000001 ++ ++typedef struct t_InternalStatistics ++{ ++ uint64_t tr64; ++ uint64_t tr127; ++ uint64_t tr255; ++ uint64_t tr511; ++ uint64_t tr1k; ++ uint64_t trmax; ++ uint64_t trmgv; ++ uint64_t rfrg; ++ uint64_t rjbr; ++ uint64_t rdrp; ++ uint64_t raln; ++ uint64_t rund; ++ uint64_t rovr; ++ uint64_t rxpf; ++ uint64_t txpf; ++ uint64_t rbyt; ++ uint64_t rpkt; ++ uint64_t rmca; ++ uint64_t rbca; ++ uint64_t rflr; ++ uint64_t rcde; ++ uint64_t rcse; ++ uint64_t tbyt; ++ uint64_t tpkt; ++ uint64_t tmca; ++ uint64_t tbca; ++ uint64_t tdrp; ++ uint64_t tfcs; ++} t_InternalStatistics; ++ ++typedef struct { ++ t_FmMacControllerDriver fmMacControllerDriver; ++ t_Handle h_App; /**< Handle to the upper layer application */ ++ struct dtsec_regs *p_MemMap; /**< pointer to dTSEC memory mapped registers. */ ++ struct dtsec_mii_reg *p_MiiMemMap; /**< pointer to dTSEC MII memory mapped registers. */ ++ uint64_t addr; /**< MAC address of device; */ ++ e_EnetMode enetMode; /**< Ethernet physical interface */ ++ t_FmMacExceptionCallback *f_Exception; ++ int mdioIrq; ++ t_FmMacExceptionCallback *f_Event; ++ bool indAddrRegUsed[DTSEC_NUM_OF_PADDRS]; /**< Whether a particular individual address recognition register is being used */ ++ uint64_t paddr[DTSEC_NUM_OF_PADDRS]; /**< MAC address for particular individual address recognition register */ ++ uint8_t numOfIndAddrInRegs; /**< Number of individual addresses in registers for this station. */ ++ bool halfDuplex; ++ t_InternalStatistics internalStatistics; ++ t_EthHash *p_MulticastAddrHash; /* pointer to driver's global address hash table */ ++ t_EthHash *p_UnicastAddrHash; /* pointer to driver's individual address hash table */ ++ uint8_t macId; ++ uint8_t tbi_phy_addr; ++ uint32_t exceptions; ++ bool ptpTsuEnabled; ++ bool enTsuErrExeption; ++ e_FmMacStatisticsLevel statisticsLevel; ++ struct dtsec_cfg *p_DtsecDriverParam; ++} t_Dtsec; ++ ++ ++#endif /* __DTSEC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.c +new file mode 100644 +index 00000000..87da25ff +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.c +@@ -0,0 +1,97 @@ ++/* ++ * Copyright 2008-2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File dtsec_mii_acc.c ++ ++ @Description FM dtsec MII register access MAC ... ++*//***************************************************************************/ ++ ++#include "error_ext.h" ++#include "std_ext.h" ++#include "fm_mac.h" ++#include "dtsec.h" ++#include "fsl_fman_dtsec_mii_acc.h" ++ ++ ++/*****************************************************************************/ ++t_Error DTSEC_MII_WritePhyReg(t_Handle h_Dtsec, ++ uint8_t phyAddr, ++ uint8_t reg, ++ uint16_t data) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ struct dtsec_mii_reg *miiregs; ++ uint16_t dtsec_freq; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MiiMemMap, E_INVALID_HANDLE); ++ ++ dtsec_freq = (uint16_t)(p_Dtsec->fmMacControllerDriver.clkFreq >> 1); ++ miiregs = p_Dtsec->p_MiiMemMap; ++ ++ err = (t_Error)fman_dtsec_mii_write_reg(miiregs, phyAddr, reg, data, dtsec_freq); ++ ++ return err; ++} ++ ++/*****************************************************************************/ ++t_Error DTSEC_MII_ReadPhyReg(t_Handle h_Dtsec, ++ uint8_t phyAddr, ++ uint8_t reg, ++ uint16_t *p_Data) ++{ ++ t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; ++ struct dtsec_mii_reg *miiregs; ++ uint16_t dtsec_freq; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MiiMemMap, E_INVALID_HANDLE); ++ ++ dtsec_freq = (uint16_t)(p_Dtsec->fmMacControllerDriver.clkFreq >> 1); ++ miiregs = p_Dtsec->p_MiiMemMap; ++ ++ err = fman_dtsec_mii_read_reg(miiregs, phyAddr, reg, p_Data, dtsec_freq); ++ ++ if (*p_Data == 0xffff) ++ RETURN_ERROR(MINOR, E_NO_DEVICE, ++ ("Read wrong data (0xffff): phyAddr 0x%x, reg 0x%x", ++ phyAddr, reg)); ++ if (err) ++ RETURN_ERROR(MINOR, (t_Error)err, NO_MSG); ++ ++ return E_OK; ++} ++ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.h +new file mode 100644 +index 00000000..75cc658a +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.h +@@ -0,0 +1,42 @@ ++/* ++ * Copyright 2008-2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __DTSEC_MII_ACC_H ++#define __DTSEC_MII_ACC_H ++ ++#include "std_ext.h" ++ ++ ++t_Error DTSEC_MII_WritePhyReg(t_Handle h_Dtsec, uint8_t phyAddr, uint8_t reg, uint16_t data); ++t_Error DTSEC_MII_ReadPhyReg(t_Handle h_Dtsec, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data); ++ ++#endif /* __DTSEC_MII_ACC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c +new file mode 100644 +index 00000000..20bf150a +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c +@@ -0,0 +1,658 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_mac.c ++ ++ @Description FM MAC ... ++*//***************************************************************************/ ++#include "std_ext.h" ++#include "string_ext.h" ++#include "sprint_ext.h" ++#include "error_ext.h" ++#include "fm_ext.h" ++ ++#include "fm_common.h" ++#include "fm_mac.h" ++ ++ ++/* ......................................................................... */ ++ ++t_Handle FM_MAC_Config (t_FmMacParams *p_FmMacParam) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver; ++ uint16_t fmClkFreq; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_INVALID_HANDLE, NULL); ++ ++ fmClkFreq = FmGetClockFreq(p_FmMacParam->h_Fm); ++ if (fmClkFreq == 0) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Can't get clock for MAC!")); ++ return NULL; ++ } ++ ++#if (DPAA_VERSION == 10) ++ if (ENET_SPEED_FROM_MODE(p_FmMacParam->enetMode) < e_ENET_SPEED_10000) ++ p_FmMacControllerDriver = (t_FmMacControllerDriver *)DTSEC_Config(p_FmMacParam); ++ else ++#if FM_MAX_NUM_OF_10G_MACS > 0 ++ p_FmMacControllerDriver = (t_FmMacControllerDriver *)TGEC_Config(p_FmMacParam); ++#else ++ p_FmMacControllerDriver = NULL; ++#endif /* FM_MAX_NUM_OF_10G_MACS > 0 */ ++#else ++ p_FmMacControllerDriver = (t_FmMacControllerDriver *)MEMAC_Config(p_FmMacParam); ++#endif /* (DPAA_VERSION == 10) */ ++ ++ if (!p_FmMacControllerDriver) ++ return NULL; ++ ++ p_FmMacControllerDriver->h_Fm = p_FmMacParam->h_Fm; ++ p_FmMacControllerDriver->enetMode = p_FmMacParam->enetMode; ++ p_FmMacControllerDriver->macId = p_FmMacParam->macId; ++ p_FmMacControllerDriver->resetOnInit = DEFAULT_resetOnInit; ++ ++ p_FmMacControllerDriver->clkFreq = fmClkFreq; ++ ++ return (t_Handle)p_FmMacControllerDriver; ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_Init (t_Handle h_FmMac) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->resetOnInit && ++ !p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit && ++ (FmResetMac(p_FmMacControllerDriver->h_Fm, ++ ((ENET_INTERFACE_FROM_MODE(p_FmMacControllerDriver->enetMode) == e_ENET_IF_XGMII) ? ++ e_FM_MAC_10G : e_FM_MAC_1G), ++ p_FmMacControllerDriver->macId) != E_OK)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't reset MAC!")); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_Init) ++ return p_FmMacControllerDriver->f_FM_MAC_Init(h_FmMac); ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_Free (t_Handle h_FmMac) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_Free) ++ return p_FmMacControllerDriver->f_FM_MAC_Free(h_FmMac); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_ConfigResetOnInit (t_Handle h_FmMac, bool enable) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit) ++ return p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit(h_FmMac, enable); ++ ++ p_FmMacControllerDriver->resetOnInit = enable; ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_ConfigLoopback (t_Handle h_FmMac, bool newVal) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback) ++ return p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback(h_FmMac, newVal); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_ConfigMaxFrameLength (t_Handle h_FmMac, uint16_t newVal) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength) ++ return p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength(h_FmMac, newVal); ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_ConfigWan (t_Handle h_FmMac, bool flag) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_ConfigWan) ++ return p_FmMacControllerDriver->f_FM_MAC_ConfigWan(h_FmMac, flag); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_ConfigPadAndCrc (t_Handle h_FmMac, bool newVal) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc) ++ return p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc(h_FmMac, newVal); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_ConfigHalfDuplex (t_Handle h_FmMac, bool newVal) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex) ++ return p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex(h_FmMac,newVal); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_ConfigTbiPhyAddr (t_Handle h_FmMac, uint8_t newVal) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_ConfigTbiPhyAddr) ++ return p_FmMacControllerDriver->f_FM_MAC_ConfigTbiPhyAddr(h_FmMac,newVal); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_ConfigLengthCheck (t_Handle h_FmMac, bool newVal) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck) ++ return p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck(h_FmMac,newVal); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_ConfigException (t_Handle h_FmMac, e_FmMacExceptions ex, bool enable) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_ConfigException) ++ return p_FmMacControllerDriver->f_FM_MAC_ConfigException(h_FmMac, ex, enable); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 ++/* ......................................................................... */ ++ ++t_Error FM_MAC_ConfigSkipFman11Workaround (t_Handle h_FmMac) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround) ++ return p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround(h_FmMac); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ ++ ++ ++/*****************************************************************************/ ++/* Run Time Control */ ++/*****************************************************************************/ ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_Enable (t_Handle h_FmMac, e_CommMode mode) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_Enable) ++ return p_FmMacControllerDriver->f_FM_MAC_Enable(h_FmMac, mode); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_Disable (t_Handle h_FmMac, e_CommMode mode) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_Disable) ++ return p_FmMacControllerDriver->f_FM_MAC_Disable(h_FmMac, mode); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MAC_Resume (t_Handle h_FmMac) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_Resume) ++ return p_FmMacControllerDriver->f_FM_MAC_Resume(h_FmMac); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_Enable1588TimeStamp (t_Handle h_FmMac) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp) ++ return p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp(h_FmMac); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_Disable1588TimeStamp (t_Handle h_FmMac) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp) ++ return p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp(h_FmMac); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_SetTxAutoPauseFrames(t_Handle h_FmMac, ++ uint16_t pauseTime) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames) ++ return p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames(h_FmMac, ++ pauseTime); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_SetTxPauseFrames(t_Handle h_FmMac, ++ uint8_t priority, ++ uint16_t pauseTime, ++ uint16_t threshTime) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames) ++ return p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames(h_FmMac, ++ priority, ++ pauseTime, ++ threshTime); ++ ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_SetRxIgnorePauseFrames (t_Handle h_FmMac, bool en) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames) ++ return p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames(h_FmMac, en); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_SetWakeOnLan (t_Handle h_FmMac, bool en) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan) ++ return p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan(h_FmMac, en); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_ResetCounters (t_Handle h_FmMac) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_ResetCounters) ++ return p_FmMacControllerDriver->f_FM_MAC_ResetCounters(h_FmMac); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_SetException(t_Handle h_FmMac, e_FmMacExceptions ex, bool enable) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_SetException) ++ return p_FmMacControllerDriver->f_FM_MAC_SetException(h_FmMac, ex, enable); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_SetStatistics (t_Handle h_FmMac, e_FmMacStatisticsLevel statisticsLevel) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_SetStatistics) ++ return p_FmMacControllerDriver->f_FM_MAC_SetStatistics(h_FmMac, statisticsLevel); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_GetStatistics (t_Handle h_FmMac, t_FmMacStatistics *p_Statistics) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_GetStatistics) ++ return p_FmMacControllerDriver->f_FM_MAC_GetStatistics(h_FmMac, p_Statistics); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_ModifyMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr) ++ return p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr(h_FmMac, p_EnetAddr); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_AddHashMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr) ++ return p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr(h_FmMac, p_EnetAddr); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_RemoveHashMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr) ++ return p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr(h_FmMac, p_EnetAddr); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_AddExactMatchMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr) ++ return p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr(h_FmMac, p_EnetAddr); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_RemovelExactMatchMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr) ++ return p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr(h_FmMac, p_EnetAddr); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_GetVesrion (t_Handle h_FmMac, uint32_t *macVresion) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_GetVersion) ++ return p_FmMacControllerDriver->f_FM_MAC_GetVersion(h_FmMac, macVresion); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++ ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_GetId (t_Handle h_FmMac, uint32_t *macId) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_GetId) ++ return p_FmMacControllerDriver->f_FM_MAC_GetId(h_FmMac, macId); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_SetPromiscuous (t_Handle h_FmMac, bool newVal) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous) ++ return p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous(h_FmMac, newVal); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_AdjustLink(t_Handle h_FmMac, e_EnetSpeed speed, bool fullDuplex) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_AdjustLink) ++ return p_FmMacControllerDriver->f_FM_MAC_AdjustLink(h_FmMac, speed, fullDuplex); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_RestartAutoneg(t_Handle h_FmMac) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg) ++ return p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg(h_FmMac); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_MII_WritePhyReg (t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t data) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg) ++ return p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg(h_FmMac, phyAddr, reg, data); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++t_Error FM_MAC_MII_ReadPhyReg(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg) ++ return p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg(h_FmMac, phyAddr, reg, p_Data); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++uint16_t FM_MAC_GetMaxFrameLength(t_Handle h_FmMac) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmMacControllerDriver, E_INVALID_HANDLE, 0); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength) ++ return p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength(h_FmMac); ++ ++ REPORT_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++ return 0; ++} ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++/*****************************************************************************/ ++t_Error FM_MAC_DumpRegs(t_Handle h_FmMac) ++{ ++ t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacControllerDriver->f_FM_MAC_DumpRegs) ++ return p_FmMacControllerDriver->f_FM_MAC_DumpRegs(h_FmMac); ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++#endif /* (defined(DEBUG_ERRORS) && ... */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h +new file mode 100644 +index 00000000..77b9a89d +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h +@@ -0,0 +1,225 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_mac.h ++ ++ @Description FM MAC ... ++*//***************************************************************************/ ++#ifndef __FM_MAC_H ++#define __FM_MAC_H ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "list_ext.h" ++#include "fm_mac_ext.h" ++#include "fm_common.h" ++ ++ ++#define __ERR_MODULE__ MODULE_FM_MAC ++ ++/**************************************************************************//** ++ @Description defaults ++*//***************************************************************************/ ++ ++ ++#define DEFAULT_halfDuplex FALSE ++#define DEFAULT_padAndCrcEnable TRUE ++#define DEFAULT_resetOnInit FALSE ++ ++ ++typedef struct { ++ uint64_t addr; /* Ethernet Address */ ++ t_List node; ++} t_EthHashEntry; ++#define ETH_HASH_ENTRY_OBJ(ptr) LIST_OBJECT(ptr, t_EthHashEntry, node) ++ ++typedef struct { ++ uint16_t size; ++ t_List *p_Lsts; ++} t_EthHash; ++ ++typedef struct { ++ t_Error (*f_FM_MAC_Init) (t_Handle h_FmMac); ++ t_Error (*f_FM_MAC_Free) (t_Handle h_FmMac); ++ ++ t_Error (*f_FM_MAC_SetStatistics) (t_Handle h_FmMac, e_FmMacStatisticsLevel statisticsLevel); ++ t_Error (*f_FM_MAC_ConfigLoopback) (t_Handle h_FmMac, bool newVal); ++ t_Error (*f_FM_MAC_ConfigMaxFrameLength) (t_Handle h_FmMac, uint16_t newVal); ++ t_Error (*f_FM_MAC_ConfigWan) (t_Handle h_FmMac, bool flag); ++ t_Error (*f_FM_MAC_ConfigPadAndCrc) (t_Handle h_FmMac, bool newVal); ++ t_Error (*f_FM_MAC_ConfigHalfDuplex) (t_Handle h_FmMac, bool newVal); ++ t_Error (*f_FM_MAC_ConfigLengthCheck) (t_Handle h_FmMac, bool newVal); ++ t_Error (*f_FM_MAC_ConfigTbiPhyAddr) (t_Handle h_FmMac, uint8_t newVal); ++ t_Error (*f_FM_MAC_ConfigException) (t_Handle h_FmMac, e_FmMacExceptions, bool enable); ++ t_Error (*f_FM_MAC_ConfigResetOnInit) (t_Handle h_FmMac, bool enable); ++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 ++ t_Error (*f_FM_MAC_ConfigSkipFman11Workaround) (t_Handle h_FmMac); ++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ ++ ++ t_Error (*f_FM_MAC_SetException) (t_Handle h_FmMac, e_FmMacExceptions ex, bool enable); ++ ++ t_Error (*f_FM_MAC_Enable) (t_Handle h_FmMac, e_CommMode mode); ++ t_Error (*f_FM_MAC_Disable) (t_Handle h_FmMac, e_CommMode mode); ++ t_Error (*f_FM_MAC_Resume) (t_Handle h_FmMac); ++ t_Error (*f_FM_MAC_Enable1588TimeStamp) (t_Handle h_FmMac); ++ t_Error (*f_FM_MAC_Disable1588TimeStamp) (t_Handle h_FmMac); ++ t_Error (*f_FM_MAC_Reset) (t_Handle h_FmMac, bool wait); ++ ++ t_Error (*f_FM_MAC_SetTxAutoPauseFrames) (t_Handle h_FmMac, ++ uint16_t pauseTime); ++ t_Error (*f_FM_MAC_SetTxPauseFrames) (t_Handle h_FmMac, ++ uint8_t priority, ++ uint16_t pauseTime, ++ uint16_t threshTime); ++ t_Error (*f_FM_MAC_SetRxIgnorePauseFrames) (t_Handle h_FmMac, bool en); ++ ++ t_Error (*f_FM_MAC_ResetCounters) (t_Handle h_FmMac); ++ t_Error (*f_FM_MAC_GetStatistics) (t_Handle h_FmMac, t_FmMacStatistics *p_Statistics); ++ ++ t_Error (*f_FM_MAC_ModifyMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); ++ t_Error (*f_FM_MAC_AddHashMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); ++ t_Error (*f_FM_MAC_RemoveHashMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); ++ t_Error (*f_FM_MAC_AddExactMatchMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); ++ t_Error (*f_FM_MAC_RemovelExactMatchMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); ++ ++ t_Error (*f_FM_MAC_SetPromiscuous) (t_Handle h_FmMac, bool newVal); ++ t_Error (*f_FM_MAC_AdjustLink) (t_Handle h_FmMac, e_EnetSpeed speed, bool fullDuplex); ++ t_Error (*f_FM_MAC_RestartAutoneg) (t_Handle h_FmMac); ++ ++ t_Error (*f_FM_MAC_SetWakeOnLan) (t_Handle h_FmMac, bool en); ++ ++ t_Error (*f_FM_MAC_GetId) (t_Handle h_FmMac, uint32_t *macId); ++ ++ t_Error (*f_FM_MAC_GetVersion) (t_Handle h_FmMac, uint32_t *macVersion); ++ ++ uint16_t (*f_FM_MAC_GetMaxFrameLength) (t_Handle h_FmMac); ++ ++ t_Error (*f_FM_MAC_MII_WritePhyReg)(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t data); ++ t_Error (*f_FM_MAC_MII_ReadPhyReg)(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data); ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ t_Error (*f_FM_MAC_DumpRegs) (t_Handle h_FmMac); ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++ t_Handle h_Fm; ++ t_FmRevisionInfo fmRevInfo; ++ e_EnetMode enetMode; ++ uint8_t macId; ++ bool resetOnInit; ++ uint16_t clkFreq; ++} t_FmMacControllerDriver; ++ ++ ++#if (DPAA_VERSION == 10) ++t_Handle DTSEC_Config(t_FmMacParams *p_FmMacParam); ++t_Handle TGEC_Config(t_FmMacParams *p_FmMacParams); ++#else ++t_Handle MEMAC_Config(t_FmMacParams *p_FmMacParam); ++#endif /* (DPAA_VERSION == 10) */ ++uint16_t FM_MAC_GetMaxFrameLength(t_Handle FmMac); ++ ++ ++/* ........................................................................... */ ++ ++static __inline__ t_EthHashEntry *DequeueAddrFromHashEntry(t_List *p_AddrLst) ++{ ++ t_EthHashEntry *p_HashEntry = NULL; ++ if (!LIST_IsEmpty(p_AddrLst)) ++ { ++ p_HashEntry = ETH_HASH_ENTRY_OBJ(p_AddrLst->p_Next); ++ LIST_DelAndInit(&p_HashEntry->node); ++ } ++ return p_HashEntry; ++} ++ ++/* ........................................................................... */ ++ ++static __inline__ void FreeHashTable(t_EthHash *p_Hash) ++{ ++ t_EthHashEntry *p_HashEntry; ++ int i = 0; ++ ++ if (p_Hash) ++ { ++ if (p_Hash->p_Lsts) ++ { ++ for (i=0; isize; i++) ++ { ++ p_HashEntry = DequeueAddrFromHashEntry(&p_Hash->p_Lsts[i]); ++ while (p_HashEntry) ++ { ++ XX_Free(p_HashEntry); ++ p_HashEntry = DequeueAddrFromHashEntry(&p_Hash->p_Lsts[i]); ++ } ++ } ++ ++ XX_Free(p_Hash->p_Lsts); ++ } ++ ++ XX_Free(p_Hash); ++ } ++} ++ ++/* ........................................................................... */ ++ ++static __inline__ t_EthHash * AllocHashTable(uint16_t size) ++{ ++ uint32_t i; ++ t_EthHash *p_Hash; ++ ++ /* Allocate address hash table */ ++ p_Hash = (t_EthHash *)XX_Malloc(sizeof(t_EthHash)); ++ if (!p_Hash) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Address hash table")); ++ return NULL; ++ } ++ p_Hash->size = size; ++ ++ p_Hash->p_Lsts = (t_List *)XX_Malloc(p_Hash->size*sizeof(t_List)); ++ if (!p_Hash->p_Lsts) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Address hash table")); ++ XX_Free(p_Hash); ++ return NULL; ++ } ++ ++ for (i=0 ; isize; i++) ++ INIT_LIST(&p_Hash->p_Lsts[i]); ++ ++ return p_Hash; ++} ++ ++ ++#endif /* __FM_MAC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.c +new file mode 100644 +index 00000000..b6a4ca25 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.c +@@ -0,0 +1,119 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#include "fman_crc32.h" ++#include "common/general.h" ++ ++ ++/* precomputed CRC values for address hashing */ ++static const uint32_t crc_tbl[256] = { ++ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, ++ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, ++ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, ++ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, ++ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, ++ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, ++ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, ++ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, ++ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, ++ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, ++ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, ++ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, ++ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, ++ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, ++ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, ++ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, ++ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, ++ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, ++ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, ++ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, ++ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, ++ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, ++ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, ++ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, ++ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, ++ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, ++ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, ++ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, ++ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, ++ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, ++ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, ++ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, ++ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, ++ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, ++ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, ++ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, ++ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, ++ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, ++ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, ++ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, ++ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, ++ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, ++ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d ++}; ++ ++/* Get the mirrored value of a byte size number. (0x11010011 --> 0x11001011) */ ++static inline uint8_t get_mirror8(uint8_t n) ++{ ++ uint8_t mirror[16] = { ++ 0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e, ++ 0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f ++ }; ++ return (uint8_t)(((mirror[n & 0x0f] << 4) | (mirror[n >> 4]))); ++} ++ ++static inline uint32_t get_mirror32(uint32_t n) ++{ ++ return ((uint32_t)get_mirror8((uint8_t)(n))<<24) | ++ ((uint32_t)get_mirror8((uint8_t)(n>>8))<<16) | ++ ((uint32_t)get_mirror8((uint8_t)(n>>16))<<8) | ++ ((uint32_t)get_mirror8((uint8_t)(n>>24))); ++} ++ ++uint32_t get_mac_addr_crc(uint64_t _addr) ++{ ++ uint32_t i; ++ uint8_t data; ++ uint32_t crc; ++ ++ /* CRC calculation */ ++ crc = 0xffffffff; ++ for (i = 0; i < 6; i++) { ++ data = (uint8_t)(_addr >> ((5-i)*8)); ++ crc = crc ^ data; ++ crc = crc_tbl[crc&0xff] ^ (crc>>8); ++ } ++ ++ crc = get_mirror32(crc); ++ return crc; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.h +new file mode 100644 +index 00000000..6e32fdc6 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.h +@@ -0,0 +1,43 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#ifndef __FMAN_CRC32_H ++#define __FMAN_CRC32_H ++ ++#include "common/general.h" ++ ++ ++uint32_t get_mac_addr_crc(uint64_t _addr); ++ ++ ++#endif /* __FMAN_CRC32_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec.c +new file mode 100644 +index 00000000..5b092865 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec.c +@@ -0,0 +1,845 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#include "fsl_fman_dtsec.h" ++ ++ ++void fman_dtsec_stop_rx(struct dtsec_regs *regs) ++{ ++ /* Assert the graceful stop bit */ ++ iowrite32be(ioread32be(®s->rctrl) | RCTRL_GRS, ®s->rctrl); ++} ++ ++void fman_dtsec_stop_tx(struct dtsec_regs *regs) ++{ ++ /* Assert the graceful stop bit */ ++ iowrite32be(ioread32be(®s->tctrl) | DTSEC_TCTRL_GTS, ®s->tctrl); ++} ++ ++void fman_dtsec_start_tx(struct dtsec_regs *regs) ++{ ++ /* clear the graceful stop bit */ ++ iowrite32be(ioread32be(®s->tctrl) & ~DTSEC_TCTRL_GTS, ®s->tctrl); ++} ++ ++void fman_dtsec_start_rx(struct dtsec_regs *regs) ++{ ++ /* clear the graceful stop bit */ ++ iowrite32be(ioread32be(®s->rctrl) & ~RCTRL_GRS, ®s->rctrl); ++} ++ ++void fman_dtsec_defconfig(struct dtsec_cfg *cfg) ++{ ++ cfg->halfdup_on = DEFAULT_HALFDUP_ON; ++ cfg->halfdup_retransmit = DEFAULT_HALFDUP_RETRANSMIT; ++ cfg->halfdup_coll_window = DEFAULT_HALFDUP_COLL_WINDOW; ++ cfg->halfdup_excess_defer = DEFAULT_HALFDUP_EXCESS_DEFER; ++ cfg->halfdup_no_backoff = DEFAULT_HALFDUP_NO_BACKOFF; ++ cfg->halfdup_bp_no_backoff = DEFAULT_HALFDUP_BP_NO_BACKOFF; ++ cfg->halfdup_alt_backoff_val = DEFAULT_HALFDUP_ALT_BACKOFF_VAL; ++ cfg->halfdup_alt_backoff_en = DEFAULT_HALFDUP_ALT_BACKOFF_EN; ++ cfg->rx_drop_bcast = DEFAULT_RX_DROP_BCAST; ++ cfg->rx_short_frm = DEFAULT_RX_SHORT_FRM; ++ cfg->rx_len_check = DEFAULT_RX_LEN_CHECK; ++ cfg->tx_pad_crc = DEFAULT_TX_PAD_CRC; ++ cfg->tx_crc = DEFAULT_TX_CRC; ++ cfg->rx_ctrl_acc = DEFAULT_RX_CTRL_ACC; ++ cfg->tx_pause_time = DEFAULT_TX_PAUSE_TIME; ++ cfg->tbipa = DEFAULT_TBIPA; /* PHY address 0 is reserved (DPAA RM)*/ ++ cfg->rx_prepend = DEFAULT_RX_PREPEND; ++ cfg->ptp_tsu_en = DEFAULT_PTP_TSU_EN; ++ cfg->ptp_exception_en = DEFAULT_PTP_EXCEPTION_EN; ++ cfg->preamble_len = DEFAULT_PREAMBLE_LEN; ++ cfg->rx_preamble = DEFAULT_RX_PREAMBLE; ++ cfg->tx_preamble = DEFAULT_TX_PREAMBLE; ++ cfg->loopback = DEFAULT_LOOPBACK; ++ cfg->rx_time_stamp_en = DEFAULT_RX_TIME_STAMP_EN; ++ cfg->tx_time_stamp_en = DEFAULT_TX_TIME_STAMP_EN; ++ cfg->rx_flow = DEFAULT_RX_FLOW; ++ cfg->tx_flow = DEFAULT_TX_FLOW; ++ cfg->rx_group_hash_exd = DEFAULT_RX_GROUP_HASH_EXD; ++ cfg->tx_pause_time_extd = DEFAULT_TX_PAUSE_TIME_EXTD; ++ cfg->rx_promisc = DEFAULT_RX_PROMISC; ++ cfg->non_back_to_back_ipg1 = DEFAULT_NON_BACK_TO_BACK_IPG1; ++ cfg->non_back_to_back_ipg2 = DEFAULT_NON_BACK_TO_BACK_IPG2; ++ cfg->min_ifg_enforcement = DEFAULT_MIN_IFG_ENFORCEMENT; ++ cfg->back_to_back_ipg = DEFAULT_BACK_TO_BACK_IPG; ++ cfg->maximum_frame = DEFAULT_MAXIMUM_FRAME; ++ cfg->tbi_phy_addr = DEFAULT_TBI_PHY_ADDR; ++ cfg->wake_on_lan = DEFAULT_WAKE_ON_LAN; ++} ++ ++int fman_dtsec_init(struct dtsec_regs *regs, struct dtsec_cfg *cfg, ++ enum enet_interface iface_mode, ++ enum enet_speed iface_speed, ++ uint8_t *macaddr, ++ uint8_t fm_rev_maj, ++ uint8_t fm_rev_min, ++ uint32_t exception_mask) ++{ ++ bool is_rgmii = FALSE; ++ bool is_sgmii = FALSE; ++ bool is_qsgmii = FALSE; ++ int i; ++ uint32_t tmp; ++ ++UNUSED(fm_rev_maj);UNUSED(fm_rev_min); ++ ++ /* let's start with a soft reset */ ++ iowrite32be(MACCFG1_SOFT_RESET, ®s->maccfg1); ++ iowrite32be(0, ®s->maccfg1); ++ ++ /*************dtsec_id2******************/ ++ tmp = ioread32be(®s->tsec_id2); ++ ++ /* check RGMII support */ ++ if (iface_mode == E_ENET_IF_RGMII || ++ iface_mode == E_ENET_IF_RMII) ++ if (tmp & DTSEC_ID2_INT_REDUCED_OFF) ++ return -EINVAL; ++ ++ if (iface_mode == E_ENET_IF_SGMII || ++ iface_mode == E_ENET_IF_MII) ++ if (tmp & DTSEC_ID2_INT_REDUCED_OFF) ++ return -EINVAL; ++ ++ /***************ECNTRL************************/ ++ ++ is_rgmii = (bool)((iface_mode == E_ENET_IF_RGMII) ? TRUE : FALSE); ++ is_sgmii = (bool)((iface_mode == E_ENET_IF_SGMII) ? TRUE : FALSE); ++ is_qsgmii = (bool)((iface_mode == E_ENET_IF_QSGMII) ? TRUE : FALSE); ++ ++ tmp = 0; ++ if (is_rgmii || iface_mode == E_ENET_IF_GMII) ++ tmp |= DTSEC_ECNTRL_GMIIM; ++ if (is_sgmii) ++ tmp |= (DTSEC_ECNTRL_SGMIIM | DTSEC_ECNTRL_TBIM); ++ if (is_qsgmii) ++ tmp |= (DTSEC_ECNTRL_SGMIIM | DTSEC_ECNTRL_TBIM | ++ DTSEC_ECNTRL_QSGMIIM); ++ if (is_rgmii) ++ tmp |= DTSEC_ECNTRL_RPM; ++ if (iface_speed == E_ENET_SPEED_100) ++ tmp |= DTSEC_ECNTRL_R100M; ++ ++ iowrite32be(tmp, ®s->ecntrl); ++ /***************ECNTRL************************/ ++ ++ /***************TCTRL************************/ ++ tmp = 0; ++ if (cfg->halfdup_on) ++ tmp |= DTSEC_TCTRL_THDF; ++ if (cfg->tx_time_stamp_en) ++ tmp |= DTSEC_TCTRL_TTSE; ++ ++ iowrite32be(tmp, ®s->tctrl); ++ ++ /***************TCTRL************************/ ++ ++ /***************PTV************************/ ++ tmp = 0; ++ ++#ifdef FM_SHORT_PAUSE_TIME_ERRATA_DTSEC1 ++ if ((fm_rev_maj == 1) && (fm_rev_min == 0)) ++ cfg->tx_pause_time += 2; ++#endif /* FM_SHORT_PAUSE_TIME_ERRATA_DTSEC1 */ ++ ++ if (cfg->tx_pause_time) ++ tmp |= cfg->tx_pause_time; ++ if (cfg->tx_pause_time_extd) ++ tmp |= cfg->tx_pause_time_extd << PTV_PTE_OFST; ++ iowrite32be(tmp, ®s->ptv); ++ ++ /***************RCTRL************************/ ++ tmp = 0; ++ tmp |= ((uint32_t)(cfg->rx_prepend & 0x0000001f)) << 16; ++ if (cfg->rx_ctrl_acc) ++ tmp |= RCTRL_CFA; ++ if (cfg->rx_group_hash_exd) ++ tmp |= RCTRL_GHTX; ++ if (cfg->rx_time_stamp_en) ++ tmp |= RCTRL_RTSE; ++ if (cfg->rx_drop_bcast) ++ tmp |= RCTRL_BC_REJ; ++ if (cfg->rx_short_frm) ++ tmp |= RCTRL_RSF; ++ if (cfg->rx_promisc) ++ tmp |= RCTRL_PROM; ++ ++ iowrite32be(tmp, ®s->rctrl); ++ /***************RCTRL************************/ ++ ++ /* ++ * Assign a Phy Address to the TBI (TBIPA). ++ * Done also in cases where TBI is not selected to avoid conflict with ++ * the external PHY's Physical address ++ */ ++ iowrite32be(cfg->tbipa, ®s->tbipa); ++ ++ /***************TMR_CTL************************/ ++ iowrite32be(0, ®s->tmr_ctrl); ++ ++ if (cfg->ptp_tsu_en) { ++ tmp = 0; ++ tmp |= TMR_PEVENT_TSRE; ++ iowrite32be(tmp, ®s->tmr_pevent); ++ ++ if (cfg->ptp_exception_en) { ++ tmp = 0; ++ tmp |= TMR_PEMASK_TSREEN; ++ iowrite32be(tmp, ®s->tmr_pemask); ++ } ++ } ++ ++ /***************MACCFG1***********************/ ++ tmp = 0; ++ if (cfg->loopback) ++ tmp |= MACCFG1_LOOPBACK; ++ if (cfg->rx_flow) ++ tmp |= MACCFG1_RX_FLOW; ++ if (cfg->tx_flow) ++ tmp |= MACCFG1_TX_FLOW; ++ iowrite32be(tmp, ®s->maccfg1); ++ ++ /***************MACCFG1***********************/ ++ ++ /***************MACCFG2***********************/ ++ tmp = 0; ++ ++ if (iface_speed < E_ENET_SPEED_1000) ++ tmp |= MACCFG2_NIBBLE_MODE; ++ else if (iface_speed == E_ENET_SPEED_1000) ++ tmp |= MACCFG2_BYTE_MODE; ++ ++ tmp |= ((uint32_t) cfg->preamble_len & 0x0000000f) ++ << PREAMBLE_LENGTH_SHIFT; ++ ++ if (cfg->rx_preamble) ++ tmp |= MACCFG2_PRE_AM_Rx_EN; ++ if (cfg->tx_preamble) ++ tmp |= MACCFG2_PRE_AM_Tx_EN; ++ if (cfg->rx_len_check) ++ tmp |= MACCFG2_LENGTH_CHECK; ++ if (cfg->tx_pad_crc) ++ tmp |= MACCFG2_PAD_CRC_EN; ++ if (cfg->tx_crc) ++ tmp |= MACCFG2_CRC_EN; ++ if (!cfg->halfdup_on) ++ tmp |= MACCFG2_FULL_DUPLEX; ++ iowrite32be(tmp, ®s->maccfg2); ++ ++ /***************MACCFG2***********************/ ++ ++ /***************IPGIFG************************/ ++ tmp = (((cfg->non_back_to_back_ipg1 << ++ IPGIFG_NON_BACK_TO_BACK_IPG_1_SHIFT) ++ & IPGIFG_NON_BACK_TO_BACK_IPG_1) ++ | ((cfg->non_back_to_back_ipg2 << ++ IPGIFG_NON_BACK_TO_BACK_IPG_2_SHIFT) ++ & IPGIFG_NON_BACK_TO_BACK_IPG_2) ++ | ((cfg->min_ifg_enforcement << ++ IPGIFG_MIN_IFG_ENFORCEMENT_SHIFT) ++ & IPGIFG_MIN_IFG_ENFORCEMENT) ++ | (cfg->back_to_back_ipg & IPGIFG_BACK_TO_BACK_IPG)); ++ iowrite32be(tmp, ®s->ipgifg); ++ ++ /***************IPGIFG************************/ ++ ++ /***************HAFDUP************************/ ++ tmp = 0; ++ ++ if (cfg->halfdup_alt_backoff_en) ++ tmp = (uint32_t)(HAFDUP_ALT_BEB | ++ ((cfg->halfdup_alt_backoff_val & 0x0000000f) ++ << HAFDUP_ALTERNATE_BEB_TRUNCATION_SHIFT)); ++ if (cfg->halfdup_bp_no_backoff) ++ tmp |= HAFDUP_BP_NO_BACKOFF; ++ if (cfg->halfdup_no_backoff) ++ tmp |= HAFDUP_NO_BACKOFF; ++ if (cfg->halfdup_excess_defer) ++ tmp |= HAFDUP_EXCESS_DEFER; ++ tmp |= ((cfg->halfdup_retransmit << HAFDUP_RETRANSMISSION_MAX_SHIFT) ++ & HAFDUP_RETRANSMISSION_MAX); ++ tmp |= (cfg->halfdup_coll_window & HAFDUP_COLLISION_WINDOW); ++ ++ iowrite32be(tmp, ®s->hafdup); ++ /***************HAFDUP************************/ ++ ++ /***************MAXFRM************************/ ++ /* Initialize MAXFRM */ ++ iowrite32be(cfg->maximum_frame, ®s->maxfrm); ++ ++ /***************MAXFRM************************/ ++ ++ /***************CAM1************************/ ++ iowrite32be(0xffffffff, ®s->cam1); ++ iowrite32be(0xffffffff, ®s->cam2); ++ ++ /***************IMASK************************/ ++ iowrite32be(exception_mask, ®s->imask); ++ /***************IMASK************************/ ++ ++ /***************IEVENT************************/ ++ iowrite32be(0xffffffff, ®s->ievent); ++ ++ /***************MACSTNADDR1/2*****************/ ++ ++ tmp = (uint32_t)((macaddr[5] << 24) | ++ (macaddr[4] << 16) | ++ (macaddr[3] << 8) | ++ macaddr[2]); ++ iowrite32be(tmp, ®s->macstnaddr1); ++ ++ tmp = (uint32_t)((macaddr[1] << 24) | ++ (macaddr[0] << 16)); ++ iowrite32be(tmp, ®s->macstnaddr2); ++ ++ /***************MACSTNADDR1/2*****************/ ++ ++ /*****************HASH************************/ ++ for (i = 0; i < NUM_OF_HASH_REGS ; i++) { ++ /* Initialize IADDRx */ ++ iowrite32be(0, ®s->igaddr[i]); ++ /* Initialize GADDRx */ ++ iowrite32be(0, ®s->gaddr[i]); ++ } ++ ++ fman_dtsec_reset_stat(regs); ++ ++ return 0; ++} ++ ++uint16_t fman_dtsec_get_max_frame_len(struct dtsec_regs *regs) ++{ ++ return (uint16_t)ioread32be(®s->maxfrm); ++} ++ ++void fman_dtsec_set_max_frame_len(struct dtsec_regs *regs, uint16_t length) ++{ ++ iowrite32be(length, ®s->maxfrm); ++} ++ ++void fman_dtsec_set_mac_address(struct dtsec_regs *regs, uint8_t *adr) ++{ ++ uint32_t tmp; ++ ++ tmp = (uint32_t)((adr[5] << 24) | ++ (adr[4] << 16) | ++ (adr[3] << 8) | ++ adr[2]); ++ iowrite32be(tmp, ®s->macstnaddr1); ++ ++ tmp = (uint32_t)((adr[1] << 24) | ++ (adr[0] << 16)); ++ iowrite32be(tmp, ®s->macstnaddr2); ++} ++ ++void fman_dtsec_get_mac_address(struct dtsec_regs *regs, uint8_t *macaddr) ++{ ++ uint32_t tmp1, tmp2; ++ ++ tmp1 = ioread32be(®s->macstnaddr1); ++ tmp2 = ioread32be(®s->macstnaddr2); ++ ++ macaddr[0] = (uint8_t)((tmp2 & 0x00ff0000) >> 16); ++ macaddr[1] = (uint8_t)((tmp2 & 0xff000000) >> 24); ++ macaddr[2] = (uint8_t)(tmp1 & 0x000000ff); ++ macaddr[3] = (uint8_t)((tmp1 & 0x0000ff00) >> 8); ++ macaddr[4] = (uint8_t)((tmp1 & 0x00ff0000) >> 16); ++ macaddr[5] = (uint8_t)((tmp1 & 0xff000000) >> 24); ++} ++ ++void fman_dtsec_set_hash_table(struct dtsec_regs *regs, uint32_t crc, bool mcast, bool ghtx) ++{ ++ int32_t bucket; ++ if (ghtx) ++ bucket = (int32_t)((crc >> 23) & 0x1ff); ++ else { ++ bucket = (int32_t)((crc >> 24) & 0xff); ++ /* if !ghtx and mcast the bit must be set in gaddr instead of igaddr. */ ++ if (mcast) ++ bucket += 0x100; ++ } ++ fman_dtsec_set_bucket(regs, bucket, TRUE); ++} ++ ++void fman_dtsec_set_bucket(struct dtsec_regs *regs, int bucket, bool enable) ++{ ++ int reg_idx = (bucket >> 5) & 0xf; ++ int bit_idx = bucket & 0x1f; ++ uint32_t bit_mask = 0x80000000 >> bit_idx; ++ uint32_t *reg; ++ ++ if (reg_idx > 7) ++ reg = ®s->gaddr[reg_idx-8]; ++ else ++ reg = ®s->igaddr[reg_idx]; ++ ++ if (enable) ++ iowrite32be(ioread32be(reg) | bit_mask, reg); ++ else ++ iowrite32be(ioread32be(reg) & (~bit_mask), reg); ++} ++ ++void fman_dtsec_reset_filter_table(struct dtsec_regs *regs, bool mcast, bool ucast) ++{ ++ int i; ++ bool ghtx; ++ ++ ghtx = (bool)((ioread32be(®s->rctrl) & RCTRL_GHTX) ? TRUE : FALSE); ++ ++ if (ucast || (ghtx && mcast)) { ++ for (i = 0; i < NUM_OF_HASH_REGS; i++) ++ iowrite32be(0, ®s->igaddr[i]); ++ } ++ if (mcast) { ++ for (i = 0; i < NUM_OF_HASH_REGS; i++) ++ iowrite32be(0, ®s->gaddr[i]); ++ } ++} ++ ++int fman_dtsec_set_tbi_phy_addr(struct dtsec_regs *regs, ++ uint8_t addr) ++{ ++ if (addr > 0 && addr < 32) ++ iowrite32be(addr, ®s->tbipa); ++ else ++ return -EINVAL; ++ ++ return 0; ++} ++ ++void fman_dtsec_set_wol(struct dtsec_regs *regs, bool en) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->maccfg2); ++ if (en) ++ tmp |= MACCFG2_MAGIC_PACKET_EN; ++ else ++ tmp &= ~MACCFG2_MAGIC_PACKET_EN; ++ iowrite32be(tmp, ®s->maccfg2); ++} ++ ++int fman_dtsec_adjust_link(struct dtsec_regs *regs, ++ enum enet_interface iface_mode, ++ enum enet_speed speed, bool full_dx) ++{ ++ uint32_t tmp; ++ ++ UNUSED(iface_mode); ++ ++ if ((speed == E_ENET_SPEED_1000) && !full_dx) ++ return -EINVAL; ++ ++ tmp = ioread32be(®s->maccfg2); ++ if (!full_dx) ++ tmp &= ~MACCFG2_FULL_DUPLEX; ++ else ++ tmp |= MACCFG2_FULL_DUPLEX; ++ ++ tmp &= ~(MACCFG2_NIBBLE_MODE | MACCFG2_BYTE_MODE); ++ if (speed < E_ENET_SPEED_1000) ++ tmp |= MACCFG2_NIBBLE_MODE; ++ else if (speed == E_ENET_SPEED_1000) ++ tmp |= MACCFG2_BYTE_MODE; ++ iowrite32be(tmp, ®s->maccfg2); ++ ++ tmp = ioread32be(®s->ecntrl); ++ if (speed == E_ENET_SPEED_100) ++ tmp |= DTSEC_ECNTRL_R100M; ++ else ++ tmp &= ~DTSEC_ECNTRL_R100M; ++ iowrite32be(tmp, ®s->ecntrl); ++ ++ return 0; ++} ++ ++void fman_dtsec_set_uc_promisc(struct dtsec_regs *regs, bool enable) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->rctrl); ++ ++ if (enable) ++ tmp |= RCTRL_UPROM; ++ else ++ tmp &= ~RCTRL_UPROM; ++ ++ iowrite32be(tmp, ®s->rctrl); ++} ++ ++void fman_dtsec_set_mc_promisc(struct dtsec_regs *regs, bool enable) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->rctrl); ++ ++ if (enable) ++ tmp |= RCTRL_MPROM; ++ else ++ tmp &= ~RCTRL_MPROM; ++ ++ iowrite32be(tmp, ®s->rctrl); ++} ++ ++bool fman_dtsec_get_clear_carry_regs(struct dtsec_regs *regs, ++ uint32_t *car1, uint32_t *car2) ++{ ++ /* read carry registers */ ++ *car1 = ioread32be(®s->car1); ++ *car2 = ioread32be(®s->car2); ++ /* clear carry registers */ ++ if (*car1) ++ iowrite32be(*car1, ®s->car1); ++ if (*car2) ++ iowrite32be(*car2, ®s->car2); ++ ++ return (bool)((*car1 | *car2) ? TRUE : FALSE); ++} ++ ++void fman_dtsec_reset_stat(struct dtsec_regs *regs) ++{ ++ /* clear HW counters */ ++ iowrite32be(ioread32be(®s->ecntrl) | ++ DTSEC_ECNTRL_CLRCNT, ®s->ecntrl); ++} ++ ++int fman_dtsec_set_stat_level(struct dtsec_regs *regs, enum dtsec_stat_level level) ++{ ++ switch (level) { ++ case E_MAC_STAT_NONE: ++ iowrite32be(0xffffffff, ®s->cam1); ++ iowrite32be(0xffffffff, ®s->cam2); ++ iowrite32be(ioread32be(®s->ecntrl) & ~DTSEC_ECNTRL_STEN, ++ ®s->ecntrl); ++ iowrite32be(ioread32be(®s->imask) & ~DTSEC_IMASK_MSROEN, ++ ®s->imask); ++ break; ++ case E_MAC_STAT_PARTIAL: ++ iowrite32be(CAM1_ERRORS_ONLY, ®s->cam1); ++ iowrite32be(CAM2_ERRORS_ONLY, ®s->cam2); ++ iowrite32be(ioread32be(®s->ecntrl) | DTSEC_ECNTRL_STEN, ++ ®s->ecntrl); ++ iowrite32be(ioread32be(®s->imask) | DTSEC_IMASK_MSROEN, ++ ®s->imask); ++ break; ++ case E_MAC_STAT_MIB_GRP1: ++ iowrite32be((uint32_t)~CAM1_MIB_GRP_1, ®s->cam1); ++ iowrite32be((uint32_t)~CAM2_MIB_GRP_1, ®s->cam2); ++ iowrite32be(ioread32be(®s->ecntrl) | DTSEC_ECNTRL_STEN, ++ ®s->ecntrl); ++ iowrite32be(ioread32be(®s->imask) | DTSEC_IMASK_MSROEN, ++ ®s->imask); ++ break; ++ case E_MAC_STAT_FULL: ++ iowrite32be(0, ®s->cam1); ++ iowrite32be(0, ®s->cam2); ++ iowrite32be(ioread32be(®s->ecntrl) | DTSEC_ECNTRL_STEN, ++ ®s->ecntrl); ++ iowrite32be(ioread32be(®s->imask) | DTSEC_IMASK_MSROEN, ++ ®s->imask); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++void fman_dtsec_set_ts(struct dtsec_regs *regs, bool en) ++{ ++ if (en) { ++ iowrite32be(ioread32be(®s->rctrl) | RCTRL_RTSE, ++ ®s->rctrl); ++ iowrite32be(ioread32be(®s->tctrl) | DTSEC_TCTRL_TTSE, ++ ®s->tctrl); ++ } else { ++ iowrite32be(ioread32be(®s->rctrl) & ~RCTRL_RTSE, ++ ®s->rctrl); ++ iowrite32be(ioread32be(®s->tctrl) & ~DTSEC_TCTRL_TTSE, ++ ®s->tctrl); ++ } ++} ++ ++void fman_dtsec_enable(struct dtsec_regs *regs, bool apply_rx, bool apply_tx) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->maccfg1); ++ ++ if (apply_rx) ++ tmp |= MACCFG1_RX_EN ; ++ ++ if (apply_tx) ++ tmp |= MACCFG1_TX_EN ; ++ ++ iowrite32be(tmp, ®s->maccfg1); ++} ++ ++void fman_dtsec_clear_addr_in_paddr(struct dtsec_regs *regs, uint8_t paddr_num) ++{ ++ iowrite32be(0, ®s->macaddr[paddr_num].exact_match1); ++ iowrite32be(0, ®s->macaddr[paddr_num].exact_match2); ++} ++ ++void fman_dtsec_add_addr_in_paddr(struct dtsec_regs *regs, ++ uint64_t addr, ++ uint8_t paddr_num) ++{ ++ uint32_t tmp; ++ ++ tmp = (uint32_t)(addr); ++ /* swap */ ++ tmp = (((tmp & 0x000000FF) << 24) | ++ ((tmp & 0x0000FF00) << 8) | ++ ((tmp & 0x00FF0000) >> 8) | ++ ((tmp & 0xFF000000) >> 24)); ++ iowrite32be(tmp, ®s->macaddr[paddr_num].exact_match1); ++ ++ tmp = (uint32_t)(addr>>32); ++ /* swap */ ++ tmp = (((tmp & 0x000000FF) << 24) | ++ ((tmp & 0x0000FF00) << 8) | ++ ((tmp & 0x00FF0000) >> 8) | ++ ((tmp & 0xFF000000) >> 24)); ++ iowrite32be(tmp, ®s->macaddr[paddr_num].exact_match2); ++} ++ ++void fman_dtsec_disable(struct dtsec_regs *regs, bool apply_rx, bool apply_tx) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->maccfg1); ++ ++ if (apply_rx) ++ tmp &= ~MACCFG1_RX_EN; ++ ++ if (apply_tx) ++ tmp &= ~MACCFG1_TX_EN; ++ ++ iowrite32be(tmp, ®s->maccfg1); ++} ++ ++void fman_dtsec_set_tx_pause_frames(struct dtsec_regs *regs, uint16_t time) ++{ ++ uint32_t ptv = 0; ++ ++ /* fixme: don't enable tx pause for half-duplex */ ++ ++ if (time) { ++ ptv = ioread32be(®s->ptv); ++ ptv &= 0xffff0000; ++ ptv |= time & 0x0000ffff; ++ iowrite32be(ptv, ®s->ptv); ++ ++ /* trigger the transmission of a flow-control pause frame */ ++ iowrite32be(ioread32be(®s->maccfg1) | MACCFG1_TX_FLOW, ++ ®s->maccfg1); ++ } else ++ iowrite32be(ioread32be(®s->maccfg1) & ~MACCFG1_TX_FLOW, ++ ®s->maccfg1); ++} ++ ++void fman_dtsec_handle_rx_pause(struct dtsec_regs *regs, bool en) ++{ ++ uint32_t tmp; ++ ++ /* todo: check if mac is set to full-duplex */ ++ ++ tmp = ioread32be(®s->maccfg1); ++ if (en) ++ tmp |= MACCFG1_RX_FLOW; ++ else ++ tmp &= ~MACCFG1_RX_FLOW; ++ iowrite32be(tmp, ®s->maccfg1); ++} ++ ++uint32_t fman_dtsec_get_rctrl(struct dtsec_regs *regs) ++{ ++ return ioread32be(®s->rctrl); ++} ++ ++uint32_t fman_dtsec_get_revision(struct dtsec_regs *regs) ++{ ++ return ioread32be(®s->tsec_id); ++} ++ ++uint32_t fman_dtsec_get_event(struct dtsec_regs *regs, uint32_t ev_mask) ++{ ++ return ioread32be(®s->ievent) & ev_mask; ++} ++ ++void fman_dtsec_ack_event(struct dtsec_regs *regs, uint32_t ev_mask) ++{ ++ iowrite32be(ev_mask, ®s->ievent); ++} ++ ++uint32_t fman_dtsec_get_interrupt_mask(struct dtsec_regs *regs) ++{ ++ return ioread32be(®s->imask); ++} ++ ++uint32_t fman_dtsec_check_and_clear_tmr_event(struct dtsec_regs *regs) ++{ ++ uint32_t event; ++ ++ event = ioread32be(®s->tmr_pevent); ++ event &= ioread32be(®s->tmr_pemask); ++ ++ if (event) ++ iowrite32be(event, ®s->tmr_pevent); ++ return event; ++} ++ ++void fman_dtsec_enable_tmr_interrupt(struct dtsec_regs *regs) ++{ ++ iowrite32be(ioread32be(®s->tmr_pemask) | TMR_PEMASK_TSREEN, ++ ®s->tmr_pemask); ++} ++ ++void fman_dtsec_disable_tmr_interrupt(struct dtsec_regs *regs) ++{ ++ iowrite32be(ioread32be(®s->tmr_pemask) & ~TMR_PEMASK_TSREEN, ++ ®s->tmr_pemask); ++} ++ ++void fman_dtsec_enable_interrupt(struct dtsec_regs *regs, uint32_t ev_mask) ++{ ++ iowrite32be(ioread32be(®s->imask) | ev_mask, ®s->imask); ++} ++ ++void fman_dtsec_disable_interrupt(struct dtsec_regs *regs, uint32_t ev_mask) ++{ ++ iowrite32be(ioread32be(®s->imask) & ~ev_mask, ®s->imask); ++} ++ ++uint32_t fman_dtsec_get_stat_counter(struct dtsec_regs *regs, ++ enum dtsec_stat_counters reg_name) ++{ ++ uint32_t ret_val; ++ ++ switch (reg_name) { ++ case E_DTSEC_STAT_TR64: ++ ret_val = ioread32be(®s->tr64); ++ break; ++ case E_DTSEC_STAT_TR127: ++ ret_val = ioread32be(®s->tr127); ++ break; ++ case E_DTSEC_STAT_TR255: ++ ret_val = ioread32be(®s->tr255); ++ break; ++ case E_DTSEC_STAT_TR511: ++ ret_val = ioread32be(®s->tr511); ++ break; ++ case E_DTSEC_STAT_TR1K: ++ ret_val = ioread32be(®s->tr1k); ++ break; ++ case E_DTSEC_STAT_TRMAX: ++ ret_val = ioread32be(®s->trmax); ++ break; ++ case E_DTSEC_STAT_TRMGV: ++ ret_val = ioread32be(®s->trmgv); ++ break; ++ case E_DTSEC_STAT_RBYT: ++ ret_val = ioread32be(®s->rbyt); ++ break; ++ case E_DTSEC_STAT_RPKT: ++ ret_val = ioread32be(®s->rpkt); ++ break; ++ case E_DTSEC_STAT_RMCA: ++ ret_val = ioread32be(®s->rmca); ++ break; ++ case E_DTSEC_STAT_RBCA: ++ ret_val = ioread32be(®s->rbca); ++ break; ++ case E_DTSEC_STAT_RXPF: ++ ret_val = ioread32be(®s->rxpf); ++ break; ++ case E_DTSEC_STAT_RALN: ++ ret_val = ioread32be(®s->raln); ++ break; ++ case E_DTSEC_STAT_RFLR: ++ ret_val = ioread32be(®s->rflr); ++ break; ++ case E_DTSEC_STAT_RCDE: ++ ret_val = ioread32be(®s->rcde); ++ break; ++ case E_DTSEC_STAT_RCSE: ++ ret_val = ioread32be(®s->rcse); ++ break; ++ case E_DTSEC_STAT_RUND: ++ ret_val = ioread32be(®s->rund); ++ break; ++ case E_DTSEC_STAT_ROVR: ++ ret_val = ioread32be(®s->rovr); ++ break; ++ case E_DTSEC_STAT_RFRG: ++ ret_val = ioread32be(®s->rfrg); ++ break; ++ case E_DTSEC_STAT_RJBR: ++ ret_val = ioread32be(®s->rjbr); ++ break; ++ case E_DTSEC_STAT_RDRP: ++ ret_val = ioread32be(®s->rdrp); ++ break; ++ case E_DTSEC_STAT_TFCS: ++ ret_val = ioread32be(®s->tfcs); ++ break; ++ case E_DTSEC_STAT_TBYT: ++ ret_val = ioread32be(®s->tbyt); ++ break; ++ case E_DTSEC_STAT_TPKT: ++ ret_val = ioread32be(®s->tpkt); ++ break; ++ case E_DTSEC_STAT_TMCA: ++ ret_val = ioread32be(®s->tmca); ++ break; ++ case E_DTSEC_STAT_TBCA: ++ ret_val = ioread32be(®s->tbca); ++ break; ++ case E_DTSEC_STAT_TXPF: ++ ret_val = ioread32be(®s->txpf); ++ break; ++ case E_DTSEC_STAT_TNCL: ++ ret_val = ioread32be(®s->tncl); ++ break; ++ case E_DTSEC_STAT_TDRP: ++ ret_val = ioread32be(®s->tdrp); ++ break; ++ default: ++ ret_val = 0; ++ } ++ ++ return ret_val; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c +new file mode 100644 +index 00000000..8819f8fc +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c +@@ -0,0 +1,163 @@ ++/* ++ * Copyright 2008-2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#include "common/general.h" ++#include "fsl_fman_dtsec_mii_acc.h" ++ ++ ++/** ++ * dtsec_mii_get_div() - calculates the value of the dtsec mii divider ++ * @dtsec_freq: dtsec clock frequency (in Mhz) ++ * ++ * This function calculates the dtsec mii clock divider that determines ++ * the MII MDC clock. MII MDC clock will be set to work in the range ++ * of 1.5 to 2.5Mhz ++ * The output of this function is the value of MIIMCFG[MgmtClk] which ++ * implicitly determines the divider value. ++ * Note: the dTSEC system clock is equal to 1/2 of the FMan clock. ++ * ++ * The table below which reflects dtsec_mii_get_div() functionality ++ * shows the relations among dtsec_freq, MgmtClk, actual divider ++ * and the MII frequency: ++ * ++ * dtsec freq MgmtClk div MII freq Mhz ++ * [0.....80] 1 (1/4)(1/8) [0 to 2.5] ++ * [81...120] 2 (1/6)(1/8) [1.6 to 2.5] ++ * [121..160] 3 (1/8)(1/8) [1.8 to 2.5] ++ * [161..200] 4 (1/10)(1/8) [2.0 to 2.5] ++ * [201..280] 5 (1/14)(1/8) [1.8 to 2.5] ++ * [281..400] 6 (1/20)(1/8) [1.1 to 2.5] ++ * [401..560] 7 (1/28)(1/8) [1.8 to 2.5] ++ * [560..frq] 7 (1/28)(1/8) [frq/224] ++ * ++ * Returns: the MIIMCFG[MgmtClk] appropriate value ++ */ ++ ++static uint8_t dtsec_mii_get_div(uint16_t dtsec_freq) ++{ ++ uint16_t mgmt_clk; ++ ++ if (dtsec_freq < 80) mgmt_clk = 1; ++ else if (dtsec_freq < 120) mgmt_clk = 2; ++ else if (dtsec_freq < 160) mgmt_clk = 3; ++ else if (dtsec_freq < 200) mgmt_clk = 4; ++ else if (dtsec_freq < 280) mgmt_clk = 5; ++ else if (dtsec_freq < 400) mgmt_clk = 6; ++ else mgmt_clk = 7; ++ ++ return (uint8_t)mgmt_clk; ++} ++ ++void fman_dtsec_mii_reset(struct dtsec_mii_reg *regs) ++{ ++ /* Reset the management interface */ ++ iowrite32be(ioread32be(®s->miimcfg) | MIIMCFG_RESET_MGMT, ++ ®s->miimcfg); ++ iowrite32be(ioread32be(®s->miimcfg) & ~MIIMCFG_RESET_MGMT, ++ ®s->miimcfg); ++} ++ ++ ++int fman_dtsec_mii_write_reg(struct dtsec_mii_reg *regs, uint8_t addr, ++ uint8_t reg, uint16_t data, uint16_t dtsec_freq) ++{ ++ uint32_t tmp; ++ ++ /* Setup the MII Mgmt clock speed */ ++ iowrite32be((uint32_t)dtsec_mii_get_div(dtsec_freq), ®s->miimcfg); ++ wmb(); ++ ++ /* Stop the MII management read cycle */ ++ iowrite32be(0, ®s->miimcom); ++ /* Dummy read to make sure MIIMCOM is written */ ++ tmp = ioread32be(®s->miimcom); ++ wmb(); ++ ++ /* Setting up MII Management Address Register */ ++ tmp = (uint32_t)((addr << MIIMADD_PHY_ADDR_SHIFT) | reg); ++ iowrite32be(tmp, ®s->miimadd); ++ wmb(); ++ ++ /* Setting up MII Management Control Register with data */ ++ iowrite32be((uint32_t)data, ®s->miimcon); ++ /* Dummy read to make sure MIIMCON is written */ ++ tmp = ioread32be(®s->miimcon); ++ wmb(); ++ ++ /* Wait until MII management write is complete */ ++ /* todo: a timeout could be useful here */ ++ while ((ioread32be(®s->miimind)) & MIIMIND_BUSY) ++ /* busy wait */; ++ ++ return 0; ++} ++ ++int fman_dtsec_mii_read_reg(struct dtsec_mii_reg *regs, uint8_t addr, ++ uint8_t reg, uint16_t *data, uint16_t dtsec_freq) ++{ ++ uint32_t tmp; ++ ++ /* Setup the MII Mgmt clock speed */ ++ iowrite32be((uint32_t)dtsec_mii_get_div(dtsec_freq), ®s->miimcfg); ++ wmb(); ++ ++ /* Setting up the MII Management Address Register */ ++ tmp = (uint32_t)((addr << MIIMADD_PHY_ADDR_SHIFT) | reg); ++ iowrite32be(tmp, ®s->miimadd); ++ wmb(); ++ ++ /* Perform an MII management read cycle */ ++ iowrite32be(MIIMCOM_READ_CYCLE, ®s->miimcom); ++ /* Dummy read to make sure MIIMCOM is written */ ++ tmp = ioread32be(®s->miimcom); ++ wmb(); ++ ++ /* Wait until MII management read is complete */ ++ /* todo: a timeout could be useful here */ ++ while ((ioread32be(®s->miimind)) & MIIMIND_BUSY) ++ /* busy wait */; ++ ++ /* Read MII management status */ ++ *data = (uint16_t)ioread32be(®s->miimstat); ++ wmb(); ++ ++ iowrite32be(0, ®s->miimcom); ++ /* Dummy read to make sure MIIMCOM is written */ ++ tmp = ioread32be(®s->miimcom); ++ ++ if (*data == 0xffff) ++ return -ENXIO; ++ ++ return 0; ++} ++ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac.c +new file mode 100644 +index 00000000..00995a10 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac.c +@@ -0,0 +1,511 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#include "fsl_fman_memac.h" ++ ++ ++uint32_t fman_memac_get_event(struct memac_regs *regs, uint32_t ev_mask) ++{ ++ return ioread32be(®s->ievent) & ev_mask; ++} ++ ++uint32_t fman_memac_get_interrupt_mask(struct memac_regs *regs) ++{ ++ return ioread32be(®s->imask); ++} ++ ++void fman_memac_ack_event(struct memac_regs *regs, uint32_t ev_mask) ++{ ++ iowrite32be(ev_mask, ®s->ievent); ++} ++ ++void fman_memac_set_promiscuous(struct memac_regs *regs, bool val) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->command_config); ++ ++ if (val) ++ tmp |= CMD_CFG_PROMIS_EN; ++ else ++ tmp &= ~CMD_CFG_PROMIS_EN; ++ ++ iowrite32be(tmp, ®s->command_config); ++} ++ ++void fman_memac_clear_addr_in_paddr(struct memac_regs *regs, ++ uint8_t paddr_num) ++{ ++ if (paddr_num == 0) { ++ iowrite32be(0, ®s->mac_addr0.mac_addr_l); ++ iowrite32be(0, ®s->mac_addr0.mac_addr_u); ++ } else { ++ iowrite32be(0x0, ®s->mac_addr[paddr_num - 1].mac_addr_l); ++ iowrite32be(0x0, ®s->mac_addr[paddr_num - 1].mac_addr_u); ++ } ++} ++ ++void fman_memac_add_addr_in_paddr(struct memac_regs *regs, ++ uint8_t *adr, ++ uint8_t paddr_num) ++{ ++ uint32_t tmp0, tmp1; ++ ++ tmp0 = (uint32_t)(adr[0] | ++ adr[1] << 8 | ++ adr[2] << 16 | ++ adr[3] << 24); ++ tmp1 = (uint32_t)(adr[4] | adr[5] << 8); ++ ++ if (paddr_num == 0) { ++ iowrite32be(tmp0, ®s->mac_addr0.mac_addr_l); ++ iowrite32be(tmp1, ®s->mac_addr0.mac_addr_u); ++ } else { ++ iowrite32be(tmp0, ®s->mac_addr[paddr_num-1].mac_addr_l); ++ iowrite32be(tmp1, ®s->mac_addr[paddr_num-1].mac_addr_u); ++ } ++} ++ ++void fman_memac_enable(struct memac_regs *regs, bool apply_rx, bool apply_tx) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->command_config); ++ ++ if (apply_rx) ++ tmp |= CMD_CFG_RX_EN; ++ ++ if (apply_tx) ++ tmp |= CMD_CFG_TX_EN; ++ ++ iowrite32be(tmp, ®s->command_config); ++} ++ ++void fman_memac_disable(struct memac_regs *regs, bool apply_rx, bool apply_tx) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->command_config); ++ ++ if (apply_rx) ++ tmp &= ~CMD_CFG_RX_EN; ++ ++ if (apply_tx) ++ tmp &= ~CMD_CFG_TX_EN; ++ ++ iowrite32be(tmp, ®s->command_config); ++} ++ ++void fman_memac_reset_stat(struct memac_regs *regs) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->statn_config); ++ ++ tmp |= STATS_CFG_CLR; ++ ++ iowrite32be(tmp, ®s->statn_config); ++ ++ while (ioread32be(®s->statn_config) & STATS_CFG_CLR); ++} ++ ++void fman_memac_reset(struct memac_regs *regs) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->command_config); ++ ++ tmp |= CMD_CFG_SW_RESET; ++ ++ iowrite32be(tmp, ®s->command_config); ++ ++ while (ioread32be(®s->command_config) & CMD_CFG_SW_RESET); ++} ++ ++int fman_memac_init(struct memac_regs *regs, ++ struct memac_cfg *cfg, ++ enum enet_interface enet_interface, ++ enum enet_speed enet_speed, ++ bool slow_10g_if, ++ uint32_t exceptions) ++{ ++ uint32_t tmp; ++ ++ /* Config */ ++ tmp = 0; ++ if (cfg->wan_mode_enable) ++ tmp |= CMD_CFG_WAN_MODE; ++ if (cfg->promiscuous_mode_enable) ++ tmp |= CMD_CFG_PROMIS_EN; ++ if (cfg->pause_forward_enable) ++ tmp |= CMD_CFG_PAUSE_FWD; ++ if (cfg->pause_ignore) ++ tmp |= CMD_CFG_PAUSE_IGNORE; ++ if (cfg->tx_addr_ins_enable) ++ tmp |= CMD_CFG_TX_ADDR_INS; ++ if (cfg->loopback_enable) ++ tmp |= CMD_CFG_LOOPBACK_EN; ++ if (cfg->cmd_frame_enable) ++ tmp |= CMD_CFG_CNT_FRM_EN; ++ if (cfg->send_idle_enable) ++ tmp |= CMD_CFG_SEND_IDLE; ++ if (cfg->no_length_check_enable) ++ tmp |= CMD_CFG_NO_LEN_CHK; ++ if (cfg->rx_sfd_any) ++ tmp |= CMD_CFG_SFD_ANY; ++ if (cfg->pad_enable) ++ tmp |= CMD_CFG_TX_PAD_EN; ++ if (cfg->wake_on_lan) ++ tmp |= CMD_CFG_MG; ++ ++ tmp |= CMD_CFG_CRC_FWD; ++ ++ iowrite32be(tmp, ®s->command_config); ++ ++ /* Max Frame Length */ ++ iowrite32be((uint32_t)cfg->max_frame_length, ®s->maxfrm); ++ ++ /* Pause Time */ ++ iowrite32be((uint32_t)cfg->pause_quanta, ®s->pause_quanta[0]); ++ iowrite32be((uint32_t)0, ®s->pause_thresh[0]); ++ ++ /* IF_MODE */ ++ tmp = 0; ++ switch (enet_interface) { ++ case E_ENET_IF_XGMII: ++ case E_ENET_IF_XFI: ++ tmp |= IF_MODE_XGMII; ++ break; ++ default: ++ tmp |= IF_MODE_GMII; ++ if (enet_interface == E_ENET_IF_RGMII && !cfg->loopback_enable) ++ tmp |= IF_MODE_RGMII | IF_MODE_RGMII_AUTO; ++ } ++ iowrite32be(tmp, ®s->if_mode); ++ ++ /* TX_FIFO_SECTIONS */ ++ tmp = 0; ++ if (enet_interface == E_ENET_IF_XGMII || ++ enet_interface == E_ENET_IF_XFI) { ++ if(slow_10g_if) { ++ tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_SLOW_10G | ++ TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G); ++ } else { ++ tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_10G | ++ TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G); ++ } ++ } else { ++ tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_1G | ++ TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G); ++ } ++ iowrite32be(tmp, ®s->tx_fifo_sections); ++ ++ /* clear all pending events and set-up interrupts */ ++ fman_memac_ack_event(regs, 0xffffffff); ++ fman_memac_set_exception(regs, exceptions, TRUE); ++ ++ return 0; ++} ++ ++void fman_memac_set_exception(struct memac_regs *regs, uint32_t val, bool enable) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->imask); ++ if (enable) ++ tmp |= val; ++ else ++ tmp &= ~val; ++ ++ iowrite32be(tmp, ®s->imask); ++} ++ ++void fman_memac_reset_filter_table(struct memac_regs *regs) ++{ ++ uint32_t i; ++ for (i = 0; i < 64; i++) ++ iowrite32be(i & ~HASH_CTRL_MCAST_EN, ®s->hashtable_ctrl); ++} ++ ++void fman_memac_set_hash_table_entry(struct memac_regs *regs, uint32_t crc) ++{ ++ iowrite32be(crc | HASH_CTRL_MCAST_EN, ®s->hashtable_ctrl); ++} ++ ++void fman_memac_set_hash_table(struct memac_regs *regs, uint32_t val) ++{ ++ iowrite32be(val, ®s->hashtable_ctrl); ++} ++ ++uint16_t fman_memac_get_max_frame_len(struct memac_regs *regs) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->maxfrm); ++ ++ return(uint16_t)tmp; ++} ++ ++ ++void fman_memac_set_tx_pause_frames(struct memac_regs *regs, ++ uint8_t priority, ++ uint16_t pause_time, ++ uint16_t thresh_time) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->tx_fifo_sections); ++ ++ if (priority == 0xff) { ++ GET_TX_EMPTY_DEFAULT_VALUE(tmp); ++ iowrite32be(tmp, ®s->tx_fifo_sections); ++ ++ tmp = ioread32be(®s->command_config); ++ tmp &= ~CMD_CFG_PFC_MODE; ++ priority = 0; ++ } else { ++ GET_TX_EMPTY_PFC_VALUE(tmp); ++ iowrite32be(tmp, ®s->tx_fifo_sections); ++ ++ tmp = ioread32be(®s->command_config); ++ tmp |= CMD_CFG_PFC_MODE; ++ } ++ ++ iowrite32be(tmp, ®s->command_config); ++ ++ tmp = ioread32be(®s->pause_quanta[priority / 2]); ++ if (priority % 2) ++ tmp &= 0x0000FFFF; ++ else ++ tmp &= 0xFFFF0000; ++ tmp |= ((uint32_t)pause_time << (16 * (priority % 2))); ++ iowrite32be(tmp, ®s->pause_quanta[priority / 2]); ++ ++ tmp = ioread32be(®s->pause_thresh[priority / 2]); ++ if (priority % 2) ++ tmp &= 0x0000FFFF; ++ else ++ tmp &= 0xFFFF0000; ++ tmp |= ((uint32_t)thresh_time<<(16 * (priority % 2))); ++ iowrite32be(tmp, ®s->pause_thresh[priority / 2]); ++} ++ ++void fman_memac_set_rx_ignore_pause_frames(struct memac_regs *regs,bool enable) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->command_config); ++ if (enable) ++ tmp |= CMD_CFG_PAUSE_IGNORE; ++ else ++ tmp &= ~CMD_CFG_PAUSE_IGNORE; ++ ++ iowrite32be(tmp, ®s->command_config); ++} ++ ++void fman_memac_set_wol(struct memac_regs *regs, bool enable) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->command_config); ++ ++ if (enable) ++ tmp |= CMD_CFG_MG; ++ else ++ tmp &= ~CMD_CFG_MG; ++ ++ iowrite32be(tmp, ®s->command_config); ++} ++ ++#define GET_MEMAC_CNTR_64(bn) \ ++ (ioread32be(®s->bn ## _l) | \ ++ ((uint64_t)ioread32be(®s->bn ## _u) << 32)) ++ ++uint64_t fman_memac_get_counter(struct memac_regs *regs, ++ enum memac_counters reg_name) ++{ ++ uint64_t ret_val; ++ ++ switch (reg_name) { ++ case E_MEMAC_COUNTER_R64: ++ ret_val = GET_MEMAC_CNTR_64(r64); ++ break; ++ case E_MEMAC_COUNTER_R127: ++ ret_val = GET_MEMAC_CNTR_64(r127); ++ break; ++ case E_MEMAC_COUNTER_R255: ++ ret_val = GET_MEMAC_CNTR_64(r255); ++ break; ++ case E_MEMAC_COUNTER_R511: ++ ret_val = GET_MEMAC_CNTR_64(r511); ++ break; ++ case E_MEMAC_COUNTER_R1023: ++ ret_val = GET_MEMAC_CNTR_64(r1023); ++ break; ++ case E_MEMAC_COUNTER_R1518: ++ ret_val = GET_MEMAC_CNTR_64(r1518); ++ break; ++ case E_MEMAC_COUNTER_R1519X: ++ ret_val = GET_MEMAC_CNTR_64(r1519x); ++ break; ++ case E_MEMAC_COUNTER_RFRG: ++ ret_val = GET_MEMAC_CNTR_64(rfrg); ++ break; ++ case E_MEMAC_COUNTER_RJBR: ++ ret_val = GET_MEMAC_CNTR_64(rjbr); ++ break; ++ case E_MEMAC_COUNTER_RDRP: ++ ret_val = GET_MEMAC_CNTR_64(rdrp); ++ break; ++ case E_MEMAC_COUNTER_RALN: ++ ret_val = GET_MEMAC_CNTR_64(raln); ++ break; ++ case E_MEMAC_COUNTER_TUND: ++ ret_val = GET_MEMAC_CNTR_64(tund); ++ break; ++ case E_MEMAC_COUNTER_ROVR: ++ ret_val = GET_MEMAC_CNTR_64(rovr); ++ break; ++ case E_MEMAC_COUNTER_RXPF: ++ ret_val = GET_MEMAC_CNTR_64(rxpf); ++ break; ++ case E_MEMAC_COUNTER_TXPF: ++ ret_val = GET_MEMAC_CNTR_64(txpf); ++ break; ++ case E_MEMAC_COUNTER_ROCT: ++ ret_val = GET_MEMAC_CNTR_64(roct); ++ break; ++ case E_MEMAC_COUNTER_RMCA: ++ ret_val = GET_MEMAC_CNTR_64(rmca); ++ break; ++ case E_MEMAC_COUNTER_RBCA: ++ ret_val = GET_MEMAC_CNTR_64(rbca); ++ break; ++ case E_MEMAC_COUNTER_RPKT: ++ ret_val = GET_MEMAC_CNTR_64(rpkt); ++ break; ++ case E_MEMAC_COUNTER_RUCA: ++ ret_val = GET_MEMAC_CNTR_64(ruca); ++ break; ++ case E_MEMAC_COUNTER_RERR: ++ ret_val = GET_MEMAC_CNTR_64(rerr); ++ break; ++ case E_MEMAC_COUNTER_TOCT: ++ ret_val = GET_MEMAC_CNTR_64(toct); ++ break; ++ case E_MEMAC_COUNTER_TMCA: ++ ret_val = GET_MEMAC_CNTR_64(tmca); ++ break; ++ case E_MEMAC_COUNTER_TBCA: ++ ret_val = GET_MEMAC_CNTR_64(tbca); ++ break; ++ case E_MEMAC_COUNTER_TUCA: ++ ret_val = GET_MEMAC_CNTR_64(tuca); ++ break; ++ case E_MEMAC_COUNTER_TERR: ++ ret_val = GET_MEMAC_CNTR_64(terr); ++ break; ++ default: ++ ret_val = 0; ++ } ++ ++ return ret_val; ++} ++ ++void fman_memac_adjust_link(struct memac_regs *regs, ++ enum enet_interface iface_mode, ++ enum enet_speed speed, bool full_dx) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->if_mode); ++ ++ if (full_dx) ++ tmp &= ~IF_MODE_HD; ++ else ++ tmp |= IF_MODE_HD; ++ ++ if (iface_mode == E_ENET_IF_RGMII) { ++ /* Configure RGMII in manual mode */ ++ tmp &= ~IF_MODE_RGMII_AUTO; ++ tmp &= ~IF_MODE_RGMII_SP_MASK; ++ ++ if (full_dx) ++ tmp |= IF_MODE_RGMII_FD; ++ else ++ tmp &= ~IF_MODE_RGMII_FD; ++ ++ switch (speed) { ++ case E_ENET_SPEED_1000: ++ tmp |= IF_MODE_RGMII_1000; ++ break; ++ case E_ENET_SPEED_100: ++ tmp |= IF_MODE_RGMII_100; ++ break; ++ case E_ENET_SPEED_10: ++ tmp |= IF_MODE_RGMII_10; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ iowrite32be(tmp, ®s->if_mode); ++} ++ ++void fman_memac_defconfig(struct memac_cfg *cfg) ++{ ++ cfg->reset_on_init = FALSE; ++ cfg->wan_mode_enable = FALSE; ++ cfg->promiscuous_mode_enable = FALSE; ++ cfg->pause_forward_enable = FALSE; ++ cfg->pause_ignore = FALSE; ++ cfg->tx_addr_ins_enable = FALSE; ++ cfg->loopback_enable = FALSE; ++ cfg->cmd_frame_enable = FALSE; ++ cfg->rx_error_discard = FALSE; ++ cfg->send_idle_enable = FALSE; ++ cfg->no_length_check_enable = TRUE; ++ cfg->lgth_check_nostdr = FALSE; ++ cfg->time_stamp_enable = FALSE; ++ cfg->tx_ipg_length = DEFAULT_TX_IPG_LENGTH; ++ cfg->max_frame_length = DEFAULT_FRAME_LENGTH; ++ cfg->pause_quanta = DEFAULT_PAUSE_QUANTA; ++ cfg->pad_enable = TRUE; ++ cfg->phy_tx_ena_on = FALSE; ++ cfg->rx_sfd_any = FALSE; ++ cfg->rx_pbl_fwd = FALSE; ++ cfg->tx_pbl_fwd = FALSE; ++ cfg->debug_mode = FALSE; ++ cfg->wake_on_lan = FALSE; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac_mii_acc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac_mii_acc.c +new file mode 100755 +index 00000000..ccda11ec +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac_mii_acc.c +@@ -0,0 +1,213 @@ ++/* ++ * Copyright 2008-2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#include "fsl_fman_memac_mii_acc.h" ++ ++static void write_phy_reg_10g(struct memac_mii_access_mem_map *mii_regs, ++ uint8_t phy_addr, uint8_t reg, uint16_t data) ++{ ++ uint32_t tmp_reg; ++ ++ tmp_reg = ioread32be(&mii_regs->mdio_cfg); ++ /* Leave only MDIO_CLK_DIV bits set on */ ++ tmp_reg &= MDIO_CFG_CLK_DIV_MASK; ++ /* Set maximum MDIO_HOLD value to allow phy to see ++ change of data signal */ ++ tmp_reg |= MDIO_CFG_HOLD_MASK; ++ /* Add 10G interface mode */ ++ tmp_reg |= MDIO_CFG_ENC45; ++ iowrite32be(tmp_reg, &mii_regs->mdio_cfg); ++ ++ /* Wait for command completion */ ++ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) ++ udelay(1); ++ ++ /* Specify phy and register to be accessed */ ++ iowrite32be(phy_addr, &mii_regs->mdio_ctrl); ++ iowrite32be(reg, &mii_regs->mdio_addr); ++ wmb(); ++ ++ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) ++ udelay(1); ++ ++ /* Write data */ ++ iowrite32be(data, &mii_regs->mdio_data); ++ wmb(); ++ ++ /* Wait for write transaction end */ ++ while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY) ++ udelay(1); ++} ++ ++static uint32_t read_phy_reg_10g(struct memac_mii_access_mem_map *mii_regs, ++ uint8_t phy_addr, uint8_t reg, uint16_t *data) ++{ ++ uint32_t tmp_reg; ++ ++ tmp_reg = ioread32be(&mii_regs->mdio_cfg); ++ /* Leave only MDIO_CLK_DIV bits set on */ ++ tmp_reg &= MDIO_CFG_CLK_DIV_MASK; ++ /* Set maximum MDIO_HOLD value to allow phy to see ++ change of data signal */ ++ tmp_reg |= MDIO_CFG_HOLD_MASK; ++ /* Add 10G interface mode */ ++ tmp_reg |= MDIO_CFG_ENC45; ++ iowrite32be(tmp_reg, &mii_regs->mdio_cfg); ++ ++ /* Wait for command completion */ ++ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) ++ udelay(1); ++ ++ /* Specify phy and register to be accessed */ ++ iowrite32be(phy_addr, &mii_regs->mdio_ctrl); ++ iowrite32be(reg, &mii_regs->mdio_addr); ++ wmb(); ++ ++ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) ++ udelay(1); ++ ++ /* Read cycle */ ++ tmp_reg = phy_addr; ++ tmp_reg |= MDIO_CTL_READ; ++ iowrite32be(tmp_reg, &mii_regs->mdio_ctrl); ++ wmb(); ++ ++ /* Wait for data to be available */ ++ while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY) ++ udelay(1); ++ ++ *data = (uint16_t)ioread32be(&mii_regs->mdio_data); ++ ++ /* Check if there was an error */ ++ return ioread32be(&mii_regs->mdio_cfg); ++} ++ ++static void write_phy_reg_1g(struct memac_mii_access_mem_map *mii_regs, ++ uint8_t phy_addr, uint8_t reg, uint16_t data) ++{ ++ uint32_t tmp_reg; ++ ++ /* Leave only MDIO_CLK_DIV and MDIO_HOLD bits set on */ ++ tmp_reg = ioread32be(&mii_regs->mdio_cfg); ++ tmp_reg &= (MDIO_CFG_CLK_DIV_MASK | MDIO_CFG_HOLD_MASK); ++ iowrite32be(tmp_reg, &mii_regs->mdio_cfg); ++ ++ /* Wait for command completion */ ++ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) ++ udelay(1); ++ ++ /* Write transaction */ ++ tmp_reg = (phy_addr << MDIO_CTL_PHY_ADDR_SHIFT); ++ tmp_reg |= reg; ++ iowrite32be(tmp_reg, &mii_regs->mdio_ctrl); ++ ++ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) ++ udelay(1); ++ ++ iowrite32be(data, &mii_regs->mdio_data); ++ ++ wmb(); ++ ++ /* Wait for write transaction to end */ ++ while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY) ++ udelay(1); ++} ++ ++static uint32_t read_phy_reg_1g(struct memac_mii_access_mem_map *mii_regs, ++ uint8_t phy_addr, uint8_t reg, uint16_t *data) ++{ ++ uint32_t tmp_reg; ++ ++ /* Leave only MDIO_CLK_DIV and MDIO_HOLD bits set on */ ++ tmp_reg = ioread32be(&mii_regs->mdio_cfg); ++ tmp_reg &= (MDIO_CFG_CLK_DIV_MASK | MDIO_CFG_HOLD_MASK); ++ iowrite32be(tmp_reg, &mii_regs->mdio_cfg); ++ ++ /* Wait for command completion */ ++ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) ++ udelay(1); ++ ++ /* Read transaction */ ++ tmp_reg = (phy_addr << MDIO_CTL_PHY_ADDR_SHIFT); ++ tmp_reg |= reg; ++ tmp_reg |= MDIO_CTL_READ; ++ iowrite32be(tmp_reg, &mii_regs->mdio_ctrl); ++ ++ while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) ++ udelay(1); ++ ++ /* Wait for data to be available */ ++ while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY) ++ udelay(1); ++ ++ *data = (uint16_t)ioread32be(&mii_regs->mdio_data); ++ ++ /* Check error */ ++ return ioread32be(&mii_regs->mdio_cfg); ++} ++ ++/*****************************************************************************/ ++int fman_memac_mii_write_phy_reg(struct memac_mii_access_mem_map *mii_regs, ++ uint8_t phy_addr, uint8_t reg, uint16_t data, ++ enum enet_speed enet_speed) ++{ ++ /* Figure out interface type - 10G vs 1G. ++ In 10G interface both phy_addr and devAddr present. */ ++ if (enet_speed == E_ENET_SPEED_10000) ++ write_phy_reg_10g(mii_regs, phy_addr, reg, data); ++ else ++ write_phy_reg_1g(mii_regs, phy_addr, reg, data); ++ ++ return 0; ++} ++ ++/*****************************************************************************/ ++int fman_memac_mii_read_phy_reg(struct memac_mii_access_mem_map *mii_regs, ++ uint8_t phy_addr, uint8_t reg, uint16_t *data, ++ enum enet_speed enet_speed) ++{ ++ uint32_t ans; ++ /* Figure out interface type - 10G vs 1G. ++ In 10G interface both phy_addr and devAddr present. */ ++ if (enet_speed == E_ENET_SPEED_10000) ++ ans = read_phy_reg_10g(mii_regs, phy_addr, reg, data); ++ else ++ ans = read_phy_reg_1g(mii_regs, phy_addr, reg, data); ++ ++ if (ans & MDIO_CFG_READ_ERR) ++ return -EINVAL; ++ return 0; ++} ++ ++/* ......................................................................... */ ++ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_tgec.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_tgec.c +new file mode 100644 +index 00000000..fff9d5de +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_tgec.c +@@ -0,0 +1,367 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#include "fsl_fman_tgec.h" ++ ++ ++void fman_tgec_set_mac_address(struct tgec_regs *regs, uint8_t *adr) ++{ ++ uint32_t tmp0, tmp1; ++ ++ tmp0 = (uint32_t)(adr[0] | ++ adr[1] << 8 | ++ adr[2] << 16 | ++ adr[3] << 24); ++ tmp1 = (uint32_t)(adr[4] | adr[5] << 8); ++ iowrite32be(tmp0, ®s->mac_addr_0); ++ iowrite32be(tmp1, ®s->mac_addr_1); ++} ++ ++void fman_tgec_reset_stat(struct tgec_regs *regs) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->command_config); ++ ++ tmp |= CMD_CFG_STAT_CLR; ++ ++ iowrite32be(tmp, ®s->command_config); ++ ++ while (ioread32be(®s->command_config) & CMD_CFG_STAT_CLR) ; ++} ++ ++#define GET_TGEC_CNTR_64(bn) \ ++ (((uint64_t)ioread32be(®s->bn ## _u) << 32) | \ ++ ioread32be(®s->bn ## _l)) ++ ++uint64_t fman_tgec_get_counter(struct tgec_regs *regs, enum tgec_counters reg_name) ++{ ++ uint64_t ret_val; ++ ++ switch (reg_name) { ++ case E_TGEC_COUNTER_R64: ++ ret_val = GET_TGEC_CNTR_64(r64); ++ break; ++ case E_TGEC_COUNTER_R127: ++ ret_val = GET_TGEC_CNTR_64(r127); ++ break; ++ case E_TGEC_COUNTER_R255: ++ ret_val = GET_TGEC_CNTR_64(r255); ++ break; ++ case E_TGEC_COUNTER_R511: ++ ret_val = GET_TGEC_CNTR_64(r511); ++ break; ++ case E_TGEC_COUNTER_R1023: ++ ret_val = GET_TGEC_CNTR_64(r1023); ++ break; ++ case E_TGEC_COUNTER_R1518: ++ ret_val = GET_TGEC_CNTR_64(r1518); ++ break; ++ case E_TGEC_COUNTER_R1519X: ++ ret_val = GET_TGEC_CNTR_64(r1519x); ++ break; ++ case E_TGEC_COUNTER_TRFRG: ++ ret_val = GET_TGEC_CNTR_64(trfrg); ++ break; ++ case E_TGEC_COUNTER_TRJBR: ++ ret_val = GET_TGEC_CNTR_64(trjbr); ++ break; ++ case E_TGEC_COUNTER_RDRP: ++ ret_val = GET_TGEC_CNTR_64(rdrp); ++ break; ++ case E_TGEC_COUNTER_RALN: ++ ret_val = GET_TGEC_CNTR_64(raln); ++ break; ++ case E_TGEC_COUNTER_TRUND: ++ ret_val = GET_TGEC_CNTR_64(trund); ++ break; ++ case E_TGEC_COUNTER_TROVR: ++ ret_val = GET_TGEC_CNTR_64(trovr); ++ break; ++ case E_TGEC_COUNTER_RXPF: ++ ret_val = GET_TGEC_CNTR_64(rxpf); ++ break; ++ case E_TGEC_COUNTER_TXPF: ++ ret_val = GET_TGEC_CNTR_64(txpf); ++ break; ++ case E_TGEC_COUNTER_ROCT: ++ ret_val = GET_TGEC_CNTR_64(roct); ++ break; ++ case E_TGEC_COUNTER_RMCA: ++ ret_val = GET_TGEC_CNTR_64(rmca); ++ break; ++ case E_TGEC_COUNTER_RBCA: ++ ret_val = GET_TGEC_CNTR_64(rbca); ++ break; ++ case E_TGEC_COUNTER_RPKT: ++ ret_val = GET_TGEC_CNTR_64(rpkt); ++ break; ++ case E_TGEC_COUNTER_RUCA: ++ ret_val = GET_TGEC_CNTR_64(ruca); ++ break; ++ case E_TGEC_COUNTER_RERR: ++ ret_val = GET_TGEC_CNTR_64(rerr); ++ break; ++ case E_TGEC_COUNTER_TOCT: ++ ret_val = GET_TGEC_CNTR_64(toct); ++ break; ++ case E_TGEC_COUNTER_TMCA: ++ ret_val = GET_TGEC_CNTR_64(tmca); ++ break; ++ case E_TGEC_COUNTER_TBCA: ++ ret_val = GET_TGEC_CNTR_64(tbca); ++ break; ++ case E_TGEC_COUNTER_TUCA: ++ ret_val = GET_TGEC_CNTR_64(tuca); ++ break; ++ case E_TGEC_COUNTER_TERR: ++ ret_val = GET_TGEC_CNTR_64(terr); ++ break; ++ default: ++ ret_val = 0; ++ } ++ ++ return ret_val; ++} ++ ++void fman_tgec_enable(struct tgec_regs *regs, bool apply_rx, bool apply_tx) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->command_config); ++ if (apply_rx) ++ tmp |= CMD_CFG_RX_EN; ++ if (apply_tx) ++ tmp |= CMD_CFG_TX_EN; ++ iowrite32be(tmp, ®s->command_config); ++} ++ ++void fman_tgec_disable(struct tgec_regs *regs, bool apply_rx, bool apply_tx) ++{ ++ uint32_t tmp_reg_32; ++ ++ tmp_reg_32 = ioread32be(®s->command_config); ++ if (apply_rx) ++ tmp_reg_32 &= ~CMD_CFG_RX_EN; ++ if (apply_tx) ++ tmp_reg_32 &= ~CMD_CFG_TX_EN; ++ iowrite32be(tmp_reg_32, ®s->command_config); ++} ++ ++void fman_tgec_set_promiscuous(struct tgec_regs *regs, bool val) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->command_config); ++ if (val) ++ tmp |= CMD_CFG_PROMIS_EN; ++ else ++ tmp &= ~CMD_CFG_PROMIS_EN; ++ iowrite32be(tmp, ®s->command_config); ++} ++ ++void fman_tgec_reset_filter_table(struct tgec_regs *regs) ++{ ++ uint32_t i; ++ for (i = 0; i < 512; i++) ++ iowrite32be(i & ~TGEC_HASH_MCAST_EN, ®s->hashtable_ctrl); ++} ++ ++void fman_tgec_set_hash_table_entry(struct tgec_regs *regs, uint32_t crc) ++{ ++ uint32_t hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK; /* Take 9 MSB bits */ ++ iowrite32be(hash | TGEC_HASH_MCAST_EN, ®s->hashtable_ctrl); ++} ++ ++void fman_tgec_set_hash_table(struct tgec_regs *regs, uint32_t value) ++{ ++ iowrite32be(value, ®s->hashtable_ctrl); ++} ++ ++void fman_tgec_set_tx_pause_frames(struct tgec_regs *regs, uint16_t pause_time) ++{ ++ iowrite32be((uint32_t)pause_time, ®s->pause_quant); ++} ++ ++void fman_tgec_set_rx_ignore_pause_frames(struct tgec_regs *regs, bool en) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->command_config); ++ if (en) ++ tmp |= CMD_CFG_PAUSE_IGNORE; ++ else ++ tmp &= ~CMD_CFG_PAUSE_IGNORE; ++ iowrite32be(tmp, ®s->command_config); ++} ++ ++void fman_tgec_enable_1588_time_stamp(struct tgec_regs *regs, bool en) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->command_config); ++ if (en) ++ tmp |= CMD_CFG_EN_TIMESTAMP; ++ else ++ tmp &= ~CMD_CFG_EN_TIMESTAMP; ++ iowrite32be(tmp, ®s->command_config); ++} ++ ++uint32_t fman_tgec_get_event(struct tgec_regs *regs, uint32_t ev_mask) ++{ ++ return ioread32be(®s->ievent) & ev_mask; ++} ++ ++void fman_tgec_ack_event(struct tgec_regs *regs, uint32_t ev_mask) ++{ ++ iowrite32be(ev_mask, ®s->ievent); ++} ++ ++uint32_t fman_tgec_get_interrupt_mask(struct tgec_regs *regs) ++{ ++ return ioread32be(®s->imask); ++} ++ ++void fman_tgec_add_addr_in_paddr(struct tgec_regs *regs, uint8_t *adr) ++{ ++ uint32_t tmp0, tmp1; ++ ++ tmp0 = (uint32_t)(adr[0] | ++ adr[1] << 8 | ++ adr[2] << 16 | ++ adr[3] << 24); ++ tmp1 = (uint32_t)(adr[4] | adr[5] << 8); ++ iowrite32be(tmp0, ®s->mac_addr_2); ++ iowrite32be(tmp1, ®s->mac_addr_3); ++} ++ ++void fman_tgec_clear_addr_in_paddr(struct tgec_regs *regs) ++{ ++ iowrite32be(0, ®s->mac_addr_2); ++ iowrite32be(0, ®s->mac_addr_3); ++} ++ ++uint32_t fman_tgec_get_revision(struct tgec_regs *regs) ++{ ++ return ioread32be(®s->tgec_id); ++} ++ ++void fman_tgec_enable_interrupt(struct tgec_regs *regs, uint32_t ev_mask) ++{ ++ iowrite32be(ioread32be(®s->imask) | ev_mask, ®s->imask); ++} ++ ++void fman_tgec_disable_interrupt(struct tgec_regs *regs, uint32_t ev_mask) ++{ ++ iowrite32be(ioread32be(®s->imask) & ~ev_mask, ®s->imask); ++} ++ ++uint16_t fman_tgec_get_max_frame_len(struct tgec_regs *regs) ++{ ++ return (uint16_t) ioread32be(®s->maxfrm); ++} ++ ++void fman_tgec_defconfig(struct tgec_cfg *cfg) ++{ ++ cfg->wan_mode_enable = DEFAULT_WAN_MODE_ENABLE; ++ cfg->promiscuous_mode_enable = DEFAULT_PROMISCUOUS_MODE_ENABLE; ++ cfg->pause_forward_enable = DEFAULT_PAUSE_FORWARD_ENABLE; ++ cfg->pause_ignore = DEFAULT_PAUSE_IGNORE; ++ cfg->tx_addr_ins_enable = DEFAULT_TX_ADDR_INS_ENABLE; ++ cfg->loopback_enable = DEFAULT_LOOPBACK_ENABLE; ++ cfg->cmd_frame_enable = DEFAULT_CMD_FRAME_ENABLE; ++ cfg->rx_error_discard = DEFAULT_RX_ERROR_DISCARD; ++ cfg->send_idle_enable = DEFAULT_SEND_IDLE_ENABLE; ++ cfg->no_length_check_enable = DEFAULT_NO_LENGTH_CHECK_ENABLE; ++ cfg->lgth_check_nostdr = DEFAULT_LGTH_CHECK_NOSTDR; ++ cfg->time_stamp_enable = DEFAULT_TIME_STAMP_ENABLE; ++ cfg->tx_ipg_length = DEFAULT_TX_IPG_LENGTH; ++ cfg->max_frame_length = DEFAULT_MAX_FRAME_LENGTH; ++ cfg->pause_quant = DEFAULT_PAUSE_QUANT; ++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 ++ cfg->skip_fman11_workaround = FALSE; ++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ ++} ++ ++int fman_tgec_init(struct tgec_regs *regs, struct tgec_cfg *cfg, ++ uint32_t exception_mask) ++{ ++ uint32_t tmp; ++ ++ /* Config */ ++ tmp = 0x40; /* CRC forward */ ++ if (cfg->wan_mode_enable) ++ tmp |= CMD_CFG_WAN_MODE; ++ if (cfg->promiscuous_mode_enable) ++ tmp |= CMD_CFG_PROMIS_EN; ++ if (cfg->pause_forward_enable) ++ tmp |= CMD_CFG_PAUSE_FWD; ++ if (cfg->pause_ignore) ++ tmp |= CMD_CFG_PAUSE_IGNORE; ++ if (cfg->tx_addr_ins_enable) ++ tmp |= CMD_CFG_TX_ADDR_INS; ++ if (cfg->loopback_enable) ++ tmp |= CMD_CFG_LOOPBACK_EN; ++ if (cfg->cmd_frame_enable) ++ tmp |= CMD_CFG_CMD_FRM_EN; ++ if (cfg->rx_error_discard) ++ tmp |= CMD_CFG_RX_ER_DISC; ++ if (cfg->send_idle_enable) ++ tmp |= CMD_CFG_SEND_IDLE; ++ if (cfg->no_length_check_enable) ++ tmp |= CMD_CFG_NO_LEN_CHK; ++ if (cfg->time_stamp_enable) ++ tmp |= CMD_CFG_EN_TIMESTAMP; ++ iowrite32be(tmp, ®s->command_config); ++ ++ /* Max Frame Length */ ++ iowrite32be((uint32_t)cfg->max_frame_length, ®s->maxfrm); ++ /* Pause Time */ ++ iowrite32be(cfg->pause_quant, ®s->pause_quant); ++ ++ /* clear all pending events and set-up interrupts */ ++ fman_tgec_ack_event(regs, 0xffffffff); ++ fman_tgec_enable_interrupt(regs, exception_mask); ++ ++ return 0; ++} ++ ++void fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007(struct tgec_regs *regs) ++{ ++ uint32_t tmp; ++ ++ /* restore the default tx ipg Length */ ++ tmp = (ioread32be(®s->tx_ipg_len) & ~TGEC_TX_IPG_LENGTH_MASK) | 12; ++ ++ iowrite32be(tmp, ®s->tx_ipg_len); ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c +new file mode 100644 +index 00000000..85426c5f +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c +@@ -0,0 +1,1096 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File memac.c ++ ++ @Description FM mEMAC driver ++*//***************************************************************************/ ++ ++#include "std_ext.h" ++#include "string_ext.h" ++#include "error_ext.h" ++#include "xx_ext.h" ++#include "endian_ext.h" ++#include "debug_ext.h" ++ ++#include "fm_common.h" ++#include "memac.h" ++ ++ ++/*****************************************************************************/ ++/* Internal routines */ ++/*****************************************************************************/ ++ ++/* ......................................................................... */ ++ ++static uint32_t GetMacAddrHashCode(uint64_t ethAddr) ++{ ++ uint64_t mask1, mask2; ++ uint32_t xorVal = 0; ++ uint8_t i, j; ++ ++ for (i=0; i<6; i++) ++ { ++ mask1 = ethAddr & (uint64_t)0x01; ++ ethAddr >>= 1; ++ ++ for (j=0; j<7; j++) ++ { ++ mask2 = ethAddr & (uint64_t)0x01; ++ mask1 ^= mask2; ++ ethAddr >>= 1; ++ } ++ ++ xorVal |= (mask1 << (5-i)); ++ } ++ ++ return xorVal; ++} ++ ++/* ......................................................................... */ ++ ++static void SetupSgmiiInternalPhy(t_Memac *p_Memac, uint8_t phyAddr) ++{ ++ uint16_t tmpReg16; ++ e_EnetMode enetMode; ++ ++ /* In case the higher MACs are used (i.e. the MACs that should support 10G), ++ speed=10000 is provided for SGMII ports. Temporary modify enet mode ++ to 1G one, so MII functions can work correctly. */ ++ enetMode = p_Memac->enetMode; ++ ++ /* SGMII mode + AN enable */ ++ tmpReg16 = PHY_SGMII_IF_MODE_AN | PHY_SGMII_IF_MODE_SGMII; ++ if ((p_Memac->enetMode) == e_ENET_MODE_SGMII_2500) ++ tmpReg16 = PHY_SGMII_CR_PHY_RESET | PHY_SGMII_IF_SPEED_GIGABIT | PHY_SGMII_IF_MODE_SGMII; ++ ++ p_Memac->enetMode = MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_Memac->enetMode), e_ENET_SPEED_1000); ++ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x14, tmpReg16); ++ ++ /* Device ability according to SGMII specification */ ++ tmpReg16 = PHY_SGMII_DEV_ABILITY_SGMII; ++ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x4, tmpReg16); ++ ++ /* Adjust link timer for SGMII - ++ According to Cisco SGMII specification the timer should be 1.6 ms. ++ The link_timer register is configured in units of the clock. ++ - When running as 1G SGMII, Serdes clock is 125 MHz, so ++ unit = 1 / (125*10^6 Hz) = 8 ns. ++ 1.6 ms in units of 8 ns = 1.6ms / 8ns = 2 * 10^5 = 0x30d40 ++ - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so ++ unit = 1 / (312.5*10^6 Hz) = 3.2 ns. ++ 1.6 ms in units of 3.2 ns = 1.6ms / 3.2ns = 5 * 10^5 = 0x7a120. ++ Since link_timer value of 1G SGMII will be too short for 2.5 SGMII, ++ we always set up here a value of 2.5 SGMII. */ ++ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x13, 0x0007); ++ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x12, 0xa120); ++ ++ /* Restart AN */ ++ tmpReg16 = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN; ++ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x0, tmpReg16); ++ ++ /* Restore original enet mode */ ++ p_Memac->enetMode = enetMode; ++} ++ ++/* ......................................................................... */ ++ ++static void SetupSgmiiInternalPhyBaseX(t_Memac *p_Memac, uint8_t phyAddr) ++{ ++ uint16_t tmpReg16; ++ e_EnetMode enetMode; ++ ++ /* In case the higher MACs are used (i.e. the MACs that should support 10G), ++ speed=10000 is provided for SGMII ports. Temporary modify enet mode ++ to 1G one, so MII functions can work correctly. */ ++ enetMode = p_Memac->enetMode; ++ p_Memac->enetMode = MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_Memac->enetMode), e_ENET_SPEED_1000); ++ ++ /* 1000BaseX mode */ ++ tmpReg16 = PHY_SGMII_IF_MODE_1000X; ++ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x14, tmpReg16); ++ ++ /* AN Device capability */ ++ tmpReg16 = PHY_SGMII_DEV_ABILITY_1000X; ++ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x4, tmpReg16); ++ ++ /* Adjust link timer for SGMII - ++ For Serdes 1000BaseX auto-negotiation the timer should be 10 ms. ++ The link_timer register is configured in units of the clock. ++ - When running as 1G SGMII, Serdes clock is 125 MHz, so ++ unit = 1 / (125*10^6 Hz) = 8 ns. ++ 10 ms in units of 8 ns = 10ms / 8ns = 1250000 = 0x1312d0 ++ - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so ++ unit = 1 / (312.5*10^6 Hz) = 3.2 ns. ++ 10 ms in units of 3.2 ns = 10ms / 3.2ns = 3125000 = 0x2faf08. ++ Since link_timer value of 1G SGMII will be too short for 2.5 SGMII, ++ we always set up here a value of 2.5 SGMII. */ ++ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x13, 0x002f); ++ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x12, 0xaf08); ++ ++ /* Restart AN */ ++ tmpReg16 = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN; ++ MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x0, tmpReg16); ++ ++ /* Restore original enet mode */ ++ p_Memac->enetMode = enetMode; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error CheckInitParameters(t_Memac *p_Memac) ++{ ++ e_FmMacType portType; ++ ++ portType = ((ENET_SPEED_FROM_MODE(p_Memac->enetMode) < e_ENET_SPEED_10000) ? e_FM_MAC_1G : e_FM_MAC_10G); ++ ++#if (FM_MAX_NUM_OF_10G_MACS > 0) ++ if ((portType == e_FM_MAC_10G) && (p_Memac->macId >= FM_MAX_NUM_OF_10G_MACS)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("10G MAC ID must be less than %d", FM_MAX_NUM_OF_10G_MACS)); ++#endif /* (FM_MAX_NUM_OF_10G_MACS > 0) */ ++ ++ if ((portType == e_FM_MAC_1G) && (p_Memac->macId >= FM_MAX_NUM_OF_1G_MACS)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("1G MAC ID must be less than %d", FM_MAX_NUM_OF_1G_MACS)); ++ if (p_Memac->addr == 0) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet MAC must have a valid MAC address")); ++ if (!p_Memac->f_Exception) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Uninitialized f_Exception")); ++ if (!p_Memac->f_Event) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Uninitialized f_Event")); ++#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002 ++ if (!p_Memac->p_MemacDriverParam->no_length_check_enable) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("LengthCheck!")); ++#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */ ++ ++ return E_OK; ++} ++ ++/* ........................................................................... */ ++ ++static void MemacErrException(t_Handle h_Memac) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ uint32_t event, imask; ++ ++ event = fman_memac_get_event(p_Memac->p_MemMap, 0xffffffff); ++ imask = fman_memac_get_interrupt_mask(p_Memac->p_MemMap); ++ ++ /* Imask include both error and notification/event bits. ++ Leaving only error bits enabled by imask. ++ The imask error bits are shifted by 16 bits offset from ++ their corresponding location in the ievent - hence the >> 16 */ ++ event &= ((imask & MEMAC_ALL_ERRS_IMASK) >> 16); ++ ++ fman_memac_ack_event(p_Memac->p_MemMap, event); ++ ++ if (event & MEMAC_IEVNT_TS_ECC_ER) ++ p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_TS_FIFO_ECC_ERR); ++ if (event & MEMAC_IEVNT_TX_ECC_ER) ++ p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_10G_1TX_ECC_ER); ++ if (event & MEMAC_IEVNT_RX_ECC_ER) ++ p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_10G_RX_ECC_ER); ++} ++ ++static void MemacException(t_Handle h_Memac) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ uint32_t event, imask; ++ ++ event = fman_memac_get_event(p_Memac->p_MemMap, 0xffffffff); ++ imask = fman_memac_get_interrupt_mask(p_Memac->p_MemMap); ++ ++ /* Imask include both error and notification/event bits. ++ Leaving only error bits enabled by imask. ++ The imask error bits are shifted by 16 bits offset from ++ their corresponding location in the ievent - hence the >> 16 */ ++ event &= ((imask & MEMAC_ALL_ERRS_IMASK) >> 16); ++ ++ fman_memac_ack_event(p_Memac->p_MemMap, event); ++ ++ if (event & MEMAC_IEVNT_MGI) ++ p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_MAGIC_PACKET_INDICATION); ++} ++ ++/* ......................................................................... */ ++ ++static void FreeInitResources(t_Memac *p_Memac) ++{ ++ e_FmMacType portType; ++ ++ portType = ++ ((ENET_SPEED_FROM_MODE(p_Memac->enetMode) < e_ENET_SPEED_10000) ? e_FM_MAC_1G : e_FM_MAC_10G); ++ ++ if (portType == e_FM_MAC_10G) ++ FmUnregisterIntr(p_Memac->fmMacControllerDriver.h_Fm, e_FM_MOD_10G_MAC, p_Memac->macId, e_FM_INTR_TYPE_ERR); ++ else ++ FmUnregisterIntr(p_Memac->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Memac->macId, e_FM_INTR_TYPE_ERR); ++ ++ /* release the driver's group hash table */ ++ FreeHashTable(p_Memac->p_MulticastAddrHash); ++ p_Memac->p_MulticastAddrHash = NULL; ++ ++ /* release the driver's individual hash table */ ++ FreeHashTable(p_Memac->p_UnicastAddrHash); ++ p_Memac->p_UnicastAddrHash = NULL; ++} ++ ++ ++/*****************************************************************************/ ++/* mEMAC API routines */ ++/*****************************************************************************/ ++ ++/* ......................................................................... */ ++ ++static t_Error MemacEnable(t_Handle h_Memac, e_CommMode mode) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ fman_memac_enable(p_Memac->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX)); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacDisable (t_Handle h_Memac, e_CommMode mode) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ fman_memac_disable(p_Memac->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX)); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacSetPromiscuous(t_Handle h_Memac, bool newVal) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ fman_memac_set_promiscuous(p_Memac->p_MemMap, newVal); ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error MemacAdjustLink(t_Handle h_Memac, e_EnetSpeed speed, bool fullDuplex) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ if ((speed >= e_ENET_SPEED_1000) && (!fullDuplex)) ++ RETURN_ERROR(MAJOR, E_CONFLICT, ++ ("Ethernet MAC 1G or 10G does not support half-duplex")); ++ ++ fman_memac_adjust_link(p_Memac->p_MemMap, ++ (enum enet_interface)ENET_INTERFACE_FROM_MODE(p_Memac->enetMode), ++ (enum enet_speed)speed, ++ fullDuplex); ++ return E_OK; ++} ++ ++ ++/*****************************************************************************/ ++/* Memac Configs modification functions */ ++/*****************************************************************************/ ++ ++/* ......................................................................... */ ++ ++static t_Error MemacConfigLoopback(t_Handle h_Memac, bool newVal) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ p_Memac->p_MemacDriverParam->loopback_enable = newVal; ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacConfigWan(t_Handle h_Memac, bool newVal) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ p_Memac->p_MemacDriverParam->wan_mode_enable = newVal; ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacConfigMaxFrameLength(t_Handle h_Memac, uint16_t newVal) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ p_Memac->p_MemacDriverParam->max_frame_length = newVal; ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacConfigPad(t_Handle h_Memac, bool newVal) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ p_Memac->p_MemacDriverParam->pad_enable = newVal; ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacConfigLengthCheck(t_Handle h_Memac, bool newVal) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ p_Memac->p_MemacDriverParam->no_length_check_enable = !newVal; ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacConfigException(t_Handle h_Memac, e_FmMacExceptions exception, bool enable) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ uint32_t bitMask = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ GET_EXCEPTION_FLAG(bitMask, exception); ++ if (bitMask) ++ { ++ if (enable) ++ p_Memac->exceptions |= bitMask; ++ else ++ p_Memac->exceptions &= ~bitMask; ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacConfigResetOnInit(t_Handle h_Memac, bool enable) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ p_Memac->p_MemacDriverParam->reset_on_init = enable; ++ ++ return E_OK; ++} ++ ++ ++/*****************************************************************************/ ++/* Memac Run Time API functions */ ++/*****************************************************************************/ ++ ++/* ......................................................................... */ ++ ++static t_Error MemacSetTxPauseFrames(t_Handle h_Memac, ++ uint8_t priority, ++ uint16_t pauseTime, ++ uint16_t threshTime) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ if (priority != 0xFF) ++ { ++ bool PortConfigured, PreFetchEnabled; ++ ++ if (FmGetTnumAgingPeriod(p_Memac->fmMacControllerDriver.h_Fm) == 0) ++ RETURN_ERROR(MAJOR, E_CONFLICT, ("For PFC operation, TNUM aging must be enabled")); ++ ++ FmGetPortPreFetchConfiguration(p_Memac->fmMacControllerDriver.h_Fm, ++ p_Memac->fmMacControllerDriver.macId, ++ &PortConfigured, ++ &PreFetchEnabled); ++ ++ if ((ENET_SPEED_FROM_MODE(p_Memac->fmMacControllerDriver.enetMode) == e_ENET_SPEED_1000) && !PortConfigured) ++ DBG(INFO, ("For PFC correct operation, prefetch must be configured on the FM Tx PORT")); ++ ++ if ((ENET_SPEED_FROM_MODE(p_Memac->fmMacControllerDriver.enetMode) == e_ENET_SPEED_1000) && PortConfigured && !PreFetchEnabled) ++ DBG(WARNING, ("For PFC correct operation, prefetch must be configured on the FM Tx PORT")); ++ } ++ ++ fman_memac_set_tx_pause_frames(p_Memac->p_MemMap, priority, pauseTime, threshTime); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacSetTxAutoPauseFrames(t_Handle h_Memac, ++ uint16_t pauseTime) ++{ ++ return MemacSetTxPauseFrames(h_Memac, FM_MAC_NO_PFC, pauseTime, 0); ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacSetRxIgnorePauseFrames(t_Handle h_Memac, bool en) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ fman_memac_set_rx_ignore_pause_frames(p_Memac->p_MemMap, en); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacSetWakeOnLan(t_Handle h_Memac, bool en) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ fman_memac_set_wol(p_Memac->p_MemMap, en); ++ ++ return E_OK; ++} ++ ++/* .............................................................................. */ ++ ++static t_Error MemacEnable1588TimeStamp(t_Handle h_Memac) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++UNUSED(p_Memac); ++DBG(WARNING, ("mEMAC has 1588 always enabled!")); ++ ++ return E_OK; ++} ++ ++/* Counters handling */ ++/* ......................................................................... */ ++ ++static t_Error MemacGetStatistics(t_Handle h_Memac, t_FmMacStatistics *p_Statistics) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_Statistics, E_NULL_POINTER); ++ ++ p_Statistics->eStatPkts64 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R64); ++ p_Statistics->eStatPkts65to127 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R127); ++ p_Statistics->eStatPkts128to255 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R255); ++ p_Statistics->eStatPkts256to511 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R511); ++ p_Statistics->eStatPkts512to1023 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1023); ++ p_Statistics->eStatPkts1024to1518 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1518); ++ p_Statistics->eStatPkts1519to1522 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1519X); ++/* */ ++ p_Statistics->eStatFragments = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RFRG); ++ p_Statistics->eStatJabbers = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RJBR); ++ ++ p_Statistics->eStatsDropEvents = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RDRP); ++ p_Statistics->eStatCRCAlignErrors = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RALN); ++ ++ p_Statistics->eStatUndersizePkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TUND); ++ p_Statistics->eStatOversizePkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_ROVR); ++/* Pause */ ++ p_Statistics->reStatPause = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RXPF); ++ p_Statistics->teStatPause = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TXPF); ++ ++/* MIB II */ ++ p_Statistics->ifInOctets = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_ROCT); ++ p_Statistics->ifInUcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RUCA); ++ p_Statistics->ifInMcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RMCA); ++ p_Statistics->ifInBcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RBCA); ++ p_Statistics->ifInPkts = p_Statistics->ifInUcastPkts ++ + p_Statistics->ifInMcastPkts ++ + p_Statistics->ifInBcastPkts; ++ p_Statistics->ifInDiscards = 0; ++ p_Statistics->ifInErrors = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RERR); ++ ++ p_Statistics->ifOutOctets = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TOCT); ++ p_Statistics->ifOutUcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TUCA); ++ p_Statistics->ifOutMcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TMCA); ++ p_Statistics->ifOutBcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TBCA); ++ p_Statistics->ifOutPkts = p_Statistics->ifOutUcastPkts ++ + p_Statistics->ifOutMcastPkts ++ + p_Statistics->ifOutBcastPkts; ++ p_Statistics->ifOutDiscards = 0; ++ p_Statistics->ifOutErrors = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TERR); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacModifyMacAddress (t_Handle h_Memac, t_EnetAddr *p_EnetAddr) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ fman_memac_add_addr_in_paddr(p_Memac->p_MemMap, (uint8_t *)(*p_EnetAddr), 0); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacResetCounters (t_Handle h_Memac) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ fman_memac_reset_stat(p_Memac->p_MemMap); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacAddExactMatchMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr) ++{ ++ t_Memac *p_Memac = (t_Memac *) h_Memac; ++ uint64_t ethAddr; ++ uint8_t paddrNum; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); ++ ++ if (ethAddr & GROUP_ADDRESS) ++ /* Multicast address has no effect in PADDR */ ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Multicast address")); ++ ++ /* Make sure no PADDR contains this address */ ++ for (paddrNum = 0; paddrNum < MEMAC_NUM_OF_PADDRS; paddrNum++) ++ if (p_Memac->indAddrRegUsed[paddrNum]) ++ if (p_Memac->paddr[paddrNum] == ethAddr) ++ RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG); ++ ++ /* Find first unused PADDR */ ++ for (paddrNum = 0; paddrNum < MEMAC_NUM_OF_PADDRS; paddrNum++) ++ if (!(p_Memac->indAddrRegUsed[paddrNum])) ++ { ++ /* mark this PADDR as used */ ++ p_Memac->indAddrRegUsed[paddrNum] = TRUE; ++ /* store address */ ++ p_Memac->paddr[paddrNum] = ethAddr; ++ ++ /* put in hardware */ ++ fman_memac_add_addr_in_paddr(p_Memac->p_MemMap, (uint8_t*)(*p_EthAddr), paddrNum); ++ p_Memac->numOfIndAddrInRegs++; ++ ++ return E_OK; ++ } ++ ++ /* No free PADDR */ ++ RETURN_ERROR(MAJOR, E_FULL, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacDelExactMatchMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr) ++{ ++ t_Memac *p_Memac = (t_Memac *) h_Memac; ++ uint64_t ethAddr; ++ uint8_t paddrNum; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); ++ ++ /* Find used PADDR containing this address */ ++ for (paddrNum = 0; paddrNum < MEMAC_NUM_OF_PADDRS; paddrNum++) ++ { ++ if ((p_Memac->indAddrRegUsed[paddrNum]) && ++ (p_Memac->paddr[paddrNum] == ethAddr)) ++ { ++ /* mark this PADDR as not used */ ++ p_Memac->indAddrRegUsed[paddrNum] = FALSE; ++ /* clear in hardware */ ++ fman_memac_clear_addr_in_paddr(p_Memac->p_MemMap, paddrNum); ++ p_Memac->numOfIndAddrInRegs--; ++ ++ return E_OK; ++ } ++ } ++ ++ RETURN_ERROR(MAJOR, E_NOT_FOUND, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacGetId(t_Handle h_Memac, uint32_t *macId) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ *macId = p_Memac->macId; ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++ ++static t_Error MemacAddHashMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ t_EthHashEntry *p_HashEntry; ++ uint32_t hash; ++ uint64_t ethAddr; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); ++ ++ if (!(ethAddr & GROUP_ADDRESS)) ++ /* Unicast addresses not supported in hash */ ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unicast Address")); ++ ++ hash = GetMacAddrHashCode(ethAddr) & HASH_CTRL_ADDR_MASK; ++ ++ /* Create element to be added to the driver hash table */ ++ p_HashEntry = (t_EthHashEntry *)XX_Malloc(sizeof(t_EthHashEntry)); ++ p_HashEntry->addr = ethAddr; ++ INIT_LIST(&p_HashEntry->node); ++ ++ LIST_AddToTail(&(p_HashEntry->node), &(p_Memac->p_MulticastAddrHash->p_Lsts[hash])); ++ fman_memac_set_hash_table(p_Memac->p_MemMap, (hash | HASH_CTRL_MCAST_EN)); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacDelHashMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ t_EthHashEntry *p_HashEntry = NULL; ++ t_List *p_Pos; ++ uint32_t hash; ++ uint64_t ethAddr; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); ++ ++ hash = GetMacAddrHashCode(ethAddr) & HASH_CTRL_ADDR_MASK; ++ ++ LIST_FOR_EACH(p_Pos, &(p_Memac->p_MulticastAddrHash->p_Lsts[hash])) ++ { ++ p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos); ++ if (p_HashEntry->addr == ethAddr) ++ { ++ LIST_DelAndInit(&p_HashEntry->node); ++ XX_Free(p_HashEntry); ++ break; ++ } ++ } ++ if (LIST_IsEmpty(&p_Memac->p_MulticastAddrHash->p_Lsts[hash])) ++ fman_memac_set_hash_table(p_Memac->p_MemMap, (hash & ~HASH_CTRL_MCAST_EN)); ++ ++ return E_OK; ++} ++ ++ ++/* ......................................................................... */ ++ ++static t_Error MemacSetException(t_Handle h_Memac, e_FmMacExceptions exception, bool enable) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ uint32_t bitMask = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ ++ GET_EXCEPTION_FLAG(bitMask, exception); ++ if (bitMask) ++ { ++ if (enable) ++ p_Memac->exceptions |= bitMask; ++ else ++ p_Memac->exceptions &= ~bitMask; ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); ++ ++ fman_memac_set_exception(p_Memac->p_MemMap, bitMask, enable); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static uint16_t MemacGetMaxFrameLength(t_Handle h_Memac) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_VALUE(p_Memac, E_INVALID_HANDLE, 0); ++ SANITY_CHECK_RETURN_VALUE(!p_Memac->p_MemacDriverParam, E_INVALID_STATE, 0); ++ ++ return fman_memac_get_max_frame_len(p_Memac->p_MemMap); ++} ++ ++static t_Error MemacInitInternalPhy(t_Handle h_Memac) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ uint8_t i, phyAddr; ++ ++ if (ENET_INTERFACE_FROM_MODE(p_Memac->enetMode) == e_ENET_IF_SGMII) ++ { ++ /* Configure internal SGMII PHY */ ++ if (p_Memac->enetMode & ENET_IF_SGMII_BASEX) ++ SetupSgmiiInternalPhyBaseX(p_Memac, PHY_MDIO_ADDR); ++ else ++ SetupSgmiiInternalPhy(p_Memac, PHY_MDIO_ADDR); ++ } ++ else if (ENET_INTERFACE_FROM_MODE(p_Memac->enetMode) == e_ENET_IF_QSGMII) ++ { ++ /* Configure 4 internal SGMII PHYs */ ++ for (i = 0; i < 4; i++) ++ { ++ /* QSGMII PHY address occupies 3 upper bits of 5-bit ++ phyAddress; the lower 2 bits are used to extend ++ register address space and access each one of 4 ++ ports inside QSGMII. */ ++ phyAddr = (uint8_t)((PHY_MDIO_ADDR << 2) | i); ++ if (p_Memac->enetMode & ENET_IF_SGMII_BASEX) ++ SetupSgmiiInternalPhyBaseX(p_Memac, phyAddr); ++ else ++ SetupSgmiiInternalPhy(p_Memac, phyAddr); ++ } ++ } ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++/* mEMAC Init & Free API */ ++/*****************************************************************************/ ++ ++/* ......................................................................... */ ++void *g_MemacRegs; ++static t_Error MemacInit(t_Handle h_Memac) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ struct memac_cfg *p_MemacDriverParam; ++ enum enet_interface enet_interface; ++ enum enet_speed enet_speed; ++ t_EnetAddr ethAddr; ++ e_FmMacType portType; ++ t_Error err; ++ bool slow_10g_if = FALSE; ++ if (p_Memac->macId == 3) /* This is a quick WA */ ++ g_MemacRegs = p_Memac->p_MemMap; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_Memac->fmMacControllerDriver.h_Fm, E_INVALID_HANDLE); ++ ++ FM_GetRevision(p_Memac->fmMacControllerDriver.h_Fm, &p_Memac->fmMacControllerDriver.fmRevInfo); ++ if (p_Memac->fmMacControllerDriver.fmRevInfo.majorRev == 6 && ++ p_Memac->fmMacControllerDriver.fmRevInfo.minorRev == 4) ++ slow_10g_if = TRUE; ++ ++ CHECK_INIT_PARAMETERS(p_Memac, CheckInitParameters); ++ ++ p_MemacDriverParam = p_Memac->p_MemacDriverParam; ++ ++ portType = ++ ((ENET_SPEED_FROM_MODE(p_Memac->enetMode) < e_ENET_SPEED_10000) ? e_FM_MAC_1G : e_FM_MAC_10G); ++ ++ /* First, reset the MAC if desired. */ ++ if (p_MemacDriverParam->reset_on_init) ++ fman_memac_reset(p_Memac->p_MemMap); ++ ++ /* MAC Address */ ++ MAKE_ENET_ADDR_FROM_UINT64(p_Memac->addr, ethAddr); ++ fman_memac_add_addr_in_paddr(p_Memac->p_MemMap, (uint8_t*)ethAddr, 0); ++ ++ enet_interface = (enum enet_interface) ENET_INTERFACE_FROM_MODE(p_Memac->enetMode); ++ enet_speed = (enum enet_speed) ENET_SPEED_FROM_MODE(p_Memac->enetMode); ++ ++ fman_memac_init(p_Memac->p_MemMap, ++ p_Memac->p_MemacDriverParam, ++ enet_interface, ++ enet_speed, ++ slow_10g_if, ++ p_Memac->exceptions); ++ ++#ifdef FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320 ++ { ++ uint32_t tmpReg = 0; ++ ++ FM_GetRevision(p_Memac->fmMacControllerDriver.h_Fm, &p_Memac->fmMacControllerDriver.fmRevInfo); ++ /* check the FMAN version - the bug exists only in rev1 */ ++ if ((p_Memac->fmMacControllerDriver.fmRevInfo.majorRev == 6) && ++ (p_Memac->fmMacControllerDriver.fmRevInfo.minorRev == 0)) ++ { ++ /* MAC strips CRC from received frames - this workaround should ++ decrease the likelihood of bug appearance ++ */ ++ tmpReg = GET_UINT32(p_Memac->p_MemMap->command_config); ++ tmpReg &= ~CMD_CFG_CRC_FWD; ++ WRITE_UINT32(p_Memac->p_MemMap->command_config, tmpReg); ++ /* DBG(WARNING, ("mEMAC strips CRC from received frames as part of A006320 errata workaround"));*/ ++ } ++ } ++#endif /* FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320 */ ++ ++ MemacInitInternalPhy(h_Memac); ++ ++ /* Max Frame Length */ ++ err = FmSetMacMaxFrame(p_Memac->fmMacControllerDriver.h_Fm, ++ portType, ++ p_Memac->fmMacControllerDriver.macId, ++ p_MemacDriverParam->max_frame_length); ++ if (err) ++ RETURN_ERROR(MAJOR, err, ("settings Mac max frame length is FAILED")); ++ ++ p_Memac->p_MulticastAddrHash = AllocHashTable(HASH_TABLE_SIZE); ++ if (!p_Memac->p_MulticastAddrHash) ++ { ++ FreeInitResources(p_Memac); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED")); ++ } ++ ++ p_Memac->p_UnicastAddrHash = AllocHashTable(HASH_TABLE_SIZE); ++ if (!p_Memac->p_UnicastAddrHash) ++ { ++ FreeInitResources(p_Memac); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED")); ++ } ++ ++ FmRegisterIntr(p_Memac->fmMacControllerDriver.h_Fm, ++ (portType == e_FM_MAC_10G) ? e_FM_MOD_10G_MAC : e_FM_MOD_1G_MAC, ++ p_Memac->macId, ++ e_FM_INTR_TYPE_ERR, ++ MemacErrException, ++ p_Memac); ++ ++ FmRegisterIntr(p_Memac->fmMacControllerDriver.h_Fm, ++ (portType == e_FM_MAC_10G) ? e_FM_MOD_10G_MAC : e_FM_MOD_1G_MAC, ++ p_Memac->macId, ++ e_FM_INTR_TYPE_NORMAL, ++ MemacException, ++ p_Memac); ++ ++ XX_Free(p_MemacDriverParam); ++ p_Memac->p_MemacDriverParam = NULL; ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error MemacFree(t_Handle h_Memac) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ ++ if (p_Memac->p_MemacDriverParam) ++ { ++ /* Called after config */ ++ XX_Free(p_Memac->p_MemacDriverParam); ++ p_Memac->p_MemacDriverParam = NULL; ++ } ++ else ++ /* Called after init */ ++ FreeInitResources(p_Memac); ++ ++ XX_Free(p_Memac); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static void InitFmMacControllerDriver(t_FmMacControllerDriver *p_FmMacControllerDriver) ++{ ++ p_FmMacControllerDriver->f_FM_MAC_Init = MemacInit; ++ p_FmMacControllerDriver->f_FM_MAC_Free = MemacFree; ++ ++ p_FmMacControllerDriver->f_FM_MAC_SetStatistics = NULL; ++ p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback = MemacConfigLoopback; ++ p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength = MemacConfigMaxFrameLength; ++ ++ p_FmMacControllerDriver->f_FM_MAC_ConfigWan = MemacConfigWan; ++ ++ p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc = MemacConfigPad; ++ p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex = NULL; /* half-duplex is detected automatically */ ++ p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck = MemacConfigLengthCheck; ++ ++ p_FmMacControllerDriver->f_FM_MAC_ConfigException = MemacConfigException; ++ p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit = MemacConfigResetOnInit; ++ ++ p_FmMacControllerDriver->f_FM_MAC_SetException = MemacSetException; ++ ++ p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp = MemacEnable1588TimeStamp; /* always enabled */ ++ p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp = NULL; ++ ++ p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous = MemacSetPromiscuous; ++ p_FmMacControllerDriver->f_FM_MAC_AdjustLink = MemacAdjustLink; ++ p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg = NULL; ++ ++ p_FmMacControllerDriver->f_FM_MAC_Enable = MemacEnable; ++ p_FmMacControllerDriver->f_FM_MAC_Disable = MemacDisable; ++ p_FmMacControllerDriver->f_FM_MAC_Resume = MemacInitInternalPhy; ++ ++ p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames = MemacSetTxAutoPauseFrames; ++ p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames = MemacSetTxPauseFrames; ++ p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames = MemacSetRxIgnorePauseFrames; ++ ++ p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan = MemacSetWakeOnLan; ++ ++ p_FmMacControllerDriver->f_FM_MAC_ResetCounters = MemacResetCounters; ++ p_FmMacControllerDriver->f_FM_MAC_GetStatistics = MemacGetStatistics; ++ ++ p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr = MemacModifyMacAddress; ++ p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr = MemacAddHashMacAddress; ++ p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr = MemacDelHashMacAddress; ++ p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr = MemacAddExactMatchMacAddress; ++ p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr = MemacDelExactMatchMacAddress; ++ p_FmMacControllerDriver->f_FM_MAC_GetId = MemacGetId; ++ p_FmMacControllerDriver->f_FM_MAC_GetVersion = NULL; ++ p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength = MemacGetMaxFrameLength; ++ ++ p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg = MEMAC_MII_WritePhyReg; ++ p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg = MEMAC_MII_ReadPhyReg; ++} ++ ++ ++/*****************************************************************************/ ++/* mEMAC Config Main Entry */ ++/*****************************************************************************/ ++ ++/* ......................................................................... */ ++ ++t_Handle MEMAC_Config(t_FmMacParams *p_FmMacParam) ++{ ++ t_Memac *p_Memac; ++ struct memac_cfg *p_MemacDriverParam; ++ uintptr_t baseAddr; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_NULL_POINTER, NULL); ++ ++ baseAddr = p_FmMacParam->baseAddr; ++ /* Allocate memory for the mEMAC data structure */ ++ p_Memac = (t_Memac *)XX_Malloc(sizeof(t_Memac)); ++ if (!p_Memac) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("mEMAC driver structure")); ++ return NULL; ++ } ++ memset(p_Memac, 0, sizeof(t_Memac)); ++ InitFmMacControllerDriver(&p_Memac->fmMacControllerDriver); ++ ++ /* Allocate memory for the mEMAC driver parameters data structure */ ++ p_MemacDriverParam = (struct memac_cfg *)XX_Malloc(sizeof(struct memac_cfg)); ++ if (!p_MemacDriverParam) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("mEMAC driver parameters")); ++ XX_Free(p_Memac); ++ return NULL; ++ } ++ memset(p_MemacDriverParam, 0, sizeof(struct memac_cfg)); ++ ++ /* Plant parameter structure pointer */ ++ p_Memac->p_MemacDriverParam = p_MemacDriverParam; ++ ++ fman_memac_defconfig(p_MemacDriverParam); ++ ++ p_Memac->addr = ENET_ADDR_TO_UINT64(p_FmMacParam->addr); ++ ++ p_Memac->p_MemMap = (struct memac_regs *)UINT_TO_PTR(baseAddr); ++ p_Memac->p_MiiMemMap = (struct memac_mii_access_mem_map*)UINT_TO_PTR(baseAddr + MEMAC_TO_MII_OFFSET); ++ ++ p_Memac->enetMode = p_FmMacParam->enetMode; ++ p_Memac->macId = p_FmMacParam->macId; ++ p_Memac->exceptions = MEMAC_default_exceptions; ++ p_Memac->f_Exception = p_FmMacParam->f_Exception; ++ p_Memac->f_Event = p_FmMacParam->f_Event; ++ p_Memac->h_App = p_FmMacParam->h_App; ++ ++ return p_Memac; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.h +new file mode 100644 +index 00000000..2fd89dae +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.h +@@ -0,0 +1,110 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File memac.h ++ ++ @Description FM Multirate Ethernet MAC (mEMAC) ++*//***************************************************************************/ ++#ifndef __MEMAC_H ++#define __MEMAC_H ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "list_ext.h" ++ ++#include "fsl_fman_memac_mii_acc.h" ++#include "fm_mac.h" ++#include "fsl_fman_memac.h" ++ ++ ++#define MEMAC_default_exceptions \ ++ ((uint32_t)(MEMAC_IMASK_TSECC_ER | MEMAC_IMASK_TECC_ER | MEMAC_IMASK_RECC_ER | MEMAC_IMASK_MGI)) ++ ++#define GET_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \ ++ case e_FM_MAC_EX_10G_1TX_ECC_ER: \ ++ bitMask = MEMAC_IMASK_TECC_ER; break; \ ++ case e_FM_MAC_EX_10G_RX_ECC_ER: \ ++ bitMask = MEMAC_IMASK_RECC_ER; break; \ ++ case e_FM_MAC_EX_TS_FIFO_ECC_ERR: \ ++ bitMask = MEMAC_IMASK_TSECC_ER; break; \ ++ case e_FM_MAC_EX_MAGIC_PACKET_INDICATION: \ ++ bitMask = MEMAC_IMASK_MGI; break; \ ++ default: bitMask = 0;break;} ++ ++ ++typedef struct ++{ ++ t_FmMacControllerDriver fmMacControllerDriver; /**< Upper Mac control block */ ++ t_Handle h_App; /**< Handle to the upper layer application */ ++ struct memac_regs *p_MemMap; /**< Pointer to MAC memory mapped registers */ ++ struct memac_mii_access_mem_map *p_MiiMemMap; /**< Pointer to MII memory mapped registers */ ++ uint64_t addr; /**< MAC address of device */ ++ e_EnetMode enetMode; /**< Ethernet physical interface */ ++ t_FmMacExceptionCallback *f_Exception; ++ int mdioIrq; ++ t_FmMacExceptionCallback *f_Event; ++ bool indAddrRegUsed[MEMAC_NUM_OF_PADDRS]; /**< Whether a particular individual address recognition register is being used */ ++ uint64_t paddr[MEMAC_NUM_OF_PADDRS]; /**< MAC address for particular individual address recognition register */ ++ uint8_t numOfIndAddrInRegs; /**< Number of individual addresses in registers for this station. */ ++ t_EthHash *p_MulticastAddrHash; /**< Pointer to driver's global address hash table */ ++ t_EthHash *p_UnicastAddrHash; /**< Pointer to driver's individual address hash table */ ++ bool debugMode; ++ uint8_t macId; ++ uint32_t exceptions; ++ struct memac_cfg *p_MemacDriverParam; ++} t_Memac; ++ ++ ++/* Internal PHY access */ ++#define PHY_MDIO_ADDR 0 ++ ++/* Internal PHY Registers - SGMII */ ++#define PHY_SGMII_CR_PHY_RESET 0x8000 ++#define PHY_SGMII_CR_RESET_AN 0x0200 ++#define PHY_SGMII_CR_DEF_VAL 0x1140 ++#define PHY_SGMII_DEV_ABILITY_SGMII 0x4001 ++#define PHY_SGMII_DEV_ABILITY_1000X 0x01A0 ++#define PHY_SGMII_IF_SPEED_GIGABIT 0x0008 ++#define PHY_SGMII_IF_MODE_AN 0x0002 ++#define PHY_SGMII_IF_MODE_SGMII 0x0001 ++#define PHY_SGMII_IF_MODE_1000X 0x0000 ++ ++ ++#define MEMAC_TO_MII_OFFSET 0x030 /* Offset from the MEM map to the MDIO mem map */ ++ ++t_Error MEMAC_MII_WritePhyReg(t_Handle h_Memac, uint8_t phyAddr, uint8_t reg, uint16_t data); ++t_Error MEMAC_MII_ReadPhyReg(t_Handle h_Memac, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data); ++ ++ ++#endif /* __MEMAC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.c +new file mode 100644 +index 00000000..56eaffbc +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.c +@@ -0,0 +1,78 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#include "error_ext.h" ++#include "std_ext.h" ++#include "fm_mac.h" ++#include "memac.h" ++#include "xx_ext.h" ++ ++#include "fm_common.h" ++#include "memac_mii_acc.h" ++ ++ ++/*****************************************************************************/ ++t_Error MEMAC_MII_WritePhyReg(t_Handle h_Memac, ++ uint8_t phyAddr, ++ uint8_t reg, ++ uint16_t data) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MiiMemMap, E_INVALID_HANDLE); ++ ++ return (t_Error)fman_memac_mii_write_phy_reg(p_Memac->p_MiiMemMap, ++ phyAddr, ++ reg, ++ data, ++ (enum enet_speed)ENET_SPEED_FROM_MODE(p_Memac->enetMode)); ++} ++ ++/*****************************************************************************/ ++t_Error MEMAC_MII_ReadPhyReg(t_Handle h_Memac, ++ uint8_t phyAddr, ++ uint8_t reg, ++ uint16_t *p_Data) ++{ ++ t_Memac *p_Memac = (t_Memac *)h_Memac; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Memac->p_MiiMemMap, E_INVALID_HANDLE); ++ ++ return fman_memac_mii_read_phy_reg(p_Memac->p_MiiMemMap, ++ phyAddr, ++ reg, ++ p_Data, ++ (enum enet_speed)ENET_SPEED_FROM_MODE(p_Memac->enetMode)); ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.h +new file mode 100644 +index 00000000..325ec082 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.h +@@ -0,0 +1,73 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#ifndef __MEMAC_MII_ACC_H ++#define __MEMAC_MII_ACC_H ++ ++#include "std_ext.h" ++ ++ ++/* MII Management Registers */ ++#define MDIO_CFG_CLK_DIV_MASK 0x0080ff80 ++#define MDIO_CFG_CLK_DIV_SHIFT 7 ++#define MDIO_CFG_HOLD_MASK 0x0000001c ++#define MDIO_CFG_ENC45 0x00000040 ++#define MDIO_CFG_READ_ERR 0x00000002 ++#define MDIO_CFG_BSY 0x00000001 ++ ++#define MDIO_CTL_PHY_ADDR_SHIFT 5 ++#define MDIO_CTL_READ 0x00008000 ++ ++#define MDIO_DATA_BSY 0x80000000 ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(push,1) ++#endif /* defined(__MWERKS__) && ... */ ++ ++/*----------------------------------------------------*/ ++/* MII Configuration Control Memory Map Registers */ ++/*----------------------------------------------------*/ ++typedef struct t_MemacMiiAccessMemMap ++{ ++ volatile uint32_t mdio_cfg; /* 0x030 */ ++ volatile uint32_t mdio_ctrl; /* 0x034 */ ++ volatile uint32_t mdio_data; /* 0x038 */ ++ volatile uint32_t mdio_addr; /* 0x03c */ ++} t_MemacMiiAccessMemMap ; ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(pop) ++#endif /* defined(__MWERKS__) && ... */ ++ ++ ++#endif /* __MEMAC_MII_ACC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.c +new file mode 100644 +index 00000000..9b136a69 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.c +@@ -0,0 +1,975 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File tgec.c ++ ++ @Description FM 10G MAC ... ++*//***************************************************************************/ ++ ++#include "std_ext.h" ++#include "string_ext.h" ++#include "error_ext.h" ++#include "xx_ext.h" ++#include "endian_ext.h" ++#include "debug_ext.h" ++#include "crc_mac_addr_ext.h" ++ ++#include "fm_common.h" ++#include "fsl_fman_tgec.h" ++#include "tgec.h" ++ ++ ++/*****************************************************************************/ ++/* Internal routines */ ++/*****************************************************************************/ ++ ++static t_Error CheckInitParameters(t_Tgec *p_Tgec) ++{ ++ if (ENET_SPEED_FROM_MODE(p_Tgec->enetMode) < e_ENET_SPEED_10000) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 10G MAC driver only support 10G speed")); ++#if (FM_MAX_NUM_OF_10G_MACS > 0) ++ if (p_Tgec->macId >= FM_MAX_NUM_OF_10G_MACS) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("macId of 10G can not be greater than 0")); ++#endif /* (FM_MAX_NUM_OF_10G_MACS > 0) */ ++ ++ if (p_Tgec->addr == 0) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 10G MAC Must have a valid MAC Address")); ++ if (!p_Tgec->f_Exception) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("uninitialized f_Exception")); ++ if (!p_Tgec->f_Event) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("uninitialized f_Event")); ++#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002 ++ if (!p_Tgec->p_TgecDriverParam->no_length_check_enable) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("LengthCheck!")); ++#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static uint32_t GetMacAddrHashCode(uint64_t ethAddr) ++{ ++ uint32_t crc; ++ ++ /* CRC calculation */ ++ GET_MAC_ADDR_CRC(ethAddr, crc); ++ ++ crc = GetMirror32(crc); ++ ++ return crc; ++} ++ ++/* ......................................................................... */ ++ ++static void TgecErrException(t_Handle h_Tgec) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ uint32_t event; ++ struct tgec_regs *p_TgecMemMap = p_Tgec->p_MemMap; ++ ++ /* do not handle MDIO events */ ++ event = fman_tgec_get_event(p_TgecMemMap, ~(TGEC_IMASK_MDIO_SCAN_EVENT | TGEC_IMASK_MDIO_CMD_CMPL)); ++ event &= fman_tgec_get_interrupt_mask(p_TgecMemMap); ++ ++ fman_tgec_ack_event(p_TgecMemMap, event); ++ ++ if (event & TGEC_IMASK_REM_FAULT) ++ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_REM_FAULT); ++ if (event & TGEC_IMASK_LOC_FAULT) ++ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_LOC_FAULT); ++ if (event & TGEC_IMASK_TX_ECC_ER) ++ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_1TX_ECC_ER); ++ if (event & TGEC_IMASK_TX_FIFO_UNFL) ++ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_FIFO_UNFL); ++ if (event & TGEC_IMASK_TX_FIFO_OVFL) ++ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_FIFO_OVFL); ++ if (event & TGEC_IMASK_TX_ER) ++ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_ER); ++ if (event & TGEC_IMASK_RX_FIFO_OVFL) ++ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_FIFO_OVFL); ++ if (event & TGEC_IMASK_RX_ECC_ER) ++ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_ECC_ER); ++ if (event & TGEC_IMASK_RX_JAB_FRM) ++ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_JAB_FRM); ++ if (event & TGEC_IMASK_RX_OVRSZ_FRM) ++ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_OVRSZ_FRM); ++ if (event & TGEC_IMASK_RX_RUNT_FRM) ++ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_RUNT_FRM); ++ if (event & TGEC_IMASK_RX_FRAG_FRM) ++ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_FRAG_FRM); ++ if (event & TGEC_IMASK_RX_LEN_ER) ++ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_LEN_ER); ++ if (event & TGEC_IMASK_RX_CRC_ER) ++ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_CRC_ER); ++ if (event & TGEC_IMASK_RX_ALIGN_ER) ++ p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_ALIGN_ER); ++} ++ ++/* ......................................................................... */ ++ ++static void TgecException(t_Handle h_Tgec) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ uint32_t event; ++ struct tgec_regs *p_TgecMemMap = p_Tgec->p_MemMap; ++ ++ /* handle only MDIO events */ ++ event = fman_tgec_get_event(p_TgecMemMap, (TGEC_IMASK_MDIO_SCAN_EVENT | TGEC_IMASK_MDIO_CMD_CMPL)); ++ event &= fman_tgec_get_interrupt_mask(p_TgecMemMap); ++ ++ fman_tgec_ack_event(p_TgecMemMap, event); ++ ++ if (event & TGEC_IMASK_MDIO_SCAN_EVENT) ++ p_Tgec->f_Event(p_Tgec->h_App, e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO); ++ if (event & TGEC_IMASK_MDIO_CMD_CMPL) ++ p_Tgec->f_Event(p_Tgec->h_App, e_FM_MAC_EX_10G_MDIO_CMD_CMPL); ++} ++ ++/* ......................................................................... */ ++ ++static void FreeInitResources(t_Tgec *p_Tgec) ++{ ++ if (p_Tgec->mdioIrq != NO_IRQ) ++ { ++ XX_DisableIntr(p_Tgec->mdioIrq); ++ XX_FreeIntr(p_Tgec->mdioIrq); ++ } ++ ++ FmUnregisterIntr(p_Tgec->fmMacControllerDriver.h_Fm, e_FM_MOD_10G_MAC, p_Tgec->macId, e_FM_INTR_TYPE_ERR); ++ ++ /* release the driver's group hash table */ ++ FreeHashTable(p_Tgec->p_MulticastAddrHash); ++ p_Tgec->p_MulticastAddrHash = NULL; ++ ++ /* release the driver's individual hash table */ ++ FreeHashTable(p_Tgec->p_UnicastAddrHash); ++ p_Tgec->p_UnicastAddrHash = NULL; ++} ++ ++ ++/*****************************************************************************/ ++/* 10G MAC API routines */ ++/*****************************************************************************/ ++ ++/* ......................................................................... */ ++ ++static t_Error TgecEnable(t_Handle h_Tgec, e_CommMode mode) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ fman_tgec_enable(p_Tgec->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX)); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecDisable (t_Handle h_Tgec, e_CommMode mode) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ fman_tgec_disable(p_Tgec->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX)); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecSetPromiscuous(t_Handle h_Tgec, bool newVal) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ fman_tgec_set_promiscuous(p_Tgec->p_MemMap, newVal); ++ ++ return E_OK; ++} ++ ++ ++/*****************************************************************************/ ++/* Tgec Configs modification functions */ ++/*****************************************************************************/ ++ ++/* ......................................................................... */ ++ ++static t_Error TgecConfigLoopback(t_Handle h_Tgec, bool newVal) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ p_Tgec->p_TgecDriverParam->loopback_enable = newVal; ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecConfigWan(t_Handle h_Tgec, bool newVal) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ p_Tgec->p_TgecDriverParam->wan_mode_enable = newVal; ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecConfigMaxFrameLength(t_Handle h_Tgec, uint16_t newVal) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ p_Tgec->p_TgecDriverParam->max_frame_length = newVal; ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecConfigLengthCheck(t_Handle h_Tgec, bool newVal) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ UNUSED(newVal); ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ p_Tgec->p_TgecDriverParam->no_length_check_enable = !newVal; ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecConfigException(t_Handle h_Tgec, e_FmMacExceptions exception, bool enable) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ uint32_t bitMask = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ GET_EXCEPTION_FLAG(bitMask, exception); ++ if (bitMask) ++ { ++ if (enable) ++ p_Tgec->exceptions |= bitMask; ++ else ++ p_Tgec->exceptions &= ~bitMask; ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); ++ ++ return E_OK; ++} ++ ++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 ++/* ......................................................................... */ ++ ++static t_Error TgecConfigSkipFman11Workaround(t_Handle h_Tgec) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ p_Tgec->p_TgecDriverParam->skip_fman11_workaround = TRUE; ++ ++ return E_OK; ++} ++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ ++ ++ ++/*****************************************************************************/ ++/* Tgec Run Time API functions */ ++/*****************************************************************************/ ++ ++/* ......................................................................... */ ++/* backward compatibility. will be removed in the future. */ ++static t_Error TgecTxMacPause(t_Handle h_Tgec, uint16_t pauseTime) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ fman_tgec_set_tx_pause_frames(p_Tgec->p_MemMap, pauseTime); ++ ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecSetTxPauseFrames(t_Handle h_Tgec, ++ uint8_t priority, ++ uint16_t pauseTime, ++ uint16_t threshTime) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ UNUSED(priority); UNUSED(threshTime); ++ ++ fman_tgec_set_tx_pause_frames(p_Tgec->p_MemMap, pauseTime); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecRxIgnoreMacPause(t_Handle h_Tgec, bool en) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ fman_tgec_set_rx_ignore_pause_frames(p_Tgec->p_MemMap, en); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecGetStatistics(t_Handle h_Tgec, t_FmMacStatistics *p_Statistics) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ struct tgec_regs *p_TgecMemMap; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_Statistics, E_NULL_POINTER); ++ ++ p_TgecMemMap = p_Tgec->p_MemMap; ++ ++ p_Statistics->eStatPkts64 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R64); ++ p_Statistics->eStatPkts65to127 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R127); ++ p_Statistics->eStatPkts128to255 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R255); ++ p_Statistics->eStatPkts256to511 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R511); ++ p_Statistics->eStatPkts512to1023 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1023); ++ p_Statistics->eStatPkts1024to1518 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1518); ++ p_Statistics->eStatPkts1519to1522 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1519X); ++/* */ ++ p_Statistics->eStatFragments = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TRFRG); ++ p_Statistics->eStatJabbers = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TRJBR); ++ ++ p_Statistics->eStatsDropEvents = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RDRP); ++ p_Statistics->eStatCRCAlignErrors = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RALN); ++ ++ p_Statistics->eStatUndersizePkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TRUND); ++ p_Statistics->eStatOversizePkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TROVR); ++/* Pause */ ++ p_Statistics->reStatPause = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RXPF); ++ p_Statistics->teStatPause = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TXPF); ++ ++/* MIB II */ ++ p_Statistics->ifInOctets = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_ROCT); ++ p_Statistics->ifInUcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RUCA); ++ p_Statistics->ifInMcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RMCA); ++ p_Statistics->ifInBcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RBCA); ++ p_Statistics->ifInPkts = p_Statistics->ifInUcastPkts ++ + p_Statistics->ifInMcastPkts ++ + p_Statistics->ifInBcastPkts; ++ p_Statistics->ifInDiscards = 0; ++ p_Statistics->ifInErrors = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RERR); ++ ++ p_Statistics->ifOutOctets = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TOCT); ++ p_Statistics->ifOutUcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TUCA); ++ p_Statistics->ifOutMcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TMCA); ++ p_Statistics->ifOutBcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TBCA); ++ p_Statistics->ifOutPkts = p_Statistics->ifOutUcastPkts ++ + p_Statistics->ifOutMcastPkts ++ + p_Statistics->ifOutBcastPkts; ++ p_Statistics->ifOutDiscards = 0; ++ p_Statistics->ifOutErrors = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TERR); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecEnable1588TimeStamp(t_Handle h_Tgec) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ fman_tgec_enable_1588_time_stamp(p_Tgec->p_MemMap, 1); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecDisable1588TimeStamp(t_Handle h_Tgec) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ fman_tgec_enable_1588_time_stamp(p_Tgec->p_MemMap, 0); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecModifyMacAddress (t_Handle h_Tgec, t_EnetAddr *p_EnetAddr) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ p_Tgec->addr = ENET_ADDR_TO_UINT64(*p_EnetAddr); ++ fman_tgec_set_mac_address(p_Tgec->p_MemMap, (uint8_t *)(*p_EnetAddr)); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecResetCounters (t_Handle h_Tgec) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ fman_tgec_reset_stat(p_Tgec->p_MemMap); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecAddExactMatchMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *) h_Tgec; ++ uint64_t ethAddr; ++ uint8_t paddrNum; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); ++ ++ if (ethAddr & GROUP_ADDRESS) ++ /* Multicast address has no effect in PADDR */ ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Multicast address")); ++ ++ /* Make sure no PADDR contains this address */ ++ for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++) ++ if (p_Tgec->indAddrRegUsed[paddrNum]) ++ if (p_Tgec->paddr[paddrNum] == ethAddr) ++ RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG); ++ ++ /* Find first unused PADDR */ ++ for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++) ++ { ++ if (!(p_Tgec->indAddrRegUsed[paddrNum])) ++ { ++ /* mark this PADDR as used */ ++ p_Tgec->indAddrRegUsed[paddrNum] = TRUE; ++ /* store address */ ++ p_Tgec->paddr[paddrNum] = ethAddr; ++ ++ /* put in hardware */ ++ fman_tgec_add_addr_in_paddr(p_Tgec->p_MemMap, (uint8_t*)(*p_EthAddr)/* , paddrNum */); ++ p_Tgec->numOfIndAddrInRegs++; ++ ++ return E_OK; ++ } ++ } ++ ++ /* No free PADDR */ ++ RETURN_ERROR(MAJOR, E_FULL, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecDelExactMatchMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *) h_Tgec; ++ uint64_t ethAddr; ++ uint8_t paddrNum; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); ++ ++ /* Find used PADDR containing this address */ ++ for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++) ++ { ++ if ((p_Tgec->indAddrRegUsed[paddrNum]) && ++ (p_Tgec->paddr[paddrNum] == ethAddr)) ++ { ++ /* mark this PADDR as not used */ ++ p_Tgec->indAddrRegUsed[paddrNum] = FALSE; ++ /* clear in hardware */ ++ fman_tgec_clear_addr_in_paddr(p_Tgec->p_MemMap /*, paddrNum */); ++ p_Tgec->numOfIndAddrInRegs--; ++ ++ return E_OK; ++ } ++ } ++ ++ RETURN_ERROR(MAJOR, E_NOT_FOUND, NO_MSG); ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecAddHashMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ t_EthHashEntry *p_HashEntry; ++ uint32_t crc; ++ uint32_t hash; ++ uint64_t ethAddr; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); ++ ++ if (!(ethAddr & GROUP_ADDRESS)) ++ /* Unicast addresses not supported in hash */ ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unicast Address")); ++ ++ /* CRC calculation */ ++ crc = GetMacAddrHashCode(ethAddr); ++ ++ hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK; /* Take 9 MSB bits */ ++ ++ /* Create element to be added to the driver hash table */ ++ p_HashEntry = (t_EthHashEntry *)XX_Malloc(sizeof(t_EthHashEntry)); ++ p_HashEntry->addr = ethAddr; ++ INIT_LIST(&p_HashEntry->node); ++ ++ LIST_AddToTail(&(p_HashEntry->node), &(p_Tgec->p_MulticastAddrHash->p_Lsts[hash])); ++ fman_tgec_set_hash_table(p_Tgec->p_MemMap, (hash | TGEC_HASH_MCAST_EN)); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecDelHashMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ t_EthHashEntry *p_HashEntry = NULL; ++ t_List *p_Pos; ++ uint32_t crc; ++ uint32_t hash; ++ uint64_t ethAddr; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ ethAddr = ((*(uint64_t *)p_EthAddr) >> 16); ++ ++ /* CRC calculation */ ++ crc = GetMacAddrHashCode(ethAddr); ++ ++ hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK; /* Take 9 MSB bits */ ++ ++ LIST_FOR_EACH(p_Pos, &(p_Tgec->p_MulticastAddrHash->p_Lsts[hash])) ++ { ++ p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos); ++ if (p_HashEntry->addr == ethAddr) ++ { ++ LIST_DelAndInit(&p_HashEntry->node); ++ XX_Free(p_HashEntry); ++ break; ++ } ++ } ++ if (LIST_IsEmpty(&p_Tgec->p_MulticastAddrHash->p_Lsts[hash])) ++ fman_tgec_set_hash_table(p_Tgec->p_MemMap, (hash & ~TGEC_HASH_MCAST_EN)); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecGetId(t_Handle h_Tgec, uint32_t *macId) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ UNUSED(p_Tgec); ++ UNUSED(macId); ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("TgecGetId Not Supported")); ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecGetVersion(t_Handle h_Tgec, uint32_t *macVersion) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ *macVersion = fman_tgec_get_revision(p_Tgec->p_MemMap); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecSetExcpetion(t_Handle h_Tgec, e_FmMacExceptions exception, bool enable) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ uint32_t bitMask = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ ++ GET_EXCEPTION_FLAG(bitMask, exception); ++ if (bitMask) ++ { ++ if (enable) ++ p_Tgec->exceptions |= bitMask; ++ else ++ p_Tgec->exceptions &= ~bitMask; ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); ++ ++ if (enable) ++ fman_tgec_enable_interrupt(p_Tgec->p_MemMap, bitMask); ++ else ++ fman_tgec_disable_interrupt(p_Tgec->p_MemMap, bitMask); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static uint16_t TgecGetMaxFrameLength(t_Handle h_Tgec) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_VALUE(p_Tgec, E_INVALID_HANDLE, 0); ++ SANITY_CHECK_RETURN_VALUE(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE, 0); ++ ++ return fman_tgec_get_max_frame_len(p_Tgec->p_MemMap); ++} ++ ++/* ......................................................................... */ ++ ++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 ++static t_Error TgecTxEccWorkaround(t_Tgec *p_Tgec) ++{ ++ t_Error err; ++ ++#if defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0) ++ XX_Print("Applying 10G TX ECC workaround (10GMAC-A004) ... "); ++#endif /* (DEBUG_ERRORS > 0) */ ++ /* enable and set promiscuous */ ++ fman_tgec_enable(p_Tgec->p_MemMap, TRUE, TRUE); ++ fman_tgec_set_promiscuous(p_Tgec->p_MemMap, TRUE); ++ err = Fm10GTxEccWorkaround(p_Tgec->fmMacControllerDriver.h_Fm, p_Tgec->macId); ++ /* disable */ ++ fman_tgec_set_promiscuous(p_Tgec->p_MemMap, FALSE); ++ fman_tgec_enable(p_Tgec->p_MemMap, FALSE, FALSE); ++ fman_tgec_reset_stat(p_Tgec->p_MemMap); ++ fman_tgec_ack_event(p_Tgec->p_MemMap, 0xffffffff); ++#if defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0) ++ if (err) ++ XX_Print("FAILED!\n"); ++ else ++ XX_Print("done.\n"); ++#endif /* (DEBUG_ERRORS > 0) */ ++ ++ return err; ++} ++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ ++ ++/*****************************************************************************/ ++/* FM Init & Free API */ ++/*****************************************************************************/ ++ ++/* ......................................................................... */ ++ ++static t_Error TgecInit(t_Handle h_Tgec) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ struct tgec_cfg *p_TgecDriverParam; ++ t_EnetAddr ethAddr; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_Tgec->fmMacControllerDriver.h_Fm, E_INVALID_HANDLE); ++ ++ FM_GetRevision(p_Tgec->fmMacControllerDriver.h_Fm, &p_Tgec->fmMacControllerDriver.fmRevInfo); ++ CHECK_INIT_PARAMETERS(p_Tgec, CheckInitParameters); ++ ++ p_TgecDriverParam = p_Tgec->p_TgecDriverParam; ++ ++ MAKE_ENET_ADDR_FROM_UINT64(p_Tgec->addr, ethAddr); ++ fman_tgec_set_mac_address(p_Tgec->p_MemMap, (uint8_t *)ethAddr); ++ ++ /* interrupts */ ++#ifdef FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005 ++ { ++ if (p_Tgec->fmMacControllerDriver.fmRevInfo.majorRev <=2) ++ p_Tgec->exceptions &= ~(TGEC_IMASK_REM_FAULT | TGEC_IMASK_LOC_FAULT); ++ } ++#endif /* FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005 */ ++ ++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 ++ if (!p_Tgec->p_TgecDriverParam->skip_fman11_workaround && ++ ((err = TgecTxEccWorkaround(p_Tgec)) != E_OK)) ++ { ++ FreeInitResources(p_Tgec); ++ REPORT_ERROR(MINOR, err, ("TgecTxEccWorkaround FAILED")); ++ } ++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ ++ ++ err = fman_tgec_init(p_Tgec->p_MemMap, p_TgecDriverParam, p_Tgec->exceptions); ++ if (err) ++ { ++ FreeInitResources(p_Tgec); ++ RETURN_ERROR(MAJOR, err, ("This TGEC version does not support the required i/f mode")); ++ } ++ ++ /* Max Frame Length */ ++ err = FmSetMacMaxFrame(p_Tgec->fmMacControllerDriver.h_Fm, ++ e_FM_MAC_10G, ++ p_Tgec->fmMacControllerDriver.macId, ++ p_TgecDriverParam->max_frame_length); ++ if (err != E_OK) ++ { ++ FreeInitResources(p_Tgec); ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++/* we consider having no IPC a non crasher... */ ++ ++#ifdef FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007 ++ if (p_Tgec->fmMacControllerDriver.fmRevInfo.majorRev == 2) ++ fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007(p_Tgec->p_MemMap); ++#endif /* FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007 */ ++ ++ p_Tgec->p_MulticastAddrHash = AllocHashTable(HASH_TABLE_SIZE); ++ if (!p_Tgec->p_MulticastAddrHash) ++ { ++ FreeInitResources(p_Tgec); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED")); ++ } ++ ++ p_Tgec->p_UnicastAddrHash = AllocHashTable(HASH_TABLE_SIZE); ++ if (!p_Tgec->p_UnicastAddrHash) ++ { ++ FreeInitResources(p_Tgec); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED")); ++ } ++ ++ FmRegisterIntr(p_Tgec->fmMacControllerDriver.h_Fm, ++ e_FM_MOD_10G_MAC, ++ p_Tgec->macId, ++ e_FM_INTR_TYPE_ERR, ++ TgecErrException, ++ p_Tgec); ++ if (p_Tgec->mdioIrq != NO_IRQ) ++ { ++ XX_SetIntr(p_Tgec->mdioIrq, TgecException, p_Tgec); ++ XX_EnableIntr(p_Tgec->mdioIrq); ++ } ++ ++ XX_Free(p_TgecDriverParam); ++ p_Tgec->p_TgecDriverParam = NULL; ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static t_Error TgecFree(t_Handle h_Tgec) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ ++ if (p_Tgec->p_TgecDriverParam) ++ { ++ /* Called after config */ ++ XX_Free(p_Tgec->p_TgecDriverParam); ++ p_Tgec->p_TgecDriverParam = NULL; ++ } ++ else ++ /* Called after init */ ++ FreeInitResources(p_Tgec); ++ ++ XX_Free(p_Tgec); ++ ++ return E_OK; ++} ++ ++/* ......................................................................... */ ++ ++static void InitFmMacControllerDriver(t_FmMacControllerDriver *p_FmMacControllerDriver) ++{ ++ p_FmMacControllerDriver->f_FM_MAC_Init = TgecInit; ++ p_FmMacControllerDriver->f_FM_MAC_Free = TgecFree; ++ ++ p_FmMacControllerDriver->f_FM_MAC_SetStatistics = NULL; ++ p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback = TgecConfigLoopback; ++ p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength = TgecConfigMaxFrameLength; ++ ++ p_FmMacControllerDriver->f_FM_MAC_ConfigWan = TgecConfigWan; ++ ++ p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc = NULL; /* TGEC always works with pad+crc */ ++ p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex = NULL; /* half-duplex is not supported in xgec */ ++ p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck = TgecConfigLengthCheck; ++ p_FmMacControllerDriver->f_FM_MAC_ConfigException = TgecConfigException; ++ p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit = NULL; ++ ++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 ++ p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround= TgecConfigSkipFman11Workaround; ++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ ++ ++ p_FmMacControllerDriver->f_FM_MAC_SetException = TgecSetExcpetion; ++ ++ p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp = TgecEnable1588TimeStamp; ++ p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp = TgecDisable1588TimeStamp; ++ ++ p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous = TgecSetPromiscuous; ++ p_FmMacControllerDriver->f_FM_MAC_AdjustLink = NULL; ++ p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan = NULL; ++ p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg = NULL; ++ ++ p_FmMacControllerDriver->f_FM_MAC_Enable = TgecEnable; ++ p_FmMacControllerDriver->f_FM_MAC_Disable = TgecDisable; ++ p_FmMacControllerDriver->f_FM_MAC_Resume = NULL; ++ ++ p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames = TgecTxMacPause; ++ p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames = TgecSetTxPauseFrames; ++ p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames = TgecRxIgnoreMacPause; ++ ++ p_FmMacControllerDriver->f_FM_MAC_ResetCounters = TgecResetCounters; ++ p_FmMacControllerDriver->f_FM_MAC_GetStatistics = TgecGetStatistics; ++ ++ p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr = TgecModifyMacAddress; ++ p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr = TgecAddHashMacAddress; ++ p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr = TgecDelHashMacAddress; ++ p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr = TgecAddExactMatchMacAddress; ++ p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr = TgecDelExactMatchMacAddress; ++ p_FmMacControllerDriver->f_FM_MAC_GetId = TgecGetId; ++ p_FmMacControllerDriver->f_FM_MAC_GetVersion = TgecGetVersion; ++ p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength = TgecGetMaxFrameLength; ++ ++ p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg = TGEC_MII_WritePhyReg; ++ p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg = TGEC_MII_ReadPhyReg; ++} ++ ++ ++/*****************************************************************************/ ++/* Tgec Config Main Entry */ ++/*****************************************************************************/ ++ ++/* ......................................................................... */ ++ ++t_Handle TGEC_Config(t_FmMacParams *p_FmMacParam) ++{ ++ t_Tgec *p_Tgec; ++ struct tgec_cfg *p_TgecDriverParam; ++ uintptr_t baseAddr; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_NULL_POINTER, NULL); ++ ++ baseAddr = p_FmMacParam->baseAddr; ++ /* allocate memory for the UCC GETH data structure. */ ++ p_Tgec = (t_Tgec *)XX_Malloc(sizeof(t_Tgec)); ++ if (!p_Tgec) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("10G MAC driver structure")); ++ return NULL; ++ } ++ memset(p_Tgec, 0, sizeof(t_Tgec)); ++ InitFmMacControllerDriver(&p_Tgec->fmMacControllerDriver); ++ ++ /* allocate memory for the 10G MAC driver parameters data structure. */ ++ p_TgecDriverParam = (struct tgec_cfg *) XX_Malloc(sizeof(struct tgec_cfg)); ++ if (!p_TgecDriverParam) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("10G MAC driver parameters")); ++ XX_Free(p_Tgec); ++ return NULL; ++ } ++ memset(p_TgecDriverParam, 0, sizeof(struct tgec_cfg)); ++ ++ /* Plant parameter structure pointer */ ++ p_Tgec->p_TgecDriverParam = p_TgecDriverParam; ++ ++ fman_tgec_defconfig(p_TgecDriverParam); ++ ++ p_Tgec->p_MemMap = (struct tgec_regs *)UINT_TO_PTR(baseAddr); ++ p_Tgec->p_MiiMemMap = (t_TgecMiiAccessMemMap *)UINT_TO_PTR(baseAddr + TGEC_TO_MII_OFFSET); ++ p_Tgec->addr = ENET_ADDR_TO_UINT64(p_FmMacParam->addr); ++ p_Tgec->enetMode = p_FmMacParam->enetMode; ++ p_Tgec->macId = p_FmMacParam->macId; ++ p_Tgec->exceptions = DEFAULT_exceptions; ++ p_Tgec->mdioIrq = p_FmMacParam->mdioIrq; ++ p_Tgec->f_Exception = p_FmMacParam->f_Exception; ++ p_Tgec->f_Event = p_FmMacParam->f_Event; ++ p_Tgec->h_App = p_FmMacParam->h_App; ++ ++ return p_Tgec; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.h +new file mode 100644 +index 00000000..2aa39238 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.h +@@ -0,0 +1,151 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File tgec.h ++ ++ @Description FM 10G MAC ... ++*//***************************************************************************/ ++#ifndef __TGEC_H ++#define __TGEC_H ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "list_ext.h" ++#include "enet_ext.h" ++ ++#include "tgec_mii_acc.h" ++#include "fm_mac.h" ++ ++ ++#define DEFAULT_exceptions \ ++ ((uint32_t)(TGEC_IMASK_MDIO_SCAN_EVENT | \ ++ TGEC_IMASK_REM_FAULT | \ ++ TGEC_IMASK_LOC_FAULT | \ ++ TGEC_IMASK_TX_ECC_ER | \ ++ TGEC_IMASK_TX_FIFO_UNFL | \ ++ TGEC_IMASK_TX_FIFO_OVFL | \ ++ TGEC_IMASK_TX_ER | \ ++ TGEC_IMASK_RX_FIFO_OVFL | \ ++ TGEC_IMASK_RX_ECC_ER | \ ++ TGEC_IMASK_RX_JAB_FRM | \ ++ TGEC_IMASK_RX_OVRSZ_FRM | \ ++ TGEC_IMASK_RX_RUNT_FRM | \ ++ TGEC_IMASK_RX_FRAG_FRM | \ ++ TGEC_IMASK_RX_CRC_ER | \ ++ TGEC_IMASK_RX_ALIGN_ER)) ++ ++#define GET_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \ ++ case e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO: \ ++ bitMask = TGEC_IMASK_MDIO_SCAN_EVENT ; break; \ ++ case e_FM_MAC_EX_10G_MDIO_CMD_CMPL: \ ++ bitMask = TGEC_IMASK_MDIO_CMD_CMPL ; break; \ ++ case e_FM_MAC_EX_10G_REM_FAULT: \ ++ bitMask = TGEC_IMASK_REM_FAULT ; break; \ ++ case e_FM_MAC_EX_10G_LOC_FAULT: \ ++ bitMask = TGEC_IMASK_LOC_FAULT ; break; \ ++ case e_FM_MAC_EX_10G_1TX_ECC_ER: \ ++ bitMask = TGEC_IMASK_TX_ECC_ER ; break; \ ++ case e_FM_MAC_EX_10G_TX_FIFO_UNFL: \ ++ bitMask = TGEC_IMASK_TX_FIFO_UNFL ; break; \ ++ case e_FM_MAC_EX_10G_TX_FIFO_OVFL: \ ++ bitMask = TGEC_IMASK_TX_FIFO_OVFL ; break; \ ++ case e_FM_MAC_EX_10G_TX_ER: \ ++ bitMask = TGEC_IMASK_TX_ER ; break; \ ++ case e_FM_MAC_EX_10G_RX_FIFO_OVFL: \ ++ bitMask = TGEC_IMASK_RX_FIFO_OVFL ; break; \ ++ case e_FM_MAC_EX_10G_RX_ECC_ER: \ ++ bitMask = TGEC_IMASK_RX_ECC_ER ; break; \ ++ case e_FM_MAC_EX_10G_RX_JAB_FRM: \ ++ bitMask = TGEC_IMASK_RX_JAB_FRM ; break; \ ++ case e_FM_MAC_EX_10G_RX_OVRSZ_FRM: \ ++ bitMask = TGEC_IMASK_RX_OVRSZ_FRM ; break; \ ++ case e_FM_MAC_EX_10G_RX_RUNT_FRM: \ ++ bitMask = TGEC_IMASK_RX_RUNT_FRM ; break; \ ++ case e_FM_MAC_EX_10G_RX_FRAG_FRM: \ ++ bitMask = TGEC_IMASK_RX_FRAG_FRM ; break; \ ++ case e_FM_MAC_EX_10G_RX_LEN_ER: \ ++ bitMask = TGEC_IMASK_RX_LEN_ER ; break; \ ++ case e_FM_MAC_EX_10G_RX_CRC_ER: \ ++ bitMask = TGEC_IMASK_RX_CRC_ER ; break; \ ++ case e_FM_MAC_EX_10G_RX_ALIGN_ER: \ ++ bitMask = TGEC_IMASK_RX_ALIGN_ER ; break; \ ++ default: bitMask = 0;break;} ++ ++#define MAX_PACKET_ALIGNMENT 31 ++#define MAX_INTER_PACKET_GAP 0x7f ++#define MAX_INTER_PALTERNATE_BEB 0x0f ++#define MAX_RETRANSMISSION 0x0f ++#define MAX_COLLISION_WINDOW 0x03ff ++ ++#define TGEC_NUM_OF_PADDRS 1 /* number of pattern match registers (entries) */ ++ ++#define GROUP_ADDRESS 0x0000010000000000LL /* Group address bit indication */ ++ ++#define HASH_TABLE_SIZE 512 /* Hash table size (= 32 bits * 8 regs) */ ++ ++#define TGEC_TO_MII_OFFSET 0x1030 /* Offset from the MEM map to the MDIO mem map */ ++ ++/* 10-gigabit Ethernet MAC Controller ID (10GEC_ID) */ ++#define TGEC_ID_ID 0xffff0000 ++#define TGEC_ID_MAC_VERSION 0x0000FF00 ++#define TGEC_ID_MAC_REV 0x000000ff ++ ++ ++typedef struct { ++ t_FmMacControllerDriver fmMacControllerDriver; /**< Upper Mac control block */ ++ t_Handle h_App; /**< Handle to the upper layer application */ ++ struct tgec_regs *p_MemMap; /**< pointer to 10G memory mapped registers. */ ++ t_TgecMiiAccessMemMap *p_MiiMemMap; /**< pointer to MII memory mapped registers. */ ++ uint64_t addr; /**< MAC address of device; */ ++ e_EnetMode enetMode; /**< Ethernet physical interface */ ++ t_FmMacExceptionCallback *f_Exception; ++ int mdioIrq; ++ t_FmMacExceptionCallback *f_Event; ++ bool indAddrRegUsed[TGEC_NUM_OF_PADDRS]; /**< Whether a particular individual address recognition register is being used */ ++ uint64_t paddr[TGEC_NUM_OF_PADDRS]; /**< MAC address for particular individual address recognition register */ ++ uint8_t numOfIndAddrInRegs; /**< Number of individual addresses in registers for this station. */ ++ t_EthHash *p_MulticastAddrHash; /**< pointer to driver's global address hash table */ ++ t_EthHash *p_UnicastAddrHash; /**< pointer to driver's individual address hash table */ ++ bool debugMode; ++ uint8_t macId; ++ uint32_t exceptions; ++ struct tgec_cfg *p_TgecDriverParam; ++} t_Tgec; ++ ++ ++t_Error TGEC_MII_WritePhyReg(t_Handle h_Tgec, uint8_t phyAddr, uint8_t reg, uint16_t data); ++t_Error TGEC_MII_ReadPhyReg(t_Handle h_Tgec, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data); ++ ++ ++#endif /* __TGEC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.c +new file mode 100644 +index 00000000..e0fafd1d +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.c +@@ -0,0 +1,139 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++ ++#include "error_ext.h" ++#include "std_ext.h" ++#include "fm_mac.h" ++#include "tgec.h" ++#include "xx_ext.h" ++ ++#include "fm_common.h" ++ ++ ++/*****************************************************************************/ ++t_Error TGEC_MII_WritePhyReg(t_Handle h_Tgec, ++ uint8_t phyAddr, ++ uint8_t reg, ++ uint16_t data) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ t_TgecMiiAccessMemMap *p_MiiAccess; ++ uint32_t cfgStatusReg; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MiiMemMap, E_INVALID_HANDLE); ++ ++ p_MiiAccess = p_Tgec->p_MiiMemMap; ++ ++ /* Configure MII */ ++ cfgStatusReg = GET_UINT32(p_MiiAccess->mdio_cfg_status); ++ cfgStatusReg &= ~MIIMCOM_DIV_MASK; ++ /* (one half of fm clock => 2.5Mhz) */ ++ cfgStatusReg |=((((p_Tgec->fmMacControllerDriver.clkFreq*10)/2)/25) << MIIMCOM_DIV_SHIFT); ++ WRITE_UINT32(p_MiiAccess->mdio_cfg_status, cfgStatusReg); ++ ++ while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY) ++ XX_UDelay (1); ++ ++ WRITE_UINT32(p_MiiAccess->mdio_command, phyAddr); ++ ++ WRITE_UINT32(p_MiiAccess->mdio_regaddr, reg); ++ ++ CORE_MemoryBarrier(); ++ ++ while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY) ++ XX_UDelay (1); ++ ++ WRITE_UINT32(p_MiiAccess->mdio_data, data); ++ ++ CORE_MemoryBarrier(); ++ ++ while ((GET_UINT32(p_MiiAccess->mdio_data)) & MIIDATA_BUSY) ++ XX_UDelay (1); ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error TGEC_MII_ReadPhyReg(t_Handle h_Tgec, ++ uint8_t phyAddr, ++ uint8_t reg, ++ uint16_t *p_Data) ++{ ++ t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; ++ t_TgecMiiAccessMemMap *p_MiiAccess; ++ uint32_t cfgStatusReg; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MiiMemMap, E_INVALID_HANDLE); ++ ++ p_MiiAccess = p_Tgec->p_MiiMemMap; ++ ++ /* Configure MII */ ++ cfgStatusReg = GET_UINT32(p_MiiAccess->mdio_cfg_status); ++ cfgStatusReg &= ~MIIMCOM_DIV_MASK; ++ /* (one half of fm clock => 2.5Mhz) */ ++ cfgStatusReg |=((((p_Tgec->fmMacControllerDriver.clkFreq*10)/2)/25) << MIIMCOM_DIV_SHIFT); ++ WRITE_UINT32(p_MiiAccess->mdio_cfg_status, cfgStatusReg); ++ ++ while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY) ++ XX_UDelay (1); ++ ++ WRITE_UINT32(p_MiiAccess->mdio_command, phyAddr); ++ ++ WRITE_UINT32(p_MiiAccess->mdio_regaddr, reg); ++ ++ CORE_MemoryBarrier(); ++ ++ while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY) ++ XX_UDelay (1); ++ ++ WRITE_UINT32(p_MiiAccess->mdio_command, (uint32_t)(phyAddr | MIIMCOM_READ_CYCLE)); ++ ++ CORE_MemoryBarrier(); ++ ++ while ((GET_UINT32(p_MiiAccess->mdio_data)) & MIIDATA_BUSY) ++ XX_UDelay (1); ++ ++ *p_Data = (uint16_t)GET_UINT32(p_MiiAccess->mdio_data); ++ ++ cfgStatusReg = GET_UINT32(p_MiiAccess->mdio_cfg_status); ++ ++ if (cfgStatusReg & MIIMIND_READ_ERROR) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, ++ ("Read Error: phyAddr 0x%x, dev 0x%x, reg 0x%x, cfgStatusReg 0x%x", ++ ((phyAddr & 0xe0)>>5), (phyAddr & 0x1f), reg, cfgStatusReg)); ++ ++ return E_OK; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.h +new file mode 100644 +index 00000000..645cdde5 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.h +@@ -0,0 +1,80 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#ifndef __TGEC_MII_ACC_H ++#define __TGEC_MII_ACC_H ++ ++#include "std_ext.h" ++ ++ ++/* MII Management Command Register */ ++#define MIIMCOM_READ_POST_INCREMENT 0x00004000 ++#define MIIMCOM_READ_CYCLE 0x00008000 ++#define MIIMCOM_SCAN_CYCLE 0x00000800 ++#define MIIMCOM_PREAMBLE_DISABLE 0x00000400 ++ ++#define MIIMCOM_MDIO_HOLD_1_REG_CLK 0 ++#define MIIMCOM_MDIO_HOLD_2_REG_CLK 1 ++#define MIIMCOM_MDIO_HOLD_3_REG_CLK 2 ++#define MIIMCOM_MDIO_HOLD_4_REG_CLK 3 ++ ++#define MIIMCOM_DIV_MASK 0x0000ff00 ++#define MIIMCOM_DIV_SHIFT 8 ++ ++/* MII Management Indicator Register */ ++#define MIIMIND_BUSY 0x00000001 ++#define MIIMIND_READ_ERROR 0x00000002 ++ ++#define MIIDATA_BUSY 0x80000000 ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(push,1) ++#endif /* defined(__MWERKS__) && ... */ ++ ++/*----------------------------------------------------*/ ++/* MII Configuration Control Memory Map Registers */ ++/*----------------------------------------------------*/ ++typedef _Packed struct t_TgecMiiAccessMemMap ++{ ++ volatile uint32_t mdio_cfg_status; /* 0x030 */ ++ volatile uint32_t mdio_command; /* 0x034 */ ++ volatile uint32_t mdio_data; /* 0x038 */ ++ volatile uint32_t mdio_regaddr; /* 0x03c */ ++} _PackedType t_TgecMiiAccessMemMap ; ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(pop) ++#endif /* defined(__MWERKS__) && ... */ ++ ++ ++#endif /* __TGEC_MII_ACC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/Makefile +new file mode 100644 +index 00000000..bfa02f5e +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/Makefile +@@ -0,0 +1,15 @@ ++# ++# Makefile for the Freescale Ethernet controllers ++# ++ccflags-y += -DVERSION=\"\" ++# ++#Include netcomm SW specific definitions ++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk ++ ++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc ++ ++ccflags-y += -I$(NCSW_FM_INC) ++ ++obj-y += fsl-ncsw-macsec.o ++ ++fsl-ncsw-macsec-objs := fm_macsec.o fm_macsec_guest.o fm_macsec_master.o fm_macsec_secy.o +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.c +new file mode 100644 +index 00000000..0a1b31f1 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.c +@@ -0,0 +1,237 @@ ++/* ++ * Copyright 2008-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++/****************************************************************************** ++ ++ @File fm_macsec.c ++ ++ @Description FM MACSEC driver routines implementation. ++*//***************************************************************************/ ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "xx_ext.h" ++#include "string_ext.h" ++#include "sprint_ext.h" ++#include "debug_ext.h" ++ ++#include "fm_macsec.h" ++ ++ ++/****************************************/ ++/* API Init unit functions */ ++/****************************************/ ++t_Handle FM_MACSEC_Config(t_FmMacsecParams *p_FmMacsecParam) ++{ ++ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmMacsecParam, E_INVALID_HANDLE, NULL); ++ ++ if (p_FmMacsecParam->guestMode) ++ p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)FM_MACSEC_GUEST_Config(p_FmMacsecParam); ++ else ++ p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)FM_MACSEC_MASTER_Config(p_FmMacsecParam); ++ ++ if (!p_FmMacsecControllerDriver) ++ return NULL; ++ ++ return (t_Handle)p_FmMacsecControllerDriver; ++} ++ ++t_Error FM_MACSEC_Init(t_Handle h_FmMacsec) ++{ ++ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacsecControllerDriver->f_FM_MACSEC_Init) ++ return p_FmMacsecControllerDriver->f_FM_MACSEC_Init(h_FmMacsec); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_Free(t_Handle h_FmMacsec) ++{ ++ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacsecControllerDriver->f_FM_MACSEC_Free) ++ return p_FmMacsecControllerDriver->f_FM_MACSEC_Free(h_FmMacsec); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_ConfigUnknownSciFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUnknownSciFrameTreatment treatMode) ++{ ++ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUnknownSciFrameTreatment) ++ return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUnknownSciFrameTreatment(h_FmMacsec, treatMode); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_ConfigInvalidTagsFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled) ++{ ++ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigInvalidTagsFrameTreatment) ++ return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigInvalidTagsFrameTreatment(h_FmMacsec, deliverUncontrolled); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment(t_Handle h_FmMacsec, bool discardUncontrolled) ++{ ++ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment) ++ return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment(h_FmMacsec, discardUncontrolled); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_ConfigUntagFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUntagFrameTreatment treatMode) ++{ ++ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUntagFrameTreatment) ++ return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUntagFrameTreatment(h_FmMacsec, treatMode); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_ConfigPnExhaustionThreshold(t_Handle h_FmMacsec, uint32_t pnExhThr) ++{ ++ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigPnExhaustionThreshold) ++ return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigPnExhaustionThreshold(h_FmMacsec, pnExhThr); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_ConfigKeysUnreadable(t_Handle h_FmMacsec) ++{ ++ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigKeysUnreadable) ++ return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigKeysUnreadable(h_FmMacsec); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_ConfigSectagWithoutSCI(t_Handle h_FmMacsec) ++{ ++ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigSectagWithoutSCI) ++ return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigSectagWithoutSCI(h_FmMacsec); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_ConfigException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable) ++{ ++ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigException) ++ return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigException(h_FmMacsec, exception, enable); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_GetRevision(t_Handle h_FmMacsec, uint32_t *p_MacsecRevision) ++{ ++ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacsecControllerDriver->f_FM_MACSEC_GetRevision) ++ return p_FmMacsecControllerDriver->f_FM_MACSEC_GetRevision(h_FmMacsec, p_MacsecRevision); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++ ++t_Error FM_MACSEC_Enable(t_Handle h_FmMacsec) ++{ ++ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacsecControllerDriver->f_FM_MACSEC_Enable) ++ return p_FmMacsecControllerDriver->f_FM_MACSEC_Enable(h_FmMacsec); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_Disable(t_Handle h_FmMacsec) ++{ ++ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacsecControllerDriver->f_FM_MACSEC_Disable) ++ return p_FmMacsecControllerDriver->f_FM_MACSEC_Disable(h_FmMacsec); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_SetException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable) ++{ ++ t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); ++ ++ if (p_FmMacsecControllerDriver->f_FM_MACSEC_SetException) ++ return p_FmMacsecControllerDriver->f_FM_MACSEC_SetException(h_FmMacsec, exception, enable); ++ ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.h +new file mode 100644 +index 00000000..fbe51875 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.h +@@ -0,0 +1,203 @@ ++/* ++ * Copyright 2008-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/****************************************************************************** ++ @File fm_macsec.h ++ ++ @Description FM MACSEC internal structures and definitions. ++*//***************************************************************************/ ++#ifndef __FM_MACSEC_H ++#define __FM_MACSEC_H ++ ++#include "error_ext.h" ++#include "std_ext.h" ++#include "fm_macsec_ext.h" ++ ++#include "fm_common.h" ++ ++ ++#define __ERR_MODULE__ MODULE_FM_MACSEC ++ ++ ++typedef struct ++{ ++ t_Error (*f_FM_MACSEC_Init) (t_Handle h_FmMacsec); ++ t_Error (*f_FM_MACSEC_Free) (t_Handle h_FmMacsec); ++ ++ t_Error (*f_FM_MACSEC_ConfigUnknownSciFrameTreatment) (t_Handle h_FmMacsec, e_FmMacsecUnknownSciFrameTreatment treatMode); ++ t_Error (*f_FM_MACSEC_ConfigInvalidTagsFrameTreatment) (t_Handle h_FmMacsec, bool deliverUncontrolled); ++ t_Error (*f_FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment) (t_Handle h_FmMacsec, bool discardUncontrolled); ++ t_Error (*f_FM_MACSEC_ConfigChangedTextWithNoEncryptFrameTreatment) (t_Handle h_FmMacsec, bool deliverUncontrolled); ++ t_Error (*f_FM_MACSEC_ConfigUntagFrameTreatment) (t_Handle h_FmMacsec, e_FmMacsecUntagFrameTreatment treatMode); ++ t_Error (*f_FM_MACSEC_ConfigOnlyScbIsSetFrameTreatment) (t_Handle h_FmMacsec, bool deliverUncontrolled); ++ t_Error (*f_FM_MACSEC_ConfigPnExhaustionThreshold) (t_Handle h_FmMacsec, uint32_t pnExhThr); ++ t_Error (*f_FM_MACSEC_ConfigKeysUnreadable) (t_Handle h_FmMacsec); ++ t_Error (*f_FM_MACSEC_ConfigSectagWithoutSCI) (t_Handle h_FmMacsec); ++ t_Error (*f_FM_MACSEC_ConfigException) (t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable); ++ ++ t_Error (*f_FM_MACSEC_GetRevision) (t_Handle h_FmMacsec, uint32_t *p_MacsecRevision); ++ t_Error (*f_FM_MACSEC_Enable) (t_Handle h_FmMacsec); ++ t_Error (*f_FM_MACSEC_Disable) (t_Handle h_FmMacsec); ++ t_Error (*f_FM_MACSEC_SetException) (t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable); ++ ++} t_FmMacsecControllerDriver; ++ ++t_Handle FM_MACSEC_GUEST_Config(t_FmMacsecParams *p_FmMacsecParam); ++t_Handle FM_MACSEC_MASTER_Config(t_FmMacsecParams *p_FmMacsecParams); ++ ++/***********************************************************************/ ++/* MACSEC internal routines */ ++/***********************************************************************/ ++ ++/**************************************************************************//** ++ ++ @Group FM_MACSEC_InterModule_grp FM MACSEC Inter-Module Unit ++ ++ @Description FM MACSEC Inter Module functions - ++ These are not User API routines but routines that may be called ++ from other modules. This will be the case in a single core environment, ++ where instead of using the XX messaging mechanism, the routines may be ++ called from other modules. In a multicore environment, the other modules may ++ be run by other cores and therefore these routines may not be called directly. ++ ++ @{ ++*//***************************************************************************/ ++ ++#define MAX_NUM_OF_SA_PER_SC 4 ++ ++typedef enum ++{ ++ e_SC_RX = 0, ++ e_SC_TX ++} e_ScType; ++ ++typedef enum ++{ ++ e_SC_SA_A = 0, ++ e_SC_SA_B , ++ e_SC_SA_C , ++ e_SC_SA_D ++} e_ScSaId; ++ ++typedef struct ++{ ++ uint32_t scId; ++ macsecSCI_t sci; ++ bool replayProtect; ++ uint32_t replayWindow; ++ e_FmMacsecValidFrameBehavior validateFrames; ++ uint16_t confidentialityOffset; ++ e_FmMacsecSecYCipherSuite cipherSuite; ++} t_RxScParams; ++ ++typedef struct ++{ ++ uint32_t scId; ++ macsecSCI_t sci; ++ bool protectFrames; ++ e_FmMacsecSciInsertionMode sciInsertionMode; ++ bool confidentialityEnable; ++ uint16_t confidentialityOffset; ++ e_FmMacsecSecYCipherSuite cipherSuite; ++} t_TxScParams; ++ ++typedef enum e_FmMacsecGlobalExceptions { ++ e_FM_MACSEC_EX_TX_SC, /**< Tx Sc 0 frame discarded error. */ ++ e_FM_MACSEC_EX_ECC /**< MACSEC memory ECC multiple-bit error. */ ++} e_FmMacsecGlobalExceptions; ++ ++typedef enum e_FmMacsecGlobalEvents { ++ e_FM_MACSEC_EV_TX_SC_NEXT_PN /**< Tx Sc 0 Next Pn exhaustion threshold reached. */ ++} e_FmMacsecGlobalEvents; ++ ++/**************************************************************************//** ++ @Description Enum for inter-module interrupts registration ++*//***************************************************************************/ ++typedef enum e_FmMacsecEventModules{ ++ e_FM_MACSEC_MOD_SC_TX, ++ e_FM_MACSEC_MOD_DUMMY_LAST ++} e_FmMacsecEventModules; ++ ++typedef enum e_FmMacsecInterModuleEvent { ++ e_FM_MACSEC_EV_SC_TX, ++ e_FM_MACSEC_EV_ERR_SC_TX, ++ e_FM_MACSEC_EV_DUMMY_LAST ++} e_FmMacsecInterModuleEvent; ++ ++#define NUM_OF_INTER_MODULE_EVENTS (NUM_OF_TX_SC * 2) ++ ++#define GET_MACSEC_MODULE_EVENT(mod, id, intrType, event) \ ++ switch(mod){ \ ++ case e_FM_MACSEC_MOD_SC_TX: \ ++ event = (intrType == e_FM_INTR_TYPE_ERR) ? \ ++ e_FM_MACSEC_EV_ERR_SC_TX: \ ++ e_FM_MACSEC_EV_SC_TX; \ ++ event += (uint8_t)(2 * id);break; \ ++ break; \ ++ default:event = e_FM_MACSEC_EV_DUMMY_LAST; \ ++ break;} ++ ++void FmMacsecRegisterIntr(t_Handle h_FmMacsec, ++ e_FmMacsecEventModules module, ++ uint8_t modId, ++ e_FmIntrType intrType, ++ void (*f_Isr) (t_Handle h_Arg, uint32_t id), ++ t_Handle h_Arg); ++ ++void FmMacsecUnregisterIntr(t_Handle h_FmMacsec, ++ e_FmMacsecEventModules module, ++ uint8_t modId, ++ e_FmIntrType intrType); ++ ++t_Error FmMacsecAllocScs(t_Handle h_FmMacsec, e_ScType type, bool isPtp, uint32_t numOfScs, uint32_t *p_ScIds); ++t_Error FmMacsecFreeScs(t_Handle h_FmMacsec, e_ScType type, uint32_t numOfScs, uint32_t *p_ScIds); ++t_Error FmMacsecCreateRxSc(t_Handle h_FmMacsec, t_RxScParams *p_RxScParams); ++t_Error FmMacsecDeleteRxSc(t_Handle h_FmMacsec, uint32_t scId); ++t_Error FmMacsecCreateTxSc(t_Handle h_FmMacsec, t_TxScParams *p_RxScParams); ++t_Error FmMacsecDeleteTxSc(t_Handle h_FmMacsec, uint32_t scId); ++t_Error FmMacsecCreateRxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecAN_t an, uint32_t lowestPn, macsecSAKey_t key); ++t_Error FmMacsecCreateTxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecSAKey_t key); ++t_Error FmMacsecDeleteRxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId); ++t_Error FmMacsecDeleteTxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId); ++t_Error FmMacsecRxSaSetReceive(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, bool enableReceive); ++t_Error FmMacsecRxSaUpdateNextPn(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, uint32_t updtNextPN); ++t_Error FmMacsecRxSaUpdateLowestPn(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, uint32_t updtLowestPN); ++t_Error FmMacsecTxSaSetActive(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecAN_t an); ++t_Error FmMacsecTxSaGetActive(t_Handle h_FmMacsec, uint32_t scId, macsecAN_t *p_An); ++t_Error FmMacsecSetPTP(t_Handle h_FmMacsec, bool enable); ++ ++t_Error FmMacsecSetException(t_Handle h_FmMacsec, e_FmMacsecGlobalExceptions exception, uint32_t scId, bool enable); ++t_Error FmMacsecSetEvent(t_Handle h_FmMacsec, e_FmMacsecGlobalEvents event, uint32_t scId, bool enable); ++ ++ ++ ++#endif /* __FM_MACSEC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_guest.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_guest.c +new file mode 100644 +index 00000000..31d789d0 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_guest.c +@@ -0,0 +1,59 @@ ++/* ++ * Copyright 2008-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/****************************************************************************** ++ @File fm_macsec.c ++ ++ @Description FM MACSEC driver routines implementation. ++*//***************************************************************************/ ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "xx_ext.h" ++#include "string_ext.h" ++#include "sprint_ext.h" ++#include "debug_ext.h" ++#include "fm_macsec.h" ++ ++ ++/****************************************/ ++/* static functions */ ++/****************************************/ ++ ++/****************************************/ ++/* API Init unit functions */ ++/****************************************/ ++t_Handle FM_MACSEC_GUEST_Config(t_FmMacsecParams *p_FmMacsecParam) ++{ ++ UNUSED(p_FmMacsecParam); ++ return NULL; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.c +new file mode 100644 +index 00000000..623612ac +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.c +@@ -0,0 +1,1031 @@ ++/* ++ * Copyright 2008-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/****************************************************************************** ++ @File fm_macsec.c ++ ++ @Description FM MACSEC driver routines implementation. ++*//***************************************************************************/ ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "xx_ext.h" ++#include "string_ext.h" ++#include "sprint_ext.h" ++#include "fm_mac_ext.h" ++ ++#include "fm_macsec_master.h" ++ ++ ++extern uint16_t FM_MAC_GetMaxFrameLength(t_Handle FmMac); ++ ++ ++/****************************************/ ++/* static functions */ ++/****************************************/ ++static t_Error CheckFmMacsecParameters(t_FmMacsec *p_FmMacsec) ++{ ++ if (!p_FmMacsec->f_Exception) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided")); ++ ++ return E_OK; ++} ++ ++static void UnimplementedIsr(t_Handle h_Arg, uint32_t id) ++{ ++ UNUSED(h_Arg); UNUSED(id); ++ ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unimplemented Isr!")); ++} ++ ++static void MacsecEventIsr(t_Handle h_FmMacsec) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ uint32_t events,event,i; ++ ++ SANITY_CHECK_RETURN(p_FmMacsec, E_INVALID_HANDLE); ++ ++ events = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->evr); ++ events |= GET_UINT32(p_FmMacsec->p_FmMacsecRegs->ever); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->evr,events); ++ ++ for (i=0; iintrMng[event].f_Isr(p_FmMacsec->intrMng[event].h_SrcHandle, i); ++ } ++} ++ ++static void MacsecErrorIsr(t_Handle h_FmMacsec) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ uint32_t errors,error,i; ++ ++ SANITY_CHECK_RETURN(p_FmMacsec, E_INVALID_HANDLE); ++ ++ errors = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->err); ++ errors |= GET_UINT32(p_FmMacsec->p_FmMacsecRegs->erer); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->err,errors); ++ ++ for (i=0; iintrMng[error].f_Isr(p_FmMacsec->intrMng[error].h_SrcHandle, i); ++ } ++ ++ if (errors & FM_MACSEC_EX_ECC) ++ { ++ uint8_t eccType; ++ uint32_t tmpReg; ++ ++ tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->meec); ++ ASSERT_COND(tmpReg & MECC_CAP); ++ eccType = (uint8_t)((tmpReg & MECC_CET) >> MECC_CET_SHIFT); ++ ++ if (!eccType && (p_FmMacsec->userExceptions & FM_MACSEC_USER_EX_SINGLE_BIT_ECC)) ++ p_FmMacsec->f_Exception(p_FmMacsec->h_App,e_FM_MACSEC_EX_SINGLE_BIT_ECC); ++ else if (eccType && (p_FmMacsec->userExceptions & FM_MACSEC_USER_EX_MULTI_BIT_ECC)) ++ p_FmMacsec->f_Exception(p_FmMacsec->h_App,e_FM_MACSEC_EX_MULTI_BIT_ECC); ++ else ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->meec,tmpReg); ++ } ++} ++ ++static t_Error MacsecInit(t_Handle h_FmMacsec) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ t_FmMacsecDriverParam *p_FmMacsecDriverParam = NULL; ++ uint32_t tmpReg,i,macId; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ CHECK_INIT_PARAMETERS(p_FmMacsec, CheckFmMacsecParameters); ++ ++ p_FmMacsecDriverParam = p_FmMacsec->p_FmMacsecDriverParam; ++ ++ for (i=0;iintrMng[i].f_Isr = UnimplementedIsr; ++ ++ tmpReg = 0; ++ tmpReg |= (p_FmMacsecDriverParam->changedTextWithNoEncryptDeliverUncontrolled << CFG_UECT_SHIFT)| ++ (p_FmMacsecDriverParam->onlyScbIsSetDeliverUncontrolled << CFG_ESCBT_SHIFT) | ++ (p_FmMacsecDriverParam->unknownSciTreatMode << CFG_USFT_SHIFT) | ++ (p_FmMacsecDriverParam->invalidTagsDeliverUncontrolled << CFG_ITT_SHIFT) | ++ (p_FmMacsecDriverParam->encryptWithNoChangedTextDiscardUncontrolled << CFG_KFT_SHIFT) | ++ (p_FmMacsecDriverParam->untagTreatMode << CFG_UFT_SHIFT) | ++ (p_FmMacsecDriverParam->keysUnreadable << CFG_KSS_SHIFT) | ++ (p_FmMacsecDriverParam->reservedSc0 << CFG_S0I_SHIFT) | ++ (p_FmMacsecDriverParam->byPassMode << CFG_BYPN_SHIFT); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg, tmpReg); ++ ++ tmpReg = FM_MAC_GetMaxFrameLength(p_FmMacsec->h_FmMac); ++ /* At least Ethernet FCS (4 bytes) overhead must be subtracted from MFL. ++ * In addition, the SCI (8 bytes) overhead might be subtracted as well. */ ++ tmpReg -= p_FmMacsecDriverParam->mflSubtract; ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->mfl, tmpReg); ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->tpnet, p_FmMacsecDriverParam->pnExhThr); ++ ++ if (!p_FmMacsec->userExceptions) ++ p_FmMacsec->exceptions &= ~FM_MACSEC_EX_ECC; ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->erer, p_FmMacsec->exceptions); ++ ++ p_FmMacsec->numRxScAvailable = NUM_OF_RX_SC; ++ if (p_FmMacsecDriverParam->reservedSc0) ++ p_FmMacsec->numRxScAvailable --; ++ p_FmMacsec->numTxScAvailable = NUM_OF_TX_SC; ++ ++ XX_Free(p_FmMacsecDriverParam); ++ p_FmMacsec->p_FmMacsecDriverParam = NULL; ++ ++ FM_MAC_GetId(p_FmMacsec->h_FmMac, &macId); ++ FmRegisterIntr(p_FmMacsec->h_Fm, ++ e_FM_MOD_MACSEC, ++ (uint8_t)macId, ++ e_FM_INTR_TYPE_NORMAL, ++ MacsecEventIsr, ++ p_FmMacsec); ++ ++ FmRegisterIntr(p_FmMacsec->h_Fm, ++ e_FM_MOD_MACSEC, ++ 0, ++ e_FM_INTR_TYPE_ERR, ++ MacsecErrorIsr, ++ p_FmMacsec); ++ ++ return E_OK; ++} ++ ++static t_Error MacsecFree(t_Handle h_FmMacsec) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ uint32_t macId; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ FM_MAC_GetId(p_FmMacsec->h_FmMac, &macId); ++ FmUnregisterIntr(p_FmMacsec->h_Fm, ++ e_FM_MOD_MACSEC, ++ (uint8_t)macId, ++ e_FM_INTR_TYPE_NORMAL); ++ ++ FmUnregisterIntr(p_FmMacsec->h_Fm, ++ e_FM_MOD_MACSEC, ++ 0, ++ e_FM_INTR_TYPE_ERR); ++ ++ if (p_FmMacsec->rxScSpinLock) ++ XX_FreeSpinlock(p_FmMacsec->rxScSpinLock); ++ if (p_FmMacsec->txScSpinLock) ++ XX_FreeSpinlock(p_FmMacsec->txScSpinLock); ++ ++ XX_Free(p_FmMacsec); ++ ++ return E_OK; ++} ++ ++static t_Error MacsecConfigUnknownSciFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUnknownSciFrameTreatment treatMode) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ p_FmMacsec->p_FmMacsecDriverParam->unknownSciTreatMode = treatMode; ++ ++ return E_OK; ++} ++ ++static t_Error MacsecConfigInvalidTagsFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ p_FmMacsec->p_FmMacsecDriverParam->invalidTagsDeliverUncontrolled = deliverUncontrolled; ++ ++ return E_OK; ++} ++ ++static t_Error MacsecConfigChangedTextWithNoEncryptFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ p_FmMacsec->p_FmMacsecDriverParam->changedTextWithNoEncryptDeliverUncontrolled = deliverUncontrolled; ++ ++ return E_OK; ++} ++ ++static t_Error MacsecConfigOnlyScbIsSetFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ p_FmMacsec->p_FmMacsecDriverParam->onlyScbIsSetDeliverUncontrolled = deliverUncontrolled; ++ ++ return E_OK; ++} ++ ++static t_Error MacsecConfigEncryptWithNoChangedTextFrameTreatment(t_Handle h_FmMacsec, bool discardUncontrolled) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ p_FmMacsec->p_FmMacsecDriverParam->encryptWithNoChangedTextDiscardUncontrolled = discardUncontrolled; ++ ++ return E_OK; ++} ++ ++static t_Error MacsecConfigUntagFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUntagFrameTreatment treatMode) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ p_FmMacsec->p_FmMacsecDriverParam->untagTreatMode = treatMode; ++ ++ return E_OK; ++} ++ ++static t_Error MacsecConfigPnExhaustionThreshold(t_Handle h_FmMacsec, uint32_t pnExhThr) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ p_FmMacsec->p_FmMacsecDriverParam->pnExhThr = pnExhThr; ++ ++ return E_OK; ++} ++ ++static t_Error MacsecConfigKeysUnreadable(t_Handle h_FmMacsec) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ p_FmMacsec->p_FmMacsecDriverParam->keysUnreadable = TRUE; ++ ++ return E_OK; ++} ++ ++static t_Error MacsecConfigSectagWithoutSCI(t_Handle h_FmMacsec) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ p_FmMacsec->p_FmMacsecDriverParam->sectagOverhead -= MACSEC_SCI_SIZE; ++ p_FmMacsec->p_FmMacsecDriverParam->mflSubtract += MACSEC_SCI_SIZE; ++ ++ return E_OK; ++} ++ ++static t_Error MacsecConfigException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ uint32_t bitMask = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ GET_USER_EXCEPTION_FLAG(bitMask, exception); ++ if (bitMask) ++ { ++ if (enable) ++ p_FmMacsec->userExceptions |= bitMask; ++ else ++ p_FmMacsec->userExceptions &= ~bitMask; ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); ++ ++ return E_OK; ++} ++ ++static t_Error MacsecGetRevision(t_Handle h_FmMacsec, uint32_t *p_MacsecRevision) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ *p_MacsecRevision = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->ip_rev1); ++ ++ return E_OK; ++} ++ ++static t_Error MacsecEnable(t_Handle h_FmMacsec) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ uint32_t tmpReg; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg); ++ tmpReg |= CFG_BYPN; ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg,tmpReg); ++ ++ return E_OK; ++} ++ ++static t_Error MacsecDisable(t_Handle h_FmMacsec) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ uint32_t tmpReg; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg); ++ tmpReg &= ~CFG_BYPN; ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg,tmpReg); ++ ++ return E_OK; ++} ++ ++static t_Error MacsecSetException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ uint32_t bitMask; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ GET_USER_EXCEPTION_FLAG(bitMask, exception); ++ if (bitMask) ++ { ++ if (enable) ++ p_FmMacsec->userExceptions |= bitMask; ++ else ++ p_FmMacsec->userExceptions &= ~bitMask; ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); ++ ++ if (!p_FmMacsec->userExceptions) ++ p_FmMacsec->exceptions &= ~FM_MACSEC_EX_ECC; ++ else ++ p_FmMacsec->exceptions |= FM_MACSEC_EX_ECC; ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->erer, p_FmMacsec->exceptions); ++ ++ return E_OK; ++} ++ ++static void InitFmMacsecControllerDriver(t_FmMacsecControllerDriver *p_FmMacsecControllerDriver) ++{ ++ p_FmMacsecControllerDriver->f_FM_MACSEC_Init = MacsecInit; ++ p_FmMacsecControllerDriver->f_FM_MACSEC_Free = MacsecFree; ++ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUnknownSciFrameTreatment = MacsecConfigUnknownSciFrameTreatment; ++ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigInvalidTagsFrameTreatment = MacsecConfigInvalidTagsFrameTreatment; ++ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment = MacsecConfigEncryptWithNoChangedTextFrameTreatment; ++ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUntagFrameTreatment = MacsecConfigUntagFrameTreatment; ++ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigChangedTextWithNoEncryptFrameTreatment = MacsecConfigChangedTextWithNoEncryptFrameTreatment; ++ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigOnlyScbIsSetFrameTreatment = MacsecConfigOnlyScbIsSetFrameTreatment; ++ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigPnExhaustionThreshold = MacsecConfigPnExhaustionThreshold; ++ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigKeysUnreadable = MacsecConfigKeysUnreadable; ++ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigSectagWithoutSCI = MacsecConfigSectagWithoutSCI; ++ p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigException = MacsecConfigException; ++ p_FmMacsecControllerDriver->f_FM_MACSEC_GetRevision = MacsecGetRevision; ++ p_FmMacsecControllerDriver->f_FM_MACSEC_Enable = MacsecEnable; ++ p_FmMacsecControllerDriver->f_FM_MACSEC_Disable = MacsecDisable; ++ p_FmMacsecControllerDriver->f_FM_MACSEC_SetException = MacsecSetException; ++} ++ ++/****************************************/ ++/* Inter-Module functions */ ++/****************************************/ ++ ++void FmMacsecRegisterIntr(t_Handle h_FmMacsec, ++ e_FmMacsecEventModules module, ++ uint8_t modId, ++ e_FmIntrType intrType, ++ void (*f_Isr) (t_Handle h_Arg, uint32_t id), ++ t_Handle h_Arg) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ uint8_t event= 0; ++ ++ SANITY_CHECK_RETURN(p_FmMacsec, E_INVALID_HANDLE); ++ ++ GET_MACSEC_MODULE_EVENT(module, modId, intrType, event); ++ ++ ASSERT_COND(event != e_FM_MACSEC_EV_DUMMY_LAST); ++ p_FmMacsec->intrMng[event].f_Isr = f_Isr; ++ p_FmMacsec->intrMng[event].h_SrcHandle = h_Arg; ++} ++ ++void FmMacsecUnregisterIntr(t_Handle h_FmMacsec, ++ e_FmMacsecEventModules module, ++ uint8_t modId, ++ e_FmIntrType intrType) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ uint8_t event= 0; ++ ++ SANITY_CHECK_RETURN(p_FmMacsec, E_INVALID_HANDLE); ++ ++ GET_MACSEC_MODULE_EVENT(module, modId,intrType, event); ++ ++ ASSERT_COND(event != e_FM_MACSEC_EV_DUMMY_LAST); ++ p_FmMacsec->intrMng[event].f_Isr = NULL; ++ p_FmMacsec->intrMng[event].h_SrcHandle = NULL; ++} ++ ++t_Error FmMacsecAllocScs(t_Handle h_FmMacsec, e_ScType type, bool isPtp, uint32_t numOfScs, uint32_t *p_ScIds) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ t_Error err = E_OK; ++ bool *p_ScTable; ++ uint32_t *p_ScAvailable,i; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_ScIds, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(numOfScs, E_INVALID_HANDLE); ++ ++ if (type == e_SC_RX) ++ { ++ p_ScTable = (bool *)p_FmMacsec->rxScTable; ++ p_ScAvailable = &p_FmMacsec->numRxScAvailable; ++ i = (NUM_OF_RX_SC - 1); ++ } ++ else ++ { ++ p_ScTable = (bool *)p_FmMacsec->txScTable; ++ p_ScAvailable = &p_FmMacsec->numTxScAvailable; ++ i = (NUM_OF_TX_SC - 1); ++ ++ } ++ if (*p_ScAvailable < numOfScs) ++ RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Not enough SCs available")); ++ ++ if (isPtp) ++ { ++ i = 0; ++ if (p_ScTable[i]) ++ RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Sc 0 Not available")); ++ } ++ ++ for (;numOfScs;i--) ++ { ++ if (p_ScTable[i]) ++ continue; ++ numOfScs --; ++ (*p_ScAvailable)--; ++ p_ScIds[numOfScs] = i; ++ p_ScTable[i] = TRUE; ++ } ++ ++ return err; ++} ++ ++t_Error FmMacsecFreeScs(t_Handle h_FmMacsec, e_ScType type, uint32_t numOfScs, uint32_t *p_ScIds) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ t_Error err = E_OK; ++ bool *p_ScTable; ++ uint32_t *p_ScAvailable,maxNumOfSc,i; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_ScIds, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(numOfScs, E_INVALID_HANDLE); ++ ++ if (type == e_SC_RX) ++ { ++ p_ScTable = (bool *)p_FmMacsec->rxScTable; ++ p_ScAvailable = &p_FmMacsec->numRxScAvailable; ++ maxNumOfSc = NUM_OF_RX_SC; ++ } ++ else ++ { ++ p_ScTable = (bool *)p_FmMacsec->txScTable; ++ p_ScAvailable = &p_FmMacsec->numTxScAvailable; ++ maxNumOfSc = NUM_OF_TX_SC; ++ } ++ ++ if ((*p_ScAvailable + numOfScs) > maxNumOfSc) ++ RETURN_ERROR(MINOR, E_FULL, ("Too much SCs")); ++ ++ for (i=0;ip_FmMacsecRegs->cfg); ++ if (enable && (tmpReg & CFG_S0I)) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("MACSEC already in point-to-point mode")); ++ ++ if (enable) ++ tmpReg |= CFG_S0I; ++ else ++ tmpReg &= ~CFG_S0I; ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg, tmpReg); ++ ++ return E_OK; ++} ++ ++t_Error FmMacsecCreateRxSc(t_Handle h_FmMacsec, t_RxScParams *p_RxScParams) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ t_Error err = E_OK; ++ uint32_t tmpReg = 0, intFlags; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_RxScParams, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_RxScParams->scId < NUM_OF_RX_SC, E_INVALID_HANDLE); ++ ++ intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock); ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, p_RxScParams->scId); ++ tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsccfg); ++ if (tmpReg & RX_SCCFG_SCI_EN_MASK) ++ { ++ XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags); ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Rx Sc %d must be disable",p_RxScParams->scId)); ++ } ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsci1h, GET_SCI_FIRST_HALF(p_RxScParams->sci)); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsci2h, GET_SCI_SECOND_HALF(p_RxScParams->sci)); ++ tmpReg |= ((p_RxScParams->replayProtect << RX_SCCFG_RP_SHIFT) & RX_SCCFG_RP_MASK); ++ tmpReg |= ((p_RxScParams->validateFrames << RX_SCCFG_VF_SHIFT) & RX_SCCFG_VF_MASK); ++ tmpReg |= ((p_RxScParams->confidentialityOffset << RX_SCCFG_CO_SHIFT) & RX_SCCFG_CO_MASK); ++ tmpReg |= RX_SCCFG_SCI_EN_MASK; ++ tmpReg |= (p_RxScParams->cipherSuite << RX_SCCFG_CS_SHIFT); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsccfg, tmpReg); ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rpw, p_RxScParams->replayWindow); ++ ++ XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags); ++ ++ return err; ++} ++ ++t_Error FmMacsecDeleteRxSc(t_Handle h_FmMacsec, uint32_t scId) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ t_Error err = E_OK; ++ uint32_t tmpReg = 0, intFlags; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); ++ ++ intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock); ++ ++ tmpReg &= ~RX_SCCFG_SCI_EN_MASK; ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsccfg, tmpReg); ++ ++ XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags); ++ ++ return err; ++} ++ ++t_Error FmMacsecCreateTxSc(t_Handle h_FmMacsec, t_TxScParams *p_TxScParams) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ t_Error err = E_OK; ++ uint32_t tmpReg = 0, intFlags; ++ bool alwaysIncludeSCI = FALSE, useES = FALSE, useSCB = FALSE; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_TxScParams, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_TxScParams->scId < NUM_OF_TX_SC, E_INVALID_HANDLE); ++ ++ intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock); ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, p_TxScParams->scId); ++ ++ tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg); ++ if (tmpReg & TX_SCCFG_SCE_MASK) ++ { ++ XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags); ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Tx Sc %d must be disable",p_TxScParams->scId)); ++ } ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsci1h, GET_SCI_FIRST_HALF(p_TxScParams->sci)); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsci2h, GET_SCI_SECOND_HALF(p_TxScParams->sci)); ++ alwaysIncludeSCI = (p_TxScParams->sciInsertionMode == e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_SECTAG); ++ useES = (p_TxScParams->sciInsertionMode == e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_MAC_SA); ++ ++ tmpReg |= ((p_TxScParams->protectFrames << TX_SCCFG_PF_SHIFT) & TX_SCCFG_PF_MASK); ++ tmpReg |= ((alwaysIncludeSCI << TX_SCCFG_AIS_SHIFT) & TX_SCCFG_AIS_MASK); ++ tmpReg |= ((useES << TX_SCCFG_UES_SHIFT) & TX_SCCFG_UES_MASK); ++ tmpReg |= ((useSCB << TX_SCCFG_USCB_SHIFT) & TX_SCCFG_USCB_MASK); ++ tmpReg |= ((p_TxScParams->confidentialityEnable << TX_SCCFG_CE_SHIFT) & TX_SCCFG_CE_MASK); ++ tmpReg |= ((p_TxScParams->confidentialityOffset << TX_SCCFG_CO_SHIFT) & TX_SCCFG_CO_MASK); ++ tmpReg |= TX_SCCFG_SCE_MASK; ++ tmpReg |= (p_TxScParams->cipherSuite << TX_SCCFG_CS_SHIFT); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg, tmpReg); ++ ++ XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags); ++ ++ return err; ++} ++ ++t_Error FmMacsecDeleteTxSc(t_Handle h_FmMacsec, uint32_t scId) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ t_Error err = E_OK; ++ uint32_t tmpReg = 0, intFlags; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_TX_SC, E_INVALID_HANDLE); ++ ++ intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock); ++ ++ tmpReg &= ~TX_SCCFG_SCE_MASK; ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg, tmpReg); ++ ++ XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags); ++ ++ return err; ++} ++ ++t_Error FmMacsecCreateRxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecAN_t an, uint32_t lowestPn, macsecSAKey_t key) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ t_Error err = E_OK; ++ uint32_t tmpReg = 0, intFlags; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE); ++ ++ intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock); ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsanpn, DEFAULT_initNextPn); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsalpn, lowestPn); ++ MemCpy8((void*)p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsak, key, sizeof(macsecSAKey_t)); ++ ++ tmpReg |= RX_SACFG_ACTIVE; ++ tmpReg |= ((an << RX_SACFG_AN_SHIFT) & RX_SACFG_AN_MASK); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsacs, tmpReg); ++ ++ XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags); ++ ++ return err; ++} ++ ++t_Error FmMacsecCreateTxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecSAKey_t key) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ t_Error err = E_OK; ++ uint32_t tmpReg = 0, intFlags; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_TX_SC, E_INVALID_HANDLE); ++ ++ intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock); ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsanpn, DEFAULT_initNextPn); ++ MemCpy8((void*)p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsak, key, sizeof(macsecSAKey_t)); ++ ++ tmpReg |= TX_SACFG_ACTIVE; ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsacs, tmpReg); ++ ++ XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags); ++ ++ return err; ++} ++ ++t_Error FmMacsecDeleteRxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ t_Error err = E_OK; ++ uint32_t tmpReg = 0, i, intFlags; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE); ++ ++ intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock); ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsanpn, 0x0); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsalpn, 0x0); ++ for (i=0; i<4; i++) ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsak[i], 0x0); ++ ++ tmpReg |= RX_SACFG_ACTIVE; ++ tmpReg &= ~RX_SACFG_EN_MASK; ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsacs, tmpReg); ++ ++ XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags); ++ ++ return err; ++} ++ ++t_Error FmMacsecDeleteTxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ t_Error err = E_OK; ++ uint32_t tmpReg = 0, i, intFlags; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_TX_SC, E_INVALID_HANDLE); ++ ++ intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock); ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsanpn, 0x0); ++ for (i=0; i<4; i++) ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsak[i], 0x0); ++ ++ tmpReg |= TX_SACFG_ACTIVE; ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsacs, tmpReg); ++ ++ XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags); ++ ++ return err; ++} ++ ++t_Error FmMacsecRxSaSetReceive(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, bool enableReceive) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ t_Error err = E_OK; ++ uint32_t tmpReg = 0, intFlags; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE); ++ ++ intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock); ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId); ++ tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsacs); ++ if (enableReceive) ++ tmpReg |= RX_SACFG_EN_MASK; ++ else ++ tmpReg &= ~RX_SACFG_EN_MASK; ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsacs, tmpReg); ++ ++ XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags); ++ ++ return err; ++} ++ ++t_Error FmMacsecRxSaUpdateNextPn(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, uint32_t updtNextPN) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ t_Error err = E_OK; ++ uint32_t intFlags; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE); ++ ++ intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock); ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsanpn, updtNextPN); ++ ++ XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags); ++ ++ return err; ++} ++ ++t_Error FmMacsecRxSaUpdateLowestPn(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, uint32_t updtLowestPN) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ t_Error err = E_OK; ++ uint32_t intFlags; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE); ++ ++ intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock); ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId); ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsalpn, updtLowestPN); ++ ++ XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags); ++ ++ return err; ++} ++ ++t_Error FmMacsecTxSaSetActive(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecAN_t an) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ t_Error err = E_OK; ++ uint32_t tmpReg = 0, intFlags; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_TX_SC, E_INVALID_HANDLE); ++ ++ intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock); ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId); ++ ++ tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg); ++ ++ tmpReg |= ((an << TX_SCCFG_AN_SHIFT) & TX_SCCFG_AN_MASK); ++ tmpReg |= ((saId << TX_SCCFG_ASA_SHIFT) & TX_SCCFG_ASA_MASK); ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg, tmpReg); ++ ++ XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags); ++ ++ return err; ++} ++ ++t_Error FmMacsecTxSaGetActive(t_Handle h_FmMacsec, uint32_t scId, macsecAN_t *p_An) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ t_Error err = E_OK; ++ uint32_t tmpReg = 0, intFlags; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_An, E_INVALID_HANDLE); ++ ++ intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock); ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId); ++ ++ tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg); ++ ++ XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags); ++ ++ *p_An = (macsecAN_t)((tmpReg & TX_SCCFG_AN_MASK) >> TX_SCCFG_AN_SHIFT); ++ ++ return err; ++} ++ ++t_Error FmMacsecSetException(t_Handle h_FmMacsec, e_FmMacsecGlobalExceptions exception, uint32_t scId, bool enable) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ uint32_t bitMask; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ GET_EXCEPTION_FLAG(bitMask, exception, scId); ++ if (bitMask) ++ { ++ if (enable) ++ p_FmMacsec->exceptions |= bitMask; ++ else ++ p_FmMacsec->exceptions &= ~bitMask; ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->erer, p_FmMacsec->exceptions); ++ ++ return E_OK; ++} ++ ++t_Error FmMacsecSetEvent(t_Handle h_FmMacsec, e_FmMacsecGlobalEvents event, uint32_t scId, bool enable) ++{ ++ t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; ++ uint32_t bitMask; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); ++ ++ GET_EVENT_FLAG(bitMask, event, scId); ++ if (bitMask) ++ { ++ if (enable) ++ p_FmMacsec->events |= bitMask; ++ else ++ p_FmMacsec->events &= ~bitMask; ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined event")); ++ ++ WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->ever, p_FmMacsec->events); ++ ++ return E_OK; ++} ++ ++/****************************************/ ++/* API Init unit functions */ ++/****************************************/ ++t_Handle FM_MACSEC_MASTER_Config(t_FmMacsecParams *p_FmMacsecParam) ++{ ++ t_FmMacsec *p_FmMacsec; ++ uint32_t macId; ++ ++ /* Allocate FM MACSEC structure */ ++ p_FmMacsec = (t_FmMacsec *) XX_Malloc(sizeof(t_FmMacsec)); ++ if (!p_FmMacsec) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC driver structure")); ++ return NULL; ++ } ++ memset(p_FmMacsec, 0, sizeof(t_FmMacsec)); ++ InitFmMacsecControllerDriver(&p_FmMacsec->fmMacsecControllerDriver); ++ ++ /* Allocate the FM MACSEC driver's parameters structure */ ++ p_FmMacsec->p_FmMacsecDriverParam = (t_FmMacsecDriverParam *)XX_Malloc(sizeof(t_FmMacsecDriverParam)); ++ if (!p_FmMacsec->p_FmMacsecDriverParam) ++ { ++ XX_Free(p_FmMacsec); ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC driver parameters")); ++ return NULL; ++ } ++ memset(p_FmMacsec->p_FmMacsecDriverParam, 0, sizeof(t_FmMacsecDriverParam)); ++ ++ /* Initialize FM MACSEC parameters which will be kept by the driver */ ++ p_FmMacsec->h_Fm = p_FmMacsecParam->h_Fm; ++ p_FmMacsec->h_FmMac = p_FmMacsecParam->nonGuestParams.h_FmMac; ++ p_FmMacsec->p_FmMacsecRegs = (t_FmMacsecRegs *)UINT_TO_PTR(p_FmMacsecParam->nonGuestParams.baseAddr); ++ p_FmMacsec->f_Exception = p_FmMacsecParam->nonGuestParams.f_Exception; ++ p_FmMacsec->h_App = p_FmMacsecParam->nonGuestParams.h_App; ++ p_FmMacsec->userExceptions = DEFAULT_userExceptions; ++ p_FmMacsec->exceptions = DEFAULT_exceptions; ++ p_FmMacsec->events = DEFAULT_events; ++ p_FmMacsec->rxScSpinLock = XX_InitSpinlock(); ++ p_FmMacsec->txScSpinLock = XX_InitSpinlock(); ++ ++ /* Initialize FM MACSEC driver parameters parameters (for initialization phase only) */ ++ p_FmMacsec->p_FmMacsecDriverParam->unknownSciTreatMode = DEFAULT_unknownSciFrameTreatment; ++ p_FmMacsec->p_FmMacsecDriverParam->invalidTagsDeliverUncontrolled = DEFAULT_invalidTagsFrameTreatment; ++ p_FmMacsec->p_FmMacsecDriverParam->encryptWithNoChangedTextDiscardUncontrolled = DEFAULT_encryptWithNoChangedTextFrameTreatment; ++ p_FmMacsec->p_FmMacsecDriverParam->untagTreatMode = DEFAULT_untagFrameTreatment; ++ p_FmMacsec->p_FmMacsecDriverParam->keysUnreadable = DEFAULT_keysUnreadable; ++ p_FmMacsec->p_FmMacsecDriverParam->reservedSc0 = DEFAULT_sc0ReservedForPTP; ++ p_FmMacsec->p_FmMacsecDriverParam->byPassMode = !DEFAULT_normalMode; ++ p_FmMacsec->p_FmMacsecDriverParam->pnExhThr = DEFAULT_pnExhThr; ++ p_FmMacsec->p_FmMacsecDriverParam->sectagOverhead = DEFAULT_sectagOverhead; ++ p_FmMacsec->p_FmMacsecDriverParam->mflSubtract = DEFAULT_mflSubtract; ++ /* build the FM MACSEC master IPC address */ ++ memset(p_FmMacsec->fmMacsecModuleName, 0, (sizeof(char))*MODULE_NAME_SIZE); ++ FM_MAC_GetId(p_FmMacsec->h_FmMac,&macId); ++ if (Sprint (p_FmMacsec->fmMacsecModuleName, "FM-%d-MAC-%d-MACSEC-Master", ++ FmGetId(p_FmMacsec->h_Fm),macId) != 24) ++ { ++ XX_Free(p_FmMacsec->p_FmMacsecDriverParam); ++ XX_Free(p_FmMacsec); ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); ++ return NULL; ++ } ++ return p_FmMacsec; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.h +new file mode 100644 +index 00000000..2296a0f1 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.h +@@ -0,0 +1,479 @@ ++/* ++ * Copyright 2008-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/****************************************************************************** ++ @File fm_macsec_master.h ++ ++ @Description FM MACSEC internal structures and definitions. ++*//***************************************************************************/ ++#ifndef __FM_MACSEC_MASTER_H ++#define __FM_MACSEC_MASTER_H ++ ++#include "error_ext.h" ++#include "std_ext.h" ++ ++#include "fm_macsec.h" ++ ++ ++#define MACSEC_ICV_SIZE 16 ++#define MACSEC_SECTAG_SIZE 16 ++#define MACSEC_SCI_SIZE 8 ++#define MACSEC_FCS_SIZE 4 ++ ++/**************************************************************************//** ++ @Description Exceptions ++*//***************************************************************************/ ++ ++#define FM_MACSEC_EX_TX_SC_0 0x80000000 ++#define FM_MACSEC_EX_TX_SC(sc) (FM_MACSEC_EX_TX_SC_0 >> (sc)) ++#define FM_MACSEC_EX_ECC 0x00000001 ++ ++#define GET_EXCEPTION_FLAG(bitMask, exception, id) switch (exception){ \ ++ case e_FM_MACSEC_EX_TX_SC: \ ++ bitMask = FM_MACSEC_EX_TX_SC(id); break; \ ++ case e_FM_MACSEC_EX_ECC: \ ++ bitMask = FM_MACSEC_EX_ECC; break; \ ++ default: bitMask = 0;break;} ++ ++#define FM_MACSEC_USER_EX_SINGLE_BIT_ECC 0x80000000 ++#define FM_MACSEC_USER_EX_MULTI_BIT_ECC 0x40000000 ++ ++#define GET_USER_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \ ++ case e_FM_MACSEC_EX_SINGLE_BIT_ECC: \ ++ bitMask = FM_MACSEC_USER_EX_SINGLE_BIT_ECC; break; \ ++ case e_FM_MACSEC_EX_MULTI_BIT_ECC: \ ++ bitMask = FM_MACSEC_USER_EX_MULTI_BIT_ECC; break; \ ++ default: bitMask = 0;break;} ++ ++/**************************************************************************//** ++ @Description Events ++*//***************************************************************************/ ++ ++#define FM_MACSEC_EV_TX_SC_0_NEXT_PN 0x80000000 ++#define FM_MACSEC_EV_TX_SC_NEXT_PN(sc) (FM_MACSEC_EV_TX_SC_0_NEXT_PN >> (sc)) ++ ++#define GET_EVENT_FLAG(bitMask, event, id) switch (event){ \ ++ case e_FM_MACSEC_EV_TX_SC_NEXT_PN: \ ++ bitMask = FM_MACSEC_EV_TX_SC_NEXT_PN(id); break; \ ++ default: bitMask = 0;break;} ++ ++/**************************************************************************//** ++ @Description Defaults ++*//***************************************************************************/ ++#define DEFAULT_userExceptions (FM_MACSEC_USER_EX_SINGLE_BIT_ECC |\ ++ FM_MACSEC_USER_EX_MULTI_BIT_ECC) ++ ++#define DEFAULT_exceptions (FM_MACSEC_EX_TX_SC(0) |\ ++ FM_MACSEC_EX_TX_SC(1) |\ ++ FM_MACSEC_EX_TX_SC(2) |\ ++ FM_MACSEC_EX_TX_SC(3) |\ ++ FM_MACSEC_EX_TX_SC(4) |\ ++ FM_MACSEC_EX_TX_SC(5) |\ ++ FM_MACSEC_EX_TX_SC(6) |\ ++ FM_MACSEC_EX_TX_SC(7) |\ ++ FM_MACSEC_EX_TX_SC(8) |\ ++ FM_MACSEC_EX_TX_SC(9) |\ ++ FM_MACSEC_EX_TX_SC(10) |\ ++ FM_MACSEC_EX_TX_SC(11) |\ ++ FM_MACSEC_EX_TX_SC(12) |\ ++ FM_MACSEC_EX_TX_SC(13) |\ ++ FM_MACSEC_EX_TX_SC(14) |\ ++ FM_MACSEC_EX_TX_SC(15) |\ ++ FM_MACSEC_EX_ECC ) ++ ++#define DEFAULT_events (FM_MACSEC_EV_TX_SC_NEXT_PN(0) |\ ++ FM_MACSEC_EV_TX_SC_NEXT_PN(1) |\ ++ FM_MACSEC_EV_TX_SC_NEXT_PN(2) |\ ++ FM_MACSEC_EV_TX_SC_NEXT_PN(3) |\ ++ FM_MACSEC_EV_TX_SC_NEXT_PN(4) |\ ++ FM_MACSEC_EV_TX_SC_NEXT_PN(5) |\ ++ FM_MACSEC_EV_TX_SC_NEXT_PN(6) |\ ++ FM_MACSEC_EV_TX_SC_NEXT_PN(7) |\ ++ FM_MACSEC_EV_TX_SC_NEXT_PN(8) |\ ++ FM_MACSEC_EV_TX_SC_NEXT_PN(9) |\ ++ FM_MACSEC_EV_TX_SC_NEXT_PN(10) |\ ++ FM_MACSEC_EV_TX_SC_NEXT_PN(11) |\ ++ FM_MACSEC_EV_TX_SC_NEXT_PN(12) |\ ++ FM_MACSEC_EV_TX_SC_NEXT_PN(13) |\ ++ FM_MACSEC_EV_TX_SC_NEXT_PN(14) |\ ++ FM_MACSEC_EV_TX_SC_NEXT_PN(15) ) ++ ++#define DEFAULT_unknownSciFrameTreatment e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DISCARD_BOTH ++#define DEFAULT_invalidTagsFrameTreatment FALSE ++#define DEFAULT_encryptWithNoChangedTextFrameTreatment FALSE ++#define DEFAULT_untagFrameTreatment e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DELIVER_UNCONTROLLED_DISCARD_CONTROLLED ++#define DEFAULT_changedTextWithNoEncryptFrameTreatment FALSE ++#define DEFAULT_onlyScbIsSetFrameTreatment FALSE ++#define DEFAULT_keysUnreadable FALSE ++#define DEFAULT_normalMode TRUE ++#define DEFAULT_sc0ReservedForPTP FALSE ++#define DEFAULT_initNextPn 1 ++#define DEFAULT_pnExhThr 0xffffffff ++#define DEFAULT_sectagOverhead (MACSEC_ICV_SIZE + MACSEC_SECTAG_SIZE) ++#define DEFAULT_mflSubtract MACSEC_FCS_SIZE ++ ++ ++/**************************************************************************//** ++ @Description Memory Mapped Registers ++*//***************************************************************************/ ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(push,1) ++#endif /* defined(__MWERKS__) && ... */ ++ ++typedef _Packed struct ++{ ++ /* MACsec configuration */ ++ volatile uint32_t cfg; /**< MACsec configuration */ ++ volatile uint32_t et; /**< MACsec EtherType */ ++ volatile uint8_t res1[56]; /**< reserved */ ++ volatile uint32_t mfl; /**< Maximum Frame Length */ ++ volatile uint32_t tpnet; /**< TX Packet Number exhaustion threshold */ ++ volatile uint8_t res2[56]; /**< reserved */ ++ volatile uint32_t rxsca; /**< RX SC access select */ ++ volatile uint8_t res3[60]; /**< reserved */ ++ volatile uint32_t txsca; /**< TX SC access select */ ++ volatile uint8_t res4[60]; /**< reserved */ ++ ++ /* RX configuration, status and statistic */ ++ volatile uint32_t rxsci1h; /**< RX Secure Channel Identifier first half */ ++ volatile uint32_t rxsci2h; /**< RX Secure Channel Identifier second half */ ++ volatile uint8_t res5[8]; /**< reserved */ ++ volatile uint32_t ifio1hs; /**< ifInOctets first half Statistic */ ++ volatile uint32_t ifio2hs; /**< ifInOctets second half Statistic */ ++ volatile uint32_t ifiups; /**< ifInUcastPkts Statistic */ ++ volatile uint8_t res6[4]; /**< reserved */ ++ volatile uint32_t ifimps; /**< ifInMulticastPkts Statistic */ ++ volatile uint32_t ifibps; /**< ifInBroadcastPkts Statistic */ ++ volatile uint32_t rxsccfg; /**< RX Secure Channel configuration */ ++ volatile uint32_t rpw; /**< replayWindow */ ++ volatile uint8_t res7[16]; /**< reserved */ ++ volatile uint32_t inov1hs; /**< InOctetsValidated first half Statistic */ ++ volatile uint32_t inov2hs; /**< InOctetsValidated second half Statistic */ ++ volatile uint32_t inod1hs; /**< InOctetsDecrypted first half Statistic */ ++ volatile uint32_t inod2hs; /**< InOctetsDecrypted second half Statistic */ ++ volatile uint32_t rxscipus; /**< RX Secure Channel InPktsUnchecked Statistic */ ++ volatile uint32_t rxscipds; /**< RX Secure Channel InPktsDelayed Statistic */ ++ volatile uint32_t rxscipls; /**< RX Secure Channel InPktsLate Statistic */ ++ volatile uint8_t res8[4]; /**< reserved */ ++ volatile uint32_t rxaninuss[MAX_NUM_OF_SA_PER_SC]; /**< RX AN 0-3 InNotUsingSA Statistic */ ++ volatile uint32_t rxanipuss[MAX_NUM_OF_SA_PER_SC]; /**< RX AN 0-3 InPktsUnusedSA Statistic */ ++ _Packed struct ++ { ++ volatile uint32_t rxsacs; /**< RX Security Association configuration and status */ ++ volatile uint32_t rxsanpn; /**< RX Security Association nextPN */ ++ volatile uint32_t rxsalpn; /**< RX Security Association lowestPN */ ++ volatile uint32_t rxsaipos; /**< RX Security Association InPktsOK Statistic */ ++ volatile uint32_t rxsak[4]; /**< RX Security Association key (128 bit) */ ++ volatile uint32_t rxsah[4]; /**< RX Security Association hash (128 bit) */ ++ volatile uint32_t rxsaipis; /**< RX Security Association InPktsInvalid Statistic */ ++ volatile uint32_t rxsaipnvs; /**< RX Security Association InPktsNotValid Statistic */ ++ volatile uint8_t res9[8]; /**< reserved */ ++ } _PackedType fmMacsecRxScSa[NUM_OF_SA_PER_RX_SC]; ++ ++ /* TX configuration, status and statistic */ ++ volatile uint32_t txsci1h; /**< TX Secure Channel Identifier first half */ ++ volatile uint32_t txsci2h; /**< TX Secure Channel Identifier second half */ ++ volatile uint8_t res10[8]; /**< reserved */ ++ volatile uint32_t ifoo1hs; /**< ifOutOctets first half Statistic */ ++ volatile uint32_t ifoo2hs; /**< ifOutOctets second half Statistic */ ++ volatile uint32_t ifoups; /**< ifOutUcastPkts Statistic */ ++ volatile uint32_t opus; /**< OutPktsUntagged Statistic */ ++ volatile uint32_t ifomps; /**< ifOutMulticastPkts Statistic */ ++ volatile uint32_t ifobps; /**< ifOutBroadcastPkts Statistic */ ++ volatile uint32_t txsccfg; /**< TX Secure Channel configuration */ ++ volatile uint32_t optls; /**< OutPktsTooLong Statistic */ ++ volatile uint8_t res11[16]; /**< reserved */ ++ volatile uint32_t oop1hs; /**< OutOctetsProtected first half Statistic */ ++ volatile uint32_t oop2hs; /**< OutOctetsProtected second half Statistic */ ++ volatile uint32_t ooe1hs; /**< OutOctetsEncrypted first half Statistic */ ++ volatile uint32_t ooe2hs; /**< OutOctetsEncrypted second half Statistic */ ++ volatile uint8_t res12[48]; /**< reserved */ ++ _Packed struct ++ { ++ volatile uint32_t txsacs; /**< TX Security Association configuration and status */ ++ volatile uint32_t txsanpn; /**< TX Security Association nextPN */ ++ volatile uint32_t txsaopps; /**< TX Security Association OutPktsProtected Statistic */ ++ volatile uint32_t txsaopes; /**< TX Security Association OutPktsEncrypted Statistic */ ++ volatile uint32_t txsak[4]; /**< TX Security Association key (128 bit) */ ++ volatile uint32_t txsah[4]; /**< TX Security Association hash (128 bit) */ ++ volatile uint8_t res13[16]; /**< reserved */ ++ } _PackedType fmMacsecTxScSa[NUM_OF_SA_PER_TX_SC]; ++ volatile uint8_t res14[248]; /**< reserved */ ++ ++ /* Global configuration and status */ ++ volatile uint32_t ip_rev1; /**< MACsec IP Block Revision 1 register */ ++ volatile uint32_t ip_rev2; /**< MACsec IP Block Revision 2 register */ ++ volatile uint32_t evr; /**< MACsec Event Register */ ++ volatile uint32_t ever; /**< MACsec Event Enable Register */ ++ volatile uint32_t evfr; /**< MACsec Event Force Register */ ++ volatile uint32_t err; /**< MACsec Error Register */ ++ volatile uint32_t erer; /**< MACsec Error Enable Register */ ++ volatile uint32_t erfr; /**< MACsec Error Force Register */ ++ volatile uint8_t res15[40]; /**< reserved */ ++ volatile uint32_t meec; /**< MACsec Memory ECC Error Capture Register */ ++ volatile uint32_t idle; /**< MACsec Idle status Register */ ++ volatile uint8_t res16[184]; /**< reserved */ ++ /* DEBUG */ ++ volatile uint32_t rxec; /**< MACsec RX error capture Register */ ++ volatile uint8_t res17[28]; /**< reserved */ ++ volatile uint32_t txec; /**< MACsec TX error capture Register */ ++ volatile uint8_t res18[220]; /**< reserved */ ++ ++ /* Macsec Rx global statistic */ ++ volatile uint32_t ifiocp1hs; /**< ifInOctetsCp first half Statistic */ ++ volatile uint32_t ifiocp2hs; /**< ifInOctetsCp second half Statistic */ ++ volatile uint32_t ifiupcps; /**< ifInUcastPktsCp Statistic */ ++ volatile uint8_t res19[4]; /**< reserved */ ++ volatile uint32_t ifioup1hs; /**< ifInOctetsUp first half Statistic */ ++ volatile uint32_t ifioup2hs; /**< ifInOctetsUp second half Statistic */ ++ volatile uint32_t ifiupups; /**< ifInUcastPktsUp Statistic */ ++ volatile uint8_t res20[4]; /**< reserved */ ++ volatile uint32_t ifimpcps; /**< ifInMulticastPktsCp Statistic */ ++ volatile uint32_t ifibpcps; /**< ifInBroadcastPktsCp Statistic */ ++ volatile uint32_t ifimpups; /**< ifInMulticastPktsUp Statistic */ ++ volatile uint32_t ifibpups; /**< ifInBroadcastPktsUp Statistic */ ++ volatile uint32_t ipwts; /**< InPktsWithoutTag Statistic */ ++ volatile uint32_t ipkays; /**< InPktsKaY Statistic */ ++ volatile uint32_t ipbts; /**< InPktsBadTag Statistic */ ++ volatile uint32_t ipsnfs; /**< InPktsSCINotFound Statistic */ ++ volatile uint32_t ipuecs; /**< InPktsUnsupportedEC Statistic */ ++ volatile uint32_t ipescbs; /**< InPktsEponSingleCopyBroadcast Statistic */ ++ volatile uint32_t iptls; /**< InPktsTooLong Statistic */ ++ volatile uint8_t res21[52]; /**< reserved */ ++ ++ /* Macsec Tx global statistic */ ++ volatile uint32_t opds; /**< OutPktsDiscarded Statistic */ ++#if (DPAA_VERSION >= 11) ++ volatile uint8_t res22[124]; /**< reserved */ ++ _Packed struct ++ { ++ volatile uint32_t rxsak[8]; /**< RX Security Association key (128/256 bit) */ ++ volatile uint8_t res23[32]; /**< reserved */ ++ } _PackedType rxScSaKey[NUM_OF_SA_PER_RX_SC]; ++ _Packed struct ++ { ++ volatile uint32_t txsak[8]; /**< TX Security Association key (128/256 bit) */ ++ volatile uint8_t res24[32]; /**< reserved */ ++ } _PackedType txScSaKey[NUM_OF_SA_PER_TX_SC]; ++#endif /* (DPAA_VERSION >= 11) */ ++} _PackedType t_FmMacsecRegs; ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(pop) ++#endif /* defined(__MWERKS__) && ... */ ++ ++ ++/**************************************************************************//** ++ @Description General defines ++*//***************************************************************************/ ++ ++#define SCI_HIGH_MASK 0xffffffff00000000LL ++#define SCI_LOW_MASK 0x00000000ffffffffLL ++ ++#define LONG_SHIFT 32 ++ ++#define GET_SCI_FIRST_HALF(sci) (uint32_t)((macsecSCI_t)((macsecSCI_t)(sci) & SCI_HIGH_MASK) >> LONG_SHIFT) ++#define GET_SCI_SECOND_HALF(sci) (uint32_t)((macsecSCI_t)(sci) & SCI_LOW_MASK) ++ ++/**************************************************************************//** ++ @Description Configuration defines ++*//***************************************************************************/ ++ ++/* masks */ ++#define CFG_UECT 0x00000800 ++#define CFG_ESCBT 0x00000400 ++#define CFG_USFT 0x00000300 ++#define CFG_ITT 0x00000080 ++#define CFG_KFT 0x00000040 ++#define CFG_UFT 0x00000030 ++#define CFG_KSS 0x00000004 ++#define CFG_BYPN 0x00000002 ++#define CFG_S0I 0x00000001 ++ ++#define ET_TYPE 0x0000ffff ++ ++#define MFL_MAX_LEN 0x0000ffff ++ ++#define RXSCA_SC_SEL 0x0000000f ++ ++#define TXSCA_SC_SEL 0x0000000f ++ ++#define IP_REV_1_IP_ID 0xffff0000 ++#define IP_REV_1_IP_MJ 0x0000ff00 ++#define IP_REV_1_IP_MM 0x000000ff ++ ++#define IP_REV_2_IP_INT 0x00ff0000 ++#define IP_REV_2_IP_ERR 0x0000ff00 ++#define IP_REV_2_IP_CFG 0x000000ff ++ ++#define MECC_CAP 0x80000000 ++#define MECC_CET 0x40000000 ++#define MECC_SERCNT 0x00ff0000 ++#define MECC_MEMADDR 0x000001ff ++ ++/* shifts */ ++#define CFG_UECT_SHIFT (31-20) ++#define CFG_ESCBT_SHIFT (31-21) ++#define CFG_USFT_SHIFT (31-23) ++#define CFG_ITT_SHIFT (31-24) ++#define CFG_KFT_SHIFT (31-25) ++#define CFG_UFT_SHIFT (31-27) ++#define CFG_KSS_SHIFT (31-29) ++#define CFG_BYPN_SHIFT (31-30) ++#define CFG_S0I_SHIFT (31-31) ++ ++#define IP_REV_1_IP_ID_SHIFT (31-15) ++#define IP_REV_1_IP_MJ_SHIFT (31-23) ++#define IP_REV_1_IP_MM_SHIFT (31-31) ++ ++#define IP_REV_2_IP_INT_SHIFT (31-15) ++#define IP_REV_2_IP_ERR_SHIFT (31-23) ++#define IP_REV_2_IP_CFG_SHIFT (31-31) ++ ++#define MECC_CAP_SHIFT (31-0) ++#define MECC_CET_SHIFT (31-1) ++#define MECC_SERCNT_SHIFT (31-15) ++#define MECC_MEMADDR_SHIFT (31-31) ++ ++/**************************************************************************//** ++ @Description RX SC defines ++*//***************************************************************************/ ++ ++/* masks */ ++#define RX_SCCFG_SCI_EN_MASK 0x00000800 ++#define RX_SCCFG_RP_MASK 0x00000400 ++#define RX_SCCFG_VF_MASK 0x00000300 ++#define RX_SCCFG_CO_MASK 0x0000003f ++ ++/* shifts */ ++#define RX_SCCFG_SCI_EN_SHIFT (31-20) ++#define RX_SCCFG_RP_SHIFT (31-21) ++#define RX_SCCFG_VF_SHIFT (31-23) ++#define RX_SCCFG_CO_SHIFT (31-31) ++#define RX_SCCFG_CS_SHIFT (31-7) ++ ++/**************************************************************************//** ++ @Description RX SA defines ++*//***************************************************************************/ ++ ++/* masks */ ++#define RX_SACFG_ACTIVE 0x80000000 ++#define RX_SACFG_AN_MASK 0x00000006 ++#define RX_SACFG_EN_MASK 0x00000001 ++ ++/* shifts */ ++#define RX_SACFG_AN_SHIFT (31-30) ++#define RX_SACFG_EN_SHIFT (31-31) ++ ++/**************************************************************************//** ++ @Description TX SC defines ++*//***************************************************************************/ ++ ++/* masks */ ++#define TX_SCCFG_AN_MASK 0x000c0000 ++#define TX_SCCFG_ASA_MASK 0x00020000 ++#define TX_SCCFG_SCE_MASK 0x00010000 ++#define TX_SCCFG_CO_MASK 0x00003f00 ++#define TX_SCCFG_CE_MASK 0x00000010 ++#define TX_SCCFG_PF_MASK 0x00000008 ++#define TX_SCCFG_AIS_MASK 0x00000004 ++#define TX_SCCFG_UES_MASK 0x00000002 ++#define TX_SCCFG_USCB_MASK 0x00000001 ++ ++/* shifts */ ++#define TX_SCCFG_AN_SHIFT (31-13) ++#define TX_SCCFG_ASA_SHIFT (31-14) ++#define TX_SCCFG_SCE_SHIFT (31-15) ++#define TX_SCCFG_CO_SHIFT (31-23) ++#define TX_SCCFG_CE_SHIFT (31-27) ++#define TX_SCCFG_PF_SHIFT (31-28) ++#define TX_SCCFG_AIS_SHIFT (31-29) ++#define TX_SCCFG_UES_SHIFT (31-30) ++#define TX_SCCFG_USCB_SHIFT (31-31) ++#define TX_SCCFG_CS_SHIFT (31-7) ++ ++/**************************************************************************//** ++ @Description TX SA defines ++*//***************************************************************************/ ++ ++/* masks */ ++#define TX_SACFG_ACTIVE 0x80000000 ++ ++ ++typedef struct ++{ ++ void (*f_Isr) (t_Handle h_Arg, uint32_t id); ++ t_Handle h_SrcHandle; ++} t_FmMacsecIntrSrc; ++ ++typedef struct ++{ ++ e_FmMacsecUnknownSciFrameTreatment unknownSciTreatMode; ++ bool invalidTagsDeliverUncontrolled; ++ bool changedTextWithNoEncryptDeliverUncontrolled; ++ bool onlyScbIsSetDeliverUncontrolled; ++ bool encryptWithNoChangedTextDiscardUncontrolled; ++ e_FmMacsecUntagFrameTreatment untagTreatMode; ++ uint32_t pnExhThr; ++ bool keysUnreadable; ++ bool byPassMode; ++ bool reservedSc0; ++ uint32_t sectagOverhead; ++ uint32_t mflSubtract; ++} t_FmMacsecDriverParam; ++ ++typedef struct ++{ ++ t_FmMacsecControllerDriver fmMacsecControllerDriver; ++ t_Handle h_Fm; ++ t_FmMacsecRegs *p_FmMacsecRegs; ++ t_Handle h_FmMac; /**< A handle to the FM MAC object related to */ ++ char fmMacsecModuleName[MODULE_NAME_SIZE]; ++ t_FmMacsecIntrSrc intrMng[NUM_OF_INTER_MODULE_EVENTS]; ++ uint32_t events; ++ uint32_t exceptions; ++ uint32_t userExceptions; ++ t_FmMacsecExceptionsCallback *f_Exception; /**< Exception Callback Routine */ ++ t_Handle h_App; /**< A handle to an application layer object; This handle will ++ be passed by the driver upon calling the above callbacks */ ++ bool rxScTable[NUM_OF_RX_SC]; ++ uint32_t numRxScAvailable; ++ bool txScTable[NUM_OF_TX_SC]; ++ uint32_t numTxScAvailable; ++ t_Handle rxScSpinLock; ++ t_Handle txScSpinLock; ++ t_FmMacsecDriverParam *p_FmMacsecDriverParam; ++} t_FmMacsec; ++ ++ ++#endif /* __FM_MACSEC_MASTER_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.c +new file mode 100644 +index 00000000..7c72dc98 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.c +@@ -0,0 +1,883 @@ ++/* ++ * Copyright 2008-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/****************************************************************************** ++ @File fm_macsec_secy.c ++ ++ @Description FM MACSEC SECY driver routines implementation. ++*//***************************************************************************/ ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "xx_ext.h" ++#include "string_ext.h" ++#include "sprint_ext.h" ++ ++#include "fm_macsec_secy.h" ++ ++ ++/****************************************/ ++/* static functions */ ++/****************************************/ ++static void FmMacsecSecYExceptionsIsr(t_Handle h_FmMacsecSecY, uint32_t id) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ ++ UNUSED(id); ++ SANITY_CHECK_RETURN(p_FmMacsecSecY, E_INVALID_HANDLE); ++ ++ if (p_FmMacsecSecY->exceptions & FM_MACSEC_SECY_EX_FRAME_DISCARDED) ++ p_FmMacsecSecY->f_Exception(p_FmMacsecSecY->h_App, e_FM_MACSEC_SECY_EX_FRAME_DISCARDED); ++} ++ ++static void FmMacsecSecYEventsIsr(t_Handle h_FmMacsecSecY, uint32_t id) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ ++ UNUSED(id); ++ SANITY_CHECK_RETURN(p_FmMacsecSecY, E_INVALID_HANDLE); ++ ++ if (p_FmMacsecSecY->events & FM_MACSEC_SECY_EV_NEXT_PN) ++ p_FmMacsecSecY->f_Event(p_FmMacsecSecY->h_App, e_FM_MACSEC_SECY_EV_NEXT_PN); ++} ++ ++static t_Error CheckFmMacsecSecYParameters(t_FmMacsecSecY *p_FmMacsecSecY) ++{ ++ if (!p_FmMacsecSecY->f_Exception) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided")); ++ ++ if (!p_FmMacsecSecY->f_Event) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Events callback not provided")); ++ ++ if (!p_FmMacsecSecY->numOfRxSc) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Num of Rx Scs must be greater than '0'")); ++ ++ ++ return E_OK; ++} ++ ++static t_Handle FmMacsecSecYCreateSc(t_FmMacsecSecY *p_FmMacsecSecY, ++ macsecSCI_t sci, ++ e_FmMacsecSecYCipherSuite cipherSuite, ++ e_ScType type) ++{ ++ t_SecYSc *p_ScTable; ++ void *p_Params; ++ uint32_t numOfSc,i; ++ t_Error err = E_OK; ++ t_RxScParams rxScParams; ++ t_TxScParams txScParams; ++ ++ ASSERT_COND(p_FmMacsecSecY); ++ ASSERT_COND(p_FmMacsecSecY->h_FmMacsec); ++ ++ if (type == e_SC_RX) ++ { ++ memset(&rxScParams, 0, sizeof(rxScParams)); ++ i = (NUM_OF_RX_SC - 1); ++ p_ScTable = p_FmMacsecSecY->p_RxSc; ++ numOfSc = p_FmMacsecSecY->numOfRxSc; ++ rxScParams.confidentialityOffset = p_FmMacsecSecY->confidentialityOffset; ++ rxScParams.replayProtect = p_FmMacsecSecY->replayProtect; ++ rxScParams.replayWindow = p_FmMacsecSecY->replayWindow; ++ rxScParams.validateFrames = p_FmMacsecSecY->validateFrames; ++ rxScParams.cipherSuite = cipherSuite; ++ p_Params = &rxScParams; ++ } ++ else ++ { ++ memset(&txScParams, 0, sizeof(txScParams)); ++ i = (NUM_OF_TX_SC - 1); ++ p_ScTable = p_FmMacsecSecY->p_TxSc; ++ numOfSc = p_FmMacsecSecY->numOfTxSc; ++ txScParams.sciInsertionMode = p_FmMacsecSecY->sciInsertionMode; ++ txScParams.protectFrames = p_FmMacsecSecY->protectFrames; ++ txScParams.confidentialityEnable = p_FmMacsecSecY->confidentialityEnable; ++ txScParams.confidentialityOffset = p_FmMacsecSecY->confidentialityOffset; ++ txScParams.cipherSuite = cipherSuite; ++ p_Params = &txScParams; ++ } ++ ++ for (i=0;iscId = p_ScTable[i].scId; ++ ((t_RxScParams *)p_Params)->sci = sci; ++ if ((err = FmMacsecCreateRxSc(p_FmMacsecSecY->h_FmMacsec, (t_RxScParams *)p_Params)) != E_OK) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY RX SC")); ++ return NULL; ++ } ++ } ++ else ++ { ++ ((t_TxScParams *)p_Params)->scId = p_ScTable[i].scId; ++ ((t_TxScParams *)p_Params)->sci = sci; ++ if ((err = FmMacsecCreateTxSc(p_FmMacsecSecY->h_FmMacsec, (t_TxScParams *)p_Params)) != E_OK) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY TX SC")); ++ return NULL; ++ } ++ } ++ ++ p_ScTable[i].inUse = TRUE; ++ return &p_ScTable[i]; ++} ++ ++static t_Error FmMacsecSecYDeleteSc(t_FmMacsecSecY *p_FmMacsecSecY, t_SecYSc *p_FmSecYSc, e_ScType type) ++{ ++ t_Error err = E_OK; ++ ++ ASSERT_COND(p_FmMacsecSecY); ++ ASSERT_COND(p_FmMacsecSecY->h_FmMacsec); ++ ASSERT_COND(p_FmSecYSc); ++ ++ if (type == e_SC_RX) ++ { ++ if ((err = FmMacsecDeleteRxSc(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ else ++ if ((err = FmMacsecDeleteTxSc(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ p_FmSecYSc->inUse = FALSE; ++ ++ return err; ++} ++ ++/****************************************/ ++/* API Init unit functions */ ++/****************************************/ ++t_Handle FM_MACSEC_SECY_Config(t_FmMacsecSecYParams *p_FmMacsecSecYParam) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY; ++ ++ /* Allocate FM MACSEC structure */ ++ p_FmMacsecSecY = (t_FmMacsecSecY *) XX_Malloc(sizeof(t_FmMacsecSecY)); ++ if (!p_FmMacsecSecY) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY driver structure")); ++ return NULL; ++ } ++ memset(p_FmMacsecSecY, 0, sizeof(t_FmMacsecSecY)); ++ ++ /* Allocate the FM MACSEC driver's parameters structure */ ++ p_FmMacsecSecY->p_FmMacsecSecYDriverParam = (t_FmMacsecSecYDriverParam *)XX_Malloc(sizeof(t_FmMacsecSecYDriverParam)); ++ if (!p_FmMacsecSecY->p_FmMacsecSecYDriverParam) ++ { ++ XX_Free(p_FmMacsecSecY); ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY driver parameters")); ++ return NULL; ++ } ++ memset(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, 0, sizeof(t_FmMacsecSecYDriverParam)); ++ ++ /* Initialize FM MACSEC SECY parameters which will be kept by the driver */ ++ p_FmMacsecSecY->h_FmMacsec = p_FmMacsecSecYParam->h_FmMacsec; ++ p_FmMacsecSecY->f_Event = p_FmMacsecSecYParam->f_Event; ++ p_FmMacsecSecY->f_Exception = p_FmMacsecSecYParam->f_Exception; ++ p_FmMacsecSecY->h_App = p_FmMacsecSecYParam->h_App; ++ p_FmMacsecSecY->confidentialityEnable = DEFAULT_confidentialityEnable; ++ p_FmMacsecSecY->confidentialityOffset = DEFAULT_confidentialityOffset; ++ p_FmMacsecSecY->validateFrames = DEFAULT_validateFrames; ++ p_FmMacsecSecY->replayProtect = DEFAULT_replayEnable; ++ p_FmMacsecSecY->replayWindow = DEFAULT_replayWindow; ++ p_FmMacsecSecY->protectFrames = DEFAULT_protectFrames; ++ p_FmMacsecSecY->sciInsertionMode = DEFAULT_sciInsertionMode; ++ p_FmMacsecSecY->isPointToPoint = DEFAULT_ptp; ++ p_FmMacsecSecY->numOfRxSc = p_FmMacsecSecYParam->numReceiveChannels; ++ p_FmMacsecSecY->numOfTxSc = DEFAULT_numOfTxSc; ++ p_FmMacsecSecY->exceptions = DEFAULT_exceptions; ++ p_FmMacsecSecY->events = DEFAULT_events; ++ ++ memcpy(&p_FmMacsecSecY->p_FmMacsecSecYDriverParam->txScParams, ++ &p_FmMacsecSecYParam->txScParams, ++ sizeof(t_FmMacsecSecYSCParams)); ++ return p_FmMacsecSecY; ++} ++ ++t_Error FM_MACSEC_SECY_Init(t_Handle h_FmMacsecSecY) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ t_FmMacsecSecYDriverParam *p_FmMacsecSecYDriverParam = NULL; ++ uint32_t rxScIds[NUM_OF_RX_SC], txScIds[NUM_OF_TX_SC], i, j; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_HANDLE); ++ ++ CHECK_INIT_PARAMETERS(p_FmMacsecSecY, CheckFmMacsecSecYParameters); ++ ++ p_FmMacsecSecYDriverParam = p_FmMacsecSecY->p_FmMacsecSecYDriverParam; ++ ++ if ((p_FmMacsecSecY->isPointToPoint) && ++ ((err = FmMacsecSetPTP(p_FmMacsecSecY->h_FmMacsec, TRUE)) != E_OK)) ++ RETURN_ERROR(MAJOR, err, ("Can't set Poin-to-Point")); ++ ++ /* Rx Sc Allocation */ ++ p_FmMacsecSecY->p_RxSc = (t_SecYSc *)XX_Malloc(sizeof(t_SecYSc) * p_FmMacsecSecY->numOfRxSc); ++ if (!p_FmMacsecSecY->p_RxSc) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY RX SC")); ++ memset(p_FmMacsecSecY->p_RxSc, 0, sizeof(t_SecYSc) * p_FmMacsecSecY->numOfRxSc); ++ if ((err = FmMacsecAllocScs(p_FmMacsecSecY->h_FmMacsec, e_SC_RX, p_FmMacsecSecY->isPointToPoint, p_FmMacsecSecY->numOfRxSc, rxScIds)) != E_OK) ++ { ++ if (p_FmMacsecSecY->p_TxSc) ++ XX_Free(p_FmMacsecSecY->p_TxSc); ++ if (p_FmMacsecSecY->p_RxSc) ++ XX_Free(p_FmMacsecSecY->p_RxSc); ++ return ERROR_CODE(err); ++ } ++ for (i=0; inumOfRxSc; i++) ++ { ++ p_FmMacsecSecY->p_RxSc[i].scId = rxScIds[i]; ++ p_FmMacsecSecY->p_RxSc[i].type = e_SC_RX; ++ for (j=0; jp_RxSc[i].sa[j].saId = (e_ScSaId)SECY_AN_FREE_VALUE; ++ } ++ ++ /* Tx Sc Allocation */ ++ p_FmMacsecSecY->p_TxSc = (t_SecYSc *)XX_Malloc(sizeof(t_SecYSc) * p_FmMacsecSecY->numOfTxSc); ++ if (!p_FmMacsecSecY->p_TxSc) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY TX SC")); ++ memset(p_FmMacsecSecY->p_TxSc, 0, sizeof(t_SecYSc) * p_FmMacsecSecY->numOfTxSc); ++ ++ if ((err = FmMacsecAllocScs(p_FmMacsecSecY->h_FmMacsec, e_SC_TX, p_FmMacsecSecY->isPointToPoint, p_FmMacsecSecY->numOfTxSc, txScIds)) != E_OK) ++ { ++ if (p_FmMacsecSecY->p_TxSc) ++ XX_Free(p_FmMacsecSecY->p_TxSc); ++ if (p_FmMacsecSecY->p_RxSc) ++ XX_Free(p_FmMacsecSecY->p_RxSc); ++ return ERROR_CODE(err); ++ } ++ for (i=0; inumOfTxSc; i++) ++ { ++ p_FmMacsecSecY->p_TxSc[i].scId = txScIds[i]; ++ p_FmMacsecSecY->p_TxSc[i].type = e_SC_TX; ++ for (j=0; jp_TxSc[i].sa[j].saId = (e_ScSaId)SECY_AN_FREE_VALUE; ++ FmMacsecRegisterIntr(p_FmMacsecSecY->h_FmMacsec, ++ e_FM_MACSEC_MOD_SC_TX, ++ (uint8_t)txScIds[i], ++ e_FM_INTR_TYPE_ERR, ++ FmMacsecSecYExceptionsIsr, ++ p_FmMacsecSecY); ++ FmMacsecRegisterIntr(p_FmMacsecSecY->h_FmMacsec, ++ e_FM_MACSEC_MOD_SC_TX, ++ (uint8_t)txScIds[i], ++ e_FM_INTR_TYPE_NORMAL, ++ FmMacsecSecYEventsIsr, ++ p_FmMacsecSecY); ++ ++ if (p_FmMacsecSecY->exceptions & FM_MACSEC_SECY_EX_FRAME_DISCARDED) ++ FmMacsecSetException(p_FmMacsecSecY->h_FmMacsec, e_FM_MACSEC_EX_TX_SC, txScIds[i], TRUE); ++ if (p_FmMacsecSecY->events & FM_MACSEC_SECY_EV_NEXT_PN) ++ FmMacsecSetEvent(p_FmMacsecSecY->h_FmMacsec, e_FM_MACSEC_EV_TX_SC_NEXT_PN, txScIds[i], TRUE); ++ } ++ ++ FmMacsecSecYCreateSc(p_FmMacsecSecY, ++ p_FmMacsecSecYDriverParam->txScParams.sci, ++ p_FmMacsecSecYDriverParam->txScParams.cipherSuite, ++ e_SC_TX); ++ XX_Free(p_FmMacsecSecYDriverParam); ++ p_FmMacsecSecY->p_FmMacsecSecYDriverParam = NULL; ++ ++ return E_OK; ++} ++ ++t_Error FM_MACSEC_SECY_Free(t_Handle h_FmMacsecSecY) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ t_Error err = E_OK; ++ uint32_t rxScIds[NUM_OF_RX_SC], txScIds[NUM_OF_TX_SC], i; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ ++ if (p_FmMacsecSecY->isPointToPoint) ++ FmMacsecSetPTP(p_FmMacsecSecY->h_FmMacsec, FALSE); ++ if (p_FmMacsecSecY->p_RxSc) ++ { ++ for (i=0; inumOfRxSc; i++) ++ rxScIds[i] = p_FmMacsecSecY->p_RxSc[i].scId; ++ if ((err = FmMacsecFreeScs(p_FmMacsecSecY->h_FmMacsec, e_SC_RX, p_FmMacsecSecY->numOfRxSc, rxScIds)) != E_OK) ++ return ERROR_CODE(err); ++ XX_Free(p_FmMacsecSecY->p_RxSc); ++ } ++ if (p_FmMacsecSecY->p_TxSc) ++ { ++ FmMacsecSecYDeleteSc(p_FmMacsecSecY, &p_FmMacsecSecY->p_TxSc[0], e_SC_TX); ++ ++ for (i=0; inumOfTxSc; i++) { ++ txScIds[i] = p_FmMacsecSecY->p_TxSc[i].scId; ++ FmMacsecUnregisterIntr(p_FmMacsecSecY->h_FmMacsec, ++ e_FM_MACSEC_MOD_SC_TX, ++ (uint8_t)txScIds[i], ++ e_FM_INTR_TYPE_ERR); ++ FmMacsecUnregisterIntr(p_FmMacsecSecY->h_FmMacsec, ++ e_FM_MACSEC_MOD_SC_TX, ++ (uint8_t)txScIds[i], ++ e_FM_INTR_TYPE_NORMAL); ++ ++ if (p_FmMacsecSecY->exceptions & FM_MACSEC_SECY_EX_FRAME_DISCARDED) ++ FmMacsecSetException(p_FmMacsecSecY->h_FmMacsec, e_FM_MACSEC_EX_TX_SC, txScIds[i], FALSE); ++ if (p_FmMacsecSecY->events & FM_MACSEC_SECY_EV_NEXT_PN) ++ FmMacsecSetEvent(p_FmMacsecSecY->h_FmMacsec, e_FM_MACSEC_EV_TX_SC_NEXT_PN, txScIds[i], FALSE); ++ } ++ ++ if ((err = FmMacsecFreeScs(p_FmMacsecSecY->h_FmMacsec, e_SC_TX, p_FmMacsecSecY->numOfTxSc, txScIds)) != E_OK) ++ return ERROR_CODE(err); ++ XX_Free(p_FmMacsecSecY->p_TxSc); ++ } ++ ++ XX_Free(p_FmMacsecSecY); ++ ++ return err; ++} ++ ++t_Error FM_MACSEC_SECY_ConfigSciInsertionMode(t_Handle h_FmMacsecSecY, e_FmMacsecSciInsertionMode sciInsertionMode) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ ++ p_FmMacsecSecY->sciInsertionMode = sciInsertionMode; ++ ++ return E_OK; ++} ++ ++t_Error FM_MACSEC_SECY_ConfigProtectFrames(t_Handle h_FmMacsecSecY, bool protectFrames) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ ++ p_FmMacsecSecY->protectFrames = protectFrames; ++ ++ return E_OK; ++} ++ ++t_Error FM_MACSEC_SECY_ConfigReplayWindow(t_Handle h_FmMacsecSecY, bool replayProtect, uint32_t replayWindow) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ ++ p_FmMacsecSecY->replayProtect = replayProtect; ++ p_FmMacsecSecY->replayWindow = replayWindow; ++ ++ return E_OK; ++} ++ ++t_Error FM_MACSEC_SECY_ConfigValidationMode(t_Handle h_FmMacsecSecY, e_FmMacsecValidFrameBehavior validateFrames) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ ++ p_FmMacsecSecY->validateFrames = validateFrames; ++ ++ return E_OK; ++} ++ ++t_Error FM_MACSEC_SECY_ConfigConfidentiality(t_Handle h_FmMacsecSecY, bool confidentialityEnable, uint16_t confidentialityOffset) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ ++ p_FmMacsecSecY->confidentialityEnable = confidentialityEnable; ++ p_FmMacsecSecY->confidentialityOffset = confidentialityOffset; ++ ++ return E_OK; ++} ++ ++t_Error FM_MACSEC_SECY_ConfigPointToPoint(t_Handle h_FmMacsecSecY) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ ++ p_FmMacsecSecY->numOfRxSc = 1; ++ p_FmMacsecSecY->isPointToPoint = TRUE; ++ p_FmMacsecSecY->sciInsertionMode = e_FM_MACSEC_SCI_INSERTION_MODE_IMPLICT_PTP; ++ ++ return E_OK; ++} ++ ++t_Error FM_MACSEC_SECY_ConfigException(t_Handle h_FmMacsecSecY, e_FmMacsecSecYExceptions exception, bool enable) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ uint32_t bitMask = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ ++ GET_EXCEPTION_FLAG(bitMask, exception); ++ if (bitMask) ++ { ++ if (enable) ++ p_FmMacsecSecY->exceptions |= bitMask; ++ else ++ p_FmMacsecSecY->exceptions &= ~bitMask; ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); ++ ++ return E_OK; ++} ++ ++t_Error FM_MACSEC_SECY_ConfigEvent(t_Handle h_FmMacsecSecY, e_FmMacsecSecYEvents event, bool enable) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ uint32_t bitMask = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ ++ GET_EVENT_FLAG(bitMask, event); ++ if (bitMask) ++ { ++ if (enable) ++ p_FmMacsecSecY->events |= bitMask; ++ else ++ p_FmMacsecSecY->events &= ~bitMask; ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined event")); ++ ++ return E_OK; ++} ++ ++t_Handle FM_MACSEC_SECY_CreateRxSc(t_Handle h_FmMacsecSecY, t_FmMacsecSecYSCParams *p_ScParams) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmMacsecSecY, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(p_ScParams, E_NULL_POINTER, NULL); ++ SANITY_CHECK_RETURN_VALUE(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE, NULL); ++ ++ return FmMacsecSecYCreateSc(p_FmMacsecSecY, p_ScParams->sci, p_ScParams->cipherSuite, e_SC_RX); ++} ++ ++t_Error FM_MACSEC_SECY_DeleteRxSc(t_Handle h_FmMacsecSecY, t_Handle h_Sc) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); ++ ++ return FmMacsecSecYDeleteSc(p_FmMacsecSecY, p_FmSecYSc, e_SC_RX); ++} ++ ++t_Error FM_MACSEC_SECY_CreateRxSa(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t lowestPn, macsecSAKey_t key) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); ++ ++ if (p_FmSecYSc->sa[an].saId != SECY_AN_FREE_VALUE) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is already assigned",an)); ++ ++ if ((err = FmMacsecCreateRxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, (e_ScSaId)p_FmSecYSc->numOfSa, an, lowestPn, key)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ p_FmSecYSc->sa[an].saId = (e_ScSaId)p_FmSecYSc->numOfSa++; ++ return err; ++} ++ ++t_Error FM_MACSEC_SECY_DeleteRxSa(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); ++ ++ if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is already deleted",an)); ++ ++ if ((err = FmMacsecDeleteRxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ p_FmSecYSc->numOfSa--; ++ p_FmSecYSc->sa[an].saId = (e_ScSaId)SECY_AN_FREE_VALUE; ++ /* TODO - check if statistics need to be read*/ ++ return err; ++} ++ ++t_Error FM_MACSEC_SECY_RxSaEnableReceive(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); ++ ++ if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an)); ++ ++ if ((err = FmMacsecRxSaSetReceive(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, TRUE)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ p_FmSecYSc->sa[an].active = TRUE; ++ return err; ++} ++ ++t_Error FM_MACSEC_SECY_RxSaDisableReceive(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); ++ ++ if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an)); ++ ++ if ((err = FmMacsecRxSaSetReceive(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, FALSE)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ p_FmSecYSc->sa[an].active = FALSE; ++ return err; ++} ++ ++t_Error FM_MACSEC_SECY_RxSaUpdateNextPn(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t updtNextPN) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); ++ ++ if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an)); ++ ++ if ((err = FmMacsecRxSaUpdateNextPn(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, updtNextPN)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ return err; ++} ++ ++t_Error FM_MACSEC_SECY_RxSaUpdateLowestPn(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t updtLowestPN) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); ++ ++ if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an)); ++ ++ if ((err = FmMacsecRxSaUpdateLowestPn(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, updtLowestPN)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ return err; ++} ++ ++t_Error FM_MACSEC_SECY_RxSaModifyKey(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, macsecSAKey_t key) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); ++ ++ if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an)); ++ ++ if (p_FmSecYSc->sa[an].active) ++ if ((err = FmMacsecRxSaSetReceive(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, FALSE)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ /* TODO - statistics should be read */ ++ ++ if ((err = FmMacsecCreateRxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, an, 1, key)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ if (p_FmSecYSc->sa[an].active) ++ if ((err = FmMacsecRxSaSetReceive(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, TRUE)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ return err; ++} ++ ++ ++t_Error FM_MACSEC_SECY_CreateTxSa(t_Handle h_FmMacsecSecY, macsecAN_t an, macsecSAKey_t key) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ t_SecYSc *p_FmSecYSc; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0]; ++ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); ++ ++ if (p_FmSecYSc->sa[an].saId != SECY_AN_FREE_VALUE) ++ RETURN_ERROR(MINOR, err, ("An %d is already assigned",an)); ++ ++ if ((err = FmMacsecCreateTxSa(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, (e_ScSaId)p_FmSecYSc->numOfSa, key)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ p_FmSecYSc->sa[an].saId = (e_ScSaId)p_FmSecYSc->numOfSa++; ++ return err; ++} ++ ++t_Error FM_MACSEC_SECY_DeleteTxSa(t_Handle h_FmMacsecSecY, macsecAN_t an) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ t_SecYSc *p_FmSecYSc; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0]; ++ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); ++ ++ if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is already deleted",an)); ++ ++ if ((err = FmMacsecDeleteTxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ p_FmSecYSc->numOfSa--; ++ p_FmSecYSc->sa[an].saId = (e_ScSaId)SECY_AN_FREE_VALUE; ++ /* TODO - check if statistics need to be read*/ ++ return err; ++} ++ ++t_Error FM_MACSEC_SECY_TxSaModifyKey(t_Handle h_FmMacsecSecY, macsecAN_t nextActiveAn, macsecSAKey_t key) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ t_SecYSc *p_FmSecYSc; ++ macsecAN_t currentAn; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0]; ++ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(nextActiveAn < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); ++ ++ if ((err = FmMacsecTxSaGetActive(p_FmMacsecSecY->h_FmMacsec, ++ p_FmSecYSc->scId, ++ ¤tAn)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ if ((err = FmMacsecTxSaSetActive(p_FmMacsecSecY->h_FmMacsec, ++ p_FmSecYSc->scId, ++ p_FmSecYSc->sa[nextActiveAn].saId, ++ nextActiveAn)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ /* TODO - statistics should be read */ ++ ++ if ((err = FmMacsecCreateTxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[currentAn].saId, key)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ return err; ++} ++ ++t_Error FM_MACSEC_SECY_TxSaSetActive(t_Handle h_FmMacsecSecY, macsecAN_t an) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ t_SecYSc *p_FmSecYSc; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0]; ++ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); ++ ++ if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an)); ++ ++ if ((err = FmMacsecTxSaSetActive(p_FmMacsecSecY->h_FmMacsec, ++ p_FmSecYSc->scId, ++ p_FmSecYSc->sa[an].saId, ++ an)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ return err; ++} ++ ++t_Error FM_MACSEC_SECY_TxSaGetActive(t_Handle h_FmMacsecSecY, macsecAN_t *p_An) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ t_SecYSc *p_FmSecYSc; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0]; ++ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_An, E_INVALID_HANDLE); ++ ++ if ((err = FmMacsecTxSaGetActive(p_FmMacsecSecY->h_FmMacsec, ++ p_FmSecYSc->scId, ++ p_An)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ return err; ++} ++ ++t_Error FM_MACSEC_SECY_GetRxScPhysId(t_Handle h_FmMacsecSecY, t_Handle h_Sc, uint32_t *p_ScPhysId) ++{ ++ t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(((t_FmMacsecSecY *)h_FmMacsecSecY)->h_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!((t_FmMacsecSecY *)h_FmMacsecSecY)->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); ++#ifdef DISABLE_SANITY_CHECKS ++ UNUSED(h_FmMacsecSecY); ++#endif /* DISABLE_SANITY_CHECKS */ ++ ++ *p_ScPhysId = p_FmSecYSc->scId; ++ return err; ++} ++ ++t_Error FM_MACSEC_SECY_GetTxScPhysId(t_Handle h_FmMacsecSecY, uint32_t *p_ScPhysId) ++{ ++ t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; ++ t_SecYSc *p_FmSecYSc; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); ++ p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0]; ++ SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); ++ ++ *p_ScPhysId = p_FmSecYSc->scId; ++ return err; ++} ++ ++t_Error FM_MACSEC_SECY_SetException(t_Handle h_FmMacsecSecY, e_FmMacsecExceptions exception, bool enable) ++{ ++ UNUSED(h_FmMacsecSecY);UNUSED(exception);UNUSED(enable); ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_SECY_SetEvent(t_Handle h_FmMacsecSecY, e_FmMacsecSecYEvents event, bool enable) ++{ ++ UNUSED(h_FmMacsecSecY);UNUSED(event);UNUSED(enable); ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_SECY_GetStatistics(t_Handle h_FmMacsecSecY, t_FmMacsecSecYStatistics *p_Statistics) ++{ ++ UNUSED(h_FmMacsecSecY);UNUSED(p_Statistics); ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_SECY_RxScGetStatistics(t_Handle h_FmMacsecSecY, t_Handle h_Sc, t_FmMacsecSecYRxScStatistics *p_Statistics) ++{ ++ UNUSED(h_FmMacsecSecY);UNUSED(h_Sc);UNUSED(p_Statistics); ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_SECY_RxSaGetStatistics(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, t_FmMacsecSecYRxSaStatistics *p_Statistics) ++{ ++ UNUSED(h_FmMacsecSecY);UNUSED(h_Sc);UNUSED(an);UNUSED(p_Statistics); ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_SECY_TxScGetStatistics(t_Handle h_FmMacsecSecY, t_FmMacsecSecYTxScStatistics *p_Statistics) ++{ ++ UNUSED(h_FmMacsecSecY);UNUSED(p_Statistics); ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ ++t_Error FM_MACSEC_SECY_TxSaGetStatistics(t_Handle h_FmMacsecSecY, macsecAN_t an, t_FmMacsecSecYTxSaStatistics *p_Statistics) ++{ ++ UNUSED(h_FmMacsecSecY);UNUSED(an);UNUSED(p_Statistics); ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++} ++ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.h +new file mode 100644 +index 00000000..0cf624e6 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.h +@@ -0,0 +1,144 @@ ++/* ++ * Copyright 2008-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/****************************************************************************** ++ @File fm_macsec_secy.h ++ ++ @Description FM MACSEC SecY internal structures and definitions. ++*//***************************************************************************/ ++#ifndef __FM_MACSEC_SECY_H ++#define __FM_MACSEC_SECY_H ++ ++#include "error_ext.h" ++#include "std_ext.h" ++ ++#include "fm_macsec.h" ++ ++ ++/**************************************************************************//** ++ @Description Exceptions ++*//***************************************************************************/ ++ ++#define FM_MACSEC_SECY_EX_FRAME_DISCARDED 0x80000000 ++ ++#define GET_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \ ++ case e_FM_MACSEC_SECY_EX_FRAME_DISCARDED: \ ++ bitMask = FM_MACSEC_SECY_EX_FRAME_DISCARDED; break; \ ++ default: bitMask = 0;break;} ++ ++/**************************************************************************//** ++ @Description Events ++*//***************************************************************************/ ++ ++#define FM_MACSEC_SECY_EV_NEXT_PN 0x80000000 ++ ++#define GET_EVENT_FLAG(bitMask, event) switch (event){ \ ++ case e_FM_MACSEC_SECY_EV_NEXT_PN: \ ++ bitMask = FM_MACSEC_SECY_EV_NEXT_PN; break; \ ++ default: bitMask = 0;break;} ++ ++/**************************************************************************//** ++ @Description Defaults ++*//***************************************************************************/ ++ ++#define DEFAULT_exceptions (FM_MACSEC_SECY_EX_FRAME_DISCARDED) ++#define DEFAULT_events (FM_MACSEC_SECY_EV_NEXT_PN) ++#define DEFAULT_numOfTxSc 1 ++#define DEFAULT_confidentialityEnable FALSE ++#define DEFAULT_confidentialityOffset 0 ++#define DEFAULT_sciInsertionMode e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_SECTAG ++#define DEFAULT_validateFrames e_FM_MACSEC_VALID_FRAME_BEHAVIOR_STRICT ++#define DEFAULT_replayEnable FALSE ++#define DEFAULT_replayWindow 0 ++#define DEFAULT_protectFrames TRUE ++#define DEFAULT_ptp FALSE ++ ++/**************************************************************************//** ++ @Description General defines ++*//***************************************************************************/ ++ ++#define SECY_AN_FREE_VALUE MAX_NUM_OF_SA_PER_SC ++ ++ ++typedef struct { ++ e_ScSaId saId; ++ bool active; ++ union { ++ t_FmMacsecSecYRxSaStatistics rxSaStatistics; ++ t_FmMacsecSecYTxSaStatistics txSaStatistics; ++ }; ++} t_SecYSa; ++ ++typedef struct { ++ bool inUse; ++ uint32_t scId; ++ e_ScType type; ++ uint8_t numOfSa; ++ t_SecYSa sa[MAX_NUM_OF_SA_PER_SC]; ++ union { ++ t_FmMacsecSecYRxScStatistics rxScStatistics; ++ t_FmMacsecSecYTxScStatistics txScStatistics; ++ }; ++} t_SecYSc; ++ ++typedef struct { ++ t_FmMacsecSecYSCParams txScParams; /**< Tx SC Params */ ++} t_FmMacsecSecYDriverParam; ++ ++typedef struct { ++ t_Handle h_FmMacsec; ++ bool confidentialityEnable; /**< TRUE - confidentiality protection and integrity protection ++ FALSE - no confidentiality protection, only integrity protection*/ ++ uint16_t confidentialityOffset; /**< The number of initial octets of each MSDU without confidentiality protection ++ common values are 0, 30, and 50 */ ++ bool replayProtect; /**< replay protection function mode */ ++ uint32_t replayWindow; /**< the size of the replay window */ ++ e_FmMacsecValidFrameBehavior validateFrames; /**< validation function mode */ ++ e_FmMacsecSciInsertionMode sciInsertionMode; ++ bool protectFrames; ++ bool isPointToPoint; ++ e_FmMacsecSecYCipherSuite cipherSuite; /**< Cipher suite to be used for this SecY */ ++ uint32_t numOfRxSc; /**< Number of receive channels */ ++ uint32_t numOfTxSc; /**< Number of transmit channels */ ++ t_SecYSc *p_RxSc; ++ t_SecYSc *p_TxSc; ++ uint32_t events; ++ uint32_t exceptions; ++ t_FmMacsecSecYExceptionsCallback *f_Exception; /**< TODO */ ++ t_FmMacsecSecYEventsCallback *f_Event; /**< TODO */ ++ t_Handle h_App; ++ t_FmMacsecSecYStatistics statistics; ++ t_FmMacsecSecYDriverParam *p_FmMacsecSecYDriverParam; ++} t_FmMacsecSecY; ++ ++ ++#endif /* __FM_MACSEC_SECY_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Makefile +new file mode 100644 +index 00000000..619f6608 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Makefile +@@ -0,0 +1,23 @@ ++# ++# Makefile for the Freescale Ethernet controllers ++# ++ccflags-y += -DVERSION=\"\" ++# ++#Include netcomm SW specific definitions ++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk ++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc ++ ++ccflags-y += -I$(NCSW_FM_INC) ++ ++ ++obj-y += fsl-ncsw-PFM1.o ++ ++fsl-ncsw-PFM1-objs := fm.o fm_muram.o fman.o ++ ++obj-y += MAC/ ++obj-y += Pcd/ ++obj-y += SP/ ++obj-y += Port/ ++obj-y += HC/ ++obj-y += Rtc/ ++obj-y += MACSEC/ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/Makefile +new file mode 100644 +index 00000000..62fbd73c +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/Makefile +@@ -0,0 +1,26 @@ ++# ++# Makefile for the Freescale Ethernet controllers ++# ++ccflags-y += -DVERSION=\"\" ++# ++#Include netcomm SW specific definitions ++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk ++ ++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc ++ ++ccflags-y += -I$(NCSW_FM_INC) ++ ++obj-y += fsl-ncsw-Pcd.o ++ ++fsl-ncsw-Pcd-objs := fman_kg.o fman_prs.o fm_cc.o fm_kg.o fm_pcd.o fm_plcr.o fm_prs.o fm_manip.o ++ ++ifeq ($(CONFIG_FMAN_V3H),y) ++fsl-ncsw-Pcd-objs += fm_replic.o ++endif ++ifeq ($(CONFIG_FMAN_V3L),y) ++fsl-ncsw-Pcd-objs += fm_replic.o ++endif ++ifeq ($(CONFIG_FMAN_ARM),y) ++fsl-ncsw-Pcd-objs += fm_replic.o ++endif ++ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/crc64.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/crc64.h +new file mode 100644 +index 00000000..335ee681 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/crc64.h +@@ -0,0 +1,360 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++ /**************************************************************************//** ++ @File crc64.h ++ ++ @Description brief This file contains the CRC64 Table, and __inline__ ++ functions used for calculating crc. ++*//***************************************************************************/ ++#ifndef __CRC64_H ++#define __CRC64_H ++ ++#include "std_ext.h" ++ ++ ++#define BITS_PER_BYTE 8 ++ ++#define CRC64_EXPON_ECMA_182 0xC96C5795D7870F42ULL ++#define CRC64_DEFAULT_INITVAL 0xFFFFFFFFFFFFFFFFULL ++ ++#define CRC64_BYTE_MASK 0xFF ++#define CRC64_TABLE_ENTRIES ( 1 << BITS_PER_BYTE ) ++#define CRC64_ODD_MASK 1 ++ ++ ++/** ++ \brief '64 bit crc' Table ++ */ ++struct crc64_t { ++ uint64_t initial; /**< Initial seed */ ++ uint64_t table[CRC64_TABLE_ENTRIES]; /**< CRC table entries */ ++}; ++ ++ ++static struct crc64_t CRC64_ECMA_182 = { ++ CRC64_DEFAULT_INITVAL, ++ { ++ 0x0000000000000000ULL, ++ 0xb32e4cbe03a75f6fULL, ++ 0xf4843657a840a05bULL, ++ 0x47aa7ae9abe7ff34ULL, ++ 0x7bd0c384ff8f5e33ULL, ++ 0xc8fe8f3afc28015cULL, ++ 0x8f54f5d357cffe68ULL, ++ 0x3c7ab96d5468a107ULL, ++ 0xf7a18709ff1ebc66ULL, ++ 0x448fcbb7fcb9e309ULL, ++ 0x0325b15e575e1c3dULL, ++ 0xb00bfde054f94352ULL, ++ 0x8c71448d0091e255ULL, ++ 0x3f5f08330336bd3aULL, ++ 0x78f572daa8d1420eULL, ++ 0xcbdb3e64ab761d61ULL, ++ 0x7d9ba13851336649ULL, ++ 0xceb5ed8652943926ULL, ++ 0x891f976ff973c612ULL, ++ 0x3a31dbd1fad4997dULL, ++ 0x064b62bcaebc387aULL, ++ 0xb5652e02ad1b6715ULL, ++ 0xf2cf54eb06fc9821ULL, ++ 0x41e11855055bc74eULL, ++ 0x8a3a2631ae2dda2fULL, ++ 0x39146a8fad8a8540ULL, ++ 0x7ebe1066066d7a74ULL, ++ 0xcd905cd805ca251bULL, ++ 0xf1eae5b551a2841cULL, ++ 0x42c4a90b5205db73ULL, ++ 0x056ed3e2f9e22447ULL, ++ 0xb6409f5cfa457b28ULL, ++ 0xfb374270a266cc92ULL, ++ 0x48190ecea1c193fdULL, ++ 0x0fb374270a266cc9ULL, ++ 0xbc9d3899098133a6ULL, ++ 0x80e781f45de992a1ULL, ++ 0x33c9cd4a5e4ecdceULL, ++ 0x7463b7a3f5a932faULL, ++ 0xc74dfb1df60e6d95ULL, ++ 0x0c96c5795d7870f4ULL, ++ 0xbfb889c75edf2f9bULL, ++ 0xf812f32ef538d0afULL, ++ 0x4b3cbf90f69f8fc0ULL, ++ 0x774606fda2f72ec7ULL, ++ 0xc4684a43a15071a8ULL, ++ 0x83c230aa0ab78e9cULL, ++ 0x30ec7c140910d1f3ULL, ++ 0x86ace348f355aadbULL, ++ 0x3582aff6f0f2f5b4ULL, ++ 0x7228d51f5b150a80ULL, ++ 0xc10699a158b255efULL, ++ 0xfd7c20cc0cdaf4e8ULL, ++ 0x4e526c720f7dab87ULL, ++ 0x09f8169ba49a54b3ULL, ++ 0xbad65a25a73d0bdcULL, ++ 0x710d64410c4b16bdULL, ++ 0xc22328ff0fec49d2ULL, ++ 0x85895216a40bb6e6ULL, ++ 0x36a71ea8a7ace989ULL, ++ 0x0adda7c5f3c4488eULL, ++ 0xb9f3eb7bf06317e1ULL, ++ 0xfe5991925b84e8d5ULL, ++ 0x4d77dd2c5823b7baULL, ++ 0x64b62bcaebc387a1ULL, ++ 0xd7986774e864d8ceULL, ++ 0x90321d9d438327faULL, ++ 0x231c512340247895ULL, ++ 0x1f66e84e144cd992ULL, ++ 0xac48a4f017eb86fdULL, ++ 0xebe2de19bc0c79c9ULL, ++ 0x58cc92a7bfab26a6ULL, ++ 0x9317acc314dd3bc7ULL, ++ 0x2039e07d177a64a8ULL, ++ 0x67939a94bc9d9b9cULL, ++ 0xd4bdd62abf3ac4f3ULL, ++ 0xe8c76f47eb5265f4ULL, ++ 0x5be923f9e8f53a9bULL, ++ 0x1c4359104312c5afULL, ++ 0xaf6d15ae40b59ac0ULL, ++ 0x192d8af2baf0e1e8ULL, ++ 0xaa03c64cb957be87ULL, ++ 0xeda9bca512b041b3ULL, ++ 0x5e87f01b11171edcULL, ++ 0x62fd4976457fbfdbULL, ++ 0xd1d305c846d8e0b4ULL, ++ 0x96797f21ed3f1f80ULL, ++ 0x2557339fee9840efULL, ++ 0xee8c0dfb45ee5d8eULL, ++ 0x5da24145464902e1ULL, ++ 0x1a083bacedaefdd5ULL, ++ 0xa9267712ee09a2baULL, ++ 0x955cce7fba6103bdULL, ++ 0x267282c1b9c65cd2ULL, ++ 0x61d8f8281221a3e6ULL, ++ 0xd2f6b4961186fc89ULL, ++ 0x9f8169ba49a54b33ULL, ++ 0x2caf25044a02145cULL, ++ 0x6b055fede1e5eb68ULL, ++ 0xd82b1353e242b407ULL, ++ 0xe451aa3eb62a1500ULL, ++ 0x577fe680b58d4a6fULL, ++ 0x10d59c691e6ab55bULL, ++ 0xa3fbd0d71dcdea34ULL, ++ 0x6820eeb3b6bbf755ULL, ++ 0xdb0ea20db51ca83aULL, ++ 0x9ca4d8e41efb570eULL, ++ 0x2f8a945a1d5c0861ULL, ++ 0x13f02d374934a966ULL, ++ 0xa0de61894a93f609ULL, ++ 0xe7741b60e174093dULL, ++ 0x545a57dee2d35652ULL, ++ 0xe21ac88218962d7aULL, ++ 0x5134843c1b317215ULL, ++ 0x169efed5b0d68d21ULL, ++ 0xa5b0b26bb371d24eULL, ++ 0x99ca0b06e7197349ULL, ++ 0x2ae447b8e4be2c26ULL, ++ 0x6d4e3d514f59d312ULL, ++ 0xde6071ef4cfe8c7dULL, ++ 0x15bb4f8be788911cULL, ++ 0xa6950335e42fce73ULL, ++ 0xe13f79dc4fc83147ULL, ++ 0x521135624c6f6e28ULL, ++ 0x6e6b8c0f1807cf2fULL, ++ 0xdd45c0b11ba09040ULL, ++ 0x9aefba58b0476f74ULL, ++ 0x29c1f6e6b3e0301bULL, ++ 0xc96c5795d7870f42ULL, ++ 0x7a421b2bd420502dULL, ++ 0x3de861c27fc7af19ULL, ++ 0x8ec62d7c7c60f076ULL, ++ 0xb2bc941128085171ULL, ++ 0x0192d8af2baf0e1eULL, ++ 0x4638a2468048f12aULL, ++ 0xf516eef883efae45ULL, ++ 0x3ecdd09c2899b324ULL, ++ 0x8de39c222b3eec4bULL, ++ 0xca49e6cb80d9137fULL, ++ 0x7967aa75837e4c10ULL, ++ 0x451d1318d716ed17ULL, ++ 0xf6335fa6d4b1b278ULL, ++ 0xb199254f7f564d4cULL, ++ 0x02b769f17cf11223ULL, ++ 0xb4f7f6ad86b4690bULL, ++ 0x07d9ba1385133664ULL, ++ 0x4073c0fa2ef4c950ULL, ++ 0xf35d8c442d53963fULL, ++ 0xcf273529793b3738ULL, ++ 0x7c0979977a9c6857ULL, ++ 0x3ba3037ed17b9763ULL, ++ 0x888d4fc0d2dcc80cULL, ++ 0x435671a479aad56dULL, ++ 0xf0783d1a7a0d8a02ULL, ++ 0xb7d247f3d1ea7536ULL, ++ 0x04fc0b4dd24d2a59ULL, ++ 0x3886b22086258b5eULL, ++ 0x8ba8fe9e8582d431ULL, ++ 0xcc0284772e652b05ULL, ++ 0x7f2cc8c92dc2746aULL, ++ 0x325b15e575e1c3d0ULL, ++ 0x8175595b76469cbfULL, ++ 0xc6df23b2dda1638bULL, ++ 0x75f16f0cde063ce4ULL, ++ 0x498bd6618a6e9de3ULL, ++ 0xfaa59adf89c9c28cULL, ++ 0xbd0fe036222e3db8ULL, ++ 0x0e21ac88218962d7ULL, ++ 0xc5fa92ec8aff7fb6ULL, ++ 0x76d4de52895820d9ULL, ++ 0x317ea4bb22bfdfedULL, ++ 0x8250e80521188082ULL, ++ 0xbe2a516875702185ULL, ++ 0x0d041dd676d77eeaULL, ++ 0x4aae673fdd3081deULL, ++ 0xf9802b81de97deb1ULL, ++ 0x4fc0b4dd24d2a599ULL, ++ 0xfceef8632775faf6ULL, ++ 0xbb44828a8c9205c2ULL, ++ 0x086ace348f355aadULL, ++ 0x34107759db5dfbaaULL, ++ 0x873e3be7d8faa4c5ULL, ++ 0xc094410e731d5bf1ULL, ++ 0x73ba0db070ba049eULL, ++ 0xb86133d4dbcc19ffULL, ++ 0x0b4f7f6ad86b4690ULL, ++ 0x4ce50583738cb9a4ULL, ++ 0xffcb493d702be6cbULL, ++ 0xc3b1f050244347ccULL, ++ 0x709fbcee27e418a3ULL, ++ 0x3735c6078c03e797ULL, ++ 0x841b8ab98fa4b8f8ULL, ++ 0xadda7c5f3c4488e3ULL, ++ 0x1ef430e13fe3d78cULL, ++ 0x595e4a08940428b8ULL, ++ 0xea7006b697a377d7ULL, ++ 0xd60abfdbc3cbd6d0ULL, ++ 0x6524f365c06c89bfULL, ++ 0x228e898c6b8b768bULL, ++ 0x91a0c532682c29e4ULL, ++ 0x5a7bfb56c35a3485ULL, ++ 0xe955b7e8c0fd6beaULL, ++ 0xaeffcd016b1a94deULL, ++ 0x1dd181bf68bdcbb1ULL, ++ 0x21ab38d23cd56ab6ULL, ++ 0x9285746c3f7235d9ULL, ++ 0xd52f0e859495caedULL, ++ 0x6601423b97329582ULL, ++ 0xd041dd676d77eeaaULL, ++ 0x636f91d96ed0b1c5ULL, ++ 0x24c5eb30c5374ef1ULL, ++ 0x97eba78ec690119eULL, ++ 0xab911ee392f8b099ULL, ++ 0x18bf525d915feff6ULL, ++ 0x5f1528b43ab810c2ULL, ++ 0xec3b640a391f4fadULL, ++ 0x27e05a6e926952ccULL, ++ 0x94ce16d091ce0da3ULL, ++ 0xd3646c393a29f297ULL, ++ 0x604a2087398eadf8ULL, ++ 0x5c3099ea6de60cffULL, ++ 0xef1ed5546e415390ULL, ++ 0xa8b4afbdc5a6aca4ULL, ++ 0x1b9ae303c601f3cbULL, ++ 0x56ed3e2f9e224471ULL, ++ 0xe5c372919d851b1eULL, ++ 0xa26908783662e42aULL, ++ 0x114744c635c5bb45ULL, ++ 0x2d3dfdab61ad1a42ULL, ++ 0x9e13b115620a452dULL, ++ 0xd9b9cbfcc9edba19ULL, ++ 0x6a978742ca4ae576ULL, ++ 0xa14cb926613cf817ULL, ++ 0x1262f598629ba778ULL, ++ 0x55c88f71c97c584cULL, ++ 0xe6e6c3cfcadb0723ULL, ++ 0xda9c7aa29eb3a624ULL, ++ 0x69b2361c9d14f94bULL, ++ 0x2e184cf536f3067fULL, ++ 0x9d36004b35545910ULL, ++ 0x2b769f17cf112238ULL, ++ 0x9858d3a9ccb67d57ULL, ++ 0xdff2a94067518263ULL, ++ 0x6cdce5fe64f6dd0cULL, ++ 0x50a65c93309e7c0bULL, ++ 0xe388102d33392364ULL, ++ 0xa4226ac498dedc50ULL, ++ 0x170c267a9b79833fULL, ++ 0xdcd7181e300f9e5eULL, ++ 0x6ff954a033a8c131ULL, ++ 0x28532e49984f3e05ULL, ++ 0x9b7d62f79be8616aULL, ++ 0xa707db9acf80c06dULL, ++ 0x14299724cc279f02ULL, ++ 0x5383edcd67c06036ULL, ++ 0xe0ada17364673f59ULL ++ } ++}; ++ ++ ++/** ++ \brief Initializes the crc seed ++ */ ++static __inline__ uint64_t crc64_init(void) ++{ ++ return CRC64_ECMA_182.initial; ++} ++ ++/** ++ \brief Computes 64 bit the crc ++ \param[in] data Pointer to the Data in the frame ++ \param[in] len Length of the Data ++ \param[in] crc seed ++ \return calculated crc ++ */ ++static __inline__ uint64_t crc64_compute(void const *data, ++ uint32_t len, ++ uint64_t seed) ++{ ++ uint32_t i; ++ uint64_t crc = seed; ++ uint8_t *bdata = (uint8_t *) data; ++ ++ for (i = 0; i < len; i++) ++ crc = ++ CRC64_ECMA_182. ++ table[(crc ^ *bdata++) & CRC64_BYTE_MASK] ^ (crc >> 8); ++ ++ return crc; ++} ++ ++ ++#endif /* __CRC64_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c +new file mode 100644 +index 00000000..17c933b4 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c +@@ -0,0 +1,7582 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_cc.c ++ ++ @Description FM Coarse Classifier implementation ++ *//***************************************************************************/ ++#include ++#include "std_ext.h" ++#include "error_ext.h" ++#include "string_ext.h" ++#include "debug_ext.h" ++#include "fm_pcd_ext.h" ++#include "fm_muram_ext.h" ++ ++#include "fm_common.h" ++#include "fm_pcd.h" ++#include "fm_hc.h" ++#include "fm_cc.h" ++#include "crc64.h" ++ ++/****************************************/ ++/* static functions */ ++/****************************************/ ++ ++ ++static t_Error CcRootTryLock(t_Handle h_FmPcdCcTree) ++{ ++ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree; ++ ++ ASSERT_COND(h_FmPcdCcTree); ++ ++ if (FmPcdLockTryLock(p_FmPcdCcTree->p_Lock)) ++ return E_OK; ++ ++ return ERROR_CODE(E_BUSY); ++} ++ ++static void CcRootReleaseLock(t_Handle h_FmPcdCcTree) ++{ ++ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree; ++ ++ ASSERT_COND(h_FmPcdCcTree); ++ ++ FmPcdLockUnlock(p_FmPcdCcTree->p_Lock); ++} ++ ++static void UpdateNodeOwner(t_FmPcdCcNode *p_CcNode, bool add) ++{ ++ uint32_t intFlags; ++ ++ ASSERT_COND(p_CcNode); ++ ++ intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock); ++ ++ if (add) ++ p_CcNode->owners++; ++ else ++ { ++ ASSERT_COND(p_CcNode->owners); ++ p_CcNode->owners--; ++ } ++ ++ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); ++} ++ ++static __inline__ t_FmPcdStatsObj* DequeueStatsObj(t_List *p_List) ++{ ++ t_FmPcdStatsObj *p_StatsObj = NULL; ++ t_List *p_Next; ++ ++ if (!LIST_IsEmpty(p_List)) ++ { ++ p_Next = LIST_FIRST(p_List); ++ p_StatsObj = LIST_OBJECT(p_Next, t_FmPcdStatsObj, node); ++ ASSERT_COND(p_StatsObj); ++ LIST_DelAndInit(p_Next); ++ } ++ ++ return p_StatsObj; ++} ++ ++static __inline__ void EnqueueStatsObj(t_List *p_List, ++ t_FmPcdStatsObj *p_StatsObj) ++{ ++ LIST_AddToTail(&p_StatsObj->node, p_List); ++} ++ ++static void FreeStatObjects(t_List *p_List, t_Handle h_FmMuram) ++{ ++ t_FmPcdStatsObj *p_StatsObj; ++ ++ while (!LIST_IsEmpty(p_List)) ++ { ++ p_StatsObj = DequeueStatsObj(p_List); ++ ASSERT_COND(p_StatsObj); ++ ++ FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsAd); ++ FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsCounters); ++ ++ XX_Free(p_StatsObj); ++ } ++} ++ ++static t_FmPcdStatsObj* GetStatsObj(t_FmPcdCcNode *p_CcNode) ++{ ++ t_FmPcdStatsObj* p_StatsObj; ++ t_Handle h_FmMuram; ++ ++ ASSERT_COND(p_CcNode); ++ ++ /* If 'maxNumOfKeys' was passed, all statistics object were preallocated ++ upon node initialization */ ++ if (p_CcNode->maxNumOfKeys) ++ { ++ p_StatsObj = DequeueStatsObj(&p_CcNode->availableStatsLst); ++ ++ /* Clean statistics counters & ADs */ ++ MemSet8(p_StatsObj->h_StatsAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ MemSet8(p_StatsObj->h_StatsCounters, 0, p_CcNode->countersArraySize); ++ } ++ else ++ { ++ h_FmMuram = ((t_FmPcd *)(p_CcNode->h_FmPcd))->h_FmMuram; ++ ASSERT_COND(h_FmMuram); ++ ++ p_StatsObj = XX_Malloc(sizeof(t_FmPcdStatsObj)); ++ if (!p_StatsObj) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("statistics object")); ++ return NULL; ++ } ++ ++ p_StatsObj->h_StatsAd = (t_Handle)FM_MURAM_AllocMem( ++ h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE, FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!p_StatsObj->h_StatsAd) ++ { ++ XX_Free(p_StatsObj); ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for statistics ADs")); ++ return NULL; ++ } ++ MemSet8(p_StatsObj->h_StatsAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ p_StatsObj->h_StatsCounters = (t_Handle)FM_MURAM_AllocMem( ++ h_FmMuram, p_CcNode->countersArraySize, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!p_StatsObj->h_StatsCounters) ++ { ++ FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsAd); ++ XX_Free(p_StatsObj); ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for statistics counters")); ++ return NULL; ++ } ++ MemSet8(p_StatsObj->h_StatsCounters, 0, p_CcNode->countersArraySize); ++ } ++ ++ return p_StatsObj; ++} ++ ++static void PutStatsObj(t_FmPcdCcNode *p_CcNode, t_FmPcdStatsObj *p_StatsObj) ++{ ++ t_Handle h_FmMuram; ++ ++ ASSERT_COND(p_CcNode); ++ ASSERT_COND(p_StatsObj); ++ ++ /* If 'maxNumOfKeys' was passed, all statistics object were preallocated ++ upon node initialization and now will be enqueued back to the list */ ++ if (p_CcNode->maxNumOfKeys) ++ { ++ /* Clean statistics counters */ ++ MemSet8(p_StatsObj->h_StatsCounters, 0, p_CcNode->countersArraySize); ++ ++ /* Clean statistics ADs */ ++ MemSet8(p_StatsObj->h_StatsAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ EnqueueStatsObj(&p_CcNode->availableStatsLst, p_StatsObj); ++ } ++ else ++ { ++ h_FmMuram = ((t_FmPcd *)(p_CcNode->h_FmPcd))->h_FmMuram; ++ ASSERT_COND(h_FmMuram); ++ ++ FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsAd); ++ FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsCounters); ++ ++ XX_Free(p_StatsObj); ++ } ++} ++ ++static void SetStatsCounters(t_AdOfTypeStats *p_StatsAd, ++ uint32_t statsCountersAddr) ++{ ++ uint32_t tmp = (statsCountersAddr & FM_PCD_AD_STATS_COUNTERS_ADDR_MASK); ++ ++ WRITE_UINT32(p_StatsAd->statsTableAddr, tmp); ++} ++ ++ ++static void UpdateStatsAd(t_FmPcdCcStatsParams *p_FmPcdCcStatsParams, ++ t_Handle h_Ad, uint64_t physicalMuramBase) ++{ ++ t_AdOfTypeStats *p_StatsAd; ++ uint32_t statsCountersAddr, nextActionAddr, tmp; ++#if (DPAA_VERSION >= 11) ++ uint32_t frameLengthRangesAddr; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ p_StatsAd = (t_AdOfTypeStats *)p_FmPcdCcStatsParams->h_StatsAd; ++ ++ tmp = FM_PCD_AD_STATS_TYPE; ++ ++#if (DPAA_VERSION >= 11) ++ if (p_FmPcdCcStatsParams->h_StatsFLRs) ++ { ++ frameLengthRangesAddr = (uint32_t)((XX_VirtToPhys( ++ p_FmPcdCcStatsParams->h_StatsFLRs) - physicalMuramBase)); ++ tmp |= (frameLengthRangesAddr & FM_PCD_AD_STATS_FLR_ADDR_MASK); ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ WRITE_UINT32(p_StatsAd->profileTableAddr, tmp); ++ ++ nextActionAddr = (uint32_t)((XX_VirtToPhys(h_Ad) - physicalMuramBase)); ++ tmp = 0; ++ tmp |= (uint32_t)((nextActionAddr << FM_PCD_AD_STATS_NEXT_ACTION_SHIFT) ++ & FM_PCD_AD_STATS_NEXT_ACTION_MASK); ++ tmp |= (FM_PCD_AD_STATS_NAD_EN | FM_PCD_AD_STATS_OP_CODE); ++ ++#if (DPAA_VERSION >= 11) ++ if (p_FmPcdCcStatsParams->h_StatsFLRs) ++ tmp |= FM_PCD_AD_STATS_FLR_EN; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ WRITE_UINT32(p_StatsAd->nextActionIndx, tmp); ++ ++ statsCountersAddr = (uint32_t)((XX_VirtToPhys( ++ p_FmPcdCcStatsParams->h_StatsCounters) - physicalMuramBase)); ++ SetStatsCounters(p_StatsAd, statsCountersAddr); ++} ++ ++static void FillAdOfTypeContLookup(t_Handle h_Ad, ++ t_FmPcdCcStatsParams *p_FmPcdCcStatsParams, ++ t_Handle h_FmPcd, t_Handle p_CcNode, ++ t_Handle h_Manip, t_Handle h_FrmReplic) ++{ ++ t_FmPcdCcNode *p_Node = (t_FmPcdCcNode *)p_CcNode; ++ t_AdOfTypeContLookup *p_AdContLookup = (t_AdOfTypeContLookup *)h_Ad; ++ t_Handle h_TmpAd; ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint32_t tmpReg32; ++ t_Handle p_AdNewPtr = NULL; ++ ++ UNUSED(h_Manip); ++ UNUSED(h_FrmReplic); ++ ++ /* there are 3 cases handled in this routine of building a "Continue lookup" type AD. ++ * Case 1: No Manip. The action descriptor is built within the match table. ++ * p_AdResult = p_AdNewPtr; ++ * Case 2: Manip exists. A new AD is created - p_AdNewPtr. It is initialized ++ * either in the FmPcdManipUpdateAdResultForCc routine or it was already ++ * initialized and returned here. ++ * p_AdResult (within the match table) will be initialized after ++ * this routine returns and point to the existing AD. ++ * Case 3: Manip exists. The action descriptor is built within the match table. ++ * FmPcdManipUpdateAdContLookupForCc returns a NULL p_AdNewPtr. ++ */ ++ ++ /* As default, the "new" ptr is the current one. i.e. the content of the result ++ * AD will be written into the match table itself (case (1))*/ ++ p_AdNewPtr = p_AdContLookup; ++ ++ /* Initialize an action descriptor, if current statistics mode requires an Ad */ ++ if (p_FmPcdCcStatsParams) ++ { ++ ASSERT_COND(p_FmPcdCcStatsParams->h_StatsAd); ++ ASSERT_COND(p_FmPcdCcStatsParams->h_StatsCounters); ++ ++ /* Swapping addresses between statistics Ad and the current lookup AD */ ++ h_TmpAd = p_FmPcdCcStatsParams->h_StatsAd; ++ p_FmPcdCcStatsParams->h_StatsAd = h_Ad; ++ h_Ad = h_TmpAd; ++ ++ p_AdNewPtr = h_Ad; ++ p_AdContLookup = h_Ad; ++ ++ /* Init statistics Ad and connect current lookup AD as 'next action' from statistics Ad */ ++ UpdateStatsAd(p_FmPcdCcStatsParams, h_Ad, p_FmPcd->physicalMuramBase); ++ } ++ ++#if DPAA_VERSION >= 11 ++ if (h_Manip && h_FrmReplic) ++ FmPcdManipUpdateAdContLookupForCc( ++ h_Manip, ++ h_Ad, ++ &p_AdNewPtr, ++ (uint32_t)((XX_VirtToPhys( ++ FrmReplicGroupGetSourceTableDescriptor(h_FrmReplic)) ++ - p_FmPcd->physicalMuramBase))); ++ else ++ if (h_FrmReplic) ++ FrmReplicGroupUpdateAd(h_FrmReplic, h_Ad, &p_AdNewPtr); ++ else ++#endif /* (DPAA_VERSION >= 11) */ ++ if (h_Manip) ++ FmPcdManipUpdateAdContLookupForCc( ++ h_Manip, ++ h_Ad, ++ &p_AdNewPtr, ++ ++#ifdef FM_CAPWAP_SUPPORT ++ /*no check for opcode of manip - this step can be reached only with capwap_applic_specific*/ ++ (uint32_t)((XX_VirtToPhys(p_Node->h_AdTable) - p_FmPcd->physicalMuramBase)) ++#else /* not FM_CAPWAP_SUPPORT */ ++ (uint32_t)((XX_VirtToPhys(p_Node->h_Ad) ++ - p_FmPcd->physicalMuramBase)) ++#endif /* not FM_CAPWAP_SUPPORT */ ++ ); ++ ++ /* if (p_AdNewPtr = NULL) --> Done. (case (3)) */ ++ if (p_AdNewPtr) ++ { ++ /* cases (1) & (2) */ ++ tmpReg32 = 0; ++ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; ++ tmpReg32 |= ++ p_Node->sizeOfExtraction ? ((p_Node->sizeOfExtraction - 1) << 24) : ++ 0; ++ tmpReg32 |= (uint32_t)(XX_VirtToPhys(p_Node->h_AdTable) ++ - p_FmPcd->physicalMuramBase); ++ WRITE_UINT32(p_AdContLookup->ccAdBase, tmpReg32); ++ ++ tmpReg32 = 0; ++ tmpReg32 |= p_Node->numOfKeys << 24; ++ tmpReg32 |= (p_Node->lclMask ? FM_PCD_AD_CONT_LOOKUP_LCL_MASK : 0); ++ tmpReg32 |= ++ p_Node->h_KeysMatchTable ? (uint32_t)(XX_VirtToPhys( ++ p_Node->h_KeysMatchTable) - p_FmPcd->physicalMuramBase) : ++ 0; ++ WRITE_UINT32(p_AdContLookup->matchTblPtr, tmpReg32); ++ ++ tmpReg32 = 0; ++ tmpReg32 |= p_Node->prsArrayOffset << 24; ++ tmpReg32 |= p_Node->offset << 16; ++ tmpReg32 |= p_Node->parseCode; ++ WRITE_UINT32(p_AdContLookup->pcAndOffsets, tmpReg32); ++ ++ MemCpy8((void*)&p_AdContLookup->gmask, p_Node->p_GlblMask, ++ CC_GLBL_MASK_SIZE); ++ } ++} ++ ++static t_Error AllocAndFillAdForContLookupManip(t_Handle h_CcNode) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ uint32_t intFlags; ++ ++ ASSERT_COND(p_CcNode); ++ ++ intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock); ++ ++ if (!p_CcNode->h_Ad) ++ { ++ if (p_CcNode->maxNumOfKeys) ++ p_CcNode->h_Ad = p_CcNode->h_TmpAd; ++ else ++ p_CcNode->h_Ad = (t_Handle)FM_MURAM_AllocMem( ++ ((t_FmPcd *)(p_CcNode->h_FmPcd))->h_FmMuram, ++ FM_PCD_CC_AD_ENTRY_SIZE, FM_PCD_CC_AD_TABLE_ALIGN); ++ ++ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); ++ ++ if (!p_CcNode->h_Ad) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("MURAM allocation for CC action descriptor")); ++ ++ MemSet8(p_CcNode->h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ FillAdOfTypeContLookup(p_CcNode->h_Ad, NULL, p_CcNode->h_FmPcd, ++ p_CcNode, NULL, NULL); ++ } ++ else ++ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); ++ ++ return E_OK; ++} ++ ++static t_Error SetRequiredAction1( ++ t_Handle h_FmPcd, uint32_t requiredAction, ++ t_FmPcdCcKeyAndNextEngineParams *p_CcKeyAndNextEngineParamsTmp, ++ t_Handle h_AdTmp, uint16_t numOfEntries, t_Handle h_Tree) ++{ ++ t_AdOfTypeResult *p_AdTmp = (t_AdOfTypeResult *)h_AdTmp; ++ uint32_t tmpReg32; ++ t_Error err; ++ t_FmPcdCcNode *p_CcNode; ++ int i = 0; ++ uint16_t tmp = 0; ++ uint16_t profileId; ++ uint8_t relativeSchemeId, physicalSchemeId; ++ t_CcNodeInformation ccNodeInfo; ++ ++ for (i = 0; i < numOfEntries; i++) ++ { ++ if (i == 0) ++ h_AdTmp = PTR_MOVE(h_AdTmp, i*FM_PCD_CC_AD_ENTRY_SIZE); ++ else ++ h_AdTmp = PTR_MOVE(h_AdTmp, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ switch (p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.nextEngine) ++ { ++ case (e_FM_PCD_CC): ++ if (requiredAction) ++ { ++ p_CcNode = ++ p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.ccParams.h_CcNode; ++ ASSERT_COND(p_CcNode); ++ if (p_CcNode->shadowAction == requiredAction) ++ break; ++ if ((requiredAction & UPDATE_CC_WITH_TREE) ++ && !(p_CcNode->shadowAction & UPDATE_CC_WITH_TREE)) ++ { ++ ++ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); ++ ccNodeInfo.h_CcNode = h_Tree; ++ EnqueueNodeInfoToRelevantLst(&p_CcNode->ccTreesLst, ++ &ccNodeInfo, NULL); ++ p_CcKeyAndNextEngineParamsTmp[i].shadowAction |= ++ UPDATE_CC_WITH_TREE; ++ } ++ if ((requiredAction & UPDATE_CC_SHADOW_CLEAR) ++ && !(p_CcNode->shadowAction & UPDATE_CC_SHADOW_CLEAR)) ++ { ++ ++ p_CcNode->shadowAction = 0; ++ } ++ ++ if ((requiredAction & UPDATE_CC_WITH_DELETE_TREE) ++ && !(p_CcNode->shadowAction ++ & UPDATE_CC_WITH_DELETE_TREE)) ++ { ++ DequeueNodeInfoFromRelevantLst(&p_CcNode->ccTreesLst, ++ h_Tree, NULL); ++ p_CcKeyAndNextEngineParamsTmp[i].shadowAction |= ++ UPDATE_CC_WITH_DELETE_TREE; ++ } ++ if (p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.nextEngine ++ != e_FM_PCD_INVALID) ++ tmp = (uint8_t)(p_CcNode->numOfKeys + 1); ++ else ++ tmp = p_CcNode->numOfKeys; ++ err = SetRequiredAction1(h_FmPcd, requiredAction, ++ p_CcNode->keyAndNextEngineParams, ++ p_CcNode->h_AdTable, tmp, h_Tree); ++ if (err != E_OK) ++ return err; ++ if (requiredAction != UPDATE_CC_SHADOW_CLEAR) ++ p_CcNode->shadowAction |= requiredAction; ++ } ++ break; ++ ++ case (e_FM_PCD_KG): ++ if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) ++ && !(p_CcKeyAndNextEngineParamsTmp[i].shadowAction ++ & UPDATE_NIA_ENQ_WITHOUT_DMA)) ++ { ++ physicalSchemeId = ++ FmPcdKgGetSchemeId( ++ p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.kgParams.h_DirectScheme); ++ relativeSchemeId = FmPcdKgGetRelativeSchemeId( ++ h_FmPcd, physicalSchemeId); ++ if (relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) ++ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); ++ if (!FmPcdKgIsSchemeValidSw( ++ p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.kgParams.h_DirectScheme)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("Invalid direct scheme.")); ++ if (!KgIsSchemeAlwaysDirect(h_FmPcd, relativeSchemeId)) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_STATE, ++ ("For this action scheme has to be direct.")); ++ err = ++ FmPcdKgCcGetSetParams( ++ h_FmPcd, ++ p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.kgParams.h_DirectScheme, ++ requiredAction, 0); ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ p_CcKeyAndNextEngineParamsTmp[i].shadowAction |= ++ requiredAction; ++ } ++ break; ++ ++ case (e_FM_PCD_PLCR): ++ if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) ++ && !(p_CcKeyAndNextEngineParamsTmp[i].shadowAction ++ & UPDATE_NIA_ENQ_WITHOUT_DMA)) ++ { ++ if (!p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.plcrParams.overrideParams) ++ RETURN_ERROR( ++ MAJOR, ++ E_NOT_SUPPORTED, ++ ("In this initialization only overrideFqid can be initialized")); ++ if (!p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.plcrParams.sharedProfile) ++ RETURN_ERROR( ++ MAJOR, ++ E_NOT_SUPPORTED, ++ ("In this initialization only overrideFqid can be initialized")); ++ err = ++ FmPcdPlcrGetAbsoluteIdByProfileParams( ++ h_FmPcd, ++ e_FM_PCD_PLCR_SHARED, ++ NULL, ++ p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.plcrParams.newRelativeProfileId, ++ &profileId); ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ err = FmPcdPlcrCcGetSetParams(h_FmPcd, profileId, ++ requiredAction); ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ p_CcKeyAndNextEngineParamsTmp[i].shadowAction |= ++ requiredAction; ++ } ++ break; ++ ++ case (e_FM_PCD_DONE): ++ if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) ++ && !(p_CcKeyAndNextEngineParamsTmp[i].shadowAction ++ & UPDATE_NIA_ENQ_WITHOUT_DMA)) ++ { ++ tmpReg32 = GET_UINT32(p_AdTmp->nia); ++ if ((tmpReg32 & GET_NIA_BMI_AC_ENQ_FRAME(h_FmPcd)) ++ != GET_NIA_BMI_AC_ENQ_FRAME(h_FmPcd)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("Next engine was previously assigned not as PCD_DONE")); ++ tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; ++ WRITE_UINT32(p_AdTmp->nia, tmpReg32); ++ p_CcKeyAndNextEngineParamsTmp[i].shadowAction |= ++ requiredAction; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ } ++ ++ return E_OK; ++} ++ ++static t_Error SetRequiredAction( ++ t_Handle h_FmPcd, uint32_t requiredAction, ++ t_FmPcdCcKeyAndNextEngineParams *p_CcKeyAndNextEngineParamsTmp, ++ t_Handle h_AdTmp, uint16_t numOfEntries, t_Handle h_Tree) ++{ ++ t_Error err = SetRequiredAction1(h_FmPcd, requiredAction, ++ p_CcKeyAndNextEngineParamsTmp, h_AdTmp, ++ numOfEntries, h_Tree); ++ if (err != E_OK) ++ return err; ++ return SetRequiredAction1(h_FmPcd, UPDATE_CC_SHADOW_CLEAR, ++ p_CcKeyAndNextEngineParamsTmp, h_AdTmp, ++ numOfEntries, h_Tree); ++} ++ ++static t_Error ReleaseModifiedDataStructure( ++ t_Handle h_FmPcd, t_List *h_FmPcdOldPointersLst, ++ t_List *h_FmPcdNewPointersLst, ++ t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalParams, ++ bool useShadowStructs) ++{ ++ t_List *p_Pos; ++ t_Error err = E_OK; ++ t_CcNodeInformation ccNodeInfo, *p_CcNodeInformation; ++ t_Handle h_Muram; ++ t_FmPcdCcNode *p_FmPcdCcNextNode, *p_FmPcdCcWorkingOnNode; ++ t_List *p_UpdateLst; ++ uint32_t intFlags; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_AdditionalParams->h_CurrentNode, ++ E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(h_FmPcdOldPointersLst, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(h_FmPcdNewPointersLst, E_INVALID_HANDLE); ++ ++ /* We don't update subtree of the new node with new tree because it was done in the previous stage */ ++ if (p_AdditionalParams->h_NodeForAdd) ++ { ++ p_FmPcdCcNextNode = (t_FmPcdCcNode*)p_AdditionalParams->h_NodeForAdd; ++ ++ if (!p_AdditionalParams->tree) ++ p_UpdateLst = &p_FmPcdCcNextNode->ccPrevNodesLst; ++ else ++ p_UpdateLst = &p_FmPcdCcNextNode->ccTreeIdLst; ++ ++ p_CcNodeInformation = FindNodeInfoInReleventLst( ++ p_UpdateLst, p_AdditionalParams->h_CurrentNode, ++ p_FmPcdCcNextNode->h_Spinlock); ++ ++ if (p_CcNodeInformation) ++ p_CcNodeInformation->index++; ++ else ++ { ++ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); ++ ccNodeInfo.h_CcNode = (t_Handle)p_AdditionalParams->h_CurrentNode; ++ ccNodeInfo.index = 1; ++ EnqueueNodeInfoToRelevantLst(p_UpdateLst, &ccNodeInfo, ++ p_FmPcdCcNextNode->h_Spinlock); ++ } ++ if (p_AdditionalParams->h_ManipForAdd) ++ { ++ p_CcNodeInformation = FindNodeInfoInReleventLst( ++ FmPcdManipGetNodeLstPointedOnThisManip( ++ p_AdditionalParams->h_ManipForAdd), ++ p_AdditionalParams->h_CurrentNode, ++ FmPcdManipGetSpinlock(p_AdditionalParams->h_ManipForAdd)); ++ ++ if (p_CcNodeInformation) ++ p_CcNodeInformation->index++; ++ else ++ { ++ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); ++ ccNodeInfo.h_CcNode = ++ (t_Handle)p_AdditionalParams->h_CurrentNode; ++ ccNodeInfo.index = 1; ++ EnqueueNodeInfoToRelevantLst( ++ FmPcdManipGetNodeLstPointedOnThisManip( ++ p_AdditionalParams->h_ManipForAdd), ++ &ccNodeInfo, ++ FmPcdManipGetSpinlock( ++ p_AdditionalParams->h_ManipForAdd)); ++ } ++ } ++ } ++ ++ if (p_AdditionalParams->h_NodeForRmv) ++ { ++ p_FmPcdCcNextNode = (t_FmPcdCcNode*)p_AdditionalParams->h_NodeForRmv; ++ ++ if (!p_AdditionalParams->tree) ++ { ++ p_UpdateLst = &p_FmPcdCcNextNode->ccPrevNodesLst; ++ p_FmPcdCcWorkingOnNode = ++ (t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode); ++ ++ for (p_Pos = LIST_FIRST(&p_FmPcdCcWorkingOnNode->ccTreesLst); ++ p_Pos != (&p_FmPcdCcWorkingOnNode->ccTreesLst); p_Pos = ++ LIST_NEXT(p_Pos)) ++ { ++ p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); ++ ++ ASSERT_COND(p_CcNodeInformation->h_CcNode); ++ ++ err = ++ SetRequiredAction( ++ h_FmPcd, ++ UPDATE_CC_WITH_DELETE_TREE, ++ &((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->keyAndNextEngineParams[p_AdditionalParams->savedKeyIndex], ++ PTR_MOVE(((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_AdTable, p_AdditionalParams->savedKeyIndex*FM_PCD_CC_AD_ENTRY_SIZE), ++ 1, p_CcNodeInformation->h_CcNode); ++ } ++ } ++ else ++ { ++ p_UpdateLst = &p_FmPcdCcNextNode->ccTreeIdLst; ++ ++ err = ++ SetRequiredAction( ++ h_FmPcd, ++ UPDATE_CC_WITH_DELETE_TREE, ++ &((t_FmPcdCcTree *)(p_AdditionalParams->h_CurrentNode))->keyAndNextEngineParams[p_AdditionalParams->savedKeyIndex], ++ UINT_TO_PTR(((t_FmPcdCcTree *)(p_AdditionalParams->h_CurrentNode))->ccTreeBaseAddr + p_AdditionalParams->savedKeyIndex*FM_PCD_CC_AD_ENTRY_SIZE), ++ 1, p_AdditionalParams->h_CurrentNode); ++ } ++ if (err) ++ return err; ++ ++ /* We remove from the subtree of the removed node tree because it wasn't done in the previous stage ++ Update ccPrevNodesLst or ccTreeIdLst of the removed node ++ Update of the node owner */ ++ p_CcNodeInformation = FindNodeInfoInReleventLst( ++ p_UpdateLst, p_AdditionalParams->h_CurrentNode, ++ p_FmPcdCcNextNode->h_Spinlock); ++ ++ ASSERT_COND(p_CcNodeInformation); ++ ASSERT_COND(p_CcNodeInformation->index); ++ ++ p_CcNodeInformation->index--; ++ ++ if (p_CcNodeInformation->index == 0) ++ DequeueNodeInfoFromRelevantLst(p_UpdateLst, ++ p_AdditionalParams->h_CurrentNode, ++ p_FmPcdCcNextNode->h_Spinlock); ++ ++ UpdateNodeOwner(p_FmPcdCcNextNode, FALSE); ++ ++ if (p_AdditionalParams->h_ManipForRmv) ++ { ++ p_CcNodeInformation = FindNodeInfoInReleventLst( ++ FmPcdManipGetNodeLstPointedOnThisManip( ++ p_AdditionalParams->h_ManipForRmv), ++ p_AdditionalParams->h_CurrentNode, ++ FmPcdManipGetSpinlock(p_AdditionalParams->h_ManipForRmv)); ++ ++ ASSERT_COND(p_CcNodeInformation); ++ ASSERT_COND(p_CcNodeInformation->index); ++ ++ p_CcNodeInformation->index--; ++ ++ if (p_CcNodeInformation->index == 0) ++ DequeueNodeInfoFromRelevantLst( ++ FmPcdManipGetNodeLstPointedOnThisManip( ++ p_AdditionalParams->h_ManipForRmv), ++ p_AdditionalParams->h_CurrentNode, ++ FmPcdManipGetSpinlock( ++ p_AdditionalParams->h_ManipForRmv)); ++ } ++ } ++ ++ if (p_AdditionalParams->h_ManipForRmv) ++ FmPcdManipUpdateOwner(p_AdditionalParams->h_ManipForRmv, FALSE); ++ ++ if (p_AdditionalParams->p_StatsObjForRmv) ++ PutStatsObj((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode), ++ p_AdditionalParams->p_StatsObjForRmv); ++ ++#if (DPAA_VERSION >= 11) ++ if (p_AdditionalParams->h_FrmReplicForRmv) ++ FrmReplicGroupUpdateOwner(p_AdditionalParams->h_FrmReplicForRmv, ++ FALSE/* remove */); ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ if (!useShadowStructs) ++ { ++ h_Muram = FmPcdGetMuramHandle(h_FmPcd); ++ ASSERT_COND(h_Muram); ++ ++ if ((p_AdditionalParams->tree && !((t_FmPcd *)h_FmPcd)->p_CcShadow) ++ || (!p_AdditionalParams->tree ++ && !((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->maxNumOfKeys)) ++ { ++ /* We release new AD which was allocated and updated for copy from to actual AD */ ++ for (p_Pos = LIST_FIRST(h_FmPcdNewPointersLst); ++ p_Pos != (h_FmPcdNewPointersLst); p_Pos = LIST_NEXT(p_Pos)) ++ { ++ ++ p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); ++ ASSERT_COND(p_CcNodeInformation->h_CcNode); ++ FM_MURAM_FreeMem(h_Muram, p_CcNodeInformation->h_CcNode); ++ } ++ } ++ ++ /* Free Old data structure if it has to be freed - new data structure was allocated*/ ++ if (p_AdditionalParams->p_AdTableOld) ++ FM_MURAM_FreeMem(h_Muram, p_AdditionalParams->p_AdTableOld); ++ ++ if (p_AdditionalParams->p_KeysMatchTableOld) ++ FM_MURAM_FreeMem(h_Muram, p_AdditionalParams->p_KeysMatchTableOld); ++ } ++ ++ /* Update current modified node with changed fields if it's required*/ ++ if (!p_AdditionalParams->tree) ++ { ++ if (p_AdditionalParams->p_AdTableNew) ++ ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_AdTable = ++ p_AdditionalParams->p_AdTableNew; ++ ++ if (p_AdditionalParams->p_KeysMatchTableNew) ++ ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_KeysMatchTable = ++ p_AdditionalParams->p_KeysMatchTableNew; ++ ++ /* Locking node's spinlock before updating 'keys and next engine' structure, ++ as it maybe used to retrieve keys statistics */ ++ intFlags = ++ XX_LockIntrSpinlock( ++ ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_Spinlock); ++ ++ ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->numOfKeys = ++ p_AdditionalParams->numOfKeys; ++ ++ memcpy(((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->keyAndNextEngineParams, ++ &p_AdditionalParams->keyAndNextEngineParams, ++ sizeof(t_FmPcdCcKeyAndNextEngineParams) * (CC_MAX_NUM_OF_KEYS)); ++ ++ XX_UnlockIntrSpinlock( ++ ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_Spinlock, ++ intFlags); ++ } ++ else ++ { ++ uint8_t numEntries = ++ ((t_FmPcdCcTree *)(p_AdditionalParams->h_CurrentNode))->numOfEntries; ++ ASSERT_COND(numEntries < FM_PCD_MAX_NUM_OF_CC_GROUPS); ++ memcpy(&((t_FmPcdCcTree *)(p_AdditionalParams->h_CurrentNode))->keyAndNextEngineParams, ++ &p_AdditionalParams->keyAndNextEngineParams, ++ sizeof(t_FmPcdCcKeyAndNextEngineParams) * numEntries); ++ } ++ ++ ReleaseLst(h_FmPcdOldPointersLst); ++ ReleaseLst(h_FmPcdNewPointersLst); ++ ++ XX_Free(p_AdditionalParams); ++ ++ return E_OK; ++} ++ ++static t_Handle BuildNewAd( ++ t_Handle h_Ad, ++ t_FmPcdModifyCcKeyAdditionalParams *p_FmPcdModifyCcKeyAdditionalParams, ++ t_FmPcdCcNode *p_CcNode, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) ++{ ++ t_FmPcdCcNode *p_FmPcdCcNodeTmp; ++ t_Handle h_OrigAd = NULL; ++ ++ p_FmPcdCcNodeTmp = (t_FmPcdCcNode*)XX_Malloc(sizeof(t_FmPcdCcNode)); ++ if (!p_FmPcdCcNodeTmp) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_FmPcdCcNodeTmp")); ++ return NULL; ++ } ++ memset(p_FmPcdCcNodeTmp, 0, sizeof(t_FmPcdCcNode)); ++ ++ p_FmPcdCcNodeTmp->numOfKeys = p_FmPcdModifyCcKeyAdditionalParams->numOfKeys; ++ p_FmPcdCcNodeTmp->h_KeysMatchTable = ++ p_FmPcdModifyCcKeyAdditionalParams->p_KeysMatchTableNew; ++ p_FmPcdCcNodeTmp->h_AdTable = ++ p_FmPcdModifyCcKeyAdditionalParams->p_AdTableNew; ++ ++ p_FmPcdCcNodeTmp->lclMask = p_CcNode->lclMask; ++ p_FmPcdCcNodeTmp->parseCode = p_CcNode->parseCode; ++ p_FmPcdCcNodeTmp->offset = p_CcNode->offset; ++ p_FmPcdCcNodeTmp->prsArrayOffset = p_CcNode->prsArrayOffset; ++ p_FmPcdCcNodeTmp->ctrlFlow = p_CcNode->ctrlFlow; ++ p_FmPcdCcNodeTmp->ccKeySizeAccExtraction = p_CcNode->ccKeySizeAccExtraction; ++ p_FmPcdCcNodeTmp->sizeOfExtraction = p_CcNode->sizeOfExtraction; ++ p_FmPcdCcNodeTmp->glblMaskSize = p_CcNode->glblMaskSize; ++ p_FmPcdCcNodeTmp->p_GlblMask = p_CcNode->p_GlblMask; ++ ++ if (p_FmPcdCcNextEngineParams->nextEngine == e_FM_PCD_CC) ++ { ++ if (p_FmPcdCcNextEngineParams->h_Manip) ++ { ++ h_OrigAd = p_CcNode->h_Ad; ++ if (AllocAndFillAdForContLookupManip( ++ p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode) ++ != E_OK) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ XX_Free(p_FmPcdCcNodeTmp); ++ return NULL; ++ } ++ } ++ FillAdOfTypeContLookup(h_Ad, NULL, p_CcNode->h_FmPcd, p_FmPcdCcNodeTmp, ++ h_OrigAd ? NULL : p_FmPcdCcNextEngineParams->h_Manip, NULL); ++ } ++ ++#if (DPAA_VERSION >= 11) ++ if ((p_FmPcdCcNextEngineParams->nextEngine == e_FM_PCD_FR) ++ && (p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic)) ++ { ++ FillAdOfTypeContLookup( ++ h_Ad, NULL, p_CcNode->h_FmPcd, p_FmPcdCcNodeTmp, ++ p_FmPcdCcNextEngineParams->h_Manip, ++ p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic); ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ XX_Free(p_FmPcdCcNodeTmp); ++ ++ return E_OK; ++} ++ ++static t_Error DynamicChangeHc( ++ t_Handle h_FmPcd, t_List *h_OldPointersLst, t_List *h_NewPointersLst, ++ t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalParams, ++ bool useShadowStructs) ++{ ++ t_List *p_PosOld, *p_PosNew; ++ uint32_t oldAdAddrOffset, newAdAddrOffset; ++ uint16_t i = 0; ++ t_Error err = E_OK; ++ uint8_t numOfModifiedPtr; ++ ++ ASSERT_COND(h_FmPcd); ++ ASSERT_COND(h_OldPointersLst); ++ ASSERT_COND(h_NewPointersLst); ++ ++ numOfModifiedPtr = (uint8_t)LIST_NumOfObjs(h_OldPointersLst); ++ ++ if (numOfModifiedPtr) ++ { ++ p_PosNew = LIST_FIRST(h_NewPointersLst); ++ p_PosOld = LIST_FIRST(h_OldPointersLst); ++ ++ /* Retrieve address of new AD */ ++ newAdAddrOffset = FmPcdCcGetNodeAddrOffsetFromNodeInfo(h_FmPcd, ++ p_PosNew); ++ if (newAdAddrOffset == (uint32_t)ILLEGAL_BASE) ++ { ++ ReleaseModifiedDataStructure(h_FmPcd, h_OldPointersLst, ++ h_NewPointersLst, ++ p_AdditionalParams, useShadowStructs); ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("New AD address")); ++ } ++ ++ for (i = 0; i < numOfModifiedPtr; i++) ++ { ++ /* Retrieve address of current AD */ ++ oldAdAddrOffset = FmPcdCcGetNodeAddrOffsetFromNodeInfo(h_FmPcd, ++ p_PosOld); ++ if (oldAdAddrOffset == (uint32_t)ILLEGAL_BASE) ++ { ++ ReleaseModifiedDataStructure(h_FmPcd, h_OldPointersLst, ++ h_NewPointersLst, ++ p_AdditionalParams, ++ useShadowStructs); ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Old AD address")); ++ } ++ ++ /* Invoke host command to copy from new AD to old AD */ ++ err = FmHcPcdCcDoDynamicChange(((t_FmPcd *)h_FmPcd)->h_Hc, ++ oldAdAddrOffset, newAdAddrOffset); ++ if (err) ++ { ++ ReleaseModifiedDataStructure(h_FmPcd, h_OldPointersLst, ++ h_NewPointersLst, ++ p_AdditionalParams, ++ useShadowStructs); ++ RETURN_ERROR( ++ MAJOR, ++ err, ++ ("For part of nodes changes are done - situation is danger")); ++ } ++ ++ p_PosOld = LIST_NEXT(p_PosOld); ++ } ++ } ++ return E_OK; ++} ++ ++static t_Error DoDynamicChange( ++ t_Handle h_FmPcd, t_List *h_OldPointersLst, t_List *h_NewPointersLst, ++ t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalParams, ++ bool useShadowStructs) ++{ ++ t_FmPcdCcNode *p_CcNode = ++ (t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode); ++ t_List *p_PosNew; ++ t_CcNodeInformation *p_CcNodeInfo; ++ t_FmPcdCcNextEngineParams nextEngineParams; ++ t_Handle h_Ad; ++ uint32_t keySize; ++ t_Error err = E_OK; ++ uint8_t numOfModifiedPtr; ++ ++ ASSERT_COND(h_FmPcd); ++ ++ memset(&nextEngineParams, 0, sizeof(t_FmPcdCcNextEngineParams)); ++ ++ numOfModifiedPtr = (uint8_t)LIST_NumOfObjs(h_OldPointersLst); ++ ++ if (numOfModifiedPtr) ++ { ++ ++ p_PosNew = LIST_FIRST(h_NewPointersLst); ++ ++ /* Invoke host-command to copy from the new Ad to existing Ads */ ++ err = DynamicChangeHc(h_FmPcd, h_OldPointersLst, h_NewPointersLst, ++ p_AdditionalParams, useShadowStructs); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ if (useShadowStructs) ++ { ++ /* When the host-command above has ended, the old structures are 'free'and we can update ++ them by copying from the new shadow structures. */ ++ if (p_CcNode->lclMask) ++ keySize = (uint32_t)(2 * p_CcNode->ccKeySizeAccExtraction); ++ else ++ keySize = p_CcNode->ccKeySizeAccExtraction; ++ ++ MemCpy8(p_AdditionalParams->p_KeysMatchTableOld, ++ p_AdditionalParams->p_KeysMatchTableNew, ++ p_CcNode->maxNumOfKeys * keySize * sizeof(uint8_t)); ++ ++ MemCpy8( ++ p_AdditionalParams->p_AdTableOld, ++ p_AdditionalParams->p_AdTableNew, ++ (uint32_t)((p_CcNode->maxNumOfKeys + 1) ++ * FM_PCD_CC_AD_ENTRY_SIZE)); ++ ++ /* Retrieve the address of the allocated Ad */ ++ p_CcNodeInfo = CC_NODE_F_OBJECT(p_PosNew); ++ h_Ad = p_CcNodeInfo->h_CcNode; ++ ++ /* Build a new Ad that holds the old (now updated) structures */ ++ p_AdditionalParams->p_KeysMatchTableNew = ++ p_AdditionalParams->p_KeysMatchTableOld; ++ p_AdditionalParams->p_AdTableNew = p_AdditionalParams->p_AdTableOld; ++ ++ nextEngineParams.nextEngine = e_FM_PCD_CC; ++ nextEngineParams.params.ccParams.h_CcNode = (t_Handle)p_CcNode; ++ ++ BuildNewAd(h_Ad, p_AdditionalParams, p_CcNode, &nextEngineParams); ++ ++ /* HC to copy from the new Ad (old updated structures) to current Ad (uses shadow structures) */ ++ err = DynamicChangeHc(h_FmPcd, h_OldPointersLst, h_NewPointersLst, ++ p_AdditionalParams, useShadowStructs); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ } ++ ++ err = ReleaseModifiedDataStructure(h_FmPcd, h_OldPointersLst, ++ h_NewPointersLst, ++ p_AdditionalParams, useShadowStructs); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ return E_OK; ++} ++ ++#ifdef FM_CAPWAP_SUPPORT ++static bool IsCapwapApplSpecific(t_Handle h_Node) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_Node; ++ bool isManipForCapwapApplSpecificBuild = FALSE; ++ int i = 0; ++ ++ ASSERT_COND(h_Node); ++ /* assumption that this function called only for INDEXED_FLOW_ID - so no miss*/ ++ for (i = 0; i < p_CcNode->numOfKeys; i++) ++ { ++ if ( p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip && ++ FmPcdManipIsCapwapApplSpecific(p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip)) ++ { ++ isManipForCapwapApplSpecificBuild = TRUE; ++ break; ++ } ++ } ++ return isManipForCapwapApplSpecificBuild; ++ ++} ++#endif /* FM_CAPWAP_SUPPORT */ ++ ++static t_Error CcUpdateParam( ++ t_Handle h_FmPcd, t_Handle h_PcdParams, t_Handle h_FmPort, ++ t_FmPcdCcKeyAndNextEngineParams *p_CcKeyAndNextEngineParams, ++ uint16_t numOfEntries, t_Handle h_Ad, bool validate, uint16_t level, ++ t_Handle h_FmTree, bool modify) ++{ ++ t_FmPcdCcNode *p_CcNode; ++ t_Error err; ++ uint16_t tmp = 0; ++ int i = 0; ++ t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *)h_FmTree; ++ ++ level++; ++ ++ if (p_CcTree->h_IpReassemblyManip) ++ { ++ err = FmPcdManipUpdate(h_FmPcd, h_PcdParams, h_FmPort, ++ p_CcTree->h_IpReassemblyManip, NULL, validate, ++ level, h_FmTree, modify); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ if (p_CcTree->h_CapwapReassemblyManip) ++ { ++ err = FmPcdManipUpdate(h_FmPcd, h_PcdParams, h_FmPort, ++ p_CcTree->h_CapwapReassemblyManip, NULL, validate, ++ level, h_FmTree, modify); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ if (numOfEntries) ++ { ++ for (i = 0; i < numOfEntries; i++) ++ { ++ if (i == 0) ++ h_Ad = PTR_MOVE(h_Ad, i*FM_PCD_CC_AD_ENTRY_SIZE); ++ else ++ h_Ad = PTR_MOVE(h_Ad, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ if (p_CcKeyAndNextEngineParams[i].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ { ++ p_CcNode = ++ p_CcKeyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode; ++ ASSERT_COND(p_CcNode); ++ ++ if (p_CcKeyAndNextEngineParams[i].nextEngineParams.h_Manip) ++ { ++ err = ++ FmPcdManipUpdate( ++ h_FmPcd, ++ NULL, ++ h_FmPort, ++ p_CcKeyAndNextEngineParams[i].nextEngineParams.h_Manip, ++ h_Ad, validate, level, h_FmTree, modify); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ if (p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.nextEngine ++ != e_FM_PCD_INVALID) ++ tmp = (uint8_t)(p_CcNode->numOfKeys + 1); ++ else ++ tmp = p_CcNode->numOfKeys; ++ ++ err = CcUpdateParam(h_FmPcd, h_PcdParams, h_FmPort, ++ p_CcNode->keyAndNextEngineParams, tmp, ++ p_CcNode->h_AdTable, validate, level, ++ h_FmTree, modify); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ else ++ { ++ if (p_CcKeyAndNextEngineParams[i].nextEngineParams.h_Manip) ++ { ++ err = ++ FmPcdManipUpdate( ++ h_FmPcd, ++ NULL, ++ h_FmPort, ++ p_CcKeyAndNextEngineParams[i].nextEngineParams.h_Manip, ++ h_Ad, validate, level, h_FmTree, modify); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ } ++ } ++ } ++ ++ return E_OK; ++} ++ ++static ccPrivateInfo_t IcDefineCode(t_FmPcdCcNodeParams *p_CcNodeParam) ++{ ++ switch (p_CcNodeParam->extractCcParams.extractNonHdr.action) ++ { ++ case (e_FM_PCD_ACTION_EXACT_MATCH): ++ switch (p_CcNodeParam->extractCcParams.extractNonHdr.src) ++ { ++ case (e_FM_PCD_EXTRACT_FROM_KEY): ++ return CC_PRIVATE_INFO_IC_KEY_EXACT_MATCH; ++ case (e_FM_PCD_EXTRACT_FROM_HASH): ++ return CC_PRIVATE_INFO_IC_HASH_EXACT_MATCH; ++ default: ++ return CC_PRIVATE_INFO_NONE; ++ } ++ ++ case (e_FM_PCD_ACTION_INDEXED_LOOKUP): ++ switch (p_CcNodeParam->extractCcParams.extractNonHdr.src) ++ { ++ case (e_FM_PCD_EXTRACT_FROM_HASH): ++ return CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP; ++ case (e_FM_PCD_EXTRACT_FROM_FLOW_ID): ++ return CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP; ++ default: ++ return CC_PRIVATE_INFO_NONE; ++ } ++ ++ default: ++ break; ++ } ++ ++ return CC_PRIVATE_INFO_NONE; ++} ++ ++static t_CcNodeInformation * DequeueAdditionalInfoFromRelevantLst( ++ t_List *p_List) ++{ ++ t_CcNodeInformation *p_CcNodeInfo = NULL; ++ ++ if (!LIST_IsEmpty(p_List)) ++ { ++ p_CcNodeInfo = CC_NODE_F_OBJECT(p_List->p_Next); ++ LIST_DelAndInit(&p_CcNodeInfo->node); ++ } ++ ++ return p_CcNodeInfo; ++} ++ ++void ReleaseLst(t_List *p_List) ++{ ++ t_CcNodeInformation *p_CcNodeInfo = NULL; ++ ++ if (!LIST_IsEmpty(p_List)) ++ { ++ p_CcNodeInfo = DequeueAdditionalInfoFromRelevantLst(p_List); ++ while (p_CcNodeInfo) ++ { ++ XX_Free(p_CcNodeInfo); ++ p_CcNodeInfo = DequeueAdditionalInfoFromRelevantLst(p_List); ++ } ++ } ++ ++ LIST_Del(p_List); ++} ++ ++static void DeleteNode(t_FmPcdCcNode *p_CcNode) ++{ ++ uint32_t i; ++ ++ if (!p_CcNode) ++ return; ++ ++ if (p_CcNode->p_GlblMask) ++ { ++ XX_Free(p_CcNode->p_GlblMask); ++ p_CcNode->p_GlblMask = NULL; ++ } ++ ++ if (p_CcNode->h_KeysMatchTable) ++ { ++ FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd), ++ p_CcNode->h_KeysMatchTable); ++ p_CcNode->h_KeysMatchTable = NULL; ++ } ++ ++ if (p_CcNode->h_AdTable) ++ { ++ FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd), ++ p_CcNode->h_AdTable); ++ p_CcNode->h_AdTable = NULL; ++ } ++ ++ if (p_CcNode->h_Ad) ++ { ++ FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd), ++ p_CcNode->h_Ad); ++ p_CcNode->h_Ad = NULL; ++ p_CcNode->h_TmpAd = NULL; ++ } ++ ++ if (p_CcNode->h_StatsFLRs) ++ { ++ FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd), ++ p_CcNode->h_StatsFLRs); ++ p_CcNode->h_StatsFLRs = NULL; ++ } ++ ++ if (p_CcNode->h_Spinlock) ++ { ++ XX_FreeSpinlock(p_CcNode->h_Spinlock); ++ p_CcNode->h_Spinlock = NULL; ++ } ++ ++ /* Restore the original counters pointer instead of the mutual pointer (mutual to all hash buckets) */ ++ if (p_CcNode->isHashBucket ++ && (p_CcNode->statisticsMode != e_FM_PCD_CC_STATS_MODE_NONE)) ++ p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].p_StatsObj->h_StatsCounters = ++ p_CcNode->h_PrivMissStatsCounters; ++ ++ /* Releasing all currently used statistics objects, including 'miss' entry */ ++ for (i = 0; i < p_CcNode->numOfKeys + 1; i++) ++ if (p_CcNode->keyAndNextEngineParams[i].p_StatsObj) ++ PutStatsObj(p_CcNode, ++ p_CcNode->keyAndNextEngineParams[i].p_StatsObj); ++ ++ if (!LIST_IsEmpty(&p_CcNode->availableStatsLst)) ++ { ++ t_Handle h_FmMuram = FmPcdGetMuramHandle(p_CcNode->h_FmPcd); ++ ASSERT_COND(h_FmMuram); ++ ++ FreeStatObjects(&p_CcNode->availableStatsLst, h_FmMuram); ++ } ++ ++ LIST_Del(&p_CcNode->availableStatsLst); ++ ++ ReleaseLst(&p_CcNode->availableStatsLst); ++ ReleaseLst(&p_CcNode->ccPrevNodesLst); ++ ReleaseLst(&p_CcNode->ccTreeIdLst); ++ ReleaseLst(&p_CcNode->ccTreesLst); ++ ++ XX_Free(p_CcNode); ++} ++ ++static void DeleteTree(t_FmPcdCcTree *p_FmPcdTree, t_FmPcd *p_FmPcd) ++{ ++ if (p_FmPcdTree) ++ { ++ if (p_FmPcdTree->ccTreeBaseAddr) ++ { ++ FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_FmPcd), ++ UINT_TO_PTR(p_FmPcdTree->ccTreeBaseAddr)); ++ p_FmPcdTree->ccTreeBaseAddr = 0; ++ } ++ ++ ReleaseLst(&p_FmPcdTree->fmPortsLst); ++ ++ XX_Free(p_FmPcdTree); ++ } ++} ++ ++static void GetCcExtractKeySize(uint8_t parseCodeRealSize, ++ uint8_t *parseCodeCcSize) ++{ ++ if ((parseCodeRealSize > 0) && (parseCodeRealSize < 2)) ++ *parseCodeCcSize = 1; ++ else ++ if (parseCodeRealSize == 2) ++ *parseCodeCcSize = 2; ++ else ++ if ((parseCodeRealSize > 2) && (parseCodeRealSize <= 4)) ++ *parseCodeCcSize = 4; ++ else ++ if ((parseCodeRealSize > 4) && (parseCodeRealSize <= 8)) ++ *parseCodeCcSize = 8; ++ else ++ if ((parseCodeRealSize > 8) && (parseCodeRealSize <= 16)) ++ *parseCodeCcSize = 16; ++ else ++ if ((parseCodeRealSize > 16) ++ && (parseCodeRealSize <= 24)) ++ *parseCodeCcSize = 24; ++ else ++ if ((parseCodeRealSize > 24) ++ && (parseCodeRealSize <= 32)) ++ *parseCodeCcSize = 32; ++ else ++ if ((parseCodeRealSize > 32) ++ && (parseCodeRealSize <= 40)) ++ *parseCodeCcSize = 40; ++ else ++ if ((parseCodeRealSize > 40) ++ && (parseCodeRealSize <= 48)) ++ *parseCodeCcSize = 48; ++ else ++ if ((parseCodeRealSize > 48) ++ && (parseCodeRealSize <= 56)) ++ *parseCodeCcSize = 56; ++ else ++ *parseCodeCcSize = 0; ++} ++ ++static void GetSizeHeaderField(e_NetHeaderType hdr, t_FmPcdFields field, ++ uint8_t *parseCodeRealSize) ++{ ++ switch (hdr) ++ { ++ case (HEADER_TYPE_ETH): ++ switch (field.eth) ++ { ++ case (NET_HEADER_FIELD_ETH_DA): ++ *parseCodeRealSize = 6; ++ break; ++ ++ case (NET_HEADER_FIELD_ETH_SA): ++ *parseCodeRealSize = 6; ++ break; ++ ++ case (NET_HEADER_FIELD_ETH_TYPE): ++ *parseCodeRealSize = 2; ++ break; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported1")); ++ *parseCodeRealSize = CC_SIZE_ILLEGAL; ++ break; ++ } ++ break; ++ ++ case (HEADER_TYPE_PPPoE): ++ switch (field.pppoe) ++ { ++ case (NET_HEADER_FIELD_PPPoE_PID): ++ *parseCodeRealSize = 2; ++ break; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported1")); ++ *parseCodeRealSize = CC_SIZE_ILLEGAL; ++ break; ++ } ++ break; ++ ++ case (HEADER_TYPE_VLAN): ++ switch (field.vlan) ++ { ++ case (NET_HEADER_FIELD_VLAN_TCI): ++ *parseCodeRealSize = 2; ++ break; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported2")); ++ *parseCodeRealSize = CC_SIZE_ILLEGAL; ++ break; ++ } ++ break; ++ ++ case (HEADER_TYPE_MPLS): ++ switch (field.mpls) ++ { ++ case (NET_HEADER_FIELD_MPLS_LABEL_STACK): ++ *parseCodeRealSize = 4; ++ break; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported3")); ++ *parseCodeRealSize = CC_SIZE_ILLEGAL; ++ break; ++ } ++ break; ++ ++ case (HEADER_TYPE_IPv4): ++ switch (field.ipv4) ++ { ++ case (NET_HEADER_FIELD_IPv4_DST_IP): ++ case (NET_HEADER_FIELD_IPv4_SRC_IP): ++ *parseCodeRealSize = 4; ++ break; ++ ++ case (NET_HEADER_FIELD_IPv4_TOS): ++ case (NET_HEADER_FIELD_IPv4_PROTO): ++ *parseCodeRealSize = 1; ++ break; ++ ++ case (NET_HEADER_FIELD_IPv4_DST_IP ++ | NET_HEADER_FIELD_IPv4_SRC_IP): ++ *parseCodeRealSize = 8; ++ break; ++ ++ case (NET_HEADER_FIELD_IPv4_TTL): ++ *parseCodeRealSize = 1; ++ break; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported4")); ++ *parseCodeRealSize = CC_SIZE_ILLEGAL; ++ break; ++ } ++ break; ++ ++ case (HEADER_TYPE_IPv6): ++ switch (field.ipv6) ++ { ++ case (NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL ++ | NET_HEADER_FIELD_IPv6_TC): ++ *parseCodeRealSize = 4; ++ break; ++ ++ case (NET_HEADER_FIELD_IPv6_NEXT_HDR): ++ case (NET_HEADER_FIELD_IPv6_HOP_LIMIT): ++ *parseCodeRealSize = 1; ++ break; ++ ++ case (NET_HEADER_FIELD_IPv6_DST_IP): ++ case (NET_HEADER_FIELD_IPv6_SRC_IP): ++ *parseCodeRealSize = 16; ++ break; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported5")); ++ *parseCodeRealSize = CC_SIZE_ILLEGAL; ++ break; ++ } ++ break; ++ ++ case (HEADER_TYPE_IP): ++ switch (field.ip) ++ { ++ case (NET_HEADER_FIELD_IP_DSCP): ++ case (NET_HEADER_FIELD_IP_PROTO): ++ *parseCodeRealSize = 1; ++ break; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported5")); ++ *parseCodeRealSize = CC_SIZE_ILLEGAL; ++ break; ++ } ++ break; ++ ++ case (HEADER_TYPE_GRE): ++ switch (field.gre) ++ { ++ case (NET_HEADER_FIELD_GRE_TYPE): ++ *parseCodeRealSize = 2; ++ break; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported6")); ++ *parseCodeRealSize = CC_SIZE_ILLEGAL; ++ break; ++ } ++ break; ++ ++ case (HEADER_TYPE_MINENCAP): ++ switch (field.minencap) ++ { ++ case (NET_HEADER_FIELD_MINENCAP_TYPE): ++ *parseCodeRealSize = 1; ++ break; ++ ++ case (NET_HEADER_FIELD_MINENCAP_DST_IP): ++ case (NET_HEADER_FIELD_MINENCAP_SRC_IP): ++ *parseCodeRealSize = 4; ++ break; ++ ++ case (NET_HEADER_FIELD_MINENCAP_SRC_IP ++ | NET_HEADER_FIELD_MINENCAP_DST_IP): ++ *parseCodeRealSize = 8; ++ break; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported7")); ++ *parseCodeRealSize = CC_SIZE_ILLEGAL; ++ break; ++ } ++ break; ++ ++ case (HEADER_TYPE_TCP): ++ switch (field.tcp) ++ { ++ case (NET_HEADER_FIELD_TCP_PORT_SRC): ++ case (NET_HEADER_FIELD_TCP_PORT_DST): ++ *parseCodeRealSize = 2; ++ break; ++ ++ case (NET_HEADER_FIELD_TCP_PORT_SRC ++ | NET_HEADER_FIELD_TCP_PORT_DST): ++ *parseCodeRealSize = 4; ++ break; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported8")); ++ *parseCodeRealSize = CC_SIZE_ILLEGAL; ++ break; ++ } ++ break; ++ ++ case (HEADER_TYPE_UDP): ++ switch (field.udp) ++ { ++ case (NET_HEADER_FIELD_UDP_PORT_SRC): ++ case (NET_HEADER_FIELD_UDP_PORT_DST): ++ *parseCodeRealSize = 2; ++ break; ++ ++ case (NET_HEADER_FIELD_UDP_PORT_SRC ++ | NET_HEADER_FIELD_UDP_PORT_DST): ++ *parseCodeRealSize = 4; ++ break; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported9")); ++ *parseCodeRealSize = CC_SIZE_ILLEGAL; ++ break; ++ } ++ break; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported10")); ++ *parseCodeRealSize = CC_SIZE_ILLEGAL; ++ break; ++ } ++} ++ ++t_Error ValidateNextEngineParams( ++ t_Handle h_FmPcd, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams, ++ e_FmPcdCcStatsMode statsMode) ++{ ++ uint16_t absoluteProfileId; ++ t_Error err = E_OK; ++ uint8_t relativeSchemeId; ++ ++ if ((statsMode == e_FM_PCD_CC_STATS_MODE_NONE) ++ && (p_FmPcdCcNextEngineParams->statisticsEn)) ++ RETURN_ERROR( ++ MAJOR, ++ E_CONFLICT, ++ ("Statistics are requested for a key, but statistics mode was set" ++ "to 'NONE' upon initialization")); ++ ++ switch (p_FmPcdCcNextEngineParams->nextEngine) ++ { ++ case (e_FM_PCD_INVALID): ++ err = E_NOT_SUPPORTED; ++ break; ++ ++ case (e_FM_PCD_DONE): ++ if ((p_FmPcdCcNextEngineParams->params.enqueueParams.action ++ == e_FM_PCD_ENQ_FRAME) ++ && p_FmPcdCcNextEngineParams->params.enqueueParams.overrideFqid) ++ { ++ if (!p_FmPcdCcNextEngineParams->params.enqueueParams.newFqid) ++ RETURN_ERROR( ++ MAJOR, ++ E_CONFLICT, ++ ("When overrideFqid is set, newFqid must not be zero")); ++ if (p_FmPcdCcNextEngineParams->params.enqueueParams.newFqid ++ & ~0x00FFFFFF) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("fqidForCtrlFlow must be between 1 and 2^24-1")); ++ } ++ break; ++ ++ case (e_FM_PCD_KG): ++ relativeSchemeId = ++ FmPcdKgGetRelativeSchemeId( ++ h_FmPcd, ++ FmPcdKgGetSchemeId( ++ p_FmPcdCcNextEngineParams->params.kgParams.h_DirectScheme)); ++ if (relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) ++ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); ++ if (!FmPcdKgIsSchemeValidSw( ++ p_FmPcdCcNextEngineParams->params.kgParams.h_DirectScheme)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("not valid schemeIndex in KG next engine param")); ++ if (!KgIsSchemeAlwaysDirect(h_FmPcd, relativeSchemeId)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("CC Node may point only to a scheme that is always direct.")); ++ break; ++ ++ case (e_FM_PCD_PLCR): ++ if (p_FmPcdCcNextEngineParams->params.plcrParams.overrideParams) ++ { ++ /* if private policer profile, it may be uninitialized yet, therefore no checks are done at this stage */ ++ if (p_FmPcdCcNextEngineParams->params.plcrParams.sharedProfile) ++ { ++ err = ++ FmPcdPlcrGetAbsoluteIdByProfileParams( ++ h_FmPcd, ++ e_FM_PCD_PLCR_SHARED, ++ NULL, ++ p_FmPcdCcNextEngineParams->params.plcrParams.newRelativeProfileId, ++ &absoluteProfileId); ++ if (err) ++ RETURN_ERROR(MAJOR, err, ++ ("Shared profile offset is out of range")); ++ if (!FmPcdPlcrIsProfileValid(h_FmPcd, absoluteProfileId)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("Invalid profile")); ++ } ++ } ++ break; ++ ++ case (e_FM_PCD_HASH): ++ p_FmPcdCcNextEngineParams->nextEngine = e_FM_PCD_CC; ++ case (e_FM_PCD_CC): ++ if (!p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode) ++ RETURN_ERROR(MAJOR, E_NULL_POINTER, ++ ("handler to next Node is NULL")); ++ break; ++ ++#if (DPAA_VERSION >= 11) ++ case (e_FM_PCD_FR): ++ if (!p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic) ++ err = E_NOT_SUPPORTED; ++ break; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("Next engine is not correct")); ++ } ++ ++ ++ return err; ++} ++ ++static uint8_t GetGenParseCode(e_FmPcdExtractFrom src, ++ uint32_t offset, bool glblMask, ++ uint8_t *parseArrayOffset, bool fromIc, ++ ccPrivateInfo_t icCode) ++{ ++ if (!fromIc) ++ { ++ switch (src) ++ { ++ case (e_FM_PCD_EXTRACT_FROM_FRAME_START): ++ if (glblMask) ++ return CC_PC_GENERIC_WITH_MASK; ++ else ++ return CC_PC_GENERIC_WITHOUT_MASK; ++ ++ case (e_FM_PCD_EXTRACT_FROM_CURR_END_OF_PARSE): ++ *parseArrayOffset = CC_PC_PR_NEXT_HEADER_OFFSET; ++ if (offset) ++ return CC_PR_OFFSET; ++ else ++ return CC_PR_WITHOUT_OFFSET; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 'extract from' src")); ++ return CC_PC_ILLEGAL; ++ } ++ } ++ else ++ { ++ switch (icCode) ++ { ++ case (CC_PRIVATE_INFO_IC_KEY_EXACT_MATCH): ++ *parseArrayOffset = 0x50; ++ return CC_PC_GENERIC_IC_GMASK; ++ ++ case (CC_PRIVATE_INFO_IC_HASH_EXACT_MATCH): ++ *parseArrayOffset = 0x48; ++ return CC_PC_GENERIC_IC_GMASK; ++ ++ case (CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP): ++ *parseArrayOffset = 0x48; ++ return CC_PC_GENERIC_IC_HASH_INDEXED; ++ ++ case (CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP): ++ *parseArrayOffset = 0x16; ++ return CC_PC_GENERIC_IC_HASH_INDEXED; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 'extract from' src")); ++ break; ++ } ++ } ++ ++ return CC_PC_ILLEGAL; ++} ++ ++static uint8_t GetFullFieldParseCode(e_NetHeaderType hdr, e_FmPcdHdrIndex index, ++ t_FmPcdFields field) ++{ ++ switch (hdr) ++ { ++ case (HEADER_TYPE_NONE): ++ ASSERT_COND(FALSE); ++ return CC_PC_ILLEGAL; ++ ++ case (HEADER_TYPE_ETH): ++ switch (field.eth) ++ { ++ case (NET_HEADER_FIELD_ETH_DA): ++ return CC_PC_FF_MACDST; ++ case (NET_HEADER_FIELD_ETH_SA): ++ return CC_PC_FF_MACSRC; ++ case (NET_HEADER_FIELD_ETH_TYPE): ++ return CC_PC_FF_ETYPE; ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return CC_PC_ILLEGAL; ++ } ++ ++ case (HEADER_TYPE_VLAN): ++ switch (field.vlan) ++ { ++ case (NET_HEADER_FIELD_VLAN_TCI): ++ if ((index == e_FM_PCD_HDR_INDEX_NONE) ++ || (index == e_FM_PCD_HDR_INDEX_1)) ++ return CC_PC_FF_TCI1; ++ if (index == e_FM_PCD_HDR_INDEX_LAST) ++ return CC_PC_FF_TCI2; ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return CC_PC_ILLEGAL; ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return CC_PC_ILLEGAL; ++ } ++ ++ case (HEADER_TYPE_MPLS): ++ switch (field.mpls) ++ { ++ case (NET_HEADER_FIELD_MPLS_LABEL_STACK): ++ if ((index == e_FM_PCD_HDR_INDEX_NONE) ++ || (index == e_FM_PCD_HDR_INDEX_1)) ++ return CC_PC_FF_MPLS1; ++ if (index == e_FM_PCD_HDR_INDEX_LAST) ++ return CC_PC_FF_MPLS_LAST; ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS index")); ++ return CC_PC_ILLEGAL; ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return CC_PC_ILLEGAL; ++ } ++ ++ case (HEADER_TYPE_IPv4): ++ switch (field.ipv4) ++ { ++ case (NET_HEADER_FIELD_IPv4_DST_IP): ++ if ((index == e_FM_PCD_HDR_INDEX_NONE) ++ || (index == e_FM_PCD_HDR_INDEX_1)) ++ return CC_PC_FF_IPV4DST1; ++ if (index == e_FM_PCD_HDR_INDEX_2) ++ return CC_PC_FF_IPV4DST2; ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); ++ return CC_PC_ILLEGAL; ++ case (NET_HEADER_FIELD_IPv4_TOS): ++ if ((index == e_FM_PCD_HDR_INDEX_NONE) ++ || (index == e_FM_PCD_HDR_INDEX_1)) ++ return CC_PC_FF_IPV4IPTOS_TC1; ++ if (index == e_FM_PCD_HDR_INDEX_2) ++ return CC_PC_FF_IPV4IPTOS_TC2; ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); ++ return CC_PC_ILLEGAL; ++ case (NET_HEADER_FIELD_IPv4_PROTO): ++ if ((index == e_FM_PCD_HDR_INDEX_NONE) ++ || (index == e_FM_PCD_HDR_INDEX_1)) ++ return CC_PC_FF_IPV4PTYPE1; ++ if (index == e_FM_PCD_HDR_INDEX_2) ++ return CC_PC_FF_IPV4PTYPE2; ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); ++ return CC_PC_ILLEGAL; ++ case (NET_HEADER_FIELD_IPv4_SRC_IP): ++ if ((index == e_FM_PCD_HDR_INDEX_NONE) ++ || (index == e_FM_PCD_HDR_INDEX_1)) ++ return CC_PC_FF_IPV4SRC1; ++ if (index == e_FM_PCD_HDR_INDEX_2) ++ return CC_PC_FF_IPV4SRC2; ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); ++ return CC_PC_ILLEGAL; ++ case (NET_HEADER_FIELD_IPv4_SRC_IP ++ | NET_HEADER_FIELD_IPv4_DST_IP): ++ if ((index == e_FM_PCD_HDR_INDEX_NONE) ++ || (index == e_FM_PCD_HDR_INDEX_1)) ++ return CC_PC_FF_IPV4SRC1_IPV4DST1; ++ if (index == e_FM_PCD_HDR_INDEX_2) ++ return CC_PC_FF_IPV4SRC2_IPV4DST2; ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); ++ return CC_PC_ILLEGAL; ++ case (NET_HEADER_FIELD_IPv4_TTL): ++ return CC_PC_FF_IPV4TTL; ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return CC_PC_ILLEGAL; ++ } ++ ++ case (HEADER_TYPE_IPv6): ++ switch (field.ipv6) ++ { ++ case (NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL ++ | NET_HEADER_FIELD_IPv6_TC): ++ if ((index == e_FM_PCD_HDR_INDEX_NONE) ++ || (index == e_FM_PCD_HDR_INDEX_1)) ++ return CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1; ++ if (index == e_FM_PCD_HDR_INDEX_2) ++ return CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2; ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); ++ return CC_PC_ILLEGAL; ++ ++ case (NET_HEADER_FIELD_IPv6_NEXT_HDR): ++ if ((index == e_FM_PCD_HDR_INDEX_NONE) ++ || (index == e_FM_PCD_HDR_INDEX_1)) ++ return CC_PC_FF_IPV6PTYPE1; ++ if (index == e_FM_PCD_HDR_INDEX_2) ++ return CC_PC_FF_IPV6PTYPE2; ++ if (index == e_FM_PCD_HDR_INDEX_LAST) ++ return CC_PC_FF_IPPID; ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); ++ return CC_PC_ILLEGAL; ++ ++ case (NET_HEADER_FIELD_IPv6_DST_IP): ++ if ((index == e_FM_PCD_HDR_INDEX_NONE) ++ || (index == e_FM_PCD_HDR_INDEX_1)) ++ return CC_PC_FF_IPV6DST1; ++ if (index == e_FM_PCD_HDR_INDEX_2) ++ return CC_PC_FF_IPV6DST2; ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); ++ return CC_PC_ILLEGAL; ++ ++ case (NET_HEADER_FIELD_IPv6_SRC_IP): ++ if ((index == e_FM_PCD_HDR_INDEX_NONE) ++ || (index == e_FM_PCD_HDR_INDEX_1)) ++ return CC_PC_FF_IPV6SRC1; ++ if (index == e_FM_PCD_HDR_INDEX_2) ++ return CC_PC_FF_IPV6SRC2; ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); ++ return CC_PC_ILLEGAL; ++ ++ case (NET_HEADER_FIELD_IPv6_HOP_LIMIT): ++ return CC_PC_FF_IPV6HOP_LIMIT; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return CC_PC_ILLEGAL; ++ } ++ ++ case (HEADER_TYPE_IP): ++ switch (field.ip) ++ { ++ case (NET_HEADER_FIELD_IP_DSCP): ++ if ((index == e_FM_PCD_HDR_INDEX_NONE) ++ || (index == e_FM_PCD_HDR_INDEX_1)) ++ return CC_PC_FF_IPDSCP; ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP index")); ++ return CC_PC_ILLEGAL; ++ ++ case (NET_HEADER_FIELD_IP_PROTO): ++ if (index == e_FM_PCD_HDR_INDEX_LAST) ++ return CC_PC_FF_IPPID; ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP index")); ++ return CC_PC_ILLEGAL; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return CC_PC_ILLEGAL; ++ } ++ ++ case (HEADER_TYPE_GRE): ++ switch (field.gre) ++ { ++ case (NET_HEADER_FIELD_GRE_TYPE): ++ return CC_PC_FF_GREPTYPE; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return CC_PC_ILLEGAL; ++ } ++ ++ case (HEADER_TYPE_MINENCAP): ++ switch (field.minencap) ++ { ++ case (NET_HEADER_FIELD_MINENCAP_TYPE): ++ return CC_PC_FF_MINENCAP_PTYPE; ++ ++ case (NET_HEADER_FIELD_MINENCAP_DST_IP): ++ return CC_PC_FF_MINENCAP_IPDST; ++ ++ case (NET_HEADER_FIELD_MINENCAP_SRC_IP): ++ return CC_PC_FF_MINENCAP_IPSRC; ++ ++ case (NET_HEADER_FIELD_MINENCAP_SRC_IP ++ | NET_HEADER_FIELD_MINENCAP_DST_IP): ++ return CC_PC_FF_MINENCAP_IPSRC_IPDST; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return CC_PC_ILLEGAL; ++ } ++ ++ case (HEADER_TYPE_TCP): ++ switch (field.tcp) ++ { ++ case (NET_HEADER_FIELD_TCP_PORT_SRC): ++ return CC_PC_FF_L4PSRC; ++ ++ case (NET_HEADER_FIELD_TCP_PORT_DST): ++ return CC_PC_FF_L4PDST; ++ ++ case (NET_HEADER_FIELD_TCP_PORT_DST ++ | NET_HEADER_FIELD_TCP_PORT_SRC): ++ return CC_PC_FF_L4PSRC_L4PDST; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return CC_PC_ILLEGAL; ++ } ++ ++ case (HEADER_TYPE_PPPoE): ++ switch (field.pppoe) ++ { ++ case (NET_HEADER_FIELD_PPPoE_PID): ++ return CC_PC_FF_PPPPID; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return CC_PC_ILLEGAL; ++ } ++ ++ case (HEADER_TYPE_UDP): ++ switch (field.udp) ++ { ++ case (NET_HEADER_FIELD_UDP_PORT_SRC): ++ return CC_PC_FF_L4PSRC; ++ ++ case (NET_HEADER_FIELD_UDP_PORT_DST): ++ return CC_PC_FF_L4PDST; ++ ++ case (NET_HEADER_FIELD_UDP_PORT_DST ++ | NET_HEADER_FIELD_UDP_PORT_SRC): ++ return CC_PC_FF_L4PSRC_L4PDST; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return CC_PC_ILLEGAL; ++ } ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return CC_PC_ILLEGAL; ++ } ++} ++ ++static uint8_t GetPrParseCode(e_NetHeaderType hdr, e_FmPcdHdrIndex hdrIndex, ++ uint32_t offset, bool glblMask, ++ uint8_t *parseArrayOffset) ++{ ++ bool offsetRelevant = FALSE; ++ ++ if (offset) ++ offsetRelevant = TRUE; ++ ++ switch (hdr) ++ { ++ case (HEADER_TYPE_NONE): ++ ASSERT_COND(FALSE); ++ return CC_PC_ILLEGAL; ++ ++ case (HEADER_TYPE_ETH): ++ *parseArrayOffset = (uint8_t)CC_PC_PR_ETH_OFFSET; ++ break; ++ ++ case (HEADER_TYPE_USER_DEFINED_SHIM1): ++ if (offset || glblMask) ++ *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM1_OFFSET; ++ else ++ return CC_PC_PR_SHIM1; ++ break; ++ ++ case (HEADER_TYPE_USER_DEFINED_SHIM2): ++ if (offset || glblMask) ++ *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM2_OFFSET; ++ else ++ return CC_PC_PR_SHIM2; ++ break; ++ ++ case (HEADER_TYPE_LLC_SNAP): ++ *parseArrayOffset = CC_PC_PR_USER_LLC_SNAP_OFFSET; ++ break; ++ ++ case (HEADER_TYPE_PPPoE): ++ *parseArrayOffset = CC_PC_PR_PPPOE_OFFSET; ++ break; ++ ++ case (HEADER_TYPE_MPLS): ++ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) ++ || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) ++ *parseArrayOffset = CC_PC_PR_MPLS1_OFFSET; ++ else ++ if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST) ++ *parseArrayOffset = CC_PC_PR_MPLS_LAST_OFFSET; ++ else ++ { ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS header index")); ++ return CC_PC_ILLEGAL; ++ } ++ break; ++ ++ case (HEADER_TYPE_IPv4): ++ case (HEADER_TYPE_IPv6): ++ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) ++ || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) ++ *parseArrayOffset = CC_PC_PR_IP1_OFFSET; ++ else ++ if (hdrIndex == e_FM_PCD_HDR_INDEX_2) ++ *parseArrayOffset = CC_PC_PR_IP_LAST_OFFSET; ++ else ++ { ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP header index")); ++ return CC_PC_ILLEGAL; ++ } ++ break; ++ ++ case (HEADER_TYPE_MINENCAP): ++ *parseArrayOffset = CC_PC_PR_MINENC_OFFSET; ++ break; ++ ++ case (HEADER_TYPE_GRE): ++ *parseArrayOffset = CC_PC_PR_GRE_OFFSET; ++ break; ++ ++ case (HEADER_TYPE_TCP): ++ case (HEADER_TYPE_UDP): ++ case (HEADER_TYPE_IPSEC_AH): ++ case (HEADER_TYPE_IPSEC_ESP): ++ case (HEADER_TYPE_DCCP): ++ case (HEADER_TYPE_SCTP): ++ *parseArrayOffset = CC_PC_PR_L4_OFFSET; ++ break; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP header for this type of operation")); ++ return CC_PC_ILLEGAL; ++ } ++ ++ if (offsetRelevant) ++ return CC_PR_OFFSET; ++ else ++ return CC_PR_WITHOUT_OFFSET; ++} ++ ++static uint8_t GetFieldParseCode(e_NetHeaderType hdr, t_FmPcdFields field, ++ uint32_t offset, uint8_t *parseArrayOffset, ++ e_FmPcdHdrIndex hdrIndex) ++{ ++ bool offsetRelevant = FALSE; ++ ++ if (offset) ++ offsetRelevant = TRUE; ++ ++ switch (hdr) ++ { ++ case (HEADER_TYPE_NONE): ++ ASSERT_COND(FALSE); ++ break; ++ case (HEADER_TYPE_ETH): ++ switch (field.eth) ++ { ++ case (NET_HEADER_FIELD_ETH_TYPE): ++ *parseArrayOffset = CC_PC_PR_ETYPE_LAST_OFFSET; ++ break; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return CC_PC_ILLEGAL; ++ } ++ break; ++ ++ case (HEADER_TYPE_VLAN): ++ switch (field.vlan) ++ { ++ case (NET_HEADER_FIELD_VLAN_TCI): ++ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) ++ || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) ++ *parseArrayOffset = CC_PC_PR_VLAN1_OFFSET; ++ else ++ if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST) ++ *parseArrayOffset = CC_PC_PR_VLAN2_OFFSET; ++ break; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return CC_PC_ILLEGAL; ++ } ++ break; ++ ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal header ")); ++ return CC_PC_ILLEGAL; ++ } ++ ++ if (offsetRelevant) ++ return CC_PR_OFFSET; ++ else ++ return CC_PR_WITHOUT_OFFSET; ++} ++ ++static void FillAdOfTypeResult(t_Handle h_Ad, ++ t_FmPcdCcStatsParams *p_FmPcdCcStatsParams, ++ t_FmPcd *p_FmPcd, ++ t_FmPcdCcNextEngineParams *p_CcNextEngineParams) ++{ ++ t_AdOfTypeResult *p_AdResult = (t_AdOfTypeResult *)h_Ad; ++ t_Handle h_TmpAd; ++ uint32_t tmp = 0, tmpNia = 0; ++ uint16_t profileId; ++ t_Handle p_AdNewPtr = NULL; ++ t_Error err = E_OK; ++ ++ /* There are 3 cases handled in this routine of building a "result" type AD. ++ * Case 1: No Manip. The action descriptor is built within the match table. ++ * Case 2: Manip exists. A new AD is created - p_AdNewPtr. It is initialized ++ * either in the FmPcdManipUpdateAdResultForCc routine or it was already ++ * initialized and returned here. ++ * p_AdResult (within the match table) will be initialized after ++ * this routine returns and point to the existing AD. ++ * Case 3: Manip exists. The action descriptor is built within the match table. ++ * FmPcdManipUpdateAdResultForCc returns a NULL p_AdNewPtr. ++ * ++ * If statistics were enabled and the statistics mode of this node requires ++ * a statistics Ad, it will be placed after the result Ad and before the ++ * manip Ad, if manip Ad exists here. ++ */ ++ ++ /* As default, the "new" ptr is the current one. i.e. the content of the result ++ * AD will be written into the match table itself (case (1))*/ ++ p_AdNewPtr = p_AdResult; ++ ++ /* Initialize an action descriptor, if current statistics mode requires an Ad */ ++ if (p_FmPcdCcStatsParams) ++ { ++ ASSERT_COND(p_FmPcdCcStatsParams->h_StatsAd); ++ ASSERT_COND(p_FmPcdCcStatsParams->h_StatsCounters); ++ ++ /* Swapping addresses between statistics Ad and the current lookup AD addresses */ ++ h_TmpAd = p_FmPcdCcStatsParams->h_StatsAd; ++ p_FmPcdCcStatsParams->h_StatsAd = h_Ad; ++ h_Ad = h_TmpAd; ++ ++ p_AdNewPtr = h_Ad; ++ p_AdResult = h_Ad; ++ ++ /* Init statistics Ad and connect current lookup AD as 'next action' from statistics Ad */ ++ UpdateStatsAd(p_FmPcdCcStatsParams, h_Ad, p_FmPcd->physicalMuramBase); ++ } ++ ++ /* Create manip and return p_AdNewPtr to either a new descriptor or NULL */ ++ if (p_CcNextEngineParams->h_Manip) ++ FmPcdManipUpdateAdResultForCc(p_CcNextEngineParams->h_Manip, ++ p_CcNextEngineParams, h_Ad, &p_AdNewPtr); ++ ++ /* if (p_AdNewPtr = NULL) --> Done. (case (3)) */ ++ if (p_AdNewPtr) ++ { ++ /* case (1) and (2) */ ++ switch (p_CcNextEngineParams->nextEngine) ++ { ++ case (e_FM_PCD_DONE): ++ if (p_CcNextEngineParams->params.enqueueParams.action ++ == e_FM_PCD_ENQ_FRAME) ++ { ++ if (p_CcNextEngineParams->params.enqueueParams.overrideFqid) ++ { ++ tmp = FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE; ++ tmp |= ++ p_CcNextEngineParams->params.enqueueParams.newFqid; ++#if (DPAA_VERSION >= 11) ++ tmp |= ++ (p_CcNextEngineParams->params.enqueueParams.newRelativeStorageProfileId ++ & FM_PCD_AD_RESULT_VSP_MASK) ++ << FM_PCD_AD_RESULT_VSP_SHIFT; ++#endif /* (DPAA_VERSION >= 11) */ ++ } ++ else ++ { ++ tmp = FM_PCD_AD_RESULT_DATA_FLOW_TYPE; ++ tmp |= FM_PCD_AD_RESULT_PLCR_DIS; ++ } ++ } ++ ++ if (p_CcNextEngineParams->params.enqueueParams.action ++ == e_FM_PCD_DROP_FRAME) ++ tmpNia |= GET_NIA_BMI_AC_DISCARD_FRAME(p_FmPcd); ++ else ++ tmpNia |= GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd); ++ break; ++ ++ case (e_FM_PCD_KG): ++ if (p_CcNextEngineParams->params.kgParams.overrideFqid) ++ { ++ tmp = FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE; ++ tmp |= p_CcNextEngineParams->params.kgParams.newFqid; ++#if (DPAA_VERSION >= 11) ++ tmp |= ++ (p_CcNextEngineParams->params.kgParams.newRelativeStorageProfileId ++ & FM_PCD_AD_RESULT_VSP_MASK) ++ << FM_PCD_AD_RESULT_VSP_SHIFT; ++#endif /* (DPAA_VERSION >= 11) */ ++ } ++ else ++ { ++ tmp = FM_PCD_AD_RESULT_DATA_FLOW_TYPE; ++ tmp |= FM_PCD_AD_RESULT_PLCR_DIS; ++ } ++ tmpNia = NIA_KG_DIRECT; ++ tmpNia |= NIA_ENG_KG; ++ tmpNia |= NIA_KG_CC_EN; ++ tmpNia |= FmPcdKgGetSchemeId( ++ p_CcNextEngineParams->params.kgParams.h_DirectScheme); ++ break; ++ ++ case (e_FM_PCD_PLCR): ++ if (p_CcNextEngineParams->params.plcrParams.overrideParams) ++ { ++ tmp = FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE; ++ ++ /* if private policer profile, it may be uninitialized yet, therefore no checks are done at this stage */ ++ if (p_CcNextEngineParams->params.plcrParams.sharedProfile) ++ { ++ tmpNia |= NIA_PLCR_ABSOLUTE; ++ err = FmPcdPlcrGetAbsoluteIdByProfileParams( ++ (t_Handle)p_FmPcd, ++ e_FM_PCD_PLCR_SHARED, ++ NULL, ++ p_CcNextEngineParams->params.plcrParams.newRelativeProfileId, ++ &profileId); ++ ++ if (err != E_OK) { ++ REPORT_ERROR(MAJOR, err, NO_MSG); ++ return; ++ } ++ ++ } ++ else ++ profileId = ++ p_CcNextEngineParams->params.plcrParams.newRelativeProfileId; ++ ++ tmp |= p_CcNextEngineParams->params.plcrParams.newFqid; ++#if (DPAA_VERSION >= 11) ++ tmp |= ++ (p_CcNextEngineParams->params.plcrParams.newRelativeStorageProfileId ++ & FM_PCD_AD_RESULT_VSP_MASK) ++ << FM_PCD_AD_RESULT_VSP_SHIFT; ++#endif /* (DPAA_VERSION >= 11) */ ++ WRITE_UINT32( ++ p_AdResult->plcrProfile, ++ (uint32_t)((uint32_t)profileId << FM_PCD_AD_PROFILEID_FOR_CNTRL_SHIFT)); ++ } ++ else ++ tmp = FM_PCD_AD_RESULT_DATA_FLOW_TYPE; ++ ++ tmpNia |= ++ NIA_ENG_PLCR ++ | p_CcNextEngineParams->params.plcrParams.newRelativeProfileId; ++ break; ++ ++ default: ++ return; ++ }WRITE_UINT32(p_AdResult->fqid, tmp); ++ ++ if (p_CcNextEngineParams->h_Manip) ++ { ++ tmp = GET_UINT32(p_AdResult->plcrProfile); ++ tmp |= (uint32_t)(XX_VirtToPhys(p_AdNewPtr) ++ - (p_FmPcd->physicalMuramBase)) >> 4; ++ WRITE_UINT32(p_AdResult->plcrProfile, tmp); ++ ++ tmpNia |= FM_PCD_AD_RESULT_EXTENDED_MODE; ++ tmpNia |= FM_PCD_AD_RESULT_NADEN; ++ } ++ ++#if (DPAA_VERSION >= 11) ++ tmpNia |= FM_PCD_AD_RESULT_NO_OM_VSPE; ++#endif /* (DPAA_VERSION >= 11) */ ++ WRITE_UINT32(p_AdResult->nia, tmpNia); ++ } ++} ++ ++static t_Error CcUpdateParams(t_Handle h_FmPcd, t_Handle h_PcdParams, ++ t_Handle h_FmPort, t_Handle h_FmTree, ++ bool validate) ++{ ++ t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *)h_FmTree; ++ ++ return CcUpdateParam(h_FmPcd, h_PcdParams, h_FmPort, ++ p_CcTree->keyAndNextEngineParams, ++ p_CcTree->numOfEntries, ++ UINT_TO_PTR(p_CcTree->ccTreeBaseAddr), validate, 0, ++ h_FmTree, FALSE); ++} ++ ++ ++static void ReleaseNewNodeCommonPart( ++ t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo) ++{ ++ if (p_AdditionalInfo->p_AdTableNew) ++ FM_MURAM_FreeMem( ++ FmPcdGetMuramHandle( ++ ((t_FmPcdCcNode *)(p_AdditionalInfo->h_CurrentNode))->h_FmPcd), ++ p_AdditionalInfo->p_AdTableNew); ++ ++ if (p_AdditionalInfo->p_KeysMatchTableNew) ++ FM_MURAM_FreeMem( ++ FmPcdGetMuramHandle( ++ ((t_FmPcdCcNode *)(p_AdditionalInfo->h_CurrentNode))->h_FmPcd), ++ p_AdditionalInfo->p_KeysMatchTableNew); ++} ++ ++static t_Error UpdateGblMask(t_FmPcdCcNode *p_CcNode, uint8_t keySize, ++ uint8_t *p_Mask) ++{ ++ uint8_t prvGlblMaskSize = p_CcNode->glblMaskSize; ++ ++ if (p_Mask && !p_CcNode->glblMaskUpdated && (keySize <= 4) ++ && !p_CcNode->lclMask) ++ { ++ if (p_CcNode->parseCode && (p_CcNode->parseCode != CC_PC_FF_TCI1) ++ && (p_CcNode->parseCode != CC_PC_FF_TCI2) ++ && (p_CcNode->parseCode != CC_PC_FF_MPLS1) ++ && (p_CcNode->parseCode != CC_PC_FF_MPLS_LAST) ++ && (p_CcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC1) ++ && (p_CcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC2) ++ && (p_CcNode->parseCode != CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1) ++ && (p_CcNode->parseCode != CC_PC_FF_IPDSCP) ++ && (p_CcNode->parseCode != CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2)) ++ { ++ p_CcNode->glblMaskSize = 0; ++ p_CcNode->lclMask = TRUE; ++ } ++ else ++ { ++ memcpy(p_CcNode->p_GlblMask, p_Mask, (sizeof(uint8_t)) * keySize); ++ p_CcNode->glblMaskUpdated = TRUE; ++ p_CcNode->glblMaskSize = 4; ++ } ++ } ++ else ++ if (p_Mask && (keySize <= 4) && !p_CcNode->lclMask) ++ { ++ if (memcmp(p_CcNode->p_GlblMask, p_Mask, keySize) != 0) ++ { ++ p_CcNode->lclMask = TRUE; ++ p_CcNode->glblMaskSize = 0; ++ } ++ } ++ else ++ if (!p_Mask && p_CcNode->glblMaskUpdated && (keySize <= 4)) ++ { ++ uint32_t tmpMask = 0xffffffff; ++ if (memcmp(p_CcNode->p_GlblMask, &tmpMask, 4) != 0) ++ { ++ p_CcNode->lclMask = TRUE; ++ p_CcNode->glblMaskSize = 0; ++ } ++ } ++ else ++ if (p_Mask) ++ { ++ p_CcNode->lclMask = TRUE; ++ p_CcNode->glblMaskSize = 0; ++ } ++ ++ /* In static mode (maxNumOfKeys > 0), local mask is supported ++ only is mask support was enabled at initialization */ ++ if (p_CcNode->maxNumOfKeys && (!p_CcNode->maskSupport) && p_CcNode->lclMask) ++ { ++ p_CcNode->lclMask = FALSE; ++ p_CcNode->glblMaskSize = prvGlblMaskSize; ++ return ERROR_CODE(E_NOT_SUPPORTED); ++ } ++ ++ return E_OK; ++} ++ ++static __inline__ t_Handle GetNewAd(t_Handle h_FmPcdCcNodeOrTree, bool isTree) ++{ ++ t_FmPcd *p_FmPcd; ++ t_Handle h_Ad; ++ ++ if (isTree) ++ p_FmPcd = (t_FmPcd *)(((t_FmPcdCcTree *)h_FmPcdCcNodeOrTree)->h_FmPcd); ++ else ++ p_FmPcd = (t_FmPcd *)(((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->h_FmPcd); ++ ++ if ((isTree && p_FmPcd->p_CcShadow) ++ || (!isTree && ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->maxNumOfKeys)) ++ { ++ /* The allocated shadow is divided as follows: ++ 0 . . . 16 . . . ++ --------------------------------------------------- ++ | Shadow | Shadow Keys | Shadow Next | ++ | Ad | Match Table | Engine Table | ++ | (16 bytes) | (maximal size) | (maximal size) | ++ --------------------------------------------------- ++ */ ++ if (!p_FmPcd->p_CcShadow) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("CC Shadow not allocated")); ++ return NULL; ++ } ++ ++ h_Ad = p_FmPcd->p_CcShadow; ++ } ++ else ++ { ++ h_Ad = (t_Handle)FM_MURAM_AllocMem(FmPcdGetMuramHandle(p_FmPcd), ++ FM_PCD_CC_AD_ENTRY_SIZE, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!h_Ad) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CC node action descriptor")); ++ return NULL; ++ } ++ } ++ ++ return h_Ad; ++} ++ ++static t_Error BuildNewNodeCommonPart( ++ t_FmPcdCcNode *p_CcNode, int *size, ++ t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ ++ if (p_CcNode->lclMask) ++ *size = 2 * p_CcNode->ccKeySizeAccExtraction; ++ else ++ *size = p_CcNode->ccKeySizeAccExtraction; ++ ++ if (p_CcNode->maxNumOfKeys == 0) ++ { ++ p_AdditionalInfo->p_AdTableNew = (t_Handle)FM_MURAM_AllocMem( ++ FmPcdGetMuramHandle(p_FmPcd), ++ (uint32_t)((p_AdditionalInfo->numOfKeys + 1) ++ * FM_PCD_CC_AD_ENTRY_SIZE), ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!p_AdditionalInfo->p_AdTableNew) ++ RETURN_ERROR( ++ MAJOR, E_NO_MEMORY, ++ ("MURAM allocation for CC node action descriptors table")); ++ ++ p_AdditionalInfo->p_KeysMatchTableNew = (t_Handle)FM_MURAM_AllocMem( ++ FmPcdGetMuramHandle(p_FmPcd), ++ (uint32_t)(*size * sizeof(uint8_t) ++ * (p_AdditionalInfo->numOfKeys + 1)), ++ FM_PCD_CC_KEYS_MATCH_TABLE_ALIGN); ++ if (!p_AdditionalInfo->p_KeysMatchTableNew) ++ { ++ FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd), ++ p_AdditionalInfo->p_AdTableNew); ++ p_AdditionalInfo->p_AdTableNew = NULL; ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("MURAM allocation for CC node key match table")); ++ } ++ ++ MemSet8( ++ (uint8_t*)p_AdditionalInfo->p_AdTableNew, ++ 0, ++ (uint32_t)((p_AdditionalInfo->numOfKeys + 1) ++ * FM_PCD_CC_AD_ENTRY_SIZE)); ++ MemSet8((uint8_t*)p_AdditionalInfo->p_KeysMatchTableNew, 0, ++ *size * sizeof(uint8_t) * (p_AdditionalInfo->numOfKeys + 1)); ++ } ++ else ++ { ++ /* The allocated shadow is divided as follows: ++ 0 . . . 16 . . . ++ --------------------------------------------------- ++ | Shadow | Shadow Keys | Shadow Next | ++ | Ad | Match Table | Engine Table | ++ | (16 bytes) | (maximal size) | (maximal size) | ++ --------------------------------------------------- ++ */ ++ ++ if (!p_FmPcd->p_CcShadow) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("CC Shadow not allocated")); ++ ++ p_AdditionalInfo->p_KeysMatchTableNew = ++ PTR_MOVE(p_FmPcd->p_CcShadow, FM_PCD_CC_AD_ENTRY_SIZE); ++ p_AdditionalInfo->p_AdTableNew = ++ PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, p_CcNode->keysMatchTableMaxSize); ++ ++ MemSet8( ++ (uint8_t*)p_AdditionalInfo->p_AdTableNew, ++ 0, ++ (uint32_t)((p_CcNode->maxNumOfKeys + 1) ++ * FM_PCD_CC_AD_ENTRY_SIZE)); ++ MemSet8((uint8_t*)p_AdditionalInfo->p_KeysMatchTableNew, 0, ++ (*size) * sizeof(uint8_t) * (p_CcNode->maxNumOfKeys)); ++ } ++ ++ p_AdditionalInfo->p_AdTableOld = p_CcNode->h_AdTable; ++ p_AdditionalInfo->p_KeysMatchTableOld = p_CcNode->h_KeysMatchTable; ++ ++ return E_OK; ++} ++ ++static t_Error BuildNewNodeAddOrMdfyKeyAndNextEngine( ++ t_Handle h_FmPcd, t_FmPcdCcNode *p_CcNode, uint16_t keyIndex, ++ t_FmPcdCcKeyParams *p_KeyParams, ++ t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo, bool add) ++{ ++ t_Error err = E_OK; ++ t_Handle p_AdTableNewTmp, p_KeysMatchTableNewTmp; ++ t_Handle p_KeysMatchTableOldTmp, p_AdTableOldTmp; ++ int size; ++ int i = 0, j = 0; ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint32_t requiredAction = 0; ++ bool prvLclMask; ++ t_CcNodeInformation *p_CcNodeInformation; ++ t_FmPcdCcStatsParams statsParams = { 0 }; ++ t_List *p_Pos; ++ t_FmPcdStatsObj *p_StatsObj; ++ ++ /* Check that new NIA is legal */ ++ err = ValidateNextEngineParams(h_FmPcd, &p_KeyParams->ccNextEngineParams, ++ p_CcNode->statisticsMode); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ prvLclMask = p_CcNode->lclMask; ++ ++ /* Check that new key is not require update of localMask */ ++ err = UpdateGblMask(p_CcNode, p_CcNode->ccKeySizeAccExtraction, ++ p_KeyParams->p_Mask); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ ++ /* Update internal data structure with new next engine for the given index */ ++ memcpy(&p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams, ++ &p_KeyParams->ccNextEngineParams, sizeof(t_FmPcdCcNextEngineParams)); ++ ++ memcpy(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].key, ++ p_KeyParams->p_Key, p_CcNode->userSizeOfExtraction); ++ ++ if ((p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ && p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip) ++ { ++ err = ++ AllocAndFillAdForContLookupManip( ++ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ } ++ ++ if (p_KeyParams->p_Mask) ++ memcpy(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].mask, ++ p_KeyParams->p_Mask, p_CcNode->userSizeOfExtraction); ++ else ++ memset(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].mask, 0xFF, ++ p_CcNode->userSizeOfExtraction); ++ ++ /* Update numOfKeys */ ++ if (add) ++ p_AdditionalInfo->numOfKeys = (uint8_t)(p_CcNode->numOfKeys + 1); ++ else ++ p_AdditionalInfo->numOfKeys = (uint8_t)p_CcNode->numOfKeys; ++ ++ /* Allocate new tables in MURAM: keys match table and action descriptors table */ ++ err = BuildNewNodeCommonPart(p_CcNode, &size, p_AdditionalInfo); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ /* Check that manip is legal and what requiredAction is necessary for this manip */ ++ if (p_KeyParams->ccNextEngineParams.h_Manip) ++ { ++ err = FmPcdManipCheckParamsForCcNextEngine( ++ &p_KeyParams->ccNextEngineParams, &requiredAction); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ } ++ ++ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction = ++ requiredAction; ++ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction |= ++ UPDATE_CC_WITH_TREE; ++ ++ /* Update new Ad and new Key Table according to new requirement */ ++ i = 0; ++ for (j = 0; j < p_AdditionalInfo->numOfKeys; j++) ++ { ++ p_AdTableNewTmp = ++ PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j*FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ if (j == keyIndex) ++ { ++ if (p_KeyParams->ccNextEngineParams.statisticsEn) ++ { ++ /* Allocate a statistics object that holds statistics AD and counters. ++ - For added key - New statistics AD and counters pointer need to be allocated ++ new statistics object. If statistics were enabled, we need to replace the ++ existing descriptor with a new descriptor with nullified counters. ++ */ ++ p_StatsObj = GetStatsObj(p_CcNode); ++ ASSERT_COND(p_StatsObj); ++ ++ /* Store allocated statistics object */ ++ ASSERT_COND(keyIndex < CC_MAX_NUM_OF_KEYS); ++ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].p_StatsObj = ++ p_StatsObj; ++ ++ statsParams.h_StatsAd = p_StatsObj->h_StatsAd; ++ statsParams.h_StatsCounters = p_StatsObj->h_StatsCounters; ++#if (DPAA_VERSION >= 11) ++ statsParams.h_StatsFLRs = p_CcNode->h_StatsFLRs; ++ ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ /* Building action descriptor for the received new key */ ++ NextStepAd(p_AdTableNewTmp, &statsParams, ++ &p_KeyParams->ccNextEngineParams, p_FmPcd); ++ } ++ else ++ { ++ /* Building action descriptor for the received new key */ ++ NextStepAd(p_AdTableNewTmp, NULL, ++ &p_KeyParams->ccNextEngineParams, p_FmPcd); ++ } ++ ++ /* Copy the received new key into keys match table */ ++ p_KeysMatchTableNewTmp = ++ PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j*size*sizeof(uint8_t)); ++ ++ MemCpy8((void*)p_KeysMatchTableNewTmp, p_KeyParams->p_Key, ++ p_CcNode->userSizeOfExtraction); ++ ++ /* Update mask for the received new key */ ++ if (p_CcNode->lclMask) ++ { ++ if (p_KeyParams->p_Mask) ++ { ++ MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp, ++ p_CcNode->ccKeySizeAccExtraction), ++ p_KeyParams->p_Mask, ++ p_CcNode->userSizeOfExtraction); ++ } ++ else ++ if (p_CcNode->ccKeySizeAccExtraction > 4) ++ { ++ MemSet8(PTR_MOVE(p_KeysMatchTableNewTmp, ++ p_CcNode->ccKeySizeAccExtraction), ++ 0xff, p_CcNode->userSizeOfExtraction); ++ } ++ else ++ { ++ MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp, ++ p_CcNode->ccKeySizeAccExtraction), ++ p_CcNode->p_GlblMask, ++ p_CcNode->userSizeOfExtraction); ++ } ++ } ++ ++ /* If key modification requested, the old entry is omitted and replaced by the new parameters */ ++ if (!add) ++ i++; ++ } ++ else ++ { ++ /* Copy existing action descriptors to the newly allocated Ad table */ ++ p_AdTableOldTmp = ++ PTR_MOVE(p_AdditionalInfo->p_AdTableOld, i*FM_PCD_CC_AD_ENTRY_SIZE); ++ MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, ++ FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ /* Copy existing keys and their masks to the newly allocated keys match table */ ++ p_KeysMatchTableNewTmp = ++ PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j * size * sizeof(uint8_t)); ++ p_KeysMatchTableOldTmp = ++ PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableOld, i * size * sizeof(uint8_t)); ++ ++ if (p_CcNode->lclMask) ++ { ++ if (prvLclMask) ++ { ++ MemCpy8( ++ PTR_MOVE(p_KeysMatchTableNewTmp, p_CcNode->ccKeySizeAccExtraction), ++ PTR_MOVE(p_KeysMatchTableOldTmp, p_CcNode->ccKeySizeAccExtraction), ++ p_CcNode->ccKeySizeAccExtraction); ++ } ++ else ++ { ++ p_KeysMatchTableOldTmp = ++ PTR_MOVE(p_CcNode->h_KeysMatchTable, ++ i * (int)p_CcNode->ccKeySizeAccExtraction * sizeof(uint8_t)); ++ ++ if (p_CcNode->ccKeySizeAccExtraction > 4) ++ { ++ MemSet8(PTR_MOVE(p_KeysMatchTableNewTmp, ++ p_CcNode->ccKeySizeAccExtraction), ++ 0xff, p_CcNode->userSizeOfExtraction); ++ } ++ else ++ { ++ MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp, ++ p_CcNode->ccKeySizeAccExtraction), ++ p_CcNode->p_GlblMask, ++ p_CcNode->userSizeOfExtraction); ++ } ++ } ++ } ++ ++ MemCpy8(p_KeysMatchTableNewTmp, p_KeysMatchTableOldTmp, ++ p_CcNode->ccKeySizeAccExtraction); ++ ++ i++; ++ } ++ } ++ ++ /* Miss action descriptor */ ++ p_AdTableNewTmp = ++ PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j * FM_PCD_CC_AD_ENTRY_SIZE); ++ p_AdTableOldTmp = ++ PTR_MOVE(p_AdditionalInfo->p_AdTableOld, i * FM_PCD_CC_AD_ENTRY_SIZE); ++ MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ if (!LIST_IsEmpty(&p_CcNode->ccTreesLst)) ++ { ++ LIST_FOR_EACH(p_Pos, &p_CcNode->ccTreesLst) ++ { ++ p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); ++ ASSERT_COND(p_CcNodeInformation->h_CcNode); ++ /* Update the manipulation which has to be updated from parameters of the port */ ++ /* It's has to be updated with restrictions defined in the function */ ++ err = ++ SetRequiredAction( ++ p_CcNode->h_FmPcd, ++ p_CcNode->shadowAction ++ | p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction, ++ &p_AdditionalInfo->keyAndNextEngineParams[keyIndex], ++ PTR_MOVE(p_AdditionalInfo->p_AdTableNew, keyIndex*FM_PCD_CC_AD_ENTRY_SIZE), ++ 1, p_CcNodeInformation->h_CcNode); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ ++ err = ++ CcUpdateParam( ++ p_CcNode->h_FmPcd, ++ NULL, ++ NULL, ++ &p_AdditionalInfo->keyAndNextEngineParams[keyIndex], ++ 1, ++ PTR_MOVE(p_AdditionalInfo->p_AdTableNew, keyIndex*FM_PCD_CC_AD_ENTRY_SIZE), ++ TRUE, p_CcNodeInformation->index, ++ p_CcNodeInformation->h_CcNode, TRUE); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ } ++ } ++ ++ if (p_CcNode->lclMask) ++ memset(p_CcNode->p_GlblMask, 0xff, CC_GLBL_MASK_SIZE * sizeof(uint8_t)); ++ ++ if (p_KeyParams->ccNextEngineParams.nextEngine == e_FM_PCD_CC) ++ p_AdditionalInfo->h_NodeForAdd = ++ p_KeyParams->ccNextEngineParams.params.ccParams.h_CcNode; ++ if (p_KeyParams->ccNextEngineParams.h_Manip) ++ p_AdditionalInfo->h_ManipForAdd = ++ p_KeyParams->ccNextEngineParams.h_Manip; ++ ++#if (DPAA_VERSION >= 11) ++ if ((p_KeyParams->ccNextEngineParams.nextEngine == e_FM_PCD_FR) ++ && (p_KeyParams->ccNextEngineParams.params.frParams.h_FrmReplic)) ++ p_AdditionalInfo->h_FrmReplicForAdd = ++ p_KeyParams->ccNextEngineParams.params.frParams.h_FrmReplic; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ if (!add) ++ { ++ if (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ p_AdditionalInfo->h_NodeForRmv = ++ p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode; ++ ++ if (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip) ++ p_AdditionalInfo->h_ManipForRmv = ++ p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip; ++ ++ /* If statistics were previously enabled, store the old statistics object to be released */ ++ if (p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj) ++ { ++ p_AdditionalInfo->p_StatsObjForRmv = ++ p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj; ++ } ++ ++#if (DPAA_VERSION >= 11) ++ if ((p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine ++ == e_FM_PCD_FR) ++ && (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic)) ++ p_AdditionalInfo->h_FrmReplicForRmv = ++ p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic; ++#endif /* (DPAA_VERSION >= 11) */ ++ } ++ ++ return E_OK; ++} ++ ++static t_Error BuildNewNodeRemoveKey( ++ t_FmPcdCcNode *p_CcNode, uint16_t keyIndex, ++ t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo) ++{ ++ int i = 0, j = 0; ++ t_Handle p_AdTableNewTmp, p_KeysMatchTableNewTmp; ++ t_Handle p_KeysMatchTableOldTmp, p_AdTableOldTmp; ++ int size; ++ t_Error err = E_OK; ++ ++ /*save new numOfKeys*/ ++ p_AdditionalInfo->numOfKeys = (uint16_t)(p_CcNode->numOfKeys - 1); ++ ++ /*function which allocates in the memory new KeyTbl, AdTbl*/ ++ err = BuildNewNodeCommonPart(p_CcNode, &size, p_AdditionalInfo); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ /*update new Ad and new Key Table according to new requirement*/ ++ for (i = 0, j = 0; j < p_CcNode->numOfKeys; i++, j++) ++ { ++ if (j == keyIndex) ++ j++; ++ ++ if (j == p_CcNode->numOfKeys) ++ break; ++ p_AdTableNewTmp = ++ PTR_MOVE(p_AdditionalInfo->p_AdTableNew, i * FM_PCD_CC_AD_ENTRY_SIZE); ++ p_AdTableOldTmp = ++ PTR_MOVE(p_AdditionalInfo->p_AdTableOld, j * FM_PCD_CC_AD_ENTRY_SIZE); ++ MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ p_KeysMatchTableOldTmp = ++ PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableOld, j * size * sizeof(uint8_t)); ++ p_KeysMatchTableNewTmp = ++ PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, i * size * sizeof(uint8_t)); ++ MemCpy8(p_KeysMatchTableNewTmp, p_KeysMatchTableOldTmp, ++ size * sizeof(uint8_t)); ++ } ++ ++ p_AdTableNewTmp = ++ PTR_MOVE(p_AdditionalInfo->p_AdTableNew, i * FM_PCD_CC_AD_ENTRY_SIZE); ++ p_AdTableOldTmp = ++ PTR_MOVE(p_AdditionalInfo->p_AdTableOld, j * FM_PCD_CC_AD_ENTRY_SIZE); ++ MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ if (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ p_AdditionalInfo->h_NodeForRmv = ++ p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode; ++ ++ if (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip) ++ p_AdditionalInfo->h_ManipForRmv = ++ p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip; ++ ++ /* If statistics were previously enabled, store the old statistics object to be released */ ++ if (p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj) ++ { ++ p_AdditionalInfo->p_StatsObjForRmv = ++ p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj; ++ } ++ ++#if (DPAA_VERSION >= 11) ++ if ((p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine ++ == e_FM_PCD_FR) ++ && (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic)) ++ p_AdditionalInfo->h_FrmReplicForRmv = ++ p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ return E_OK; ++} ++ ++static t_Error BuildNewNodeModifyKey( ++ t_FmPcdCcNode *p_CcNode, uint16_t keyIndex, uint8_t *p_Key, ++ uint8_t *p_Mask, t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ t_Error err = E_OK; ++ t_Handle p_AdTableNewTmp, p_KeysMatchTableNewTmp; ++ t_Handle p_KeysMatchTableOldTmp, p_AdTableOldTmp; ++ int size; ++ int i = 0, j = 0; ++ bool prvLclMask; ++ t_FmPcdStatsObj *p_StatsObj, tmpStatsObj; ++ p_AdditionalInfo->numOfKeys = p_CcNode->numOfKeys; ++ ++ prvLclMask = p_CcNode->lclMask; ++ ++ /* Check that new key is not require update of localMask */ ++ err = UpdateGblMask(p_CcNode, p_CcNode->ccKeySizeAccExtraction, p_Mask); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ ++ /* Update internal data structure with new next engine for the given index */ ++ memcpy(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].key, p_Key, ++ p_CcNode->userSizeOfExtraction); ++ ++ if (p_Mask) ++ memcpy(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].mask, p_Mask, ++ p_CcNode->userSizeOfExtraction); ++ else ++ memset(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].mask, 0xFF, ++ p_CcNode->userSizeOfExtraction); ++ ++ /*function which build in the memory new KeyTbl, AdTbl*/ ++ err = BuildNewNodeCommonPart(p_CcNode, &size, p_AdditionalInfo); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ /*fill the New AdTable and New KeyTable*/ ++ for (j = 0, i = 0; j < p_AdditionalInfo->numOfKeys; j++, i++) ++ { ++ p_AdTableNewTmp = ++ PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j*FM_PCD_CC_AD_ENTRY_SIZE); ++ p_AdTableOldTmp = ++ PTR_MOVE(p_AdditionalInfo->p_AdTableOld, i*FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ if (j == keyIndex) ++ { ++ ASSERT_COND(keyIndex < CC_MAX_NUM_OF_KEYS); ++ if (p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj) ++ { ++ /* As statistics were enabled, we need to update the existing ++ statistics descriptor with a new nullified counters. */ ++ p_StatsObj = GetStatsObj(p_CcNode); ++ ASSERT_COND(p_StatsObj); ++ ++ SetStatsCounters( ++ p_AdTableNewTmp, ++ (uint32_t)((XX_VirtToPhys(p_StatsObj->h_StatsCounters) ++ - p_FmPcd->physicalMuramBase))); ++ ++ tmpStatsObj.h_StatsAd = p_StatsObj->h_StatsAd; ++ tmpStatsObj.h_StatsCounters = p_StatsObj->h_StatsCounters; ++ ++ /* As we need to replace only the counters, we build a new statistics ++ object that holds the old AD and the new counters - this will be the ++ currently used statistics object. ++ The newly allocated AD is not required and may be released back to ++ the available objects with the previous counters pointer. */ ++ p_StatsObj->h_StatsAd = ++ p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsAd; ++ ++ p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsAd = ++ tmpStatsObj.h_StatsAd; ++ ++ /* Store allocated statistics object */ ++ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].p_StatsObj = ++ p_StatsObj; ++ ++ /* As statistics were previously enabled, store the old statistics object to be released */ ++ p_AdditionalInfo->p_StatsObjForRmv = ++ p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj; ++ } ++ ++ p_KeysMatchTableNewTmp = ++ PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j * size * sizeof(uint8_t)); ++ ++ MemCpy8(p_KeysMatchTableNewTmp, p_Key, ++ p_CcNode->userSizeOfExtraction); ++ ++ if (p_CcNode->lclMask) ++ { ++ if (p_Mask) ++ MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp, ++ p_CcNode->ccKeySizeAccExtraction), ++ p_Mask, p_CcNode->userSizeOfExtraction); ++ else ++ if (p_CcNode->ccKeySizeAccExtraction > 4) ++ MemSet8(PTR_MOVE(p_KeysMatchTableNewTmp, ++ p_CcNode->ccKeySizeAccExtraction), ++ 0xff, p_CcNode->userSizeOfExtraction); ++ else ++ MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp, ++ p_CcNode->ccKeySizeAccExtraction), ++ p_CcNode->p_GlblMask, ++ p_CcNode->userSizeOfExtraction); ++ } ++ } ++ else ++ { ++ p_KeysMatchTableNewTmp = ++ PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j * size * sizeof(uint8_t)); ++ p_KeysMatchTableOldTmp = ++ PTR_MOVE(p_CcNode->h_KeysMatchTable, i * size * sizeof(uint8_t)); ++ ++ if (p_CcNode->lclMask) ++ { ++ if (prvLclMask) ++ MemCpy8( ++ PTR_MOVE(p_KeysMatchTableNewTmp, p_CcNode->ccKeySizeAccExtraction), ++ PTR_MOVE(p_KeysMatchTableOldTmp, p_CcNode->ccKeySizeAccExtraction), ++ p_CcNode->userSizeOfExtraction); ++ else ++ { ++ p_KeysMatchTableOldTmp = ++ PTR_MOVE(p_CcNode->h_KeysMatchTable, ++ i * (int)p_CcNode->ccKeySizeAccExtraction * sizeof(uint8_t)); ++ ++ if (p_CcNode->ccKeySizeAccExtraction > 4) ++ MemSet8(PTR_MOVE(p_KeysMatchTableNewTmp, ++ p_CcNode->ccKeySizeAccExtraction), ++ 0xff, p_CcNode->userSizeOfExtraction); ++ else ++ MemCpy8( ++ PTR_MOVE(p_KeysMatchTableNewTmp, p_CcNode->ccKeySizeAccExtraction), ++ p_CcNode->p_GlblMask, ++ p_CcNode->userSizeOfExtraction); ++ } ++ } ++ MemCpy8((void*)p_KeysMatchTableNewTmp, p_KeysMatchTableOldTmp, ++ p_CcNode->ccKeySizeAccExtraction); ++ } ++ } ++ ++ p_AdTableNewTmp = ++ PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j * FM_PCD_CC_AD_ENTRY_SIZE); ++ p_AdTableOldTmp = PTR_MOVE(p_CcNode->h_AdTable, i * FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ return E_OK; ++} ++ ++static t_Error BuildNewNodeModifyNextEngine( ++ t_Handle h_FmPcd, t_Handle h_FmPcdCcNodeOrTree, uint16_t keyIndex, ++ t_FmPcdCcNextEngineParams *p_CcNextEngineParams, t_List *h_OldLst, ++ t_List *h_NewLst, t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo) ++{ ++ t_Error err = E_OK; ++ uint32_t requiredAction = 0; ++ t_List *p_Pos; ++ t_CcNodeInformation *p_CcNodeInformation, ccNodeInfo; ++ t_Handle p_Ad; ++ t_FmPcdCcNode *p_FmPcdCcNode1 = NULL; ++ t_FmPcdCcTree *p_FmPcdCcTree = NULL; ++ t_FmPcdStatsObj *p_StatsObj; ++ t_FmPcdCcStatsParams statsParams = { 0 }; ++ ++ ASSERT_COND(p_CcNextEngineParams); ++ ++ /* check that new NIA is legal */ ++ if (!p_AdditionalInfo->tree) ++ err = ValidateNextEngineParams( ++ h_FmPcd, p_CcNextEngineParams, ++ ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->statisticsMode); ++ else ++ /* Statistics are not supported for CC root */ ++ err = ValidateNextEngineParams(h_FmPcd, p_CcNextEngineParams, ++ e_FM_PCD_CC_STATS_MODE_NONE); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ /* Update internal data structure for next engine per index (index - key) */ ++ memcpy(&p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams, ++ p_CcNextEngineParams, sizeof(t_FmPcdCcNextEngineParams)); ++ ++ /* Check that manip is legal and what requiredAction is necessary for this manip */ ++ if (p_CcNextEngineParams->h_Manip) ++ { ++ err = FmPcdManipCheckParamsForCcNextEngine(p_CcNextEngineParams, ++ &requiredAction); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ } ++ ++ if (!p_AdditionalInfo->tree) ++ { ++ p_FmPcdCcNode1 = (t_FmPcdCcNode *)h_FmPcdCcNodeOrTree; ++ p_AdditionalInfo->numOfKeys = p_FmPcdCcNode1->numOfKeys; ++ p_Ad = p_FmPcdCcNode1->h_AdTable; ++ ++ if (p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ p_AdditionalInfo->h_NodeForRmv = ++ p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode; ++ ++ if (p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip) ++ p_AdditionalInfo->h_ManipForRmv = ++ p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip; ++ ++#if (DPAA_VERSION >= 11) ++ if ((p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine ++ == e_FM_PCD_FR) ++ && (p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic)) ++ p_AdditionalInfo->h_FrmReplicForRmv = ++ p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic; ++#endif /* (DPAA_VERSION >= 11) */ ++ } ++ else ++ { ++ p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcNodeOrTree; ++ p_Ad = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr); ++ ++ if (p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ p_AdditionalInfo->h_NodeForRmv = ++ p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode; ++ ++ if (p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip) ++ p_AdditionalInfo->h_ManipForRmv = ++ p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip; ++ ++#if (DPAA_VERSION >= 11) ++ if ((p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine ++ == e_FM_PCD_FR) ++ && (p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic)) ++ p_AdditionalInfo->h_FrmReplicForRmv = ++ p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic; ++#endif /* (DPAA_VERSION >= 11) */ ++ } ++ ++ if ((p_CcNextEngineParams->nextEngine == e_FM_PCD_CC) ++ && p_CcNextEngineParams->h_Manip) ++ { ++ err = AllocAndFillAdForContLookupManip( ++ p_CcNextEngineParams->params.ccParams.h_CcNode); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ } ++ ++ ASSERT_COND(p_Ad); ++ ++ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); ++ ccNodeInfo.h_CcNode = PTR_MOVE(p_Ad, keyIndex * FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ /* If statistics were enabled, this Ad is the statistics Ad. Need to follow its ++ nextAction to retrieve the actual Nia-Ad. If statistics should remain enabled, ++ only the actual Nia-Ad should be modified. */ ++ if ((!p_AdditionalInfo->tree) ++ && (((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj) ++ && (p_CcNextEngineParams->statisticsEn)) ++ ccNodeInfo.h_CcNode = ++ ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsAd; ++ ++ EnqueueNodeInfoToRelevantLst(h_OldLst, &ccNodeInfo, NULL); ++ ++ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); ++ p_Ad = GetNewAd(h_FmPcdCcNodeOrTree, p_AdditionalInfo->tree); ++ if (!p_Ad) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("MURAM allocation for CC node action descriptor")); ++ MemSet8((uint8_t *)p_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ /* If statistics were not enabled before, but requested now - Allocate a statistics ++ object that holds statistics AD and counters. */ ++ if ((!p_AdditionalInfo->tree) ++ && (!((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj) ++ && (p_CcNextEngineParams->statisticsEn)) ++ { ++ p_StatsObj = GetStatsObj((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree); ++ ASSERT_COND(p_StatsObj); ++ ++ /* Store allocated statistics object */ ++ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].p_StatsObj = ++ p_StatsObj; ++ ++ statsParams.h_StatsAd = p_StatsObj->h_StatsAd; ++ statsParams.h_StatsCounters = p_StatsObj->h_StatsCounters; ++ ++#if (DPAA_VERSION >= 11) ++ statsParams.h_StatsFLRs = ++ ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->h_StatsFLRs; ++ ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ NextStepAd(p_Ad, &statsParams, p_CcNextEngineParams, h_FmPcd); ++ } ++ else ++ NextStepAd(p_Ad, NULL, p_CcNextEngineParams, h_FmPcd); ++ ++ ccNodeInfo.h_CcNode = p_Ad; ++ EnqueueNodeInfoToRelevantLst(h_NewLst, &ccNodeInfo, NULL); ++ ++ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction = ++ requiredAction; ++ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction |= ++ UPDATE_CC_WITH_TREE; ++ ++ if (!p_AdditionalInfo->tree) ++ { ++ ASSERT_COND(p_FmPcdCcNode1); ++ if (!LIST_IsEmpty(&p_FmPcdCcNode1->ccTreesLst)) ++ { ++ LIST_FOR_EACH(p_Pos, &p_FmPcdCcNode1->ccTreesLst) ++ { ++ p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); ++ ++ ASSERT_COND(p_CcNodeInformation->h_CcNode); ++ /* Update the manipulation which has to be updated from parameters of the port ++ it's has to be updated with restrictions defined in the function */ ++ ++ err = ++ SetRequiredAction( ++ p_FmPcdCcNode1->h_FmPcd, ++ p_FmPcdCcNode1->shadowAction ++ | p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction, ++ &p_AdditionalInfo->keyAndNextEngineParams[keyIndex], ++ p_Ad, 1, p_CcNodeInformation->h_CcNode); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ ++ err = CcUpdateParam( ++ p_FmPcdCcNode1->h_FmPcd, NULL, NULL, ++ &p_AdditionalInfo->keyAndNextEngineParams[keyIndex], 1, ++ p_Ad, TRUE, p_CcNodeInformation->index, ++ p_CcNodeInformation->h_CcNode, TRUE); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ } ++ } ++ } ++ else ++ { ++ ASSERT_COND(p_FmPcdCcTree); ++ ++ err = ++ SetRequiredAction( ++ h_FmPcd, ++ p_FmPcdCcTree->requiredAction ++ | p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction, ++ &p_AdditionalInfo->keyAndNextEngineParams[keyIndex], ++ p_Ad, 1, (t_Handle)p_FmPcdCcTree); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ ++ err = CcUpdateParam(h_FmPcd, NULL, NULL, ++ &p_AdditionalInfo->keyAndNextEngineParams[keyIndex], ++ 1, p_Ad, TRUE, 0, (t_Handle)p_FmPcdCcTree, TRUE); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ } ++ ++ if (p_CcNextEngineParams->nextEngine == e_FM_PCD_CC) ++ p_AdditionalInfo->h_NodeForAdd = ++ p_CcNextEngineParams->params.ccParams.h_CcNode; ++ if (p_CcNextEngineParams->h_Manip) ++ p_AdditionalInfo->h_ManipForAdd = p_CcNextEngineParams->h_Manip; ++ ++ /* If statistics were previously enabled, but now are disabled, ++ store the old statistics object to be released */ ++ if ((!p_AdditionalInfo->tree) ++ && (((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj) ++ && (!p_CcNextEngineParams->statisticsEn)) ++ { ++ p_AdditionalInfo->p_StatsObjForRmv = ++ ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj; ++ ++ ++ p_AdditionalInfo->keyAndNextEngineParams[keyIndex].p_StatsObj = NULL; ++ } ++#if (DPAA_VERSION >= 11) ++ if ((p_CcNextEngineParams->nextEngine == e_FM_PCD_FR) ++ && (p_CcNextEngineParams->params.frParams.h_FrmReplic)) ++ p_AdditionalInfo->h_FrmReplicForAdd = ++ p_CcNextEngineParams->params.frParams.h_FrmReplic; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ return E_OK; ++} ++ ++static void UpdateAdPtrOfNodesWhichPointsOnCrntMdfNode( ++ t_FmPcdCcNode *p_CrntMdfNode, t_List *h_OldLst, ++ t_FmPcdCcNextEngineParams **p_NextEngineParams) ++{ ++ t_CcNodeInformation *p_CcNodeInformation; ++ t_FmPcdCcNode *p_NodePtrOnCurrentMdfNode = NULL; ++ t_List *p_Pos; ++ int i = 0; ++ t_Handle p_AdTablePtOnCrntCurrentMdfNode/*, p_AdTableNewModified*/; ++ t_CcNodeInformation ccNodeInfo; ++ ++ LIST_FOR_EACH(p_Pos, &p_CrntMdfNode->ccPrevNodesLst) ++ { ++ p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); ++ p_NodePtrOnCurrentMdfNode = ++ (t_FmPcdCcNode *)p_CcNodeInformation->h_CcNode; ++ ++ ASSERT_COND(p_NodePtrOnCurrentMdfNode); ++ ++ /* Search in the previous node which exact index points on this current modified node for getting AD */ ++ for (i = 0; i < p_NodePtrOnCurrentMdfNode->numOfKeys + 1; i++) ++ { ++ if (p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ { ++ if (p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode ++ == (t_Handle)p_CrntMdfNode) ++ { ++ if (p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip) ++ p_AdTablePtOnCrntCurrentMdfNode = p_CrntMdfNode->h_Ad; ++ else ++ if (p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].p_StatsObj) ++ p_AdTablePtOnCrntCurrentMdfNode = ++ p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].p_StatsObj->h_StatsAd; ++ else ++ p_AdTablePtOnCrntCurrentMdfNode = ++ PTR_MOVE(p_NodePtrOnCurrentMdfNode->h_AdTable, i*FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); ++ ccNodeInfo.h_CcNode = p_AdTablePtOnCrntCurrentMdfNode; ++ EnqueueNodeInfoToRelevantLst(h_OldLst, &ccNodeInfo, NULL); ++ ++ if (!(*p_NextEngineParams)) ++ *p_NextEngineParams = ++ &p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams; ++ } ++ } ++ } ++ ++ ASSERT_COND(i != p_NodePtrOnCurrentMdfNode->numOfKeys); ++ } ++} ++ ++static void UpdateAdPtrOfTreesWhichPointsOnCrntMdfNode( ++ t_FmPcdCcNode *p_CrntMdfNode, t_List *h_OldLst, ++ t_FmPcdCcNextEngineParams **p_NextEngineParams) ++{ ++ t_CcNodeInformation *p_CcNodeInformation; ++ t_FmPcdCcTree *p_TreePtrOnCurrentMdfNode = NULL; ++ t_List *p_Pos; ++ int i = 0; ++ t_Handle p_AdTableTmp; ++ t_CcNodeInformation ccNodeInfo; ++ ++ LIST_FOR_EACH(p_Pos, &p_CrntMdfNode->ccTreeIdLst) ++ { ++ p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); ++ p_TreePtrOnCurrentMdfNode = ++ (t_FmPcdCcTree *)p_CcNodeInformation->h_CcNode; ++ ++ ASSERT_COND(p_TreePtrOnCurrentMdfNode); ++ ++ /*search in the trees which exact index points on this current modified node for getting AD */ ++ for (i = 0; i < p_TreePtrOnCurrentMdfNode->numOfEntries; i++) ++ { ++ if (p_TreePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ { ++ if (p_TreePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode ++ == (t_Handle)p_CrntMdfNode) ++ { ++ p_AdTableTmp = ++ UINT_TO_PTR(p_TreePtrOnCurrentMdfNode->ccTreeBaseAddr + i*FM_PCD_CC_AD_ENTRY_SIZE); ++ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); ++ ccNodeInfo.h_CcNode = p_AdTableTmp; ++ EnqueueNodeInfoToRelevantLst(h_OldLst, &ccNodeInfo, NULL); ++ ++ if (!(*p_NextEngineParams)) ++ *p_NextEngineParams = ++ &p_TreePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams; ++ } ++ } ++ } ++ ++ ASSERT_COND(i == p_TreePtrOnCurrentMdfNode->numOfEntries); ++ } ++} ++ ++static t_FmPcdModifyCcKeyAdditionalParams * ModifyNodeCommonPart( ++ t_Handle h_FmPcdCcNodeOrTree, uint16_t keyIndex, ++ e_ModifyState modifyState, bool ttlCheck, bool hashCheck, bool tree) ++{ ++ t_FmPcdModifyCcKeyAdditionalParams *p_FmPcdModifyCcKeyAdditionalParams; ++ int i = 0, j = 0; ++ bool wasUpdate = FALSE; ++ t_FmPcdCcNode *p_CcNode = NULL; ++ t_FmPcdCcTree *p_FmPcdCcTree; ++ uint16_t numOfKeys; ++ t_FmPcdCcKeyAndNextEngineParams *p_KeyAndNextEngineParams; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmPcdCcNodeOrTree, E_INVALID_HANDLE, NULL); ++ ++ if (!tree) ++ { ++ p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNodeOrTree; ++ numOfKeys = p_CcNode->numOfKeys; ++ ++ /* node has to be pointed by another node or tree */ ++ ++ p_KeyAndNextEngineParams = (t_FmPcdCcKeyAndNextEngineParams *)XX_Malloc( ++ sizeof(t_FmPcdCcKeyAndNextEngineParams) * (numOfKeys + 1)); ++ if (!p_KeyAndNextEngineParams) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Next engine and required action structure")); ++ return NULL; ++ } ++ memcpy(p_KeyAndNextEngineParams, p_CcNode->keyAndNextEngineParams, ++ (numOfKeys + 1) * sizeof(t_FmPcdCcKeyAndNextEngineParams)); ++ ++ if (ttlCheck) ++ { ++ if ((p_CcNode->parseCode == CC_PC_FF_IPV4TTL) ++ || (p_CcNode->parseCode == CC_PC_FF_IPV6HOP_LIMIT)) ++ { ++ XX_Free(p_KeyAndNextEngineParams); ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("nodeId of CC_PC_FF_IPV4TTL or CC_PC_FF_IPV6HOP_LIMIT can not be used for this operation")); ++ return NULL; ++ } ++ } ++ ++ if (hashCheck) ++ { ++ if (p_CcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED) ++ { ++ XX_Free(p_KeyAndNextEngineParams); ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("nodeId of CC_PC_GENERIC_IC_HASH_INDEXED can not be used for this operation")); ++ return NULL; ++ } ++ } ++ } ++ else ++ { ++ p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcNodeOrTree; ++ numOfKeys = p_FmPcdCcTree->numOfEntries; ++ ++ p_KeyAndNextEngineParams = (t_FmPcdCcKeyAndNextEngineParams *)XX_Malloc( ++ sizeof(t_FmPcdCcKeyAndNextEngineParams) ++ * FM_PCD_MAX_NUM_OF_CC_GROUPS); ++ if (!p_KeyAndNextEngineParams) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Next engine and required action structure")); ++ return NULL; ++ } ++ memcpy(p_KeyAndNextEngineParams, ++ p_FmPcdCcTree->keyAndNextEngineParams, ++ FM_PCD_MAX_NUM_OF_CC_GROUPS ++ * sizeof(t_FmPcdCcKeyAndNextEngineParams)); ++ } ++ ++ p_FmPcdModifyCcKeyAdditionalParams = ++ (t_FmPcdModifyCcKeyAdditionalParams *)XX_Malloc( ++ sizeof(t_FmPcdModifyCcKeyAdditionalParams)); ++ if (!p_FmPcdModifyCcKeyAdditionalParams) ++ { ++ XX_Free(p_KeyAndNextEngineParams); ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Allocation of internal data structure FAILED")); ++ return NULL; ++ } ++ memset(p_FmPcdModifyCcKeyAdditionalParams, 0, ++ sizeof(t_FmPcdModifyCcKeyAdditionalParams)); ++ ++ p_FmPcdModifyCcKeyAdditionalParams->h_CurrentNode = h_FmPcdCcNodeOrTree; ++ p_FmPcdModifyCcKeyAdditionalParams->savedKeyIndex = keyIndex; ++ ++ while (i < numOfKeys) ++ { ++ if ((j == keyIndex) && !wasUpdate) ++ { ++ if (modifyState == e_MODIFY_STATE_ADD) ++ j++; ++ else ++ if (modifyState == e_MODIFY_STATE_REMOVE) ++ i++; ++ wasUpdate = TRUE; ++ } ++ else ++ { ++ memcpy(&p_FmPcdModifyCcKeyAdditionalParams->keyAndNextEngineParams[j], ++ p_KeyAndNextEngineParams + i, ++ sizeof(t_FmPcdCcKeyAndNextEngineParams)); ++ i++; ++ j++; ++ } ++ } ++ ++ if (keyIndex == numOfKeys) ++ { ++ if (modifyState == e_MODIFY_STATE_ADD) ++ j++; ++ } ++ ++ memcpy(&p_FmPcdModifyCcKeyAdditionalParams->keyAndNextEngineParams[j], ++ p_KeyAndNextEngineParams + numOfKeys, ++ sizeof(t_FmPcdCcKeyAndNextEngineParams)); ++ ++ XX_Free(p_KeyAndNextEngineParams); ++ ++ return p_FmPcdModifyCcKeyAdditionalParams; ++} ++ ++static t_Error UpdatePtrWhichPointOnCrntMdfNode( ++ t_FmPcdCcNode *p_CcNode, ++ t_FmPcdModifyCcKeyAdditionalParams *p_FmPcdModifyCcKeyAdditionalParams, ++ t_List *h_OldLst, t_List *h_NewLst) ++{ ++ t_FmPcdCcNextEngineParams *p_NextEngineParams = NULL; ++ t_CcNodeInformation ccNodeInfo = { 0 }; ++ t_Handle h_NewAd; ++ t_Handle h_OrigAd = NULL; ++ ++ /* Building a list of all action descriptors that point to the previous node */ ++ if (!LIST_IsEmpty(&p_CcNode->ccPrevNodesLst)) ++ UpdateAdPtrOfNodesWhichPointsOnCrntMdfNode(p_CcNode, h_OldLst, ++ &p_NextEngineParams); ++ ++ if (!LIST_IsEmpty(&p_CcNode->ccTreeIdLst)) ++ UpdateAdPtrOfTreesWhichPointsOnCrntMdfNode(p_CcNode, h_OldLst, ++ &p_NextEngineParams); ++ ++ /* This node must be found as next engine of one of its previous nodes or trees*/ ++ if (p_NextEngineParams) ++ { ++ /* Building a new action descriptor that points to the modified node */ ++ h_NewAd = GetNewAd(p_CcNode, FALSE); ++ if (!h_NewAd) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); ++ MemSet8(h_NewAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ h_OrigAd = p_CcNode->h_Ad; ++ BuildNewAd(h_NewAd, p_FmPcdModifyCcKeyAdditionalParams, p_CcNode, ++ p_NextEngineParams); ++ ++ ccNodeInfo.h_CcNode = h_NewAd; ++ EnqueueNodeInfoToRelevantLst(h_NewLst, &ccNodeInfo, NULL); ++ ++ if (p_NextEngineParams->h_Manip && !h_OrigAd) ++ FmPcdManipUpdateOwner(p_NextEngineParams->h_Manip, FALSE); ++ } ++ return E_OK; ++} ++ ++static void UpdateCcRootOwner(t_FmPcdCcTree *p_FmPcdCcTree, bool add) ++{ ++ ASSERT_COND(p_FmPcdCcTree); ++ ++ /* this routine must be protected by the calling routine! */ ++ ++ if (add) ++ p_FmPcdCcTree->owners++; ++ else ++ { ++ ASSERT_COND(p_FmPcdCcTree->owners); ++ p_FmPcdCcTree->owners--; ++ } ++} ++ ++static t_Error CheckAndSetManipParamsWithCcNodeParams(t_FmPcdCcNode *p_CcNode) ++{ ++ t_Error err = E_OK; ++ int i = 0; ++ ++ for (i = 0; i < p_CcNode->numOfKeys; i++) ++ { ++ if (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip) ++ { ++ err = ++ FmPcdManipCheckParamsWithCcNodeParams( ++ p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip, ++ (t_Handle)p_CcNode); ++ if (err) ++ return err; ++ } ++ } ++ ++ return err; ++} ++static t_Error ValidateAndCalcStatsParams(t_FmPcdCcNode *p_CcNode, ++ t_FmPcdCcNodeParams *p_CcNodeParam, ++ uint32_t *p_NumOfRanges, ++ uint32_t *p_CountersArraySize) ++{ ++ e_FmPcdCcStatsMode statisticsMode = p_CcNode->statisticsMode; ++ uint32_t i; ++ ++ UNUSED(p_CcNodeParam); ++ ++ switch (statisticsMode) ++ { ++ case e_FM_PCD_CC_STATS_MODE_NONE: ++ for (i = 0; i < p_CcNode->numOfKeys; i++) ++ if (p_CcNodeParam->keysParams.keyParams[i].ccNextEngineParams.statisticsEn) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("Statistics cannot be enabled for key %d when statistics mode was set to 'NONE'", i)); ++ return E_OK; ++ ++ case e_FM_PCD_CC_STATS_MODE_FRAME: ++ case e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME: ++ *p_NumOfRanges = 1; ++ *p_CountersArraySize = 2 * FM_PCD_CC_STATS_COUNTER_SIZE; ++ return E_OK; ++ ++#if (DPAA_VERSION >= 11) ++ case e_FM_PCD_CC_STATS_MODE_RMON: ++ { ++ uint16_t *p_FrameLengthRanges = ++ p_CcNodeParam->keysParams.frameLengthRanges; ++ uint32_t i; ++ ++ if (p_FrameLengthRanges[0] <= 0) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Statistics mode")); ++ ++ if (p_FrameLengthRanges[0] == 0xFFFF) ++ { ++ *p_NumOfRanges = 1; ++ *p_CountersArraySize = 2 * FM_PCD_CC_STATS_COUNTER_SIZE; ++ return E_OK; ++ } ++ ++ for (i = 1; i < FM_PCD_CC_STATS_MAX_NUM_OF_FLR; i++) ++ { ++ if (p_FrameLengthRanges[i - 1] >= p_FrameLengthRanges[i]) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("Frame length range must be larger at least by 1 from preceding range")); ++ ++ /* Stop when last range is reached */ ++ if (p_FrameLengthRanges[i] == 0xFFFF) ++ break; ++ } ++ ++ if ((i >= FM_PCD_CC_STATS_MAX_NUM_OF_FLR) ++ || (p_FrameLengthRanges[i] != 0xFFFF)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("Last Frame length range must be 0xFFFF")); ++ ++ *p_NumOfRanges = i + 1; ++ ++ /* Allocate an extra counter for byte count, as counters ++ array always begins with byte count */ ++ *p_CountersArraySize = (*p_NumOfRanges + 1) ++ * FM_PCD_CC_STATS_COUNTER_SIZE; ++ ++ } ++ return E_OK; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Statistics mode")); ++ } ++} ++ ++static t_Error CheckParams(t_Handle h_FmPcd, t_FmPcdCcNodeParams *p_CcNodeParam, ++ t_FmPcdCcNode *p_CcNode, bool *isKeyTblAlloc) ++{ ++ int tmp = 0; ++ t_FmPcdCcKeyParams *p_KeyParams; ++ t_Error err; ++ uint32_t requiredAction = 0; ++ ++ /* Validate statistics parameters */ ++ err = ValidateAndCalcStatsParams(p_CcNode, p_CcNodeParam, ++ &(p_CcNode->numOfStatsFLRs), ++ &(p_CcNode->countersArraySize)); ++ if (err) ++ RETURN_ERROR(MAJOR, err, ("Invalid statistics parameters")); ++ ++ /* Validate next engine parameters on Miss */ ++ err = ValidateNextEngineParams( ++ h_FmPcd, &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, ++ p_CcNode->statisticsMode); ++ if (err) ++ RETURN_ERROR(MAJOR, err, ++ ("For this node MissNextEngineParams are not valid")); ++ ++ if (p_CcNodeParam->keysParams.ccNextEngineParamsForMiss.h_Manip) ++ { ++ err = FmPcdManipCheckParamsForCcNextEngine( ++ &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, ++ &requiredAction); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ } ++ ++ memcpy(&p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams, ++ &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, ++ sizeof(t_FmPcdCcNextEngineParams)); ++ ++ p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].requiredAction = ++ requiredAction; ++ ++ if ((p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ && p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.h_Manip) ++ { ++ err = ++ AllocAndFillAdForContLookupManip( ++ p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.params.ccParams.h_CcNode); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ } ++ ++ for (tmp = 0; tmp < p_CcNode->numOfKeys; tmp++) ++ { ++ p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp]; ++ ++ if (!p_KeyParams->p_Key) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("p_Key is not initialized")); ++ ++ err = ValidateNextEngineParams(h_FmPcd, ++ &p_KeyParams->ccNextEngineParams, ++ p_CcNode->statisticsMode); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ ++ err = UpdateGblMask(p_CcNode, p_CcNodeParam->keysParams.keySize, ++ p_KeyParams->p_Mask); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ ++ if (p_KeyParams->ccNextEngineParams.h_Manip) ++ { ++ err = FmPcdManipCheckParamsForCcNextEngine( ++ &p_KeyParams->ccNextEngineParams, &requiredAction); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ } ++ ++ /* Store 'key' parameters - key, mask (if passed by the user) */ ++ memcpy(p_CcNode->keyAndNextEngineParams[tmp].key, p_KeyParams->p_Key, ++ p_CcNodeParam->keysParams.keySize); ++ ++ if (p_KeyParams->p_Mask) ++ memcpy(p_CcNode->keyAndNextEngineParams[tmp].mask, ++ p_KeyParams->p_Mask, p_CcNodeParam->keysParams.keySize); ++ else ++ memset((void *)(p_CcNode->keyAndNextEngineParams[tmp].mask), 0xFF, ++ p_CcNodeParam->keysParams.keySize); ++ ++ /* Store next engine parameters */ ++ memcpy(&p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams, ++ &p_KeyParams->ccNextEngineParams, ++ sizeof(t_FmPcdCcNextEngineParams)); ++ ++ p_CcNode->keyAndNextEngineParams[tmp].requiredAction = requiredAction; ++ ++ if ((p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ && p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip) ++ { ++ err = ++ AllocAndFillAdForContLookupManip( ++ p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.params.ccParams.h_CcNode); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ } ++ } ++ ++ if (p_CcNode->maxNumOfKeys) ++ { ++ if (p_CcNode->maxNumOfKeys < p_CcNode->numOfKeys) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("Number of keys exceed the provided maximal number of keys")); ++ } ++ ++ *isKeyTblAlloc = TRUE; ++ ++ return E_OK; ++} ++ ++static t_Error Ipv4TtlOrIpv6HopLimitCheckParams( ++ t_Handle h_FmPcd, t_FmPcdCcNodeParams *p_CcNodeParam, ++ t_FmPcdCcNode *p_CcNode, bool *isKeyTblAlloc) ++{ ++ int tmp = 0; ++ t_FmPcdCcKeyParams *p_KeyParams; ++ t_Error err; ++ uint8_t key = 0x01; ++ uint32_t requiredAction = 0; ++ ++ if (p_CcNode->numOfKeys != 1) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("For node of the type IPV4_TTL or IPV6_HOP_LIMIT the maximal supported 'numOfKeys' is 1")); ++ ++ if ((p_CcNodeParam->keysParams.maxNumOfKeys) ++ && (p_CcNodeParam->keysParams.maxNumOfKeys != 1)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("For node of the type IPV4_TTL or IPV6_HOP_LIMIT the maximal supported 'maxNumOfKeys' is 1")); ++ ++ /* Validate statistics parameters */ ++ err = ValidateAndCalcStatsParams(p_CcNode, p_CcNodeParam, ++ &(p_CcNode->numOfStatsFLRs), ++ &(p_CcNode->countersArraySize)); ++ if (err) ++ RETURN_ERROR(MAJOR, err, ("Invalid statistics parameters")); ++ ++ err = ValidateNextEngineParams( ++ h_FmPcd, &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, ++ p_CcNodeParam->keysParams.statisticsMode); ++ if (err) ++ RETURN_ERROR(MAJOR, err, ++ ("For this node MissNextEngineParams are not valid")); ++ ++ if (p_CcNodeParam->keysParams.ccNextEngineParamsForMiss.h_Manip) ++ { ++ err = FmPcdManipCheckParamsForCcNextEngine( ++ &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, ++ &requiredAction); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ } ++ ++ memcpy(&p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams, ++ &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, ++ sizeof(t_FmPcdCcNextEngineParams)); ++ ++ p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].requiredAction = ++ requiredAction; ++ ++ if ((p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ && p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.h_Manip) ++ { ++ err = ++ AllocAndFillAdForContLookupManip( ++ p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.params.ccParams.h_CcNode); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ } ++ ++ for (tmp = 0; tmp < p_CcNode->numOfKeys; tmp++) ++ { ++ p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp]; ++ ++ if (p_KeyParams->p_Mask) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("For node of the type IPV4_TTL or IPV6_HOP_LIMIT p_Mask can not be initialized")); ++ ++ if (memcmp(p_KeyParams->p_Key, &key, 1) != 0) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("For node of the type IPV4_TTL or IPV6_HOP_LIMIT p_Key has to be 1")); ++ ++ err = ValidateNextEngineParams(h_FmPcd, ++ &p_KeyParams->ccNextEngineParams, ++ p_CcNode->statisticsMode); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ ++ if (p_KeyParams->ccNextEngineParams.h_Manip) ++ { ++ err = FmPcdManipCheckParamsForCcNextEngine( ++ &p_KeyParams->ccNextEngineParams, &requiredAction); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ } ++ ++ /* Store 'key' parameters - key (fixed to 0x01), key size of 1 byte and full mask */ ++ p_CcNode->keyAndNextEngineParams[tmp].key[0] = key; ++ p_CcNode->keyAndNextEngineParams[tmp].mask[0] = 0xFF; ++ ++ /* Store NextEngine parameters */ ++ memcpy(&p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams, ++ &p_KeyParams->ccNextEngineParams, ++ sizeof(t_FmPcdCcNextEngineParams)); ++ ++ if ((p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ && p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip) ++ { ++ err = ++ AllocAndFillAdForContLookupManip( ++ p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.params.ccParams.h_CcNode); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ } ++ p_CcNode->keyAndNextEngineParams[tmp].requiredAction = requiredAction; ++ } ++ ++ *isKeyTblAlloc = FALSE; ++ ++ return E_OK; ++} ++ ++static t_Error IcHashIndexedCheckParams(t_Handle h_FmPcd, ++ t_FmPcdCcNodeParams *p_CcNodeParam, ++ t_FmPcdCcNode *p_CcNode, ++ bool *isKeyTblAlloc) ++{ ++ int tmp = 0, countOnes = 0; ++ t_FmPcdCcKeyParams *p_KeyParams; ++ t_Error err; ++ uint16_t glblMask = p_CcNodeParam->extractCcParams.extractNonHdr.icIndxMask; ++ uint16_t countMask = (uint16_t)(glblMask >> 4); ++ uint32_t requiredAction = 0; ++ ++ if (glblMask & 0x000f) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("icIndxMask has to be with last nibble 0")); ++ ++ while (countMask) ++ { ++ countOnes++; ++ countMask = (uint16_t)(countMask >> 1); ++ } ++ ++ if (!POWER_OF_2(p_CcNode->numOfKeys)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("For Node of the type INDEXED numOfKeys has to be powerOfTwo")); ++ ++ if (p_CcNode->numOfKeys != ((uint32_t)1 << countOnes)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("For Node of the type IC_HASH_INDEXED numOfKeys has to be powerOfTwo")); ++ ++ if (p_CcNodeParam->keysParams.maxNumOfKeys ++ && (p_CcNodeParam->keysParams.maxNumOfKeys != p_CcNode->numOfKeys)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("For Node of the type INDEXED 'maxNumOfKeys' should be 0 or equal 'numOfKeys'")); ++ ++ /* Validate statistics parameters */ ++ err = ValidateAndCalcStatsParams(p_CcNode, p_CcNodeParam, ++ &(p_CcNode->numOfStatsFLRs), ++ &(p_CcNode->countersArraySize)); ++ if (err) ++ RETURN_ERROR(MAJOR, err, ("Invalid statistics parameters")); ++ ++ err = ValidateNextEngineParams( ++ h_FmPcd, &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, ++ p_CcNode->statisticsMode); ++ if (GET_ERROR_TYPE(err) != E_NOT_SUPPORTED) ++ RETURN_ERROR( ++ MAJOR, ++ err, ++ ("MissNextEngineParams for the node of the type IC_INDEX_HASH has to be UnInitialized")); ++ ++ for (tmp = 0; tmp < p_CcNode->numOfKeys; tmp++) ++ { ++ p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp]; ++ ++ if (p_KeyParams->p_Mask || p_KeyParams->p_Key) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("For Node of the type IC_HASH_INDEXED p_Key or p_Mask has to be NULL")); ++ ++ if ((glblMask & (tmp * 16)) == (tmp * 16)) ++ { ++ err = ValidateNextEngineParams(h_FmPcd, ++ &p_KeyParams->ccNextEngineParams, ++ p_CcNode->statisticsMode); ++ if (err) ++ RETURN_ERROR( ++ MAJOR, ++ err, ++ ("This index has to be initialized for the node of the type IC_INDEX_HASH according to settings of GlobalMask ")); ++ ++ if (p_KeyParams->ccNextEngineParams.h_Manip) ++ { ++ err = FmPcdManipCheckParamsForCcNextEngine( ++ &p_KeyParams->ccNextEngineParams, &requiredAction); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ p_CcNode->keyAndNextEngineParams[tmp].requiredAction = ++ requiredAction; ++ } ++ ++ memcpy(&p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams, ++ &p_KeyParams->ccNextEngineParams, ++ sizeof(t_FmPcdCcNextEngineParams)); ++ ++ if ((p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ && p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip) ++ { ++ err = ++ AllocAndFillAdForContLookupManip( ++ p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.params.ccParams.h_CcNode); ++ if (err) ++ RETURN_ERROR(MAJOR, err, (NO_MSG)); ++ } ++ } ++ else ++ { ++ err = ValidateNextEngineParams(h_FmPcd, ++ &p_KeyParams->ccNextEngineParams, ++ p_CcNode->statisticsMode); ++ if (GET_ERROR_TYPE(err) != E_NOT_SUPPORTED) ++ RETURN_ERROR( ++ MAJOR, ++ err, ++ ("This index has to be UnInitialized for the node of the type IC_INDEX_HASH according to settings of GlobalMask")); ++ } ++ } ++ ++ *isKeyTblAlloc = FALSE; ++ cpu_to_be16s(&glblMask); ++ memcpy(PTR_MOVE(p_CcNode->p_GlblMask, 2), &glblMask, 2); ++ ++ return E_OK; ++} ++ ++static t_Error ModifyNextEngineParamNode( ++ t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint16_t keyIndex, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; ++ t_FmPcd *p_FmPcd; ++ t_List h_OldPointersLst, h_NewPointersLst; ++ t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_VALUE); ++ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); ++ ++ if (keyIndex >= p_CcNode->numOfKeys) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("keyIndex > previously cleared last index + 1")); ++ ++ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ ++ INIT_LIST(&h_OldPointersLst); ++ INIT_LIST(&h_NewPointersLst); ++ ++ p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex, ++ e_MODIFY_STATE_CHANGE, FALSE, ++ FALSE, FALSE); ++ if (!p_ModifyKeyParams) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ ++ if (p_CcNode->maxNumOfKeys ++ && !TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) ++ { ++ XX_Free(p_ModifyKeyParams); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = BuildNewNodeModifyNextEngine(h_FmPcd, p_CcNode, keyIndex, ++ p_FmPcdCcNextEngineParams, ++ &h_OldPointersLst, &h_NewPointersLst, ++ p_ModifyKeyParams); ++ if (err) ++ { ++ XX_Free(p_ModifyKeyParams); ++ if (p_CcNode->maxNumOfKeys) ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst, ++ p_ModifyKeyParams, FALSE); ++ ++ if (p_CcNode->maxNumOfKeys) ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ ++ ReleaseLst(&h_OldPointersLst); ++ ReleaseLst(&h_NewPointersLst); ++ ++ return err; ++} ++ ++static t_Error FindKeyIndex(t_Handle h_CcNode, uint8_t keySize, uint8_t *p_Key, ++ uint8_t *p_Mask, uint16_t *p_KeyIndex) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ uint8_t tmpMask[FM_PCD_MAX_SIZE_OF_KEY]; ++ uint16_t i; ++ ++ ASSERT_COND(p_Key); ++ ASSERT_COND(p_KeyIndex); ++ ASSERT_COND(keySize < FM_PCD_MAX_SIZE_OF_KEY); ++ ++ if (keySize != p_CcNode->userSizeOfExtraction) ++ RETURN_ERROR( ++ MINOR, E_INVALID_VALUE, ++ ("Key size doesn't match the extraction size of the node")); ++ ++ /* If user didn't pass a mask for this key, we'll look for full extraction mask */ ++ if (!p_Mask) ++ memset(tmpMask, 0xFF, keySize); ++ ++ for (i = 0; i < p_CcNode->numOfKeys; i++) ++ { ++ /* Comparing received key */ ++ if (memcmp(p_Key, p_CcNode->keyAndNextEngineParams[i].key, keySize) ++ == 0) ++ { ++ if (p_Mask) ++ { ++ /* If a user passed a mask for this key, it must match to the existing key's mask for a correct match */ ++ if (memcmp(p_Mask, p_CcNode->keyAndNextEngineParams[i].mask, ++ keySize) == 0) ++ { ++ *p_KeyIndex = i; ++ return E_OK; ++ } ++ } ++ else ++ { ++ /* If user didn't pass a mask for this key, check if the existing key mask is full extraction */ ++ if (memcmp(tmpMask, p_CcNode->keyAndNextEngineParams[i].mask, ++ keySize) == 0) ++ { ++ *p_KeyIndex = i; ++ return E_OK; ++ } ++ } ++ } ++ } ++ ++ return ERROR_CODE(E_NOT_FOUND); ++} ++ ++static t_Error CalcAndUpdateCcShadow(t_FmPcdCcNode *p_CcNode, ++ bool isKeyTblAlloc, ++ uint32_t *p_MatchTableSize, ++ uint32_t *p_AdTableSize) ++{ ++ uint32_t shadowSize; ++ t_Error err; ++ ++ /* Calculate keys table maximal size - each entry consists of a key and a mask, ++ (if local mask support is requested) */ ++ *p_MatchTableSize = p_CcNode->ccKeySizeAccExtraction * sizeof(uint8_t) ++ * p_CcNode->maxNumOfKeys; ++ ++ if (p_CcNode->maskSupport) ++ *p_MatchTableSize *= 2; ++ ++ /* Calculate next action descriptors table, including one more entry for miss */ ++ *p_AdTableSize = (uint32_t)((p_CcNode->maxNumOfKeys + 1) ++ * FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ /* Calculate maximal shadow size of this node. ++ All shadow structures will be used for runtime modifications host command. If ++ keys table was allocated for this node, the keys table and next engines table may ++ be modified in run time (entries added or removed), so shadow tables are requires. ++ Otherwise, the only supported runtime modification is a specific next engine update ++ and this requires shadow memory of a single AD */ ++ ++ /* Shadow size should be enough to hold the following 3 structures: ++ * 1 - an action descriptor */ ++ shadowSize = FM_PCD_CC_AD_ENTRY_SIZE; ++ ++ /* 2 - keys match table, if was allocated for the current node */ ++ if (isKeyTblAlloc) ++ shadowSize += *p_MatchTableSize; ++ ++ /* 3 - next action descriptors table */ ++ shadowSize += *p_AdTableSize; ++ ++ /* Update shadow to the calculated size */ ++ err = FmPcdUpdateCcShadow(p_CcNode->h_FmPcd, (uint32_t)shadowSize, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (err != E_OK) ++ { ++ DeleteNode(p_CcNode); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CC node shadow")); ++ } ++ ++ return E_OK; ++} ++ ++static t_Error AllocStatsObjs(t_FmPcdCcNode *p_CcNode) ++{ ++ t_FmPcdStatsObj *p_StatsObj; ++ t_Handle h_FmMuram, h_StatsAd, h_StatsCounters; ++ uint32_t i; ++ ++ h_FmMuram = FmPcdGetMuramHandle(p_CcNode->h_FmPcd); ++ if (!h_FmMuram) ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM MURAM")); ++ ++ /* Allocate statistics ADs and statistics counter. An extra pair (AD + counters) ++ will be allocated to support runtime modifications */ ++ for (i = 0; i < p_CcNode->maxNumOfKeys + 2; i++) ++ { ++ /* Allocate list object structure */ ++ p_StatsObj = XX_Malloc(sizeof(t_FmPcdStatsObj)); ++ if (!p_StatsObj) ++ { ++ FreeStatObjects(&p_CcNode->availableStatsLst, h_FmMuram); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Statistics object")); ++ } ++ memset(p_StatsObj, 0, sizeof(t_FmPcdStatsObj)); ++ ++ /* Allocate statistics AD from MURAM */ ++ h_StatsAd = (t_Handle)FM_MURAM_AllocMem(h_FmMuram, ++ FM_PCD_CC_AD_ENTRY_SIZE, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!h_StatsAd) ++ { ++ FreeStatObjects(&p_CcNode->availableStatsLst, h_FmMuram); ++ XX_Free(p_StatsObj); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("MURAM allocation for statistics ADs")); ++ } ++ MemSet8(h_StatsAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ /* Allocate statistics counters from MURAM */ ++ h_StatsCounters = (t_Handle)FM_MURAM_AllocMem( ++ h_FmMuram, p_CcNode->countersArraySize, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!h_StatsCounters) ++ { ++ FreeStatObjects(&p_CcNode->availableStatsLst, h_FmMuram); ++ FM_MURAM_FreeMem(h_FmMuram, h_StatsAd); ++ XX_Free(p_StatsObj); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("MURAM allocation for statistics counters")); ++ } ++ MemSet8(h_StatsCounters, 0, p_CcNode->countersArraySize); ++ ++ p_StatsObj->h_StatsAd = h_StatsAd; ++ p_StatsObj->h_StatsCounters = h_StatsCounters; ++ ++ EnqueueStatsObj(&p_CcNode->availableStatsLst, p_StatsObj); ++ } ++ ++ return E_OK; ++} ++ ++static t_Error MatchTableGetKeyStatistics( ++ t_FmPcdCcNode *p_CcNode, uint16_t keyIndex, ++ t_FmPcdCcKeyStatistics *p_KeyStatistics) ++{ ++ uint32_t *p_StatsCounters, i; ++ ++ if (p_CcNode->statisticsMode == e_FM_PCD_CC_STATS_MODE_NONE) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("Statistics were not enabled for this match table")); ++ ++ if (!p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("Statistics were not enabled for this key")); ++ ++ memset(p_KeyStatistics, 0, sizeof(t_FmPcdCcKeyStatistics)); ++ ++ p_StatsCounters = ++ p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsCounters; ++ ASSERT_COND(p_StatsCounters); ++ ++ p_KeyStatistics->byteCount = GET_UINT32(*p_StatsCounters); ++ ++ for (i = 1; i <= p_CcNode->numOfStatsFLRs; i++) ++ { ++ p_StatsCounters = ++ PTR_MOVE(p_StatsCounters, FM_PCD_CC_STATS_COUNTER_SIZE); ++ ++ p_KeyStatistics->frameCount += GET_UINT32(*p_StatsCounters); ++ ++#if (DPAA_VERSION >= 11) ++ p_KeyStatistics->frameLengthRangeCount[i - 1] = ++ GET_UINT32(*p_StatsCounters); ++#endif /* (DPAA_VERSION >= 11) */ ++ } ++ ++ return E_OK; ++} ++ ++static t_Error MatchTableSet(t_Handle h_FmPcd, t_FmPcdCcNode *p_CcNode, ++ t_FmPcdCcNodeParams *p_CcNodeParam) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ t_FmPcdCcNode *p_FmPcdCcNextNode; ++ t_Error err = E_OK; ++ uint32_t tmp, keySize; ++ bool glblMask = FALSE; ++ t_FmPcdCcKeyParams *p_KeyParams; ++ t_Handle h_FmMuram, p_KeysMatchTblTmp, p_AdTableTmp; ++#if (DPAA_VERSION >= 11) ++ t_Handle h_StatsFLRs; ++#endif /* (DPAA_VERSION >= 11) */ ++ bool fullField = FALSE; ++ ccPrivateInfo_t icCode = CC_PRIVATE_INFO_NONE; ++ bool isKeyTblAlloc, fromIc = FALSE; ++ uint32_t matchTableSize, adTableSize; ++ t_CcNodeInformation ccNodeInfo, *p_CcInformation; ++ t_FmPcdStatsObj *p_StatsObj; ++ t_FmPcdCcStatsParams statsParams = { 0 }; ++ t_Handle h_Manip; ++ ++ ASSERT_COND(h_FmPcd); ++ ASSERT_COND(p_CcNode); ++ ASSERT_COND(p_CcNodeParam); ++ ++ p_CcNode->p_GlblMask = (t_Handle)XX_Malloc( ++ CC_GLBL_MASK_SIZE * sizeof(uint8_t)); ++ memset(p_CcNode->p_GlblMask, 0, CC_GLBL_MASK_SIZE * sizeof(uint8_t)); ++ ++ p_CcNode->h_FmPcd = h_FmPcd; ++ p_CcNode->numOfKeys = p_CcNodeParam->keysParams.numOfKeys; ++ p_CcNode->maxNumOfKeys = p_CcNodeParam->keysParams.maxNumOfKeys; ++ p_CcNode->maskSupport = p_CcNodeParam->keysParams.maskSupport; ++ p_CcNode->statisticsMode = p_CcNodeParam->keysParams.statisticsMode; ++ ++ /* For backward compatibility - even if statistics mode is nullified, ++ we'll fix it to frame mode so we can support per-key request for ++ statistics using 'statisticsEn' in next engine parameters */ ++ if (!p_CcNode->maxNumOfKeys ++ && (p_CcNode->statisticsMode == e_FM_PCD_CC_STATS_MODE_NONE)) ++ p_CcNode->statisticsMode = e_FM_PCD_CC_STATS_MODE_FRAME; ++ ++ h_FmMuram = FmPcdGetMuramHandle(h_FmPcd); ++ if (!h_FmMuram) ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM MURAM")); ++ ++ INIT_LIST(&p_CcNode->ccPrevNodesLst); ++ INIT_LIST(&p_CcNode->ccTreeIdLst); ++ INIT_LIST(&p_CcNode->ccTreesLst); ++ INIT_LIST(&p_CcNode->availableStatsLst); ++ ++ p_CcNode->h_Spinlock = XX_InitSpinlock(); ++ if (!p_CcNode->h_Spinlock) ++ { ++ DeleteNode(p_CcNode); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("CC node spinlock")); ++ } ++ ++ if ((p_CcNodeParam->extractCcParams.type == e_FM_PCD_EXTRACT_BY_HDR) ++ && ((p_CcNodeParam->extractCcParams.extractByHdr.hdr ++ == HEADER_TYPE_IPv4) ++ || (p_CcNodeParam->extractCcParams.extractByHdr.hdr ++ == HEADER_TYPE_IPv6)) ++ && (p_CcNodeParam->extractCcParams.extractByHdr.type ++ == e_FM_PCD_EXTRACT_FULL_FIELD) ++ && ((p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField.ipv6 ++ == NET_HEADER_FIELD_IPv6_HOP_LIMIT) ++ || (p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField.ipv4 ++ == NET_HEADER_FIELD_IPv4_TTL))) ++ { ++ err = Ipv4TtlOrIpv6HopLimitCheckParams(h_FmPcd, p_CcNodeParam, p_CcNode, ++ &isKeyTblAlloc); ++ glblMask = FALSE; ++ } ++ else ++ if ((p_CcNodeParam->extractCcParams.type == e_FM_PCD_EXTRACT_NON_HDR) ++ && ((p_CcNodeParam->extractCcParams.extractNonHdr.src ++ == e_FM_PCD_EXTRACT_FROM_KEY) ++ || (p_CcNodeParam->extractCcParams.extractNonHdr.src ++ == e_FM_PCD_EXTRACT_FROM_HASH) ++ || (p_CcNodeParam->extractCcParams.extractNonHdr.src ++ == e_FM_PCD_EXTRACT_FROM_FLOW_ID))) ++ { ++ if ((p_CcNodeParam->extractCcParams.extractNonHdr.src ++ == e_FM_PCD_EXTRACT_FROM_FLOW_ID) ++ && (p_CcNodeParam->extractCcParams.extractNonHdr.offset != 0)) ++ { ++ DeleteNode(p_CcNode); ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("In the case of the extraction from e_FM_PCD_EXTRACT_FROM_FLOW_ID offset has to be 0")); ++ } ++ ++ icCode = IcDefineCode(p_CcNodeParam); ++ fromIc = TRUE; ++ if (icCode == CC_PRIVATE_INFO_NONE) ++ { ++ DeleteNode(p_CcNode); ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("user asked extraction from IC and field in internal context or action wasn't initialized in the right way")); ++ } ++ ++ if ((icCode == CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP) ++ || (icCode == CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP)) ++ { ++ err = IcHashIndexedCheckParams(h_FmPcd, p_CcNodeParam, p_CcNode, ++ &isKeyTblAlloc); ++ glblMask = TRUE; ++ } ++ else ++ { ++ err = CheckParams(h_FmPcd, p_CcNodeParam, p_CcNode, ++ &isKeyTblAlloc); ++ if (p_CcNode->glblMaskSize) ++ glblMask = TRUE; ++ } ++ } ++ else ++ { ++ err = CheckParams(h_FmPcd, p_CcNodeParam, p_CcNode, &isKeyTblAlloc); ++ if (p_CcNode->glblMaskSize) ++ glblMask = TRUE; ++ } ++ ++ if (err) ++ { ++ DeleteNode(p_CcNode); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ switch (p_CcNodeParam->extractCcParams.type) ++ { ++ case (e_FM_PCD_EXTRACT_BY_HDR): ++ switch (p_CcNodeParam->extractCcParams.extractByHdr.type) ++ { ++ case (e_FM_PCD_EXTRACT_FULL_FIELD): ++ p_CcNode->parseCode = ++ GetFullFieldParseCode( ++ p_CcNodeParam->extractCcParams.extractByHdr.hdr, ++ p_CcNodeParam->extractCcParams.extractByHdr.hdrIndex, ++ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField); ++ GetSizeHeaderField( ++ p_CcNodeParam->extractCcParams.extractByHdr.hdr, ++ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField, ++ &p_CcNode->sizeOfExtraction); ++ fullField = TRUE; ++ if ((p_CcNode->parseCode != CC_PC_FF_TCI1) ++ && (p_CcNode->parseCode != CC_PC_FF_TCI2) ++ && (p_CcNode->parseCode != CC_PC_FF_MPLS1) ++ && (p_CcNode->parseCode != CC_PC_FF_MPLS_LAST) ++ && (p_CcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC1) ++ && (p_CcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC2) ++ && (p_CcNode->parseCode ++ != CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1) ++ && (p_CcNode->parseCode != CC_PC_FF_IPDSCP) ++ && (p_CcNode->parseCode ++ != CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2) ++ && glblMask) ++ { ++ glblMask = FALSE; ++ p_CcNode->glblMaskSize = 4; ++ p_CcNode->lclMask = TRUE; ++ } ++ break; ++ ++ case (e_FM_PCD_EXTRACT_FROM_HDR): ++ p_CcNode->sizeOfExtraction = ++ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromHdr.size; ++ p_CcNode->offset = ++ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromHdr.offset; ++ p_CcNode->userOffset = ++ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromHdr.offset; ++ p_CcNode->parseCode = ++ GetPrParseCode( ++ p_CcNodeParam->extractCcParams.extractByHdr.hdr, ++ p_CcNodeParam->extractCcParams.extractByHdr.hdrIndex, ++ p_CcNode->offset, glblMask, ++ &p_CcNode->prsArrayOffset); ++ break; ++ ++ case (e_FM_PCD_EXTRACT_FROM_FIELD): ++ p_CcNode->offset = ++ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.offset; ++ p_CcNode->userOffset = ++ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.offset; ++ p_CcNode->sizeOfExtraction = ++ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.size; ++ p_CcNode->parseCode = ++ GetFieldParseCode( ++ p_CcNodeParam->extractCcParams.extractByHdr.hdr, ++ p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.field, ++ p_CcNode->offset, ++ &p_CcNode->prsArrayOffset, ++ p_CcNodeParam->extractCcParams.extractByHdr.hdrIndex); ++ break; ++ ++ default: ++ DeleteNode(p_CcNode); ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ break; ++ ++ case (e_FM_PCD_EXTRACT_NON_HDR): ++ /* get the field code for the generic extract */ ++ p_CcNode->sizeOfExtraction = ++ p_CcNodeParam->extractCcParams.extractNonHdr.size; ++ p_CcNode->offset = ++ p_CcNodeParam->extractCcParams.extractNonHdr.offset; ++ p_CcNode->userOffset = ++ p_CcNodeParam->extractCcParams.extractNonHdr.offset; ++ p_CcNode->parseCode = GetGenParseCode( ++ p_CcNodeParam->extractCcParams.extractNonHdr.src, ++ p_CcNode->offset, glblMask, &p_CcNode->prsArrayOffset, ++ fromIc, icCode); ++ ++ if (p_CcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED) ++ { ++ if ((p_CcNode->offset + p_CcNode->sizeOfExtraction) > 8) ++ { ++ DeleteNode(p_CcNode); ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_SELECTION, ++ ("when node of the type CC_PC_GENERIC_IC_HASH_INDEXED offset + size can not be bigger then size of HASH 64 bits (8 bytes)")); ++ } ++ } ++ if ((p_CcNode->parseCode == CC_PC_GENERIC_IC_GMASK) ++ || (p_CcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED)) ++ { ++ p_CcNode->offset += p_CcNode->prsArrayOffset; ++ p_CcNode->prsArrayOffset = 0; ++ } ++ break; ++ ++ default: ++ DeleteNode(p_CcNode); ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ ++ if (p_CcNode->parseCode == CC_PC_ILLEGAL) ++ { ++ DeleteNode(p_CcNode); ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("illegal extraction type")); ++ } ++ ++ if ((p_CcNode->sizeOfExtraction > FM_PCD_MAX_SIZE_OF_KEY) ++ || !p_CcNode->sizeOfExtraction) ++ { ++ DeleteNode(p_CcNode); ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("sizeOfExatrction can not be greater than 56 and not 0")); ++ } ++ ++ if (p_CcNodeParam->keysParams.keySize != p_CcNode->sizeOfExtraction) ++ { ++ DeleteNode(p_CcNode); ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("keySize has to be equal to sizeOfExtraction")); ++ } ++ ++ p_CcNode->userSizeOfExtraction = p_CcNode->sizeOfExtraction; ++ ++ if (!glblMask) ++ memset(p_CcNode->p_GlblMask, 0xff, CC_GLBL_MASK_SIZE * sizeof(uint8_t)); ++ ++ err = CheckAndSetManipParamsWithCcNodeParams(p_CcNode); ++ if (err != E_OK) ++ { ++ DeleteNode(p_CcNode); ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("keySize has to be equal to sizeOfExtraction")); ++ } ++ ++ /* Calculating matching table entry size by rounding up the user-defined size of extraction to valid entry size */ ++ GetCcExtractKeySize(p_CcNode->sizeOfExtraction, ++ &p_CcNode->ccKeySizeAccExtraction); ++ ++ /* If local mask is used, it is stored next to each key in the keys match table */ ++ if (p_CcNode->lclMask) ++ keySize = (uint32_t)(2 * p_CcNode->ccKeySizeAccExtraction); ++ else ++ keySize = p_CcNode->ccKeySizeAccExtraction; ++ ++ /* Update CC shadow with maximal size required by this node */ ++ if (p_CcNode->maxNumOfKeys) ++ { ++ err = CalcAndUpdateCcShadow(p_CcNode, isKeyTblAlloc, &matchTableSize, ++ &adTableSize); ++ if (err != E_OK) ++ { ++ DeleteNode(p_CcNode); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ p_CcNode->keysMatchTableMaxSize = matchTableSize; ++ ++ if (p_CcNode->statisticsMode != e_FM_PCD_CC_STATS_MODE_NONE) ++ { ++ err = AllocStatsObjs(p_CcNode); ++ if (err != E_OK) ++ { ++ DeleteNode(p_CcNode); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ } ++ ++ /* If manipulation will be initialized before this node, it will use the table ++ descriptor in the AD table of previous node and this node will need an extra ++ AD as his table descriptor. */ ++ p_CcNode->h_TmpAd = (t_Handle)FM_MURAM_AllocMem( ++ h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE, FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!p_CcNode->h_TmpAd) ++ { ++ DeleteNode(p_CcNode); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("MURAM allocation for CC action descriptor")); ++ } ++ } ++ else ++ { ++ matchTableSize = (uint32_t)(keySize * sizeof(uint8_t) ++ * (p_CcNode->numOfKeys + 1)); ++ adTableSize = (uint32_t)(FM_PCD_CC_AD_ENTRY_SIZE ++ * (p_CcNode->numOfKeys + 1)); ++ } ++ ++#if (DPAA_VERSION >= 11) ++ switch (p_CcNode->statisticsMode) ++ { ++ ++ case e_FM_PCD_CC_STATS_MODE_RMON: ++ /* If RMON statistics or RMON conditional statistics modes are requested, ++ allocate frame length ranges array */ ++ p_CcNode->h_StatsFLRs = FM_MURAM_AllocMem( ++ h_FmMuram, ++ (uint32_t)(p_CcNode->numOfStatsFLRs) ++ * FM_PCD_CC_STATS_FLR_SIZE, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ ++ if (!p_CcNode->h_StatsFLRs) ++ { ++ DeleteNode(p_CcNode); ++ RETURN_ERROR( ++ MAJOR, E_NO_MEMORY, ++ ("MURAM allocation for CC frame length ranges array")); ++ } ++ ++ /* Initialize using value received from the user */ ++ for (tmp = 0; tmp < p_CcNode->numOfStatsFLRs; tmp++) ++ { ++ uint16_t flr = ++ cpu_to_be16(p_CcNodeParam->keysParams.frameLengthRanges[tmp]); ++ ++ h_StatsFLRs = ++ PTR_MOVE(p_CcNode->h_StatsFLRs, tmp * FM_PCD_CC_STATS_FLR_SIZE); ++ ++ MemCpy8(h_StatsFLRs, ++ &flr, ++ FM_PCD_CC_STATS_FLR_SIZE); ++ } ++ break; ++ ++ default: ++ break; ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ /* Allocate keys match table. Not required for some CC nodes, for example for IPv4 TTL ++ identification, IPv6 hop count identification, etc. */ ++ if (isKeyTblAlloc) ++ { ++ p_CcNode->h_KeysMatchTable = (t_Handle)FM_MURAM_AllocMem( ++ h_FmMuram, matchTableSize, FM_PCD_CC_KEYS_MATCH_TABLE_ALIGN); ++ if (!p_CcNode->h_KeysMatchTable) ++ { ++ DeleteNode(p_CcNode); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("MURAM allocation for CC node key match table")); ++ } ++ MemSet8((uint8_t *)p_CcNode->h_KeysMatchTable, 0, matchTableSize); ++ } ++ ++ /* Allocate action descriptors table */ ++ p_CcNode->h_AdTable = (t_Handle)FM_MURAM_AllocMem(h_FmMuram, adTableSize, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!p_CcNode->h_AdTable) ++ { ++ DeleteNode(p_CcNode); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("MURAM allocation for CC node action descriptors table")); ++ } ++ MemSet8((uint8_t *)p_CcNode->h_AdTable, 0, adTableSize); ++ ++ p_KeysMatchTblTmp = p_CcNode->h_KeysMatchTable; ++ p_AdTableTmp = p_CcNode->h_AdTable; ++ ++ /* For each key, create the key and the next step AD */ ++ for (tmp = 0; tmp < p_CcNode->numOfKeys; tmp++) ++ { ++ p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp]; ++ ++ if (p_KeysMatchTblTmp) ++ { ++ /* Copy the key */ ++ MemCpy8((void*)p_KeysMatchTblTmp, p_KeyParams->p_Key, ++ p_CcNode->sizeOfExtraction); ++ ++ /* Copy the key mask or initialize it to 0xFF..F */ ++ if (p_CcNode->lclMask && p_KeyParams->p_Mask) ++ { ++ MemCpy8(PTR_MOVE(p_KeysMatchTblTmp, ++ p_CcNode->ccKeySizeAccExtraction), /* User's size of extraction rounded up to a valid matching table entry size */ ++ p_KeyParams->p_Mask, p_CcNode->sizeOfExtraction); /* Exact size of extraction as received from the user */ ++ } ++ else ++ if (p_CcNode->lclMask) ++ { ++ MemSet8(PTR_MOVE(p_KeysMatchTblTmp, ++ p_CcNode->ccKeySizeAccExtraction), /* User's size of extraction rounded up to a valid matching table entry size */ ++ 0xff, p_CcNode->sizeOfExtraction); /* Exact size of extraction as received from the user */ ++ } ++ ++ p_KeysMatchTblTmp = ++ PTR_MOVE(p_KeysMatchTblTmp, keySize * sizeof(uint8_t)); ++ } ++ ++ /* Create the next action descriptor in the match table */ ++ if (p_KeyParams->ccNextEngineParams.statisticsEn) ++ { ++ p_StatsObj = GetStatsObj(p_CcNode); ++ ASSERT_COND(p_StatsObj); ++ ++ statsParams.h_StatsAd = p_StatsObj->h_StatsAd; ++ statsParams.h_StatsCounters = p_StatsObj->h_StatsCounters; ++#if (DPAA_VERSION >= 11) ++ statsParams.h_StatsFLRs = p_CcNode->h_StatsFLRs; ++ ++#endif /* (DPAA_VERSION >= 11) */ ++ NextStepAd(p_AdTableTmp, &statsParams, ++ &p_KeyParams->ccNextEngineParams, p_FmPcd); ++ ++ p_CcNode->keyAndNextEngineParams[tmp].p_StatsObj = p_StatsObj; ++ } ++ else ++ { ++ NextStepAd(p_AdTableTmp, NULL, &p_KeyParams->ccNextEngineParams, ++ p_FmPcd); ++ ++ p_CcNode->keyAndNextEngineParams[tmp].p_StatsObj = NULL; ++ } ++ ++ p_AdTableTmp = PTR_MOVE(p_AdTableTmp, FM_PCD_CC_AD_ENTRY_SIZE); ++ } ++ ++ /* Update next engine for the 'miss' entry */ ++ if (p_CcNodeParam->keysParams.ccNextEngineParamsForMiss.statisticsEn) ++ { ++ p_StatsObj = GetStatsObj(p_CcNode); ++ ASSERT_COND(p_StatsObj); ++ ++ /* All 'bucket' nodes of a hash table should share the same statistics counters, ++ allocated by the hash table. So, if this node is a bucket of a hash table, ++ we'll replace the locally allocated counters with the shared counters. */ ++ if (p_CcNode->isHashBucket) ++ { ++ ASSERT_COND(p_CcNode->h_MissStatsCounters); ++ ++ /* Store original counters pointer and replace it with mutual preallocated pointer */ ++ p_CcNode->h_PrivMissStatsCounters = p_StatsObj->h_StatsCounters; ++ p_StatsObj->h_StatsCounters = p_CcNode->h_MissStatsCounters; ++ } ++ ++ statsParams.h_StatsAd = p_StatsObj->h_StatsAd; ++ statsParams.h_StatsCounters = p_StatsObj->h_StatsCounters; ++#if (DPAA_VERSION >= 11) ++ statsParams.h_StatsFLRs = p_CcNode->h_StatsFLRs; ++ ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ NextStepAd(p_AdTableTmp, &statsParams, ++ &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, ++ p_FmPcd); ++ ++ p_CcNode->keyAndNextEngineParams[tmp].p_StatsObj = p_StatsObj; ++ } ++ else ++ { ++ NextStepAd(p_AdTableTmp, NULL, ++ &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, ++ p_FmPcd); ++ ++ p_CcNode->keyAndNextEngineParams[tmp].p_StatsObj = NULL; ++ } ++ ++ /* This parameter will be used to initialize the "key length" field in the action descriptor ++ that points to this node and it should be 0 for full field extraction */ ++ if (fullField == TRUE) ++ p_CcNode->sizeOfExtraction = 0; ++ ++ for (tmp = 0; tmp < MIN(p_CcNode->numOfKeys + 1, CC_MAX_NUM_OF_KEYS); tmp++) ++ { ++ if (p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ { ++ p_FmPcdCcNextNode = ++ (t_FmPcdCcNode*)p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.params.ccParams.h_CcNode; ++ p_CcInformation = FindNodeInfoInReleventLst( ++ &p_FmPcdCcNextNode->ccPrevNodesLst, (t_Handle)p_CcNode, ++ p_FmPcdCcNextNode->h_Spinlock); ++ if (!p_CcInformation) ++ { ++ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); ++ ccNodeInfo.h_CcNode = (t_Handle)p_CcNode; ++ ccNodeInfo.index = 1; ++ EnqueueNodeInfoToRelevantLst(&p_FmPcdCcNextNode->ccPrevNodesLst, ++ &ccNodeInfo, ++ p_FmPcdCcNextNode->h_Spinlock); ++ } ++ else ++ p_CcInformation->index++; ++ ++ if (p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip) ++ { ++ h_Manip = ++ p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip; ++ p_CcInformation = FindNodeInfoInReleventLst( ++ FmPcdManipGetNodeLstPointedOnThisManip(h_Manip), ++ (t_Handle)p_CcNode, FmPcdManipGetSpinlock(h_Manip)); ++ if (!p_CcInformation) ++ { ++ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); ++ ccNodeInfo.h_CcNode = (t_Handle)p_CcNode; ++ ccNodeInfo.index = 1; ++ EnqueueNodeInfoToRelevantLst( ++ FmPcdManipGetNodeLstPointedOnThisManip(h_Manip), ++ &ccNodeInfo, FmPcdManipGetSpinlock(h_Manip)); ++ } ++ else ++ p_CcInformation->index++; ++ } ++ } ++ } ++ ++ p_AdTableTmp = p_CcNode->h_AdTable; ++ ++ if (!FmPcdLockTryLockAll(h_FmPcd)) ++ { ++ FM_PCD_MatchTableDelete((t_Handle)p_CcNode); ++ DBG(TRACE, ("FmPcdLockTryLockAll failed")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ /* Required action for each next engine */ ++ for (tmp = 0; tmp < MIN(p_CcNode->numOfKeys + 1, CC_MAX_NUM_OF_KEYS); tmp++) ++ { ++ if (p_CcNode->keyAndNextEngineParams[tmp].requiredAction) ++ { ++ err = SetRequiredAction( ++ h_FmPcd, ++ p_CcNode->keyAndNextEngineParams[tmp].requiredAction, ++ &p_CcNode->keyAndNextEngineParams[tmp], p_AdTableTmp, 1, ++ NULL); ++ if (err) ++ { ++ FmPcdLockUnlockAll(h_FmPcd); ++ FM_PCD_MatchTableDelete((t_Handle)p_CcNode); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ p_AdTableTmp = PTR_MOVE(p_AdTableTmp, FM_PCD_CC_AD_ENTRY_SIZE); ++ } ++ } ++ ++ FmPcdLockUnlockAll(h_FmPcd); ++ ++ return E_OK; ++} ++/************************** End of static functions **************************/ ++ ++/*****************************************************************************/ ++/* Inter-module API routines */ ++/*****************************************************************************/ ++ ++t_CcNodeInformation* FindNodeInfoInReleventLst(t_List *p_List, t_Handle h_Info, ++ t_Handle h_Spinlock) ++{ ++ t_CcNodeInformation *p_CcInformation; ++ t_List *p_Pos; ++ uint32_t intFlags; ++ ++ intFlags = XX_LockIntrSpinlock(h_Spinlock); ++ ++ for (p_Pos = LIST_FIRST(p_List); p_Pos != (p_List); ++ p_Pos = LIST_NEXT(p_Pos)) ++ { ++ p_CcInformation = CC_NODE_F_OBJECT(p_Pos); ++ ++ ASSERT_COND(p_CcInformation->h_CcNode); ++ ++ if (p_CcInformation->h_CcNode == h_Info) ++ { ++ XX_UnlockIntrSpinlock(h_Spinlock, intFlags); ++ return p_CcInformation; ++ } ++ } ++ ++ XX_UnlockIntrSpinlock(h_Spinlock, intFlags); ++ ++ return NULL; ++} ++ ++void EnqueueNodeInfoToRelevantLst(t_List *p_List, t_CcNodeInformation *p_CcInfo, ++ t_Handle h_Spinlock) ++{ ++ t_CcNodeInformation *p_CcInformation; ++ uint32_t intFlags = 0; ++ ++ p_CcInformation = (t_CcNodeInformation *)XX_Malloc( ++ sizeof(t_CcNodeInformation)); ++ ++ if (p_CcInformation) ++ { ++ memset(p_CcInformation, 0, sizeof(t_CcNodeInformation)); ++ memcpy(p_CcInformation, p_CcInfo, sizeof(t_CcNodeInformation)); ++ INIT_LIST(&p_CcInformation->node); ++ ++ if (h_Spinlock) ++ intFlags = XX_LockIntrSpinlock(h_Spinlock); ++ ++ LIST_AddToTail(&p_CcInformation->node, p_List); ++ ++ if (h_Spinlock) ++ XX_UnlockIntrSpinlock(h_Spinlock, intFlags); ++ } ++ else ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("CC Node Information")); ++} ++ ++void DequeueNodeInfoFromRelevantLst(t_List *p_List, t_Handle h_Info, ++ t_Handle h_Spinlock) ++{ ++ t_CcNodeInformation *p_CcInformation = NULL; ++ uint32_t intFlags = 0; ++ t_List *p_Pos; ++ ++ if (h_Spinlock) ++ intFlags = XX_LockIntrSpinlock(h_Spinlock); ++ ++ if (LIST_IsEmpty(p_List)) ++ { ++ XX_RestoreAllIntr(intFlags); ++ return; ++ } ++ ++ for (p_Pos = LIST_FIRST(p_List); p_Pos != (p_List); ++ p_Pos = LIST_NEXT(p_Pos)) ++ { ++ p_CcInformation = CC_NODE_F_OBJECT(p_Pos); ++ ASSERT_COND(p_CcInformation); ++ ASSERT_COND(p_CcInformation->h_CcNode); ++ if (p_CcInformation->h_CcNode == h_Info) ++ break; ++ } ++ ++ if (p_CcInformation) ++ { ++ LIST_DelAndInit(&p_CcInformation->node); ++ XX_Free(p_CcInformation); ++ } ++ ++ if (h_Spinlock) ++ XX_UnlockIntrSpinlock(h_Spinlock, intFlags); ++} ++ ++void NextStepAd(t_Handle h_Ad, t_FmPcdCcStatsParams *p_FmPcdCcStatsParams, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams, ++ t_FmPcd *p_FmPcd) ++{ ++ switch (p_FmPcdCcNextEngineParams->nextEngine) ++ { ++ case (e_FM_PCD_KG): ++ case (e_FM_PCD_PLCR): ++ case (e_FM_PCD_DONE): ++ /* if NIA is not CC, create a "result" type AD */ ++ FillAdOfTypeResult(h_Ad, p_FmPcdCcStatsParams, p_FmPcd, ++ p_FmPcdCcNextEngineParams); ++ break; ++#if (DPAA_VERSION >= 11) ++ case (e_FM_PCD_FR): ++ if (p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic) ++ { ++ FillAdOfTypeContLookup( ++ h_Ad, p_FmPcdCcStatsParams, p_FmPcd, ++ p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode, ++ p_FmPcdCcNextEngineParams->h_Manip, ++ p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic); ++ FrmReplicGroupUpdateOwner( ++ p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic, ++ TRUE/* add */); ++ } ++ break; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ case (e_FM_PCD_CC): ++ /* if NIA is not CC, create a TD to continue the CC lookup */ ++ FillAdOfTypeContLookup( ++ h_Ad, p_FmPcdCcStatsParams, p_FmPcd, ++ p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode, ++ p_FmPcdCcNextEngineParams->h_Manip, NULL); ++ ++ UpdateNodeOwner(p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode, ++ TRUE); ++ break; ++ ++ default: ++ return; ++ } ++} ++ ++t_Error FmPcdCcTreeAddIPR(t_Handle h_FmPcd, t_Handle h_FmTree, ++ t_Handle h_NetEnv, t_Handle h_IpReassemblyManip, ++ bool createSchemes) ++{ ++ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree; ++ t_FmPcdCcNextEngineParams nextEngineParams; ++ t_NetEnvParams netEnvParams; ++ t_Handle h_Ad; ++ bool isIpv6Present; ++ uint8_t ipv4GroupId, ipv6GroupId; ++ t_Error err; ++ ++ ASSERT_COND(p_FmPcdCcTree); ++ ++ /* this routine must be protected by the calling routine! */ ++ ++ memset(&nextEngineParams, 0, sizeof(t_FmPcdCcNextEngineParams)); ++ memset(&netEnvParams, 0, sizeof(t_NetEnvParams)); ++ ++ h_Ad = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr); ++ ++ isIpv6Present = FmPcdManipIpReassmIsIpv6Hdr(h_IpReassemblyManip); ++ ++ if (isIpv6Present ++ && (p_FmPcdCcTree->numOfEntries > (FM_PCD_MAX_NUM_OF_CC_GROUPS - 2))) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("need two free entries for IPR")); ++ ++ if (p_FmPcdCcTree->numOfEntries > (FM_PCD_MAX_NUM_OF_CC_GROUPS - 1)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("need two free entries for IPR")); ++ ++ nextEngineParams.nextEngine = e_FM_PCD_DONE; ++ nextEngineParams.h_Manip = h_IpReassemblyManip; ++ ++ /* Lock tree */ ++ err = CcRootTryLock(p_FmPcdCcTree); ++ if (err) ++ return ERROR_CODE(E_BUSY); ++ ++ if (p_FmPcdCcTree->h_IpReassemblyManip == h_IpReassemblyManip) ++ { ++ CcRootReleaseLock(p_FmPcdCcTree); ++ return E_OK; ++ } ++ ++ if ((p_FmPcdCcTree->h_IpReassemblyManip) ++ && (p_FmPcdCcTree->h_IpReassemblyManip != h_IpReassemblyManip)) ++ { ++ CcRootReleaseLock(p_FmPcdCcTree); ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("This tree was previously updated with different IPR")); ++ } ++ ++ /* Initialize IPR for the first time for this tree */ ++ if (isIpv6Present) ++ { ++ ipv6GroupId = p_FmPcdCcTree->numOfGrps++; ++ p_FmPcdCcTree->fmPcdGroupParam[ipv6GroupId].baseGroupEntry = ++ (FM_PCD_MAX_NUM_OF_CC_GROUPS - 2); ++ ++ if (createSchemes) ++ { ++ err = FmPcdManipBuildIpReassmScheme(h_FmPcd, h_NetEnv, ++ p_FmPcdCcTree, ++ h_IpReassemblyManip, FALSE, ++ ipv6GroupId); ++ if (err) ++ { ++ p_FmPcdCcTree->numOfGrps--; ++ CcRootReleaseLock(p_FmPcdCcTree); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ } ++ ++ NextStepAd( ++ PTR_MOVE(h_Ad, (FM_PCD_MAX_NUM_OF_CC_GROUPS-2) * FM_PCD_CC_AD_ENTRY_SIZE), ++ NULL, &nextEngineParams, h_FmPcd); ++ } ++ ++ ipv4GroupId = p_FmPcdCcTree->numOfGrps++; ++ p_FmPcdCcTree->fmPcdGroupParam[ipv4GroupId].totalBitsMask = 0; ++ p_FmPcdCcTree->fmPcdGroupParam[ipv4GroupId].baseGroupEntry = ++ (FM_PCD_MAX_NUM_OF_CC_GROUPS - 1); ++ ++ if (createSchemes) ++ { ++ err = FmPcdManipBuildIpReassmScheme(h_FmPcd, h_NetEnv, p_FmPcdCcTree, ++ h_IpReassemblyManip, TRUE, ++ ipv4GroupId); ++ if (err) ++ { ++ p_FmPcdCcTree->numOfGrps--; ++ if (isIpv6Present) ++ { ++ p_FmPcdCcTree->numOfGrps--; ++ FmPcdManipDeleteIpReassmSchemes(h_IpReassemblyManip); ++ } ++ CcRootReleaseLock(p_FmPcdCcTree); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ } ++ ++ NextStepAd( ++ PTR_MOVE(h_Ad, (FM_PCD_MAX_NUM_OF_CC_GROUPS-1) * FM_PCD_CC_AD_ENTRY_SIZE), ++ NULL, &nextEngineParams, h_FmPcd); ++ ++ p_FmPcdCcTree->h_IpReassemblyManip = h_IpReassemblyManip; ++ ++ CcRootReleaseLock(p_FmPcdCcTree); ++ ++ return E_OK; ++} ++ ++t_Error FmPcdCcTreeAddCPR(t_Handle h_FmPcd, t_Handle h_FmTree, ++ t_Handle h_NetEnv, t_Handle h_ReassemblyManip, ++ bool createSchemes) ++{ ++ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree; ++ t_FmPcdCcNextEngineParams nextEngineParams; ++ t_NetEnvParams netEnvParams; ++ t_Handle h_Ad; ++ uint8_t groupId; ++ t_Error err; ++ ++ ASSERT_COND(p_FmPcdCcTree); ++ ++ /* this routine must be protected by the calling routine! */ ++ memset(&nextEngineParams, 0, sizeof(t_FmPcdCcNextEngineParams)); ++ memset(&netEnvParams, 0, sizeof(t_NetEnvParams)); ++ ++ h_Ad = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr); ++ ++ if (p_FmPcdCcTree->numOfEntries > (FM_PCD_MAX_NUM_OF_CC_GROUPS - 1)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("need one free entries for CPR")); ++ ++ nextEngineParams.nextEngine = e_FM_PCD_DONE; ++ nextEngineParams.h_Manip = h_ReassemblyManip; ++ ++ /* Lock tree */ ++ err = CcRootTryLock(p_FmPcdCcTree); ++ if (err) ++ return ERROR_CODE(E_BUSY); ++ ++ if (p_FmPcdCcTree->h_CapwapReassemblyManip == h_ReassemblyManip) ++ { ++ CcRootReleaseLock(p_FmPcdCcTree); ++ return E_OK; ++ } ++ ++ if ((p_FmPcdCcTree->h_CapwapReassemblyManip) ++ && (p_FmPcdCcTree->h_CapwapReassemblyManip != h_ReassemblyManip)) ++ { ++ CcRootReleaseLock(p_FmPcdCcTree); ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("This tree was previously updated with different CPR")); ++ } ++ ++ groupId = p_FmPcdCcTree->numOfGrps++; ++ p_FmPcdCcTree->fmPcdGroupParam[groupId].baseGroupEntry = ++ (FM_PCD_MAX_NUM_OF_CC_GROUPS - 1); ++ ++ if (createSchemes) ++ { ++ err = FmPcdManipBuildCapwapReassmScheme(h_FmPcd, h_NetEnv, ++ p_FmPcdCcTree, ++ h_ReassemblyManip, groupId); ++ if (err) ++ { ++ p_FmPcdCcTree->numOfGrps--; ++ CcRootReleaseLock(p_FmPcdCcTree); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ } ++ ++ NextStepAd( ++ PTR_MOVE(h_Ad, (FM_PCD_MAX_NUM_OF_CC_GROUPS-1) * FM_PCD_CC_AD_ENTRY_SIZE), ++ NULL, &nextEngineParams, h_FmPcd); ++ ++ p_FmPcdCcTree->h_CapwapReassemblyManip = h_ReassemblyManip; ++ ++ CcRootReleaseLock(p_FmPcdCcTree); ++ ++ return E_OK; ++} ++ ++t_Handle FmPcdCcTreeGetSavedManipParams(t_Handle h_FmTree) ++{ ++ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree; ++ ++ ASSERT_COND(p_FmPcdCcTree); ++ ++ return p_FmPcdCcTree->h_FmPcdCcSavedManipParams; ++} ++ ++void FmPcdCcTreeSetSavedManipParams(t_Handle h_FmTree, ++ t_Handle h_SavedManipParams) ++{ ++ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree; ++ ++ ASSERT_COND(p_FmPcdCcTree); ++ ++ p_FmPcdCcTree->h_FmPcdCcSavedManipParams = h_SavedManipParams; ++} ++ ++uint8_t FmPcdCcGetParseCode(t_Handle h_CcNode) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ ++ ASSERT_COND(p_CcNode); ++ ++ return p_CcNode->parseCode; ++} ++ ++uint8_t FmPcdCcGetOffset(t_Handle h_CcNode) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ ++ ASSERT_COND(p_CcNode); ++ ++ return p_CcNode->offset; ++} ++ ++uint16_t FmPcdCcGetNumOfKeys(t_Handle h_CcNode) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ ++ ASSERT_COND(p_CcNode); ++ ++ return p_CcNode->numOfKeys; ++} ++ ++t_Error FmPcdCcModifyNextEngineParamTree( ++ t_Handle h_FmPcd, t_Handle h_FmPcdCcTree, uint8_t grpId, uint8_t index, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) ++{ ++ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree; ++ t_FmPcd *p_FmPcd; ++ t_List h_OldPointersLst, h_NewPointersLst; ++ uint16_t keyIndex; ++ t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((grpId <= 7), E_INVALID_VALUE); ++ ++ if (grpId >= p_FmPcdCcTree->numOfGrps) ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ++ ("grpId you asked > numOfGroup of relevant tree")); ++ ++ if (index >= p_FmPcdCcTree->fmPcdGroupParam[grpId].numOfEntriesInGroup) ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("index > numOfEntriesInGroup")); ++ ++ p_FmPcd = (t_FmPcd *)h_FmPcd; ++ ++ INIT_LIST(&h_OldPointersLst); ++ INIT_LIST(&h_NewPointersLst); ++ ++ keyIndex = (uint16_t)(p_FmPcdCcTree->fmPcdGroupParam[grpId].baseGroupEntry ++ + index); ++ ++ p_ModifyKeyParams = ModifyNodeCommonPart(p_FmPcdCcTree, keyIndex, ++ e_MODIFY_STATE_CHANGE, FALSE, ++ FALSE, TRUE); ++ if (!p_ModifyKeyParams) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ ++ p_ModifyKeyParams->tree = TRUE; ++ ++ if (p_FmPcd->p_CcShadow ++ && !TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) ++ { ++ XX_Free(p_ModifyKeyParams); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = BuildNewNodeModifyNextEngine(p_FmPcd, p_FmPcdCcTree, keyIndex, ++ p_FmPcdCcNextEngineParams, ++ &h_OldPointersLst, &h_NewPointersLst, ++ p_ModifyKeyParams); ++ if (err) ++ { ++ XX_Free(p_ModifyKeyParams); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst, ++ p_ModifyKeyParams, FALSE); ++ ++ if (p_FmPcd->p_CcShadow) ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ ++ ReleaseLst(&h_OldPointersLst); ++ ReleaseLst(&h_NewPointersLst); ++ ++ return err; ++ ++} ++ ++t_Error FmPcdCcRemoveKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, ++ uint16_t keyIndex) ++{ ++ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; ++ t_FmPcd *p_FmPcd; ++ t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; ++ t_List h_OldPointersLst, h_NewPointersLst; ++ bool useShadowStructs = FALSE; ++ t_Error err = E_OK; ++ ++ if (keyIndex >= p_CcNode->numOfKeys) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("impossible to remove key when numOfKeys <= keyIndex")); ++ ++ if (p_CcNode->h_FmPcd != h_FmPcd) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("handler to FmPcd is different from the handle provided at node initialization time")); ++ ++ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ ++ INIT_LIST(&h_OldPointersLst); ++ INIT_LIST(&h_NewPointersLst); ++ ++ p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex, ++ e_MODIFY_STATE_REMOVE, TRUE, TRUE, ++ FALSE); ++ if (!p_ModifyKeyParams) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ ++ if (p_CcNode->maxNumOfKeys) ++ { ++ if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) ++ { ++ XX_Free(p_ModifyKeyParams); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ useShadowStructs = TRUE; ++ } ++ ++ err = BuildNewNodeRemoveKey(p_CcNode, keyIndex, p_ModifyKeyParams); ++ if (err) ++ { ++ XX_Free(p_ModifyKeyParams); ++ if (p_CcNode->maxNumOfKeys) ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ err = UpdatePtrWhichPointOnCrntMdfNode(p_CcNode, p_ModifyKeyParams, ++ &h_OldPointersLst, ++ &h_NewPointersLst); ++ if (err) ++ { ++ ReleaseNewNodeCommonPart(p_ModifyKeyParams); ++ XX_Free(p_ModifyKeyParams); ++ if (p_CcNode->maxNumOfKeys) ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst, ++ p_ModifyKeyParams, useShadowStructs); ++ ++ if (p_CcNode->maxNumOfKeys) ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ ++ ReleaseLst(&h_OldPointersLst); ++ ReleaseLst(&h_NewPointersLst); ++ ++ return err; ++} ++ ++t_Error FmPcdCcModifyKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, ++ uint16_t keyIndex, uint8_t keySize, uint8_t *p_Key, ++ uint8_t *p_Mask) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; ++ t_FmPcd *p_FmPcd; ++ t_List h_OldPointersLst, h_NewPointersLst; ++ t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; ++ uint16_t tmpKeyIndex; ++ bool useShadowStructs = FALSE; ++ t_Error err = E_OK; ++ ++ if (keyIndex >= p_CcNode->numOfKeys) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("keyIndex > previously cleared last index + 1")); ++ ++ if (keySize != p_CcNode->userSizeOfExtraction) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("size for ModifyKey has to be the same as defined in SetNode")); ++ ++ if (p_CcNode->h_FmPcd != h_FmPcd) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("handler to FmPcd is different from the handle provided at node initialization time")); ++ ++ err = FindKeyIndex(h_FmPcdCcNode, keySize, p_Key, p_Mask, &tmpKeyIndex); ++ if (GET_ERROR_TYPE(err) != E_NOT_FOUND) ++ RETURN_ERROR( ++ MINOR, ++ E_ALREADY_EXISTS, ++ ("The received key and mask pair was already found in the match table of the provided node")); ++ ++ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ ++ INIT_LIST(&h_OldPointersLst); ++ INIT_LIST(&h_NewPointersLst); ++ ++ p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex, ++ e_MODIFY_STATE_CHANGE, TRUE, TRUE, ++ FALSE); ++ if (!p_ModifyKeyParams) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ ++ if (p_CcNode->maxNumOfKeys) ++ { ++ if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) ++ { ++ XX_Free(p_ModifyKeyParams); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ useShadowStructs = TRUE; ++ } ++ ++ err = BuildNewNodeModifyKey(p_CcNode, keyIndex, p_Key, p_Mask, ++ p_ModifyKeyParams); ++ if (err) ++ { ++ XX_Free(p_ModifyKeyParams); ++ if (p_CcNode->maxNumOfKeys) ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ err = UpdatePtrWhichPointOnCrntMdfNode(p_CcNode, p_ModifyKeyParams, ++ &h_OldPointersLst, ++ &h_NewPointersLst); ++ if (err) ++ { ++ ReleaseNewNodeCommonPart(p_ModifyKeyParams); ++ XX_Free(p_ModifyKeyParams); ++ if (p_CcNode->maxNumOfKeys) ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst, ++ p_ModifyKeyParams, useShadowStructs); ++ ++ if (p_CcNode->maxNumOfKeys) ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ ++ ReleaseLst(&h_OldPointersLst); ++ ReleaseLst(&h_NewPointersLst); ++ ++ return err; ++} ++ ++t_Error FmPcdCcModifyMissNextEngineParamNode( ++ t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; ++ t_FmPcd *p_FmPcd; ++ t_List h_OldPointersLst, h_NewPointersLst; ++ uint16_t keyIndex; ++ t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_VALUE); ++ ++ keyIndex = p_CcNode->numOfKeys; ++ ++ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ ++ INIT_LIST(&h_OldPointersLst); ++ INIT_LIST(&h_NewPointersLst); ++ ++ p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex, ++ e_MODIFY_STATE_CHANGE, FALSE, TRUE, ++ FALSE); ++ if (!p_ModifyKeyParams) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ ++ if (p_CcNode->maxNumOfKeys ++ && !TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) ++ { ++ XX_Free(p_ModifyKeyParams); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = BuildNewNodeModifyNextEngine(h_FmPcd, p_CcNode, keyIndex, ++ p_FmPcdCcNextEngineParams, ++ &h_OldPointersLst, &h_NewPointersLst, ++ p_ModifyKeyParams); ++ if (err) ++ { ++ XX_Free(p_ModifyKeyParams); ++ if (p_CcNode->maxNumOfKeys) ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst, ++ p_ModifyKeyParams, FALSE); ++ ++ if (p_CcNode->maxNumOfKeys) ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ ++ ReleaseLst(&h_OldPointersLst); ++ ReleaseLst(&h_NewPointersLst); ++ ++ return err; ++} ++ ++t_Error FmPcdCcAddKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, ++ uint16_t keyIndex, uint8_t keySize, ++ t_FmPcdCcKeyParams *p_FmPcdCcKeyParams) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; ++ t_FmPcd *p_FmPcd; ++ t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; ++ t_List h_OldPointersLst, h_NewPointersLst; ++ bool useShadowStructs = FALSE; ++ uint16_t tmpKeyIndex; ++ t_Error err = E_OK; ++ ++ if (keyIndex > p_CcNode->numOfKeys) ++ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ++ ("keyIndex > previously cleared last index + 1")); ++ ++ if (keySize != p_CcNode->userSizeOfExtraction) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("keySize has to be defined as it was defined in initialization step")); ++ ++ if (p_CcNode->h_FmPcd != h_FmPcd) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("handler to FmPcd is different from the handle provided at node initialization time")); ++ ++ if (p_CcNode->maxNumOfKeys) ++ { ++ if (p_CcNode->numOfKeys == p_CcNode->maxNumOfKeys) ++ RETURN_ERROR( ++ MAJOR, ++ E_FULL, ++ ("number of keys exceeds the maximal number of keys provided at node initialization time")); ++ } ++ else ++ if (p_CcNode->numOfKeys == FM_PCD_MAX_NUM_OF_KEYS) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("number of keys can not be larger than %d", FM_PCD_MAX_NUM_OF_KEYS)); ++ ++ err = FindKeyIndex(h_FmPcdCcNode, keySize, p_FmPcdCcKeyParams->p_Key, ++ p_FmPcdCcKeyParams->p_Mask, &tmpKeyIndex); ++ if (GET_ERROR_TYPE(err) != E_NOT_FOUND) ++ RETURN_ERROR( ++ MAJOR, ++ E_ALREADY_EXISTS, ++ ("The received key and mask pair was already found in the match table of the provided node")); ++ ++ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ ++ INIT_LIST(&h_OldPointersLst); ++ INIT_LIST(&h_NewPointersLst); ++ ++ p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex, ++ e_MODIFY_STATE_ADD, TRUE, TRUE, ++ FALSE); ++ if (!p_ModifyKeyParams) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ ++ if (p_CcNode->maxNumOfKeys) ++ { ++ if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) ++ { ++ XX_Free(p_ModifyKeyParams); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ useShadowStructs = TRUE; ++ } ++ ++ err = BuildNewNodeAddOrMdfyKeyAndNextEngine(h_FmPcd, p_CcNode, keyIndex, ++ p_FmPcdCcKeyParams, ++ p_ModifyKeyParams, TRUE); ++ if (err) ++ { ++ ReleaseNewNodeCommonPart(p_ModifyKeyParams); ++ XX_Free(p_ModifyKeyParams); ++ if (p_CcNode->maxNumOfKeys) ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ err = UpdatePtrWhichPointOnCrntMdfNode(p_CcNode, p_ModifyKeyParams, ++ &h_OldPointersLst, ++ &h_NewPointersLst); ++ if (err) ++ { ++ ReleaseNewNodeCommonPart(p_ModifyKeyParams); ++ XX_Free(p_ModifyKeyParams); ++ if (p_CcNode->maxNumOfKeys) ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst, ++ p_ModifyKeyParams, useShadowStructs); ++ if (p_CcNode->maxNumOfKeys) ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ ++ ReleaseLst(&h_OldPointersLst); ++ ReleaseLst(&h_NewPointersLst); ++ ++ return err; ++} ++ ++t_Error FmPcdCcModifyKeyAndNextEngine(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, ++ uint16_t keyIndex, uint8_t keySize, ++ t_FmPcdCcKeyParams *p_FmPcdCcKeyParams) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; ++ t_FmPcd *p_FmPcd; ++ t_List h_OldPointersLst, h_NewPointersLst; ++ t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; ++ uint16_t tmpKeyIndex; ++ bool useShadowStructs = FALSE; ++ t_Error err = E_OK; ++ ++ if (keyIndex > p_CcNode->numOfKeys) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("keyIndex > previously cleared last index + 1")); ++ ++ if (keySize != p_CcNode->userSizeOfExtraction) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("keySize has to be defined as it was defined in initialization step")); ++ ++ if (p_CcNode->h_FmPcd != h_FmPcd) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("handler to FmPcd is different from the handle provided at node initialization time")); ++ ++ err = FindKeyIndex(h_FmPcdCcNode, keySize, p_FmPcdCcKeyParams->p_Key, ++ p_FmPcdCcKeyParams->p_Mask, &tmpKeyIndex); ++ if (GET_ERROR_TYPE(err) != E_NOT_FOUND) ++ RETURN_ERROR( ++ MINOR, ++ E_ALREADY_EXISTS, ++ ("The received key and mask pair was already found in the match table of the provided node")); ++ ++ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ ++ INIT_LIST(&h_OldPointersLst); ++ INIT_LIST(&h_NewPointersLst); ++ ++ p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex, ++ e_MODIFY_STATE_CHANGE, TRUE, TRUE, ++ FALSE); ++ if (!p_ModifyKeyParams) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ ++ if (p_CcNode->maxNumOfKeys) ++ { ++ if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) ++ { ++ XX_Free(p_ModifyKeyParams); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ useShadowStructs = TRUE; ++ } ++ ++ err = BuildNewNodeAddOrMdfyKeyAndNextEngine(h_FmPcd, p_CcNode, keyIndex, ++ p_FmPcdCcKeyParams, ++ p_ModifyKeyParams, FALSE); ++ if (err) ++ { ++ ReleaseNewNodeCommonPart(p_ModifyKeyParams); ++ XX_Free(p_ModifyKeyParams); ++ if (p_CcNode->maxNumOfKeys) ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ err = UpdatePtrWhichPointOnCrntMdfNode(p_CcNode, p_ModifyKeyParams, ++ &h_OldPointersLst, ++ &h_NewPointersLst); ++ if (err) ++ { ++ ReleaseNewNodeCommonPart(p_ModifyKeyParams); ++ XX_Free(p_ModifyKeyParams); ++ if (p_CcNode->maxNumOfKeys) ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst, ++ p_ModifyKeyParams, useShadowStructs); ++ ++ if (p_CcNode->maxNumOfKeys) ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ ++ ReleaseLst(&h_OldPointersLst); ++ ReleaseLst(&h_NewPointersLst); ++ ++ return err; ++} ++ ++uint32_t FmPcdCcGetNodeAddrOffsetFromNodeInfo(t_Handle h_FmPcd, ++ t_Handle h_Pointer) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ t_CcNodeInformation *p_CcNodeInfo; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, ++ (uint32_t)ILLEGAL_BASE); ++ ++ p_CcNodeInfo = CC_NODE_F_OBJECT(h_Pointer); ++ ++ return (uint32_t)(XX_VirtToPhys(p_CcNodeInfo->h_CcNode) ++ - p_FmPcd->physicalMuramBase); ++} ++ ++t_Error FmPcdCcGetGrpParams(t_Handle h_FmPcdCcTree, uint8_t grpId, ++ uint32_t *p_GrpBits, uint8_t *p_GrpBase) ++{ ++ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree, E_INVALID_HANDLE); ++ ++ if (grpId >= p_FmPcdCcTree->numOfGrps) ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ++ ("grpId you asked > numOfGroup of relevant tree")); ++ ++ *p_GrpBits = p_FmPcdCcTree->fmPcdGroupParam[grpId].totalBitsMask; ++ *p_GrpBase = p_FmPcdCcTree->fmPcdGroupParam[grpId].baseGroupEntry; ++ ++ return E_OK; ++} ++ ++t_Error FmPcdCcBindTree(t_Handle h_FmPcd, t_Handle h_PcdParams, ++ t_Handle h_FmPcdCcTree, uint32_t *p_Offset, ++ t_Handle h_FmPort) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree, E_INVALID_HANDLE); ++ ++ /* this routine must be protected by the calling routine by locking all PCD modules! */ ++ ++ err = CcUpdateParams(h_FmPcd, h_PcdParams, h_FmPort, h_FmPcdCcTree, TRUE); ++ ++ if (err == E_OK) ++ UpdateCcRootOwner(p_FmPcdCcTree, TRUE); ++ ++ *p_Offset = (uint32_t)(XX_VirtToPhys( ++ UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr)) ++ - p_FmPcd->physicalMuramBase); ++ ++ return err; ++} ++ ++t_Error FmPcdCcUnbindTree(t_Handle h_FmPcd, t_Handle h_FmPcdCcTree) ++{ ++ t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree; ++ ++ /* this routine must be protected by the calling routine by locking all PCD modules! */ ++ ++ UNUSED(h_FmPcd); ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree, E_INVALID_HANDLE); ++ ++ UpdateCcRootOwner(p_FmPcdCcTree, FALSE); ++ ++ return E_OK; ++} ++ ++t_Error FmPcdCcNodeTreeTryLock(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, ++ t_List *p_List) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; ++ t_List *p_Pos, *p_Tmp; ++ t_CcNodeInformation *p_CcNodeInfo, nodeInfo; ++ uint32_t intFlags; ++ t_Error err = E_OK; ++ ++ intFlags = FmPcdLock(h_FmPcd); ++ ++ LIST_FOR_EACH(p_Pos, &p_CcNode->ccTreesLst) ++ { ++ p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos); ++ ASSERT_COND(p_CcNodeInfo->h_CcNode); ++ ++ err = CcRootTryLock(p_CcNodeInfo->h_CcNode); ++ ++ if (err) ++ { ++ LIST_FOR_EACH(p_Tmp, &p_CcNode->ccTreesLst) ++ { ++ if (p_Tmp == p_Pos) ++ break; ++ ++ CcRootReleaseLock(p_CcNodeInfo->h_CcNode); ++ } ++ break; ++ } ++ ++ memset(&nodeInfo, 0, sizeof(t_CcNodeInformation)); ++ nodeInfo.h_CcNode = p_CcNodeInfo->h_CcNode; ++ EnqueueNodeInfoToRelevantLst(p_List, &nodeInfo, NULL); ++ } ++ ++ FmPcdUnlock(h_FmPcd, intFlags); ++ CORE_MemoryBarrier(); ++ ++ return err; ++} ++ ++void FmPcdCcNodeTreeReleaseLock(t_Handle h_FmPcd, t_List *p_List) ++{ ++ t_List *p_Pos; ++ t_CcNodeInformation *p_CcNodeInfo; ++ t_Handle h_FmPcdCcTree; ++ uint32_t intFlags; ++ ++ intFlags = FmPcdLock(h_FmPcd); ++ ++ LIST_FOR_EACH(p_Pos, p_List) ++ { ++ p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos); ++ h_FmPcdCcTree = p_CcNodeInfo->h_CcNode; ++ CcRootReleaseLock(h_FmPcdCcTree); ++ } ++ ++ ReleaseLst(p_List); ++ ++ FmPcdUnlock(h_FmPcd, intFlags); ++ CORE_MemoryBarrier(); ++} ++ ++t_Error FmPcdUpdateCcShadow(t_FmPcd *p_FmPcd, uint32_t size, uint32_t align) ++{ ++ uint32_t intFlags; ++ uint32_t newSize = 0, newAlign = 0; ++ bool allocFail = FALSE; ++ ++ ASSERT_COND(p_FmPcd); ++ ++ if (!size) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("size must be larger then 0")); ++ ++ if (!POWER_OF_2(align)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("alignment must be power of 2")); ++ ++ newSize = p_FmPcd->ccShadowSize; ++ newAlign = p_FmPcd->ccShadowAlign; ++ ++ /* Check if current shadow is large enough to hold the requested size */ ++ if (size > p_FmPcd->ccShadowSize) ++ newSize = size; ++ ++ /* Check if current shadow matches the requested alignment */ ++ if (align > p_FmPcd->ccShadowAlign) ++ newAlign = align; ++ ++ /* If a bigger shadow size or bigger shadow alignment are required, ++ a new shadow will be allocated */ ++ if ((newSize != p_FmPcd->ccShadowSize) ++ || (newAlign != p_FmPcd->ccShadowAlign)) ++ { ++ intFlags = FmPcdLock(p_FmPcd); ++ ++ if (p_FmPcd->p_CcShadow) ++ { ++ FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_FmPcd), p_FmPcd->p_CcShadow); ++ p_FmPcd->ccShadowSize = 0; ++ p_FmPcd->ccShadowAlign = 0; ++ } ++ ++ p_FmPcd->p_CcShadow = FM_MURAM_AllocMem(FmPcdGetMuramHandle(p_FmPcd), ++ newSize, newAlign); ++ if (!p_FmPcd->p_CcShadow) ++ { ++ allocFail = TRUE; ++ ++ /* If new shadow size allocation failed, ++ re-allocate with previous parameters */ ++ p_FmPcd->p_CcShadow = FM_MURAM_AllocMem( ++ FmPcdGetMuramHandle(p_FmPcd), p_FmPcd->ccShadowSize, ++ p_FmPcd->ccShadowAlign); ++ } ++ ++ FmPcdUnlock(p_FmPcd, intFlags); ++ ++ if (allocFail) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("MURAM allocation for CC Shadow memory")); ++ ++ p_FmPcd->ccShadowSize = newSize; ++ p_FmPcd->ccShadowAlign = newAlign; ++ } ++ ++ return E_OK; ++} ++ ++#if (DPAA_VERSION >= 11) ++void FmPcdCcGetAdTablesThatPointOnReplicGroup(t_Handle h_Node, ++ t_Handle h_ReplicGroup, ++ t_List *p_AdTables, ++ uint32_t *p_NumOfAdTables) ++{ ++ t_FmPcdCcNode *p_CurrentNode = (t_FmPcdCcNode *)h_Node; ++ int i = 0; ++ void * p_AdTable; ++ t_CcNodeInformation ccNodeInfo; ++ ++ ASSERT_COND(h_Node); ++ *p_NumOfAdTables = 0; ++ ++ /* search in the current node which exact index points on this current replicator group for getting AD */ ++ for (i = 0; i < p_CurrentNode->numOfKeys + 1; i++) ++ { ++ if ((p_CurrentNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine ++ == e_FM_PCD_FR) ++ && ((p_CurrentNode->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic ++ == (t_Handle)h_ReplicGroup))) ++ { ++ /* save the current ad table in the list */ ++ /* this entry uses the input replicator group */ ++ p_AdTable = ++ PTR_MOVE(p_CurrentNode->h_AdTable, i*FM_PCD_CC_AD_ENTRY_SIZE); ++ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); ++ ccNodeInfo.h_CcNode = p_AdTable; ++ EnqueueNodeInfoToRelevantLst(p_AdTables, &ccNodeInfo, NULL); ++ (*p_NumOfAdTables)++; ++ } ++ } ++ ++ ASSERT_COND(i != p_CurrentNode->numOfKeys); ++} ++#endif /* (DPAA_VERSION >= 11) */ ++/*********************** End of inter-module routines ************************/ ++ ++/****************************************/ ++/* API Init unit functions */ ++/****************************************/ ++ ++t_Handle FM_PCD_CcRootBuild(t_Handle h_FmPcd, ++ t_FmPcdCcTreeParams *p_PcdGroupsParam) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ t_Error err = E_OK; ++ int i = 0, j = 0, k = 0; ++ t_FmPcdCcTree *p_FmPcdCcTree; ++ uint8_t numOfEntries; ++ t_Handle p_CcTreeTmp; ++ t_FmPcdCcGrpParams *p_FmPcdCcGroupParams; ++ t_FmPcdCcKeyAndNextEngineParams *p_Params, *p_KeyAndNextEngineParams; ++ t_NetEnvParams netEnvParams; ++ uint8_t lastOne = 0; ++ uint32_t requiredAction = 0; ++ t_FmPcdCcNode *p_FmPcdCcNextNode; ++ t_CcNodeInformation ccNodeInfo, *p_CcInformation; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(p_PcdGroupsParam, E_INVALID_HANDLE, NULL); ++ ++ if (p_PcdGroupsParam->numOfGrps > FM_PCD_MAX_NUM_OF_CC_GROUPS) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("numOfGrps should not exceed %d", FM_PCD_MAX_NUM_OF_CC_GROUPS)); ++ return NULL; ++ } ++ ++ p_FmPcdCcTree = (t_FmPcdCcTree*)XX_Malloc(sizeof(t_FmPcdCcTree)); ++ if (!p_FmPcdCcTree) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("PCD tree structure")); ++ return NULL; ++ } ++ memset(p_FmPcdCcTree, 0, sizeof(t_FmPcdCcTree)); ++ p_FmPcdCcTree->h_FmPcd = h_FmPcd; ++ ++ p_Params = (t_FmPcdCcKeyAndNextEngineParams*)XX_Malloc( ++ FM_PCD_MAX_NUM_OF_CC_GROUPS ++ * sizeof(t_FmPcdCcKeyAndNextEngineParams)); ++ memset(p_Params, ++ 0, ++ FM_PCD_MAX_NUM_OF_CC_GROUPS ++ * sizeof(t_FmPcdCcKeyAndNextEngineParams)); ++ ++ INIT_LIST(&p_FmPcdCcTree->fmPortsLst); ++ ++#ifdef FM_CAPWAP_SUPPORT ++ if ((p_PcdGroupsParam->numOfGrps == 1) && ++ (p_PcdGroupsParam->ccGrpParams[0].numOfDistinctionUnits == 0) && ++ (p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].nextEngine == e_FM_PCD_CC) && ++ p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].params.ccParams.h_CcNode && ++ IsCapwapApplSpecific(p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].params.ccParams.h_CcNode)) ++ { ++ p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].h_Manip = FmPcdManipApplSpecificBuild(); ++ if (!p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].h_Manip) ++ { ++ DeleteTree(p_FmPcdCcTree,p_FmPcd); ++ XX_Free(p_Params); ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ return NULL; ++ } ++ } ++#endif /* FM_CAPWAP_SUPPORT */ ++ ++ numOfEntries = 0; ++ p_FmPcdCcTree->netEnvId = FmPcdGetNetEnvId(p_PcdGroupsParam->h_NetEnv); ++ ++ for (i = 0; i < p_PcdGroupsParam->numOfGrps; i++) ++ { ++ p_FmPcdCcGroupParams = &p_PcdGroupsParam->ccGrpParams[i]; ++ ++ if (p_FmPcdCcGroupParams->numOfDistinctionUnits ++ > FM_PCD_MAX_NUM_OF_CC_UNITS) ++ { ++ DeleteTree(p_FmPcdCcTree, p_FmPcd); ++ XX_Free(p_Params); ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ++ ("numOfDistinctionUnits (group %d) should not exceed %d", i, FM_PCD_MAX_NUM_OF_CC_UNITS)); ++ return NULL; ++ } ++ ++ p_FmPcdCcTree->fmPcdGroupParam[i].baseGroupEntry = numOfEntries; ++ p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup = (uint8_t)(0x01 ++ << p_FmPcdCcGroupParams->numOfDistinctionUnits); ++ numOfEntries += p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup; ++ if (numOfEntries > FM_PCD_MAX_NUM_OF_CC_GROUPS) ++ { ++ DeleteTree(p_FmPcdCcTree, p_FmPcd); ++ XX_Free(p_Params); ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("numOfEntries can not be larger than %d", FM_PCD_MAX_NUM_OF_CC_GROUPS)); ++ return NULL; ++ } ++ ++ if (lastOne) ++ { ++ if (p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup > lastOne) ++ { ++ DeleteTree(p_FmPcdCcTree, p_FmPcd); ++ XX_Free(p_Params); ++ REPORT_ERROR(MAJOR, E_CONFLICT, ("numOfEntries per group must be set in descending order")); ++ return NULL; ++ } ++ } ++ ++ lastOne = p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup; ++ ++ netEnvParams.netEnvId = p_FmPcdCcTree->netEnvId; ++ netEnvParams.numOfDistinctionUnits = ++ p_FmPcdCcGroupParams->numOfDistinctionUnits; ++ ++ memcpy(netEnvParams.unitIds, &p_FmPcdCcGroupParams->unitIds, ++ (sizeof(uint8_t)) * p_FmPcdCcGroupParams->numOfDistinctionUnits); ++ ++ err = PcdGetUnitsVector(p_FmPcd, &netEnvParams); ++ if (err) ++ { ++ DeleteTree(p_FmPcdCcTree, p_FmPcd); ++ XX_Free(p_Params); ++ REPORT_ERROR(MAJOR, err, NO_MSG); ++ return NULL; ++ } ++ ++ p_FmPcdCcTree->fmPcdGroupParam[i].totalBitsMask = netEnvParams.vector; ++ for (j = 0; j < p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup; ++ j++) ++ { ++ err = ValidateNextEngineParams( ++ h_FmPcd, ++ &p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j], ++ e_FM_PCD_CC_STATS_MODE_NONE); ++ if (err) ++ { ++ DeleteTree(p_FmPcdCcTree, p_FmPcd); ++ XX_Free(p_Params); ++ REPORT_ERROR(MAJOR, err, (NO_MSG)); ++ return NULL; ++ } ++ ++ if (p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j].h_Manip) ++ { ++ err = FmPcdManipCheckParamsForCcNextEngine( ++ &p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j], ++ &requiredAction); ++ if (err) ++ { ++ DeleteTree(p_FmPcdCcTree, p_FmPcd); ++ XX_Free(p_Params); ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ return NULL; ++ } ++ } ++ p_KeyAndNextEngineParams = p_Params + k; ++ ++ memcpy(&p_KeyAndNextEngineParams->nextEngineParams, ++ &p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j], ++ sizeof(t_FmPcdCcNextEngineParams)); ++ ++ if ((p_KeyAndNextEngineParams->nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ && p_KeyAndNextEngineParams->nextEngineParams.h_Manip) ++ { ++ err = ++ AllocAndFillAdForContLookupManip( ++ p_KeyAndNextEngineParams->nextEngineParams.params.ccParams.h_CcNode); ++ if (err) ++ { ++ DeleteTree(p_FmPcdCcTree, p_FmPcd); ++ XX_Free(p_Params); ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CC Tree")); ++ return NULL; ++ } ++ } ++ ++ requiredAction |= UPDATE_CC_WITH_TREE; ++ p_KeyAndNextEngineParams->requiredAction = requiredAction; ++ ++ k++; ++ } ++ } ++ ++ p_FmPcdCcTree->numOfEntries = (uint8_t)k; ++ p_FmPcdCcTree->numOfGrps = p_PcdGroupsParam->numOfGrps; ++ ++ p_FmPcdCcTree->ccTreeBaseAddr = ++ PTR_TO_UINT(FM_MURAM_AllocMem(FmPcdGetMuramHandle(h_FmPcd), ++ (uint32_t)( FM_PCD_MAX_NUM_OF_CC_GROUPS * FM_PCD_CC_AD_ENTRY_SIZE), ++ FM_PCD_CC_TREE_ADDR_ALIGN)); ++ if (!p_FmPcdCcTree->ccTreeBaseAddr) ++ { ++ DeleteTree(p_FmPcdCcTree, p_FmPcd); ++ XX_Free(p_Params); ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CC Tree")); ++ return NULL; ++ } ++ MemSet8( ++ UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr), 0, ++ (uint32_t)(FM_PCD_MAX_NUM_OF_CC_GROUPS * FM_PCD_CC_AD_ENTRY_SIZE)); ++ ++ p_CcTreeTmp = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr); ++ ++ for (i = 0; i < numOfEntries; i++) ++ { ++ p_KeyAndNextEngineParams = p_Params + i; ++ ++ NextStepAd(p_CcTreeTmp, NULL, ++ &p_KeyAndNextEngineParams->nextEngineParams, p_FmPcd); ++ ++ p_CcTreeTmp = PTR_MOVE(p_CcTreeTmp, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ memcpy(&p_FmPcdCcTree->keyAndNextEngineParams[i], ++ p_KeyAndNextEngineParams, ++ sizeof(t_FmPcdCcKeyAndNextEngineParams)); ++ ++ if (p_FmPcdCcTree->keyAndNextEngineParams[i].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ { ++ p_FmPcdCcNextNode = ++ (t_FmPcdCcNode*)p_FmPcdCcTree->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode; ++ p_CcInformation = FindNodeInfoInReleventLst( ++ &p_FmPcdCcNextNode->ccTreeIdLst, (t_Handle)p_FmPcdCcTree, ++ p_FmPcdCcNextNode->h_Spinlock); ++ ++ if (!p_CcInformation) ++ { ++ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); ++ ccNodeInfo.h_CcNode = (t_Handle)p_FmPcdCcTree; ++ ccNodeInfo.index = 1; ++ EnqueueNodeInfoToRelevantLst(&p_FmPcdCcNextNode->ccTreeIdLst, ++ &ccNodeInfo, ++ p_FmPcdCcNextNode->h_Spinlock); ++ } ++ else ++ p_CcInformation->index++; ++ } ++ } ++ ++ FmPcdIncNetEnvOwners(h_FmPcd, p_FmPcdCcTree->netEnvId); ++ p_CcTreeTmp = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr); ++ ++ if (!FmPcdLockTryLockAll(p_FmPcd)) ++ { ++ FM_PCD_CcRootDelete(p_FmPcdCcTree); ++ XX_Free(p_Params); ++ DBG(TRACE, ("FmPcdLockTryLockAll failed")); ++ return NULL; ++ } ++ ++ for (i = 0; i < numOfEntries; i++) ++ { ++ if (p_FmPcdCcTree->keyAndNextEngineParams[i].requiredAction) ++ { ++ err = SetRequiredAction( ++ h_FmPcd, ++ p_FmPcdCcTree->keyAndNextEngineParams[i].requiredAction, ++ &p_FmPcdCcTree->keyAndNextEngineParams[i], p_CcTreeTmp, 1, ++ p_FmPcdCcTree); ++ if (err) ++ { ++ FmPcdLockUnlockAll(p_FmPcd); ++ FM_PCD_CcRootDelete(p_FmPcdCcTree); ++ XX_Free(p_Params); ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory")); ++ return NULL; ++ } ++ p_CcTreeTmp = PTR_MOVE(p_CcTreeTmp, FM_PCD_CC_AD_ENTRY_SIZE); ++ } ++ } ++ ++ FmPcdLockUnlockAll(p_FmPcd); ++ p_FmPcdCcTree->p_Lock = FmPcdAcquireLock(p_FmPcd); ++ if (!p_FmPcdCcTree->p_Lock) ++ { ++ FM_PCD_CcRootDelete(p_FmPcdCcTree); ++ XX_Free(p_Params); ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM CC lock")); ++ return NULL; ++ } ++ ++ XX_Free(p_Params); ++ ++ return p_FmPcdCcTree; ++} ++ ++t_Error FM_PCD_CcRootDelete(t_Handle h_CcTree) ++{ ++ t_FmPcd *p_FmPcd; ++ t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *)h_CcTree; ++ int i = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_CcTree, E_INVALID_STATE); ++ p_FmPcd = (t_FmPcd *)p_CcTree->h_FmPcd; ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ ++ FmPcdDecNetEnvOwners(p_FmPcd, p_CcTree->netEnvId); ++ ++ if (p_CcTree->owners) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_SELECTION, ++ ("the tree with this ID can not be removed because this tree is occupied, first - unbind this tree")); ++ ++ /* Delete ip-reassembly schemes if exist */ ++ if (p_CcTree->h_IpReassemblyManip) ++ { ++ FmPcdManipDeleteIpReassmSchemes(p_CcTree->h_IpReassemblyManip); ++ FmPcdManipUpdateOwner(p_CcTree->h_IpReassemblyManip, FALSE); ++ } ++ ++ /* Delete capwap-reassembly schemes if exist */ ++ if (p_CcTree->h_CapwapReassemblyManip) ++ { ++ FmPcdManipDeleteCapwapReassmSchemes(p_CcTree->h_CapwapReassemblyManip); ++ FmPcdManipUpdateOwner(p_CcTree->h_CapwapReassemblyManip, FALSE); ++ } ++ ++ for (i = 0; i < p_CcTree->numOfEntries; i++) ++ { ++ if (p_CcTree->keyAndNextEngineParams[i].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ UpdateNodeOwner( ++ p_CcTree->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode, ++ FALSE); ++ ++ if (p_CcTree->keyAndNextEngineParams[i].nextEngineParams.h_Manip) ++ FmPcdManipUpdateOwner( ++ p_CcTree->keyAndNextEngineParams[i].nextEngineParams.h_Manip, ++ FALSE); ++ ++#ifdef FM_CAPWAP_SUPPORT ++ if ((p_CcTree->numOfGrps == 1) && ++ (p_CcTree->fmPcdGroupParam[0].numOfEntriesInGroup == 1) && ++ (p_CcTree->keyAndNextEngineParams[0].nextEngineParams.nextEngine == e_FM_PCD_CC) && ++ p_CcTree->keyAndNextEngineParams[0].nextEngineParams.params.ccParams.h_CcNode && ++ IsCapwapApplSpecific(p_CcTree->keyAndNextEngineParams[0].nextEngineParams.params.ccParams.h_CcNode)) ++ { ++ if (FM_PCD_ManipNodeDelete(p_CcTree->keyAndNextEngineParams[0].nextEngineParams.h_Manip) != E_OK) ++ return E_INVALID_STATE; ++ } ++#endif /* FM_CAPWAP_SUPPORT */ ++ ++#if (DPAA_VERSION >= 11) ++ if ((p_CcTree->keyAndNextEngineParams[i].nextEngineParams.nextEngine ++ == e_FM_PCD_FR) ++ && (p_CcTree->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic)) ++ FrmReplicGroupUpdateOwner( ++ p_CcTree->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic, ++ FALSE); ++#endif /* (DPAA_VERSION >= 11) */ ++ } ++ ++ if (p_CcTree->p_Lock) ++ FmPcdReleaseLock(p_CcTree->h_FmPcd, p_CcTree->p_Lock); ++ ++ DeleteTree(p_CcTree, p_FmPcd); ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_CcRootModifyNextEngine( ++ t_Handle h_CcTree, uint8_t grpId, uint8_t index, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) ++{ ++ t_FmPcd *p_FmPcd; ++ t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *)h_CcTree; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_CcTree, E_INVALID_STATE); ++ p_FmPcd = (t_FmPcd *)p_CcTree->h_FmPcd; ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ ++ if (!FmPcdLockTryLockAll(p_FmPcd)) ++ { ++ DBG(TRACE, ("FmPcdLockTryLockAll failed")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = FmPcdCcModifyNextEngineParamTree(p_FmPcd, p_CcTree, grpId, index, ++ p_FmPcdCcNextEngineParams); ++ FmPcdLockUnlockAll(p_FmPcd); ++ ++ if (err) ++ { ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ return E_OK; ++} ++ ++t_Handle FM_PCD_MatchTableSet(t_Handle h_FmPcd, ++ t_FmPcdCcNodeParams *p_CcNodeParam) ++{ ++ t_FmPcdCcNode *p_CcNode; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(p_CcNodeParam, E_NULL_POINTER, NULL); ++ ++ p_CcNode = (t_FmPcdCcNode*)XX_Malloc(sizeof(t_FmPcdCcNode)); ++ if (!p_CcNode) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory")); ++ return NULL; ++ } ++ memset(p_CcNode, 0, sizeof(t_FmPcdCcNode)); ++ ++ err = MatchTableSet(h_FmPcd, p_CcNode, p_CcNodeParam); ++ ++ switch(GET_ERROR_TYPE(err) ++) { ++ case E_OK: ++ break; ++ ++ case E_BUSY: ++ DBG(TRACE, ("E_BUSY error")); ++ return NULL; ++ ++ default: ++ REPORT_ERROR(MAJOR, err, NO_MSG); ++ return NULL; ++ } ++ ++ return p_CcNode; ++} ++ ++t_Error FM_PCD_MatchTableDelete(t_Handle h_CcNode) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ int i = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_CcNode->h_FmPcd, E_INVALID_HANDLE); ++ ++ if (p_CcNode->owners) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("This node cannot be removed because it is occupied; first unbind this node")); ++ ++ for (i = 0; i < p_CcNode->numOfKeys; i++) ++ if (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ UpdateNodeOwner( ++ p_CcNode->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode, ++ FALSE); ++ ++ if (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ UpdateNodeOwner( ++ p_CcNode->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode, ++ FALSE); ++ ++ /* Handle also Miss entry */ ++ for (i = 0; i < p_CcNode->numOfKeys + 1; i++) ++ { ++ if (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip) ++ FmPcdManipUpdateOwner( ++ p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip, ++ FALSE); ++ ++#if (DPAA_VERSION >= 11) ++ if ((p_CcNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine ++ == e_FM_PCD_FR) ++ && (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic)) ++ { ++ FrmReplicGroupUpdateOwner( ++ p_CcNode->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic, ++ FALSE); ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ } ++ ++ DeleteNode(p_CcNode); ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_MatchTableAddKey(t_Handle h_CcNode, uint16_t keyIndex, ++ uint8_t keySize, ++ t_FmPcdCcKeyParams *p_KeyParams) ++{ ++ t_FmPcd *p_FmPcd; ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_KeyParams, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); ++ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); ++ ++ if (keyIndex == FM_PCD_LAST_KEY_INDEX) ++ keyIndex = p_CcNode->numOfKeys; ++ ++ if (!FmPcdLockTryLockAll(p_FmPcd)) ++ { ++ DBG(TRACE, ("FmPcdLockTryLockAll failed")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = FmPcdCcAddKey(p_FmPcd, p_CcNode, keyIndex, keySize, p_KeyParams); ++ ++ FmPcdLockUnlockAll(p_FmPcd); ++ ++ switch(GET_ERROR_TYPE(err) ++) { ++ case E_OK: ++ return E_OK; ++ ++ case E_BUSY: ++ DBG(TRACE, ("E_BUSY error")); ++ return ERROR_CODE(E_BUSY); ++ ++ default: ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++} ++ ++t_Error FM_PCD_MatchTableRemoveKey(t_Handle h_CcNode, uint16_t keyIndex) ++{ ++ t_FmPcd *p_FmPcd; ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); ++ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); ++ ++ if (!FmPcdLockTryLockAll(p_FmPcd)) ++ { ++ DBG(TRACE, ("FmPcdLockTryLockAll failed")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = FmPcdCcRemoveKey(p_FmPcd, p_CcNode, keyIndex); ++ ++ FmPcdLockUnlockAll(p_FmPcd); ++ ++ switch(GET_ERROR_TYPE(err) ++) { ++ case E_OK: ++ return E_OK; ++ ++ case E_BUSY: ++ DBG(TRACE, ("E_BUSY error")); ++ return ERROR_CODE(E_BUSY); ++ ++ default: ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_MatchTableModifyKey(t_Handle h_CcNode, uint16_t keyIndex, ++ uint8_t keySize, uint8_t *p_Key, ++ uint8_t *p_Mask) ++{ ++ t_FmPcd *p_FmPcd; ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); ++ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); ++ ++ ++ if (!FmPcdLockTryLockAll(p_FmPcd)) ++ { ++ DBG(TRACE, ("FmPcdLockTryLockAll failed")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = FmPcdCcModifyKey(p_FmPcd, p_CcNode, keyIndex, keySize, p_Key, p_Mask); ++ ++ FmPcdLockUnlockAll(p_FmPcd); ++ ++ switch(GET_ERROR_TYPE(err) ++) { ++ case E_OK: ++ return E_OK; ++ ++ case E_BUSY: ++ DBG(TRACE, ("E_BUSY error")); ++ return ERROR_CODE(E_BUSY); ++ ++ default: ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++} ++ ++t_Error FM_PCD_MatchTableModifyNextEngine( ++ t_Handle h_CcNode, uint16_t keyIndex, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) ++{ ++ t_FmPcd *p_FmPcd; ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); ++ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); ++ ++ if (!FmPcdLockTryLockAll(p_FmPcd)) ++ { ++ DBG(TRACE, ("FmPcdLockTryLockAll failed")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = ModifyNextEngineParamNode(p_FmPcd, p_CcNode, keyIndex, ++ p_FmPcdCcNextEngineParams); ++ ++ FmPcdLockUnlockAll(p_FmPcd); ++ ++ switch(GET_ERROR_TYPE(err) ++) { ++ case E_OK: ++ return E_OK; ++ ++ case E_BUSY: ++ DBG(TRACE, ("E_BUSY error")); ++ return ERROR_CODE(E_BUSY); ++ ++ default: ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++} ++ ++t_Error FM_PCD_MatchTableModifyMissNextEngine( ++ t_Handle h_CcNode, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) ++{ ++ t_FmPcd *p_FmPcd; ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); ++ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); ++ ++ if (!FmPcdLockTryLockAll(p_FmPcd)) ++ { ++ DBG(TRACE, ("FmPcdLockTryLockAll failed")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = FmPcdCcModifyMissNextEngineParamNode(p_FmPcd, p_CcNode, ++ p_FmPcdCcNextEngineParams); ++ ++ FmPcdLockUnlockAll(p_FmPcd); ++ ++ switch(GET_ERROR_TYPE(err) ++) { ++ case E_OK: ++ return E_OK; ++ ++ case E_BUSY: ++ DBG(TRACE, ("E_BUSY error")); ++ return ERROR_CODE(E_BUSY); ++ ++ default: ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++} ++ ++t_Error FM_PCD_MatchTableModifyKeyAndNextEngine(t_Handle h_CcNode, ++ uint16_t keyIndex, ++ uint8_t keySize, ++ t_FmPcdCcKeyParams *p_KeyParams) ++{ ++ t_FmPcd *p_FmPcd; ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_KeyParams, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); ++ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); ++ ++ if (!FmPcdLockTryLockAll(p_FmPcd)) ++ { ++ DBG(TRACE, ("FmPcdLockTryLockAll failed")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = FmPcdCcModifyKeyAndNextEngine(p_FmPcd, p_CcNode, keyIndex, keySize, ++ p_KeyParams); ++ ++ FmPcdLockUnlockAll(p_FmPcd); ++ ++ switch(GET_ERROR_TYPE(err) ++) { ++ case E_OK: ++ return E_OK; ++ ++ case E_BUSY: ++ DBG(TRACE, ("E_BUSY error")); ++ return ERROR_CODE(E_BUSY); ++ ++ default: ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++} ++ ++t_Error FM_PCD_MatchTableFindNRemoveKey(t_Handle h_CcNode, uint8_t keySize, ++ uint8_t *p_Key, uint8_t *p_Mask) ++{ ++ t_FmPcd *p_FmPcd; ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ uint16_t keyIndex; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); ++ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); ++ ++ if (!FmPcdLockTryLockAll(p_FmPcd)) ++ { ++ DBG(TRACE, ("FmPcdLockTryLockAll failed")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex); ++ if (GET_ERROR_TYPE(err) != E_OK) ++ { ++ FmPcdLockUnlockAll(p_FmPcd); ++ RETURN_ERROR( ++ MAJOR, ++ err, ++ ("The received key and mask pair was not found in the match table of the provided node")); ++ } ++ ++ err = FmPcdCcRemoveKey(p_FmPcd, p_CcNode, keyIndex); ++ ++ FmPcdLockUnlockAll(p_FmPcd); ++ ++ switch(GET_ERROR_TYPE(err) ++) { ++ case E_OK: ++ return E_OK; ++ ++ case E_BUSY: ++ DBG(TRACE, ("E_BUSY error")); ++ return ERROR_CODE(E_BUSY); ++ ++ default: ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++} ++ ++t_Error FM_PCD_MatchTableFindNModifyNextEngine( ++ t_Handle h_CcNode, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) ++{ ++ t_FmPcd *p_FmPcd; ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ uint16_t keyIndex; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); ++ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); ++ ++ if (!FmPcdLockTryLockAll(p_FmPcd)) ++ { ++ DBG(TRACE, ("FmPcdLockTryLockAll failed")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex); ++ if (GET_ERROR_TYPE(err) != E_OK) ++ { ++ FmPcdLockUnlockAll(p_FmPcd); ++ RETURN_ERROR( ++ MAJOR, ++ err, ++ ("The received key and mask pair was not found in the match table of the provided node")); ++ } ++ ++ err = ModifyNextEngineParamNode(p_FmPcd, p_CcNode, keyIndex, ++ p_FmPcdCcNextEngineParams); ++ ++ FmPcdLockUnlockAll(p_FmPcd); ++ ++ switch(GET_ERROR_TYPE(err) ++) { ++ case E_OK: ++ return E_OK; ++ ++ case E_BUSY: ++ DBG(TRACE, ("E_BUSY error")); ++ return ERROR_CODE(E_BUSY); ++ ++ default: ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++} ++ ++t_Error FM_PCD_MatchTableFindNModifyKeyAndNextEngine( ++ t_Handle h_CcNode, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask, ++ t_FmPcdCcKeyParams *p_KeyParams) ++{ ++ t_FmPcd *p_FmPcd; ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ uint16_t keyIndex; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_KeyParams, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); ++ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); ++ ++ if (!FmPcdLockTryLockAll(p_FmPcd)) ++ { ++ DBG(TRACE, ("FmPcdLockTryLockAll failed")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex); ++ if (GET_ERROR_TYPE(err) != E_OK) ++ { ++ FmPcdLockUnlockAll(p_FmPcd); ++ RETURN_ERROR( ++ MAJOR, ++ err, ++ ("The received key and mask pair was not found in the match table of the provided node")); ++ } ++ ++ err = FmPcdCcModifyKeyAndNextEngine(p_FmPcd, h_CcNode, keyIndex, keySize, ++ p_KeyParams); ++ ++ FmPcdLockUnlockAll(p_FmPcd); ++ ++ switch(GET_ERROR_TYPE(err) ++) { ++ case E_OK: ++ return E_OK; ++ ++ case E_BUSY: ++ DBG(TRACE, ("E_BUSY error")); ++ return ERROR_CODE(E_BUSY); ++ ++ default: ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++} ++ ++t_Error FM_PCD_MatchTableFindNModifyKey(t_Handle h_CcNode, uint8_t keySize, ++ uint8_t *p_Key, uint8_t *p_Mask, ++ uint8_t *p_NewKey, uint8_t *p_NewMask) ++{ ++ t_FmPcd *p_FmPcd; ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ t_List h_List; ++ uint16_t keyIndex; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_NewKey, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); ++ p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); ++ ++ INIT_LIST(&h_List); ++ ++ err = FmPcdCcNodeTreeTryLock(p_FmPcd, p_CcNode, &h_List); ++ if (err) ++ { ++ DBG(TRACE, ("Node's trees lock failed")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex); ++ if (GET_ERROR_TYPE(err) != E_OK) ++ { ++ FmPcdCcNodeTreeReleaseLock(p_FmPcd, &h_List); ++ RETURN_ERROR(MAJOR, err, ++ ("The received key and mask pair was not found in the " ++ "match table of the provided node")); ++ } ++ ++ err = FmPcdCcModifyKey(p_FmPcd, p_CcNode, keyIndex, keySize, p_NewKey, ++ p_NewMask); ++ ++ FmPcdCcNodeTreeReleaseLock(p_FmPcd, &h_List); ++ ++ switch(GET_ERROR_TYPE(err) ++) { ++ case E_OK: ++ return E_OK; ++ ++ case E_BUSY: ++ DBG(TRACE, ("E_BUSY error")); ++ return ERROR_CODE(E_BUSY); ++ ++ default: ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++} ++ ++t_Error FM_PCD_MatchTableGetNextEngine( ++ t_Handle h_CcNode, uint16_t keyIndex, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ ++ SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER); ++ ++ if (keyIndex >= p_CcNode->numOfKeys) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("keyIndex exceeds current number of keys")); ++ ++ if (keyIndex > (FM_PCD_MAX_NUM_OF_KEYS - 1)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("keyIndex can not be larger than %d", (FM_PCD_MAX_NUM_OF_KEYS - 1))); ++ ++ memcpy(p_FmPcdCcNextEngineParams, ++ &p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams, ++ sizeof(t_FmPcdCcNextEngineParams)); ++ ++ return E_OK; ++} ++ ++ ++uint32_t FM_PCD_MatchTableGetKeyCounter(t_Handle h_CcNode, uint16_t keyIndex) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ uint32_t *p_StatsCounters, frameCount; ++ uint32_t intFlags; ++ ++ SANITY_CHECK_RETURN_VALUE(p_CcNode, E_INVALID_HANDLE, 0); ++ ++ if (p_CcNode->statisticsMode == e_FM_PCD_CC_STATS_MODE_NONE) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Statistics were not enabled for this match table")); ++ return 0; ++ } ++ ++ if ((p_CcNode->statisticsMode != e_FM_PCD_CC_STATS_MODE_FRAME) ++ && (p_CcNode->statisticsMode ++ != e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME)) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Frame count is not supported in the statistics mode of this match table")); ++ return 0; ++ } ++ ++ intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock); ++ ++ if (keyIndex >= p_CcNode->numOfKeys) ++ { ++ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("The provided keyIndex exceeds the number of keys in this match table")); ++ return 0; ++ } ++ ++ if (!p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj) ++ { ++ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Statistics were not enabled for this key")); ++ return 0; ++ } ++ ++ p_StatsCounters = ++ p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsCounters; ++ ASSERT_COND(p_StatsCounters); ++ ++ /* The first counter is byte counter, so we need to advance to the next counter */ ++ frameCount = GET_UINT32(*(uint32_t *)(PTR_MOVE(p_StatsCounters, ++ FM_PCD_CC_STATS_COUNTER_SIZE))); ++ ++ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); ++ ++ return frameCount; ++} ++ ++t_Error FM_PCD_MatchTableGetKeyStatistics( ++ t_Handle h_CcNode, uint16_t keyIndex, ++ t_FmPcdCcKeyStatistics *p_KeyStatistics) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ uint32_t intFlags; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(h_CcNode, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_KeyStatistics, E_NULL_POINTER); ++ ++ intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock); ++ ++ if (keyIndex >= p_CcNode->numOfKeys) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("The provided keyIndex exceeds the number of keys in this match table")); ++ ++ err = MatchTableGetKeyStatistics(p_CcNode, keyIndex, p_KeyStatistics); ++ ++ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); ++ ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_MatchTableGetMissStatistics( ++ t_Handle h_CcNode, t_FmPcdCcKeyStatistics *p_MissStatistics) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ uint32_t intFlags; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(h_CcNode, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_MissStatistics, E_NULL_POINTER); ++ ++ intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock); ++ ++ err = MatchTableGetKeyStatistics(p_CcNode, p_CcNode->numOfKeys, ++ p_MissStatistics); ++ ++ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); ++ ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_MatchTableFindNGetKeyStatistics( ++ t_Handle h_CcNode, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask, ++ t_FmPcdCcKeyStatistics *p_KeyStatistics) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ uint16_t keyIndex; ++ uint32_t intFlags; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_KeyStatistics, E_NULL_POINTER); ++ ++ intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock); ++ ++ err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex); ++ if (GET_ERROR_TYPE(err) != E_OK) ++ { ++ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); ++ RETURN_ERROR(MAJOR, err, ++ ("The received key and mask pair was not found in the " ++ "match table of the provided node")); ++ } ++ ++ ASSERT_COND(keyIndex < p_CcNode->numOfKeys); ++ ++ err = MatchTableGetKeyStatistics(p_CcNode, keyIndex, p_KeyStatistics); ++ ++ XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); ++ ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_MatchTableGetIndexedHashBucket(t_Handle h_CcNode, ++ uint8_t keySize, uint8_t *p_Key, ++ uint8_t hashShift, ++ t_Handle *p_CcNodeBucketHandle, ++ uint8_t *p_BucketIndex, ++ uint16_t *p_LastIndex) ++{ ++ t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; ++ uint16_t glblMask; ++ uint64_t crc64 = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(h_CcNode, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR( ++ p_CcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED, ++ E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_CcNodeBucketHandle, E_NULL_POINTER); ++ ++ memcpy(&glblMask, PTR_MOVE(p_CcNode->p_GlblMask, 2), 2); ++ be16_to_cpus(&glblMask); ++ ++ crc64 = crc64_init(); ++ crc64 = crc64_compute(p_Key, keySize, crc64); ++ crc64 >>= hashShift; ++ ++ *p_BucketIndex = (uint8_t)(((crc64 >> (8 * (6 - p_CcNode->userOffset))) ++ & glblMask) >> 4); ++ if (*p_BucketIndex >= p_CcNode->numOfKeys) ++ RETURN_ERROR(MINOR, E_NOT_IN_RANGE, ("bucket index!")); ++ ++ *p_CcNodeBucketHandle = ++ p_CcNode->keyAndNextEngineParams[*p_BucketIndex].nextEngineParams.params.ccParams.h_CcNode; ++ if (!*p_CcNodeBucketHandle) ++ RETURN_ERROR(MINOR, E_NOT_FOUND, ("bucket!")); ++ ++ *p_LastIndex = ((t_FmPcdCcNode *)*p_CcNodeBucketHandle)->numOfKeys; ++ ++ return E_OK; ++} ++ ++t_Handle FM_PCD_HashTableSet(t_Handle h_FmPcd, t_FmPcdHashTableParams *p_Param) ++{ ++ t_FmPcdCcNode *p_CcNodeHashTbl; ++ t_FmPcdCcNodeParams *p_IndxHashCcNodeParam, *p_ExactMatchCcNodeParam; ++ t_FmPcdCcNode *p_CcNode; ++ t_Handle h_MissStatsCounters = NULL; ++ t_FmPcdCcKeyParams *p_HashKeyParams; ++ int i; ++ uint16_t numOfSets, numOfWays, countMask, onesCount = 0; ++ bool statsEnForMiss = FALSE; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(p_Param, E_NULL_POINTER, NULL); ++ ++ if (p_Param->maxNumOfKeys == 0) ++ { ++ REPORT_ERROR(MINOR, E_INVALID_VALUE, ("Max number of keys must be higher then 0")); ++ return NULL; ++ } ++ ++ if (p_Param->hashResMask == 0) ++ { ++ REPORT_ERROR(MINOR, E_INVALID_VALUE, ("Hash result mask must differ from 0")); ++ return NULL; ++ } ++ ++ /*Fix: QorIQ SDK / QSDK-2131*/ ++ if (p_Param->ccNextEngineParamsForMiss.nextEngine == e_FM_PCD_INVALID) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Next PCD Engine for on-miss entry is invalid. On-miss entry is always required. You can use e_FM_PCD_DONE.")); ++ return NULL; ++ } ++ ++#if (DPAA_VERSION >= 11) ++ if (p_Param->statisticsMode == e_FM_PCD_CC_STATS_MODE_RMON) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ++ ("RMON statistics mode is not supported for hash table")); ++ return NULL; ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ p_ExactMatchCcNodeParam = (t_FmPcdCcNodeParams*)XX_Malloc( ++ sizeof(t_FmPcdCcNodeParams)); ++ if (!p_ExactMatchCcNodeParam) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_ExactMatchCcNodeParam")); ++ return NULL; ++ } ++ memset(p_ExactMatchCcNodeParam, 0, sizeof(t_FmPcdCcNodeParams)); ++ ++ p_IndxHashCcNodeParam = (t_FmPcdCcNodeParams*)XX_Malloc( ++ sizeof(t_FmPcdCcNodeParams)); ++ if (!p_IndxHashCcNodeParam) ++ { ++ XX_Free(p_ExactMatchCcNodeParam); ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_IndxHashCcNodeParam")); ++ return NULL; ++ } ++ memset(p_IndxHashCcNodeParam, 0, sizeof(t_FmPcdCcNodeParams)); ++ ++ /* Calculate number of sets and number of ways of the hash table */ ++ countMask = (uint16_t)(p_Param->hashResMask >> 4); ++ while (countMask) ++ { ++ onesCount++; ++ countMask = (uint16_t)(countMask >> 1); ++ } ++ ++ numOfSets = (uint16_t)(1 << onesCount); ++ numOfWays = (uint16_t)DIV_CEIL(p_Param->maxNumOfKeys, numOfSets); ++ ++ if (p_Param->maxNumOfKeys % numOfSets) ++ DBG(INFO, ("'maxNumOfKeys' is not a multiple of hash number of ways, so number of ways will be rounded up")); ++ ++ if ((p_Param->statisticsMode == e_FM_PCD_CC_STATS_MODE_FRAME) ++ || (p_Param->statisticsMode == e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME)) ++ { ++ /* Allocating a statistics counters table that will be used by all ++ 'miss' entries of the hash table */ ++ h_MissStatsCounters = (t_Handle)FM_MURAM_AllocMem( ++ FmPcdGetMuramHandle(h_FmPcd), 2 * FM_PCD_CC_STATS_COUNTER_SIZE, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!h_MissStatsCounters) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for statistics table for hash miss")); ++ XX_Free(p_IndxHashCcNodeParam); ++ XX_Free(p_ExactMatchCcNodeParam); ++ return NULL; ++ } ++ memset(h_MissStatsCounters, 0, (2 * FM_PCD_CC_STATS_COUNTER_SIZE)); ++ ++ /* Always enable statistics for 'miss', so that a statistics AD will be ++ initialized from the start. We'll store the requested 'statistics enable' ++ value and it will be used when statistics are read by the user. */ ++ statsEnForMiss = p_Param->ccNextEngineParamsForMiss.statisticsEn; ++ p_Param->ccNextEngineParamsForMiss.statisticsEn = TRUE; ++ } ++ ++ /* Building exact-match node params, will be used to create the hash buckets */ ++ p_ExactMatchCcNodeParam->extractCcParams.type = e_FM_PCD_EXTRACT_NON_HDR; ++ ++ p_ExactMatchCcNodeParam->extractCcParams.extractNonHdr.src = ++ e_FM_PCD_EXTRACT_FROM_KEY; ++ p_ExactMatchCcNodeParam->extractCcParams.extractNonHdr.action = ++ e_FM_PCD_ACTION_EXACT_MATCH; ++ p_ExactMatchCcNodeParam->extractCcParams.extractNonHdr.offset = 0; ++ p_ExactMatchCcNodeParam->extractCcParams.extractNonHdr.size = ++ p_Param->matchKeySize; ++ ++ p_ExactMatchCcNodeParam->keysParams.maxNumOfKeys = numOfWays; ++ p_ExactMatchCcNodeParam->keysParams.maskSupport = FALSE; ++ p_ExactMatchCcNodeParam->keysParams.statisticsMode = ++ p_Param->statisticsMode; ++ p_ExactMatchCcNodeParam->keysParams.numOfKeys = 0; ++ p_ExactMatchCcNodeParam->keysParams.keySize = p_Param->matchKeySize; ++ p_ExactMatchCcNodeParam->keysParams.ccNextEngineParamsForMiss = ++ p_Param->ccNextEngineParamsForMiss; ++ ++ p_HashKeyParams = p_IndxHashCcNodeParam->keysParams.keyParams; ++ ++ for (i = 0; i < numOfSets; i++) ++ { ++ /* Each exact-match node will be marked as a 'bucket' and provided with ++ a pointer to statistics counters, to be used for 'miss' entry ++ statistics */ ++ p_CcNode = (t_FmPcdCcNode *)XX_Malloc(sizeof(t_FmPcdCcNode)); ++ if (!p_CcNode) ++ break; ++ memset(p_CcNode, 0, sizeof(t_FmPcdCcNode)); ++ ++ p_CcNode->isHashBucket = TRUE; ++ p_CcNode->h_MissStatsCounters = h_MissStatsCounters; ++ ++ err = MatchTableSet(h_FmPcd, p_CcNode, p_ExactMatchCcNodeParam); ++ if (err) ++ break; ++ ++ p_HashKeyParams[i].ccNextEngineParams.nextEngine = e_FM_PCD_CC; ++ p_HashKeyParams[i].ccNextEngineParams.statisticsEn = FALSE; ++ p_HashKeyParams[i].ccNextEngineParams.params.ccParams.h_CcNode = ++ p_CcNode; ++ } ++ ++ if (i < numOfSets) ++ { ++ for (i = i - 1; i >= 0; i--) ++ FM_PCD_MatchTableDelete( ++ p_HashKeyParams[i].ccNextEngineParams.params.ccParams.h_CcNode); ++ ++ FM_MURAM_FreeMem(FmPcdGetMuramHandle(h_FmPcd), h_MissStatsCounters); ++ ++ REPORT_ERROR(MAJOR, E_NULL_POINTER, NO_MSG); ++ XX_Free(p_IndxHashCcNodeParam); ++ XX_Free(p_ExactMatchCcNodeParam); ++ return NULL; ++ } ++ ++ /* Creating indexed-hash CC node */ ++ p_IndxHashCcNodeParam->extractCcParams.type = e_FM_PCD_EXTRACT_NON_HDR; ++ p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.src = ++ e_FM_PCD_EXTRACT_FROM_HASH; ++ p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.action = ++ e_FM_PCD_ACTION_INDEXED_LOOKUP; ++ p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.icIndxMask = ++ p_Param->hashResMask; ++ p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.offset = ++ p_Param->hashShift; ++ p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.size = 2; ++ ++ p_IndxHashCcNodeParam->keysParams.maxNumOfKeys = numOfSets; ++ p_IndxHashCcNodeParam->keysParams.maskSupport = FALSE; ++ p_IndxHashCcNodeParam->keysParams.statisticsMode = ++ e_FM_PCD_CC_STATS_MODE_NONE; ++ /* Number of keys of this node is number of sets of the hash */ ++ p_IndxHashCcNodeParam->keysParams.numOfKeys = numOfSets; ++ p_IndxHashCcNodeParam->keysParams.keySize = 2; ++ ++ p_CcNodeHashTbl = FM_PCD_MatchTableSet(h_FmPcd, p_IndxHashCcNodeParam); ++ ++ if (p_CcNodeHashTbl) ++ { ++ p_CcNodeHashTbl->kgHashShift = p_Param->kgHashShift; ++ ++ /* Storing the allocated counters for buckets 'miss' in the hash table ++ and if statistics for miss were enabled. */ ++ p_CcNodeHashTbl->h_MissStatsCounters = h_MissStatsCounters; ++ p_CcNodeHashTbl->statsEnForMiss = statsEnForMiss; ++ } ++ ++ XX_Free(p_IndxHashCcNodeParam); ++ XX_Free(p_ExactMatchCcNodeParam); ++ ++ return p_CcNodeHashTbl; ++} ++ ++t_Error FM_PCD_HashTableDelete(t_Handle h_HashTbl) ++{ ++ t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl; ++ t_Handle h_FmPcd; ++ t_Handle *p_HashBuckets, h_MissStatsCounters; ++ uint16_t i, numOfBuckets; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE); ++ ++ /* Store all hash buckets before the hash is freed */ ++ numOfBuckets = p_HashTbl->numOfKeys; ++ ++ p_HashBuckets = (t_Handle *)XX_Malloc(numOfBuckets * sizeof(t_Handle)); ++ if (!p_HashBuckets) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); ++ ++ for (i = 0; i < numOfBuckets; i++) ++ p_HashBuckets[i] = ++ p_HashTbl->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode; ++ ++ h_FmPcd = p_HashTbl->h_FmPcd; ++ h_MissStatsCounters = p_HashTbl->h_MissStatsCounters; ++ ++ /* Free the hash */ ++ err = FM_PCD_MatchTableDelete(p_HashTbl); ++ ++ /* Free each hash bucket */ ++ for (i = 0; i < numOfBuckets; i++) ++ err |= FM_PCD_MatchTableDelete(p_HashBuckets[i]); ++ ++ XX_Free(p_HashBuckets); ++ ++ /* Free statistics counters for 'miss', if these were allocated */ ++ if (h_MissStatsCounters) ++ FM_MURAM_FreeMem(FmPcdGetMuramHandle(h_FmPcd), h_MissStatsCounters); ++ ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_HashTableAddKey(t_Handle h_HashTbl, uint8_t keySize, ++ t_FmPcdCcKeyParams *p_KeyParams) ++{ ++ t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl; ++ t_Handle h_HashBucket; ++ uint8_t bucketIndex; ++ uint16_t lastIndex; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_KeyParams, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_KeyParams->p_Key, E_NULL_POINTER); ++ ++ if (p_KeyParams->p_Mask) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("Keys masks not supported for hash table")); ++ ++ err = FM_PCD_MatchTableGetIndexedHashBucket(p_HashTbl, keySize, ++ p_KeyParams->p_Key, ++ p_HashTbl->kgHashShift, ++ &h_HashBucket, &bucketIndex, ++ &lastIndex); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ return FM_PCD_MatchTableAddKey(h_HashBucket, FM_PCD_LAST_KEY_INDEX, keySize, ++ p_KeyParams); ++} ++ ++t_Error FM_PCD_HashTableRemoveKey(t_Handle h_HashTbl, uint8_t keySize, ++ uint8_t *p_Key) ++{ ++ t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl; ++ t_Handle h_HashBucket; ++ uint8_t bucketIndex; ++ uint16_t lastIndex; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); ++ ++ err = FM_PCD_MatchTableGetIndexedHashBucket(p_HashTbl, keySize, p_Key, ++ p_HashTbl->kgHashShift, ++ &h_HashBucket, &bucketIndex, ++ &lastIndex); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ return FM_PCD_MatchTableFindNRemoveKey(h_HashBucket, keySize, p_Key, NULL); ++} ++ ++t_Error FM_PCD_HashTableModifyNextEngine( ++ t_Handle h_HashTbl, uint8_t keySize, uint8_t *p_Key, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) ++{ ++ t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl; ++ t_Handle h_HashBucket; ++ uint8_t bucketIndex; ++ uint16_t lastIndex; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER); ++ ++ err = FM_PCD_MatchTableGetIndexedHashBucket(p_HashTbl, keySize, p_Key, ++ p_HashTbl->kgHashShift, ++ &h_HashBucket, &bucketIndex, ++ &lastIndex); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ return FM_PCD_MatchTableFindNModifyNextEngine(h_HashBucket, keySize, p_Key, ++ NULL, ++ p_FmPcdCcNextEngineParams); ++} ++ ++t_Error FM_PCD_HashTableModifyMissNextEngine( ++ t_Handle h_HashTbl, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) ++{ ++ t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl; ++ t_Handle h_HashBucket; ++ uint8_t i; ++ bool nullifyMissStats = FALSE; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(h_HashTbl, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER); ++ ++ if ((!p_HashTbl->h_MissStatsCounters) ++ && (p_FmPcdCcNextEngineParams->statisticsEn)) ++ RETURN_ERROR( ++ MAJOR, ++ E_CONFLICT, ++ ("Statistics are requested for a key, but statistics mode was set" ++ "to 'NONE' upon initialization")); ++ ++ if (p_HashTbl->h_MissStatsCounters) ++ { ++ if ((!p_HashTbl->statsEnForMiss) ++ && (p_FmPcdCcNextEngineParams->statisticsEn)) ++ nullifyMissStats = TRUE; ++ ++ if ((p_HashTbl->statsEnForMiss) ++ && (!p_FmPcdCcNextEngineParams->statisticsEn)) ++ { ++ p_HashTbl->statsEnForMiss = FALSE; ++ p_FmPcdCcNextEngineParams->statisticsEn = TRUE; ++ } ++ } ++ ++ for (i = 0; i < p_HashTbl->numOfKeys; i++) ++ { ++ h_HashBucket = ++ p_HashTbl->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode; ++ ++ err = FM_PCD_MatchTableModifyMissNextEngine(h_HashBucket, ++ p_FmPcdCcNextEngineParams); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ if (nullifyMissStats) ++ { ++ memset(p_HashTbl->h_MissStatsCounters, 0, ++ (2 * FM_PCD_CC_STATS_COUNTER_SIZE)); ++ memset(p_HashTbl->h_MissStatsCounters, 0, ++ (2 * FM_PCD_CC_STATS_COUNTER_SIZE)); ++ p_HashTbl->statsEnForMiss = TRUE; ++ } ++ ++ return E_OK; ++} ++ ++ ++t_Error FM_PCD_HashTableGetMissNextEngine( ++ t_Handle h_HashTbl, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) ++{ ++ t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl; ++ t_FmPcdCcNode *p_HashBucket; ++ ++ SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE); ++ ++ /* Miss next engine of each bucket was initialized with the next engine of the hash table */ ++ p_HashBucket = ++ p_HashTbl->keyAndNextEngineParams[0].nextEngineParams.params.ccParams.h_CcNode; ++ ++ memcpy(p_FmPcdCcNextEngineParams, ++ &p_HashBucket->keyAndNextEngineParams[p_HashBucket->numOfKeys].nextEngineParams, ++ sizeof(t_FmPcdCcNextEngineParams)); ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_HashTableFindNGetKeyStatistics( ++ t_Handle h_HashTbl, uint8_t keySize, uint8_t *p_Key, ++ t_FmPcdCcKeyStatistics *p_KeyStatistics) ++{ ++ t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl; ++ t_Handle h_HashBucket; ++ uint8_t bucketIndex; ++ uint16_t lastIndex; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_KeyStatistics, E_NULL_POINTER); ++ ++ err = FM_PCD_MatchTableGetIndexedHashBucket(p_HashTbl, keySize, p_Key, ++ p_HashTbl->kgHashShift, ++ &h_HashBucket, &bucketIndex, ++ &lastIndex); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ return FM_PCD_MatchTableFindNGetKeyStatistics(h_HashBucket, keySize, p_Key, ++ NULL, p_KeyStatistics); ++} ++ ++t_Error FM_PCD_HashTableGetMissStatistics( ++ t_Handle h_HashTbl, t_FmPcdCcKeyStatistics *p_MissStatistics) ++{ ++ t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl; ++ t_Handle h_HashBucket; ++ ++ SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_MissStatistics, E_NULL_POINTER); ++ ++ if (!p_HashTbl->statsEnForMiss) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("Statistics were not enabled for miss")); ++ ++ h_HashBucket = ++ p_HashTbl->keyAndNextEngineParams[0].nextEngineParams.params.ccParams.h_CcNode; ++ ++ return FM_PCD_MatchTableGetMissStatistics(h_HashBucket, p_MissStatistics); ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.h +new file mode 100644 +index 00000000..3456bb56 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.h +@@ -0,0 +1,399 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_cc.h ++ ++ @Description FM PCD CC ... ++*//***************************************************************************/ ++#ifndef __FM_CC_H ++#define __FM_CC_H ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "list_ext.h" ++ ++#include "fm_pcd.h" ++ ++ ++/***********************************************************************/ ++/* Coarse classification defines */ ++/***********************************************************************/ ++ ++#define CC_MAX_NUM_OF_KEYS (FM_PCD_MAX_NUM_OF_KEYS + 1) ++ ++#define CC_PC_FF_MACDST 0x00 ++#define CC_PC_FF_MACSRC 0x01 ++#define CC_PC_FF_ETYPE 0x02 ++ ++#define CC_PC_FF_TCI1 0x03 ++#define CC_PC_FF_TCI2 0x04 ++ ++#define CC_PC_FF_MPLS1 0x06 ++#define CC_PC_FF_MPLS_LAST 0x07 ++ ++#define CC_PC_FF_IPV4DST1 0x08 ++#define CC_PC_FF_IPV4DST2 0x16 ++#define CC_PC_FF_IPV4IPTOS_TC1 0x09 ++#define CC_PC_FF_IPV4IPTOS_TC2 0x17 ++#define CC_PC_FF_IPV4PTYPE1 0x0A ++#define CC_PC_FF_IPV4PTYPE2 0x18 ++#define CC_PC_FF_IPV4SRC1 0x0b ++#define CC_PC_FF_IPV4SRC2 0x19 ++#define CC_PC_FF_IPV4SRC1_IPV4DST1 0x0c ++#define CC_PC_FF_IPV4SRC2_IPV4DST2 0x1a ++#define CC_PC_FF_IPV4TTL 0x29 ++ ++ ++#define CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1 0x0d /*TODO - CLASS - what is it? TOS*/ ++#define CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2 0x1b ++#define CC_PC_FF_IPV6PTYPE1 0x0e ++#define CC_PC_FF_IPV6PTYPE2 0x1c ++#define CC_PC_FF_IPV6DST1 0x0f ++#define CC_PC_FF_IPV6DST2 0x1d ++#define CC_PC_FF_IPV6SRC1 0x10 ++#define CC_PC_FF_IPV6SRC2 0x1e ++#define CC_PC_FF_IPV6HOP_LIMIT 0x2a ++#define CC_PC_FF_IPPID 0x24 ++#define CC_PC_FF_IPDSCP 0x76 ++ ++#define CC_PC_FF_GREPTYPE 0x11 ++ ++#define CC_PC_FF_MINENCAP_PTYPE 0x12 ++#define CC_PC_FF_MINENCAP_IPDST 0x13 ++#define CC_PC_FF_MINENCAP_IPSRC 0x14 ++#define CC_PC_FF_MINENCAP_IPSRC_IPDST 0x15 ++ ++#define CC_PC_FF_L4PSRC 0x1f ++#define CC_PC_FF_L4PDST 0x20 ++#define CC_PC_FF_L4PSRC_L4PDST 0x21 ++ ++#define CC_PC_FF_PPPPID 0x05 ++ ++#define CC_PC_PR_SHIM1 0x22 ++#define CC_PC_PR_SHIM2 0x23 ++ ++#define CC_PC_GENERIC_WITHOUT_MASK 0x27 ++#define CC_PC_GENERIC_WITH_MASK 0x28 ++#define CC_PC_GENERIC_IC_GMASK 0x2B ++#define CC_PC_GENERIC_IC_HASH_INDEXED 0x2C ++#define CC_PC_GENERIC_IC_AGING_MASK 0x2D ++ ++#define CC_PR_OFFSET 0x25 ++#define CC_PR_WITHOUT_OFFSET 0x26 ++ ++#define CC_PC_PR_ETH_OFFSET 19 ++#define CC_PC_PR_USER_DEFINED_SHIM1_OFFSET 16 ++#define CC_PC_PR_USER_DEFINED_SHIM2_OFFSET 17 ++#define CC_PC_PR_USER_LLC_SNAP_OFFSET 20 ++#define CC_PC_PR_VLAN1_OFFSET 21 ++#define CC_PC_PR_VLAN2_OFFSET 22 ++#define CC_PC_PR_PPPOE_OFFSET 24 ++#define CC_PC_PR_MPLS1_OFFSET 25 ++#define CC_PC_PR_MPLS_LAST_OFFSET 26 ++#define CC_PC_PR_IP1_OFFSET 27 ++#define CC_PC_PR_IP_LAST_OFFSET 28 ++#define CC_PC_PR_MINENC_OFFSET 28 ++#define CC_PC_PR_L4_OFFSET 30 ++#define CC_PC_PR_GRE_OFFSET 29 ++#define CC_PC_PR_ETYPE_LAST_OFFSET 23 ++#define CC_PC_PR_NEXT_HEADER_OFFSET 31 ++ ++#define CC_PC_ILLEGAL 0xff ++#define CC_SIZE_ILLEGAL 0 ++ ++#define FM_PCD_CC_KEYS_MATCH_TABLE_ALIGN 16 ++#define FM_PCD_CC_AD_TABLE_ALIGN 16 ++#define FM_PCD_CC_AD_ENTRY_SIZE 16 ++#define FM_PCD_CC_NUM_OF_KEYS 255 ++#define FM_PCD_CC_TREE_ADDR_ALIGN 256 ++ ++#define FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE 0x00000000 ++#define FM_PCD_AD_RESULT_DATA_FLOW_TYPE 0x80000000 ++#define FM_PCD_AD_RESULT_PLCR_DIS 0x20000000 ++#define FM_PCD_AD_RESULT_EXTENDED_MODE 0x80000000 ++#define FM_PCD_AD_RESULT_NADEN 0x20000000 ++#define FM_PCD_AD_RESULT_STATISTICS_EN 0x40000000 ++ ++#define FM_PCD_AD_CONT_LOOKUP_TYPE 0x40000000 ++#define FM_PCD_AD_CONT_LOOKUP_LCL_MASK 0x00800000 ++ ++#define FM_PCD_AD_STATS_TYPE 0x40000000 ++#define FM_PCD_AD_STATS_FLR_ADDR_MASK 0x00FFFFFF ++#define FM_PCD_AD_STATS_COUNTERS_ADDR_MASK 0x00FFFFFF ++#define FM_PCD_AD_STATS_NEXT_ACTION_MASK 0xFFFF0000 ++#define FM_PCD_AD_STATS_NEXT_ACTION_SHIFT 12 ++#define FM_PCD_AD_STATS_NAD_EN 0x00008000 ++#define FM_PCD_AD_STATS_OP_CODE 0x00000036 ++#define FM_PCD_AD_STATS_FLR_EN 0x00004000 ++#define FM_PCD_AD_STATS_COND_EN 0x00002000 ++ ++ ++ ++#define FM_PCD_AD_BYPASS_TYPE 0xc0000000 ++ ++#define FM_PCD_AD_TYPE_MASK 0xc0000000 ++#define FM_PCD_AD_OPCODE_MASK 0x0000000f ++ ++#define FM_PCD_AD_PROFILEID_FOR_CNTRL_SHIFT 16 ++#if (DPAA_VERSION >= 11) ++#define FM_PCD_AD_RESULT_VSP_SHIFT 24 ++#define FM_PCD_AD_RESULT_NO_OM_VSPE 0x02000000 ++#define FM_PCD_AD_RESULT_VSP_MASK 0x3f ++#define FM_PCD_AD_NCSPFQIDM_MASK 0x80000000 ++#endif /* (DPAA_VERSION >= 11) */ ++ ++#define GLBL_MASK_FOR_HASH_INDEXED 0xfff00000 ++#define CC_GLBL_MASK_SIZE 4 ++#define CC_AGING_MASK_SIZE 4 ++ ++typedef uint32_t ccPrivateInfo_t; /**< private info of CC: */ ++ ++#define CC_PRIVATE_INFO_NONE 0 ++#define CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP 0x80000000 ++#define CC_PRIVATE_INFO_IC_HASH_EXACT_MATCH 0x40000000 ++#define CC_PRIVATE_INFO_IC_KEY_EXACT_MATCH 0x20000000 ++#define CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP 0x10000000 ++ ++#define CC_BUILD_AGING_MASK(numOfKeys) ((((1LL << ((numOfKeys) + 1)) - 1)) << (31 - (numOfKeys))) ++/***********************************************************************/ ++/* Memory map */ ++/***********************************************************************/ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(push,1) ++#endif /* defined(__MWERKS__) && ... */ ++ ++typedef struct ++{ ++ volatile uint32_t fqid; ++ volatile uint32_t plcrProfile; ++ volatile uint32_t nia; ++ volatile uint32_t res; ++} t_AdOfTypeResult; ++ ++typedef struct ++{ ++ volatile uint32_t ccAdBase; ++ volatile uint32_t matchTblPtr; ++ volatile uint32_t pcAndOffsets; ++ volatile uint32_t gmask; ++} t_AdOfTypeContLookup; ++ ++typedef struct ++{ ++ volatile uint32_t profileTableAddr; ++ volatile uint32_t reserved; ++ volatile uint32_t nextActionIndx; ++ volatile uint32_t statsTableAddr; ++} t_AdOfTypeStats; ++ ++typedef union ++{ ++ volatile t_AdOfTypeResult adResult; ++ volatile t_AdOfTypeContLookup adContLookup; ++} t_Ad; ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(pop) ++#endif /* defined(__MWERKS__) && ... */ ++ ++ ++/***********************************************************************/ ++/* Driver's internal structures */ ++/***********************************************************************/ ++ ++typedef struct t_FmPcdStatsObj ++{ ++ t_Handle h_StatsAd; ++ t_Handle h_StatsCounters; ++ t_List node; ++} t_FmPcdStatsObj; ++ ++typedef struct ++{ ++ uint8_t key[FM_PCD_MAX_SIZE_OF_KEY]; ++ uint8_t mask[FM_PCD_MAX_SIZE_OF_KEY]; ++ ++ t_FmPcdCcNextEngineParams nextEngineParams; ++ uint32_t requiredAction; ++ uint32_t shadowAction; ++ ++ t_FmPcdStatsObj *p_StatsObj; ++ ++} t_FmPcdCcKeyAndNextEngineParams; ++ ++typedef struct ++{ ++ t_Handle p_Ad; ++ e_FmPcdEngine fmPcdEngine; ++ bool adAllocated; ++ bool isTree; ++ ++ uint32_t myInfo; ++ t_List *h_CcNextNodesLst; ++ t_Handle h_AdditionalInfo; ++ t_Handle h_Node; ++} t_FmPcdModifyCcAdditionalParams; ++ ++typedef struct ++{ ++ t_Handle p_AdTableNew; ++ t_Handle p_KeysMatchTableNew; ++ t_Handle p_AdTableOld; ++ t_Handle p_KeysMatchTableOld; ++ uint16_t numOfKeys; ++ t_Handle h_CurrentNode; ++ uint16_t savedKeyIndex; ++ t_Handle h_NodeForAdd; ++ t_Handle h_NodeForRmv; ++ t_Handle h_ManipForRmv; ++ t_Handle h_ManipForAdd; ++ t_FmPcdStatsObj *p_StatsObjForRmv; ++#if (DPAA_VERSION >= 11) ++ t_Handle h_FrmReplicForAdd; ++ t_Handle h_FrmReplicForRmv; ++#endif /* (DPAA_VERSION >= 11) */ ++ bool tree; ++ ++ t_FmPcdCcKeyAndNextEngineParams keyAndNextEngineParams[CC_MAX_NUM_OF_KEYS]; ++} t_FmPcdModifyCcKeyAdditionalParams; ++ ++typedef struct ++{ ++ t_Handle h_Manip; ++ t_Handle h_CcNode; ++} t_CcNextEngineInfo; ++ ++typedef struct ++{ ++ uint16_t numOfKeys; ++ uint16_t maxNumOfKeys; ++ ++ bool maskSupport; ++ uint32_t keysMatchTableMaxSize; ++ ++ e_FmPcdCcStatsMode statisticsMode; ++ uint32_t numOfStatsFLRs; ++ uint32_t countersArraySize; ++ ++ bool isHashBucket; /**< Valid for match table node that is a bucket of a hash table only */ ++ t_Handle h_MissStatsCounters; /**< Valid for hash table node and match table that is a bucket; ++ Holds the statistics counters allocated by the hash table and ++ are shared by all hash table buckets; */ ++ t_Handle h_PrivMissStatsCounters; /**< Valid for match table node that is a bucket of a hash table only; ++ Holds the statistics counters that were allocated for this node ++ and replaced by the shared counters (allocated by the hash table); */ ++ bool statsEnForMiss; /**< Valid for hash table node only; TRUE is statistics are currently ++ enabled for hash 'miss', FALSE otherwise; This parameter effects the ++ returned statistics count to user, statistics AD always present for 'miss' ++ for all hash buckets; */ ++ bool glblMaskUpdated; ++ t_Handle p_GlblMask; ++ bool lclMask; ++ uint8_t parseCode; ++ uint8_t offset; ++ uint8_t prsArrayOffset; ++ bool ctrlFlow; ++ uint16_t owners; ++ ++ uint8_t ccKeySizeAccExtraction; ++ uint8_t sizeOfExtraction; ++ uint8_t glblMaskSize; ++ ++ t_Handle h_KeysMatchTable; ++ t_Handle h_AdTable; ++ t_Handle h_StatsAds; ++ t_Handle h_TmpAd; ++ t_Handle h_Ad; ++ t_Handle h_StatsFLRs; ++ ++ t_List availableStatsLst; ++ ++ t_List ccPrevNodesLst; ++ ++ t_List ccTreeIdLst; ++ t_List ccTreesLst; ++ ++ t_Handle h_FmPcd; ++ uint32_t shadowAction; ++ uint8_t userSizeOfExtraction; ++ uint8_t userOffset; ++ uint8_t kgHashShift; /* used in hash-table */ ++ ++ t_Handle h_Spinlock; ++ ++ t_FmPcdCcKeyAndNextEngineParams keyAndNextEngineParams[CC_MAX_NUM_OF_KEYS]; ++} t_FmPcdCcNode; ++ ++typedef struct ++{ ++ t_FmPcdCcNode *p_FmPcdCcNode; ++ bool occupied; ++ uint16_t owners; ++ volatile bool lock; ++} t_FmPcdCcNodeArray; ++ ++typedef struct ++{ ++ uint8_t numOfEntriesInGroup; ++ uint32_t totalBitsMask; ++ uint8_t baseGroupEntry; ++} t_FmPcdCcGroupParam; ++ ++typedef struct ++{ ++ t_Handle h_FmPcd; ++ uint8_t netEnvId; ++ uintptr_t ccTreeBaseAddr; ++ uint8_t numOfGrps; ++ t_FmPcdCcGroupParam fmPcdGroupParam[FM_PCD_MAX_NUM_OF_CC_GROUPS]; ++ t_List fmPortsLst; ++ t_FmPcdLock *p_Lock; ++ uint8_t numOfEntries; ++ uint16_t owners; ++ t_Handle h_FmPcdCcSavedManipParams; ++ bool modifiedState; ++ uint32_t requiredAction; ++ t_Handle h_IpReassemblyManip; ++ t_Handle h_CapwapReassemblyManip; ++ ++ t_FmPcdCcKeyAndNextEngineParams keyAndNextEngineParams[FM_PCD_MAX_NUM_OF_CC_GROUPS]; ++} t_FmPcdCcTree; ++ ++ ++t_Error FmPcdCcNodeTreeTryLock(t_Handle h_FmPcd,t_Handle h_FmPcdCcNode, t_List *p_List); ++void FmPcdCcNodeTreeReleaseLock(t_Handle h_FmPcd, t_List *p_List); ++t_Error FmPcdUpdateCcShadow (t_FmPcd *p_FmPcd, uint32_t size, uint32_t align); ++ ++ ++#endif /* __FM_CC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c +new file mode 100644 +index 00000000..f183d2f9 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c +@@ -0,0 +1,3242 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_kg.c ++ ++ @Description FM PCD ... ++*//***************************************************************************/ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "string_ext.h" ++#include "debug_ext.h" ++#include "net_ext.h" ++#include "fm_port_ext.h" ++ ++#include "fm_common.h" ++#include "fm_pcd.h" ++#include "fm_hc.h" ++#include "fm_pcd_ipc.h" ++#include "fm_kg.h" ++#include "fsl_fman_kg.h" ++ ++ ++/****************************************/ ++/* static functions */ ++/****************************************/ ++ ++static uint32_t KgHwLock(t_Handle h_FmPcdKg) ++{ ++ ASSERT_COND(h_FmPcdKg); ++ return XX_LockIntrSpinlock(((t_FmPcdKg *)h_FmPcdKg)->h_HwSpinlock); ++} ++ ++static void KgHwUnlock(t_Handle h_FmPcdKg, uint32_t intFlags) ++{ ++ ASSERT_COND(h_FmPcdKg); ++ XX_UnlockIntrSpinlock(((t_FmPcdKg *)h_FmPcdKg)->h_HwSpinlock, intFlags); ++} ++ ++static uint32_t KgSchemeLock(t_Handle h_Scheme) ++{ ++ ASSERT_COND(h_Scheme); ++ return FmPcdLockSpinlock(((t_FmPcdKgScheme *)h_Scheme)->p_Lock); ++} ++ ++static void KgSchemeUnlock(t_Handle h_Scheme, uint32_t intFlags) ++{ ++ ASSERT_COND(h_Scheme); ++ FmPcdUnlockSpinlock(((t_FmPcdKgScheme *)h_Scheme)->p_Lock, intFlags); ++} ++ ++static bool KgSchemeFlagTryLock(t_Handle h_Scheme) ++{ ++ ASSERT_COND(h_Scheme); ++ return FmPcdLockTryLock(((t_FmPcdKgScheme *)h_Scheme)->p_Lock); ++} ++ ++static void KgSchemeFlagUnlock(t_Handle h_Scheme) ++{ ++ ASSERT_COND(h_Scheme); ++ FmPcdLockUnlock(((t_FmPcdKgScheme *)h_Scheme)->p_Lock); ++} ++ ++static t_Error WriteKgarWait(t_FmPcd *p_FmPcd, uint32_t fmkg_ar) ++{ ++ ++ struct fman_kg_regs *regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; ++ ++ if (fman_kg_write_ar_wait(regs, fmkg_ar)) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Keygen scheme access violation")); ++ ++ return E_OK; ++} ++ ++static e_FmPcdKgExtractDfltSelect GetGenericSwDefault(t_FmPcdKgExtractDflt swDefaults[], uint8_t numOfSwDefaults, uint8_t code) ++{ ++ int i; ++ ++ switch (code) ++ { ++ case (KG_SCH_GEN_PARSE_RESULT_N_FQID): ++ case (KG_SCH_GEN_DEFAULT): ++ case (KG_SCH_GEN_NEXTHDR): ++ for (i=0 ; ifmRevInfo.majorRev < 6) ++ return KG_SCH_KN_PTYPE2; ++#endif /* FM_KG_NO_IPPID_SUPPORT */ ++ return KG_SCH_KN_IPPID; ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); ++ return 0; ++ case (NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL | NET_HEADER_FIELD_IPv6_TC): ++ if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) ++ return (KG_SCH_KN_IPV6FL1 | KG_SCH_KN_IPTOS_TC1); ++ if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST)) ++ return (KG_SCH_KN_IPV6FL2 | KG_SCH_KN_IPTOS_TC2); ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); ++ return 0; ++ case (NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_TC): ++ if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) ++ return KG_SCH_KN_IPTOS_TC1; ++ if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST)) ++ return KG_SCH_KN_IPTOS_TC2; ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); ++ return 0; ++ case (NET_HEADER_FIELD_IPv6_FL): ++ if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) ++ return KG_SCH_KN_IPV6FL1; ++ if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST)) ++ return KG_SCH_KN_IPV6FL2; ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); ++ return 0; ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return 0; ++ } ++ case (HEADER_TYPE_GRE): ++ switch (field.gre) ++ { ++ case (NET_HEADER_FIELD_GRE_TYPE): ++ return KG_SCH_KN_GREPTYPE; ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return 0; ++ } ++ case (HEADER_TYPE_MINENCAP): ++ switch (field.minencap) ++ { ++ case (NET_HEADER_FIELD_MINENCAP_SRC_IP): ++ return KG_SCH_KN_IPSRC2; ++ case (NET_HEADER_FIELD_MINENCAP_DST_IP): ++ return KG_SCH_KN_IPDST2; ++ case (NET_HEADER_FIELD_MINENCAP_TYPE): ++ return KG_SCH_KN_PTYPE2; ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return 0; ++ } ++ case (HEADER_TYPE_TCP): ++ switch (field.tcp) ++ { ++ case (NET_HEADER_FIELD_TCP_PORT_SRC): ++ return KG_SCH_KN_L4PSRC; ++ case (NET_HEADER_FIELD_TCP_PORT_DST): ++ return KG_SCH_KN_L4PDST; ++ case (NET_HEADER_FIELD_TCP_FLAGS): ++ return KG_SCH_KN_TFLG; ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return 0; ++ } ++ case (HEADER_TYPE_UDP): ++ switch (field.udp) ++ { ++ case (NET_HEADER_FIELD_UDP_PORT_SRC): ++ return KG_SCH_KN_L4PSRC; ++ case (NET_HEADER_FIELD_UDP_PORT_DST): ++ return KG_SCH_KN_L4PDST; ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return 0; ++ } ++ case (HEADER_TYPE_IPSEC_AH): ++ switch (field.ipsecAh) ++ { ++ case (NET_HEADER_FIELD_IPSEC_AH_SPI): ++ return KG_SCH_KN_IPSEC_SPI; ++ case (NET_HEADER_FIELD_IPSEC_AH_NH): ++ return KG_SCH_KN_IPSEC_NH; ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return 0; ++ } ++ case (HEADER_TYPE_IPSEC_ESP): ++ switch (field.ipsecEsp) ++ { ++ case (NET_HEADER_FIELD_IPSEC_ESP_SPI): ++ return KG_SCH_KN_IPSEC_SPI; ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return 0; ++ } ++ case (HEADER_TYPE_SCTP): ++ switch (field.sctp) ++ { ++ case (NET_HEADER_FIELD_SCTP_PORT_SRC): ++ return KG_SCH_KN_L4PSRC; ++ case (NET_HEADER_FIELD_SCTP_PORT_DST): ++ return KG_SCH_KN_L4PDST; ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return 0; ++ } ++ case (HEADER_TYPE_DCCP): ++ switch (field.dccp) ++ { ++ case (NET_HEADER_FIELD_DCCP_PORT_SRC): ++ return KG_SCH_KN_L4PSRC; ++ case (NET_HEADER_FIELD_DCCP_PORT_DST): ++ return KG_SCH_KN_L4PDST; ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return 0; ++ } ++ case (HEADER_TYPE_PPPoE): ++ switch (field.pppoe) ++ { ++ case (NET_HEADER_FIELD_PPPoE_PID): ++ return KG_SCH_KN_PPPID; ++ case (NET_HEADER_FIELD_PPPoE_SID): ++ return KG_SCH_KN_PPPSID; ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return 0; ++ } ++ default: ++ break; ++ ++ } ++ ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); ++ return 0; ++} ++ ++ ++static uint8_t GetKnownFieldId(uint32_t bitMask) ++{ ++ uint8_t cnt = 0; ++ ++ while (bitMask) ++ if (bitMask & 0x80000000) ++ break; ++ else ++ { ++ cnt++; ++ bitMask <<= 1; ++ } ++ return cnt; ++ ++} ++ ++static uint8_t GetExtractedOrMask(uint8_t bitOffset, bool fqid) ++{ ++ uint8_t i, mask, numOfOnesToClear, walking1Mask = 1; ++ ++ /* bitOffset 1-7 --> mask 0x1-0x7F */ ++ if (bitOffset<8) ++ { ++ mask = 0; ++ for (i = 0 ; i < bitOffset ; i++, walking1Mask <<= 1) ++ mask |= walking1Mask; ++ } ++ else ++ { ++ mask = 0xFF; ++ numOfOnesToClear = 0; ++ if (fqid && bitOffset>24) ++ /* bitOffset 25-31 --> mask 0xFE-0x80 */ ++ numOfOnesToClear = (uint8_t)(bitOffset-24); ++ else ++ /* bitOffset 9-15 --> mask 0xFE-0x80 */ ++ if (!fqid && bitOffset>8) ++ numOfOnesToClear = (uint8_t)(bitOffset-8); ++ for (i = 0 ; i < numOfOnesToClear ; i++, walking1Mask <<= 1) ++ mask &= ~walking1Mask; ++ /* bitOffset 8-24 for FQID, 8 for PP --> no mask (0xFF)*/ ++ } ++ return mask; ++} ++ ++static void IncSchemeOwners(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort) ++{ ++ t_FmPcdKg *p_FmPcdKg; ++ t_FmPcdKgScheme *p_Scheme; ++ uint32_t intFlags; ++ uint8_t relativeSchemeId; ++ int i; ++ ++ p_FmPcdKg = p_FmPcd->p_FmPcdKg; ++ ++ /* for each scheme - update owners counters */ ++ for (i = 0; i < p_BindPort->numOfSchemes; i++) ++ { ++ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, p_BindPort->schemesIds[i]); ++ ASSERT_COND(relativeSchemeId < FM_PCD_KG_NUM_OF_SCHEMES); ++ ++ p_Scheme = &p_FmPcdKg->schemes[relativeSchemeId]; ++ ++ /* increment owners number */ ++ intFlags = KgSchemeLock(p_Scheme); ++ p_Scheme->owners++; ++ KgSchemeUnlock(p_Scheme, intFlags); ++ } ++} ++ ++static void DecSchemeOwners(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort) ++{ ++ t_FmPcdKg *p_FmPcdKg; ++ t_FmPcdKgScheme *p_Scheme; ++ uint32_t intFlags; ++ uint8_t relativeSchemeId; ++ int i; ++ ++ p_FmPcdKg = p_FmPcd->p_FmPcdKg; ++ ++ /* for each scheme - update owners counters */ ++ for (i = 0; i < p_BindPort->numOfSchemes; i++) ++ { ++ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, p_BindPort->schemesIds[i]); ++ ASSERT_COND(relativeSchemeId < FM_PCD_KG_NUM_OF_SCHEMES); ++ ++ p_Scheme = &p_FmPcdKg->schemes[relativeSchemeId]; ++ ++ /* increment owners number */ ++ ASSERT_COND(p_Scheme->owners); ++ intFlags = KgSchemeLock(p_Scheme); ++ p_Scheme->owners--; ++ KgSchemeUnlock(p_Scheme, intFlags); ++ } ++} ++ ++static void UpdateRequiredActionFlag(t_FmPcdKgScheme *p_Scheme, bool set) ++{ ++ /* this routine is locked by the calling routine */ ++ ASSERT_COND(p_Scheme); ++ ASSERT_COND(p_Scheme->valid); ++ ++ if (set) ++ p_Scheme->requiredActionFlag = TRUE; ++ else ++ { ++ p_Scheme->requiredAction = 0; ++ p_Scheme->requiredActionFlag = FALSE; ++ } ++} ++ ++static t_Error KgWriteSp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint32_t spReg, bool add) ++{ ++ struct fman_kg_regs *p_KgRegs; ++ ++ uint32_t tmpKgarReg = 0, intFlags; ++ t_Error err = E_OK; ++ ++ /* The calling routine had locked the port, so for each port only one core can access ++ * (so we don't need a lock here) */ ++ ++ if (p_FmPcd->h_Hc) ++ return FmHcKgWriteSp(p_FmPcd->h_Hc, hardwarePortId, spReg, add); ++ ++ p_KgRegs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; ++ ++ tmpKgarReg = FmPcdKgBuildReadPortSchemeBindActionReg(hardwarePortId); ++ /* lock a common KG reg */ ++ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); ++ err = WriteKgarWait(p_FmPcd, tmpKgarReg); ++ if (err) ++ { ++ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ fman_kg_write_sp(p_KgRegs, spReg, add); ++ ++ tmpKgarReg = FmPcdKgBuildWritePortSchemeBindActionReg(hardwarePortId); ++ ++ err = WriteKgarWait(p_FmPcd, tmpKgarReg); ++ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); ++ return err; ++} ++ ++static t_Error KgWriteCpp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint32_t cppReg) ++{ ++ struct fman_kg_regs *p_KgRegs; ++ uint32_t tmpKgarReg, intFlags; ++ t_Error err; ++ ++ p_KgRegs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; ++ ++ if (p_FmPcd->h_Hc) ++ { ++ err = FmHcKgWriteCpp(p_FmPcd->h_Hc, hardwarePortId, cppReg); ++ return err; ++ } ++ ++ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); ++ fman_kg_write_cpp(p_KgRegs, cppReg); ++ tmpKgarReg = FmPcdKgBuildWritePortClsPlanBindActionReg(hardwarePortId); ++ err = WriteKgarWait(p_FmPcd, tmpKgarReg); ++ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); ++ ++ return err; ++} ++ ++static uint32_t BuildCppReg(t_FmPcd *p_FmPcd, uint8_t clsPlanGrpId) ++{ ++ uint32_t tmpKgpeCpp; ++ ++ tmpKgpeCpp = (uint32_t)(p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].baseEntry / 8); ++ tmpKgpeCpp |= (uint32_t)(((p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].sizeOfGrp / 8) - 1) << FM_KG_PE_CPP_MASK_SHIFT); ++ ++ return tmpKgpeCpp; ++} ++ ++static t_Error BindPortToClsPlanGrp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId) ++{ ++ uint32_t tmpKgpeCpp = 0; ++ ++ tmpKgpeCpp = BuildCppReg(p_FmPcd, clsPlanGrpId); ++ return KgWriteCpp(p_FmPcd, hardwarePortId, tmpKgpeCpp); ++} ++ ++static void UnbindPortToClsPlanGrp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId) ++{ ++ KgWriteCpp(p_FmPcd, hardwarePortId, 0); ++} ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++static uint32_t __attribute__((unused)) ReadClsPlanBlockActionReg(uint8_t grpId) ++{ ++ return (uint32_t)(FM_KG_KGAR_GO | ++ FM_KG_KGAR_READ | ++ FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY | ++ DUMMY_PORT_ID | ++ ((uint32_t)grpId << FM_PCD_KG_KGAR_NUM_SHIFT) | ++ FM_PCD_KG_KGAR_WSEL_MASK); ++ ++ /* if we ever want to write 1 by 1, use: ++ sel = (uint8_t)(0x01 << (7- (entryId % CLS_PLAN_NUM_PER_GRP))); ++ */ ++} ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++static void PcdKgErrorException(t_Handle h_FmPcd) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ uint32_t event,schemeIndexes = 0, index = 0; ++ struct fman_kg_regs *p_KgRegs; ++ ++ ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); ++ p_KgRegs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; ++ fman_kg_get_event(p_KgRegs, &event, &schemeIndexes); ++ ++ if (event & FM_EX_KG_DOUBLE_ECC) ++ p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC); ++ if (event & FM_EX_KG_KEYSIZE_OVERFLOW) ++ { ++ if (schemeIndexes) ++ { ++ while (schemeIndexes) ++ { ++ if (schemeIndexes & 0x1) ++ p_FmPcd->f_FmPcdIndexedException(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW, (uint16_t)(31 - index)); ++ schemeIndexes >>= 1; ++ index+=1; ++ } ++ } ++ else /* this should happen only when interrupt is forced. */ ++ p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW); ++ } ++} ++ ++static t_Error KgInitGuest(t_FmPcd *p_FmPcd) ++{ ++ t_Error err = E_OK; ++ t_FmPcdIpcKgSchemesParams kgAlloc; ++ uint32_t replyLength; ++ t_FmPcdIpcReply reply; ++ t_FmPcdIpcMsg msg; ++ ++ ASSERT_COND(p_FmPcd->guestId != NCSW_MASTER_ID); ++ ++ /* in GUEST_PARTITION, we use the IPC */ ++ memset(&reply, 0, sizeof(reply)); ++ memset(&msg, 0, sizeof(msg)); ++ memset(&kgAlloc, 0, sizeof(t_FmPcdIpcKgSchemesParams)); ++ kgAlloc.numOfSchemes = p_FmPcd->p_FmPcdKg->numOfSchemes; ++ kgAlloc.guestId = p_FmPcd->guestId; ++ msg.msgId = FM_PCD_ALLOC_KG_SCHEMES; ++ memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc)); ++ replyLength = sizeof(uint32_t) + p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t); ++ if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) + sizeof(kgAlloc), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ if (replyLength != (sizeof(uint32_t) + p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t))) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ memcpy(p_FmPcd->p_FmPcdKg->schemesIds, (uint8_t*)(reply.replyBody),p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t)); ++ ++ return (t_Error)reply.error; ++} ++ ++static t_Error KgInitMaster(t_FmPcd *p_FmPcd) ++{ ++ t_Error err = E_OK; ++ struct fman_kg_regs *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; ++ ++ ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); ++ ++ if (p_FmPcd->exceptions & FM_EX_KG_DOUBLE_ECC) ++ FmEnableRamsEcc(p_FmPcd->h_Fm); ++ ++ fman_kg_init(p_Regs, p_FmPcd->exceptions, GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd)); ++ ++ /* register even if no interrupts enabled, to allow future enablement */ ++ FmRegisterIntr(p_FmPcd->h_Fm, ++ e_FM_MOD_KG, ++ 0, ++ e_FM_INTR_TYPE_ERR, ++ PcdKgErrorException, ++ p_FmPcd); ++ ++ fman_kg_enable_scheme_interrupts(p_Regs); ++ ++ if (p_FmPcd->p_FmPcdKg->numOfSchemes) ++ { ++ err = FmPcdKgAllocSchemes(p_FmPcd, ++ p_FmPcd->p_FmPcdKg->numOfSchemes, ++ p_FmPcd->guestId, ++ p_FmPcd->p_FmPcdKg->schemesIds); ++ if (err) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ return E_OK; ++} ++ ++static void ValidateSchemeSw(t_FmPcdKgScheme *p_Scheme) ++{ ++ ASSERT_COND(!p_Scheme->valid); ++ if (p_Scheme->netEnvId != ILLEGAL_NETENV) ++ FmPcdIncNetEnvOwners(p_Scheme->h_FmPcd, p_Scheme->netEnvId); ++ p_Scheme->valid = TRUE; ++} ++ ++static t_Error InvalidateSchemeSw(t_FmPcdKgScheme *p_Scheme) ++{ ++ if (p_Scheme->owners) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Trying to delete a scheme that has ports bound to")); ++ ++ if (p_Scheme->netEnvId != ILLEGAL_NETENV) ++ FmPcdDecNetEnvOwners(p_Scheme->h_FmPcd, p_Scheme->netEnvId); ++ p_Scheme->valid = FALSE; ++ ++ return E_OK; ++} ++ ++static t_Error BuildSchemeRegs(t_FmPcdKgScheme *p_Scheme, ++ t_FmPcdKgSchemeParams *p_SchemeParams, ++ struct fman_kg_scheme_regs *p_SchemeRegs) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)(p_Scheme->h_FmPcd); ++ uint32_t grpBits = 0; ++ uint8_t grpBase; ++ bool direct=TRUE, absolute=FALSE; ++ uint16_t profileId=0, numOfProfiles=0, relativeProfileId; ++ t_Error err = E_OK; ++ int i = 0; ++ t_NetEnvParams netEnvParams; ++ uint32_t tmpReg, fqbTmp = 0, ppcTmp = 0, selectTmp, maskTmp, knownTmp, genTmp; ++ t_FmPcdKgKeyExtractAndHashParams *p_KeyAndHash = NULL; ++ uint8_t j, curr, idx; ++ uint8_t id, shift=0, code=0, offset=0, size=0; ++ t_FmPcdExtractEntry *p_Extract = NULL; ++ t_FmPcdKgExtractedOrParams *p_ExtractOr; ++ bool generic = FALSE; ++ t_KnownFieldsMasks bitMask; ++ e_FmPcdKgExtractDfltSelect swDefault = (e_FmPcdKgExtractDfltSelect)0; ++ t_FmPcdKgSchemesExtracts *p_LocalExtractsArray; ++ uint8_t numOfSwDefaults = 0; ++ t_FmPcdKgExtractDflt swDefaults[NUM_OF_SW_DEFAULTS]; ++ uint8_t currGenId = 0; ++ ++ memset(swDefaults, 0, NUM_OF_SW_DEFAULTS*sizeof(t_FmPcdKgExtractDflt)); ++ memset(p_SchemeRegs, 0, sizeof(struct fman_kg_scheme_regs)); ++ ++ if (p_SchemeParams->netEnvParams.numOfDistinctionUnits > FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("numOfDistinctionUnits should not exceed %d", FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)); ++ ++ /* by netEnv parameters, get match vector */ ++ if (!p_SchemeParams->alwaysDirect) ++ { ++ p_Scheme->netEnvId = FmPcdGetNetEnvId(p_SchemeParams->netEnvParams.h_NetEnv); ++ netEnvParams.netEnvId = p_Scheme->netEnvId; ++ netEnvParams.numOfDistinctionUnits = p_SchemeParams->netEnvParams.numOfDistinctionUnits; ++ memcpy(netEnvParams.unitIds, p_SchemeParams->netEnvParams.unitIds, (sizeof(uint8_t))*p_SchemeParams->netEnvParams.numOfDistinctionUnits); ++ err = PcdGetUnitsVector(p_FmPcd, &netEnvParams); ++ if (err) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ p_Scheme->matchVector = netEnvParams.vector; ++ } ++ else ++ { ++ p_Scheme->matchVector = SCHEME_ALWAYS_DIRECT; ++ p_Scheme->netEnvId = ILLEGAL_NETENV; ++ } ++ ++ if (p_SchemeParams->nextEngine == e_FM_PCD_INVALID) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next Engine of the scheme is not Valid")); ++ ++ if (p_SchemeParams->bypassFqidGeneration) ++ { ++#ifdef FM_KG_NO_BYPASS_FQID_GEN ++ if ((p_FmPcd->fmRevInfo.majorRev != 4) && (p_FmPcd->fmRevInfo.majorRev < 6)) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("bypassFqidGeneration.")); ++#endif /* FM_KG_NO_BYPASS_FQID_GEN */ ++ if (p_SchemeParams->baseFqid) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("baseFqid set for a scheme that does not generate an FQID")); ++ } ++ else ++ if (!p_SchemeParams->baseFqid) ++ DBG(WARNING, ("baseFqid is 0.")); ++ ++ if (p_SchemeParams->nextEngine == e_FM_PCD_PLCR) ++ { ++ direct = p_SchemeParams->kgNextEngineParams.plcrProfile.direct; ++ p_Scheme->directPlcr = direct; ++ absolute = (bool)(p_SchemeParams->kgNextEngineParams.plcrProfile.sharedProfile ? TRUE : FALSE); ++ if (!direct && absolute) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Indirect policing is not available when profile is shared.")); ++ ++ if (direct) ++ { ++ profileId = p_SchemeParams->kgNextEngineParams.plcrProfile.profileSelect.directRelativeProfileId; ++ numOfProfiles = 1; ++ } ++ else ++ { ++ profileId = p_SchemeParams->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase; ++ shift = p_SchemeParams->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.fqidOffsetShift; ++ numOfProfiles = p_SchemeParams->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.numOfProfiles; ++ } ++ } ++ ++ if (p_SchemeParams->nextEngine == e_FM_PCD_CC) ++ { ++#ifdef FM_KG_NO_BYPASS_PLCR_PROFILE_GEN ++ if ((p_SchemeParams->kgNextEngineParams.cc.plcrNext) && (p_SchemeParams->kgNextEngineParams.cc.bypassPlcrProfileGeneration)) ++ { ++ if ((p_FmPcd->fmRevInfo.majorRev != 4) && (p_FmPcd->fmRevInfo.majorRev < 6)) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("bypassPlcrProfileGeneration.")); ++ } ++#endif /* FM_KG_NO_BYPASS_PLCR_PROFILE_GEN */ ++ ++ err = FmPcdCcGetGrpParams(p_SchemeParams->kgNextEngineParams.cc.h_CcTree, ++ p_SchemeParams->kgNextEngineParams.cc.grpId, ++ &grpBits, ++ &grpBase); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ p_Scheme->ccUnits = grpBits; ++ ++ if ((p_SchemeParams->kgNextEngineParams.cc.plcrNext) && ++ (!p_SchemeParams->kgNextEngineParams.cc.bypassPlcrProfileGeneration)) ++ { ++ if (p_SchemeParams->kgNextEngineParams.cc.plcrProfile.sharedProfile) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Shared profile may not be used after Coarse classification.")); ++ absolute = FALSE; ++ direct = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.direct; ++ if (direct) ++ { ++ profileId = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.profileSelect.directRelativeProfileId; ++ numOfProfiles = 1; ++ } ++ else ++ { ++ profileId = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase; ++ shift = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.fqidOffsetShift; ++ numOfProfiles = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.numOfProfiles; ++ } ++ } ++ } ++ ++ /* if policer is used directly after KG, or after CC */ ++ if ((p_SchemeParams->nextEngine == e_FM_PCD_PLCR) || ++ ((p_SchemeParams->nextEngine == e_FM_PCD_CC) && ++ (p_SchemeParams->kgNextEngineParams.cc.plcrNext) && ++ (!p_SchemeParams->kgNextEngineParams.cc.bypassPlcrProfileGeneration))) ++ { ++ /* if private policer profile, it may be uninitialized yet, therefore no checks are done at this stage */ ++ if (absolute) ++ { ++ /* for absolute direct policy only, */ ++ relativeProfileId = profileId; ++ err = FmPcdPlcrGetAbsoluteIdByProfileParams((t_Handle)p_FmPcd,e_FM_PCD_PLCR_SHARED,NULL, relativeProfileId, &profileId); ++ if (err) ++ RETURN_ERROR(MAJOR, err, ("Shared profile not valid offset")); ++ if (!FmPcdPlcrIsProfileValid(p_FmPcd, profileId)) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Shared profile not valid.")); ++ p_Scheme->relativeProfileId = profileId; ++ } ++ else ++ { ++ /* save relative profile id's for later check */ ++ p_Scheme->nextRelativePlcrProfile = TRUE; ++ p_Scheme->relativeProfileId = profileId; ++ p_Scheme->numOfProfiles = numOfProfiles; ++ } ++ } ++ else ++ { ++ /* if policer is NOT going to be used after KG at all than if bypassFqidGeneration ++ is set, we do not need numOfUsedExtractedOrs and hashDistributionNumOfFqids */ ++ if (p_SchemeParams->bypassFqidGeneration && p_SchemeParams->numOfUsedExtractedOrs) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("numOfUsedExtractedOrs is set in a scheme that does not generate FQID or policer profile ID")); ++ if (p_SchemeParams->bypassFqidGeneration && ++ p_SchemeParams->useHash && ++ p_SchemeParams->keyExtractAndHashParams.hashDistributionNumOfFqids) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("hashDistributionNumOfFqids is set in a scheme that does not generate FQID or policer profile ID")); ++ } ++ ++ /* configure all 21 scheme registers */ ++ tmpReg = KG_SCH_MODE_EN; ++ switch (p_SchemeParams->nextEngine) ++ { ++ case (e_FM_PCD_PLCR): ++ /* add to mode register - NIA */ ++ tmpReg |= KG_SCH_MODE_NIA_PLCR; ++ tmpReg |= NIA_ENG_PLCR; ++ tmpReg |= (uint32_t)(p_SchemeParams->kgNextEngineParams.plcrProfile.sharedProfile ? NIA_PLCR_ABSOLUTE:0); ++ /* initialize policer profile command - */ ++ /* configure kgse_ppc */ ++ if (direct) ++ /* use profileId as base, other fields are 0 */ ++ p_SchemeRegs->kgse_ppc = (uint32_t)profileId; ++ else ++ { ++ if (shift > MAX_PP_SHIFT) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fqidOffsetShift may not be larger than %d", MAX_PP_SHIFT)); ++ ++ if (!numOfProfiles || !POWER_OF_2(numOfProfiles)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfProfiles must not be 0 and must be a power of 2")); ++ ++ ppcTmp = ((uint32_t)shift << KG_SCH_PP_SHIFT_HIGH_SHIFT) & KG_SCH_PP_SHIFT_HIGH; ++ ppcTmp |= ((uint32_t)shift << KG_SCH_PP_SHIFT_LOW_SHIFT) & KG_SCH_PP_SHIFT_LOW; ++ ppcTmp |= ((uint32_t)(numOfProfiles-1) << KG_SCH_PP_MASK_SHIFT); ++ ppcTmp |= (uint32_t)profileId; ++ ++ p_SchemeRegs->kgse_ppc = ppcTmp; ++ } ++ break; ++ case (e_FM_PCD_CC): ++ /* mode reg - define NIA */ ++ tmpReg |= (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC); ++ ++ p_SchemeRegs->kgse_ccbs = grpBits; ++ tmpReg |= (uint32_t)(grpBase << KG_SCH_MODE_CCOBASE_SHIFT); ++ ++ if (p_SchemeParams->kgNextEngineParams.cc.plcrNext) ++ { ++ if (!p_SchemeParams->kgNextEngineParams.cc.bypassPlcrProfileGeneration) ++ { ++ /* find out if absolute or relative */ ++ if (absolute) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("It is illegal to request a shared profile in a scheme that is in a KG->CC->PLCR flow")); ++ if (direct) ++ { ++ /* mask = 0, base = directProfileId */ ++ p_SchemeRegs->kgse_ppc = (uint32_t)profileId; ++ } ++ else ++ { ++ if (shift > MAX_PP_SHIFT) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fqidOffsetShift may not be larger than %d", MAX_PP_SHIFT)); ++ if (!numOfProfiles || !POWER_OF_2(numOfProfiles)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfProfiles must not be 0 and must be a power of 2")); ++ ++ ppcTmp = ((uint32_t)shift << KG_SCH_PP_SHIFT_HIGH_SHIFT) & KG_SCH_PP_SHIFT_HIGH; ++ ppcTmp |= ((uint32_t)shift << KG_SCH_PP_SHIFT_LOW_SHIFT) & KG_SCH_PP_SHIFT_LOW; ++ ppcTmp |= ((uint32_t)(numOfProfiles-1) << KG_SCH_PP_MASK_SHIFT); ++ ppcTmp |= (uint32_t)profileId; ++ ++ p_SchemeRegs->kgse_ppc = ppcTmp; ++ } ++ } ++ } ++ break; ++ case (e_FM_PCD_DONE): ++ if (p_SchemeParams->kgNextEngineParams.doneAction == e_FM_PCD_DROP_FRAME) ++ tmpReg |= GET_NIA_BMI_AC_DISCARD_FRAME(p_FmPcd); ++ else ++ tmpReg |= GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd); ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Next engine not supported")); ++ } ++ p_SchemeRegs->kgse_mode = tmpReg; ++ ++ p_SchemeRegs->kgse_mv = p_Scheme->matchVector; ++ ++#if (DPAA_VERSION >= 11) ++ if (p_SchemeParams->overrideStorageProfile) ++ { ++ p_SchemeRegs->kgse_om |= KG_SCH_OM_VSPE; ++ ++ if (p_SchemeParams->storageProfile.direct) ++ { ++ profileId = p_SchemeParams->storageProfile.profileSelect.directRelativeProfileId; ++ shift = 0; ++ numOfProfiles = 1; ++ } ++ else ++ { ++ profileId = p_SchemeParams->storageProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase; ++ shift = p_SchemeParams->storageProfile.profileSelect.indirectProfile.fqidOffsetShift; ++ numOfProfiles = p_SchemeParams->storageProfile.profileSelect.indirectProfile.numOfProfiles; ++ } ++ if (shift > MAX_SP_SHIFT) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fqidOffsetShift may not be larger than %d", MAX_SP_SHIFT)); ++ ++ if (!numOfProfiles || !POWER_OF_2(numOfProfiles)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfProfiles must not be 0 and must be a power of 2")); ++ ++ tmpReg = (uint32_t)shift << KG_SCH_VSP_SHIFT; ++ tmpReg |= ((uint32_t)(numOfProfiles-1) << KG_SCH_VSP_MASK_SHIFT); ++ tmpReg |= (uint32_t)profileId; ++ ++ ++ p_SchemeRegs->kgse_vsp = tmpReg; ++ ++ p_Scheme->vspe = TRUE; ++ ++ } ++ else ++ p_SchemeRegs->kgse_vsp = KG_SCH_VSP_NO_KSP_EN; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ if (p_SchemeParams->useHash) ++ { ++ p_KeyAndHash = &p_SchemeParams->keyExtractAndHashParams; ++ ++ if (p_KeyAndHash->numOfUsedExtracts >= FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfUsedExtracts out of range")); ++ ++ /* configure kgse_dv0 */ ++ p_SchemeRegs->kgse_dv0 = p_KeyAndHash->privateDflt0; ++ ++ /* configure kgse_dv1 */ ++ p_SchemeRegs->kgse_dv1 = p_KeyAndHash->privateDflt1; ++ ++ if (!p_SchemeParams->bypassFqidGeneration) ++ { ++ if (!p_KeyAndHash->hashDistributionNumOfFqids || !POWER_OF_2(p_KeyAndHash->hashDistributionNumOfFqids)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashDistributionNumOfFqids must not be 0 and must be a power of 2")); ++ if ((p_KeyAndHash->hashDistributionNumOfFqids-1) & p_SchemeParams->baseFqid) ++ DBG(WARNING, ("baseFqid unaligned. Distribution may result in less than hashDistributionNumOfFqids queues.")); ++ } ++ ++ /* configure kgse_ekdv */ ++ tmpReg = 0; ++ for ( i=0 ;inumOfUsedDflts ; i++) ++ { ++ switch (p_KeyAndHash->dflts[i].type) ++ { ++ case (e_FM_PCD_KG_MAC_ADDR): ++ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_MAC_ADDR_SHIFT); ++ break; ++ case (e_FM_PCD_KG_TCI): ++ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_TCI_SHIFT); ++ break; ++ case (e_FM_PCD_KG_ENET_TYPE): ++ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_ENET_TYPE_SHIFT); ++ break; ++ case (e_FM_PCD_KG_PPP_SESSION_ID): ++ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PPP_SESSION_ID_SHIFT); ++ break; ++ case (e_FM_PCD_KG_PPP_PROTOCOL_ID): ++ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PPP_PROTOCOL_ID_SHIFT); ++ break; ++ case (e_FM_PCD_KG_MPLS_LABEL): ++ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_MPLS_LABEL_SHIFT); ++ break; ++ case (e_FM_PCD_KG_IP_ADDR): ++ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IP_ADDR_SHIFT); ++ break; ++ case (e_FM_PCD_KG_PROTOCOL_TYPE): ++ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PROTOCOL_TYPE_SHIFT); ++ break; ++ case (e_FM_PCD_KG_IP_TOS_TC): ++ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IP_TOS_TC_SHIFT); ++ break; ++ case (e_FM_PCD_KG_IPV6_FLOW_LABEL): ++ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_L4_PORT_SHIFT); ++ break; ++ case (e_FM_PCD_KG_IPSEC_SPI): ++ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IPSEC_SPI_SHIFT); ++ break; ++ case (e_FM_PCD_KG_L4_PORT): ++ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_L4_PORT_SHIFT); ++ break; ++ case (e_FM_PCD_KG_TCP_FLAG): ++ tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_TCP_FLAG_SHIFT); ++ break; ++ case (e_FM_PCD_KG_GENERIC_FROM_DATA): ++ swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_FROM_DATA; ++ swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect; ++ numOfSwDefaults ++; ++ break; ++ case (e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V): ++ swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V; ++ swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect; ++ numOfSwDefaults ++; ++ break; ++ case (e_FM_PCD_KG_GENERIC_NOT_FROM_DATA): ++ swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_NOT_FROM_DATA; ++ swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect; ++ numOfSwDefaults ++; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ } ++ p_SchemeRegs->kgse_ekdv = tmpReg; ++ ++ p_LocalExtractsArray = (t_FmPcdKgSchemesExtracts *)XX_Malloc(sizeof(t_FmPcdKgSchemesExtracts)); ++ if (!p_LocalExtractsArray) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("No memory")); ++ ++ /* configure kgse_ekfc and kgse_gec */ ++ knownTmp = 0; ++ for ( i=0 ;inumOfUsedExtracts ; i++) ++ { ++ p_Extract = &p_KeyAndHash->extractArray[i]; ++ switch (p_Extract->type) ++ { ++ case (e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO): ++ knownTmp |= KG_SCH_KN_PORT_ID; ++ /* save in driver structure */ ++ p_LocalExtractsArray->extractsArray[i].id = GetKnownFieldId(KG_SCH_KN_PORT_ID); ++ p_LocalExtractsArray->extractsArray[i].known = TRUE; ++ break; ++ case (e_FM_PCD_EXTRACT_BY_HDR): ++ switch (p_Extract->extractByHdr.hdr) ++ { ++#if (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) ++ case (HEADER_TYPE_UDP_LITE): ++ p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP; ++ break; ++#endif /* (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ ++ case (HEADER_TYPE_UDP_ENCAP_ESP): ++ switch (p_Extract->extractByHdr.type) ++ { ++ case (e_FM_PCD_EXTRACT_FROM_HDR): ++ /* case where extraction from ESP only */ ++ if (p_Extract->extractByHdr.extractByHdrType.fromHdr.offset >= UDP_HEADER_SIZE) ++ { ++ p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_Scheme->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP); ++ p_Extract->extractByHdr.extractByHdrType.fromHdr.offset -= UDP_HEADER_SIZE; ++ p_Extract->extractByHdr.ignoreProtocolValidation = TRUE; ++ } ++ else ++ { ++ p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP; ++ p_Extract->extractByHdr.ignoreProtocolValidation = FALSE; ++ } ++ break; ++ case (e_FM_PCD_EXTRACT_FROM_FIELD): ++ switch (p_Extract->extractByHdr.extractByHdrType.fromField.field.udpEncapEsp) ++ { ++ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC): ++ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST): ++ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN): ++ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM): ++ p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP; ++ break; ++ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI): ++ p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR; ++ p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_Scheme->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP); ++ /*p_Extract->extractByHdr.extractByHdrType.fromField.offset += ESP_SPI_OFFSET;*/ ++ p_Extract->extractByHdr.ignoreProtocolValidation = TRUE; ++ break; ++ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM): ++ p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR; ++ p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_Scheme->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP); ++ p_Extract->extractByHdr.extractByHdrType.fromField.offset += ESP_SEQ_NUM_OFFSET; ++ p_Extract->extractByHdr.ignoreProtocolValidation = TRUE; ++ break; ++ } ++ break; ++ case (e_FM_PCD_EXTRACT_FULL_FIELD): ++ switch (p_Extract->extractByHdr.extractByHdrType.fullField.udpEncapEsp) ++ { ++ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC): ++ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST): ++ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN): ++ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM): ++ p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP; ++ break; ++ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI): ++ p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR; ++ p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_Scheme->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP); ++ p_Extract->extractByHdr.extractByHdrType.fromHdr.size = ESP_SPI_SIZE; ++ p_Extract->extractByHdr.extractByHdrType.fromHdr.offset = ESP_SPI_OFFSET; ++ p_Extract->extractByHdr.ignoreProtocolValidation = TRUE; ++ break; ++ case (NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM): ++ p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR; ++ p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_Scheme->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP); ++ p_Extract->extractByHdr.extractByHdrType.fromHdr.size = ESP_SEQ_NUM_SIZE; ++ p_Extract->extractByHdr.extractByHdrType.fromHdr.offset = ESP_SEQ_NUM_OFFSET; ++ p_Extract->extractByHdr.ignoreProtocolValidation = TRUE; ++ break; ++ } ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++ switch (p_Extract->extractByHdr.type) ++ { ++ case (e_FM_PCD_EXTRACT_FROM_HDR): ++ generic = TRUE; ++ /* get the header code for the generic extract */ ++ code = GetGenHdrCode(p_Extract->extractByHdr.hdr, p_Extract->extractByHdr.hdrIndex, p_Extract->extractByHdr.ignoreProtocolValidation); ++ /* set generic register fields */ ++ offset = p_Extract->extractByHdr.extractByHdrType.fromHdr.offset; ++ size = p_Extract->extractByHdr.extractByHdrType.fromHdr.size; ++ break; ++ case (e_FM_PCD_EXTRACT_FROM_FIELD): ++ generic = TRUE; ++ /* get the field code for the generic extract */ ++ code = GetGenFieldCode(p_Extract->extractByHdr.hdr, ++ p_Extract->extractByHdr.extractByHdrType.fromField.field, p_Extract->extractByHdr.ignoreProtocolValidation,p_Extract->extractByHdr.hdrIndex); ++ offset = p_Extract->extractByHdr.extractByHdrType.fromField.offset; ++ size = p_Extract->extractByHdr.extractByHdrType.fromField.size; ++ break; ++ case (e_FM_PCD_EXTRACT_FULL_FIELD): ++ if (!p_Extract->extractByHdr.ignoreProtocolValidation) ++ { ++ /* if we have a known field for it - use it, otherwise use generic */ ++ bitMask = GetKnownProtMask(p_FmPcd, p_Extract->extractByHdr.hdr, p_Extract->extractByHdr.hdrIndex, ++ p_Extract->extractByHdr.extractByHdrType.fullField); ++ if (bitMask) ++ { ++ knownTmp |= bitMask; ++ /* save in driver structure */ ++ p_LocalExtractsArray->extractsArray[i].id = GetKnownFieldId(bitMask); ++ p_LocalExtractsArray->extractsArray[i].known = TRUE; ++ } ++ else ++ generic = TRUE; ++ } ++ else ++ generic = TRUE; ++ if (generic) ++ { ++ /* tmp - till we cover more headers under generic */ ++ XX_Free(p_LocalExtractsArray); ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Full header selection not supported")); ++ } ++ break; ++ default: ++ XX_Free(p_LocalExtractsArray); ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ break; ++ case (e_FM_PCD_EXTRACT_NON_HDR): ++ /* use generic */ ++ generic = TRUE; ++ offset = 0; ++ /* get the field code for the generic extract */ ++ code = GetGenCode(p_Extract->extractNonHdr.src, &offset); ++ offset += p_Extract->extractNonHdr.offset; ++ size = p_Extract->extractNonHdr.size; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ ++ if (generic) ++ { ++ /* set generic register fields */ ++ if (currGenId >= FM_KG_NUM_OF_GENERIC_REGS) ++ { ++ XX_Free(p_LocalExtractsArray); ++ RETURN_ERROR(MAJOR, E_FULL, ("Generic registers are fully used")); ++ } ++ if (!code) ++ { ++ XX_Free(p_LocalExtractsArray); ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG); ++ } ++ ++ genTmp = KG_SCH_GEN_VALID; ++ genTmp |= (uint32_t)(code << KG_SCH_GEN_HT_SHIFT); ++ genTmp |= offset; ++ if ((size > MAX_KG_SCH_SIZE) || (size < 1)) ++ { ++ XX_Free(p_LocalExtractsArray); ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal extraction (size out of range)")); ++ } ++ genTmp |= (uint32_t)((size - 1) << KG_SCH_GEN_SIZE_SHIFT); ++ swDefault = GetGenericSwDefault(swDefaults, numOfSwDefaults, code); ++ if (swDefault == e_FM_PCD_KG_DFLT_ILLEGAL) ++ DBG(WARNING, ("No sw default configured")); ++ else ++ genTmp |= swDefault << KG_SCH_GEN_DEF_SHIFT; ++ ++ genTmp |= KG_SCH_GEN_MASK; ++ p_SchemeRegs->kgse_gec[currGenId] = genTmp; ++ /* save in driver structure */ ++ p_LocalExtractsArray->extractsArray[i].id = currGenId++; ++ p_LocalExtractsArray->extractsArray[i].known = FALSE; ++ generic = FALSE; ++ } ++ } ++ p_SchemeRegs->kgse_ekfc = knownTmp; ++ ++ selectTmp = 0; ++ maskTmp = 0xFFFFFFFF; ++ /* configure kgse_bmch, kgse_bmcl and kgse_fqb */ ++ ++ if (p_KeyAndHash->numOfUsedMasks > FM_PCD_KG_NUM_OF_EXTRACT_MASKS) ++ { ++ XX_Free(p_LocalExtractsArray); ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Only %d masks supported", FM_PCD_KG_NUM_OF_EXTRACT_MASKS)); ++ } ++ for ( i=0 ;inumOfUsedMasks ; i++) ++ { ++ /* Get the relative id of the extract (for known 0-0x1f, for generic 0-7) */ ++ id = p_LocalExtractsArray->extractsArray[p_KeyAndHash->masks[i].extractArrayIndex].id; ++ /* Get the shift of the select field (depending on i) */ ++ GET_MASK_SEL_SHIFT(shift,i); ++ if (p_LocalExtractsArray->extractsArray[p_KeyAndHash->masks[i].extractArrayIndex].known) ++ selectTmp |= id << shift; ++ else ++ selectTmp |= (id + MASK_FOR_GENERIC_BASE_ID) << shift; ++ ++ /* Get the shift of the offset field (depending on i) - may ++ be in kgse_bmch or in kgse_fqb (depending on i) */ ++ GET_MASK_OFFSET_SHIFT(shift,i); ++ if (i<=1) ++ selectTmp |= p_KeyAndHash->masks[i].offset << shift; ++ else ++ fqbTmp |= p_KeyAndHash->masks[i].offset << shift; ++ ++ /* Get the shift of the mask field (depending on i) */ ++ GET_MASK_SHIFT(shift,i); ++ /* pass all bits */ ++ maskTmp |= KG_SCH_BITMASK_MASK << shift; ++ /* clear bits that need masking */ ++ maskTmp &= ~(0xFF << shift) ; ++ /* set mask bits */ ++ maskTmp |= (p_KeyAndHash->masks[i].mask << shift) ; ++ } ++ p_SchemeRegs->kgse_bmch = selectTmp; ++ p_SchemeRegs->kgse_bmcl = maskTmp; ++ /* kgse_fqb will be written t the end of the routine */ ++ ++ /* configure kgse_hc */ ++ if (p_KeyAndHash->hashShift > MAX_HASH_SHIFT) ++ { ++ XX_Free(p_LocalExtractsArray); ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashShift must not be larger than %d", MAX_HASH_SHIFT)); ++ } ++ if (p_KeyAndHash->hashDistributionFqidsShift > MAX_DIST_FQID_SHIFT) ++ { ++ XX_Free(p_LocalExtractsArray); ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashDistributionFqidsShift must not be larger than %d", MAX_DIST_FQID_SHIFT)); ++ } ++ ++ tmpReg = 0; ++ ++ tmpReg |= ((p_KeyAndHash->hashDistributionNumOfFqids - 1) << p_KeyAndHash->hashDistributionFqidsShift); ++ tmpReg |= p_KeyAndHash->hashShift << KG_SCH_HASH_CONFIG_SHIFT_SHIFT; ++ ++ if (p_KeyAndHash->symmetricHash) ++ { ++ if ((!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_MACSRC) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_MACDST)) || ++ (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPSRC1) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPDST1)) || ++ (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPSRC2) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPDST2)) || ++ (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_L4PSRC) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_L4PDST))) ++ { ++ XX_Free(p_LocalExtractsArray); ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("symmetricHash set but src/dest extractions missing")); ++ } ++ tmpReg |= KG_SCH_HASH_CONFIG_SYM; ++ } ++ p_SchemeRegs->kgse_hc = tmpReg; ++ ++ /* build the return array describing the order of the extractions */ ++ ++ /* the last currGenId places of the array ++ are for generic extracts that are always last. ++ We now sort for the calculation of the order of the known ++ extractions we sort the known extracts between orderedArray[0] and ++ orderedArray[p_KeyAndHash->numOfUsedExtracts - currGenId - 1]. ++ for the calculation of the order of the generic extractions we use: ++ num_of_generic - currGenId ++ num_of_known - p_KeyAndHash->numOfUsedExtracts - currGenId ++ first_generic_index = num_of_known */ ++ curr = 0; ++ for (i=0;inumOfUsedExtracts ; i++) ++ { ++ if (p_LocalExtractsArray->extractsArray[i].known) ++ { ++ ASSERT_COND(curr<(p_KeyAndHash->numOfUsedExtracts - currGenId)); ++ j = curr; ++ /* id is the extract id (port id = 0, mac src = 1 etc.). the value in the array is the original ++ index in the user's extractions array */ ++ /* we compare the id of the current extract with the id of the extract in the orderedArray[j-1] ++ location */ ++ while ((j > 0) && (p_LocalExtractsArray->extractsArray[i].id < ++ p_LocalExtractsArray->extractsArray[p_Scheme->orderedArray[j-1]].id)) ++ { ++ p_Scheme->orderedArray[j] = ++ p_Scheme->orderedArray[j-1]; ++ j--; ++ } ++ p_Scheme->orderedArray[j] = (uint8_t)i; ++ curr++; ++ } ++ else ++ { ++ /* index is first_generic_index + generic index (id) */ ++ idx = (uint8_t)(p_KeyAndHash->numOfUsedExtracts - currGenId + p_LocalExtractsArray->extractsArray[i].id); ++ ASSERT_COND(idx < FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY); ++ p_Scheme->orderedArray[idx]= (uint8_t)i; ++ } ++ } ++ XX_Free(p_LocalExtractsArray); ++ } ++ else ++ { ++ /* clear all unused registers: */ ++ p_SchemeRegs->kgse_ekfc = 0; ++ p_SchemeRegs->kgse_ekdv = 0; ++ p_SchemeRegs->kgse_bmch = 0; ++ p_SchemeRegs->kgse_bmcl = 0; ++ p_SchemeRegs->kgse_hc = 0; ++ p_SchemeRegs->kgse_dv0 = 0; ++ p_SchemeRegs->kgse_dv1 = 0; ++ } ++ ++ if (p_SchemeParams->bypassFqidGeneration) ++ p_SchemeRegs->kgse_hc |= KG_SCH_HASH_CONFIG_NO_FQID; ++ ++ /* configure kgse_spc */ ++ if ( p_SchemeParams->schemeCounter.update) ++ p_SchemeRegs->kgse_spc = p_SchemeParams->schemeCounter.value; ++ ++ ++ /* check that are enough generic registers */ ++ if (p_SchemeParams->numOfUsedExtractedOrs + currGenId > FM_KG_NUM_OF_GENERIC_REGS) ++ RETURN_ERROR(MAJOR, E_FULL, ("Generic registers are fully used")); ++ ++ /* extracted OR mask on Qid */ ++ for ( i=0 ;inumOfUsedExtractedOrs ; i++) ++ { ++ ++ p_Scheme->extractedOrs = TRUE; ++ /* configure kgse_gec[i] */ ++ p_ExtractOr = &p_SchemeParams->extractedOrs[i]; ++ switch (p_ExtractOr->type) ++ { ++ case (e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO): ++ code = KG_SCH_GEN_PARSE_RESULT_N_FQID; ++ offset = 0; ++ break; ++ case (e_FM_PCD_EXTRACT_BY_HDR): ++ /* get the header code for the generic extract */ ++ code = GetGenHdrCode(p_ExtractOr->extractByHdr.hdr, p_ExtractOr->extractByHdr.hdrIndex, p_ExtractOr->extractByHdr.ignoreProtocolValidation); ++ /* set generic register fields */ ++ offset = p_ExtractOr->extractionOffset; ++ break; ++ case (e_FM_PCD_EXTRACT_NON_HDR): ++ /* get the field code for the generic extract */ ++ offset = 0; ++ code = GetGenCode(p_ExtractOr->src, &offset); ++ offset += p_ExtractOr->extractionOffset; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ ++ /* set generic register fields */ ++ if (!code) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG); ++ genTmp = KG_SCH_GEN_EXTRACT_TYPE | KG_SCH_GEN_VALID; ++ genTmp |= (uint32_t)(code << KG_SCH_GEN_HT_SHIFT); ++ genTmp |= offset; ++ if (!!p_ExtractOr->bitOffsetInFqid == !!p_ExtractOr->bitOffsetInPlcrProfile) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, (" extracted byte must effect either FQID or Policer profile")); ++ ++ /************************************************************************************ ++ bitOffsetInFqid and bitOffsetInPolicerProfile are translated to rotate parameter ++ in the following way: ++ ++ Driver API and implementation: ++ ============================== ++ FQID: extracted OR byte may be shifted right 1-31 bits to effect parts of the FQID. ++ if shifted less than 8 bits, or more than 24 bits a mask is set on the bits that ++ are not overlapping FQID. ++ ------------------------ ++ | FQID (24) | ++ ------------------------ ++ -------- ++ | | extracted OR byte ++ -------- ++ ++ Policer Profile: extracted OR byte may be shifted right 1-15 bits to effect parts of the ++ PP id. Unless shifted exactly 8 bits to overlap the PP id, a mask is set on the bits that ++ are not overlapping PP id. ++ ++ -------- ++ | PP (8) | ++ -------- ++ -------- ++ | | extracted OR byte ++ -------- ++ ++ HW implementation ++ ================= ++ FQID and PP construct a 32 bit word in the way describe below. Extracted byte is located ++ as the highest byte of that word and may be rotated to effect any part os the FQID or ++ the PP. ++ ------------------------ -------- ++ | FQID (24) || PP (8) | ++ ------------------------ -------- ++ -------- ++ | | extracted OR byte ++ -------- ++ ++ ************************************************************************************/ ++ ++ if (p_ExtractOr->bitOffsetInFqid) ++ { ++ if (p_ExtractOr->bitOffsetInFqid > MAX_KG_SCH_FQID_BIT_OFFSET ) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal extraction (bitOffsetInFqid out of range)")); ++ if (p_ExtractOr->bitOffsetInFqid<8) ++ genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInFqid+24) << KG_SCH_GEN_SIZE_SHIFT); ++ else ++ genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInFqid-8) << KG_SCH_GEN_SIZE_SHIFT); ++ p_ExtractOr->mask &= GetExtractedOrMask(p_ExtractOr->bitOffsetInFqid, TRUE); ++ } ++ else /* effect policer profile */ ++ { ++ if (p_ExtractOr->bitOffsetInPlcrProfile > MAX_KG_SCH_PP_BIT_OFFSET ) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal extraction (bitOffsetInPlcrProfile out of range)")); ++ p_Scheme->bitOffsetInPlcrProfile = p_ExtractOr->bitOffsetInPlcrProfile; ++ genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInPlcrProfile+16) << KG_SCH_GEN_SIZE_SHIFT); ++ p_ExtractOr->mask &= GetExtractedOrMask(p_ExtractOr->bitOffsetInPlcrProfile, FALSE); ++ } ++ ++ genTmp |= (uint32_t)(p_ExtractOr->extractionOffset << KG_SCH_GEN_DEF_SHIFT); ++ /* clear bits that need masking */ ++ genTmp &= ~KG_SCH_GEN_MASK ; ++ /* set mask bits */ ++ genTmp |= (uint32_t)(p_ExtractOr->mask << KG_SCH_GEN_MASK_SHIFT); ++ p_SchemeRegs->kgse_gec[currGenId++] = genTmp; ++ ++ } ++ /* clear all unused GEC registers */ ++ for ( i=currGenId ;ikgse_gec[i] = 0; ++ ++ /* add base Qid for this scheme */ ++ /* add configuration for kgse_fqb */ ++ if (p_SchemeParams->baseFqid & ~0x00FFFFFF) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("baseFqid must be between 1 and 2^24-1")); ++ ++ fqbTmp |= p_SchemeParams->baseFqid; ++ p_SchemeRegs->kgse_fqb = fqbTmp; ++ ++ p_Scheme->nextEngine = p_SchemeParams->nextEngine; ++ p_Scheme->doneAction = p_SchemeParams->kgNextEngineParams.doneAction; ++ ++ return E_OK; ++} ++ ++ ++/*****************************************************************************/ ++/* Inter-module API routines */ ++/*****************************************************************************/ ++ ++t_Error FmPcdKgBuildClsPlanGrp(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_Grp, t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ t_FmPcdKgClsPlanGrp *p_ClsPlanGrp; ++ t_FmPcdIpcKgClsPlanParams kgAlloc; ++ t_Error err = E_OK; ++ uint32_t oredVectors = 0; ++ int i, j; ++ ++ /* this routine is protected by the calling routine ! */ ++ if (p_Grp->numOfOptions >= FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Too many classification plan basic options selected.")); ++ ++ /* find a new clsPlan group */ ++ for (i = 0; i < FM_MAX_NUM_OF_PORTS; i++) ++ if (!p_FmPcd->p_FmPcdKg->clsPlanGrps[i].used) ++ break; ++ if (i == FM_MAX_NUM_OF_PORTS) ++ RETURN_ERROR(MAJOR, E_FULL,("No classification plan groups available.")); ++ ++ p_FmPcd->p_FmPcdKg->clsPlanGrps[i].used = TRUE; ++ ++ p_Grp->clsPlanGrpId = (uint8_t)i; ++ ++ if (p_Grp->numOfOptions == 0) ++ p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId = (uint8_t)i; ++ ++ p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[i]; ++ p_ClsPlanGrp->netEnvId = p_Grp->netEnvId; ++ p_ClsPlanGrp->owners = 0; ++ FmPcdSetClsPlanGrpId(p_FmPcd, p_Grp->netEnvId, p_Grp->clsPlanGrpId); ++ if (p_Grp->numOfOptions != 0) ++ FmPcdIncNetEnvOwners(p_FmPcd, p_Grp->netEnvId); ++ ++ p_ClsPlanGrp->sizeOfGrp = (uint16_t)(1 << p_Grp->numOfOptions); ++ /* a minimal group of 8 is required */ ++ if (p_ClsPlanGrp->sizeOfGrp < CLS_PLAN_NUM_PER_GRP) ++ p_ClsPlanGrp->sizeOfGrp = CLS_PLAN_NUM_PER_GRP; ++ if (p_FmPcd->guestId == NCSW_MASTER_ID) ++ { ++ err = KgAllocClsPlanEntries(h_FmPcd, p_ClsPlanGrp->sizeOfGrp, p_FmPcd->guestId, &p_ClsPlanGrp->baseEntry); ++ ++ if (err) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, NO_MSG); ++ } ++ else ++ { ++ t_FmPcdIpcMsg msg; ++ uint32_t replyLength; ++ t_FmPcdIpcReply reply; ++ ++ /* in GUEST_PARTITION, we use the IPC, to also set a private driver group if required */ ++ memset(&reply, 0, sizeof(reply)); ++ memset(&msg, 0, sizeof(msg)); ++ memset(&kgAlloc, 0, sizeof(kgAlloc)); ++ kgAlloc.guestId = p_FmPcd->guestId; ++ kgAlloc.numOfClsPlanEntries = p_ClsPlanGrp->sizeOfGrp; ++ msg.msgId = FM_PCD_ALLOC_KG_CLSPLAN; ++ memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc)); ++ replyLength = (sizeof(uint32_t) + sizeof(p_ClsPlanGrp->baseEntry)); ++ if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) + sizeof(kgAlloc), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ if (replyLength != (sizeof(uint32_t) + sizeof(p_ClsPlanGrp->baseEntry))) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ if ((t_Error)reply.error != E_OK) ++ RETURN_ERROR(MINOR, (t_Error)reply.error, NO_MSG); ++ ++ p_ClsPlanGrp->baseEntry = *(uint8_t*)(reply.replyBody); ++ } ++ ++ /* build classification plan entries parameters */ ++ p_ClsPlanSet->baseEntry = p_ClsPlanGrp->baseEntry; ++ p_ClsPlanSet->numOfClsPlanEntries = p_ClsPlanGrp->sizeOfGrp; ++ ++ oredVectors = 0; ++ for (i = 0; inumOfOptions; i++) ++ { ++ oredVectors |= p_Grp->optVectors[i]; ++ /* save an array of used options - the indexes represent the power of 2 index */ ++ p_ClsPlanGrp->optArray[i] = p_Grp->options[i]; ++ } ++ /* set the classification plan relevant entries so that all bits ++ * relevant to the list of options is cleared ++ */ ++ for (j = 0; jsizeOfGrp; j++) ++ p_ClsPlanSet->vectors[j] = ~oredVectors; ++ ++ for (i = 0; inumOfOptions; i++) ++ { ++ /* option i got the place 2^i in the clsPlan array. all entries that ++ * have bit i set, should have the vector bit cleared. So each option ++ * has one location that it is exclusive (1,2,4,8...) and represent the ++ * presence of that option only, and other locations that represent a ++ * combination of options. ++ * e.g: ++ * If ethernet-BC is option 1 it gets entry 2 in the table. Entry 2 ++ * now represents a frame with ethernet-BC header - so the bit ++ * representing ethernet-BC should be set and all other option bits ++ * should be cleared. ++ * Entries 2,3,6,7,10... also have ethernet-BC and therefore have bit ++ * vector[1] set, but they also have other bits set: ++ * 3=1+2, options 0 and 1 ++ * 6=2+4, options 1 and 2 ++ * 7=1+2+4, options 0,1,and 2 ++ * 10=2+8, options 1 and 3 ++ * etc. ++ * */ ++ ++ /* now for each option (i), we set their bits in all entries (j) ++ * that contain bit 2^i. ++ */ ++ for (j = 0; jsizeOfGrp; j++) ++ { ++ if (j & (1<vectors[j] |= p_Grp->optVectors[i]; ++ } ++ } ++ ++ return E_OK; ++} ++ ++void FmPcdKgDestroyClsPlanGrp(t_Handle h_FmPcd, uint8_t grpId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ t_FmPcdIpcKgClsPlanParams kgAlloc; ++ t_Error err; ++ t_FmPcdIpcMsg msg; ++ uint32_t replyLength; ++ t_FmPcdIpcReply reply; ++ ++ /* check that no port is bound to this clsPlan */ ++ if (p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].owners) ++ { ++ REPORT_ERROR(MINOR, E_INVALID_STATE, ("Trying to delete a clsPlan grp that has ports bound to")); ++ return; ++ } ++ ++ FmPcdSetClsPlanGrpId(p_FmPcd, p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].netEnvId, ILLEGAL_CLS_PLAN); ++ ++ if (grpId == p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId) ++ p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId = ILLEGAL_CLS_PLAN; ++ else ++ FmPcdDecNetEnvOwners(p_FmPcd, p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].netEnvId); ++ ++ /* free blocks */ ++ if (p_FmPcd->guestId == NCSW_MASTER_ID) ++ KgFreeClsPlanEntries(h_FmPcd, ++ p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].sizeOfGrp, ++ p_FmPcd->guestId, ++ p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].baseEntry); ++ else /* in GUEST_PARTITION, we use the IPC, to also set a private driver group if required */ ++ { ++ memset(&reply, 0, sizeof(reply)); ++ memset(&msg, 0, sizeof(msg)); ++ kgAlloc.guestId = p_FmPcd->guestId; ++ kgAlloc.numOfClsPlanEntries = p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].sizeOfGrp; ++ kgAlloc.clsPlanBase = p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].baseEntry; ++ msg.msgId = FM_PCD_FREE_KG_CLSPLAN; ++ memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc)); ++ replyLength = sizeof(uint32_t); ++ err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) + sizeof(kgAlloc), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ { ++ REPORT_ERROR(MINOR, err, NO_MSG); ++ return; ++ } ++ if (replyLength != sizeof(uint32_t)) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ return; ++ } ++ if ((t_Error)reply.error != E_OK) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Free KG clsPlan failed")); ++ return; ++ } ++ } ++ ++ /* clear clsPlan driver structure */ ++ memset(&p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId], 0, sizeof(t_FmPcdKgClsPlanGrp)); ++} ++ ++t_Error FmPcdKgBuildBindPortToSchemes(t_Handle h_FmPcd, t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort, uint32_t *p_SpReg, bool add) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint32_t j, schemesPerPortVector = 0; ++ t_FmPcdKgScheme *p_Scheme; ++ uint8_t i, relativeSchemeId; ++ uint32_t tmp, walking1Mask; ++ uint8_t swPortIndex = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); ++ ++ /* for each scheme */ ++ for (i = 0; inumOfSchemes; i++) ++ { ++ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, p_BindPort->schemesIds[i]); ++ if (relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES) ++ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); ++ ++ if (add) ++ { ++ p_Scheme = &p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId]; ++ if (!FmPcdKgIsSchemeValidSw(p_Scheme)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Requested scheme is invalid.")); ++ /* check netEnvId of the port against the scheme netEnvId */ ++ if ((p_Scheme->netEnvId != p_BindPort->netEnvId) && (p_Scheme->netEnvId != ILLEGAL_NETENV)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Port may not be bound to requested scheme - differ in netEnvId")); ++ ++ /* if next engine is private port policer profile, we need to check that it is valid */ ++ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, p_BindPort->hardwarePortId); ++ if (p_Scheme->nextRelativePlcrProfile) ++ { ++ for (j = 0;jnumOfProfiles;j++) ++ { ++ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].h_FmPort); ++ if (p_Scheme->relativeProfileId+j >= p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Relative profile not in range")); ++ if (!FmPcdPlcrIsProfileValid(p_FmPcd, (uint16_t)(p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase + p_Scheme->relativeProfileId + j))) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Relative profile not valid.")); ++ } ++ } ++ if (!p_BindPort->useClsPlan) ++ { ++ /* This check may be redundant as port is a assigned to the whole NetEnv */ ++ ++ /* if this port does not use clsPlan, it may not be bound to schemes with units that contain ++ cls plan options. Schemes that are used only directly, should not be checked. ++ it also may not be bound to schemes that go to CC with units that are options - so we OR ++ the match vector and the grpBits (= ccUnits) */ ++ if ((p_Scheme->matchVector != SCHEME_ALWAYS_DIRECT) || p_Scheme->ccUnits) ++ { ++ uint8_t netEnvId; ++ walking1Mask = 0x80000000; ++ netEnvId = (p_Scheme->netEnvId == ILLEGAL_NETENV)? p_BindPort->netEnvId:p_Scheme->netEnvId; ++ tmp = (p_Scheme->matchVector == SCHEME_ALWAYS_DIRECT)? 0:p_Scheme->matchVector; ++ tmp |= p_Scheme->ccUnits; ++ while (tmp) ++ { ++ if (tmp & walking1Mask) ++ { ++ tmp &= ~walking1Mask; ++ if (!PcdNetEnvIsUnitWithoutOpts(p_FmPcd, netEnvId, walking1Mask)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Port (without clsPlan) may not be bound to requested scheme - uses clsPlan options")); ++ } ++ walking1Mask >>= 1; ++ } ++ } ++ } ++ } ++ /* build vector */ ++ schemesPerPortVector |= 1 << (31 - p_BindPort->schemesIds[i]); ++ } ++ ++ *p_SpReg = schemesPerPortVector; ++ ++ return E_OK; ++} ++ ++t_Error FmPcdKgBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint32_t spReg; ++ t_Error err = E_OK; ++ ++ err = FmPcdKgBuildBindPortToSchemes(h_FmPcd, p_SchemeBind, &spReg, TRUE); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ err = KgWriteSp(p_FmPcd, p_SchemeBind->hardwarePortId, spReg, TRUE); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ IncSchemeOwners(p_FmPcd, p_SchemeBind); ++ ++ return E_OK; ++} ++ ++t_Error FmPcdKgUnbindPortToSchemes(t_Handle h_FmPcd, t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint32_t spReg; ++ t_Error err = E_OK; ++ ++ err = FmPcdKgBuildBindPortToSchemes(p_FmPcd, p_SchemeBind, &spReg, FALSE); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ err = KgWriteSp(p_FmPcd, p_SchemeBind->hardwarePortId, spReg, FALSE); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ DecSchemeOwners(p_FmPcd, p_SchemeBind); ++ ++ return E_OK; ++} ++ ++bool FmPcdKgIsSchemeValidSw(t_Handle h_Scheme) ++{ ++ t_FmPcdKgScheme *p_Scheme = (t_FmPcdKgScheme*)h_Scheme; ++ ++ return p_Scheme->valid; ++} ++ ++bool KgIsSchemeAlwaysDirect(t_Handle h_FmPcd, uint8_t schemeId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ if (p_FmPcd->p_FmPcdKg->schemes[schemeId].matchVector == SCHEME_ALWAYS_DIRECT) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++t_Error FmPcdKgAllocSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ uint8_t i, j; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE); ++ ++ /* This routine is issued only on master core of master partition - ++ either directly or through IPC, so no need for lock */ ++ ++ for (j = 0, i = 0; i < FM_PCD_KG_NUM_OF_SCHEMES && j < numOfSchemes; i++) ++ { ++ if (!p_FmPcd->p_FmPcdKg->schemesMng[i].allocated) ++ { ++ p_FmPcd->p_FmPcdKg->schemesMng[i].allocated = TRUE; ++ p_FmPcd->p_FmPcdKg->schemesMng[i].ownerId = guestId; ++ p_SchemesIds[j] = i; ++ j++; ++ } ++ } ++ ++ if (j != numOfSchemes) ++ { ++ /* roll back */ ++ for (j--; j; j--) ++ { ++ p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[j]].allocated = FALSE; ++ p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[j]].ownerId = 0; ++ p_SchemesIds[j] = 0; ++ } ++ ++ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("No schemes found")); ++ } ++ ++ return E_OK; ++} ++ ++t_Error FmPcdKgFreeSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ uint8_t i; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE); ++ ++ /* This routine is issued only on master core of master partition - ++ either directly or through IPC */ ++ ++ for (i = 0; i < numOfSchemes; i++) ++ { ++ if (!p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].allocated) ++ { ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Scheme was not previously allocated")); ++ } ++ if (p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].ownerId != guestId) ++ { ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Scheme is not owned by caller. ")); ++ } ++ p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].allocated = FALSE; ++ p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].ownerId = 0; ++ } ++ ++ return E_OK; ++} ++ ++t_Error KgAllocClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t *p_First) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ uint8_t numOfBlocks, blocksFound=0, first=0; ++ uint8_t i, j; ++ ++ /* This routine is issued only on master core of master partition - ++ either directly or through IPC, so no need for lock */ ++ ++ if (!numOfClsPlanEntries) ++ return E_OK; ++ ++ if ((numOfClsPlanEntries % CLS_PLAN_NUM_PER_GRP) || (!POWER_OF_2(numOfClsPlanEntries))) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfClsPlanEntries must be a power of 2 and divisible by 8")); ++ ++ numOfBlocks = (uint8_t)(numOfClsPlanEntries/CLS_PLAN_NUM_PER_GRP); ++ ++ /* try to find consequent blocks */ ++ first = 0; ++ for (i = 0; i < FM_PCD_MAX_NUM_OF_CLS_PLANS/CLS_PLAN_NUM_PER_GRP;) ++ { ++ if (!p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].allocated) ++ { ++ blocksFound++; ++ i++; ++ if (blocksFound == numOfBlocks) ++ break; ++ } ++ else ++ { ++ blocksFound = 0; ++ /* advance i to the next aligned address */ ++ first = i = (uint8_t)(first + numOfBlocks); ++ } ++ } ++ ++ if (blocksFound == numOfBlocks) ++ { ++ *p_First = (uint8_t)(first * CLS_PLAN_NUM_PER_GRP); ++ for (j = first; j < (first + numOfBlocks); j++) ++ { ++ p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[j].allocated = TRUE; ++ p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[j].ownerId = guestId; ++ } ++ return E_OK; ++ } ++ else ++ RETURN_ERROR(MINOR, E_FULL, ("No resources for clsPlan")); ++} ++ ++void KgFreeClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t base) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint8_t numOfBlocks; ++ uint8_t i, baseBlock; ++ ++#ifdef DISABLE_ASSERTIONS ++UNUSED(guestId); ++#endif /* DISABLE_ASSERTIONS */ ++ ++ /* This routine is issued only on master core of master partition - ++ either directly or through IPC, so no need for lock */ ++ ++ numOfBlocks = (uint8_t)(numOfClsPlanEntries/CLS_PLAN_NUM_PER_GRP); ++ ASSERT_COND(!(base%CLS_PLAN_NUM_PER_GRP)); ++ ++ baseBlock = (uint8_t)(base/CLS_PLAN_NUM_PER_GRP); ++ for (i=baseBlock;ip_FmPcdKg->clsPlanBlocksMng[i].allocated); ++ ASSERT_COND(guestId == p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].ownerId); ++ p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].allocated = FALSE; ++ p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].ownerId = 0; ++ } ++} ++ ++void KgEnable(t_FmPcd *p_FmPcd) ++{ ++ struct fman_kg_regs *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; ++ ++ ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); ++ fman_kg_enable(p_Regs); ++} ++ ++void KgDisable(t_FmPcd *p_FmPcd) ++{ ++ struct fman_kg_regs *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; ++ ++ ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); ++ fman_kg_disable(p_Regs); ++} ++ ++void KgSetClsPlan(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanSet *p_Set) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ struct fman_kg_cp_regs *p_FmPcdKgPortRegs; ++ uint32_t tmpKgarReg = 0, intFlags; ++ uint16_t i, j; ++ ++ /* This routine is protected by the calling routine ! */ ++ ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); ++ p_FmPcdKgPortRegs = &p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->clsPlanRegs; ++ ++ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); ++ for (i=p_Set->baseEntry;ibaseEntry+p_Set->numOfClsPlanEntries;i+=8) ++ { ++ tmpKgarReg = FmPcdKgBuildWriteClsPlanBlockActionReg((uint8_t)(i / CLS_PLAN_NUM_PER_GRP)); ++ ++ for (j = i; j < i+8; j++) ++ { ++ ASSERT_COND(IN_RANGE(0, (j - p_Set->baseEntry), FM_PCD_MAX_NUM_OF_CLS_PLANS-1)); ++ WRITE_UINT32(p_FmPcdKgPortRegs->kgcpe[j % CLS_PLAN_NUM_PER_GRP],p_Set->vectors[j - p_Set->baseEntry]); ++ } ++ ++ if (WriteKgarWait(p_FmPcd, tmpKgarReg) != E_OK) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("WriteKgarWait FAILED")); ++ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); ++ return; ++ } ++ } ++ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); ++} ++ ++t_Handle KgConfig( t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams) ++{ ++ t_FmPcdKg *p_FmPcdKg; ++ ++ UNUSED(p_FmPcd); ++ ++ if (p_FmPcdParams->numOfSchemes > FM_PCD_KG_NUM_OF_SCHEMES) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ++ ("numOfSchemes should not exceed %d", FM_PCD_KG_NUM_OF_SCHEMES)); ++ return NULL; ++ } ++ ++ p_FmPcdKg = (t_FmPcdKg *)XX_Malloc(sizeof(t_FmPcdKg)); ++ if (!p_FmPcdKg) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Keygen allocation FAILED")); ++ return NULL; ++ } ++ memset(p_FmPcdKg, 0, sizeof(t_FmPcdKg)); ++ ++ ++ if (FmIsMaster(p_FmPcd->h_Fm)) ++ { ++ p_FmPcdKg->p_FmPcdKgRegs = (struct fman_kg_regs *)UINT_TO_PTR(FmGetPcdKgBaseAddr(p_FmPcdParams->h_Fm)); ++ p_FmPcd->exceptions |= DEFAULT_fmPcdKgErrorExceptions; ++ p_FmPcdKg->p_IndirectAccessRegs = (u_FmPcdKgIndirectAccessRegs *)&p_FmPcdKg->p_FmPcdKgRegs->fmkg_indirect[0]; ++ } ++ ++ p_FmPcdKg->numOfSchemes = p_FmPcdParams->numOfSchemes; ++ if ((p_FmPcd->guestId == NCSW_MASTER_ID) && !p_FmPcdKg->numOfSchemes) ++ { ++ p_FmPcdKg->numOfSchemes = FM_PCD_KG_NUM_OF_SCHEMES; ++ DBG(WARNING, ("numOfSchemes was defined 0 by user, re-defined by driver to FM_PCD_KG_NUM_OF_SCHEMES")); ++ } ++ ++ p_FmPcdKg->emptyClsPlanGrpId = ILLEGAL_CLS_PLAN; ++ ++ return p_FmPcdKg; ++} ++ ++t_Error KgInit(t_FmPcd *p_FmPcd) ++{ ++ t_Error err = E_OK; ++ ++ p_FmPcd->p_FmPcdKg->h_HwSpinlock = XX_InitSpinlock(); ++ if (!p_FmPcd->p_FmPcdKg->h_HwSpinlock) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM KG HW spinlock")); ++ ++ if (p_FmPcd->guestId == NCSW_MASTER_ID) ++ err = KgInitMaster(p_FmPcd); ++ else ++ err = KgInitGuest(p_FmPcd); ++ ++ if (err != E_OK) ++ { ++ if (p_FmPcd->p_FmPcdKg->h_HwSpinlock) ++ XX_FreeSpinlock(p_FmPcd->p_FmPcdKg->h_HwSpinlock); ++ } ++ ++ return err; ++} ++ ++t_Error KgFree(t_FmPcd *p_FmPcd) ++{ ++ t_FmPcdIpcKgSchemesParams kgAlloc; ++ t_Error err = E_OK; ++ t_FmPcdIpcMsg msg; ++ uint32_t replyLength; ++ t_FmPcdIpcReply reply; ++ ++ FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_KG, 0, e_FM_INTR_TYPE_ERR); ++ ++ if (p_FmPcd->guestId == NCSW_MASTER_ID) ++ { ++ err = FmPcdKgFreeSchemes(p_FmPcd, ++ p_FmPcd->p_FmPcdKg->numOfSchemes, ++ p_FmPcd->guestId, ++ p_FmPcd->p_FmPcdKg->schemesIds); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ if (p_FmPcd->p_FmPcdKg->h_HwSpinlock) ++ XX_FreeSpinlock(p_FmPcd->p_FmPcdKg->h_HwSpinlock); ++ ++ return E_OK; ++ } ++ ++ /* guest */ ++ memset(&reply, 0, sizeof(reply)); ++ memset(&msg, 0, sizeof(msg)); ++ kgAlloc.numOfSchemes = p_FmPcd->p_FmPcdKg->numOfSchemes; ++ kgAlloc.guestId = p_FmPcd->guestId; ++ ASSERT_COND(kgAlloc.numOfSchemes < FM_PCD_KG_NUM_OF_SCHEMES); ++ memcpy(kgAlloc.schemesIds, p_FmPcd->p_FmPcdKg->schemesIds, (sizeof(uint8_t))*kgAlloc.numOfSchemes); ++ msg.msgId = FM_PCD_FREE_KG_SCHEMES; ++ memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc)); ++ replyLength = sizeof(uint32_t); ++ if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) + sizeof(kgAlloc), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ if (replyLength != sizeof(uint32_t)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ ++ if (p_FmPcd->p_FmPcdKg->h_HwSpinlock) ++ XX_FreeSpinlock(p_FmPcd->p_FmPcdKg->h_HwSpinlock); ++ ++ return (t_Error)reply.error; ++} ++ ++t_Error FmPcdKgSetOrBindToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t netEnvId, protocolOpt_t *p_OptArray, uint8_t *p_ClsPlanGrpId, bool *p_IsEmptyClsPlanGrp) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ t_FmPcdKgInterModuleClsPlanGrpParams grpParams, *p_GrpParams; ++ t_FmPcdKgClsPlanGrp *p_ClsPlanGrp; ++ t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet; ++ t_Error err; ++ ++ /* This function is issued only from FM_PORT_SetPcd which locked all PCD modules, ++ so no need for lock here */ ++ ++ memset(&grpParams, 0, sizeof(grpParams)); ++ grpParams.clsPlanGrpId = ILLEGAL_CLS_PLAN; ++ p_GrpParams = &grpParams; ++ ++ p_GrpParams->netEnvId = netEnvId; ++ ++ /* Get from the NetEnv the information of the clsPlan (can be already created, ++ * or needs to build) */ ++ err = PcdGetClsPlanGrpParams(h_FmPcd, p_GrpParams); ++ if (err) ++ RETURN_ERROR(MINOR,err,NO_MSG); ++ ++ if (p_GrpParams->grpExists) ++ { ++ /* this group was already updated (at least) in SW */ ++ *p_ClsPlanGrpId = p_GrpParams->clsPlanGrpId; ++ } ++ else ++ { ++ p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet)); ++ if (!p_ClsPlanSet) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Classification plan set")); ++ memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet)); ++ /* Build (in SW) the clsPlan parameters, including the vectors to be written to HW */ ++ err = FmPcdKgBuildClsPlanGrp(h_FmPcd, p_GrpParams, p_ClsPlanSet); ++ if (err) ++ { ++ XX_Free(p_ClsPlanSet); ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ *p_ClsPlanGrpId = p_GrpParams->clsPlanGrpId; ++ ++ if (p_FmPcd->h_Hc) ++ { ++ /* write clsPlan entries to memory */ ++ err = FmHcPcdKgSetClsPlan(p_FmPcd->h_Hc, p_ClsPlanSet); ++ if (err) ++ { ++ XX_Free(p_ClsPlanSet); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ } ++ else ++ /* write clsPlan entries to memory */ ++ KgSetClsPlan(p_FmPcd, p_ClsPlanSet); ++ ++ XX_Free(p_ClsPlanSet); ++ } ++ ++ /* Set caller parameters */ ++ ++ /* mark if this is an empty classification group */ ++ if (*p_ClsPlanGrpId == p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId) ++ *p_IsEmptyClsPlanGrp = TRUE; ++ else ++ *p_IsEmptyClsPlanGrp = FALSE; ++ ++ p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[*p_ClsPlanGrpId]; ++ ++ /* increment owners number */ ++ p_ClsPlanGrp->owners++; ++ ++ /* copy options array for port */ ++ memcpy(p_OptArray, &p_FmPcd->p_FmPcdKg->clsPlanGrps[*p_ClsPlanGrpId].optArray, FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)*sizeof(protocolOpt_t)); ++ ++ /* bind port to the new or existing group */ ++ err = BindPortToClsPlanGrp(p_FmPcd, hardwarePortId, p_GrpParams->clsPlanGrpId); ++ if (err) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ return E_OK; ++} ++ ++t_Error FmPcdKgDeleteOrUnbindPortToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ t_FmPcdKgClsPlanGrp *p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId]; ++ t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet; ++ t_Error err; ++ ++ /* This function is issued only from FM_PORT_DeletePcd which locked all PCD modules, ++ so no need for lock here */ ++ ++ UnbindPortToClsPlanGrp(p_FmPcd, hardwarePortId); ++ ++ /* decrement owners number */ ++ ASSERT_COND(p_ClsPlanGrp->owners); ++ p_ClsPlanGrp->owners--; ++ ++ if (!p_ClsPlanGrp->owners) ++ { ++ if (p_FmPcd->h_Hc) ++ { ++ err = FmHcPcdKgDeleteClsPlan(p_FmPcd->h_Hc, clsPlanGrpId); ++ return err; ++ } ++ else ++ { ++ /* clear clsPlan entries in memory */ ++ p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet)); ++ if (!p_ClsPlanSet) ++ { ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Classification plan set")); ++ } ++ memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet)); ++ ++ p_ClsPlanSet->baseEntry = p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].baseEntry; ++ p_ClsPlanSet->numOfClsPlanEntries = p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].sizeOfGrp; ++ KgSetClsPlan(p_FmPcd, p_ClsPlanSet); ++ XX_Free(p_ClsPlanSet); ++ ++ FmPcdKgDestroyClsPlanGrp(h_FmPcd, clsPlanGrpId); ++ } ++ } ++ return E_OK; ++} ++ ++uint32_t FmPcdKgGetRequiredAction(t_Handle h_FmPcd, uint8_t schemeId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); ++ ++ return p_FmPcd->p_FmPcdKg->schemes[schemeId].requiredAction; ++} ++ ++uint32_t FmPcdKgGetRequiredActionFlag(t_Handle h_FmPcd, uint8_t schemeId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); ++ ++ return p_FmPcd->p_FmPcdKg->schemes[schemeId].requiredActionFlag; ++} ++ ++bool FmPcdKgIsDirectPlcr(t_Handle h_FmPcd, uint8_t schemeId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); ++ ++ return p_FmPcd->p_FmPcdKg->schemes[schemeId].directPlcr; ++} ++ ++ ++uint16_t FmPcdKgGetRelativeProfileId(t_Handle h_FmPcd, uint8_t schemeId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); ++ ++ return p_FmPcd->p_FmPcdKg->schemes[schemeId].relativeProfileId; ++} ++ ++bool FmPcdKgIsDistrOnPlcrProfile(t_Handle h_FmPcd, uint8_t schemeId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); ++ ++ if ((p_FmPcd->p_FmPcdKg->schemes[schemeId].extractedOrs && ++ p_FmPcd->p_FmPcdKg->schemes[schemeId].bitOffsetInPlcrProfile) || ++ p_FmPcd->p_FmPcdKg->schemes[schemeId].nextRelativePlcrProfile) ++ return TRUE; ++ else ++ return FALSE; ++ ++} ++ ++e_FmPcdEngine FmPcdKgGetNextEngine(t_Handle h_FmPcd, uint8_t relativeSchemeId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].valid); ++ ++ return p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextEngine; ++} ++ ++e_FmPcdDoneAction FmPcdKgGetDoneAction(t_Handle h_FmPcd, uint8_t schemeId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); ++ ++ return p_FmPcd->p_FmPcdKg->schemes[schemeId].doneAction; ++} ++ ++void FmPcdKgUpdateRequiredAction(t_Handle h_Scheme, uint32_t requiredAction) ++{ ++ t_FmPcdKgScheme *p_Scheme = (t_FmPcdKgScheme *)h_Scheme; ++ ++ /* this routine is protected by calling routine */ ++ ++ ASSERT_COND(p_Scheme->valid); ++ ++ p_Scheme->requiredAction |= requiredAction; ++} ++ ++bool FmPcdKgHwSchemeIsValid(uint32_t schemeModeReg) ++{ ++ return (bool)!!(schemeModeReg & KG_SCH_MODE_EN); ++} ++ ++uint32_t FmPcdKgBuildWriteSchemeActionReg(uint8_t schemeId, bool updateCounter) ++{ ++ return (uint32_t)(((uint32_t)schemeId << FM_PCD_KG_KGAR_NUM_SHIFT) | ++ FM_KG_KGAR_GO | ++ FM_KG_KGAR_WRITE | ++ FM_KG_KGAR_SEL_SCHEME_ENTRY | ++ DUMMY_PORT_ID | ++ (updateCounter ? FM_KG_KGAR_SCM_WSEL_UPDATE_CNT:0)); ++} ++ ++uint32_t FmPcdKgBuildReadSchemeActionReg(uint8_t schemeId) ++{ ++ return (uint32_t)(((uint32_t)schemeId << FM_PCD_KG_KGAR_NUM_SHIFT) | ++ FM_KG_KGAR_GO | ++ FM_KG_KGAR_READ | ++ FM_KG_KGAR_SEL_SCHEME_ENTRY | ++ DUMMY_PORT_ID | ++ FM_KG_KGAR_SCM_WSEL_UPDATE_CNT); ++ ++} ++ ++uint32_t FmPcdKgBuildWriteClsPlanBlockActionReg(uint8_t grpId) ++{ ++ return (uint32_t)(FM_KG_KGAR_GO | ++ FM_KG_KGAR_WRITE | ++ FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY | ++ DUMMY_PORT_ID | ++ ((uint32_t)grpId << FM_PCD_KG_KGAR_NUM_SHIFT) | ++ FM_PCD_KG_KGAR_WSEL_MASK); ++ ++ /* if we ever want to write 1 by 1, use: ++ sel = (uint8_t)(0x01 << (7- (entryId % CLS_PLAN_NUM_PER_GRP))); ++ */ ++} ++ ++uint32_t FmPcdKgBuildWritePortSchemeBindActionReg(uint8_t hardwarePortId) ++{ ++ ++ return (uint32_t)(FM_KG_KGAR_GO | ++ FM_KG_KGAR_WRITE | ++ FM_PCD_KG_KGAR_SEL_PORT_ENTRY | ++ hardwarePortId | ++ FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP); ++} ++ ++uint32_t FmPcdKgBuildReadPortSchemeBindActionReg(uint8_t hardwarePortId) ++{ ++ ++ return (uint32_t)(FM_KG_KGAR_GO | ++ FM_KG_KGAR_READ | ++ FM_PCD_KG_KGAR_SEL_PORT_ENTRY | ++ hardwarePortId | ++ FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP); ++} ++ ++uint32_t FmPcdKgBuildWritePortClsPlanBindActionReg(uint8_t hardwarePortId) ++{ ++ ++ return (uint32_t)(FM_KG_KGAR_GO | ++ FM_KG_KGAR_WRITE | ++ FM_PCD_KG_KGAR_SEL_PORT_ENTRY | ++ hardwarePortId | ++ FM_PCD_KG_KGAR_SEL_PORT_WSEL_CPP); ++} ++ ++uint8_t FmPcdKgGetClsPlanGrpBase(t_Handle h_FmPcd, uint8_t clsPlanGrp) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ return p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrp].baseEntry; ++} ++ ++uint16_t FmPcdKgGetClsPlanGrpSize(t_Handle h_FmPcd, uint8_t clsPlanGrp) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ return p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrp].sizeOfGrp; ++} ++ ++ ++uint8_t FmPcdKgGetSchemeId(t_Handle h_Scheme) ++{ ++ return ((t_FmPcdKgScheme*)h_Scheme)->schemeId; ++ ++} ++ ++#if (DPAA_VERSION >= 11) ++bool FmPcdKgGetVspe(t_Handle h_Scheme) ++{ ++ return ((t_FmPcdKgScheme*)h_Scheme)->vspe; ++ ++} ++#endif /* (DPAA_VERSION >= 11) */ ++ ++uint8_t FmPcdKgGetRelativeSchemeId(t_Handle h_FmPcd, uint8_t schemeId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint8_t i; ++ ++ for (i = 0;ip_FmPcdKg->numOfSchemes;i++) ++ if (p_FmPcd->p_FmPcdKg->schemesIds[i] == schemeId) ++ return i; ++ ++ if (i == p_FmPcd->p_FmPcdKg->numOfSchemes) ++ REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("Scheme is out of partition range")); ++ ++ return FM_PCD_KG_NUM_OF_SCHEMES; ++} ++ ++t_Handle FmPcdKgGetSchemeHandle(t_Handle h_FmPcd, uint8_t relativeSchemeId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ ASSERT_COND(p_FmPcd); ++ ++ /* check that schemeId is in range */ ++ if (relativeSchemeId >= p_FmPcd->p_FmPcdKg->numOfSchemes) ++ { ++ REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("relative-scheme-id %d!", relativeSchemeId)); ++ return NULL; ++ } ++ ++ if (!FmPcdKgIsSchemeValidSw(&p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId])) ++ return NULL; ++ ++ return &p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId]; ++} ++ ++bool FmPcdKgIsSchemeHasOwners(t_Handle h_Scheme) ++{ ++ return (((t_FmPcdKgScheme*)h_Scheme)->owners == 0)?FALSE:TRUE; ++} ++ ++t_Error FmPcdKgCcGetSetParams(t_Handle h_FmPcd, t_Handle h_Scheme, uint32_t requiredAction, uint32_t value) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint8_t relativeSchemeId, physicalSchemeId; ++ uint32_t tmpKgarReg, tmpReg32 = 0, intFlags; ++ t_Error err; ++ t_FmPcdKgScheme *p_Scheme = (t_FmPcdKgScheme*)h_Scheme; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, 0); ++ SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, 0); ++ SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0); ++ ++ /* Calling function locked all PCD modules, so no need to lock here */ ++ ++ if (!FmPcdKgIsSchemeValidSw(h_Scheme)) ++ RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid")); ++ ++ if (p_FmPcd->h_Hc) ++ { ++ err = FmHcPcdKgCcGetSetParams(p_FmPcd->h_Hc, h_Scheme, requiredAction, value); ++ ++ UpdateRequiredActionFlag(h_Scheme,TRUE); ++ FmPcdKgUpdateRequiredAction(h_Scheme,requiredAction); ++ return err; ++ } ++ ++ physicalSchemeId = p_Scheme->schemeId; ++ ++ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId); ++ if (relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES) ++ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); ++ ++ if (!p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].requiredActionFlag || ++ !(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].requiredAction & requiredAction)) ++ { ++ if (requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) ++ { ++ switch (p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextEngine) ++ { ++ case (e_FM_PCD_DONE): ++ if (p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].doneAction == e_FM_PCD_ENQ_FRAME) ++ { ++ tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); ++ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); ++ WriteKgarWait(p_FmPcd, tmpKgarReg); ++ tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode); ++ ASSERT_COND(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)); ++ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode, tmpReg32 | NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA); ++ /* call indirect command for scheme write */ ++ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE); ++ WriteKgarWait(p_FmPcd, tmpKgarReg); ++ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); ++ } ++ break; ++ case (e_FM_PCD_PLCR): ++ if (!p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].directPlcr || ++ (p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].extractedOrs && ++ p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].bitOffsetInPlcrProfile) || ++ p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextRelativePlcrProfile) ++ { ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("In this situation PP can not be with distribution and has to be shared")); ++ } ++ err = FmPcdPlcrCcGetSetParams(h_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].relativeProfileId, requiredAction); ++ if (err) ++ { ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE,("in this situation the next engine after scheme can be or PLCR or ENQ_FRAME")); ++ } ++ } ++ if (requiredAction & UPDATE_KG_NIA_CC_WA) ++ { ++ if (p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextEngine == e_FM_PCD_CC) ++ { ++ tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); ++ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); ++ WriteKgarWait(p_FmPcd, tmpKgarReg); ++ tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode); ++ ASSERT_COND(tmpReg32 & (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC)); ++ tmpReg32 &= ~NIA_FM_CTL_AC_CC; ++ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode, tmpReg32 | NIA_FM_CTL_AC_PRE_CC); ++ /* call indirect command for scheme write */ ++ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE); ++ WriteKgarWait(p_FmPcd, tmpKgarReg); ++ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); ++ } ++ } ++ if (requiredAction & UPDATE_KG_OPT_MODE) ++ { ++ tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); ++ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); ++ WriteKgarWait(p_FmPcd, tmpKgarReg); ++ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_om, value); ++ /* call indirect command for scheme write */ ++ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE); ++ WriteKgarWait(p_FmPcd, tmpKgarReg); ++ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); ++ } ++ if (requiredAction & UPDATE_KG_NIA) ++ { ++ tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); ++ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); ++ WriteKgarWait(p_FmPcd, tmpKgarReg); ++ tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode); ++ tmpReg32 &= ~(NIA_ENG_MASK | NIA_AC_MASK); ++ tmpReg32 |= value; ++ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode, tmpReg32); ++ /* call indirect command for scheme write */ ++ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE); ++ WriteKgarWait(p_FmPcd, tmpKgarReg); ++ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); ++ } ++ } ++ ++ UpdateRequiredActionFlag(h_Scheme, TRUE); ++ FmPcdKgUpdateRequiredAction(h_Scheme, requiredAction); ++ ++ return E_OK; ++} ++/*********************** End of inter-module routines ************************/ ++ ++ ++/****************************************/ ++/* API routines */ ++/****************************************/ ++ ++t_Handle FM_PCD_KgSchemeSet(t_Handle h_FmPcd, t_FmPcdKgSchemeParams *p_SchemeParams) ++{ ++ t_FmPcd *p_FmPcd; ++ struct fman_kg_scheme_regs schemeRegs; ++ struct fman_kg_scheme_regs *p_MemRegs; ++ uint8_t i; ++ t_Error err = E_OK; ++ uint32_t tmpKgarReg; ++ uint32_t intFlags; ++ uint8_t physicalSchemeId, relativeSchemeId = 0; ++ t_FmPcdKgScheme *p_Scheme; ++ ++ if (p_SchemeParams->modify) ++ { ++ p_Scheme = (t_FmPcdKgScheme *)p_SchemeParams->id.h_Scheme; ++ p_FmPcd = p_Scheme->h_FmPcd; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, NULL); ++ ++ if (!FmPcdKgIsSchemeValidSw(p_Scheme)) ++ { ++ REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ++ ("Scheme is invalid")); ++ return NULL; ++ } ++ ++ if (!KgSchemeFlagTryLock(p_Scheme)) ++ { ++ DBG(TRACE, ("Scheme Try Lock - BUSY")); ++ /* Signal to caller BUSY condition */ ++ p_SchemeParams->id.h_Scheme = NULL; ++ return NULL; ++ } ++ } ++ else ++ { ++ p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, NULL); ++ ++ relativeSchemeId = p_SchemeParams->id.relativeSchemeId; ++ /* check that schemeId is in range */ ++ if (relativeSchemeId >= p_FmPcd->p_FmPcdKg->numOfSchemes) ++ { ++ REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("relative-scheme-id %d!", relativeSchemeId)); ++ return NULL; ++ } ++ ++ p_Scheme = &p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId]; ++ if (FmPcdKgIsSchemeValidSw(p_Scheme)) ++ { ++ REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ++ ("Scheme id (%d)!", relativeSchemeId)); ++ return NULL; ++ } ++ /* Clear all fields, scheme may have beed previously used */ ++ memset(p_Scheme, 0, sizeof(t_FmPcdKgScheme)); ++ ++ p_Scheme->schemeId = p_FmPcd->p_FmPcdKg->schemesIds[relativeSchemeId]; ++ p_Scheme->h_FmPcd = p_FmPcd; ++ ++ p_Scheme->p_Lock = FmPcdAcquireLock(p_FmPcd); ++ if (!p_Scheme->p_Lock) ++ REPORT_ERROR(MAJOR, E_NOT_AVAILABLE, ("FM KG Scheme lock obj!")); ++ } ++ ++ err = BuildSchemeRegs((t_Handle)p_Scheme, p_SchemeParams, &schemeRegs); ++ if (err) ++ { ++ REPORT_ERROR(MAJOR, err, NO_MSG); ++ if (p_SchemeParams->modify) ++ KgSchemeFlagUnlock(p_Scheme); ++ if (!p_SchemeParams->modify && ++ p_Scheme->p_Lock) ++ FmPcdReleaseLock(p_FmPcd, p_Scheme->p_Lock); ++ return NULL; ++ } ++ ++ if (p_FmPcd->h_Hc) ++ { ++ err = FmHcPcdKgSetScheme(p_FmPcd->h_Hc, ++ (t_Handle)p_Scheme, ++ &schemeRegs, ++ p_SchemeParams->schemeCounter.update); ++ if (p_SchemeParams->modify) ++ KgSchemeFlagUnlock(p_Scheme); ++ if (err) ++ { ++ if (!p_SchemeParams->modify && ++ p_Scheme->p_Lock) ++ FmPcdReleaseLock(p_FmPcd, p_Scheme->p_Lock); ++ return NULL; ++ } ++ if (!p_SchemeParams->modify) ++ ValidateSchemeSw(p_Scheme); ++ return (t_Handle)p_Scheme; ++ } ++ ++ physicalSchemeId = p_Scheme->schemeId; ++ ++ /* configure all 21 scheme registers */ ++ p_MemRegs = &p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs; ++ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); ++ WRITE_UINT32(p_MemRegs->kgse_ppc, schemeRegs.kgse_ppc); ++ WRITE_UINT32(p_MemRegs->kgse_ccbs, schemeRegs.kgse_ccbs); ++ WRITE_UINT32(p_MemRegs->kgse_mode, schemeRegs.kgse_mode); ++ WRITE_UINT32(p_MemRegs->kgse_mv, schemeRegs.kgse_mv); ++ WRITE_UINT32(p_MemRegs->kgse_dv0, schemeRegs.kgse_dv0); ++ WRITE_UINT32(p_MemRegs->kgse_dv1, schemeRegs.kgse_dv1); ++ WRITE_UINT32(p_MemRegs->kgse_ekdv, schemeRegs.kgse_ekdv); ++ WRITE_UINT32(p_MemRegs->kgse_ekfc, schemeRegs.kgse_ekfc); ++ WRITE_UINT32(p_MemRegs->kgse_bmch, schemeRegs.kgse_bmch); ++ WRITE_UINT32(p_MemRegs->kgse_bmcl, schemeRegs.kgse_bmcl); ++ WRITE_UINT32(p_MemRegs->kgse_hc, schemeRegs.kgse_hc); ++ WRITE_UINT32(p_MemRegs->kgse_spc, schemeRegs.kgse_spc); ++ WRITE_UINT32(p_MemRegs->kgse_fqb, schemeRegs.kgse_fqb); ++ WRITE_UINT32(p_MemRegs->kgse_om, schemeRegs.kgse_om); ++ WRITE_UINT32(p_MemRegs->kgse_vsp, schemeRegs.kgse_vsp); ++ for (i=0 ; ikgse_gec[i], schemeRegs.kgse_gec[i]); ++ ++ /* call indirect command for scheme write */ ++ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, p_SchemeParams->schemeCounter.update); ++ ++ WriteKgarWait(p_FmPcd, tmpKgarReg); ++ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); ++ ++ if (!p_SchemeParams->modify) ++ ValidateSchemeSw(p_Scheme); ++ else ++ KgSchemeFlagUnlock(p_Scheme); ++ ++ return (t_Handle)p_Scheme; ++} ++ ++t_Error FM_PCD_KgSchemeDelete(t_Handle h_Scheme) ++{ ++ t_FmPcd *p_FmPcd; ++ uint8_t physicalSchemeId; ++ uint32_t tmpKgarReg, intFlags; ++ t_Error err = E_OK; ++ t_FmPcdKgScheme *p_Scheme = (t_FmPcdKgScheme *)h_Scheme; ++ ++ SANITY_CHECK_RETURN_ERROR(h_Scheme, E_INVALID_HANDLE); ++ ++ p_FmPcd = (t_FmPcd*)(p_Scheme->h_FmPcd); ++ ++ UpdateRequiredActionFlag(h_Scheme, FALSE); ++ ++ /* check that no port is bound to this scheme */ ++ err = InvalidateSchemeSw(h_Scheme); ++ if (err) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ if (p_FmPcd->h_Hc) ++ { ++ err = FmHcPcdKgDeleteScheme(p_FmPcd->h_Hc, h_Scheme); ++ if (p_Scheme->p_Lock) ++ FmPcdReleaseLock(p_FmPcd, p_Scheme->p_Lock); ++ return err; ++ } ++ ++ physicalSchemeId = ((t_FmPcdKgScheme *)h_Scheme)->schemeId; ++ ++ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); ++ /* clear mode register, including enable bit */ ++ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode, 0); ++ ++ /* call indirect command for scheme write */ ++ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE); ++ ++ WriteKgarWait(p_FmPcd, tmpKgarReg); ++ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); ++ ++ if (p_Scheme->p_Lock) ++ FmPcdReleaseLock(p_FmPcd, p_Scheme->p_Lock); ++ ++ return E_OK; ++} ++ ++uint32_t FM_PCD_KgSchemeGetCounter(t_Handle h_Scheme) ++{ ++ t_FmPcd *p_FmPcd; ++ uint32_t tmpKgarReg, spc, intFlags; ++ uint8_t physicalSchemeId; ++ ++ SANITY_CHECK_RETURN_VALUE(h_Scheme, E_INVALID_HANDLE, 0); ++ ++ p_FmPcd = (t_FmPcd*)(((t_FmPcdKgScheme *)h_Scheme)->h_FmPcd); ++ if (p_FmPcd->h_Hc) ++ return FmHcPcdKgGetSchemeCounter(p_FmPcd->h_Hc, h_Scheme); ++ ++ physicalSchemeId = ((t_FmPcdKgScheme *)h_Scheme)->schemeId; ++ ++ if (FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId) == FM_PCD_KG_NUM_OF_SCHEMES) ++ REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); ++ ++ tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); ++ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); ++ WriteKgarWait(p_FmPcd, tmpKgarReg); ++ if (!(GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode) & KG_SCH_MODE_EN)) ++ REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid")); ++ spc = GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_spc); ++ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); ++ ++ return spc; ++} ++ ++t_Error FM_PCD_KgSchemeSetCounter(t_Handle h_Scheme, uint32_t value) ++{ ++ t_FmPcd *p_FmPcd; ++ uint32_t tmpKgarReg, intFlags; ++ uint8_t physicalSchemeId; ++ ++ SANITY_CHECK_RETURN_VALUE(h_Scheme, E_INVALID_HANDLE, 0); ++ ++ p_FmPcd = (t_FmPcd*)(((t_FmPcdKgScheme *)h_Scheme)->h_FmPcd); ++ ++ if (!FmPcdKgIsSchemeValidSw(h_Scheme)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Requested scheme is invalid.")); ++ ++ if (p_FmPcd->h_Hc) ++ return FmHcPcdKgSetSchemeCounter(p_FmPcd->h_Hc, h_Scheme, value); ++ ++ physicalSchemeId = ((t_FmPcdKgScheme *)h_Scheme)->schemeId; ++ /* check that schemeId is in range */ ++ if (FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId) == FM_PCD_KG_NUM_OF_SCHEMES) ++ REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); ++ ++ /* read specified scheme into scheme registers */ ++ tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); ++ intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); ++ WriteKgarWait(p_FmPcd, tmpKgarReg); ++ if (!(GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode) & KG_SCH_MODE_EN)) ++ { ++ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); ++ RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid")); ++ } ++ ++ /* change counter value */ ++ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_spc, value); ++ ++ /* call indirect command for scheme write */ ++ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, TRUE); ++ ++ WriteKgarWait(p_FmPcd, tmpKgarReg); ++ KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_KgSetAdditionalDataAfterParsing(t_Handle h_FmPcd, uint8_t payloadOffset) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ struct fman_kg_regs *p_Regs; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs, E_NULL_POINTER); ++ ++ p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; ++ if (!FmIsMaster(p_FmPcd->h_Fm)) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_KgSetAdditionalDataAfterParsing - guest mode!")); ++ ++ WRITE_UINT32(p_Regs->fmkg_fdor,payloadOffset); ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_KgSetDfltValue(t_Handle h_FmPcd, uint8_t valueId, uint32_t value) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ struct fman_kg_regs *p_Regs; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(((valueId == 0) || (valueId == 1)), E_INVALID_VALUE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs, E_NULL_POINTER); ++ ++ p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; ++ ++ if (!FmIsMaster(p_FmPcd->h_Fm)) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_KgSetDfltValue - guest mode!")); ++ ++ if (valueId == 0) ++ WRITE_UINT32(p_Regs->fmkg_gdv0r,value); ++ else ++ WRITE_UINT32(p_Regs->fmkg_gdv1r,value); ++ return E_OK; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.h +new file mode 100644 +index 00000000..cb7521a1 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.h +@@ -0,0 +1,206 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_kg.h ++ ++ @Description FM KG private header ++*//***************************************************************************/ ++#ifndef __FM_KG_H ++#define __FM_KG_H ++ ++#include "std_ext.h" ++ ++/***********************************************************************/ ++/* Keygen defines */ ++/***********************************************************************/ ++/* maskes */ ++#if (DPAA_VERSION >= 11) ++#define KG_SCH_VSP_SHIFT_MASK 0x0003f000 ++#define KG_SCH_OM_VSPE 0x00000001 ++#define KG_SCH_VSP_NO_KSP_EN 0x80000000 ++ ++#define MAX_SP_SHIFT 23 ++#define KG_SCH_VSP_MASK_SHIFT 12 ++#define KG_SCH_VSP_SHIFT 24 ++#endif /* (DPAA_VERSION >= 11) */ ++ ++typedef uint32_t t_KnownFieldsMasks; ++#define KG_SCH_KN_PORT_ID 0x80000000 ++#define KG_SCH_KN_MACDST 0x40000000 ++#define KG_SCH_KN_MACSRC 0x20000000 ++#define KG_SCH_KN_TCI1 0x10000000 ++#define KG_SCH_KN_TCI2 0x08000000 ++#define KG_SCH_KN_ETYPE 0x04000000 ++#define KG_SCH_KN_PPPSID 0x02000000 ++#define KG_SCH_KN_PPPID 0x01000000 ++#define KG_SCH_KN_MPLS1 0x00800000 ++#define KG_SCH_KN_MPLS2 0x00400000 ++#define KG_SCH_KN_MPLS_LAST 0x00200000 ++#define KG_SCH_KN_IPSRC1 0x00100000 ++#define KG_SCH_KN_IPDST1 0x00080000 ++#define KG_SCH_KN_PTYPE1 0x00040000 ++#define KG_SCH_KN_IPTOS_TC1 0x00020000 ++#define KG_SCH_KN_IPV6FL1 0x00010000 ++#define KG_SCH_KN_IPSRC2 0x00008000 ++#define KG_SCH_KN_IPDST2 0x00004000 ++#define KG_SCH_KN_PTYPE2 0x00002000 ++#define KG_SCH_KN_IPTOS_TC2 0x00001000 ++#define KG_SCH_KN_IPV6FL2 0x00000800 ++#define KG_SCH_KN_GREPTYPE 0x00000400 ++#define KG_SCH_KN_IPSEC_SPI 0x00000200 ++#define KG_SCH_KN_IPSEC_NH 0x00000100 ++#define KG_SCH_KN_IPPID 0x00000080 ++#define KG_SCH_KN_L4PSRC 0x00000004 ++#define KG_SCH_KN_L4PDST 0x00000002 ++#define KG_SCH_KN_TFLG 0x00000001 ++ ++typedef uint8_t t_GenericCodes; ++#define KG_SCH_GEN_SHIM1 0x70 ++#define KG_SCH_GEN_DEFAULT 0x10 ++#define KG_SCH_GEN_PARSE_RESULT_N_FQID 0x20 ++#define KG_SCH_GEN_START_OF_FRM 0x40 ++#define KG_SCH_GEN_SHIM2 0x71 ++#define KG_SCH_GEN_IP_PID_NO_V 0x72 ++#define KG_SCH_GEN_ETH 0x03 ++#define KG_SCH_GEN_ETH_NO_V 0x73 ++#define KG_SCH_GEN_SNAP 0x04 ++#define KG_SCH_GEN_SNAP_NO_V 0x74 ++#define KG_SCH_GEN_VLAN1 0x05 ++#define KG_SCH_GEN_VLAN1_NO_V 0x75 ++#define KG_SCH_GEN_VLAN2 0x06 ++#define KG_SCH_GEN_VLAN2_NO_V 0x76 ++#define KG_SCH_GEN_ETH_TYPE 0x07 ++#define KG_SCH_GEN_ETH_TYPE_NO_V 0x77 ++#define KG_SCH_GEN_PPP 0x08 ++#define KG_SCH_GEN_PPP_NO_V 0x78 ++#define KG_SCH_GEN_MPLS1 0x09 ++#define KG_SCH_GEN_MPLS2 0x19 ++#define KG_SCH_GEN_MPLS3 0x29 ++#define KG_SCH_GEN_MPLS1_NO_V 0x79 ++#define KG_SCH_GEN_MPLS_LAST 0x0a ++#define KG_SCH_GEN_MPLS_LAST_NO_V 0x7a ++#define KG_SCH_GEN_IPV4 0x0b ++#define KG_SCH_GEN_IPV6 0x1b ++#define KG_SCH_GEN_L3_NO_V 0x7b ++#define KG_SCH_GEN_IPV4_TUNNELED 0x0c ++#define KG_SCH_GEN_IPV6_TUNNELED 0x1c ++#define KG_SCH_GEN_MIN_ENCAP 0x2c ++#define KG_SCH_GEN_IP2_NO_V 0x7c ++#define KG_SCH_GEN_GRE 0x0d ++#define KG_SCH_GEN_GRE_NO_V 0x7d ++#define KG_SCH_GEN_TCP 0x0e ++#define KG_SCH_GEN_UDP 0x1e ++#define KG_SCH_GEN_IPSEC_AH 0x2e ++#define KG_SCH_GEN_SCTP 0x3e ++#define KG_SCH_GEN_DCCP 0x4e ++#define KG_SCH_GEN_IPSEC_ESP 0x6e ++#define KG_SCH_GEN_L4_NO_V 0x7e ++#define KG_SCH_GEN_NEXTHDR 0x7f ++/* shifts */ ++#define KG_SCH_PP_SHIFT_HIGH_SHIFT 27 ++#define KG_SCH_PP_SHIFT_LOW_SHIFT 12 ++#define KG_SCH_PP_MASK_SHIFT 16 ++#define KG_SCH_MODE_CCOBASE_SHIFT 24 ++#define KG_SCH_DEF_MAC_ADDR_SHIFT 30 ++#define KG_SCH_DEF_TCI_SHIFT 28 ++#define KG_SCH_DEF_ENET_TYPE_SHIFT 26 ++#define KG_SCH_DEF_PPP_SESSION_ID_SHIFT 24 ++#define KG_SCH_DEF_PPP_PROTOCOL_ID_SHIFT 22 ++#define KG_SCH_DEF_MPLS_LABEL_SHIFT 20 ++#define KG_SCH_DEF_IP_ADDR_SHIFT 18 ++#define KG_SCH_DEF_PROTOCOL_TYPE_SHIFT 16 ++#define KG_SCH_DEF_IP_TOS_TC_SHIFT 14 ++#define KG_SCH_DEF_IPV6_FLOW_LABEL_SHIFT 12 ++#define KG_SCH_DEF_IPSEC_SPI_SHIFT 10 ++#define KG_SCH_DEF_L4_PORT_SHIFT 8 ++#define KG_SCH_DEF_TCP_FLAG_SHIFT 6 ++#define KG_SCH_HASH_CONFIG_SHIFT_SHIFT 24 ++#define KG_SCH_GEN_MASK_SHIFT 16 ++#define KG_SCH_GEN_HT_SHIFT 8 ++#define KG_SCH_GEN_SIZE_SHIFT 24 ++#define KG_SCH_GEN_DEF_SHIFT 29 ++#define FM_PCD_KG_KGAR_NUM_SHIFT 16 ++ ++/* others */ ++#define NUM_OF_SW_DEFAULTS 3 ++#define MAX_PP_SHIFT 23 ++#define MAX_KG_SCH_SIZE 16 ++#define MASK_FOR_GENERIC_BASE_ID 0x20 ++#define MAX_HASH_SHIFT 40 ++#define MAX_KG_SCH_FQID_BIT_OFFSET 31 ++#define MAX_KG_SCH_PP_BIT_OFFSET 15 ++#define MAX_DIST_FQID_SHIFT 23 ++ ++#define GET_MASK_SEL_SHIFT(shift,i) \ ++switch (i) { \ ++ case (0):shift = 26;break; \ ++ case (1):shift = 20;break; \ ++ case (2):shift = 10;break; \ ++ case (3):shift = 4;break; \ ++ default: \ ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); \ ++} ++ ++#define GET_MASK_OFFSET_SHIFT(shift,i) \ ++switch (i) { \ ++ case (0):shift = 16;break; \ ++ case (1):shift = 0;break; \ ++ case (2):shift = 28;break; \ ++ case (3):shift = 24;break; \ ++ default: \ ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); \ ++} ++ ++#define GET_MASK_SHIFT(shift,i) \ ++switch (i) { \ ++ case (0):shift = 24;break; \ ++ case (1):shift = 16;break; \ ++ case (2):shift = 8;break; \ ++ case (3):shift = 0;break; \ ++ default: \ ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); \ ++} ++ ++/***********************************************************************/ ++/* Keygen defines */ ++/***********************************************************************/ ++ ++#define KG_DOUBLE_MEANING_REGS_OFFSET 0x100 ++#define NO_VALIDATION 0x70 ++#define KG_ACTION_REG_TO 1024 ++#define KG_MAX_PROFILE 255 ++#define SCHEME_ALWAYS_DIRECT 0xFFFFFFFF ++ ++ ++#endif /* __FM_KG_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c +new file mode 100644 +index 00000000..113777e5 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c +@@ -0,0 +1,5571 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_manip.c ++ ++ @Description FM PCD manip ... ++ *//***************************************************************************/ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "string_ext.h" ++#include "debug_ext.h" ++#include "fm_pcd_ext.h" ++#include "fm_port_ext.h" ++#include "fm_muram_ext.h" ++#include "memcpy_ext.h" ++ ++#include "fm_common.h" ++#include "fm_hc.h" ++#include "fm_manip.h" ++ ++/****************************************/ ++/* static functions */ ++/****************************************/ ++static t_Handle GetManipInfo(t_FmPcdManip *p_Manip, e_ManipInfo manipInfo) ++{ ++ t_FmPcdManip *p_CurManip = p_Manip; ++ ++ if (!MANIP_IS_UNIFIED(p_Manip)) ++ p_CurManip = p_Manip; ++ else ++ { ++ /* go to first unified */ ++ while (MANIP_IS_UNIFIED_NON_FIRST(p_CurManip)) ++ p_CurManip = p_CurManip->h_PrevManip; ++ } ++ ++ switch (manipInfo) ++ { ++ case (e_MANIP_HMCT): ++ return p_CurManip->p_Hmct; ++ case (e_MANIP_HMTD): ++ return p_CurManip->h_Ad; ++ case (e_MANIP_HANDLER_TABLE_OWNER): ++ return (t_Handle)p_CurManip; ++ default: ++ return NULL; ++ } ++} ++ ++static uint16_t GetHmctSize(t_FmPcdManip *p_Manip) ++{ ++ uint16_t size = 0; ++ t_FmPcdManip *p_CurManip = p_Manip; ++ ++ if (!MANIP_IS_UNIFIED(p_Manip)) ++ return p_Manip->tableSize; ++ ++ /* accumulate sizes, starting with the first node */ ++ while (MANIP_IS_UNIFIED_NON_FIRST(p_CurManip)) ++ p_CurManip = p_CurManip->h_PrevManip; ++ ++ while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip)) ++ { ++ size += p_CurManip->tableSize; ++ p_CurManip = (t_FmPcdManip *)p_CurManip->h_NextManip; ++ } ++ size += p_CurManip->tableSize; /* add last size */ ++ ++ return (size); ++} ++ ++static uint16_t GetDataSize(t_FmPcdManip *p_Manip) ++{ ++ uint16_t size = 0; ++ t_FmPcdManip *p_CurManip = p_Manip; ++ ++ if (!MANIP_IS_UNIFIED(p_Manip)) ++ return p_Manip->dataSize; ++ ++ /* accumulate sizes, starting with the first node */ ++ while (MANIP_IS_UNIFIED_NON_FIRST(p_CurManip)) ++ p_CurManip = p_CurManip->h_PrevManip; ++ ++ while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip)) ++ { ++ size += p_CurManip->dataSize; ++ p_CurManip = (t_FmPcdManip *)p_CurManip->h_NextManip; ++ } ++ size += p_CurManip->dataSize; /* add last size */ ++ ++ return (size); ++} ++ ++static t_Error CalculateTableSize(t_FmPcdManipParams *p_FmPcdManipParams, ++ uint16_t *p_TableSize, uint8_t *p_DataSize) ++{ ++ uint8_t localDataSize, remain, tableSize = 0, dataSize = 0; ++ ++ if (p_FmPcdManipParams->u.hdr.rmv) ++ { ++ switch (p_FmPcdManipParams->u.hdr.rmvParams.type) ++ { ++ case (e_FM_PCD_MANIP_RMV_GENERIC): ++ tableSize += HMCD_BASIC_SIZE; ++ break; ++ case (e_FM_PCD_MANIP_RMV_BY_HDR): ++ switch (p_FmPcdManipParams->u.hdr.rmvParams.u.byHdr.type) ++ { ++ case (e_FM_PCD_MANIP_RMV_BY_HDR_SPECIFIC_L2): ++#if (DPAA_VERSION >= 11) ++ case (e_FM_PCD_MANIP_RMV_BY_HDR_CAPWAP): ++ case (e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START): ++#endif /* (DPAA_VERSION >= 11) */ ++ tableSize += HMCD_BASIC_SIZE; ++ break; ++ default: ++ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ++ ("Unknown byHdr.type")); ++ } ++ break; ++ default: ++ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ++ ("Unknown rmvParams.type")); ++ } ++ } ++ ++ if (p_FmPcdManipParams->u.hdr.insrt) ++ { ++ switch (p_FmPcdManipParams->u.hdr.insrtParams.type) ++ { ++ case (e_FM_PCD_MANIP_INSRT_GENERIC): ++ remain = ++ (uint8_t)(p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size ++ % 4); ++ if (remain) ++ localDataSize = ++ (uint8_t)(p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size ++ + 4 - remain); ++ else ++ localDataSize = ++ p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size; ++ tableSize += (uint8_t)(HMCD_BASIC_SIZE + localDataSize); ++ break; ++ case (e_FM_PCD_MANIP_INSRT_BY_HDR): ++ { ++ switch (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.type) ++ { ++ ++ case (e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2): ++ tableSize += HMCD_BASIC_SIZE + HMCD_PTR_SIZE; ++ switch (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.specificL2) ++ { ++ case (e_FM_PCD_MANIP_HDR_INSRT_MPLS): ++ case (e_FM_PCD_MANIP_HDR_INSRT_PPPOE): ++ dataSize += ++ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.size; ++ break; ++ default: ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++ } ++ break; ++#if (DPAA_VERSION >= 11) ++ case (e_FM_PCD_MANIP_INSRT_BY_HDR_IP): ++ tableSize += ++ (HMCD_BASIC_SIZE + HMCD_PTR_SIZE ++ + HMCD_PARAM_SIZE ++ + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size); ++ dataSize += 2; ++ break; ++ ++ case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP): ++ case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE): ++ tableSize += (HMCD_BASIC_SIZE + HMCD_L4_HDR_SIZE); ++ ++ break; ++ ++ case (e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP): ++ tableSize += ++ (HMCD_BASIC_SIZE ++ + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size); ++ break; ++#endif /* (DPAA_VERSION >= 11) */ ++ default: ++ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ++ ("Unknown byHdr.type")); ++ } ++ } ++ break; ++ default: ++ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ++ ("Unknown insrtParams.type")); ++ } ++ } ++ ++ if (p_FmPcdManipParams->u.hdr.fieldUpdate) ++ { ++ switch (p_FmPcdManipParams->u.hdr.fieldUpdateParams.type) ++ { ++ case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN): ++ tableSize += HMCD_BASIC_SIZE; ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType ++ == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN) ++ { ++ tableSize += HMCD_PTR_SIZE; ++ dataSize += DSCP_TO_VLAN_TABLE_SIZE; ++ } ++ break; ++ case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4): ++ tableSize += HMCD_BASIC_SIZE; ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates ++ & HDR_MANIP_IPV4_ID) ++ { ++ tableSize += HMCD_PARAM_SIZE; ++ dataSize += 2; ++ } ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates ++ & HDR_MANIP_IPV4_SRC) ++ tableSize += HMCD_IPV4_ADDR_SIZE; ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates ++ & HDR_MANIP_IPV4_DST) ++ tableSize += HMCD_IPV4_ADDR_SIZE; ++ break; ++ case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6): ++ tableSize += HMCD_BASIC_SIZE; ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates ++ & HDR_MANIP_IPV6_SRC) ++ tableSize += HMCD_IPV6_ADDR_SIZE; ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates ++ & HDR_MANIP_IPV6_DST) ++ tableSize += HMCD_IPV6_ADDR_SIZE; ++ break; ++ case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP): ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates ++ == HDR_MANIP_TCP_UDP_CHECKSUM) ++ /* we implement this case with the update-checksum descriptor */ ++ tableSize += HMCD_BASIC_SIZE; ++ else ++ /* we implement this case with the TCP/UDP-update descriptor */ ++ tableSize += HMCD_BASIC_SIZE + HMCD_PARAM_SIZE; ++ break; ++ default: ++ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ++ ("Unknown fieldUpdateParams.type")); ++ } ++ } ++ ++ if (p_FmPcdManipParams->u.hdr.custom) ++ { ++ switch (p_FmPcdManipParams->u.hdr.customParams.type) ++ { ++ case (e_FM_PCD_MANIP_HDR_CUSTOM_IP_REPLACE): ++ { ++ tableSize += HMCD_BASIC_SIZE + HMCD_PARAM_SIZE + HMCD_PARAM_SIZE; ++ dataSize += ++ p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.hdrSize; ++ if ((p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.replaceType ++ == e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4) ++ && (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.updateIpv4Id)) ++ dataSize += 2; ++ } ++ break; ++ case (e_FM_PCD_MANIP_HDR_CUSTOM_GEN_FIELD_REPLACE): ++ tableSize += HMCD_BASIC_SIZE + HMCD_PARAM_SIZE; ++ break; ++ default: ++ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ++ ("Unknown customParams.type")); ++ } ++ } ++ ++ *p_TableSize = tableSize; ++ *p_DataSize = dataSize; ++ ++ return E_OK; ++} ++ ++static t_Error GetPrOffsetByHeaderOrField(t_FmManipHdrInfo *p_HdrInfo, ++ uint8_t *parseArrayOffset) ++{ ++ e_NetHeaderType hdr = p_HdrInfo->hdr; ++ e_FmPcdHdrIndex hdrIndex = p_HdrInfo->hdrIndex; ++ bool byField = p_HdrInfo->byField; ++ t_FmPcdFields field; ++ ++ if (byField) ++ field = p_HdrInfo->fullField; ++ ++ if (byField) ++ { ++ switch (hdr) ++ { ++ case (HEADER_TYPE_ETH): ++ switch (field.eth) ++ { ++ case (NET_HEADER_FIELD_ETH_TYPE): ++ *parseArrayOffset = CC_PC_PR_ETYPE_LAST_OFFSET; ++ break; ++ default: ++ RETURN_ERROR( ++ MAJOR, ++ E_NOT_SUPPORTED, ++ ("Header manipulation of the type Ethernet with this field not supported")); ++ } ++ break; ++ case (HEADER_TYPE_VLAN): ++ switch (field.vlan) ++ { ++ case (NET_HEADER_FIELD_VLAN_TCI): ++ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) ++ || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) ++ *parseArrayOffset = CC_PC_PR_VLAN1_OFFSET; ++ else ++ if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST) ++ *parseArrayOffset = CC_PC_PR_VLAN2_OFFSET; ++ break; ++ default: ++ RETURN_ERROR( ++ MAJOR, ++ E_NOT_SUPPORTED, ++ ("Header manipulation of the type VLAN with this field not supported")); ++ } ++ break; ++ default: ++ RETURN_ERROR( ++ MAJOR, ++ E_NOT_SUPPORTED, ++ ("Header manipulation of this header by field not supported")); ++ } ++ } ++ else ++ { ++ switch (hdr) ++ { ++ case (HEADER_TYPE_ETH): ++ *parseArrayOffset = (uint8_t)CC_PC_PR_ETH_OFFSET; ++ break; ++ case (HEADER_TYPE_USER_DEFINED_SHIM1): ++ *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM1_OFFSET; ++ break; ++ case (HEADER_TYPE_USER_DEFINED_SHIM2): ++ *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM2_OFFSET; ++ break; ++ case (HEADER_TYPE_LLC_SNAP): ++ *parseArrayOffset = CC_PC_PR_USER_LLC_SNAP_OFFSET; ++ break; ++ case (HEADER_TYPE_PPPoE): ++ *parseArrayOffset = CC_PC_PR_PPPOE_OFFSET; ++ break; ++ case (HEADER_TYPE_MPLS): ++ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) ++ || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) ++ *parseArrayOffset = CC_PC_PR_MPLS1_OFFSET; ++ else ++ if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST) ++ *parseArrayOffset = CC_PC_PR_MPLS_LAST_OFFSET; ++ break; ++ case (HEADER_TYPE_IPv4): ++ case (HEADER_TYPE_IPv6): ++ if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) ++ || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) ++ *parseArrayOffset = CC_PC_PR_IP1_OFFSET; ++ else ++ if (hdrIndex == e_FM_PCD_HDR_INDEX_2) ++ *parseArrayOffset = CC_PC_PR_IP_LAST_OFFSET; ++ break; ++ case (HEADER_TYPE_MINENCAP): ++ *parseArrayOffset = CC_PC_PR_MINENC_OFFSET; ++ break; ++ case (HEADER_TYPE_GRE): ++ *parseArrayOffset = CC_PC_PR_GRE_OFFSET; ++ break; ++ case (HEADER_TYPE_TCP): ++ case (HEADER_TYPE_UDP): ++ case (HEADER_TYPE_IPSEC_AH): ++ case (HEADER_TYPE_IPSEC_ESP): ++ case (HEADER_TYPE_DCCP): ++ case (HEADER_TYPE_SCTP): ++ *parseArrayOffset = CC_PC_PR_L4_OFFSET; ++ break; ++ case (HEADER_TYPE_CAPWAP): ++ case (HEADER_TYPE_CAPWAP_DTLS): ++ *parseArrayOffset = CC_PC_PR_NEXT_HEADER_OFFSET; ++ break; ++ default: ++ RETURN_ERROR( ++ MAJOR, ++ E_NOT_SUPPORTED, ++ ("Header manipulation of this header is not supported")); ++ } ++ } ++ return E_OK; ++} ++ ++static t_Error BuildHmct(t_FmPcdManip *p_Manip, ++ t_FmPcdManipParams *p_FmPcdManipParams, ++ uint8_t *p_DestHmct, uint8_t *p_DestData, bool new) ++{ ++ uint32_t *p_TmpHmct = (uint32_t*)p_DestHmct, *p_LocalData; ++ uint32_t tmpReg = 0, *p_Last = NULL, tmp_ipv6_addr; ++ uint8_t remain, i, size = 0, origSize, *p_UsrData = NULL, *p_TmpData = ++ p_DestData; ++ t_Handle h_FmPcd = p_Manip->h_FmPcd; ++ uint8_t j = 0; ++ ++ if (p_FmPcdManipParams->u.hdr.rmv) ++ { ++ if (p_FmPcdManipParams->u.hdr.rmvParams.type ++ == e_FM_PCD_MANIP_RMV_GENERIC) ++ { ++ /* initialize HMCD */ ++ tmpReg = (uint32_t)(HMCD_OPCODE_GENERIC_RMV) << HMCD_OC_SHIFT; ++ /* tmp, should be conditional */ ++ tmpReg |= p_FmPcdManipParams->u.hdr.rmvParams.u.generic.offset ++ << HMCD_RMV_OFFSET_SHIFT; ++ tmpReg |= p_FmPcdManipParams->u.hdr.rmvParams.u.generic.size ++ << HMCD_RMV_SIZE_SHIFT; ++ } ++ else ++ if (p_FmPcdManipParams->u.hdr.rmvParams.type ++ == e_FM_PCD_MANIP_RMV_BY_HDR) ++ { ++ switch (p_FmPcdManipParams->u.hdr.rmvParams.u.byHdr.type) ++ { ++ case (e_FM_PCD_MANIP_RMV_BY_HDR_SPECIFIC_L2): ++ { ++ uint8_t hmcdOpt; ++ ++ /* initialize HMCD */ ++ tmpReg = (uint32_t)(HMCD_OPCODE_L2_RMV) << HMCD_OC_SHIFT; ++ ++ switch (p_FmPcdManipParams->u.hdr.rmvParams.u.byHdr.u.specificL2) ++ { ++ case (e_FM_PCD_MANIP_HDR_RMV_ETHERNET): ++ hmcdOpt = HMCD_RMV_L2_ETHERNET; ++ break; ++ case (e_FM_PCD_MANIP_HDR_RMV_STACKED_QTAGS): ++ hmcdOpt = HMCD_RMV_L2_STACKED_QTAGS; ++ break; ++ case (e_FM_PCD_MANIP_HDR_RMV_ETHERNET_AND_MPLS): ++ hmcdOpt = HMCD_RMV_L2_ETHERNET_AND_MPLS; ++ break; ++ case (e_FM_PCD_MANIP_HDR_RMV_MPLS): ++ hmcdOpt = HMCD_RMV_L2_MPLS; ++ break; ++ case (e_FM_PCD_MANIP_HDR_RMV_PPPOE): ++ hmcdOpt = HMCD_RMV_L2_PPPOE; ++ break; ++ default: ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++ } ++ tmpReg |= hmcdOpt << HMCD_L2_MODE_SHIFT; ++ break; ++ } ++#if (DPAA_VERSION >= 11) ++ case (e_FM_PCD_MANIP_RMV_BY_HDR_CAPWAP): ++ tmpReg = (uint32_t)(HMCD_OPCODE_CAPWAP_RMV) ++ << HMCD_OC_SHIFT; ++ break; ++ case (e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START): ++ { ++ uint8_t prsArrayOffset; ++ t_Error err = E_OK; ++ ++ tmpReg = (uint32_t)(HMCD_OPCODE_RMV_TILL) ++ << HMCD_OC_SHIFT; ++ ++ err = ++ GetPrOffsetByHeaderOrField( ++ &p_FmPcdManipParams->u.hdr.rmvParams.u.byHdr.u.hdrInfo, ++ &prsArrayOffset); ++ ASSERT_COND(!err); ++ /* was previously checked */ ++ ++ tmpReg |= ((uint32_t)prsArrayOffset << 16); ++ } ++ break; ++#endif /* (DPAA_VERSION >= 11) */ ++ default: ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("manip header remove by hdr type!")); ++ } ++ } ++ ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ /* save a pointer to the "last" indication word */ ++ p_Last = p_TmpHmct; ++ /* advance to next command */ ++ p_TmpHmct += HMCD_BASIC_SIZE / 4; ++ } ++ ++ if (p_FmPcdManipParams->u.hdr.insrt) ++ { ++ if (p_FmPcdManipParams->u.hdr.insrtParams.type ++ == e_FM_PCD_MANIP_INSRT_GENERIC) ++ { ++ /* initialize HMCD */ ++ if (p_FmPcdManipParams->u.hdr.insrtParams.u.generic.replace) ++ tmpReg = (uint32_t)(HMCD_OPCODE_GENERIC_REPLACE) ++ << HMCD_OC_SHIFT; ++ else ++ tmpReg = (uint32_t)(HMCD_OPCODE_GENERIC_INSRT) << HMCD_OC_SHIFT; ++ ++ tmpReg |= p_FmPcdManipParams->u.hdr.insrtParams.u.generic.offset ++ << HMCD_INSRT_OFFSET_SHIFT; ++ tmpReg |= p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size ++ << HMCD_INSRT_SIZE_SHIFT; ++ ++ size = p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size; ++ p_UsrData = p_FmPcdManipParams->u.hdr.insrtParams.u.generic.p_Data; ++ ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ /* save a pointer to the "last" indication word */ ++ p_Last = p_TmpHmct; ++ ++ p_TmpHmct += HMCD_BASIC_SIZE / 4; ++ ++ /* initialize data to be inserted */ ++ /* if size is not a multiple of 4, padd with 0's */ ++ origSize = size; ++ remain = (uint8_t)(size % 4); ++ if (remain) ++ { ++ size += (uint8_t)(4 - remain); ++ p_LocalData = (uint32_t *)XX_Malloc(size); ++ memset((uint8_t *)p_LocalData, 0, size); ++ memcpy((uint8_t *)p_LocalData, p_UsrData, origSize); ++ } ++ else ++ p_LocalData = (uint32_t*)p_UsrData; ++ ++ /* initialize data and advance pointer to next command */ ++ MemCpy8(p_TmpHmct, p_LocalData, size); ++ p_TmpHmct += size / sizeof(uint32_t); ++ ++ if (remain) ++ XX_Free(p_LocalData); ++ } ++ ++ else ++ if (p_FmPcdManipParams->u.hdr.insrtParams.type ++ == e_FM_PCD_MANIP_INSRT_BY_HDR) ++ { ++ switch (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.type) ++ { ++ case (e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2): ++ { ++ uint8_t hmcdOpt; ++ ++ /* initialize HMCD */ ++ tmpReg = (uint32_t)(HMCD_OPCODE_L2_INSRT) ++ << HMCD_OC_SHIFT; ++ ++ switch (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.specificL2) ++ { ++ case (e_FM_PCD_MANIP_HDR_INSRT_MPLS): ++ if (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.update) ++ hmcdOpt = HMCD_INSRT_N_UPDATE_L2_MPLS; ++ else ++ hmcdOpt = HMCD_INSRT_L2_MPLS; ++ break; ++ case (e_FM_PCD_MANIP_HDR_INSRT_PPPOE): ++ hmcdOpt = HMCD_INSRT_L2_PPPOE; ++ break; ++ default: ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); ++ } ++ tmpReg |= hmcdOpt << HMCD_L2_MODE_SHIFT; ++ ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ /* save a pointer to the "last" indication word */ ++ p_Last = p_TmpHmct; ++ ++ p_TmpHmct += HMCD_BASIC_SIZE / 4; ++ ++ /* set size and pointer of user's data */ ++ size = ++ (uint8_t)p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.size; ++ ++ ASSERT_COND(p_TmpData); ++ MemCpy8( ++ p_TmpData, ++ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.p_Data, ++ size); ++ tmpReg = ++ (size << HMCD_INSRT_L2_SIZE_SHIFT) ++ | (uint32_t)(XX_VirtToPhys(p_TmpData) ++ - (((t_FmPcd*)h_FmPcd)->physicalMuramBase)); ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ p_TmpHmct += HMCD_PTR_SIZE / 4; ++ p_TmpData += size; ++ } ++ break; ++#if (DPAA_VERSION >= 11) ++ case (e_FM_PCD_MANIP_INSRT_BY_HDR_IP): ++ tmpReg = (uint32_t)(HMCD_OPCODE_IP_INSRT) ++ << HMCD_OC_SHIFT; ++ if (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.calcL4Checksum) ++ tmpReg |= HMCD_IP_L4_CS_CALC; ++ if (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.mappingMode ++ == e_FM_PCD_MANIP_HDR_QOS_MAPPING_AS_IS) ++ tmpReg |= HMCD_IP_OR_QOS; ++ tmpReg |= ++ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.lastPidOffset ++ & HMCD_IP_LAST_PID_MASK; ++ tmpReg |= ++ ((p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size ++ << HMCD_IP_SIZE_SHIFT) ++ & HMCD_IP_SIZE_MASK); ++ if (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.dontFragOverwrite) ++ tmpReg |= HMCD_IP_DF_MODE; ++ ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ ++ /* save a pointer to the "last" indication word */ ++ p_Last = p_TmpHmct; ++ ++ p_TmpHmct += HMCD_BASIC_SIZE / 4; ++ ++ /* set IP id */ ++ ASSERT_COND(p_TmpData); ++ WRITE_UINT16( ++ *(uint16_t*)p_TmpData, ++ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.id); ++ WRITE_UINT32( ++ *p_TmpHmct, ++ (uint32_t)(XX_VirtToPhys(p_TmpData) - (((t_FmPcd*)p_Manip->h_FmPcd)->physicalMuramBase))); ++ p_TmpData += 2; ++ p_TmpHmct += HMCD_PTR_SIZE / 4; ++ ++ WRITE_UINT8(*p_TmpHmct, p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.lastDstOffset); ++ p_TmpHmct += HMCD_PARAM_SIZE / 4; ++ ++ MemCpy8( ++ p_TmpHmct, ++ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.p_Data, ++ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size); ++ p_TmpHmct += ++ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size ++ / 4; ++ break; ++ case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE): ++ tmpReg = HMCD_INSRT_UDP_LITE; ++ case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP): ++ tmpReg |= (uint32_t)(HMCD_OPCODE_UDP_INSRT) ++ << HMCD_OC_SHIFT; ++ ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ ++ /* save a pointer to the "last" indication word */ ++ p_Last = p_TmpHmct; ++ ++ p_TmpHmct += HMCD_BASIC_SIZE / 4; ++ ++ MemCpy8( ++ p_TmpHmct, ++ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.p_Data, ++ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size); ++ p_TmpHmct += ++ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size ++ / 4; ++ break; ++ case (e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP): ++ tmpReg = (uint32_t)(HMCD_OPCODE_CAPWAP_INSRT) ++ << HMCD_OC_SHIFT; ++ tmpReg |= HMCD_CAPWAP_INSRT; ++ ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ ++ /* save a pointer to the "last" indication word */ ++ p_Last = p_TmpHmct; ++ ++ p_TmpHmct += HMCD_BASIC_SIZE / 4; ++ ++ MemCpy8( ++ p_TmpHmct, ++ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.p_Data, ++ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size); ++ p_TmpHmct += ++ p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size ++ / 4; ++ break; ++#endif /* (DPAA_VERSION >= 11) */ ++ default: ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("manip header insert by header type!")); ++ ++ } ++ } ++ } ++ ++ if (p_FmPcdManipParams->u.hdr.fieldUpdate) ++ { ++ switch (p_FmPcdManipParams->u.hdr.fieldUpdateParams.type) ++ { ++ case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN): ++ /* set opcode */ ++ tmpReg = (uint32_t)(HMCD_OPCODE_VLAN_PRI_UPDATE) ++ << HMCD_OC_SHIFT; ++ ++ /* set mode & table pointer */ ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType ++ == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN) ++ { ++ /* set Mode */ ++ tmpReg |= (uint32_t)(HMCD_VLAN_PRI_UPDATE_DSCP_TO_VPRI) ++ << HMCD_VLAN_PRI_REP_MODE_SHIFT; ++ /* set VPRI default */ ++ tmpReg |= ++ p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.u.dscpToVpri.vpriDefVal; ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ /* save a pointer to the "last" indication word */ ++ p_Last = p_TmpHmct; ++ /* write the table pointer into the Manip descriptor */ ++ p_TmpHmct += HMCD_BASIC_SIZE / 4; ++ ++ tmpReg = 0; ++ ASSERT_COND(p_TmpData); ++ for (i = 0; i < HMCD_DSCP_VALUES; i++) ++ { ++ /* first we build from each 8 values a 32bit register */ ++ tmpReg |= ++ (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.u.dscpToVpri.dscpToVpriTable[i]) ++ << (32 - 4 * (j + 1)); ++ j++; ++ /* Than we write this register to the next table word ++ * (i=7-->word 0, i=15-->word 1,... i=63-->word 7) */ ++ if ((i % 8) == 7) ++ { ++ WRITE_UINT32(*((uint32_t*)p_TmpData + (i+1)/8-1), ++ tmpReg); ++ tmpReg = 0; ++ j = 0; ++ } ++ } ++ ++ WRITE_UINT32( ++ *p_TmpHmct, ++ (uint32_t)(XX_VirtToPhys(p_TmpData) - (((t_FmPcd*)h_FmPcd)->physicalMuramBase))); ++ p_TmpHmct += HMCD_PTR_SIZE / 4; ++ ++ p_TmpData += DSCP_TO_VLAN_TABLE_SIZE; ++ } ++ else ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType ++ == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_VPRI) ++ { ++ /* set Mode */ ++ /* line commented out as it has no-side-effect ('0' value). */ ++ /*tmpReg |= HMCD_VLAN_PRI_UPDATE << HMCD_VLAN_PRI_REP_MODE_SHIFT*/; ++ /* set VPRI parameter */ ++ tmpReg |= ++ p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.u.vpri; ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ /* save a pointer to the "last" indication word */ ++ p_Last = p_TmpHmct; ++ p_TmpHmct += HMCD_BASIC_SIZE / 4; ++ } ++ break; ++ ++ case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4): ++ /* set opcode */ ++ tmpReg = (uint32_t)(HMCD_OPCODE_IPV4_UPDATE) << HMCD_OC_SHIFT; ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates ++ & HDR_MANIP_IPV4_TTL) ++ tmpReg |= HMCD_IPV4_UPDATE_TTL; ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates ++ & HDR_MANIP_IPV4_TOS) ++ { ++ tmpReg |= HMCD_IPV4_UPDATE_TOS; ++ tmpReg |= ++ p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.tos ++ << HMCD_IPV4_UPDATE_TOS_SHIFT; ++ } ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates ++ & HDR_MANIP_IPV4_ID) ++ tmpReg |= HMCD_IPV4_UPDATE_ID; ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates ++ & HDR_MANIP_IPV4_SRC) ++ tmpReg |= HMCD_IPV4_UPDATE_SRC; ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates ++ & HDR_MANIP_IPV4_DST) ++ tmpReg |= HMCD_IPV4_UPDATE_DST; ++ /* write the first 4 bytes of the descriptor */ ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ /* save a pointer to the "last" indication word */ ++ p_Last = p_TmpHmct; ++ ++ p_TmpHmct += HMCD_BASIC_SIZE / 4; ++ ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates ++ & HDR_MANIP_IPV4_ID) ++ { ++ ASSERT_COND(p_TmpData); ++ WRITE_UINT16( ++ *(uint16_t*)p_TmpData, ++ p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.id); ++ WRITE_UINT32( ++ *p_TmpHmct, ++ (uint32_t)(XX_VirtToPhys(p_TmpData) - (((t_FmPcd*)p_Manip->h_FmPcd)->physicalMuramBase))); ++ p_TmpData += 2; ++ p_TmpHmct += HMCD_PTR_SIZE / 4; ++ } ++ ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates ++ & HDR_MANIP_IPV4_SRC) ++ { ++ WRITE_UINT32( ++ *p_TmpHmct, ++ p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.src); ++ p_TmpHmct += HMCD_IPV4_ADDR_SIZE / 4; ++ } ++ ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates ++ & HDR_MANIP_IPV4_DST) ++ { ++ WRITE_UINT32( ++ *p_TmpHmct, ++ p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.dst); ++ p_TmpHmct += HMCD_IPV4_ADDR_SIZE / 4; ++ } ++ break; ++ ++ case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6): ++ /* set opcode */ ++ tmpReg = (uint32_t)(HMCD_OPCODE_IPV6_UPDATE) << HMCD_OC_SHIFT; ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates ++ & HDR_MANIP_IPV6_HL) ++ tmpReg |= HMCD_IPV6_UPDATE_HL; ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates ++ & HDR_MANIP_IPV6_TC) ++ { ++ tmpReg |= HMCD_IPV6_UPDATE_TC; ++ tmpReg |= ++ p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.trafficClass ++ << HMCD_IPV6_UPDATE_TC_SHIFT; ++ } ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates ++ & HDR_MANIP_IPV6_SRC) ++ tmpReg |= HMCD_IPV6_UPDATE_SRC; ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates ++ & HDR_MANIP_IPV6_DST) ++ tmpReg |= HMCD_IPV6_UPDATE_DST; ++ /* write the first 4 bytes of the descriptor */ ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ /* save a pointer to the "last" indication word */ ++ p_Last = p_TmpHmct; ++ ++ p_TmpHmct += HMCD_BASIC_SIZE / 4; ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates ++ & HDR_MANIP_IPV6_SRC) ++ { ++ for (i = 0; i < NET_HEADER_FIELD_IPv6_ADDR_SIZE; i += 4) ++ { ++ memcpy(&tmp_ipv6_addr, ++ &p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.src[i], ++ sizeof(uint32_t)); ++ WRITE_UINT32(*p_TmpHmct, tmp_ipv6_addr); ++ p_TmpHmct += HMCD_PTR_SIZE / 4; ++ } ++ } ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates ++ & HDR_MANIP_IPV6_DST) ++ { ++ for (i = 0; i < NET_HEADER_FIELD_IPv6_ADDR_SIZE; i += 4) ++ { ++ memcpy(&tmp_ipv6_addr, ++ &p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.dst[i], ++ sizeof(uint32_t)); ++ WRITE_UINT32(*p_TmpHmct, tmp_ipv6_addr); ++ p_TmpHmct += HMCD_PTR_SIZE / 4; ++ } ++ } ++ break; ++ ++ case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP): ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates ++ == HDR_MANIP_TCP_UDP_CHECKSUM) ++ { ++ /* we implement this case with the update-checksum descriptor */ ++ /* set opcode */ ++ tmpReg = (uint32_t)(HMCD_OPCODE_TCP_UDP_CHECKSUM) ++ << HMCD_OC_SHIFT; ++ /* write the first 4 bytes of the descriptor */ ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ /* save a pointer to the "last" indication word */ ++ p_Last = p_TmpHmct; ++ ++ p_TmpHmct += HMCD_BASIC_SIZE / 4; ++ } ++ else ++ { ++ /* we implement this case with the TCP/UDP update descriptor */ ++ /* set opcode */ ++ tmpReg = (uint32_t)(HMCD_OPCODE_TCP_UDP_UPDATE) ++ << HMCD_OC_SHIFT; ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates ++ & HDR_MANIP_TCP_UDP_DST) ++ tmpReg |= HMCD_TCP_UDP_UPDATE_DST; ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates ++ & HDR_MANIP_TCP_UDP_SRC) ++ tmpReg |= HMCD_TCP_UDP_UPDATE_SRC; ++ /* write the first 4 bytes of the descriptor */ ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ /* save a pointer to the "last" indication word */ ++ p_Last = p_TmpHmct; ++ ++ p_TmpHmct += HMCD_BASIC_SIZE / 4; ++ ++ tmpReg = 0; ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates ++ & HDR_MANIP_TCP_UDP_SRC) ++ tmpReg |= ++ ((uint32_t)p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.src) ++ << HMCD_TCP_UDP_UPDATE_SRC_SHIFT; ++ if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates ++ & HDR_MANIP_TCP_UDP_DST) ++ tmpReg |= ++ ((uint32_t)p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.dst); ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ p_TmpHmct += HMCD_PTR_SIZE / 4; ++ } ++ break; ++ ++ default: ++ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ++ ("Unknown fieldUpdateParams.type")); ++ } ++ } ++ ++ if (p_FmPcdManipParams->u.hdr.custom) ++ { ++ switch (p_FmPcdManipParams->u.hdr.customParams.type) ++ { ++ case (e_FM_PCD_MANIP_HDR_CUSTOM_IP_REPLACE): ++ /* set opcode */ ++ tmpReg = (uint32_t)(HMCD_OPCODE_REPLACE_IP) << HMCD_OC_SHIFT; ++ ++ if (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.decTtlHl) ++ tmpReg |= HMCD_IP_REPLACE_TTL_HL; ++ if (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.replaceType ++ == e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV4_BY_IPV6) ++ /* line commented out as it has no-side-effect ('0' value). */ ++ /*tmpReg |= HMCD_IP_REPLACE_REPLACE_IPV4*/; ++ else ++ if (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.replaceType ++ == e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4) ++ { ++ tmpReg |= HMCD_IP_REPLACE_REPLACE_IPV6; ++ if (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.updateIpv4Id) ++ tmpReg |= HMCD_IP_REPLACE_ID; ++ } ++ else ++ RETURN_ERROR( ++ MINOR, ++ E_NOT_SUPPORTED, ++ ("One flag out of HDR_MANIP_IP_REPLACE_IPV4, HDR_MANIP_IP_REPLACE_IPV6 - must be set.")); ++ ++ /* write the first 4 bytes of the descriptor */ ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ /* save a pointer to the "last" indication word */ ++ p_Last = p_TmpHmct; ++ ++ p_TmpHmct += HMCD_BASIC_SIZE / 4; ++ ++ size = ++ p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.hdrSize; ++ ASSERT_COND(p_TmpData); ++ MemCpy8( ++ p_TmpData, ++ p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.hdr, ++ size); ++ tmpReg = (uint32_t)(size << HMCD_IP_REPLACE_L3HDRSIZE_SHIFT); ++ tmpReg |= (uint32_t)(XX_VirtToPhys(p_TmpData) ++ - (((t_FmPcd*)h_FmPcd)->physicalMuramBase)); ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ p_TmpHmct += HMCD_PTR_SIZE / 4; ++ p_TmpData += size; ++ ++ if ((p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.replaceType ++ == e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4) ++ && (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.updateIpv4Id)) ++ { ++ WRITE_UINT16( ++ *(uint16_t*)p_TmpData, ++ p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.id); ++ WRITE_UINT32( ++ *p_TmpHmct, ++ (uint32_t)(XX_VirtToPhys(p_TmpData) - (((t_FmPcd*)h_FmPcd)->physicalMuramBase))); ++ p_TmpData += 2; ++ } ++ p_TmpHmct += HMCD_PTR_SIZE / 4; ++ break; ++ case (e_FM_PCD_MANIP_HDR_CUSTOM_GEN_FIELD_REPLACE): ++ /* set opcode */ ++ tmpReg = (uint32_t)(HMCD_OPCODE_GEN_FIELD_REPLACE) << HMCD_OC_SHIFT; ++ tmpReg |= p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.size << HMCD_GEN_FIELD_SIZE_SHIFT; ++ tmpReg |= p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.srcOffset << HMCD_GEN_FIELD_SRC_OFF_SHIFT; ++ tmpReg |= p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.dstOffset << HMCD_GEN_FIELD_DST_OFF_SHIFT; ++ if (p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.mask) ++ tmpReg |= HMCD_GEN_FIELD_MASK_EN; ++ ++ /* write the first 4 bytes of the descriptor */ ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ /* save a pointer to the "last" indication word */ ++ p_Last = p_TmpHmct; ++ ++ p_TmpHmct += HMCD_BASIC_SIZE/4; ++ ++ if (p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.mask) ++ { ++ tmpReg = p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.mask << HMCD_GEN_FIELD_MASK_SHIFT; ++ tmpReg |= p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.maskOffset << HMCD_GEN_FIELD_MASK_OFF_SHIFT; ++ /* write the next 4 bytes of the descriptor */ ++ WRITE_UINT32(*p_TmpHmct, tmpReg); ++ } ++ p_TmpHmct += HMCD_PARAM_SIZE/4; ++ break; ++ default: ++ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ++ ("Unknown customParams.type")); ++ } ++ } ++ ++ /* If this node has a nextManip, and no parsing is required, the old table must be copied to the new table ++ the old table and should be freed */ ++ if (p_FmPcdManipParams->h_NextManip ++ && (p_Manip->nextManipType == e_FM_PCD_MANIP_HDR) ++ && (MANIP_DONT_REPARSE(p_Manip))) ++ { ++ if (new) ++ { ++ /* If this is the first time this manip is created we need to free unused memory. If it ++ * is a dynamic changes case, the memory used is either the CC shadow or the existing ++ * table - no allocation, no free */ ++ MANIP_UPDATE_UNIFIED_POSITION(p_FmPcdManipParams->h_NextManip); ++ ++ p_Manip->unifiedPosition = e_MANIP_UNIFIED_FIRST; ++ } ++ } ++ else ++ { ++ ASSERT_COND(p_Last); ++ /* set the "last" indication on the last command of the current table */ ++ WRITE_UINT32(*p_Last, GET_UINT32(*p_Last) | HMCD_LAST); ++ } ++ ++ return E_OK; ++} ++ ++static t_Error CreateManipActionNew(t_FmPcdManip *p_Manip, ++ t_FmPcdManipParams *p_FmPcdManipParams) ++{ ++ t_FmPcdManip *p_CurManip; ++ t_Error err; ++ uint32_t nextSize = 0, totalSize; ++ uint16_t tmpReg; ++ uint8_t *p_OldHmct, *p_TmpHmctPtr, *p_TmpDataPtr; ++ ++ /* set Manip structure */ ++ ++ p_Manip->dontParseAfterManip = ++ p_FmPcdManipParams->u.hdr.dontParseAfterManip; ++ ++ if (p_FmPcdManipParams->h_NextManip) ++ { /* Next Header manipulation exists */ ++ p_Manip->nextManipType = MANIP_GET_TYPE(p_FmPcdManipParams->h_NextManip); ++ ++ if ((p_Manip->nextManipType == e_FM_PCD_MANIP_HDR) && p_Manip->dontParseAfterManip) ++ nextSize = (uint32_t)(GetHmctSize(p_FmPcdManipParams->h_NextManip) ++ + GetDataSize(p_FmPcdManipParams->h_NextManip)); ++ else /* either parsing is required or next manip is Frag; no table merging. */ ++ p_Manip->cascaded = TRUE; ++ /* pass up the "cascaded" attribute. The whole chain is cascaded ++ * if something is cascaded along the way. */ ++ if (MANIP_IS_CASCADED(p_FmPcdManipParams->h_NextManip)) ++ p_Manip->cascaded = TRUE; ++ } ++ ++ /* Allocate new table */ ++ /* calculate table size according to manip parameters */ ++ err = CalculateTableSize(p_FmPcdManipParams, &p_Manip->tableSize, ++ &p_Manip->dataSize); ++ if (err) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ totalSize = (uint16_t)(p_Manip->tableSize + p_Manip->dataSize + nextSize); ++ ++ p_Manip->p_Hmct = (uint8_t*)FM_MURAM_AllocMem( ++ ((t_FmPcd *)p_Manip->h_FmPcd)->h_FmMuram, totalSize, 4); ++ if (!p_Manip->p_Hmct) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc failed")); ++ ++ if (p_Manip->dataSize) ++ p_Manip->p_Data = ++ (uint8_t*)PTR_MOVE(p_Manip->p_Hmct, (p_Manip->tableSize + nextSize)); ++ ++ /* update shadow size to allow runtime replacement of Header manipulation */ ++ /* The allocated shadow is divided as follows: ++ 0 . . . 16 . . . ++ -------------------------------- ++ | Shadow | Shadow HMTD | ++ | HMTD | Match Table | ++ | (16 bytes) | (maximal size) | ++ -------------------------------- ++ */ ++ ++ err = FmPcdUpdateCcShadow(p_Manip->h_FmPcd, (uint32_t)(totalSize + 16), ++ (uint16_t)FM_PCD_CC_AD_TABLE_ALIGN); ++ if (err != E_OK) ++ { ++ FM_MURAM_FreeMem(p_Manip->h_FmPcd, p_Manip->p_Hmct); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("MURAM allocation for HdrManip node shadow")); ++ } ++ ++ if (p_FmPcdManipParams->h_NextManip ++ && (p_Manip->nextManipType == e_FM_PCD_MANIP_HDR) ++ && (MANIP_DONT_REPARSE(p_Manip))) ++ { ++ p_OldHmct = (uint8_t *)GetManipInfo(p_FmPcdManipParams->h_NextManip, ++ e_MANIP_HMCT); ++ p_CurManip = p_FmPcdManipParams->h_NextManip; ++ /* Run till the last Manip (which is the first to configure) */ ++ while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip)) ++ p_CurManip = p_CurManip->h_NextManip; ++ ++ while (p_CurManip) ++ { ++ /* If this is a unified table, point to the part of the table ++ * which is the relative offset in HMCT. ++ */ ++ p_TmpHmctPtr = (uint8_t*)PTR_MOVE(p_Manip->p_Hmct, ++ (p_Manip->tableSize + ++ (PTR_TO_UINT(p_CurManip->p_Hmct) - ++ PTR_TO_UINT(p_OldHmct)))); ++ if (p_CurManip->p_Data) ++ p_TmpDataPtr = (uint8_t*)PTR_MOVE(p_Manip->p_Hmct, ++ (p_Manip->tableSize + ++ (PTR_TO_UINT(p_CurManip->p_Data) - ++ PTR_TO_UINT(p_OldHmct)))); ++ else ++ p_TmpDataPtr = NULL; ++ ++ BuildHmct(p_CurManip, &p_CurManip->manipParams, p_TmpHmctPtr, ++ p_TmpDataPtr, FALSE); ++ /* update old manip table pointer */ ++ MANIP_SET_HMCT_PTR(p_CurManip, p_TmpHmctPtr); ++ MANIP_SET_DATA_PTR(p_CurManip, p_TmpDataPtr); ++ ++ p_CurManip = p_CurManip->h_PrevManip; ++ } ++ /* We copied the HMCT to create a new large HMCT so we can free the old one */ ++ FM_MURAM_FreeMem(MANIP_GET_MURAM(p_FmPcdManipParams->h_NextManip), ++ p_OldHmct); ++ } ++ ++ /* Fill table */ ++ err = BuildHmct(p_Manip, p_FmPcdManipParams, p_Manip->p_Hmct, ++ p_Manip->p_Data, TRUE); ++ if (err) ++ { ++ FM_MURAM_FreeMem(p_Manip->h_FmPcd, p_Manip->p_Hmct); ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ /* Build HMTD (table descriptor) */ ++ tmpReg = HMTD_CFG_TYPE; /* NADEN = 0 */ ++ ++ /* add parseAfterManip */ ++ if (!p_Manip->dontParseAfterManip) ++ tmpReg |= HMTD_CFG_PRS_AFTER_HM; ++ ++ /* create cascade */ ++ /*if (p_FmPcdManipParams->h_NextManip ++ && (!MANIP_DONT_REPARSE(p_Manip) || (p_Manip->nextManipType != e_FM_PCD_MANIP_HDR)))*/ ++ if (p_Manip->cascaded) ++ { ++ uint16_t nextAd; ++ /* indicate that there's another HM table descriptor */ ++ tmpReg |= HMTD_CFG_NEXT_AD_EN; ++ /* get address of next HMTD (table descriptor; h_Ad). ++ * If the next HMTD was removed due to table unifing, get the address ++ * of the "next next" as written in the h_Ad of the next h_Manip node. ++ */ ++ if (p_Manip->unifiedPosition != e_MANIP_UNIFIED_FIRST) ++ nextAd = (uint16_t)((uint32_t)(XX_VirtToPhys(MANIP_GET_HMTD_PTR(p_FmPcdManipParams->h_NextManip)) - (((t_FmPcd*)p_Manip->h_FmPcd)->physicalMuramBase)) >> 4); ++ else ++ nextAd = ((t_Hmtd *)((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_Ad)->nextAdIdx; ++ ++ WRITE_UINT16(((t_Hmtd *)p_Manip->h_Ad)->nextAdIdx, nextAd); ++ } ++ ++ WRITE_UINT16(((t_Hmtd *)p_Manip->h_Ad)->cfg, tmpReg); ++ WRITE_UINT32( ++ ((t_Hmtd *)p_Manip->h_Ad)->hmcdBasePtr, ++ (uint32_t)(XX_VirtToPhys(p_Manip->p_Hmct) - (((t_FmPcd*)p_Manip->h_FmPcd)->physicalMuramBase))); ++ ++ WRITE_UINT8(((t_Hmtd *)p_Manip->h_Ad)->opCode, HMAN_OC); ++ ++ if (p_Manip->unifiedPosition == e_MANIP_UNIFIED_FIRST) ++ { ++ /* The HMTD of the next Manip is never going to be used */ ++ if (((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->muramAllocate) ++ FM_MURAM_FreeMem( ++ ((t_FmPcd *)((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_FmPcd)->h_FmMuram, ++ ((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_Ad); ++ else ++ XX_Free(((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_Ad); ++ ((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_Ad = NULL; ++ } ++ ++ return E_OK; ++} ++ ++static t_Error CreateManipActionShadow(t_FmPcdManip *p_Manip, ++ t_FmPcdManipParams *p_FmPcdManipParams) ++{ ++ uint8_t *p_WholeHmct, *p_TmpHmctPtr, newDataSize, *p_TmpDataPtr = NULL; ++ uint16_t newSize; ++ t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd; ++ t_Error err; ++ t_FmPcdManip *p_CurManip = p_Manip; ++ ++ err = CalculateTableSize(p_FmPcdManipParams, &newSize, &newDataSize); ++ if (err) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ /* check coherency of new table parameters */ ++ if (newSize > p_Manip->tableSize) ++ RETURN_ERROR( ++ MINOR, ++ E_INVALID_VALUE, ++ ("New Hdr Manip configuration requires larger size than current one (command table).")); ++ if (newDataSize > p_Manip->dataSize) ++ RETURN_ERROR( ++ MINOR, ++ E_INVALID_VALUE, ++ ("New Hdr Manip configuration requires larger size than current one (data).")); ++ if (p_FmPcdManipParams->h_NextManip) ++ RETURN_ERROR( ++ MINOR, E_INVALID_VALUE, ++ ("New Hdr Manip configuration can not contain h_NextManip.")); ++ if (MANIP_IS_UNIFIED(p_Manip) && (newSize != p_Manip->tableSize)) ++ RETURN_ERROR( ++ MINOR, ++ E_INVALID_VALUE, ++ ("New Hdr Manip configuration in a chained manipulation requires different size than current one.")); ++ if (p_Manip->dontParseAfterManip ++ != p_FmPcdManipParams->u.hdr.dontParseAfterManip) ++ RETURN_ERROR( ++ MINOR, ++ E_INVALID_VALUE, ++ ("New Hdr Manip configuration differs in dontParseAfterManip value.")); ++ ++ p_Manip->tableSize = newSize; ++ p_Manip->dataSize = newDataSize; ++ ++ /* Build the new table in the shadow */ ++ if (!MANIP_IS_UNIFIED(p_Manip)) ++ { ++ p_TmpHmctPtr = (uint8_t*)PTR_MOVE(p_FmPcd->p_CcShadow, 16); ++ if (p_Manip->p_Data) ++ p_TmpDataPtr = ++ (uint8_t*)PTR_MOVE(p_TmpHmctPtr, ++ (PTR_TO_UINT(p_Manip->p_Data) - PTR_TO_UINT(p_Manip->p_Hmct))); ++ ++ BuildHmct(p_Manip, p_FmPcdManipParams, p_TmpHmctPtr, p_Manip->p_Data, ++ FALSE); ++ } ++ else ++ { ++ p_WholeHmct = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMCT); ++ ASSERT_COND(p_WholeHmct); ++ ++ /* Run till the last Manip (which is the first to configure) */ ++ while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip)) ++ p_CurManip = p_CurManip->h_NextManip; ++ ++ while (p_CurManip) ++ { ++ /* If this is a non-head node in a unified table, point to the part of the shadow ++ * which is the relative offset in HMCT. ++ * else, point to the beginning of the ++ * shadow table (we save 16 for the HMTD. ++ */ ++ p_TmpHmctPtr = ++ (uint8_t*)PTR_MOVE(p_FmPcd->p_CcShadow, ++ (16 + PTR_TO_UINT(p_CurManip->p_Hmct) - PTR_TO_UINT(p_WholeHmct))); ++ if (p_CurManip->p_Data) ++ p_TmpDataPtr = ++ (uint8_t*)PTR_MOVE(p_FmPcd->p_CcShadow, ++ (16 + PTR_TO_UINT(p_CurManip->p_Data) - PTR_TO_UINT(p_WholeHmct))); ++ ++ BuildHmct(p_CurManip, &p_CurManip->manipParams, p_TmpHmctPtr, ++ p_TmpDataPtr, FALSE); ++ p_CurManip = p_CurManip->h_PrevManip; ++ } ++ } ++ ++ return E_OK; ++} ++ ++static t_Error CreateManipActionBackToOrig( ++ t_FmPcdManip *p_Manip, t_FmPcdManipParams *p_FmPcdManipParams) ++{ ++ uint8_t *p_WholeHmct = NULL, *p_TmpHmctPtr, *p_TmpDataPtr; ++ t_FmPcdManip *p_CurManip = p_Manip; ++ ++ /* Build the new table in the shadow */ ++ if (!MANIP_IS_UNIFIED(p_Manip)) ++ BuildHmct(p_Manip, p_FmPcdManipParams, p_Manip->p_Hmct, p_Manip->p_Data, ++ FALSE); ++ else ++ { ++ p_WholeHmct = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMCT); ++ ASSERT_COND(p_WholeHmct); ++ ++ /* Run till the last Manip (which is the first to configure) */ ++ while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip)) ++ p_CurManip = p_CurManip->h_NextManip; ++ ++ while (p_CurManip) ++ { ++ /* If this is a unified table, point to the part of the table ++ * which is the relative offset in HMCT. ++ */ ++ p_TmpHmctPtr = p_CurManip->p_Hmct; /*- (uint32_t)p_WholeHmct*/ ++ p_TmpDataPtr = p_CurManip->p_Data; /*- (uint32_t)p_WholeHmct*/ ++ ++ BuildHmct(p_CurManip, &p_CurManip->manipParams, p_TmpHmctPtr, ++ p_TmpDataPtr, FALSE); ++ ++ p_CurManip = p_CurManip->h_PrevManip; ++ } ++ } ++ ++ return E_OK; ++} ++ ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++static t_Error UpdateManipIc(t_Handle h_Manip, uint8_t icOffset) ++{ ++ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; ++ t_Handle p_Ad; ++ uint32_t tmpReg32 = 0; ++ SANITY_CHECK_RETURN_ERROR(h_Manip, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad, E_INVALID_HANDLE); ++ ++ switch (p_Manip->opcode) ++ { ++ case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX): ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; ++ if (p_Manip->updateParams & INTERNAL_CONTEXT_OFFSET) ++ { ++ tmpReg32 = ++ *(uint32_t *)&((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets; ++ tmpReg32 |= (uint32_t)((uint32_t)icOffset << 16); ++ *(uint32_t *)&((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets = ++ tmpReg32; ++ p_Manip->updateParams &= ~INTERNAL_CONTEXT_OFFSET; ++ p_Manip->icOffset = icOffset; ++ } ++ else ++ { ++ if (p_Manip->icOffset != icOffset) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("this manipulation was updated previously by different value");); ++ } ++ break; ++ case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST): ++ if (p_Manip->h_Frag) ++ { ++ if (p_Manip->updateParams & INTERNAL_CONTEXT_OFFSET) ++ { ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; ++ tmpReg32 |= GET_UINT32(((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets); ++ tmpReg32 |= (uint32_t)((uint32_t)icOffset << 16); ++ WRITE_UINT32(((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets, tmpReg32); ++ p_Manip->updateParams &= ~INTERNAL_CONTEXT_OFFSET; ++ p_Manip->icOffset = icOffset; ++ } ++ else ++ { ++ if (p_Manip->icOffset != icOffset) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("this manipulation was updated previousely by different value");); ++ } ++ } ++ break; ++ } ++ ++ return E_OK; ++} ++ ++static t_Error UpdateInitMvIntFrameHeaderFromFrameToBufferPrefix( ++ t_Handle h_FmPort, t_FmPcdManip *p_Manip, t_Handle h_Ad, bool validate) ++{ ++ ++ t_AdOfTypeContLookup *p_Ad = (t_AdOfTypeContLookup *)h_Ad; ++ t_FmPortGetSetCcParams fmPortGetSetCcParams; ++ t_Error err; ++ uint32_t tmpReg32; ++ ++ memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams)); ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR( ++ (p_Manip->opcode & HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX), ++ E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(!p_Manip->muramAllocate, E_INVALID_STATE); ++ ++ if (p_Manip->updateParams) ++ { ++ if ((!(p_Manip->updateParams & OFFSET_OF_PR)) ++ || (p_Manip->shadowUpdateParams & OFFSET_OF_PR)) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_STATE, ++ ("in this stage parameters from Port has not be updated")); ++ ++ fmPortGetSetCcParams.getCcParams.type = p_Manip->updateParams; ++ fmPortGetSetCcParams.setCcParams.type = UPDATE_PSO; ++ fmPortGetSetCcParams.setCcParams.psoSize = 16; ++ ++ err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_PR) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_STATE, ++ ("Parser result offset wasn't configured previousely")); ++#ifdef FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 ++ ASSERT_COND(!(fmPortGetSetCcParams.getCcParams.prOffset % 16)); ++#endif ++ } ++ else ++ if (validate) ++ { ++ if ((!(p_Manip->shadowUpdateParams & OFFSET_OF_PR)) ++ || (p_Manip->updateParams & OFFSET_OF_PR)) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_STATE, ++ ("in this stage parameters from Port has be updated")); ++ fmPortGetSetCcParams.getCcParams.type = p_Manip->shadowUpdateParams; ++ fmPortGetSetCcParams.setCcParams.type = UPDATE_PSO; ++ fmPortGetSetCcParams.setCcParams.psoSize = 16; ++ ++ err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_PR) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_STATE, ++ ("Parser result offset wasn't configured previousely")); ++ ++ } ++ ++ ASSERT_COND(p_Ad); ++ ++ if (p_Manip->updateParams & OFFSET_OF_PR) ++ { ++ tmpReg32 = 0; ++ tmpReg32 |= fmPortGetSetCcParams.getCcParams.prOffset; ++ WRITE_UINT32(p_Ad->matchTblPtr, ++ (GET_UINT32(p_Ad->matchTblPtr) | tmpReg32)); ++ p_Manip->updateParams &= ~OFFSET_OF_PR; ++ p_Manip->shadowUpdateParams |= OFFSET_OF_PR; ++ } ++ else ++ if (validate) ++ { ++ tmpReg32 = GET_UINT32(p_Ad->matchTblPtr); ++ if ((uint8_t)tmpReg32 != fmPortGetSetCcParams.getCcParams.prOffset) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("this manipulation was updated previousely by different value");); ++ } ++ ++ return E_OK; ++} ++ ++static t_Error UpdateModifyCapwapFragmenation(t_FmPcdManip *p_Manip, t_Handle h_Ad, bool validate,t_Handle h_FmTree) ++{ ++ t_AdOfTypeContLookup *p_Ad = (t_AdOfTypeContLookup *)h_Ad; ++ t_FmPcdCcSavedManipParams *p_SavedManipParams = NULL; ++ uint32_t tmpReg32 = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip,E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Frag,E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Manip->frag,E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(((p_Manip->opcode == HMAN_OC_CAPWAP_FRAGMENTATION) || (p_Manip->opcode == HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER)), E_INVALID_STATE); ++ ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Frag; ++ ++ if (p_Manip->updateParams) ++ { ++ ++ if ((!(p_Manip->updateParams & OFFSET_OF_DATA)) || ++ ((p_Manip->shadowUpdateParams & OFFSET_OF_DATA))) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has not be updated")); ++ p_SavedManipParams = FmPcdCcTreeGetSavedManipParams(h_FmTree); ++ if (!p_SavedManipParams) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("for this manipulation tree has to be configured previosely with this type")); ++ p_Manip->capwapFragParams.dataOffset = p_SavedManipParams->capwapParams.dataOffset; ++ ++ tmpReg32 = GET_UINT32(p_Ad->pcAndOffsets); ++ tmpReg32 |= ((uint32_t)p_Manip->capwapFragParams.dataOffset<< 16); ++ WRITE_UINT32(p_Ad->pcAndOffsets,tmpReg32); ++ ++ p_Manip->updateParams &= ~OFFSET_OF_DATA; ++ p_Manip->shadowUpdateParams |= OFFSET_OF_DATA; ++ } ++ else if (validate) ++ { ++ ++ p_SavedManipParams = FmPcdCcTreeGetSavedManipParams(h_FmTree); ++ if (!p_SavedManipParams) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("for this manipulation tree has to be configured previosely with this type")); ++ if (p_Manip->capwapFragParams.dataOffset != p_SavedManipParams->capwapParams.dataOffset) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("this manipulation was updated previousely by different value")); ++ } ++ ++ return E_OK; ++} ++ ++static t_Error UpdateInitCapwapFragmentation(t_Handle h_FmPort, ++ t_FmPcdManip *p_Manip, ++ t_Handle h_Ad, ++ bool validate, ++ t_Handle h_FmTree) ++{ ++ t_AdOfTypeContLookup *p_Ad; ++ t_FmPortGetSetCcParams fmPortGetSetCcParams; ++ t_Error err; ++ uint32_t tmpReg32 = 0; ++ t_FmPcdCcSavedManipParams *p_SavedManipParams; ++ ++ UNUSED(h_Ad); ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip,E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Frag,E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Manip->frag,E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(((p_Manip->opcode == HMAN_OC_CAPWAP_FRAGMENTATION) || ++ (p_Manip->opcode == HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER)), E_INVALID_STATE); ++ ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Frag; ++ ++ if (p_Manip->updateParams) ++ { ++ if ((!(p_Manip->updateParams & OFFSET_OF_DATA)) || ++ ((p_Manip->shadowUpdateParams & OFFSET_OF_DATA))) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has not be updated")); ++ fmPortGetSetCcParams.getCcParams.type = p_Manip->updateParams; ++ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN | UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY; ++ fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL; ++ /* For CAPWAP Rassembly used FMAN_CTRL2 hardcoded - so for fragmentation its better to use FMAN_CTRL1 */ ++ fmPortGetSetCcParams.setCcParams.orFmanCtrl = FPM_PORT_FM_CTL1; ++ ++ err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_DATA) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Data offset wasn't configured previousely")); ++ ++ p_SavedManipParams = (t_FmPcdCcSavedManipParams *)XX_Malloc(sizeof(t_FmPcdCcSavedManipParams)); ++ p_SavedManipParams->capwapParams.dataOffset = fmPortGetSetCcParams.getCcParams.dataOffset; ++ ++#ifdef FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 ++ ASSERT_COND(!(p_SavedManipParams->capwapParams.dataOffset % 16)); ++#endif /* FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 */ ++ ++ FmPcdCcTreeSetSavedManipParams(h_FmTree, (t_Handle)p_SavedManipParams); ++ } ++ else if (validate) ++ { ++ if ((!(p_Manip->shadowUpdateParams & OFFSET_OF_DATA)) || ++ ((p_Manip->updateParams & OFFSET_OF_DATA))) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has be updated")); ++ fmPortGetSetCcParams.getCcParams.type = p_Manip->shadowUpdateParams; ++ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN | UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY; ++ fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL; ++ err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_DATA) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Data offset wasn't configured previousely")); ++ } ++ ++ if (p_Manip->updateParams) ++ { ++ tmpReg32 = GET_UINT32(p_Ad->pcAndOffsets); ++ tmpReg32 |= ((uint32_t)fmPortGetSetCcParams.getCcParams.dataOffset<< 16); ++ WRITE_UINT32(p_Ad->pcAndOffsets,tmpReg32); ++ ++ p_Manip->updateParams &= ~OFFSET_OF_DATA; ++ p_Manip->shadowUpdateParams |= OFFSET_OF_DATA; ++ p_Manip->capwapFragParams.dataOffset = fmPortGetSetCcParams.getCcParams.dataOffset; ++ } ++ else if (validate) ++ { ++ if (p_Manip->capwapFragParams.dataOffset != fmPortGetSetCcParams.getCcParams.dataOffset) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("this manipulation was updated previousely by different value")); ++ } ++ ++ return E_OK; ++} ++ ++static t_Error UpdateInitCapwapReasm(t_Handle h_FmPcd, ++ t_Handle h_FmPort, ++ t_FmPcdManip *p_Manip, ++ t_Handle h_Ad, ++ bool validate) ++{ ++ t_CapwapReasmPram *p_ReassmTbl; ++ t_Error err; ++ t_FmPortGetSetCcParams fmPortGetSetCcParams; ++ uint8_t i = 0; ++ uint16_t size; ++ uint32_t tmpReg32; ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ t_FmPcdCcCapwapReassmTimeoutParams ccCapwapReassmTimeoutParams; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip,E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Frag,E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Manip->frag,E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Manip->opcode == HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST), E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(h_FmPcd,E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc,E_INVALID_HANDLE); ++ ++ if (p_Manip->h_FmPcd != h_FmPcd) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("handler of PCD previously was initiated by different value")); ++ ++ UNUSED(h_Ad); ++ ++ memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams)); ++ p_ReassmTbl = (t_CapwapReasmPram *)p_Manip->h_Frag; ++ ++ if (p_Manip->updateParams) ++ { ++ if ((!(p_Manip->updateParams & NUM_OF_TASKS) && ++ !(p_Manip->updateParams & OFFSET_OF_DATA) && ++ !(p_Manip->updateParams & OFFSET_OF_PR) && ++ !(p_Manip->updateParams & HW_PORT_ID)) || ++ ((p_Manip->shadowUpdateParams & NUM_OF_TASKS) || ++ (p_Manip->shadowUpdateParams & OFFSET_OF_DATA) || (p_Manip->shadowUpdateParams & OFFSET_OF_PR) || ++ (p_Manip->shadowUpdateParams & HW_PORT_ID))) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has not be updated")); ++ ++ fmPortGetSetCcParams.getCcParams.type = p_Manip->updateParams; ++ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN; ++ fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL; ++ ++ err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ if (fmPortGetSetCcParams.getCcParams.type & NUM_OF_TASKS) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Num of tasks wasn't configured previousely")); ++ if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_DATA) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("offset of the data wasn't configured previousely")); ++ if (fmPortGetSetCcParams.getCcParams.type & HW_PORT_ID) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("hwPortId wasn't updated")); ++#ifdef FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 ++ ASSERT_COND((fmPortGetSetCcParams.getCcParams.dataOffset % 16) == 0); ++#endif /* FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 */ ++ } ++ else if (validate) ++ { ++ if ((!(p_Manip->shadowUpdateParams & NUM_OF_TASKS) && ++ !(p_Manip->shadowUpdateParams & OFFSET_OF_DATA) && ++ !(p_Manip->shadowUpdateParams & OFFSET_OF_PR) && ++ !(p_Manip->shadowUpdateParams & HW_PORT_ID)) && ++ ((p_Manip->updateParams & NUM_OF_TASKS) || ++ (p_Manip->updateParams & OFFSET_OF_DATA) || (p_Manip->updateParams & OFFSET_OF_PR) || ++ (p_Manip->updateParams & HW_PORT_ID))) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has be updated")); ++ ++ fmPortGetSetCcParams.getCcParams.type = p_Manip->shadowUpdateParams; ++ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN; ++ fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL; ++ ++ err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ if (fmPortGetSetCcParams.getCcParams.type & NUM_OF_TASKS) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("NumOfTasks wasn't configured previously")); ++ if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_DATA) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("offset of the data wasn't configured previously")); ++ if (fmPortGetSetCcParams.getCcParams.type & HW_PORT_ID) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("hwPortId wasn't updated")); ++ } ++ ++ if (p_Manip->updateParams) ++ { ++ if (p_Manip->updateParams & NUM_OF_TASKS) ++ { ++ /*recommendation of Microcode team - (maxNumFramesInProcess * 2) */ ++ size = (uint16_t)(p_Manip->capwapFragParams.maxNumFramesInProcess*2 + fmPortGetSetCcParams.getCcParams.numOfTasks); ++ if (size > 255) ++ RETURN_ERROR(MAJOR,E_INVALID_VALUE, ("numOfOpenReassmEntries + numOfTasks per port can not be greater than 256")); ++ ++ p_Manip->capwapFragParams.numOfTasks = fmPortGetSetCcParams.getCcParams.numOfTasks; ++ ++ /*p_ReassmFrmDescrIndxPoolTbl*/ ++ p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl = ++ (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, ++ (uint32_t)(size + 1), ++ 4); ++ if (!p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for CAPWAP Reassembly frame buffer index pool table")); ++ ++ MemSet8(p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl, 0, (uint32_t)(size + 1)); ++ ++ for ( i = 0; i < size; i++) ++ WRITE_UINT8(*(uint8_t *)PTR_MOVE(p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl, i), (uint8_t)(i+1)); ++ ++ tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl) - p_FmPcd->physicalMuramBase); ++ ++ WRITE_UINT32(p_ReassmTbl->reasmFrmDescIndexPoolTblPtr, tmpReg32); ++ ++ /*p_ReassmFrmDescrPoolTbl*/ ++ p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl = ++ (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, ++ (uint32_t)((size + 1) * FM_PCD_MANIP_CAPWAP_REASM_RFD_SIZE), ++ 4); ++ ++ if (!p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for CAPWAP Reassembly frame buffer pool table")); ++ ++ MemSet8(p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl, 0, (uint32_t)((size +1)* FM_PCD_MANIP_CAPWAP_REASM_RFD_SIZE)); ++ ++ tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl) - p_FmPcd->physicalMuramBase); ++ ++ WRITE_UINT32(p_ReassmTbl->reasmFrmDescPoolTblPtr, tmpReg32); ++ ++ /*p_TimeOutTbl*/ ++ ++ p_Manip->capwapFragParams.p_TimeOutTbl = ++ (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, ++ (uint32_t)((size + 1)* FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_ENTRY_SIZE), ++ 4); ++ ++ if (!p_Manip->capwapFragParams.p_TimeOutTbl) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for CAPWAP Reassembly timeout table")); ++ ++ MemSet8(p_Manip->capwapFragParams.p_TimeOutTbl, 0, (uint16_t)((size + 1)*FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_ENTRY_SIZE)); ++ ++ tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->capwapFragParams.p_TimeOutTbl) - p_FmPcd->physicalMuramBase); ++ WRITE_UINT32(p_ReassmTbl->timeOutTblPtr, tmpReg32); ++ ++ p_Manip->updateParams &= ~NUM_OF_TASKS; ++ p_Manip->shadowUpdateParams |= NUM_OF_TASKS; ++ } ++ ++ if (p_Manip->updateParams & OFFSET_OF_DATA) ++ { ++ p_Manip->capwapFragParams.dataOffset = fmPortGetSetCcParams.getCcParams.dataOffset; ++ tmpReg32 = GET_UINT32(p_ReassmTbl->mode); ++ tmpReg32|= p_Manip->capwapFragParams.dataOffset; ++ WRITE_UINT32(p_ReassmTbl->mode, tmpReg32); ++ p_Manip->updateParams &= ~OFFSET_OF_DATA; ++ p_Manip->shadowUpdateParams |= OFFSET_OF_DATA; ++ } ++ ++ if (!(fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_PR)) ++ { ++ p_Manip->capwapFragParams.prOffset = fmPortGetSetCcParams.getCcParams.prOffset; ++ ++ tmpReg32 = GET_UINT32(p_ReassmTbl->mode); ++ tmpReg32|= FM_PCD_MANIP_CAPWAP_REASM_PR_COPY; ++ WRITE_UINT32(p_ReassmTbl->mode, tmpReg32); ++ ++ tmpReg32 = GET_UINT32(p_ReassmTbl->intStatsTblPtr); ++ tmpReg32 |= (uint32_t)p_Manip->capwapFragParams.prOffset << 24; ++ WRITE_UINT32(p_ReassmTbl->intStatsTblPtr, tmpReg32); ++ p_Manip->updateParams &= ~OFFSET_OF_PR; ++ p_Manip->shadowUpdateParams |= OFFSET_OF_PR; ++ } ++ else ++ { ++ p_Manip->capwapFragParams.prOffset = 0xff; ++ p_Manip->updateParams &= ~OFFSET_OF_PR; ++ p_Manip->shadowUpdateParams |= OFFSET_OF_PR; ++ } ++ ++ p_Manip->capwapFragParams.hwPortId = fmPortGetSetCcParams.getCcParams.hardwarePortId; ++ p_Manip->updateParams &= ~HW_PORT_ID; ++ p_Manip->shadowUpdateParams |= HW_PORT_ID; ++ ++ /*timeout hc */ ++ ccCapwapReassmTimeoutParams.fqidForTimeOutFrames = p_Manip->capwapFragParams.fqidForTimeOutFrames; ++ ccCapwapReassmTimeoutParams.portIdAndCapwapReassmTbl = (uint32_t)p_Manip->capwapFragParams.hwPortId << 24; ++ ccCapwapReassmTimeoutParams.portIdAndCapwapReassmTbl |= (uint32_t)((XX_VirtToPhys(p_ReassmTbl) - p_FmPcd->physicalMuramBase)); ++ ccCapwapReassmTimeoutParams.timeoutRequestTime = (((uint32_t)1<capwapFragParams.bitFor1Micro) * p_Manip->capwapFragParams.timeoutRoutineRequestTime)/2; ++ return FmHcPcdCcCapwapTimeoutReassm(p_FmPcd->h_Hc,&ccCapwapReassmTimeoutParams); ++ } ++ ++ else if (validate) ++ { ++ if (fmPortGetSetCcParams.getCcParams.hardwarePortId != p_Manip->capwapFragParams.hwPortId) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Reassembly manipulation previously was assigned to another port")); ++ if (fmPortGetSetCcParams.getCcParams.numOfTasks != p_Manip->capwapFragParams.numOfTasks) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfTasks for this manipulation previously was defined by another value ")); ++ ++ if (!(fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_PR)) ++ { ++ if (p_Manip->capwapFragParams.prOffset != fmPortGetSetCcParams.getCcParams.prOffset) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Parse result offset previously was defined by another value ")); ++ } ++ else ++ { ++ if (p_Manip->capwapFragParams.prOffset != 0xff) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Parse result offset previously was defined by another value ")); ++ } ++ if (fmPortGetSetCcParams.getCcParams.dataOffset != p_Manip->capwapFragParams.dataOffset) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Data offset previously was defined by another value ")); ++ } ++ ++ return E_OK; ++} ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++ ++t_Error FmPcdRegisterReassmPort(t_Handle h_FmPcd, t_Handle h_ReasmCommonPramTbl) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ t_FmPcdCcReassmTimeoutParams ccReassmTimeoutParams = { 0 }; ++ t_Error err = E_OK; ++ uint8_t result; ++ uint32_t bitFor1Micro, tsbs, log2num; ++ ++ ASSERT_COND(p_FmPcd); ++ ASSERT_COND(h_ReasmCommonPramTbl); ++ ++ bitFor1Micro = FmGetTimeStampScale(p_FmPcd->h_Fm); ++ if (bitFor1Micro == 0) ++ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Timestamp scale")); ++ ++ bitFor1Micro = 32 - bitFor1Micro; ++ LOG2(FM_PCD_MANIP_REASM_TIMEOUT_THREAD_THRESH, log2num); ++ tsbs = bitFor1Micro - log2num; ++ ++ ccReassmTimeoutParams.iprcpt = (uint32_t)(XX_VirtToPhys( ++ h_ReasmCommonPramTbl) - p_FmPcd->physicalMuramBase); ++ ccReassmTimeoutParams.tsbs = (uint8_t)tsbs; ++ ccReassmTimeoutParams.activate = TRUE; ++ if ((err = FmHcPcdCcTimeoutReassm(p_FmPcd->h_Hc, &ccReassmTimeoutParams, ++ &result)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ switch (result) ++ { ++ case (0): ++ return E_OK; ++ case (1): ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("failed to allocate TNUM")); ++ case (2): ++ RETURN_ERROR( ++ MAJOR, E_NO_MEMORY, ++ ("failed to allocate internal buffer from the HC-Port")); ++ case (3): ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("'Disable Timeout Task' with invalid IPRCPT")); ++ case (4): ++ RETURN_ERROR(MAJOR, E_FULL, ("too many timeout tasks")); ++ case (5): ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("invalid sub command")); ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); ++ } ++ return E_OK; ++} ++ ++static t_Error CreateReassCommonTable(t_FmPcdManip *p_Manip) ++{ ++ uint32_t tmpReg32 = 0, i, bitFor1Micro; ++ uint64_t tmpReg64, size; ++ t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd; ++ t_Error err = E_OK; ++ ++ bitFor1Micro = FmGetTimeStampScale(p_FmPcd->h_Fm); ++ if (bitFor1Micro == 0) ++ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Timestamp scale")); ++ ++ /* Allocation of the Reassembly Common Parameters table. This table is located in the ++ MURAM. Its size is 64 bytes and its base address should be 8-byte aligned. */ ++ p_Manip->reassmParams.p_ReassCommonTbl = ++ (t_ReassCommonTbl *)FM_MURAM_AllocMem( ++ p_FmPcd->h_FmMuram, ++ FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_SIZE, ++ FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_ALIGN); ++ ++ if (!p_Manip->reassmParams.p_ReassCommonTbl) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("MURAM alloc for Reassembly common parameters table")); ++ ++ MemSet8(p_Manip->reassmParams.p_ReassCommonTbl, 0, ++ FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_SIZE); ++ ++ /* Setting the TimeOut Mode.*/ ++ tmpReg32 = 0; ++ if (p_Manip->reassmParams.timeOutMode ++ == e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAMES) ++ tmpReg32 |= FM_PCD_MANIP_REASM_TIME_OUT_BETWEEN_FRAMES; ++ ++ /* Setting TimeOut FQID - Frames that time out are enqueued to this FQID. ++ In order to cause TimeOut frames to be discarded, this queue should be configured accordingly*/ ++ tmpReg32 |= p_Manip->reassmParams.fqidForTimeOutFrames; ++ WRITE_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->timeoutModeAndFqid, ++ tmpReg32); ++ ++ /* Calculation the size of IP Reassembly Frame Descriptor - number of frames that are allowed to be reassembled simultaneously + 129.*/ ++ size = p_Manip->reassmParams.maxNumFramesInProcess + 129; ++ ++ /*Allocation of IP Reassembly Frame Descriptor Indexes Pool - This pool resides in the MURAM */ ++ p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr = ++ PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, ++ (uint32_t)(size * 2), ++ 256)); ++ if (!p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr) ++ RETURN_ERROR( ++ MAJOR, E_NO_MEMORY, ++ ("MURAM alloc for Reassembly frame descriptor indexes pool")); ++ ++ MemSet8(UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr), ++ 0, (uint32_t)(size * 2)); ++ ++ /* The entries in IP Reassembly Frame Descriptor Indexes Pool contains indexes starting with 1 up to ++ the maximum number of frames that are allowed to be reassembled simultaneously + 128. ++ The last entry in this pool must contain the index zero*/ ++ for (i = 0; i < (size - 1); i++) ++ WRITE_UINT16( ++ *(uint16_t *)PTR_MOVE(UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr), (i<<1)), ++ (uint16_t)(i+1)); ++ ++ /* Sets the IP Reassembly Frame Descriptor Indexes Pool offset from MURAM */ ++ tmpReg32 = (uint32_t)(XX_VirtToPhys( ++ UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr)) ++ - p_FmPcd->physicalMuramBase); ++ WRITE_UINT32( ++ p_Manip->reassmParams.p_ReassCommonTbl->reassFrmDescIndexPoolTblPtr, ++ tmpReg32); ++ ++ /* Allocation of the Reassembly Frame Descriptors Pool - This pool resides in external memory. ++ The number of entries in this pool should be equal to the number of entries in IP Reassembly Frame Descriptor Indexes Pool.*/ ++ p_Manip->reassmParams.reassFrmDescrPoolTblAddr = ++ PTR_TO_UINT(XX_MallocSmart((uint32_t)(size * 64), p_Manip->reassmParams.dataMemId, 64)); ++ ++ if (!p_Manip->reassmParams.reassFrmDescrPoolTblAddr) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory allocation FAILED")); ++ ++ MemSet8(UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrPoolTblAddr), 0, ++ (uint32_t)(size * 64)); ++ ++ /* Sets the Reassembly Frame Descriptors Pool and liodn offset*/ ++ tmpReg64 = (uint64_t)(XX_VirtToPhys( ++ UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrPoolTblAddr))); ++ tmpReg64 |= ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset ++ & FM_PCD_MANIP_REASM_LIODN_MASK) ++ << (uint64_t)FM_PCD_MANIP_REASM_LIODN_SHIFT); ++ tmpReg64 |= ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset ++ & FM_PCD_MANIP_REASM_ELIODN_MASK) ++ << (uint64_t)FM_PCD_MANIP_REASM_ELIODN_SHIFT); ++ WRITE_UINT32( ++ p_Manip->reassmParams.p_ReassCommonTbl->liodnAndReassFrmDescPoolPtrHi, ++ (uint32_t)(tmpReg64 >> 32)); ++ WRITE_UINT32( ++ p_Manip->reassmParams.p_ReassCommonTbl->reassFrmDescPoolPtrLow, ++ (uint32_t)tmpReg64); ++ ++ /*Allocation of the TimeOut table - This table resides in the MURAM. ++ The number of entries in this table is identical to the number of entries in the Reassembly Frame Descriptors Pool*/ ++ p_Manip->reassmParams.timeOutTblAddr = ++ PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, (uint32_t)(size * 8),8)); ++ ++ if (!p_Manip->reassmParams.timeOutTblAddr) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("MURAM alloc for Reassembly timeout table")); ++ ++ MemSet8(UINT_TO_PTR(p_Manip->reassmParams.timeOutTblAddr), 0, ++ (uint16_t)(size * 8)); ++ ++ /* Sets the TimeOut table offset from MURAM */ ++ tmpReg32 = (uint32_t)(XX_VirtToPhys( ++ UINT_TO_PTR(p_Manip->reassmParams.timeOutTblAddr)) ++ - p_FmPcd->physicalMuramBase); ++ WRITE_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->timeOutTblPtr, ++ tmpReg32); ++ ++ /* Sets the Expiration Delay */ ++ tmpReg32 = 0; ++ tmpReg32 |= (((uint32_t)(1 << bitFor1Micro)) ++ * p_Manip->reassmParams.timeoutThresholdForReassmProcess); ++ WRITE_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->expirationDelay, ++ tmpReg32); ++ ++ err = FmPcdRegisterReassmPort(p_FmPcd, ++ p_Manip->reassmParams.p_ReassCommonTbl); ++ if (err != E_OK) ++ { ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, ++ p_Manip->reassmParams.p_ReassCommonTbl); ++ RETURN_ERROR(MAJOR, err, ("port registration")); ++ } ++ ++ return err; ++} ++ ++static t_Error CreateReassTable(t_FmPcdManip *p_Manip, e_NetHeaderType hdr) ++{ ++ t_FmPcd *p_FmPcd = p_Manip->h_FmPcd; ++ uint32_t tmpReg32, autoLearnHashTblSize; ++ uint32_t numOfWays, setSize, setSizeCode, keySize; ++ uint32_t waySize, numOfSets, numOfEntries; ++ uint64_t tmpReg64; ++ uint16_t minFragSize; ++ uint16_t maxReassemSize; ++ uintptr_t *p_AutoLearnHashTblAddr, *p_AutoLearnSetLockTblAddr; ++ t_ReassTbl **p_ReassTbl; ++ ++ switch (hdr) ++ { ++ case HEADER_TYPE_IPv4: ++ p_ReassTbl = &p_Manip->reassmParams.ip.p_Ipv4ReassTbl; ++ p_AutoLearnHashTblAddr = ++ &p_Manip->reassmParams.ip.ipv4AutoLearnHashTblAddr; ++ p_AutoLearnSetLockTblAddr = ++ &p_Manip->reassmParams.ip.ipv4AutoLearnSetLockTblAddr; ++ minFragSize = p_Manip->reassmParams.ip.minFragSize[0]; ++ maxReassemSize = 0; ++ numOfWays = p_Manip->reassmParams.ip.numOfFramesPerHashEntry[0]; ++ keySize = 4 + 4 + 1 + 2; /* 3-tuple + IP-Id */ ++ break; ++ case HEADER_TYPE_IPv6: ++ p_ReassTbl = &p_Manip->reassmParams.ip.p_Ipv6ReassTbl; ++ p_AutoLearnHashTblAddr = ++ &p_Manip->reassmParams.ip.ipv6AutoLearnHashTblAddr; ++ p_AutoLearnSetLockTblAddr = ++ &p_Manip->reassmParams.ip.ipv6AutoLearnSetLockTblAddr; ++ minFragSize = p_Manip->reassmParams.ip.minFragSize[1]; ++ maxReassemSize = 0; ++ numOfWays = p_Manip->reassmParams.ip.numOfFramesPerHashEntry[1]; ++ keySize = 16 + 16 + 4; /* 2-tuple + IP-Id */ ++ if (numOfWays > e_FM_PCD_MANIP_SIX_WAYS_HASH) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("num of ways")); ++ break; ++ case HEADER_TYPE_CAPWAP: ++ p_ReassTbl = &p_Manip->reassmParams.capwap.p_ReassTbl; ++ p_AutoLearnHashTblAddr = ++ &p_Manip->reassmParams.capwap.autoLearnHashTblAddr; ++ p_AutoLearnSetLockTblAddr = ++ &p_Manip->reassmParams.capwap.autoLearnSetLockTblAddr; ++ minFragSize = 0; ++ maxReassemSize = p_Manip->reassmParams.capwap.maxRessembledsSize; ++ numOfWays = p_Manip->reassmParams.capwap.numOfFramesPerHashEntry; ++ keySize = 4; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("header type")); ++ } ++ keySize += 2; /* 2 bytes reserved for RFDIndex */ ++#if (DPAA_VERSION >= 11) ++ keySize += 2; /* 2 bytes reserved */ ++#endif /* (DPAA_VERSION >= 11) */ ++ waySize = ROUND_UP(keySize, 8); ++ ++ /* Allocates the Reassembly Parameters Table - This table is located in the MURAM.*/ ++ *p_ReassTbl = (t_ReassTbl *)FM_MURAM_AllocMem( ++ p_FmPcd->h_FmMuram, FM_PCD_MANIP_REASM_TABLE_SIZE, ++ FM_PCD_MANIP_REASM_TABLE_ALIGN); ++ if (!*p_ReassTbl) ++ RETURN_ERROR( MAJOR, E_NO_MEMORY, ++ ("MURAM alloc for Reassembly specific parameters table")); ++ memset(*p_ReassTbl, 0, sizeof(t_ReassTbl)); ++ ++ /* Sets the Reassembly common Parameters table offset from MURAM in the Reassembly Table descriptor*/ ++ tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->reassmParams.p_ReassCommonTbl) ++ - p_FmPcd->physicalMuramBase); ++ WRITE_UINT32((*p_ReassTbl)->reassCommonPrmTblPtr, tmpReg32); ++ ++ /* Calculate set size (set size is rounded-up to next power of 2) */ ++ NEXT_POWER_OF_2(numOfWays * waySize, setSize); ++ ++ /* Get set size code */ ++ LOG2(setSize, setSizeCode); ++ ++ /* Sets ways number and set size code */ ++ WRITE_UINT16((*p_ReassTbl)->waysNumAndSetSize, ++ (uint16_t)((numOfWays << 8) | setSizeCode)); ++ ++ /* It is recommended that the total number of entries in this table ++ (number of sets * number of ways) will be twice the number of frames that ++ are expected to be reassembled simultaneously.*/ ++ numOfEntries = (uint32_t)(p_Manip->reassmParams.maxNumFramesInProcess * 2); ++ ++ /* sets number calculation - number of entries = number of sets * number of ways */ ++ numOfSets = numOfEntries / numOfWays; ++ ++ /* Sets AutoLearnHashKeyMask*/ ++ NEXT_POWER_OF_2(numOfSets, numOfSets); ++ ++ WRITE_UINT16((*p_ReassTbl)->autoLearnHashKeyMask, ++ (uint16_t)(numOfSets - 1)); ++ ++ /* Allocation of Reassembly Automatic Learning Hash Table - This table resides in external memory. ++ The size of this table is determined by the number of sets and the set size. ++ Table size = set size * number of sets ++ This table base address should be aligned to SetSize.*/ ++ autoLearnHashTblSize = numOfSets * setSize; ++ ++ *p_AutoLearnHashTblAddr = ++ PTR_TO_UINT(XX_MallocSmart(autoLearnHashTblSize, p_Manip->reassmParams.dataMemId, setSize)); ++ if (!*p_AutoLearnHashTblAddr) ++ { ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, *p_ReassTbl); ++ *p_ReassTbl = NULL; ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory allocation FAILED")); ++ } ++ MemSet8(UINT_TO_PTR(*p_AutoLearnHashTblAddr), 0, autoLearnHashTblSize); ++ ++ /* Sets the Reassembly Automatic Learning Hash Table and liodn offset */ ++ tmpReg64 = ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset ++ & FM_PCD_MANIP_REASM_LIODN_MASK) ++ << (uint64_t)FM_PCD_MANIP_REASM_LIODN_SHIFT); ++ tmpReg64 |= ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset ++ & FM_PCD_MANIP_REASM_ELIODN_MASK) ++ << (uint64_t)FM_PCD_MANIP_REASM_ELIODN_SHIFT); ++ tmpReg64 |= XX_VirtToPhys(UINT_TO_PTR(*p_AutoLearnHashTblAddr)); ++ WRITE_UINT32( (*p_ReassTbl)->liodnAlAndAutoLearnHashTblPtrHi, ++ (uint32_t)(tmpReg64 >> 32)); ++ WRITE_UINT32((*p_ReassTbl)->autoLearnHashTblPtrLow, (uint32_t)tmpReg64); ++ ++ /* Allocation of the Set Lock table - This table resides in external memory ++ The size of this table is (number of sets in the Reassembly Automatic Learning Hash table)*4 bytes. ++ This table resides in external memory and its base address should be 4-byte aligned */ ++ *p_AutoLearnSetLockTblAddr = ++ PTR_TO_UINT(XX_MallocSmart((uint32_t)(numOfSets * 4), p_Manip->reassmParams.dataMemId, 4)); ++ if (!*p_AutoLearnSetLockTblAddr) ++ { ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, *p_ReassTbl); ++ *p_ReassTbl = NULL; ++ XX_FreeSmart(UINT_TO_PTR(*p_AutoLearnHashTblAddr)); ++ *p_AutoLearnHashTblAddr = 0; ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory allocation FAILED")); ++ } ++ MemSet8(UINT_TO_PTR(*p_AutoLearnSetLockTblAddr), 0, (numOfSets * 4)); ++ ++ /* sets Set Lock table pointer and liodn offset*/ ++ tmpReg64 = ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset ++ & FM_PCD_MANIP_REASM_LIODN_MASK) ++ << (uint64_t)FM_PCD_MANIP_REASM_LIODN_SHIFT); ++ tmpReg64 |= ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset ++ & FM_PCD_MANIP_REASM_ELIODN_MASK) ++ << (uint64_t)FM_PCD_MANIP_REASM_ELIODN_SHIFT); ++ tmpReg64 |= XX_VirtToPhys(UINT_TO_PTR(*p_AutoLearnSetLockTblAddr)); ++ WRITE_UINT32( (*p_ReassTbl)->liodnSlAndAutoLearnSetLockTblPtrHi, ++ (uint32_t)(tmpReg64 >> 32)); ++ WRITE_UINT32((*p_ReassTbl)->autoLearnSetLockTblPtrLow, (uint32_t)tmpReg64); ++ ++ /* Sets user's requested minimum fragment size (in Bytes) for First/Middle fragment */ ++ WRITE_UINT16((*p_ReassTbl)->minFragSize, minFragSize); ++ ++ WRITE_UINT16((*p_ReassTbl)->maxReassemblySize, maxReassemSize); ++ ++ return E_OK; ++} ++ ++static t_Error UpdateInitReasm(t_Handle h_FmPcd, t_Handle h_PcdParams, ++ t_Handle h_FmPort, t_FmPcdManip *p_Manip, ++ t_Handle h_Ad, bool validate) ++{ ++ t_FmPortGetSetCcParams fmPortGetSetCcParams; ++ uint32_t tmpReg32; ++ t_Error err; ++ t_FmPortPcdParams *p_PcdParams = (t_FmPortPcdParams *)h_PcdParams; ++#if (DPAA_VERSION >= 11) ++ t_FmPcdCtrlParamsPage *p_ParamsPage; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Manip->frag, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR( ++ (p_Manip->opcode == HMAN_OC_IP_REASSEMBLY) || (p_Manip->opcode == HMAN_OC_CAPWAP_REASSEMBLY), ++ E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Manip->updateParams || h_PcdParams, ++ E_INVALID_HANDLE); ++ ++ UNUSED(h_Ad); ++ ++ if (!p_Manip->updateParams) ++ return E_OK; ++ ++ if (p_Manip->h_FmPcd != h_FmPcd) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_STATE, ++ ("handler of PCD previously was initiated by different value")); ++ ++ if (p_Manip->updateParams) ++ { ++ if ((!(p_Manip->updateParams ++ & (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK))) ++ || ((p_Manip->shadowUpdateParams ++ & (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK)))) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_STATE, ++ ("in this stage parameters from Port has not be updated")); ++ ++ fmPortGetSetCcParams.setCcParams.type = 0; ++ if (p_Manip->opcode == HMAN_OC_CAPWAP_REASSEMBLY) ++ { ++ fmPortGetSetCcParams.setCcParams.type |= UPDATE_OFP_DPTE; ++ fmPortGetSetCcParams.setCcParams.ofpDpde = 0xF; ++ } ++ fmPortGetSetCcParams.getCcParams.type = p_Manip->updateParams | FM_REV; ++ if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) ++ != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ if (fmPortGetSetCcParams.getCcParams.type ++ & (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK | FM_REV)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("offset of the data wasn't configured previously")); ++ if (p_Manip->updateParams ++ & (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK)) ++ { ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ uint8_t *p_Ptr, i, totalNumOfTnums; ++ ++ totalNumOfTnums = ++ (uint8_t)(fmPortGetSetCcParams.getCcParams.numOfTasks ++ + fmPortGetSetCcParams.getCcParams.numOfExtraTasks); ++ ++ p_Manip->reassmParams.internalBufferPoolAddr = ++ PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, ++ (uint32_t)(totalNumOfTnums * BMI_FIFO_UNITS), ++ BMI_FIFO_UNITS)); ++ if (!p_Manip->reassmParams.internalBufferPoolAddr) ++ RETURN_ERROR( ++ MAJOR, E_NO_MEMORY, ++ ("MURAM alloc for Reassembly internal buffers pool")); ++ MemSet8( ++ UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolAddr), ++ 0, (uint32_t)(totalNumOfTnums * BMI_FIFO_UNITS)); ++ ++ p_Manip->reassmParams.internalBufferPoolManagementIndexAddr = ++ PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, ++ (uint32_t)(5 + totalNumOfTnums), ++ 4)); ++ if (!p_Manip->reassmParams.internalBufferPoolManagementIndexAddr) ++ RETURN_ERROR( ++ MAJOR, ++ E_NO_MEMORY, ++ ("MURAM alloc for Reassembly internal buffers management")); ++ ++ p_Ptr = ++ (uint8_t*)UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolManagementIndexAddr); ++ WRITE_UINT32( ++ *(uint32_t*)p_Ptr, ++ (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolAddr)) - p_FmPcd->physicalMuramBase)); ++ for (i = 0, p_Ptr += 4; i < totalNumOfTnums; i++, p_Ptr++) ++ WRITE_UINT8(*p_Ptr, i); ++ WRITE_UINT8(*p_Ptr, 0xFF); ++ ++ tmpReg32 = ++ (4 << FM_PCD_MANIP_REASM_COMMON_INT_BUFFER_IDX_SHIFT) ++ | ((uint32_t)(XX_VirtToPhys( ++ UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolManagementIndexAddr)) ++ - p_FmPcd->physicalMuramBase)); ++ WRITE_UINT32( ++ p_Manip->reassmParams.p_ReassCommonTbl->internalBufferManagement, ++ tmpReg32); ++ ++ p_Manip->updateParams &= ~(NUM_OF_TASKS | NUM_OF_EXTRA_TASKS ++ | DISCARD_MASK); ++ p_Manip->shadowUpdateParams |= (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS ++ | DISCARD_MASK); ++ } ++ } ++ ++ if (p_Manip->opcode == HMAN_OC_CAPWAP_REASSEMBLY) ++ { ++ if (p_Manip->reassmParams.capwap.h_Scheme) ++ { ++ p_PcdParams->p_KgParams->h_Schemes[p_PcdParams->p_KgParams->numOfSchemes] = ++ p_Manip->reassmParams.capwap.h_Scheme; ++ p_PcdParams->p_KgParams->numOfSchemes++; ++ } ++ ++ } ++ else ++ { ++ if (p_Manip->reassmParams.ip.h_Ipv4Scheme) ++ { ++ p_PcdParams->p_KgParams->h_Schemes[p_PcdParams->p_KgParams->numOfSchemes] = ++ p_Manip->reassmParams.ip.h_Ipv4Scheme; ++ p_PcdParams->p_KgParams->numOfSchemes++; ++ } ++ if (p_Manip->reassmParams.ip.h_Ipv6Scheme) ++ { ++ p_PcdParams->p_KgParams->h_Schemes[p_PcdParams->p_KgParams->numOfSchemes] = ++ p_Manip->reassmParams.ip.h_Ipv6Scheme; ++ p_PcdParams->p_KgParams->numOfSchemes++; ++ } ++#if (DPAA_VERSION >= 11) ++ if (fmPortGetSetCcParams.getCcParams.revInfo.majorRev >= 6) ++ { ++ if ((err = FmPortSetGprFunc(h_FmPort, e_FM_PORT_GPR_MURAM_PAGE, ++ (void**)&p_ParamsPage)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ tmpReg32 = NIA_ENG_KG; ++ if (p_Manip->reassmParams.ip.h_Ipv4Scheme) ++ { ++ tmpReg32 |= NIA_KG_DIRECT; ++ tmpReg32 |= NIA_KG_CC_EN; ++ tmpReg32 |= FmPcdKgGetSchemeId( ++ p_Manip->reassmParams.ip.h_Ipv4Scheme); ++ WRITE_UINT32(p_ParamsPage->iprIpv4Nia, tmpReg32); ++ } ++ if (p_Manip->reassmParams.ip.h_Ipv6Scheme) ++ { ++ tmpReg32 &= ~NIA_AC_MASK; ++ tmpReg32 |= NIA_KG_DIRECT; ++ tmpReg32 |= NIA_KG_CC_EN; ++ tmpReg32 |= FmPcdKgGetSchemeId( ++ p_Manip->reassmParams.ip.h_Ipv6Scheme); ++ WRITE_UINT32(p_ParamsPage->iprIpv6Nia, tmpReg32); ++ } ++ } ++#else ++ if (fmPortGetSetCcParams.getCcParams.revInfo.majorRev < 6) ++ { ++ WRITE_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->discardMask, ++ fmPortGetSetCcParams.getCcParams.discardMask); ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ } ++ return E_OK; ++} ++ ++#if (DPAA_VERSION == 10) ++static t_Error FmPcdFragHcScratchPoolFill(t_Handle h_FmPcd, uint8_t scratchBpid) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ t_FmPcdCcFragScratchPoolCmdParams fmPcdCcFragScratchPoolCmdParams; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ ++ memset(&fmPcdCcFragScratchPoolCmdParams, 0, sizeof(t_FmPcdCcFragScratchPoolCmdParams)); ++ ++ fmPcdCcFragScratchPoolCmdParams.numOfBuffers = NUM_OF_SCRATCH_POOL_BUFFERS; ++ fmPcdCcFragScratchPoolCmdParams.bufferPoolId = scratchBpid; ++ if ((err = FmHcPcdCcIpFragScratchPollCmd(p_FmPcd->h_Hc, TRUE, &fmPcdCcFragScratchPoolCmdParams)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ if (fmPcdCcFragScratchPoolCmdParams.numOfBuffers != 0) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Fill scratch pool failed," ++ "Failed to release %d buffers to the BM (missing FBPRs)", ++ fmPcdCcFragScratchPoolCmdParams.numOfBuffers)); ++ ++ return E_OK; ++} ++ ++static t_Error FmPcdFragHcScratchPoolEmpty(t_Handle h_FmPcd, uint8_t scratchBpid) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ t_FmPcdCcFragScratchPoolCmdParams fmPcdCcFragScratchPoolCmdParams; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ ++ memset(&fmPcdCcFragScratchPoolCmdParams, 0, sizeof(t_FmPcdCcFragScratchPoolCmdParams)); ++ ++ fmPcdCcFragScratchPoolCmdParams.bufferPoolId = scratchBpid; ++ if ((err = FmHcPcdCcIpFragScratchPollCmd(p_FmPcd->h_Hc, FALSE, &fmPcdCcFragScratchPoolCmdParams)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ return E_OK; ++} ++#endif /* (DPAA_VERSION == 10) */ ++ ++static void ReleaseManipHandler(t_FmPcdManip *p_Manip, t_FmPcd *p_FmPcd) ++{ ++ if (p_Manip->h_Ad) ++ { ++ if (p_Manip->muramAllocate) ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->h_Ad); ++ else ++ XX_Free(p_Manip->h_Ad); ++ p_Manip->h_Ad = NULL; ++ } ++ if (p_Manip->p_Template) ++ { ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->p_Template); ++ p_Manip->p_Template = NULL; ++ } ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++ if (p_Manip->h_Frag) ++ { ++ if (p_Manip->capwapFragParams.p_AutoLearnHashTbl) ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, ++ p_Manip->capwapFragParams.p_AutoLearnHashTbl); ++ if (p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl) ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, ++ p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl); ++ if (p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl) ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, ++ p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl); ++ if (p_Manip->capwapFragParams.p_TimeOutTbl) ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, ++ p_Manip->capwapFragParams.p_TimeOutTbl); ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->h_Frag); ++ ++ } ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++ if (p_Manip->frag) ++ { ++ if (p_Manip->fragParams.p_Frag) ++ { ++#if (DPAA_VERSION == 10) ++ FmPcdFragHcScratchPoolEmpty((t_Handle)p_FmPcd, p_Manip->fragParams.scratchBpid); ++#endif /* (DPAA_VERSION == 10) */ ++ ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->fragParams.p_Frag); ++ } ++ } ++ else ++ if (p_Manip->reassm) ++ { ++ FmPcdUnregisterReassmPort(p_FmPcd, ++ p_Manip->reassmParams.p_ReassCommonTbl); ++ ++ if (p_Manip->reassmParams.timeOutTblAddr) ++ FM_MURAM_FreeMem( ++ p_FmPcd->h_FmMuram, ++ UINT_TO_PTR(p_Manip->reassmParams.timeOutTblAddr)); ++ if (p_Manip->reassmParams.reassFrmDescrPoolTblAddr) ++ XX_FreeSmart( ++ UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrPoolTblAddr)); ++ if (p_Manip->reassmParams.p_ReassCommonTbl) ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, ++ p_Manip->reassmParams.p_ReassCommonTbl); ++ if (p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr) ++ FM_MURAM_FreeMem( ++ p_FmPcd->h_FmMuram, ++ UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr)); ++ if (p_Manip->reassmParams.internalBufferPoolManagementIndexAddr) ++ FM_MURAM_FreeMem( ++ p_FmPcd->h_FmMuram, ++ UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolManagementIndexAddr)); ++ if (p_Manip->reassmParams.internalBufferPoolAddr) ++ FM_MURAM_FreeMem( ++ p_FmPcd->h_FmMuram, ++ UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolAddr)); ++ if (p_Manip->reassmParams.hdr == HEADER_TYPE_CAPWAP) ++ { ++ ++ } ++ else ++ { ++ if (p_Manip->reassmParams.ip.ipv4AutoLearnHashTblAddr) ++ XX_FreeSmart( ++ UINT_TO_PTR(p_Manip->reassmParams.ip.ipv4AutoLearnHashTblAddr)); ++ if (p_Manip->reassmParams.ip.ipv6AutoLearnHashTblAddr) ++ XX_FreeSmart( ++ UINT_TO_PTR(p_Manip->reassmParams.ip.ipv6AutoLearnHashTblAddr)); ++ if (p_Manip->reassmParams.ip.ipv4AutoLearnSetLockTblAddr) ++ XX_FreeSmart( ++ UINT_TO_PTR(p_Manip->reassmParams.ip.ipv4AutoLearnSetLockTblAddr)); ++ if (p_Manip->reassmParams.ip.ipv6AutoLearnSetLockTblAddr) ++ XX_FreeSmart( ++ UINT_TO_PTR(p_Manip->reassmParams.ip.ipv6AutoLearnSetLockTblAddr)); ++ if (p_Manip->reassmParams.ip.p_Ipv4ReassTbl) ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, ++ p_Manip->reassmParams.ip.p_Ipv4ReassTbl); ++ if (p_Manip->reassmParams.ip.p_Ipv6ReassTbl) ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, ++ p_Manip->reassmParams.ip.p_Ipv6ReassTbl); ++ if (p_Manip->reassmParams.ip.h_Ipv6Ad) ++ XX_FreeSmart(p_Manip->reassmParams.ip.h_Ipv6Ad); ++ if (p_Manip->reassmParams.ip.h_Ipv4Ad) ++ XX_FreeSmart(p_Manip->reassmParams.ip.h_Ipv4Ad); ++ } ++ } ++ ++ if (p_Manip->p_StatsTbl) ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->p_StatsTbl); ++} ++ ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++static t_Error CheckManipParamsAndSetType(t_FmPcdManip *p_Manip, t_FmPcdManipParams *p_ManipParams) ++{ ++ if (p_ManipParams->u.hdr.rmv) ++ { ++ switch (p_ManipParams->u.hdr.rmvParams.type) ++ { ++ case (e_FM_PCD_MANIP_RMV_BY_HDR): ++ switch (p_ManipParams->u.hdr.rmvParams.u.byHdr.type) ++ { ++ case (e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START) : ++ if (p_ManipParams->u.hdr.rmvParams.u.byHdr.u.fromStartByHdr.include) ++ { ++ switch (p_ManipParams->u.hdr.rmvParams.u.byHdr.u.fromStartByHdr.hdrInfo.hdr) ++ { ++ case (HEADER_TYPE_CAPWAP_DTLS) : ++ p_Manip->opcode = HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST; ++ p_Manip->muramAllocate = TRUE; ++ if (p_ManipParams->u.hdr.insrt) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("for CAPWAP_DTLS_HDR remove can not be insrt manipualtion after")); ++ if (p_ManipParams->fragOrReasm) ++ { ++ if (!p_ManipParams->fragOrReasmParams.frag) ++ { ++ switch (p_ManipParams->fragOrReasmParams.hdr) ++ { ++ case (HEADER_TYPE_CAPWAP): ++ p_Manip->opcode = HMAN_OC_CAPWAP_REASSEMBLY; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("unsupported header for Reassembly")); ++ } ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("for this type of manipulation frag can not be TRUE")); ++ } ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("non valid net header of remove location")); ++ } ++ } ++ else ++ { ++ switch (p_ManipParams->u.hdr.rmvParams.u.byHdr.u.fromStartByHdr.hdrInfo.hdr) ++ { ++ case (HEADER_TYPE_CAPWAP_DTLS) : ++ case (HEADER_TYPE_CAPWAP) : ++ if (p_ManipParams->fragOrReasm || p_ManipParams->u.hdr.insrt) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("for the type of remove e_FM_PCD_MANIP_RMV_FROM_START_OF_FRAME_TILL_CAPWAP can not be insert or fragOrReasm TRUE")); ++ p_Manip->opcode = HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR; ++ p_Manip->muramAllocate = TRUE; ++ p_ManipParams->u.hdr.insrt = TRUE; //internal frame header ++ break; ++ default : ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid type of remove manipulation")); ++ } ++ } ++ break; ++ default : ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid type of remove manipulation")); ++ } ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid type of remove manipulation")); ++ } ++ } ++ else if (p_ManipParams->u.hdr.insrt) ++ { ++ switch (p_ManipParams->u.hdr.insrtParams.type) ++ { ++ case (e_FM_PCD_MANIP_INSRT_BY_TEMPLATE) : ++ ++ p_Manip->opcode = HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER; ++ p_Manip->muramAllocate = FALSE; ++ if (p_ManipParams->fragOrReasm) ++ { ++ if (p_ManipParams->fragOrReasmParams.frag) ++ { ++ switch (p_ManipParams->fragOrReasmParams.hdr) ++ { ++ case (HEADER_TYPE_CAPWAP): ++ p_Manip->opcode = HMAN_OC_CAPWAP_FRAGMENTATION; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid header for fragmentation")); ++ } ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_STATE,("can not reach this point")); ++ } ++ break; ++ ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("for only isert manipulation unsupported type")); ++ } ++ } ++ else if (p_ManipParams->fragOrReasm) ++ { ++ if (p_ManipParams->fragOrReasmParams.frag) ++ { ++ switch (p_ManipParams->fragOrReasmParams.hdr) ++ { ++ case (HEADER_TYPE_CAPWAP): ++ p_Manip->opcode = HMAN_OC_CAPWAP_FRAGMENTATION; ++ p_Manip->muramAllocate = FALSE; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Unsupported header for fragmentation")); ++ } ++ } ++ else ++ { ++ switch (p_ManipParams->fragOrReasmParams.hdr) ++ { ++ case (HEADER_TYPE_CAPWAP): ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Reassembly has to be with additional operation - rmv = TRUE, type of remove - e_FM_PCD_MANIP_RMV_FROM_START_OF_FRAME_INCLUDE_SPECIFIC_LOCATION,type = e_FM_PCD_MANIP_LOC_BY_HDR, hdr = HEADER_TYPE_CAPWAP_DTLS")); ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Unsupported header for reassembly")); ++ } ++ } ++ ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("User didn't ask for any manipulation")); ++ ++ p_Manip->insrt = p_ManipParams->u.hdr.insrt; ++ p_Manip->rmv = p_ManipParams->u.hdr.rmv; ++ ++ return E_OK; ++} ++ ++#else /* not (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++static t_Error CheckManipParamsAndSetType(t_FmPcdManip *p_Manip, ++ t_FmPcdManipParams *p_ManipParams) ++{ ++ switch (p_ManipParams->type) ++ { ++ case e_FM_PCD_MANIP_HDR: ++ /* Check that next-manip is not already used */ ++ if (p_ManipParams->h_NextManip) ++ { ++ if (!MANIP_IS_FIRST(p_ManipParams->h_NextManip)) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_STATE, ++ ("h_NextManip is already a part of another chain")); ++ if ((MANIP_GET_TYPE(p_ManipParams->h_NextManip) ++ != e_FM_PCD_MANIP_HDR) && ++ (MANIP_GET_TYPE(p_ManipParams->h_NextManip) ++ != e_FM_PCD_MANIP_FRAG)) ++ RETURN_ERROR( ++ MAJOR, ++ E_NOT_SUPPORTED, ++ ("For a Header Manipulation node - no support of h_NextManip of type other than Header Manipulation or Fragmentation.")); ++ } ++ ++ if (p_ManipParams->u.hdr.rmv) ++ { ++ switch (p_ManipParams->u.hdr.rmvParams.type) ++ { ++ case (e_FM_PCD_MANIP_RMV_BY_HDR): ++ switch (p_ManipParams->u.hdr.rmvParams.u.byHdr.type) ++ { ++ case (e_FM_PCD_MANIP_RMV_BY_HDR_SPECIFIC_L2): ++ break; ++#if (DPAA_VERSION >= 11) ++ case (e_FM_PCD_MANIP_RMV_BY_HDR_CAPWAP): ++ break; ++ case (e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START): ++ { ++ t_Error err; ++ uint8_t prsArrayOffset; ++ ++ err = ++ GetPrOffsetByHeaderOrField( ++ &p_ManipParams->u.hdr.rmvParams.u.byHdr.u.hdrInfo, ++ &prsArrayOffset); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ break; ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ default: ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("invalid type of remove manipulation")); ++ } ++ break; ++ case (e_FM_PCD_MANIP_RMV_GENERIC): ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("invalid type of remove manipulation")); ++ } ++ p_Manip->opcode = HMAN_OC; ++ p_Manip->muramAllocate = TRUE; ++ p_Manip->rmv = TRUE; ++ } ++ else ++ if (p_ManipParams->u.hdr.insrt) ++ { ++ switch (p_ManipParams->u.hdr.insrtParams.type) ++ { ++ case (e_FM_PCD_MANIP_INSRT_BY_HDR): ++ { ++ switch (p_ManipParams->u.hdr.insrtParams.u.byHdr.type) ++ { ++ case (e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2): ++ /* nothing to check */ ++ break; ++#if (DPAA_VERSION >= 11) ++ case (e_FM_PCD_MANIP_INSRT_BY_HDR_IP): ++ if (p_ManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size ++ % 4) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("IP inserted header must be of size which is a multiple of four bytes")); ++ break; ++ case (e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP): ++ if (p_ManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size ++ % 4) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("CAPWAP inserted header must be of size which is a multiple of four bytes")); ++ break; ++ case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP): ++ case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE): ++ if (p_ManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size ++ != 8) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("Inserted header must be of size 8")); ++ break; ++#endif /* (DPAA_VERSION >= 11) */ ++ default: ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("unsupported insert by header type")); ++ } ++ } ++ case (e_FM_PCD_MANIP_INSRT_GENERIC): ++ break; ++ default: ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("for only insert manipulation unsupported type")); ++ } ++ p_Manip->opcode = HMAN_OC; ++ p_Manip->muramAllocate = TRUE; ++ p_Manip->insrt = TRUE; ++ } ++ else ++ if (p_ManipParams->u.hdr.fieldUpdate) ++ { ++ /* Check parameters */ ++ if (p_ManipParams->u.hdr.fieldUpdateParams.type ++ == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN) ++ { ++ if ((p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType ++ == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_VPRI) ++ && (p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.u.vpri ++ > 7)) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("vpri should get values of 0-7 ")); ++ if (p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType ++ == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN) ++ { ++ int i; ++ ++ if (p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.u.dscpToVpri.vpriDefVal ++ > 7) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("vpriDefVal should get values of 0-7 ")); ++ for (i = 0; i < FM_PCD_MANIP_DSCP_TO_VLAN_TRANS; ++ i++) ++ if (p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.u.dscpToVpri.dscpToVpriTable[i] ++ & 0xf0) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("dscpToVpriTabl value out of range (0-15)")); ++ } ++ ++ } ++ ++ p_Manip->opcode = HMAN_OC; ++ p_Manip->muramAllocate = TRUE; ++ p_Manip->fieldUpdate = TRUE; ++ } ++ else ++ if (p_ManipParams->u.hdr.custom) ++ { ++ if (p_ManipParams->u.hdr.customParams.type == e_FM_PCD_MANIP_HDR_CUSTOM_GEN_FIELD_REPLACE) ++ { ++ ++ if ((p_ManipParams->u.hdr.customParams.u.genFieldReplace.size == 0) || ++ (p_ManipParams->u.hdr.customParams.u.genFieldReplace.size > 8)) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("size should get values of 1-8 ")); ++ ++ if (p_ManipParams->u.hdr.customParams.u.genFieldReplace.srcOffset > 7) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("srcOffset should be <= 7")); ++ ++ if ((p_ManipParams->u.hdr.customParams.u.genFieldReplace.srcOffset + ++ p_ManipParams->u.hdr.customParams.u.genFieldReplace.size) > 8) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("(srcOffset + size) should be <= 8")); ++ ++ if ((p_ManipParams->u.hdr.customParams.u.genFieldReplace.dstOffset + ++ p_ManipParams->u.hdr.customParams.u.genFieldReplace.size) > 256) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("(dstOffset + size) should be <= 256")); ++ ++ } ++ ++ p_Manip->opcode = HMAN_OC; ++ p_Manip->muramAllocate = TRUE; ++ p_Manip->custom = TRUE; ++ } ++ break; ++ case e_FM_PCD_MANIP_REASSEM: ++ if (p_ManipParams->h_NextManip) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ++ ("next manip with reassembly")); ++ switch (p_ManipParams->u.reassem.hdr) ++ { ++ case (HEADER_TYPE_IPv4): ++ p_Manip->reassmParams.hdr = HEADER_TYPE_IPv4; ++ p_Manip->opcode = HMAN_OC_IP_REASSEMBLY; ++ break; ++ case (HEADER_TYPE_IPv6): ++ p_Manip->reassmParams.hdr = HEADER_TYPE_IPv6; ++ p_Manip->opcode = HMAN_OC_IP_REASSEMBLY; ++ break; ++#if (DPAA_VERSION >= 11) ++ case (HEADER_TYPE_CAPWAP): ++ p_Manip->reassmParams.hdr = HEADER_TYPE_CAPWAP; ++ p_Manip->opcode = HMAN_OC_CAPWAP_REASSEMBLY; ++ break; ++#endif /* (DPAA_VERSION >= 11) */ ++ default: ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ++ ("header for reassembly")); ++ } ++ break; ++ case e_FM_PCD_MANIP_FRAG: ++ if (p_ManipParams->h_NextManip) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ++ ("next manip with fragmentation")); ++ switch (p_ManipParams->u.frag.hdr) ++ { ++ case (HEADER_TYPE_IPv4): ++ case (HEADER_TYPE_IPv6): ++ p_Manip->opcode = HMAN_OC_IP_FRAGMENTATION; ++ break; ++#if (DPAA_VERSION >= 11) ++ case (HEADER_TYPE_CAPWAP): ++ p_Manip->opcode = HMAN_OC_CAPWAP_FRAGMENTATION; ++ break; ++#endif /* (DPAA_VERSION >= 11) */ ++ default: ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ++ ("header for fragmentation")); ++ } ++ p_Manip->muramAllocate = TRUE; ++ break; ++ case e_FM_PCD_MANIP_SPECIAL_OFFLOAD: ++ switch (p_ManipParams->u.specialOffload.type) ++ { ++ case (e_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC): ++ p_Manip->opcode = HMAN_OC_IPSEC_MANIP; ++ p_Manip->muramAllocate = TRUE; ++ break; ++#if (DPAA_VERSION >= 11) ++ case (e_FM_PCD_MANIP_SPECIAL_OFFLOAD_CAPWAP): ++ p_Manip->opcode = HMAN_OC_CAPWAP_MANIP; ++ p_Manip->muramAllocate = TRUE; ++ break; ++#endif /* (DPAA_VERSION >= 11) */ ++ default: ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ++ ("special offload type")); ++ } ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("manip type")); ++ } ++ ++ return E_OK; ++} ++#endif /* not (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++ ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++ ++static t_Error UpdateIndxStats(t_Handle h_FmPcd, ++ t_Handle h_FmPort, ++ t_FmPcdManip *p_Manip) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ uint32_t tmpReg32 = 0; ++ t_AdOfTypeContLookup *p_Ad; ++ t_FmPortGetSetCcParams fmPortGetSetCcParams; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip,E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE); ++ ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; ++ if (p_Manip->h_FmPcd != h_FmPcd) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("handler of PCD previously was initiated by different value")); ++ ++ memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams)); ++ ++ if (!p_Manip->p_StatsTbl) ++ { ++ ++ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNDN; ++ fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_CC; ++ err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ tmpReg32 = GET_UINT32(p_Ad->ccAdBase); ++ ++ p_Manip->p_StatsTbl = ++ (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, ++ (uint32_t)p_Manip->owner * FM_PCD_MANIP_INDEXED_STATS_ENTRY_SIZE, ++ 4); ++ if (!p_Manip->p_StatsTbl) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for Manipulation indexed statistics table")); ++ ++ MemSet8(p_Manip->p_StatsTbl, 0, (uint32_t)(p_Manip->owner * 4)); ++ ++ tmpReg32 |= (uint32_t)(XX_VirtToPhys(p_Manip->p_StatsTbl) - p_FmPcd->physicalMuramBase); ++ ++ if (p_Manip->cnia) ++ tmpReg32 |= FM_PCD_MANIP_INDEXED_STATS_CNIA; ++ ++ tmpReg32 |= FM_PCD_MANIP_INDEXED_STATS_DPD; ++ WRITE_UINT32(p_Ad->ccAdBase, tmpReg32); ++ } ++ else ++ { ++ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNDN; ++ fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_CC; ++ err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ return E_OK; ++} ++ ++static t_Error RmvHdrTillSpecLocNOrInsrtIntFrmHdr(t_FmPcdManipHdrRmvParams *p_ManipParams, t_FmPcdManip *p_Manip) ++{ ++ t_AdOfTypeContLookup *p_Ad; ++ uint32_t tmpReg32 = 0; ++ uint8_t prsArrayOffset = 0; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip,E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_ManipParams,E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE); ++ ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; ++ if (p_Manip->rmv) ++ { ++ err = GetPrOffsetByHeaderOrField(&p_ManipParams->u.byHdr.u.fromStartByHdr.hdrInfo, &prsArrayOffset); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ tmpReg32 |= (uint32_t)prsArrayOffset << 24; ++ tmpReg32 |= HMAN_RMV_HDR; ++ } ++ ++ if (p_Manip->insrt) ++ tmpReg32 |= HMAN_INSRT_INT_FRM_HDR; ++ ++ tmpReg32 |= (uint32_t)HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR; ++ ++ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); ++ ++ tmpReg32 = 0; ++ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; ++ WRITE_UINT32(p_Ad->ccAdBase, tmpReg32); ++ ++ return E_OK; ++} ++ ++static t_Error MvIntFrameHeaderFromFrameToBufferPrefix(t_FmPcdManip *p_Manip, ++ bool caamUsed) ++{ ++ t_AdOfTypeContLookup *p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; ++ uint32_t tmpReg32 = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Ad, E_INVALID_HANDLE); ++ ++ p_Manip->updateParams |= OFFSET_OF_PR | INTERNAL_CONTEXT_OFFSET; ++ ++ tmpReg32 = 0; ++ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; ++ *(uint32_t *)&p_Ad->ccAdBase = tmpReg32; ++ ++ tmpReg32 = 0; ++ tmpReg32 |= HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX; ++ tmpReg32 |= (uint32_t)0x16 << 16; ++ *(uint32_t *)&p_Ad->pcAndOffsets = tmpReg32; ++ ++ if (caamUsed) ++ *(uint32_t *)&p_Ad->gmask = 0xf0000000; ++ ++ return E_OK; ++} ++ ++static t_Error CapwapRmvDtlsHdr(t_FmPcd *p_FmPcd, t_FmPcdManip *p_Manip) ++{ ++ t_AdOfTypeContLookup *p_Ad; ++ uint32_t tmpReg32 = 0; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE); ++ ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; ++ ++ tmpReg32 = 0; ++ tmpReg32 |= (uint32_t)HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST; ++ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); ++ ++ tmpReg32 = 0; ++ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; ++ ++ ++ if (p_Manip->h_Frag) ++ { ++ p_Manip->updateParams |= INTERNAL_CONTEXT_OFFSET; ++ tmpReg32 |= (uint32_t)(XX_VirtToPhys(p_Manip->h_Frag) - (p_FmPcd->physicalMuramBase)); ++ } ++ ++ WRITE_UINT32(p_Ad->ccAdBase, tmpReg32); ++ ++ return err; ++} ++ ++static t_Error CapwapReassembly(t_CapwapReassemblyParams *p_ManipParams, ++ t_FmPcdManip *p_Manip, ++ t_FmPcd *p_FmPcd, ++ uint8_t poolId) ++{ ++ t_Handle p_Table; ++ uint32_t tmpReg32 = 0; ++ int i = 0; ++ uint8_t log2Num; ++ uint8_t numOfSets; ++ uint32_t j = 0; ++ uint32_t bitFor1Micro; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); ++ ++ if (!p_FmPcd->h_Hc) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE,("hc port has to be initialized in this mode")); ++ if (!POWER_OF_2(p_ManipParams->timeoutRoutineRequestTime)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("timeoutRoutineRequestTime has to be power of 2")); ++ if (!POWER_OF_2(p_ManipParams->maxNumFramesInProcess)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE,("maxNumFramesInProcess has to be power of 2")); ++ if (!p_ManipParams->timeoutRoutineRequestTime && p_ManipParams->timeoutThresholdForReassmProcess) ++ DBG(WARNING, ("if timeoutRoutineRequestTime 0, timeoutThresholdForReassmProcess is uselessly")); ++ if (p_ManipParams->numOfFramesPerHashEntry == e_FM_PCD_MANIP_FOUR_WAYS_HASH) ++ { ++ if ((p_ManipParams->maxNumFramesInProcess < 4) || ++ (p_ManipParams->maxNumFramesInProcess > 512)) ++ RETURN_ERROR(MAJOR,E_INVALID_VALUE, ("In the case of numOfFramesPerHashEntry = e_FM_PCD_MANIP_EIGHT_WAYS_HASH maxNumFramesInProcess has to be in the range 4-512")); ++ } ++ else ++ { ++ if ((p_ManipParams->maxNumFramesInProcess < 8) || ++ (p_ManipParams->maxNumFramesInProcess > 2048)) ++ RETURN_ERROR(MAJOR,E_INVALID_VALUE, ("In the case of numOfFramesPerHashEntry = e_FM_PCD_MANIP_FOUR_WAYS_HASH maxNumFramesInProcess has to be in the range 8-2048")); ++ } ++ ++ bitFor1Micro = FmGetTimeStampScale(p_FmPcd->h_Fm); ++ if (bitFor1Micro == 0) ++ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Timestamp scale")); ++ ++ p_Manip->updateParams |= (NUM_OF_TASKS | OFFSET_OF_PR | OFFSET_OF_DATA | HW_PORT_ID); ++ ++ p_Manip->h_Frag = (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, ++ FM_PCD_MANIP_CAPWAP_REASM_TABLE_SIZE, ++ FM_PCD_MANIP_CAPWAP_REASM_TABLE_ALIGN); ++ if (!p_Manip->h_Frag) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc CAPWAP reassembly parameters table")); ++ ++ MemSet8(p_Manip->h_Frag, 0, FM_PCD_MANIP_CAPWAP_REASM_TABLE_SIZE); ++ ++ p_Table = (t_CapwapReasmPram *)p_Manip->h_Frag; ++ ++ p_Manip->capwapFragParams.p_AutoLearnHashTbl = ++ (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, ++ (uint32_t)(p_ManipParams->maxNumFramesInProcess * 2 * FM_PCD_MANIP_CAPWAP_REASM_AUTO_LEARNING_HASH_ENTRY_SIZE), ++ FM_PCD_MANIP_CAPWAP_REASM_TABLE_ALIGN); ++ ++ if (!p_Manip->capwapFragParams.p_AutoLearnHashTbl) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY,("MURAM alloc for CAPWAP automatic learning hash table")); ++ ++ MemSet8(p_Manip->capwapFragParams.p_AutoLearnHashTbl, 0, (uint32_t)(p_ManipParams->maxNumFramesInProcess * 2 * FM_PCD_MANIP_CAPWAP_REASM_AUTO_LEARNING_HASH_ENTRY_SIZE)); ++ ++ tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->capwapFragParams.p_AutoLearnHashTbl) - p_FmPcd->physicalMuramBase); ++ ++ WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->autoLearnHashTblPtr, tmpReg32); ++ ++ tmpReg32 = 0; ++ if (p_ManipParams->timeOutMode == e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAMES) ++ tmpReg32 |= FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_BETWEEN_FRAMES; ++ if (p_ManipParams->haltOnDuplicationFrag) ++ tmpReg32 |= FM_PCD_MANIP_CAPWAP_REASM_HALT_ON_DUPLICATE_FRAG; ++ if (p_ManipParams->numOfFramesPerHashEntry == e_FM_PCD_MANIP_EIGHT_WAYS_HASH) ++ { ++ i = 8; ++ tmpReg32 |= FM_PCD_MANIP_CAPWAP_REASM_AUTOMATIC_LEARNIN_HASH_8_WAYS; ++ } ++ else ++ i = 4; ++ ++ numOfSets = (uint8_t)((p_ManipParams->maxNumFramesInProcess * 2) / i); ++ LOG2(numOfSets, log2Num); ++ tmpReg32 |= (uint32_t)(log2Num - 1) << 24; ++ ++ WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->mode, tmpReg32); ++ ++ for (j=0; jmaxNumFramesInProcess*2; j++) ++ if (((j / i) % 2)== 0) ++ WRITE_UINT32(*(uint32_t *)PTR_MOVE(p_Manip->capwapFragParams.p_AutoLearnHashTbl, j * FM_PCD_MANIP_CAPWAP_REASM_AUTO_LEARNING_HASH_ENTRY_SIZE), 0x80000000); ++ ++ tmpReg32 = 0x00008000; ++ tmpReg32 |= (uint32_t)poolId << 16; ++ WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->bufferPoolIdAndRisc1SetIndexes, tmpReg32); ++ WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->risc23SetIndexes, 0x80008000); ++ WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->risc4SetIndexesAndExtendedStatsTblPtr, 0x80000000); ++ ++ p_Manip->capwapFragParams.maxNumFramesInProcess = p_ManipParams->maxNumFramesInProcess; ++ ++ p_Manip->capwapFragParams.sgBpid = poolId; ++ ++ p_Manip->capwapFragParams.fqidForTimeOutFrames = p_ManipParams->fqidForTimeOutFrames; ++ p_Manip->capwapFragParams.timeoutRoutineRequestTime = p_ManipParams->timeoutRoutineRequestTime; ++ p_Manip->capwapFragParams.bitFor1Micro = bitFor1Micro; ++ ++ tmpReg32 = 0; ++ tmpReg32 |= (((uint32_t)1<capwapFragParams.bitFor1Micro) * p_ManipParams->timeoutThresholdForReassmProcess); ++ WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->expirationDelay, tmpReg32); ++ ++ return E_OK; ++} ++ ++static t_Error CapwapFragmentation(t_CapwapFragmentationParams *p_ManipParams, ++ t_FmPcdManip *p_Manip, ++ t_FmPcd *p_FmPcd, ++ uint8_t poolId) ++{ ++ t_AdOfTypeContLookup *p_Ad; ++ uint32_t tmpReg32 = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE); ++ ++ p_Manip->updateParams |= OFFSET_OF_DATA; ++ ++ p_Manip->frag = TRUE; ++ ++ p_Manip->h_Frag = (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, ++ FM_PCD_CC_AD_ENTRY_SIZE, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!p_Manip->h_Frag) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for CAPWAP fragmentation table descriptor")); ++ ++ MemSet8(p_Manip->h_Frag, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Frag; ++ ++ tmpReg32 = 0; ++ tmpReg32 |= (uint32_t)HMAN_OC_CAPWAP_FRAGMENTATION; ++ ++ if (p_ManipParams->headerOptionsCompr) ++ tmpReg32 |= FM_PCD_MANIP_CAPWAP_FRAG_COMPR_OPTION_FIELD_EN; ++ tmpReg32 |= ((uint32_t)poolId << 8); ++ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); ++ ++ tmpReg32 = 0; ++ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; ++ WRITE_UINT32(p_Ad->ccAdBase, tmpReg32); ++ ++ p_Manip->sizeForFragmentation = p_ManipParams->sizeForFragmentation; ++ p_Manip->capwapFragParams.sgBpid = poolId; ++ ++ return E_OK; ++} ++ ++static t_Error IndxStats(t_FmPcdStatsParams *p_StatsParams,t_FmPcdManip *p_Manip,t_FmPcd *p_FmPcd) ++{ ++ t_AdOfTypeContLookup *p_Ad; ++ uint32_t tmpReg32 = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE); ++ ++ UNUSED(p_FmPcd); ++ ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; ++ ++ tmpReg32 = 0; ++ tmpReg32 |= (uint32_t)HMAN_OC_CAPWAP_INDEXED_STATS; ++ if (p_StatsParams->type == e_FM_PCD_STATS_PER_FLOWID) ++ tmpReg32 |= (uint32_t)0x16 << 16; ++ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); ++ ++ tmpReg32 = 0; ++ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; ++ WRITE_UINT32(p_Ad->ccAdBase, tmpReg32); ++ ++ return E_OK; ++} ++ ++static t_Error InsrtHdrByTempl(t_FmPcdManipHdrInsrtParams *p_ManipParams, t_FmPcdManip *p_Manip, t_FmPcd *p_FmPcd) ++{ ++ t_FmPcdManipHdrInsrtByTemplateParams *p_InsrtByTemplate = &p_ManipParams->u.byTemplate; ++ uint8_t tmpReg8 = 0xff; ++ t_AdOfTypeContLookup *p_Ad; ++ bool ipModify = FALSE; ++ uint32_t tmpReg32 = 0, tmpRegNia = 0; ++ uint16_t tmpReg16 = 0; ++ t_Error err = E_OK; ++ uint8_t extraAddedBytes = 0, blockSize = 0, extraAddedBytesAlignedToBlockSize = 0, log2Num = 0; ++ uint8_t *p_Template = NULL; ++ ++ SANITY_CHECK_RETURN_ERROR(p_ManipParams,E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_Manip,E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd,E_NULL_POINTER); ++ ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; ++ if (p_Manip->insrt) ++ { ++ if ((!p_InsrtByTemplate->size && p_InsrtByTemplate->modifyOuterIp) || ++ (!p_InsrtByTemplate->size && p_InsrtByTemplate->modifyOuterVlan)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : asking for header template modifications with no template for insertion (template size)")); ++ ++ if (p_InsrtByTemplate->size && p_InsrtByTemplate->modifyOuterIp && (p_InsrtByTemplate->size <= p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : size of template < ipOuterOffset")); ++ ++ if (p_InsrtByTemplate->size > 128) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Size of header template for insertion can not be more than 128")); ++ ++ if (p_InsrtByTemplate->size) ++ { ++ p_Manip->p_Template = (uint8_t *)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, ++ p_InsrtByTemplate->size, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if(!p_Manip->p_Template) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory allocation in MURAM FAILED")); ++ ++ tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->p_Template) - (p_FmPcd->physicalMuramBase)); ++ tmpReg32 |= (uint32_t)p_InsrtByTemplate->size << 24; ++ *(uint32_t *)&p_Ad->matchTblPtr = tmpReg32; ++ } ++ ++ tmpReg32 = 0; ++ ++ p_Template = (uint8_t *)XX_Malloc(p_InsrtByTemplate->size * sizeof(uint8_t)); ++ ++ if (!p_Template) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("XX_Malloc allocation FAILED")); ++ ++ memcpy(p_Template, p_InsrtByTemplate->hdrTemplate, p_InsrtByTemplate->size * sizeof(uint8_t)); ++ ++ if (p_InsrtByTemplate->modifyOuterIp) ++ { ++ ipModify = TRUE; ++ ++ tmpReg8 = (uint8_t)p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset]; ++ ++ if((tmpReg8 & 0xf0) == 0x40) ++ tmpReg8 = 4; ++ else if((tmpReg8 & 0xf0) == 0x60) ++ tmpReg8 = 6; ++ else ++ tmpReg8 = 0xff; ++ ++ if (tmpReg8 != 0xff) ++ { ++ if(p_InsrtByTemplate->modifyOuterIpParams.dscpEcn & 0xff00) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : IPV4 present in header template, dscpEcn has to be only 1 byte")); ++ if(p_InsrtByTemplate->modifyOuterIpParams.recalculateLength) ++ { ++ ++ if((p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedAlignedToBlockSize + p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedNotAlignedToBlockSize) > 255) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("extra Byte added can not be more than 256 bytes")); ++ extraAddedBytes = (uint8_t) (p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedAlignedToBlockSize + p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedNotAlignedToBlockSize); ++ blockSize = p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.blockSize; ++ extraAddedBytesAlignedToBlockSize = p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedAlignedToBlockSize; ++ /*IP header template - IP totalLength - ++ (1 byte) extraByteForIp = headerTemplateSize - ipOffset + insertedBytesAfterThisStage , ++ in the case of SEC insertedBytesAfterThisStage - SEC trailer (21/31) + header(13) ++ second byte - extraByteForIp = headerTemplate - ipOffset + insertedBytesAfterThisStage*/ ++ } ++ if (blockSize) ++ { ++ if (!POWER_OF_2(blockSize)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("inputFrmPaddingUpToBlockSize has to be power of 2")); ++ } ++ ++ } ++ if (tmpReg8 == 4) ++ { ++ if ((IPv4_HDRCHECKSUM_FIELD_OFFSET_FROM_IP + p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset) > p_InsrtByTemplate->size) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : IP present in header template, user asked for IP modifications but ipOffset + ipTotalLengthFieldOffset in header template bigger than template size")); ++ ++ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_DSCECN_FIELD_OFFSET_FROM_IP] = (uint8_t)p_InsrtByTemplate->modifyOuterIpParams.dscpEcn; ++ ++ if (blockSize) ++ blockSize -= 1; ++ ++ if ((p_InsrtByTemplate->size - p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + extraAddedBytes) > 255) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("p_InsrtByTemplate->size - p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + extraAddedBytes has to be less than 255")); ++ ++ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_TOTALLENGTH_FIELD_OFFSET_FROM_IP + 1] = blockSize; // IPV6 - in AD instead of SEQ IND ++ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_TOTALLENGTH_FIELD_OFFSET_FROM_IP] = (uint8_t)(p_InsrtByTemplate->size - p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + extraAddedBytes);// for IPV6 decrement additional 40 bytes of IPV6 heade size ++ ++ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_ID_FIELD_OFFSET_FROM_IP] = 0x00; ++ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_ID_FIELD_OFFSET_FROM_IP + 1] = extraAddedBytesAlignedToBlockSize; ++ ++ /*IP header template - relevant only for ipv4 CheckSum = 0*/ ++ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_HDRCHECKSUM_FIELD_OFFSET_FROM_IP] = 0x00; ++ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_HDRCHECKSUM_FIELD_OFFSET_FROM_IP + 1] = 0x00; ++ ++ /*UDP checksum has to be 0*/ ++ if (p_InsrtByTemplate->modifyOuterIpParams.udpPresent) ++ { ++ if ((p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP + UDP_CHECKSUM_FIELD_SIZE) > p_InsrtByTemplate->size) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : UDP present according to user but (UDP offset + UDP header size) < size of header template")); ++ ++ p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP ] = 0x00; ++ p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP + 1] = 0x00; ++ ++ } ++ ++ if (p_InsrtByTemplate->modifyOuterIpParams.ipIdentGenId > 7) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("ipIdentGenId has to be one out of 8 sequence number generators (0 - 7) for IP identification field")); ++ ++ tmpRegNia |= (uint32_t)p_InsrtByTemplate->modifyOuterIpParams.ipIdentGenId<<24; ++ } ++ else if (tmpReg8 == 6) ++ { ++ /*TODO - add check for maximum value of blockSize;*/ ++ if (blockSize) ++ LOG2(blockSize, log2Num); ++ tmpRegNia |= (uint32_t)log2Num << 24; ++ ++ // for IPV6 decrement additional 40 bytes of IPV6 heade size - because IPV6 header size is not included in payloadLength ++ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv6_PAYLOAD_LENGTH_OFFSET_FROM_IP] = (uint8_t)(p_InsrtByTemplate->size - p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + extraAddedBytes - 40); ++ p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv6_PAYLOAD_LENGTH_OFFSET_FROM_IP + 1] = extraAddedBytesAlignedToBlockSize; ++ if (p_InsrtByTemplate->modifyOuterIpParams.udpPresent) ++ { ++ if ((p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP + UDP_CHECKSUM_FIELD_SIZE) > p_InsrtByTemplate->size) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : UDP present according to user but (UDP offset + UDP header size) < size of header template")); ++ if (p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv6_NEXT_HEADER_OFFSET_FROM_IP] != 0x88) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("OUr suppport is only IPv6/UDPLite")); ++ p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_LENGTH_FIELD_OFFSET_FROM_UDP] = 0x00; ++ p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_LENGTH_FIELD_OFFSET_FROM_UDP + 1] = 0x08; ++ p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP] = 0x00; ++ p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP + 1] = 0x00; ++ } ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("IP version supported only IPV4")); ++ } ++ ++ tmpReg32 = tmpReg16 = tmpReg8 = 0; ++ /*TODO - check it*/ ++ if (p_InsrtByTemplate->modifyOuterVlan) ++ { ++ if (p_InsrtByTemplate->modifyOuterVlanParams.vpri & ~0x07) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE,("Inconsistent parameters : user asked for VLAN modifications but VPRI more than 3 bits")); ++ ++ memcpy(&tmpReg16, &p_Template[VLAN_TAG_FIELD_OFFSET_FROM_ETH], 2*(sizeof(uint8_t))); ++ if ((tmpReg16 != 0x9100) && (tmpReg16!= 0x9200) && (tmpReg16 != 0x8100)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE,("Inconsistent parameters : user asked for VLAN modifications but Tag Protocol identifier is not VLAN ")); ++ ++ memcpy(&tmpReg8, &p_Template[14],1*(sizeof(uint8_t))); ++ tmpReg8 &= 0x1f; ++ tmpReg8 |= (uint8_t)(p_InsrtByTemplate->modifyOuterVlanParams.vpri << 5); ++ ++ p_Template[14] = tmpReg8; ++ } ++ ++ MemCpy8(p_Manip->p_Template, p_Template, p_InsrtByTemplate->size); ++ ++ XX_Free(p_Template); ++ } ++ ++ tmpReg32 = 0; ++ if (p_Manip->h_Frag) ++ { ++ tmpRegNia |= (uint32_t)(XX_VirtToPhys(p_Manip->h_Frag) - (p_FmPcd->physicalMuramBase)); ++ tmpReg32 |= (uint32_t)p_Manip->sizeForFragmentation << 16; ++ } ++ else ++ tmpReg32 = 0xffff0000; ++ ++ if (ipModify) ++ tmpReg32 |= (uint32_t)p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset << 8; ++ else ++ tmpReg32 |= (uint32_t)0x0000ff00; ++ ++ tmpReg32 |= (uint32_t)HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER; ++ *(uint32_t *)&p_Ad->pcAndOffsets = tmpReg32; ++ ++ tmpRegNia |= FM_PCD_AD_CONT_LOOKUP_TYPE; ++ *(uint32_t *)&p_Ad->ccAdBase = tmpRegNia; ++ ++ return err; ++} ++ ++static t_Error CheckStatsParamsAndSetType(t_FmPcdManip *p_Manip, t_FmPcdStatsParams *p_StatsParams) ++{ ++ ++ switch (p_StatsParams->type) ++ { ++ case (e_FM_PCD_STATS_PER_FLOWID): ++ p_Manip->opcode = HMAN_OC_CAPWAP_INDEXED_STATS; ++ p_Manip->muramAllocate = TRUE; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Unsupported statistics type")); ++ } ++ ++ return E_OK; ++} ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++ ++static t_Error FillReassmManipParams(t_FmPcdManip *p_Manip, e_NetHeaderType hdr) ++{ ++ t_AdOfTypeContLookup *p_Ad; ++ t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd; ++ uint32_t tmpReg32; ++ t_Error err = E_OK; ++ ++ /* Creates the Reassembly Parameters table. It contains parameters that are specific to either the IPv4 reassembly ++ function or to the IPv6 reassembly function. If both IPv4 reassembly and IPv6 reassembly are required, then ++ two separate IP Reassembly Parameter tables are required.*/ ++ if ((err = CreateReassTable(p_Manip, hdr)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ /* Sets the first Ad register (ccAdBase) - Action Descriptor Type and Pointer to the Reassembly Parameters Table offset from MURAM*/ ++ tmpReg32 = 0; ++ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; ++ ++ /* Gets the required Action descriptor table pointer */ ++ switch (hdr) ++ { ++ case HEADER_TYPE_IPv4: ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->reassmParams.ip.h_Ipv4Ad; ++ tmpReg32 |= (uint32_t)(XX_VirtToPhys( ++ p_Manip->reassmParams.ip.p_Ipv4ReassTbl) ++ - (p_FmPcd->physicalMuramBase)); ++ break; ++ case HEADER_TYPE_IPv6: ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->reassmParams.ip.h_Ipv6Ad; ++ tmpReg32 |= (uint32_t)(XX_VirtToPhys( ++ p_Manip->reassmParams.ip.p_Ipv6ReassTbl) ++ - (p_FmPcd->physicalMuramBase)); ++ break; ++ case HEADER_TYPE_CAPWAP: ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->reassmParams.capwap.h_Ad; ++ tmpReg32 |= (uint32_t)(XX_VirtToPhys( ++ p_Manip->reassmParams.capwap.p_ReassTbl) ++ - (p_FmPcd->physicalMuramBase)); ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("header type")); ++ } ++ ++ WRITE_UINT32(p_Ad->ccAdBase, tmpReg32); ++ ++ /* Sets the second Ad register (matchTblPtr) - Buffer pool ID (BPID for V2) and Scatter/Gather table offset*/ ++ /* mark the Scatter/Gather table offset to be set later on when the port will be known */ ++ p_Manip->updateParams = (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK); ++ ++ if ((hdr == HEADER_TYPE_IPv6) || (hdr == HEADER_TYPE_IPv4)) ++ { ++#if (DPAA_VERSION == 10) ++ tmpReg32 = (uint32_t)(p_Manip->reassmParams.sgBpid << 8); ++ WRITE_UINT32(p_Ad->matchTblPtr, tmpReg32); ++#endif /* (DPAA_VERSION == 10) */ ++#if (DPAA_VERSION >= 11) ++ if (p_Manip->reassmParams.ip.nonConsistentSpFqid != 0) ++ { ++ tmpReg32 = FM_PCD_AD_NCSPFQIDM_MASK ++ | (uint32_t)(p_Manip->reassmParams.ip.nonConsistentSpFqid); ++ WRITE_UINT32(p_Ad->gmask, tmpReg32); ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ /* Sets the third Ad register (pcAndOffsets)- IP Reassemble Operation Code*/ ++ tmpReg32 = 0; ++ tmpReg32 |= (uint32_t)HMAN_OC_IP_REASSEMBLY; ++ } ++#if (DPAA_VERSION >= 11) ++ else ++ if (hdr == HEADER_TYPE_CAPWAP) ++ { ++ tmpReg32 = 0; ++ tmpReg32 |= (uint32_t)HMAN_OC_CAPWAP_REASSEMBLY; ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); ++ ++ p_Manip->reassm = TRUE; ++ ++ return E_OK; ++} ++ ++static t_Error SetIpv4ReassmManip(t_FmPcdManip *p_Manip) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd; ++ ++ /* Allocation if IPv4 Action descriptor */ ++ p_Manip->reassmParams.ip.h_Ipv4Ad = (t_Handle)XX_MallocSmart( ++ FM_PCD_CC_AD_ENTRY_SIZE, p_Manip->reassmParams.dataMemId, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!p_Manip->reassmParams.ip.h_Ipv4Ad) ++ { ++ ReleaseManipHandler(p_Manip, p_FmPcd); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("Allocation of IPv4 table descriptor")); ++ } ++ ++ memset(p_Manip->reassmParams.ip.h_Ipv4Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ /* Fill reassembly manipulation parameter in the IP Reassembly Action Descriptor */ ++ return FillReassmManipParams(p_Manip, HEADER_TYPE_IPv4); ++} ++ ++static t_Error SetIpv6ReassmManip(t_FmPcdManip *p_Manip) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd; ++ ++ /* Allocation if IPv6 Action descriptor */ ++ p_Manip->reassmParams.ip.h_Ipv6Ad = (t_Handle)XX_MallocSmart( ++ FM_PCD_CC_AD_ENTRY_SIZE, p_Manip->reassmParams.dataMemId, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!p_Manip->reassmParams.ip.h_Ipv6Ad) ++ { ++ ReleaseManipHandler(p_Manip, p_FmPcd); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("Allocation of IPv6 table descriptor")); ++ } ++ ++ memset(p_Manip->reassmParams.ip.h_Ipv6Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ /* Fill reassembly manipulation parameter in the IP Reassembly Action Descriptor */ ++ return FillReassmManipParams(p_Manip, HEADER_TYPE_IPv6); ++} ++ ++static t_Error IpReassembly(t_FmPcdManipReassemParams *p_ManipReassmParams, ++ t_FmPcdManip *p_Manip) ++{ ++ uint32_t maxSetNumber = 10000; ++ t_FmPcdManipReassemIpParams reassmManipParams = ++ p_ManipReassmParams->u.ipReassem; ++ t_Error res; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip->h_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(((t_FmPcd *)p_Manip->h_FmPcd)->h_Hc, ++ E_INVALID_HANDLE); ++ ++ /* Check validation of user's parameter.*/ ++ if ((reassmManipParams.timeoutThresholdForReassmProcess < 1000) ++ || (reassmManipParams.timeoutThresholdForReassmProcess > 8000000)) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("timeoutThresholdForReassmProcess should be 1msec - 8sec")); ++ /* It is recommended that the total number of entries in this table (number of sets * number of ways) ++ will be twice the number of frames that are expected to be reassembled simultaneously.*/ ++ if (reassmManipParams.maxNumFramesInProcess ++ > (reassmManipParams.maxNumFramesInProcess * maxSetNumber / 2)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("maxNumFramesInProcess has to be less than (maximun set number * number of ways / 2)")); ++ ++ if ((p_ManipReassmParams->hdr == HEADER_TYPE_IPv6) ++ && (reassmManipParams.minFragSize[1] < 256)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("minFragSize[1] must be >= 256")); ++ ++ /* Saves user's reassembly manipulation parameters */ ++ p_Manip->reassmParams.ip.relativeSchemeId[0] = ++ reassmManipParams.relativeSchemeId[0]; ++ p_Manip->reassmParams.ip.relativeSchemeId[1] = ++ reassmManipParams.relativeSchemeId[1]; ++ p_Manip->reassmParams.ip.numOfFramesPerHashEntry[0] = ++ reassmManipParams.numOfFramesPerHashEntry[0]; ++ p_Manip->reassmParams.ip.numOfFramesPerHashEntry[1] = ++ reassmManipParams.numOfFramesPerHashEntry[1]; ++ p_Manip->reassmParams.ip.minFragSize[0] = reassmManipParams.minFragSize[0]; ++ p_Manip->reassmParams.ip.minFragSize[1] = reassmManipParams.minFragSize[1]; ++ p_Manip->reassmParams.maxNumFramesInProcess = ++ reassmManipParams.maxNumFramesInProcess; ++ p_Manip->reassmParams.timeOutMode = reassmManipParams.timeOutMode; ++ p_Manip->reassmParams.fqidForTimeOutFrames = ++ reassmManipParams.fqidForTimeOutFrames; ++ p_Manip->reassmParams.timeoutThresholdForReassmProcess = ++ reassmManipParams.timeoutThresholdForReassmProcess; ++ p_Manip->reassmParams.dataMemId = reassmManipParams.dataMemId; ++ p_Manip->reassmParams.dataLiodnOffset = reassmManipParams.dataLiodnOffset; ++#if (DPAA_VERSION == 10) ++ p_Manip->reassmParams.sgBpid = reassmManipParams.sgBpid; ++#endif /* (DPAA_VERSION == 10) */ ++#if (DPAA_VERSION >= 11) ++ if (reassmManipParams.nonConsistentSpFqid != 0) ++ { ++ p_Manip->reassmParams.ip.nonConsistentSpFqid = ++ reassmManipParams.nonConsistentSpFqid; ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ /* Creates and initializes the IP Reassembly common parameter table */ ++ CreateReassCommonTable(p_Manip); ++ ++ /* Creation of IPv4 reassembly manipulation */ ++ if ((p_Manip->reassmParams.hdr == HEADER_TYPE_IPv6) ++ || (p_Manip->reassmParams.hdr == HEADER_TYPE_IPv4)) ++ { ++ res = SetIpv4ReassmManip(p_Manip); ++ if (res != E_OK) ++ return res; ++ } ++ ++ /* Creation of IPv6 reassembly manipulation */ ++ if (p_Manip->reassmParams.hdr == HEADER_TYPE_IPv6) ++ { ++ res = SetIpv6ReassmManip(p_Manip); ++ if (res != E_OK) ++ return res; ++ } ++ ++ return E_OK; ++} ++ ++static void setIpReassmSchemeParams(t_FmPcd* p_FmPcd, ++ t_FmPcdKgSchemeParams *p_Scheme, ++ t_Handle h_CcTree, bool ipv4, ++ uint8_t groupId) ++{ ++ uint32_t j; ++ uint8_t res; ++ ++ /* Configures scheme's network environment parameters */ ++ p_Scheme->netEnvParams.numOfDistinctionUnits = 2; ++ if (ipv4) ++ res = FmPcdNetEnvGetUnitId( ++ p_FmPcd, FmPcdGetNetEnvId(p_Scheme->netEnvParams.h_NetEnv), ++ HEADER_TYPE_IPv4, FALSE, 0); ++ else ++ res = FmPcdNetEnvGetUnitId( ++ p_FmPcd, FmPcdGetNetEnvId(p_Scheme->netEnvParams.h_NetEnv), ++ HEADER_TYPE_IPv6, FALSE, 0); ++ ASSERT_COND(res != FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); ++ p_Scheme->netEnvParams.unitIds[0] = res; ++ ++ res = FmPcdNetEnvGetUnitId( ++ p_FmPcd, FmPcdGetNetEnvId(p_Scheme->netEnvParams.h_NetEnv), ++ HEADER_TYPE_USER_DEFINED_SHIM2, FALSE, 0); ++ ASSERT_COND(res != FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); ++ p_Scheme->netEnvParams.unitIds[1] = res; ++ ++ /* Configures scheme's next engine parameters*/ ++ p_Scheme->nextEngine = e_FM_PCD_CC; ++ p_Scheme->kgNextEngineParams.cc.h_CcTree = h_CcTree; ++ p_Scheme->kgNextEngineParams.cc.grpId = groupId; ++ p_Scheme->useHash = TRUE; ++ ++ /* Configures scheme's key*/ ++ if (ipv4 == TRUE) ++ { ++ p_Scheme->keyExtractAndHashParams.numOfUsedExtracts = 4; ++ p_Scheme->keyExtractAndHashParams.extractArray[0].type = ++ e_FM_PCD_EXTRACT_BY_HDR; ++ p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.type = ++ e_FM_PCD_EXTRACT_FULL_FIELD; ++ p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.hdr = ++ HEADER_TYPE_IPv4; ++ p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.extractByHdrType.fullField.ipv4 = ++ NET_HEADER_FIELD_IPv4_DST_IP; ++ p_Scheme->keyExtractAndHashParams.extractArray[1].type = ++ e_FM_PCD_EXTRACT_BY_HDR; ++ p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.type = ++ e_FM_PCD_EXTRACT_FULL_FIELD; ++ p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.hdr = ++ HEADER_TYPE_IPv4; ++ p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.extractByHdrType.fullField.ipv4 = ++ NET_HEADER_FIELD_IPv4_SRC_IP; ++ p_Scheme->keyExtractAndHashParams.extractArray[2].type = ++ e_FM_PCD_EXTRACT_BY_HDR; ++ p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.type = ++ e_FM_PCD_EXTRACT_FULL_FIELD; ++ p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.hdr = ++ HEADER_TYPE_IPv4; ++ p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.extractByHdrType.fullField.ipv4 = ++ NET_HEADER_FIELD_IPv4_PROTO; ++ p_Scheme->keyExtractAndHashParams.extractArray[3].type = ++ e_FM_PCD_EXTRACT_BY_HDR; ++ p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.hdr = ++ HEADER_TYPE_IPv4; ++ p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.type = ++ e_FM_PCD_EXTRACT_FROM_HDR; ++ p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.ignoreProtocolValidation = ++ FALSE; ++ p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.extractByHdrType.fromHdr.size = ++ 2; ++ p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.extractByHdrType.fromHdr.offset = ++ 4; ++ } ++ else /* IPv6 */ ++ { ++ p_Scheme->keyExtractAndHashParams.numOfUsedExtracts = 3; ++ p_Scheme->keyExtractAndHashParams.extractArray[0].type = ++ e_FM_PCD_EXTRACT_BY_HDR; ++ p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.type = ++ e_FM_PCD_EXTRACT_FULL_FIELD; ++ p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.hdr = ++ HEADER_TYPE_IPv6; ++ p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.extractByHdrType.fullField.ipv6 = ++ NET_HEADER_FIELD_IPv6_DST_IP; ++ p_Scheme->keyExtractAndHashParams.extractArray[1].type = ++ e_FM_PCD_EXTRACT_BY_HDR; ++ p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.type = ++ e_FM_PCD_EXTRACT_FULL_FIELD; ++ p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.hdr = ++ HEADER_TYPE_IPv6; ++ p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.extractByHdrType.fullField.ipv6 = ++ NET_HEADER_FIELD_IPv6_SRC_IP; ++ p_Scheme->keyExtractAndHashParams.extractArray[2].type = ++ e_FM_PCD_EXTRACT_BY_HDR; ++ p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.hdr = ++ HEADER_TYPE_USER_DEFINED_SHIM2; ++ p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.type = ++ e_FM_PCD_EXTRACT_FROM_HDR; ++ p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.extractByHdrType.fromHdr.size = ++ 4; ++ p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.extractByHdrType.fromHdr.offset = ++ 4; ++ p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.ignoreProtocolValidation = ++ TRUE; ++ } ++ ++ p_Scheme->keyExtractAndHashParams.privateDflt0 = 0x01020304; ++ p_Scheme->keyExtractAndHashParams.privateDflt1 = 0x11121314; ++ p_Scheme->keyExtractAndHashParams.numOfUsedDflts = ++ FM_PCD_KG_NUM_OF_DEFAULT_GROUPS; ++ for (j = 0; j < FM_PCD_KG_NUM_OF_DEFAULT_GROUPS; j++) ++ { ++ p_Scheme->keyExtractAndHashParams.dflts[j].type = ++ (e_FmPcdKgKnownFieldsDfltTypes)j; /* all types */ ++ p_Scheme->keyExtractAndHashParams.dflts[j].dfltSelect = ++ e_FM_PCD_KG_DFLT_GBL_0; ++ } ++} ++ ++static t_Error IpReassemblyStats(t_FmPcdManip *p_Manip, ++ t_FmPcdManipReassemIpStats *p_Stats) ++{ ++ ASSERT_COND(p_Manip); ++ ASSERT_COND(p_Stats); ++ ASSERT_COND(p_Manip->reassmParams.p_ReassCommonTbl); ++ ++ p_Stats->timeout = ++ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalTimeOutCounter); ++ p_Stats->rfdPoolBusy = ++ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalRfdPoolBusyCounter); ++ p_Stats->internalBufferBusy = ++ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalInternalBufferBusy); ++ p_Stats->externalBufferBusy = ++ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalExternalBufferBusy); ++ p_Stats->sgFragments = ++ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalSgFragmentCounter); ++ p_Stats->dmaSemaphoreDepletion = ++ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalDmaSemaphoreDepletionCounter); ++#if (DPAA_VERSION >= 11) ++ p_Stats->nonConsistentSp = ++ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalNCSPCounter); ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ if (p_Manip->reassmParams.ip.p_Ipv4ReassTbl) ++ { ++ p_Stats->specificHdrStatistics[0].successfullyReassembled = ++ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalSuccessfullyReasmFramesCounter); ++ p_Stats->specificHdrStatistics[0].validFragments = ++ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalValidFragmentCounter); ++ p_Stats->specificHdrStatistics[0].processedFragments = ++ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalProcessedFragCounter); ++ p_Stats->specificHdrStatistics[0].malformedFragments = ++ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalMalformdFragCounter); ++ p_Stats->specificHdrStatistics[0].autoLearnBusy = ++ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalSetBusyCounter); ++ p_Stats->specificHdrStatistics[0].discardedFragments = ++ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalDiscardedFragsCounter); ++ p_Stats->specificHdrStatistics[0].moreThan16Fragments = ++ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalMoreThan16FramesCounter); ++ } ++ if (p_Manip->reassmParams.ip.p_Ipv6ReassTbl) ++ { ++ p_Stats->specificHdrStatistics[1].successfullyReassembled = ++ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalSuccessfullyReasmFramesCounter); ++ p_Stats->specificHdrStatistics[1].validFragments = ++ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalValidFragmentCounter); ++ p_Stats->specificHdrStatistics[1].processedFragments = ++ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalProcessedFragCounter); ++ p_Stats->specificHdrStatistics[1].malformedFragments = ++ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalMalformdFragCounter); ++ p_Stats->specificHdrStatistics[1].autoLearnBusy = ++ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalSetBusyCounter); ++ p_Stats->specificHdrStatistics[1].discardedFragments = ++ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalDiscardedFragsCounter); ++ p_Stats->specificHdrStatistics[1].moreThan16Fragments = ++ GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalMoreThan16FramesCounter); ++ } ++ return E_OK; ++} ++ ++static t_Error IpFragmentationStats(t_FmPcdManip *p_Manip, ++ t_FmPcdManipFragIpStats *p_Stats) ++{ ++ t_AdOfTypeContLookup *p_Ad; ++ ++ ASSERT_COND(p_Manip); ++ ASSERT_COND(p_Stats); ++ ASSERT_COND(p_Manip->h_Ad); ++ ASSERT_COND(p_Manip->fragParams.p_Frag); ++ ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; ++ ++ p_Stats->totalFrames = GET_UINT32(p_Ad->gmask); ++ p_Stats->fragmentedFrames = GET_UINT32(p_Manip->fragParams.p_Frag->ccAdBase) ++ & 0x00ffffff; ++ p_Stats->generatedFragments = ++ GET_UINT32(p_Manip->fragParams.p_Frag->matchTblPtr); ++ ++ return E_OK; ++} ++ ++static t_Error IpFragmentation(t_FmPcdManipFragIpParams *p_ManipParams, ++ t_FmPcdManip *p_Manip) ++{ ++ uint32_t pcAndOffsetsReg = 0, ccAdBaseReg = 0, gmaskReg = 0; ++ t_FmPcd *p_FmPcd; ++#if (DPAA_VERSION == 10) ++ t_Error err = E_OK; ++#endif /* (DPAA_VERSION == 10) */ ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_ManipParams->sizeForFragmentation != 0xFFFF, ++ E_INVALID_VALUE); ++ ++ p_FmPcd = p_Manip->h_FmPcd; ++ /* Allocation of fragmentation Action Descriptor */ ++ p_Manip->fragParams.p_Frag = (t_AdOfTypeContLookup *)FM_MURAM_AllocMem( ++ p_FmPcd->h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!p_Manip->fragParams.p_Frag) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("MURAM alloc for Fragmentation table descriptor")); ++ MemSet8(p_Manip->fragParams.p_Frag, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ /* Prepare the third Ad register (pcAndOffsets)- OperationCode */ ++ pcAndOffsetsReg = (uint32_t)HMAN_OC_IP_FRAGMENTATION; ++ ++ /* Prepare the first Ad register (ccAdBase) - Don't frag action and Action descriptor type*/ ++ ccAdBaseReg = FM_PCD_AD_CONT_LOOKUP_TYPE; ++ ccAdBaseReg |= (p_ManipParams->dontFragAction ++ << FM_PCD_MANIP_IP_FRAG_DF_SHIFT); ++ ++ ++ /* Set Scatter/Gather BPid */ ++ if (p_ManipParams->sgBpidEn) ++ { ++ ccAdBaseReg |= FM_PCD_MANIP_IP_FRAG_SG_BDID_EN; ++ pcAndOffsetsReg |= ((p_ManipParams->sgBpid ++ << FM_PCD_MANIP_IP_FRAG_SG_BDID_SHIFT) ++ & FM_PCD_MANIP_IP_FRAG_SG_BDID_MASK); ++ } ++ ++ /* Prepare the first Ad register (gmask) - scratch buffer pool id and Pointer to fragment ID */ ++ gmaskReg = (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_FmPcd->ipv6FrameIdAddr)) ++ - p_FmPcd->physicalMuramBase); ++#if (DPAA_VERSION == 10) ++ gmaskReg |= p_ManipParams->scratchBpid << FM_PCD_MANIP_IP_FRAG_SCRATCH_BPID; ++#else ++ gmaskReg |= (0xFF) << FM_PCD_MANIP_IP_FRAG_SCRATCH_BPID; ++#endif /* (DPAA_VERSION == 10) */ ++ ++ /* Set all Ad registers */ ++ WRITE_UINT32(p_Manip->fragParams.p_Frag->pcAndOffsets, pcAndOffsetsReg); ++ WRITE_UINT32(p_Manip->fragParams.p_Frag->ccAdBase, ccAdBaseReg); ++ WRITE_UINT32(p_Manip->fragParams.p_Frag->gmask, gmaskReg); ++ ++ /* Saves user's fragmentation manipulation parameters */ ++ p_Manip->frag = TRUE; ++ p_Manip->sizeForFragmentation = p_ManipParams->sizeForFragmentation; ++ ++#if (DPAA_VERSION == 10) ++ p_Manip->fragParams.scratchBpid = p_ManipParams->scratchBpid; ++ ++ /* scratch buffer pool initialization */ ++ if ((err = FmPcdFragHcScratchPoolFill((t_Handle)p_FmPcd, p_ManipParams->scratchBpid)) != E_OK) ++ { ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->fragParams.p_Frag); ++ p_Manip->fragParams.p_Frag = NULL; ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++#endif /* (DPAA_VERSION == 10) */ ++ ++ return E_OK; ++} ++ ++static t_Error IPManip(t_FmPcdManip *p_Manip) ++{ ++ t_Error err = E_OK; ++ t_FmPcd *p_FmPcd; ++ t_AdOfTypeContLookup *p_Ad; ++ uint32_t tmpReg32 = 0, tmpRegNia = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); ++ p_FmPcd = p_Manip->h_FmPcd; ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; ++ ++ tmpReg32 = FM_PCD_MANIP_IP_NO_FRAGMENTATION; ++ if (p_Manip->frag == TRUE) ++ { ++ tmpRegNia = (uint32_t)(XX_VirtToPhys(p_Manip->fragParams.p_Frag) ++ - (p_FmPcd->physicalMuramBase)); ++ tmpReg32 = (uint32_t)p_Manip->sizeForFragmentation ++ << FM_PCD_MANIP_IP_MTU_SHIFT; ++ } ++ ++ tmpRegNia |= FM_PCD_AD_CONT_LOOKUP_TYPE; ++ tmpReg32 |= HMAN_OC_IP_MANIP; ++ ++#if (DPAA_VERSION >= 11) ++ tmpRegNia |= FM_PCD_MANIP_IP_CNIA; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); ++ WRITE_UINT32(p_Ad->ccAdBase, tmpRegNia); ++ WRITE_UINT32(p_Ad->gmask, 0); ++ /* Total frame counter - MUST be initialized to zero.*/ ++ ++ return err; ++} ++ ++static t_Error UpdateInitIpFrag(t_Handle h_FmPcd, t_Handle h_PcdParams, ++ t_Handle h_FmPort, t_FmPcdManip *p_Manip, ++ t_Handle h_Ad, bool validate) ++{ ++ t_FmPortGetSetCcParams fmPortGetSetCcParams; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Manip->opcode == HMAN_OC_IP_FRAGMENTATION), ++ E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); ++ ++ UNUSED(h_FmPcd); ++ UNUSED(h_Ad); ++ UNUSED(h_PcdParams); ++ UNUSED(validate); ++ UNUSED(p_Manip); ++ ++ fmPortGetSetCcParams.setCcParams.type = 0; ++ fmPortGetSetCcParams.getCcParams.type = MANIP_EXTRA_SPACE; ++ if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ if (!fmPortGetSetCcParams.getCcParams.internalBufferOffset) ++ DBG(WARNING, ("manipExtraSpace must be larger than '0'")); ++ ++ return E_OK; ++} ++ ++static t_Error IPSecManip(t_FmPcdManipParams *p_ManipParams, ++ t_FmPcdManip *p_Manip) ++{ ++ t_AdOfTypeContLookup *p_Ad; ++ t_FmPcdManipSpecialOffloadIPSecParams *p_IPSecParams; ++ t_Error err = E_OK; ++ uint32_t tmpReg32 = 0; ++ uint32_t power; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_ManipParams, E_INVALID_HANDLE); ++ ++ p_IPSecParams = &p_ManipParams->u.specialOffload.u.ipsec; ++ ++ SANITY_CHECK_RETURN_ERROR( ++ !p_IPSecParams->variableIpHdrLen || p_IPSecParams->decryption, ++ E_INVALID_VALUE); ++ SANITY_CHECK_RETURN_ERROR( ++ !p_IPSecParams->variableIpVersion || !p_IPSecParams->decryption, ++ E_INVALID_VALUE); ++ SANITY_CHECK_RETURN_ERROR( ++ !p_IPSecParams->variableIpVersion || p_IPSecParams->outerIPHdrLen, ++ E_INVALID_VALUE); ++ SANITY_CHECK_RETURN_ERROR( ++ !p_IPSecParams->arwSize || p_IPSecParams->arwAddr, ++ E_INVALID_VALUE); ++ SANITY_CHECK_RETURN_ERROR( ++ !p_IPSecParams->arwSize || p_IPSecParams->decryption, ++ E_INVALID_VALUE); ++ SANITY_CHECK_RETURN_ERROR((p_IPSecParams->arwSize % 16) == 0, E_INVALID_VALUE); ++ ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; ++ ++ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; ++ tmpReg32 |= (p_IPSecParams->decryption) ? FM_PCD_MANIP_IPSEC_DEC : 0; ++ tmpReg32 |= (p_IPSecParams->ecnCopy) ? FM_PCD_MANIP_IPSEC_ECN_EN : 0; ++ tmpReg32 |= (p_IPSecParams->dscpCopy) ? FM_PCD_MANIP_IPSEC_DSCP_EN : 0; ++ tmpReg32 |= ++ (p_IPSecParams->variableIpHdrLen) ? FM_PCD_MANIP_IPSEC_VIPL_EN : 0; ++ tmpReg32 |= ++ (p_IPSecParams->variableIpVersion) ? FM_PCD_MANIP_IPSEC_VIPV_EN : 0; ++ if (p_IPSecParams->arwSize) ++ tmpReg32 |= (uint32_t)((XX_VirtToPhys(UINT_TO_PTR(p_IPSecParams->arwAddr))-FM_MM_MURAM) ++ & (FM_MURAM_SIZE-1)); ++ WRITE_UINT32(p_Ad->ccAdBase, tmpReg32); ++ ++ tmpReg32 = 0; ++ if (p_IPSecParams->arwSize) { ++ NEXT_POWER_OF_2((p_IPSecParams->arwSize + 32), power); ++ LOG2(power, power); ++ tmpReg32 = (p_IPSecParams->arwSize | (power - 5)) << FM_PCD_MANIP_IPSEC_ARW_SIZE_SHIFT; ++ } ++ ++ if (p_ManipParams->h_NextManip) ++ tmpReg32 |= ++ (uint32_t)(XX_VirtToPhys(((t_FmPcdManip *)p_ManipParams->h_NextManip)->h_Ad)- ++ (((t_FmPcd *)p_Manip->h_FmPcd)->physicalMuramBase)) >> 4; ++ WRITE_UINT32(p_Ad->matchTblPtr, tmpReg32); ++ ++ tmpReg32 = HMAN_OC_IPSEC_MANIP; ++ tmpReg32 |= p_IPSecParams->outerIPHdrLen ++ << FM_PCD_MANIP_IPSEC_IP_HDR_LEN_SHIFT; ++ if (p_ManipParams->h_NextManip) ++ tmpReg32 |= FM_PCD_MANIP_IPSEC_NADEN; ++ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); ++ ++ return err; ++} ++ ++static t_Error SetCapwapReassmManip(t_FmPcdManip *p_Manip) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd; ++ ++ /* Allocation if CAPWAP Action descriptor */ ++ p_Manip->reassmParams.capwap.h_Ad = (t_Handle)XX_MallocSmart( ++ FM_PCD_CC_AD_ENTRY_SIZE, p_Manip->reassmParams.dataMemId, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!p_Manip->reassmParams.capwap.h_Ad) ++ { ++ ReleaseManipHandler(p_Manip, p_FmPcd); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("Allocation of CAPWAP table descriptor")); ++ } ++ ++ memset(p_Manip->reassmParams.capwap.h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ /* Fill reassembly manipulation parameter in the Reassembly Action Descriptor */ ++ return FillReassmManipParams(p_Manip, HEADER_TYPE_CAPWAP); ++} ++ ++static void setCapwapReassmSchemeParams(t_FmPcd* p_FmPcd, ++ t_FmPcdKgSchemeParams *p_Scheme, ++ t_Handle h_CcTree, uint8_t groupId) ++{ ++ uint8_t res; ++ ++ /* Configures scheme's network environment parameters */ ++ p_Scheme->netEnvParams.numOfDistinctionUnits = 1; ++ res = FmPcdNetEnvGetUnitId( ++ p_FmPcd, FmPcdGetNetEnvId(p_Scheme->netEnvParams.h_NetEnv), ++ HEADER_TYPE_USER_DEFINED_SHIM2, FALSE, 0); ++ ASSERT_COND(res != FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); ++ p_Scheme->netEnvParams.unitIds[0] = res; ++ ++ /* Configures scheme's next engine parameters*/ ++ p_Scheme->nextEngine = e_FM_PCD_CC; ++ p_Scheme->kgNextEngineParams.cc.h_CcTree = h_CcTree; ++ p_Scheme->kgNextEngineParams.cc.grpId = groupId; ++ p_Scheme->useHash = TRUE; ++ ++ /* Configures scheme's key*/ ++ p_Scheme->keyExtractAndHashParams.numOfUsedExtracts = 2; ++ p_Scheme->keyExtractAndHashParams.extractArray[0].type = ++ e_FM_PCD_EXTRACT_NON_HDR; ++ p_Scheme->keyExtractAndHashParams.extractArray[0].extractNonHdr.src = ++ e_FM_PCD_EXTRACT_FROM_PARSE_RESULT; ++ p_Scheme->keyExtractAndHashParams.extractArray[0].extractNonHdr.action = ++ e_FM_PCD_ACTION_NONE; ++ p_Scheme->keyExtractAndHashParams.extractArray[0].extractNonHdr.offset = 20; ++ p_Scheme->keyExtractAndHashParams.extractArray[0].extractNonHdr.size = 4; ++ p_Scheme->keyExtractAndHashParams.extractArray[1].type = ++ e_FM_PCD_EXTRACT_NON_HDR; ++ p_Scheme->keyExtractAndHashParams.extractArray[1].extractNonHdr.src = ++ e_FM_PCD_EXTRACT_FROM_DFLT_VALUE; ++ p_Scheme->keyExtractAndHashParams.extractArray[1].extractNonHdr.action = ++ e_FM_PCD_ACTION_NONE; ++ p_Scheme->keyExtractAndHashParams.extractArray[1].extractNonHdr.offset = 0; ++ p_Scheme->keyExtractAndHashParams.extractArray[1].extractNonHdr.size = 1; ++ ++ p_Scheme->keyExtractAndHashParams.privateDflt0 = 0x0; ++ p_Scheme->keyExtractAndHashParams.privateDflt1 = 0x0; ++ p_Scheme->keyExtractAndHashParams.numOfUsedDflts = 1; ++ p_Scheme->keyExtractAndHashParams.dflts[0].type = e_FM_PCD_KG_GENERIC_NOT_FROM_DATA; ++ p_Scheme->keyExtractAndHashParams.dflts[0].dfltSelect = e_FM_PCD_KG_DFLT_PRIVATE_0; ++} ++ ++#if (DPAA_VERSION >= 11) ++static t_Error CapwapReassemblyStats(t_FmPcdManip *p_Manip, ++ t_FmPcdManipReassemCapwapStats *p_Stats) ++{ ++ ASSERT_COND(p_Manip); ++ ASSERT_COND(p_Stats); ++ ASSERT_COND(p_Manip->reassmParams.p_ReassCommonTbl); ++ ++ p_Stats->timeout = ++ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalTimeOutCounter); ++ p_Stats->rfdPoolBusy = ++ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalRfdPoolBusyCounter); ++ p_Stats->internalBufferBusy = ++ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalInternalBufferBusy); ++ p_Stats->externalBufferBusy = ++ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalExternalBufferBusy); ++ p_Stats->sgFragments = ++ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalSgFragmentCounter); ++ p_Stats->dmaSemaphoreDepletion = ++ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalDmaSemaphoreDepletionCounter); ++ p_Stats->exceedMaxReassemblyFrameLen = ++ GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalNCSPCounter); ++ ++ p_Stats->successfullyReassembled = ++ GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalSuccessfullyReasmFramesCounter); ++ p_Stats->validFragments = ++ GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalValidFragmentCounter); ++ p_Stats->processedFragments = ++ GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalProcessedFragCounter); ++ p_Stats->malformedFragments = ++ GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalMalformdFragCounter); ++ p_Stats->autoLearnBusy = ++ GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalSetBusyCounter); ++ p_Stats->discardedFragments = ++ GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalDiscardedFragsCounter); ++ p_Stats->moreThan16Fragments = ++ GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalMoreThan16FramesCounter); ++ ++ return E_OK; ++} ++ ++static t_Error CapwapFragmentationStats(t_FmPcdManip *p_Manip, ++ t_FmPcdManipFragCapwapStats *p_Stats) ++{ ++ t_AdOfTypeContLookup *p_Ad; ++ ++ ASSERT_COND(p_Manip); ++ ASSERT_COND(p_Stats); ++ ASSERT_COND(p_Manip->h_Ad); ++ ASSERT_COND(p_Manip->fragParams.p_Frag); ++ ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; ++ ++ p_Stats->totalFrames = GET_UINT32(p_Ad->gmask); ++ ++ return E_OK; ++} ++ ++static t_Error CapwapReassembly(t_FmPcdManipReassemParams *p_ManipReassmParams, ++ t_FmPcdManip *p_Manip) ++{ ++ uint32_t maxSetNumber = 10000; ++ t_FmPcdManipReassemCapwapParams reassmManipParams = ++ p_ManipReassmParams->u.capwapReassem; ++ t_Error res; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip->h_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(((t_FmPcd *)p_Manip->h_FmPcd)->h_Hc, ++ E_INVALID_HANDLE); ++ ++ /* Check validation of user's parameter.*/ ++ if ((reassmManipParams.timeoutThresholdForReassmProcess < 1000) ++ || (reassmManipParams.timeoutThresholdForReassmProcess > 8000000)) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("timeoutThresholdForReassmProcess should be 1msec - 8sec")); ++ /* It is recommended that the total number of entries in this table (number of sets * number of ways) ++ will be twice the number of frames that are expected to be reassembled simultaneously.*/ ++ if (reassmManipParams.maxNumFramesInProcess ++ > (reassmManipParams.maxNumFramesInProcess * maxSetNumber / 2)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("maxNumFramesInProcess has to be less than (maximun set number * number of ways / 2)")); ++ ++ /* Saves user's reassembly manipulation parameters */ ++ p_Manip->reassmParams.capwap.relativeSchemeId = ++ reassmManipParams.relativeSchemeId; ++ p_Manip->reassmParams.capwap.numOfFramesPerHashEntry = ++ reassmManipParams.numOfFramesPerHashEntry; ++ p_Manip->reassmParams.capwap.maxRessembledsSize = ++ reassmManipParams.maxReassembledFrameLength; ++ p_Manip->reassmParams.maxNumFramesInProcess = ++ reassmManipParams.maxNumFramesInProcess; ++ p_Manip->reassmParams.timeOutMode = reassmManipParams.timeOutMode; ++ p_Manip->reassmParams.fqidForTimeOutFrames = ++ reassmManipParams.fqidForTimeOutFrames; ++ p_Manip->reassmParams.timeoutThresholdForReassmProcess = ++ reassmManipParams.timeoutThresholdForReassmProcess; ++ p_Manip->reassmParams.dataMemId = reassmManipParams.dataMemId; ++ p_Manip->reassmParams.dataLiodnOffset = reassmManipParams.dataLiodnOffset; ++ ++ /* Creates and initializes the Reassembly common parameter table */ ++ CreateReassCommonTable(p_Manip); ++ ++ res = SetCapwapReassmManip(p_Manip); ++ if (res != E_OK) ++ return res; ++ ++ return E_OK; ++} ++ ++static t_Error CapwapFragmentation(t_FmPcdManipFragCapwapParams *p_ManipParams, ++ t_FmPcdManip *p_Manip) ++{ ++ t_FmPcd *p_FmPcd; ++ t_AdOfTypeContLookup *p_Ad; ++ uint32_t pcAndOffsetsReg = 0, ccAdBaseReg = 0, gmaskReg = 0; ++ uint32_t tmpReg32 = 0, tmpRegNia = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_ManipParams->sizeForFragmentation != 0xFFFF, ++ E_INVALID_VALUE); ++ p_FmPcd = p_Manip->h_FmPcd; ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ ++ /* Allocation of fragmentation Action Descriptor */ ++ p_Manip->fragParams.p_Frag = (t_AdOfTypeContLookup *)FM_MURAM_AllocMem( ++ p_FmPcd->h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!p_Manip->fragParams.p_Frag) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("MURAM alloc for Fragmentation table descriptor")); ++ MemSet8(p_Manip->fragParams.p_Frag, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ /* Prepare the third Ad register (pcAndOffsets)- OperationCode */ ++ pcAndOffsetsReg = (uint32_t)HMAN_OC_CAPWAP_FRAGMENTATION; ++ ++ /* Prepare the first Ad register (ccAdBase) - Don't frag action and Action descriptor type*/ ++ ccAdBaseReg = FM_PCD_AD_CONT_LOOKUP_TYPE; ++ ccAdBaseReg |= ++ (p_ManipParams->compressModeEn) ? FM_PCD_MANIP_CAPWAP_FRAG_COMPRESS_EN : ++ 0; ++ ++ /* Set Scatter/Gather BPid */ ++ if (p_ManipParams->sgBpidEn) ++ { ++ ccAdBaseReg |= FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_EN; ++ pcAndOffsetsReg |= ((p_ManipParams->sgBpid ++ << FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_SHIFT) ++ & FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_MASK); ++ } ++ ++ /* Prepare the first Ad register (gmask) - scratch buffer pool id and Pointer to fragment ID */ ++ gmaskReg = (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_FmPcd->capwapFrameIdAddr)) ++ - p_FmPcd->physicalMuramBase); ++ gmaskReg |= (0xFF) << FM_PCD_MANIP_IP_FRAG_SCRATCH_BPID; ++ ++ /* Set all Ad registers */ ++ WRITE_UINT32(p_Manip->fragParams.p_Frag->pcAndOffsets, pcAndOffsetsReg); ++ WRITE_UINT32(p_Manip->fragParams.p_Frag->ccAdBase, ccAdBaseReg); ++ WRITE_UINT32(p_Manip->fragParams.p_Frag->gmask, gmaskReg); ++ ++ /* Saves user's fragmentation manipulation parameters */ ++ p_Manip->frag = TRUE; ++ p_Manip->sizeForFragmentation = p_ManipParams->sizeForFragmentation; ++ ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; ++ ++ tmpRegNia = (uint32_t)(XX_VirtToPhys(p_Manip->fragParams.p_Frag) ++ - (p_FmPcd->physicalMuramBase)); ++ tmpReg32 = (uint32_t)p_Manip->sizeForFragmentation ++ << FM_PCD_MANIP_CAPWAP_FRAG_CHECK_MTU_SHIFT; ++ ++ tmpRegNia |= FM_PCD_AD_CONT_LOOKUP_TYPE; ++ tmpReg32 |= HMAN_OC_CAPWAP_FRAG_CHECK; ++ ++ tmpRegNia |= FM_PCD_MANIP_CAPWAP_FRAG_CHECK_CNIA; ++ ++ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); ++ WRITE_UINT32(p_Ad->ccAdBase, tmpRegNia); ++ WRITE_UINT32(p_Ad->gmask, 0); ++ /* Total frame counter - MUST be initialized to zero.*/ ++ ++ return E_OK; ++} ++ ++static t_Error UpdateInitCapwapFrag(t_Handle h_FmPcd, t_Handle h_PcdParams, ++ t_Handle h_FmPort, t_FmPcdManip *p_Manip, ++ t_Handle h_Ad, bool validate) ++{ ++ t_FmPortGetSetCcParams fmPortGetSetCcParams; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Manip->opcode == HMAN_OC_CAPWAP_FRAGMENTATION), ++ E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); ++ ++ UNUSED(h_FmPcd); ++ UNUSED(h_Ad); ++ UNUSED(h_PcdParams); ++ UNUSED(validate); ++ UNUSED(p_Manip); ++ ++ fmPortGetSetCcParams.setCcParams.type = 0; ++ fmPortGetSetCcParams.getCcParams.type = MANIP_EXTRA_SPACE; ++ if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ if (!fmPortGetSetCcParams.getCcParams.internalBufferOffset) ++ DBG(WARNING, ("manipExtraSpace must be larger than '0'")); ++ ++ return E_OK; ++} ++ ++static t_Error CapwapManip(t_FmPcdManipParams *p_ManipParams, ++ t_FmPcdManip *p_Manip) ++{ ++ t_AdOfTypeContLookup *p_Ad; ++ t_FmPcdManipSpecialOffloadCapwapParams *p_Params; ++ t_Error err = E_OK; ++ uint32_t tmpReg32 = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_ManipParams, E_INVALID_HANDLE); ++ ++ p_Params = &p_ManipParams->u.specialOffload.u.capwap; ++ ++ p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; ++ tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; ++ tmpReg32 |= (p_Params->dtls) ? FM_PCD_MANIP_CAPWAP_DTLS : 0; ++ /* TODO - add 'qosSrc' */ ++ WRITE_UINT32(p_Ad->ccAdBase, tmpReg32); ++ ++ tmpReg32 = HMAN_OC_CAPWAP_MANIP; ++ if (p_ManipParams->h_NextManip) ++ { ++ WRITE_UINT32( ++ p_Ad->matchTblPtr, ++ (uint32_t)(XX_VirtToPhys(((t_FmPcdManip *)p_ManipParams->h_NextManip)->h_Ad)- (((t_FmPcd *)p_Manip->h_FmPcd)->physicalMuramBase)) >> 4); ++ ++ tmpReg32 |= FM_PCD_MANIP_CAPWAP_NADEN; ++ } ++ ++ WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); ++ ++ return err; ++} ++#endif /* (DPAA_VERSION >= 11) */ ++ ++static t_Handle ManipOrStatsSetNode(t_Handle h_FmPcd, t_Handle *p_Params, ++ bool stats) ++{ ++ t_FmPcdManip *p_Manip; ++ t_Error err; ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ ++ p_Manip = (t_FmPcdManip*)XX_Malloc(sizeof(t_FmPcdManip)); ++ if (!p_Manip) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory")); ++ return NULL; ++ } ++ memset(p_Manip, 0, sizeof(t_FmPcdManip)); ++ ++ p_Manip->type = ((t_FmPcdManipParams *)p_Params)->type; ++ memcpy((uint8_t*)&p_Manip->manipParams, p_Params, ++ sizeof(p_Manip->manipParams)); ++ ++ if (!stats) ++ err = CheckManipParamsAndSetType(p_Manip, ++ (t_FmPcdManipParams *)p_Params); ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++ else ++ err = CheckStatsParamsAndSetType(p_Manip, (t_FmPcdStatsParams *)p_Params); ++#else /* not (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++ else ++ { ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Statistics node!")); ++ XX_Free(p_Manip); ++ return NULL; ++ } ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++ if (err) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Invalid header manipulation type")); ++ XX_Free(p_Manip); ++ return NULL; ++ } ++ ++ if ((p_Manip->opcode != HMAN_OC_IP_REASSEMBLY) && (p_Manip->opcode != HMAN_OC_CAPWAP_REASSEMBLY)) ++ { ++ /* In Case of reassembly manipulation the reassembly action descriptor will ++ be defines later on */ ++ if (p_Manip->muramAllocate) ++ { ++ p_Manip->h_Ad = (t_Handle)FM_MURAM_AllocMem( ++ p_FmPcd->h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!p_Manip->h_Ad) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for Manipulation action descriptor")); ++ ReleaseManipHandler(p_Manip, p_FmPcd); ++ XX_Free(p_Manip); ++ return NULL; ++ } ++ ++ MemSet8(p_Manip->h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ } ++ else ++ { ++ p_Manip->h_Ad = (t_Handle)XX_Malloc( ++ FM_PCD_CC_AD_ENTRY_SIZE * sizeof(uint8_t)); ++ if (!p_Manip->h_Ad) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Allocation of Manipulation action descriptor")); ++ ReleaseManipHandler(p_Manip, p_FmPcd); ++ XX_Free(p_Manip); ++ return NULL; ++ } ++ ++ memset(p_Manip->h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE * sizeof(uint8_t)); ++ } ++ } ++ ++ p_Manip->h_FmPcd = h_FmPcd; ++ ++ return p_Manip; ++} ++ ++static void UpdateAdPtrOfNodesWhichPointsOnCrntMdfManip( ++ t_FmPcdManip *p_CrntMdfManip, t_List *h_NodesLst) ++{ ++ t_CcNodeInformation *p_CcNodeInformation; ++ t_FmPcdCcNode *p_NodePtrOnCurrentMdfManip = NULL; ++ t_List *p_Pos; ++ int i = 0; ++ t_Handle p_AdTablePtOnCrntCurrentMdfNode/*, p_AdTableNewModified*/; ++ t_CcNodeInformation ccNodeInfo; ++ ++ LIST_FOR_EACH(p_Pos, &p_CrntMdfManip->nodesLst) ++ { ++ p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); ++ p_NodePtrOnCurrentMdfManip = ++ (t_FmPcdCcNode *)p_CcNodeInformation->h_CcNode; ++ ++ ASSERT_COND(p_NodePtrOnCurrentMdfManip); ++ ++ /* Search in the previous node which exact index points on this current modified node for getting AD */ ++ for (i = 0; i < p_NodePtrOnCurrentMdfManip->numOfKeys + 1; i++) ++ { ++ if (p_NodePtrOnCurrentMdfManip->keyAndNextEngineParams[i].nextEngineParams.nextEngine ++ == e_FM_PCD_CC) ++ { ++ if (p_NodePtrOnCurrentMdfManip->keyAndNextEngineParams[i].nextEngineParams.h_Manip ++ == (t_Handle)p_CrntMdfManip) ++ { ++ if (p_NodePtrOnCurrentMdfManip->keyAndNextEngineParams[i].p_StatsObj) ++ p_AdTablePtOnCrntCurrentMdfNode = ++ p_NodePtrOnCurrentMdfManip->keyAndNextEngineParams[i].p_StatsObj->h_StatsAd; ++ else ++ p_AdTablePtOnCrntCurrentMdfNode = ++ PTR_MOVE(p_NodePtrOnCurrentMdfManip->h_AdTable, i*FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); ++ ccNodeInfo.h_CcNode = p_AdTablePtOnCrntCurrentMdfNode; ++ EnqueueNodeInfoToRelevantLst(h_NodesLst, &ccNodeInfo, NULL); ++ } ++ } ++ } ++ ++ ASSERT_COND(i != p_NodePtrOnCurrentMdfManip->numOfKeys); ++ } ++} ++ ++static void BuildHmtd(uint8_t *p_Dest, uint8_t *p_Src, uint8_t *p_Hmcd, ++ t_FmPcd *p_FmPcd) ++{ ++ t_Error err; ++ ++ /* Copy the HMTD */ ++ MemCpy8(p_Dest, (uint8_t*)p_Src, 16); ++ /* Replace the HMCT table pointer */ ++ WRITE_UINT32( ++ ((t_Hmtd *)p_Dest)->hmcdBasePtr, ++ (uint32_t)(XX_VirtToPhys(p_Hmcd) - ((t_FmPcd*)p_FmPcd)->physicalMuramBase)); ++ /* Call Host Command to replace HMTD by a new HMTD */ ++ err = FmHcPcdCcDoDynamicChange( ++ p_FmPcd->h_Hc, ++ (uint32_t)(XX_VirtToPhys(p_Src) - p_FmPcd->physicalMuramBase), ++ (uint32_t)(XX_VirtToPhys(p_Dest) - p_FmPcd->physicalMuramBase)); ++ if (err) ++ REPORT_ERROR(MINOR, err, ("Failed in dynamic manip change, continued to the rest of the owners.")); ++} ++ ++static t_Error FmPcdManipInitUpdate(t_Handle h_FmPcd, t_Handle h_PcdParams, ++ t_Handle h_FmPort, t_Handle h_Manip, ++ t_Handle h_Ad, bool validate, int level, ++ t_Handle h_FmTree) ++{ ++ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(h_Manip, E_INVALID_HANDLE); ++ ++ UNUSED(level); ++ UNUSED(h_FmTree); ++ ++ switch (p_Manip->opcode) ++ { ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++ case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX): ++ err = UpdateInitMvIntFrameHeaderFromFrameToBufferPrefix(h_FmPort, ++ p_Manip, ++ h_Ad, ++ validate); ++ break; ++ case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER): ++ if (!p_Manip->h_Frag) ++ break; ++ case (HMAN_OC_CAPWAP_FRAGMENTATION): ++ err = UpdateInitCapwapFragmentation(h_FmPort, p_Manip, h_Ad, validate, h_FmTree); ++ break; ++ case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST): ++ if (p_Manip->h_Frag) ++ err = UpdateInitCapwapReasm(h_FmPcd, h_FmPort, p_Manip, h_Ad, validate); ++ break; ++ case (HMAN_OC_CAPWAP_INDEXED_STATS): ++ err = UpdateIndxStats(h_FmPcd, h_FmPort, p_Manip); ++ break; ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++ case (HMAN_OC_IP_REASSEMBLY): ++ err = UpdateInitReasm(h_FmPcd, h_PcdParams, h_FmPort, p_Manip, h_Ad, ++ validate); ++ break; ++ case (HMAN_OC_IP_FRAGMENTATION): ++ err = UpdateInitIpFrag(h_FmPcd, h_PcdParams, h_FmPort, p_Manip, ++ h_Ad, validate); ++ break; ++#if (DPAA_VERSION >= 11) ++ case (HMAN_OC_CAPWAP_FRAGMENTATION): ++ err = UpdateInitCapwapFrag(h_FmPcd, h_PcdParams, h_FmPort, p_Manip, ++ h_Ad, validate); ++ break; ++ case (HMAN_OC_CAPWAP_REASSEMBLY): ++ err = UpdateInitReasm(h_FmPcd, h_PcdParams, h_FmPort, p_Manip, h_Ad, ++ validate); ++ break; ++#endif /* (DPAA_VERSION >= 11) */ ++ default: ++ return E_OK; ++ } ++ ++ return err; ++} ++ ++static t_Error FmPcdManipModifyUpdate(t_Handle h_Manip, t_Handle h_Ad, ++ bool validate, int level, ++ t_Handle h_FmTree) ++{ ++ ++ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; ++ t_Error err = E_OK; ++ ++ UNUSED(level); ++ ++ switch (p_Manip->opcode) ++ { ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++ case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX): ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("modify node with this type of manipulation is not suppported")); ++ case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST): ++ ++ if (p_Manip->h_Frag) ++ { ++ if (!(p_Manip->shadowUpdateParams & NUM_OF_TASKS) ++ && !(p_Manip->shadowUpdateParams & OFFSET_OF_DATA) ++ && !(p_Manip->shadowUpdateParams & OFFSET_OF_PR)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("modify node with this type of manipulation requires manipulation be updated previously in SetPcd function")); ++ } ++ break; ++ case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER): ++ if (p_Manip->h_Frag) ++ err = UpdateModifyCapwapFragmenation(p_Manip, h_Ad, validate, h_FmTree); ++ break; ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++ default: ++ return E_OK; ++ } ++ ++ return err; ++} ++ ++/*****************************************************************************/ ++/* Inter-module API routines */ ++/*****************************************************************************/ ++ ++t_Error FmPcdManipUpdate(t_Handle h_FmPcd, t_Handle h_PcdParams, ++ t_Handle h_FmPort, t_Handle h_Manip, t_Handle h_Ad, ++ bool validate, int level, t_Handle h_FmTree, ++ bool modify) ++{ ++ t_Error err; ++ ++ if (!modify) ++ err = FmPcdManipInitUpdate(h_FmPcd, h_PcdParams, h_FmPort, h_Manip, ++ h_Ad, validate, level, h_FmTree); ++ else ++ err = FmPcdManipModifyUpdate(h_Manip, h_Ad, validate, level, h_FmTree); ++ ++ return err; ++} ++ ++void FmPcdManipUpdateOwner(t_Handle h_Manip, bool add) ++{ ++ ++ uint32_t intFlags; ++ ++ intFlags = XX_LockIntrSpinlock(((t_FmPcdManip *)h_Manip)->h_Spinlock); ++ if (add) ++ ((t_FmPcdManip *)h_Manip)->owner++; ++ else ++ { ++ ASSERT_COND(((t_FmPcdManip *)h_Manip)->owner); ++ ((t_FmPcdManip *)h_Manip)->owner--; ++ } ++ XX_UnlockIntrSpinlock(((t_FmPcdManip *)h_Manip)->h_Spinlock, intFlags); ++} ++ ++t_List *FmPcdManipGetNodeLstPointedOnThisManip(t_Handle h_Manip) ++{ ++ ASSERT_COND(h_Manip); ++ return &((t_FmPcdManip *)h_Manip)->nodesLst; ++} ++ ++t_List *FmPcdManipGetSpinlock(t_Handle h_Manip) ++{ ++ ASSERT_COND(h_Manip); ++ return ((t_FmPcdManip *)h_Manip)->h_Spinlock; ++} ++ ++t_Error FmPcdManipCheckParamsForCcNextEngine( ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams, ++ uint32_t *requiredAction) ++{ ++ t_FmPcdManip *p_Manip; ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++ t_Error err = E_OK; ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))*/ ++ bool pointFromCc = TRUE; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams->h_Manip, ++ E_NULL_POINTER); ++ ++ p_Manip = (t_FmPcdManip *)(p_FmPcdCcNextEngineParams->h_Manip); ++ *requiredAction = 0; ++ ++ while (p_Manip) ++ { ++ switch (p_Manip->opcode) ++ { ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++ case (HMAN_OC_CAPWAP_INDEXED_STATS): ++ if (p_FmPcdCcNextEngineParams->nextEngine != e_FM_PCD_DONE) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("For this type of header manipulation has to be nextEngine e_FM_PCD_DONE")); ++ if (p_FmPcdCcNextEngineParams->params.enqueueParams.overrideFqid) ++ p_Manip->cnia = TRUE; ++ case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST): ++ *requiredAction = UPDATE_NIA_ENQ_WITHOUT_DMA; ++ case (HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR): ++ p_Manip->ownerTmp++; ++ break; ++ case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER): ++ if ((p_FmPcdCcNextEngineParams->nextEngine != e_FM_PCD_DONE) ++ && !p_FmPcdCcNextEngineParams->params.enqueueParams.overrideFqid) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("For this type of header manipulation has to be nextEngine e_FM_PCD_DONE with fqidForCtrlFlow FALSE")); ++ p_Manip->ownerTmp++; ++ break; ++ case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX): ++ if ((p_FmPcdCcNextEngineParams->nextEngine != e_FM_PCD_CC) ++ && (FmPcdCcGetParseCode(p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode) ++ != CC_PC_GENERIC_IC_HASH_INDEXED)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("For this type of header manipulation next engine has to be CC and action = e_FM_PCD_ACTION_INDEXED_LOOKUP")); ++ err = UpdateManipIc(p_FmPcdCcNextEngineParams->h_Manip, ++ FmPcdCcGetOffset(p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode)); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ *requiredAction = UPDATE_NIA_ENQ_WITHOUT_DMA; ++ break; ++ #endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++ case (HMAN_OC_IP_FRAGMENTATION): ++ case (HMAN_OC_IP_REASSEMBLY): ++#if (DPAA_VERSION >= 11) ++ case (HMAN_OC_CAPWAP_REASSEMBLY): ++ case (HMAN_OC_CAPWAP_FRAGMENTATION): ++#endif /* (DPAA_VERSION >= 11) */ ++ if (p_FmPcdCcNextEngineParams->nextEngine != e_FM_PCD_DONE) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("For this type of header manipulation has to be nextEngine e_FM_PCD_DONE")); ++ p_Manip->ownerTmp++; ++ break; ++ case (HMAN_OC_IPSEC_MANIP): ++#if (DPAA_VERSION >= 11) ++ case (HMAN_OC_CAPWAP_MANIP): ++#endif /* (DPAA_VERSION >= 11) */ ++ p_Manip->ownerTmp++; ++ break; ++ case (HMAN_OC): ++ if ((p_FmPcdCcNextEngineParams->nextEngine == e_FM_PCD_CC) ++ && MANIP_IS_CASCADED(p_Manip)) ++ RETURN_ERROR( ++ MINOR, ++ E_INVALID_STATE, ++ ("Can't have a cascaded manipulation when and Next Engine is CC")); ++ if (!MANIP_IS_FIRST(p_Manip) && pointFromCc) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("h_Manip is already used and may not be shared (no sharing of non-head manip nodes)")); ++ break; ++ default: ++ RETURN_ERROR( ++ MAJOR, E_INVALID_STATE, ++ ("invalid type of header manipulation for this state")); ++ } ++ p_Manip = p_Manip->h_NextManip; ++ pointFromCc = FALSE; ++ } ++ return E_OK; ++} ++ ++ ++t_Error FmPcdManipCheckParamsWithCcNodeParams(t_Handle h_Manip, ++ t_Handle h_FmPcdCcNode) ++{ ++ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(h_Manip, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(h_FmPcdCcNode, E_INVALID_HANDLE); ++ ++ switch (p_Manip->opcode) ++ { ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++ case (HMAN_OC_CAPWAP_INDEXED_STATS): ++ if (p_Manip->ownerTmp != FmPcdCcGetNumOfKeys(h_FmPcdCcNode)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("The manipulation of the type statistics flowId if exist has to be pointed by all numOfKeys")); ++ break; ++ case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST): ++ if (p_Manip->h_Frag) ++ { ++ if (p_Manip->ownerTmp != FmPcdCcGetNumOfKeys(h_FmPcdCcNode)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("The manipulation of the type remove DTLS if exist has to be pointed by all numOfKeys")); ++ err = UpdateManipIc(h_Manip, FmPcdCcGetOffset(h_FmPcdCcNode)); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ break; ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++ default: ++ break; ++ } ++ ++ return err; ++} ++ ++void FmPcdManipUpdateAdResultForCc( ++ t_Handle h_Manip, t_FmPcdCcNextEngineParams *p_CcNextEngineParams, ++ t_Handle p_Ad, t_Handle *p_AdNewPtr) ++{ ++ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; ++ ++ /* This routine creates a Manip AD and can return in "p_AdNewPtr" ++ * either the new descriptor or NULL if it writes the Manip AD into p_AD (into the match table) */ ++ ++ ASSERT_COND(p_Manip); ++ ASSERT_COND(p_CcNextEngineParams); ++ ASSERT_COND(p_Ad); ++ ASSERT_COND(p_AdNewPtr); ++ ++ FmPcdManipUpdateOwner(h_Manip, TRUE); ++ ++ /* According to "type", either build & initialize a new AD (p_AdNew) or initialize ++ * p_Ad ( the AD in the match table) and set p_AdNew = NULL. */ ++ switch (p_Manip->opcode) ++ { ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++ case (HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR): ++ case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST): ++ case (HMAN_OC_CAPWAP_INDEXED_STATS): ++ *p_AdNewPtr = p_Manip->h_Ad; ++ break; ++ case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER): ++ case (HMAN_OC_CAPWAP_FRAGMENTATION): ++ WRITE_UINT32(((t_AdOfTypeResult *)p_Ad)->fqid, ++ ((t_AdOfTypeResult *)(p_Manip->h_Ad))->fqid); ++ WRITE_UINT32(((t_AdOfTypeResult *)p_Ad)->plcrProfile, ++ ((t_AdOfTypeResult *)(p_Manip->h_Ad))->plcrProfile); ++ WRITE_UINT32(((t_AdOfTypeResult *)p_Ad)->nia, ++ ((t_AdOfTypeResult *)(p_Manip->h_Ad))->nia); ++ *p_AdNewPtr = NULL; ++ break; ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++ case (HMAN_OC_IPSEC_MANIP): ++#if (DPAA_VERSION >= 11) ++ case (HMAN_OC_CAPWAP_MANIP): ++#endif /* (DPAA_VERSION >= 11) */ ++ *p_AdNewPtr = p_Manip->h_Ad; ++ break; ++ case (HMAN_OC_IP_FRAGMENTATION): ++#if (DPAA_VERSION >= 11) ++ case (HMAN_OC_CAPWAP_FRAGMENTATION): ++#endif /* (DPAA_VERSION >= 11) */ ++ if ((p_CcNextEngineParams->nextEngine == e_FM_PCD_DONE) ++ && (!p_CcNextEngineParams->params.enqueueParams.overrideFqid)) ++ { ++ memcpy((uint8_t *)p_Ad, (uint8_t *)p_Manip->h_Ad, ++ sizeof(t_AdOfTypeContLookup)); ++#if (DPAA_VERSION >= 11) ++ WRITE_UINT32( ++ ((t_AdOfTypeContLookup *)p_Ad)->ccAdBase, ++ GET_UINT32(((t_AdOfTypeContLookup *)p_Ad)->ccAdBase) & ~FM_PCD_MANIP_IP_CNIA); ++#endif /* (DPAA_VERSION >= 11) */ ++ *p_AdNewPtr = NULL; ++ } ++ else ++ *p_AdNewPtr = p_Manip->h_Ad; ++ break; ++ case (HMAN_OC_IP_REASSEMBLY): ++ if (FmPcdManipIpReassmIsIpv6Hdr(p_Manip)) ++ { ++ if (!p_Manip->reassmParams.ip.ipv6Assigned) ++ { ++ *p_AdNewPtr = p_Manip->reassmParams.ip.h_Ipv6Ad; ++ p_Manip->reassmParams.ip.ipv6Assigned = TRUE; ++ FmPcdManipUpdateOwner(h_Manip, FALSE); ++ } ++ else ++ { ++ *p_AdNewPtr = p_Manip->reassmParams.ip.h_Ipv4Ad; ++ p_Manip->reassmParams.ip.ipv6Assigned = FALSE; ++ } ++ } ++ else ++ *p_AdNewPtr = p_Manip->reassmParams.ip.h_Ipv4Ad; ++ memcpy((uint8_t *)p_Ad, (uint8_t *)*p_AdNewPtr, ++ sizeof(t_AdOfTypeContLookup)); ++ *p_AdNewPtr = NULL; ++ break; ++#if (DPAA_VERSION >= 11) ++ case (HMAN_OC_CAPWAP_REASSEMBLY): ++ *p_AdNewPtr = p_Manip->reassmParams.capwap.h_Ad; ++ memcpy((uint8_t *)p_Ad, (uint8_t *)*p_AdNewPtr, ++ sizeof(t_AdOfTypeContLookup)); ++ *p_AdNewPtr = NULL; ++ break; ++#endif /* (DPAA_VERSION >= 11) */ ++ case (HMAN_OC): ++ /* Allocate and initialize HMTD */ ++ *p_AdNewPtr = p_Manip->h_Ad; ++ break; ++ default: ++ break; ++ } ++} ++ ++void FmPcdManipUpdateAdContLookupForCc(t_Handle h_Manip, t_Handle p_Ad, ++ t_Handle *p_AdNewPtr, ++ uint32_t adTableOffset) ++{ ++ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; ++ ++ /* This routine creates a Manip AD and can return in "p_AdNewPtr" ++ * either the new descriptor or NULL if it writes the Manip AD into p_AD (into the match table) */ ++ ASSERT_COND(p_Manip); ++ ++ FmPcdManipUpdateOwner(h_Manip, TRUE); ++ ++ switch (p_Manip->opcode) ++ { ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++ case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX): ++ WRITE_UINT32(((t_AdOfTypeContLookup *)p_Ad)->ccAdBase, ++ ((t_AdOfTypeContLookup *)(p_Manip->h_Ad))->ccAdBase); ++ WRITE_UINT32( ++ ((t_AdOfTypeContLookup *)p_Ad)->matchTblPtr, ++ ((t_AdOfTypeContLookup *)(p_Manip->h_Ad))->matchTblPtr); ++ WRITE_UINT32( ++ ((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets, ++ ((t_AdOfTypeContLookup *)(p_Manip->h_Ad))->pcAndOffsets); ++ WRITE_UINT32(((t_AdOfTypeContLookup *)p_Ad)->gmask, ++ ((t_AdOfTypeContLookup *)(p_Manip->h_Ad))->gmask); ++ WRITE_UINT32( ++ ((t_AdOfTypeContLookup *)p_Ad)->ccAdBase, ++ (GET_UINT32(((t_AdOfTypeContLookup *)p_Ad)->ccAdBase) | adTableOffset)); ++ *p_AdNewPtr = NULL; ++ break; ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++ case (HMAN_OC): ++ /* Initialize HMTD within the match table*/ ++ MemSet8(p_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ /* copy the existing HMTD *//* ask Alla - memcpy??? */ ++ memcpy((uint8_t*)p_Ad, p_Manip->h_Ad, sizeof(t_Hmtd)); ++ /* update NADEN to be "1"*/ ++ WRITE_UINT16( ++ ((t_Hmtd *)p_Ad)->cfg, ++ (uint16_t)(GET_UINT16(((t_Hmtd *)p_Ad)->cfg) | HMTD_CFG_NEXT_AD_EN)); ++ /* update next action descriptor */ ++ WRITE_UINT16(((t_Hmtd *)p_Ad)->nextAdIdx, ++ (uint16_t)(adTableOffset >> 4)); ++ /* mark that Manip's HMTD is not used */ ++ *p_AdNewPtr = NULL; ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++t_Error FmPcdManipBuildIpReassmScheme(t_FmPcd *p_FmPcd, t_Handle h_NetEnv, ++ t_Handle h_CcTree, t_Handle h_Manip, ++ bool isIpv4, uint8_t groupId) ++{ ++ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; ++ t_FmPcdKgSchemeParams *p_SchemeParams = NULL; ++ t_Handle h_Scheme; ++ ++ ASSERT_COND(p_FmPcd); ++ ASSERT_COND(h_NetEnv); ++ ASSERT_COND(p_Manip); ++ ++ /* scheme was already build, no need to check for IPv6 */ ++ if (p_Manip->reassmParams.ip.h_Ipv4Scheme) ++ return E_OK; ++ ++ if (isIpv4) { ++ h_Scheme = FmPcdKgGetSchemeHandle(p_FmPcd, p_Manip->reassmParams.ip.relativeSchemeId[0]); ++ if (h_Scheme) { ++ /* scheme was found */ ++ p_Manip->reassmParams.ip.h_Ipv4Scheme = h_Scheme; ++ return E_OK; ++ } ++ } else { ++ h_Scheme = FmPcdKgGetSchemeHandle(p_FmPcd, p_Manip->reassmParams.ip.relativeSchemeId[1]); ++ if (h_Scheme) { ++ /* scheme was found */ ++ p_Manip->reassmParams.ip.h_Ipv6Scheme = h_Scheme; ++ return E_OK; ++ } ++ } ++ ++ p_SchemeParams = XX_Malloc(sizeof(t_FmPcdKgSchemeParams)); ++ if (!p_SchemeParams) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("Memory allocation failed for scheme")); ++ ++ /* Configures the IPv4 or IPv6 scheme*/ ++ memset(p_SchemeParams, 0, sizeof(t_FmPcdKgSchemeParams)); ++ p_SchemeParams->netEnvParams.h_NetEnv = h_NetEnv; ++ p_SchemeParams->id.relativeSchemeId = (uint8_t)( ++ (isIpv4 == TRUE) ? p_Manip->reassmParams.ip.relativeSchemeId[0] : ++ p_Manip->reassmParams.ip.relativeSchemeId[1]); ++ p_SchemeParams->schemeCounter.update = TRUE; ++#if (DPAA_VERSION >= 11) ++ p_SchemeParams->alwaysDirect = TRUE; ++ p_SchemeParams->bypassFqidGeneration = TRUE; ++#else ++ p_SchemeParams->keyExtractAndHashParams.hashDistributionNumOfFqids = 1; ++ p_SchemeParams->baseFqid = 0xFFFFFF; /*TODO- baseFqid*/ ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ setIpReassmSchemeParams(p_FmPcd, p_SchemeParams, h_CcTree, isIpv4, groupId); ++ ++ /* Sets the new scheme */ ++ if (isIpv4) ++ p_Manip->reassmParams.ip.h_Ipv4Scheme = FM_PCD_KgSchemeSet( ++ p_FmPcd, p_SchemeParams); ++ else ++ p_Manip->reassmParams.ip.h_Ipv6Scheme = FM_PCD_KgSchemeSet( ++ p_FmPcd, p_SchemeParams); ++ ++ XX_Free(p_SchemeParams); ++ ++ return E_OK; ++} ++ ++t_Error FmPcdManipDeleteIpReassmSchemes(t_Handle h_Manip) ++{ ++ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; ++ ++ ASSERT_COND(p_Manip); ++ ++ if ((p_Manip->reassmParams.ip.h_Ipv4Scheme) && ++ !FmPcdKgIsSchemeHasOwners(p_Manip->reassmParams.ip.h_Ipv4Scheme)) ++ FM_PCD_KgSchemeDelete(p_Manip->reassmParams.ip.h_Ipv4Scheme); ++ ++ if ((p_Manip->reassmParams.ip.h_Ipv6Scheme) && ++ !FmPcdKgIsSchemeHasOwners(p_Manip->reassmParams.ip.h_Ipv6Scheme)) ++ FM_PCD_KgSchemeDelete(p_Manip->reassmParams.ip.h_Ipv6Scheme); ++ ++ return E_OK; ++} ++ ++bool FmPcdManipIpReassmIsIpv6Hdr(t_Handle h_Manip) ++{ ++ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; ++ ++ ASSERT_COND(p_Manip); ++ ++ return (p_Manip->reassmParams.hdr == HEADER_TYPE_IPv6); ++} ++ ++t_Error FmPcdManipBuildCapwapReassmScheme(t_FmPcd *p_FmPcd, t_Handle h_NetEnv, ++ t_Handle h_CcTree, t_Handle h_Manip, ++ uint8_t groupId) ++{ ++ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; ++ t_FmPcdKgSchemeParams *p_SchemeParams = NULL; ++ ++ ASSERT_COND(p_FmPcd); ++ ASSERT_COND(h_NetEnv); ++ ASSERT_COND(p_Manip); ++ ++ /* scheme was already build, no need to check for IPv6 */ ++ if (p_Manip->reassmParams.capwap.h_Scheme) ++ return E_OK; ++ ++ p_SchemeParams = XX_Malloc(sizeof(t_FmPcdKgSchemeParams)); ++ if (!p_SchemeParams) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ++ ("Memory allocation failed for scheme")); ++ ++ memset(p_SchemeParams, 0, sizeof(t_FmPcdKgSchemeParams)); ++ p_SchemeParams->netEnvParams.h_NetEnv = h_NetEnv; ++ p_SchemeParams->id.relativeSchemeId = ++ (uint8_t)p_Manip->reassmParams.capwap.relativeSchemeId; ++ p_SchemeParams->schemeCounter.update = TRUE; ++ p_SchemeParams->bypassFqidGeneration = TRUE; ++ ++ setCapwapReassmSchemeParams(p_FmPcd, p_SchemeParams, h_CcTree, groupId); ++ ++ p_Manip->reassmParams.capwap.h_Scheme = FM_PCD_KgSchemeSet(p_FmPcd, ++ p_SchemeParams); ++ ++ XX_Free(p_SchemeParams); ++ ++ return E_OK; ++} ++ ++t_Error FmPcdManipDeleteCapwapReassmSchemes(t_Handle h_Manip) ++{ ++ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; ++ ++ ASSERT_COND(p_Manip); ++ ++ if (p_Manip->reassmParams.capwap.h_Scheme) ++ FM_PCD_KgSchemeDelete(p_Manip->reassmParams.capwap.h_Scheme); ++ ++ return E_OK; ++} ++ ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++t_Handle FmPcdManipApplSpecificBuild(void) ++{ ++ t_FmPcdManip *p_Manip; ++ ++ p_Manip = (t_FmPcdManip*)XX_Malloc(sizeof(t_FmPcdManip)); ++ if (!p_Manip) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory")); ++ return NULL; ++ } ++ memset(p_Manip, 0, sizeof(t_FmPcdManip)); ++ ++ p_Manip->opcode = HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX; ++ p_Manip->muramAllocate = FALSE; ++ ++ p_Manip->h_Ad = (t_Handle)XX_Malloc(FM_PCD_CC_AD_ENTRY_SIZE * sizeof(uint8_t)); ++ if (!p_Manip->h_Ad) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Allocation of Manipulation action descriptor")); ++ XX_Free(p_Manip); ++ return NULL; ++ } ++ ++ memset(p_Manip->h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE * sizeof(uint8_t)); ++ ++ /*treatFdStatusFieldsAsErrors = TRUE hardcoded - assumption its always come after CAAM*/ ++ /*Application specific = type of flowId index, move internal frame header from data to IC, ++ SEC errors check*/ ++ if (MvIntFrameHeaderFromFrameToBufferPrefix(p_Manip, TRUE)!= E_OK) ++ { ++ XX_Free(p_Manip->h_Ad); ++ XX_Free(p_Manip); ++ return NULL; ++ } ++ return p_Manip; ++} ++ ++bool FmPcdManipIsCapwapApplSpecific(t_Handle h_Manip) ++{ ++ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; ++ ASSERT_COND(h_Manip); ++ ++ return (bool)((p_Manip->opcode == HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST) ? TRUE : FALSE); ++} ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++/*********************** End of inter-module routines ************************/ ++ ++/****************************************/ ++/* API Init unit functions */ ++/****************************************/ ++ ++t_Handle FM_PCD_ManipNodeSet(t_Handle h_FmPcd, ++ t_FmPcdManipParams *p_ManipParams) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ t_FmPcdManip *p_Manip; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(p_ManipParams, E_INVALID_HANDLE, NULL); ++ ++ p_Manip = ManipOrStatsSetNode(h_FmPcd, (t_Handle)p_ManipParams, FALSE); ++ if (!p_Manip) ++ return NULL; ++ ++ if (((p_Manip->opcode == HMAN_OC_IP_REASSEMBLY) ++ || (p_Manip->opcode == HMAN_OC_IP_FRAGMENTATION) ++ || (p_Manip->opcode == HMAN_OC) ++ || (p_Manip->opcode == HMAN_OC_IPSEC_MANIP) ++#if (DPAA_VERSION >= 11) ++ || (p_Manip->opcode == HMAN_OC_CAPWAP_MANIP) ++ || (p_Manip->opcode == HMAN_OC_CAPWAP_FRAGMENTATION) ++ || (p_Manip->opcode == HMAN_OC_CAPWAP_REASSEMBLY) ++#endif /* (DPAA_VERSION >= 11) */ ++ ) && (!FmPcdIsAdvancedOffloadSupported(p_FmPcd))) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Advanced-offload must be enabled")); ++ XX_Free(p_Manip); ++ return NULL; ++ } ++ p_Manip->h_Spinlock = XX_InitSpinlock(); ++ if (!p_Manip->h_Spinlock) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED HEADER MANIPULATION TYPE")); ++ ReleaseManipHandler(p_Manip, p_FmPcd); ++ XX_Free(p_Manip); ++ return NULL; ++ }INIT_LIST(&p_Manip->nodesLst); ++ ++ switch (p_Manip->opcode) ++ { ++ case (HMAN_OC_IP_REASSEMBLY): ++ /* IpReassembly */ ++ err = IpReassembly(&p_ManipParams->u.reassem, p_Manip); ++ break; ++ case (HMAN_OC_IP_FRAGMENTATION): ++ /* IpFragmentation */ ++ err = IpFragmentation(&p_ManipParams->u.frag.u.ipFrag, p_Manip); ++ if (err) ++ break; ++ err = IPManip(p_Manip); ++ break; ++ case (HMAN_OC_IPSEC_MANIP): ++ err = IPSecManip(p_ManipParams, p_Manip); ++ break; ++#if (DPAA_VERSION >= 11) ++ case (HMAN_OC_CAPWAP_REASSEMBLY): ++ /* CapwapReassembly */ ++ err = CapwapReassembly(&p_ManipParams->u.reassem, p_Manip); ++ break; ++ case (HMAN_OC_CAPWAP_FRAGMENTATION): ++ /* CapwapFragmentation */ ++ err = CapwapFragmentation(&p_ManipParams->u.frag.u.capwapFrag, ++ p_Manip); ++ break; ++ case (HMAN_OC_CAPWAP_MANIP): ++ err = CapwapManip(p_ManipParams, p_Manip); ++ break; ++#endif /* (DPAA_VERSION >= 11) */ ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++ case (HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR): ++ /* HmanType1 */ ++ err = RmvHdrTillSpecLocNOrInsrtIntFrmHdr(&p_ManipParams->u.hdr.rmvParams, p_Manip); ++ break; ++ case (HMAN_OC_CAPWAP_FRAGMENTATION): ++ err = CapwapFragmentation(&p_ManipParams->fragOrReasmParams.u.capwapFragParams, ++ p_Manip, ++ p_FmPcd, ++ p_ManipParams->fragOrReasmParams.sgBpid); ++ if (err) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED HEADER MANIPULATION TYPE")); ++ ReleaseManipHandler(p_Manip, p_FmPcd); ++ XX_Free(p_Manip); ++ return NULL; ++ } ++ if (p_Manip->insrt) ++ p_Manip->opcode = HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER; ++ case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER): ++ /* HmanType2 + if user asked only for fragmentation still need to allocate HmanType2 */ ++ err = InsrtHdrByTempl(&p_ManipParams->u.hdr.insrtParams, p_Manip, p_FmPcd); ++ break; ++ case (HMAN_OC_CAPWAP_REASSEMBLY): ++ err = CapwapReassembly(&p_ManipParams->fragOrReasmParams.u.capwapReasmParams, ++ p_Manip, ++ p_FmPcd, ++ p_ManipParams->fragOrReasmParams.sgBpid); ++ if (err) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED HEADER MANIPULATION TYPE")); ++ ReleaseManipHandler(p_Manip, p_FmPcd); ++ XX_Free(p_Manip); ++ return NULL; ++ } ++ if (p_Manip->rmv) ++ p_Manip->opcode = HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST; ++ case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST): ++ /*CAPWAP decapsulation + if user asked only for reassembly still need to allocate CAPWAP decapsulation*/ ++ err = CapwapRmvDtlsHdr(p_FmPcd, p_Manip); ++ break; ++ case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX): ++ /*Application Specific type 1*/ ++ err = MvIntFrameHeaderFromFrameToBufferPrefix(p_Manip, TRUE); ++ break; ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++ case (HMAN_OC): ++ /* New Manip */ ++ err = CreateManipActionNew(p_Manip, p_ManipParams); ++ break; ++ default: ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED HEADER MANIPULATION TYPE")); ++ ReleaseManipHandler(p_Manip, p_FmPcd); ++ XX_Free(p_Manip); ++ return NULL; ++ } ++ ++ if (err) ++ { ++ REPORT_ERROR(MAJOR, err, NO_MSG); ++ ReleaseManipHandler(p_Manip, p_FmPcd); ++ XX_Free(p_Manip); ++ return NULL; ++ } ++ ++ if (p_ManipParams->h_NextManip) ++ { ++ /* in the check routine we've verified that h_NextManip has no owners ++ * and that only supported types are allowed. */ ++ p_Manip->h_NextManip = p_ManipParams->h_NextManip; ++ /* save a "prev" pointer in h_NextManip */ ++ MANIP_SET_PREV(p_Manip->h_NextManip, p_Manip); ++ FmPcdManipUpdateOwner(p_Manip->h_NextManip, TRUE); ++ } ++ ++ return p_Manip; ++} ++ ++t_Error FM_PCD_ManipNodeReplace(t_Handle h_Manip, ++ t_FmPcdManipParams *p_ManipParams) ++{ ++ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip, *p_FirstManip; ++ t_FmPcd *p_FmPcd = (t_FmPcd *)(p_Manip->h_FmPcd); ++ t_Error err; ++ uint8_t *p_WholeHmct = NULL, *p_ShadowHmct = NULL, *p_Hmtd = NULL; ++ t_List lstOfNodeshichPointsOnCrntMdfManip, *p_Pos; ++ t_CcNodeInformation *p_CcNodeInfo; ++ SANITY_CHECK_RETURN_ERROR(h_Manip, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_ManipParams, E_INVALID_HANDLE); ++ ++ INIT_LIST(&lstOfNodeshichPointsOnCrntMdfManip); ++ ++ if ((p_ManipParams->type != e_FM_PCD_MANIP_HDR) ++ || (p_Manip->type != e_FM_PCD_MANIP_HDR)) ++ RETURN_ERROR( ++ MINOR, ++ E_NOT_SUPPORTED, ++ ("FM_PCD_ManipNodeReplace Functionality supported only for Header Manipulation.")); ++ ++ ASSERT_COND(p_Manip->opcode == HMAN_OC); ++ ASSERT_COND(p_Manip->manipParams.h_NextManip == p_Manip->h_NextManip); ++ memcpy((uint8_t*)&p_Manip->manipParams, p_ManipParams, ++ sizeof(p_Manip->manipParams)); ++ p_Manip->manipParams.h_NextManip = p_Manip->h_NextManip; ++ ++ /* The replacement of the HdrManip depends on the node type.*/ ++ /* ++ * (1) If this is an independent node, all its owners should be updated. ++ * ++ * (2) If it is the head of a cascaded chain (it does not have a "prev" but ++ * it has a "next" and it has a "cascaded" indication), the next ++ * node remains unchanged, and the behavior is as in (1). ++ * ++ * (3) If it is not the head, but a part of a cascaded chain, in can be ++ * also replaced as a regular node with just one owner. ++ * ++ * (4) If it is a part of a chain implemented as a unified table, the ++ * whole table is replaced and the owners of the head node must be updated. ++ * ++ */ ++ /* lock shadow */ ++ if (!p_FmPcd->p_CcShadow) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("CC Shadow not allocated")); ++ ++ if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) ++ return ERROR_CODE(E_BUSY); ++ ++ /* this routine creates a new manip action in the CC Shadow. */ ++ err = CreateManipActionShadow(p_Manip, p_ManipParams); ++ if (err) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ /* If the owners list is empty (these are NOT the "owners" counter, but pointers from CC) ++ * replace only HMTD and no lcok is required. Otherwise ++ * lock the whole PCD ++ * In case 4 MANIP_IS_UNIFIED_NON_FIRST(p_Manip) - Use the head node instead. */ ++ if (!FmPcdLockTryLockAll(p_FmPcd)) ++ { ++ DBG(TRACE, ("FmPcdLockTryLockAll failed")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ p_ShadowHmct = (uint8_t*)PTR_MOVE(p_FmPcd->p_CcShadow, 16); ++ ++ p_FirstManip = (t_FmPcdManip*)GetManipInfo(p_Manip, ++ e_MANIP_HANDLER_TABLE_OWNER); ++ ASSERT_COND(p_FirstManip); ++ ++ if (!LIST_IsEmpty(&p_FirstManip->nodesLst)) ++ UpdateAdPtrOfNodesWhichPointsOnCrntMdfManip( ++ p_FirstManip, &lstOfNodeshichPointsOnCrntMdfManip); ++ ++ p_Hmtd = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMTD); ++ ASSERT_COND(p_Hmtd); ++ BuildHmtd(p_FmPcd->p_CcShadow, (uint8_t *)p_Hmtd, p_ShadowHmct, ++ ((t_FmPcd*)(p_Manip->h_FmPcd))); ++ ++ LIST_FOR_EACH(p_Pos, &lstOfNodeshichPointsOnCrntMdfManip) ++ { ++ p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos); ++ BuildHmtd(p_FmPcd->p_CcShadow, (uint8_t *)p_CcNodeInfo->h_CcNode, ++ p_ShadowHmct, ((t_FmPcd*)(p_Manip->h_FmPcd))); ++ } ++ ++ p_WholeHmct = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMCT); ++ ASSERT_COND(p_WholeHmct); ++ ++ /* re-build the HMCT n the original location */ ++ err = CreateManipActionBackToOrig(p_Manip, p_ManipParams); ++ if (err) ++ { ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ p_Hmtd = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMTD); ++ ASSERT_COND(p_Hmtd); ++ BuildHmtd(p_FmPcd->p_CcShadow, (uint8_t *)p_Hmtd, p_WholeHmct, ++ ((t_FmPcd*)p_Manip->h_FmPcd)); ++ ++ /* If LIST > 0, create a list of p_Ad's that point to the HMCT. Join also t_HMTD to this list. ++ * For each p_Hmct (from list+fixed): ++ * call Host Command to replace HMTD by a new one */LIST_FOR_EACH(p_Pos, &lstOfNodeshichPointsOnCrntMdfManip) ++ { ++ p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos); ++ BuildHmtd(p_FmPcd->p_CcShadow, (uint8_t *)p_CcNodeInfo->h_CcNode, ++ p_WholeHmct, ((t_FmPcd*)(p_Manip->h_FmPcd))); ++ } ++ ++ ++ ReleaseLst(&lstOfNodeshichPointsOnCrntMdfManip); ++ ++ FmPcdLockUnlockAll(p_FmPcd); ++ ++ /* unlock shadow */ ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_ManipNodeDelete(t_Handle h_ManipNode) ++{ ++ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_ManipNode; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); ++ ++ if (p_Manip->owner) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("This manipulation node not be removed because this node is occupied, first - unbind this node ")); ++ ++ if (p_Manip->h_NextManip) ++ { ++ MANIP_SET_PREV(p_Manip->h_NextManip, NULL); ++ FmPcdManipUpdateOwner(p_Manip->h_NextManip, FALSE); ++ } ++ ++ if (p_Manip->p_Hmct ++ && (MANIP_IS_UNIFIED_FIRST(p_Manip) || !MANIP_IS_UNIFIED(p_Manip))) ++ FM_MURAM_FreeMem(((t_FmPcd *)p_Manip->h_FmPcd)->h_FmMuram, ++ p_Manip->p_Hmct); ++ ++ if (p_Manip->h_Spinlock) ++ { ++ XX_FreeSpinlock(p_Manip->h_Spinlock); ++ p_Manip->h_Spinlock = NULL; ++ } ++ ++ ReleaseManipHandler(p_Manip, p_Manip->h_FmPcd); ++ ++ XX_Free(h_ManipNode); ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_ManipGetStatistics(t_Handle h_ManipNode, ++ t_FmPcdManipStats *p_FmPcdManipStats) ++{ ++ t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_ManipNode; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcdManipStats, E_NULL_POINTER); ++ ++ switch (p_Manip->opcode) ++ { ++ case (HMAN_OC_IP_REASSEMBLY): ++ return IpReassemblyStats(p_Manip, ++ &p_FmPcdManipStats->u.reassem.u.ipReassem); ++ case (HMAN_OC_IP_FRAGMENTATION): ++ return IpFragmentationStats(p_Manip, ++ &p_FmPcdManipStats->u.frag.u.ipFrag); ++#if (DPAA_VERSION >= 11) ++ case (HMAN_OC_CAPWAP_REASSEMBLY): ++ return CapwapReassemblyStats( ++ p_Manip, &p_FmPcdManipStats->u.reassem.u.capwapReassem); ++ case (HMAN_OC_CAPWAP_FRAGMENTATION): ++ return CapwapFragmentationStats( ++ p_Manip, &p_FmPcdManipStats->u.frag.u.capwapFrag); ++#endif /* (DPAA_VERSION >= 11) */ ++ default: ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ++ ("no statistics to this type of manip")); ++ } ++ ++ return E_OK; ++} ++ ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++t_Handle FM_PCD_StatisticsSetNode(t_Handle h_FmPcd, t_FmPcdStatsParams *p_StatsParams) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ t_FmPcdManip *p_Manip; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmPcd,E_INVALID_HANDLE,NULL); ++ SANITY_CHECK_RETURN_VALUE(p_StatsParams,E_INVALID_HANDLE,NULL); ++ ++ p_Manip = ManipOrStatsSetNode(h_FmPcd, (t_Handle)p_StatsParams, TRUE); ++ if (!p_Manip) ++ return NULL; ++ ++ switch (p_Manip->opcode) ++ { ++ case (HMAN_OC_CAPWAP_INDEXED_STATS): ++ /* Indexed statistics */ ++ err = IndxStats(p_StatsParams, p_Manip, p_FmPcd); ++ break; ++ default: ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED Statistics type")); ++ ReleaseManipHandler(p_Manip, p_FmPcd); ++ XX_Free(p_Manip); ++ return NULL; ++ } ++ ++ if (err) ++ { ++ REPORT_ERROR(MAJOR, err, NO_MSG); ++ ReleaseManipHandler(p_Manip, p_FmPcd); ++ XX_Free(p_Manip); ++ return NULL; ++ } ++ ++ return p_Manip; ++} ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.h +new file mode 100644 +index 00000000..853bb834 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.h +@@ -0,0 +1,555 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_manip.h ++ ++ @Description FM PCD manip... ++*//***************************************************************************/ ++#ifndef __FM_MANIP_H ++#define __FM_MANIP_H ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "list_ext.h" ++ ++#include "fm_cc.h" ++ ++ ++/***********************************************************************/ ++/* Header manipulations defines */ ++/***********************************************************************/ ++ ++#define NUM_OF_SCRATCH_POOL_BUFFERS 1000 /*TODO - Change it!!*/ ++ ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++#define HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR 0x2e ++#define HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER 0x31 ++#define HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX 0x2f ++#define HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST 0x30 ++#define HMAN_OC_CAPWAP_REASSEMBLY 0x11 /* dummy */ ++#define HMAN_OC_CAPWAP_INDEXED_STATS 0x32 /* dummy */ ++#define HMAN_OC_CAPWAP_FRAGMENTATION 0x33 ++#else ++#define HMAN_OC_CAPWAP_MANIP 0x2F ++#define HMAN_OC_CAPWAP_FRAG_CHECK 0x2E ++#define HMAN_OC_CAPWAP_FRAGMENTATION 0x33 ++#define HMAN_OC_CAPWAP_REASSEMBLY 0x30 ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++#define HMAN_OC_IP_MANIP 0x34 ++#define HMAN_OC_IP_FRAGMENTATION 0x74 ++#define HMAN_OC_IP_REASSEMBLY 0xB4 ++#define HMAN_OC_IPSEC_MANIP 0xF4 ++#define HMAN_OC 0x35 ++ ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++#define HMAN_RMV_HDR 0x80000000 ++#define HMAN_INSRT_INT_FRM_HDR 0x40000000 ++ ++#define UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP 6 ++#define UDP_CHECKSUM_FIELD_SIZE 2 ++#define UDP_LENGTH_FIELD_OFFSET_FROM_UDP 4 ++ ++#define IPv4_DSCECN_FIELD_OFFSET_FROM_IP 1 ++#define IPv4_TOTALLENGTH_FIELD_OFFSET_FROM_IP 2 ++#define IPv4_HDRCHECKSUM_FIELD_OFFSET_FROM_IP 10 ++#define VLAN_TAG_FIELD_OFFSET_FROM_ETH 12 ++#define IPv4_ID_FIELD_OFFSET_FROM_IP 4 ++ ++#define IPv6_PAYLOAD_LENGTH_OFFSET_FROM_IP 4 ++#define IPv6_NEXT_HEADER_OFFSET_FROM_IP 6 ++ ++#define FM_PCD_MANIP_CAPWAP_REASM_TABLE_SIZE 0x80 ++#define FM_PCD_MANIP_CAPWAP_REASM_TABLE_ALIGN 8 ++#define FM_PCD_MANIP_CAPWAP_REASM_RFD_SIZE 32 ++#define FM_PCD_MANIP_CAPWAP_REASM_AUTO_LEARNING_HASH_ENTRY_SIZE 4 ++#define FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_ENTRY_SIZE 8 ++ ++ ++#define FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_BETWEEN_FRAMES 0x40000000 ++#define FM_PCD_MANIP_CAPWAP_REASM_HALT_ON_DUPLICATE_FRAG 0x10000000 ++#define FM_PCD_MANIP_CAPWAP_REASM_AUTOMATIC_LEARNIN_HASH_8_WAYS 0x08000000 ++#define FM_PCD_MANIP_CAPWAP_REASM_PR_COPY 0x00800000 ++ ++#define FM_PCD_MANIP_CAPWAP_FRAG_COMPR_OPTION_FIELD_EN 0x80000000 ++ ++#define FM_PCD_MANIP_INDEXED_STATS_ENTRY_SIZE 4 ++#define FM_PCD_MANIP_INDEXED_STATS_CNIA 0x20000000 ++#define FM_PCD_MANIP_INDEXED_STATS_DPD 0x10000000 ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++ ++#if (DPAA_VERSION >= 11) ++#define FM_PCD_MANIP_CAPWAP_DTLS 0x00040000 ++#define FM_PCD_MANIP_CAPWAP_NADEN 0x20000000 ++ ++#define FM_PCD_MANIP_CAPWAP_FRAG_CHECK_MTU_SHIFT 16 ++#define FM_PCD_MANIP_CAPWAP_FRAG_CHECK_NO_FRAGMENTATION 0xFFFF0000 ++#define FM_PCD_MANIP_CAPWAP_FRAG_CHECK_CNIA 0x20000000 ++ ++#define FM_PCD_MANIP_CAPWAP_FRAG_COMPRESS_EN 0x04000000 ++#define FM_PCD_MANIP_CAPWAP_FRAG_SCRATCH_BPID 24 ++#define FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_EN 0x08000000 ++#define FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_MASK 0xFF000000 ++#define FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_SHIFT 24 ++#endif /* (DPAA_VERSION >= 11) */ ++ ++#define FM_PCD_MANIP_REASM_TABLE_SIZE 0x40 ++#define FM_PCD_MANIP_REASM_TABLE_ALIGN 8 ++ ++#define FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_SIZE 64 ++#define FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_ALIGN 8 ++#define FM_PCD_MANIP_REASM_TIME_OUT_BETWEEN_FRAMES 0x80000000 ++#define FM_PCD_MANIP_REASM_COUPLING_ENABLE 0x40000000 ++#define FM_PCD_MANIP_REASM_COUPLING_MASK 0xFF000000 ++#define FM_PCD_MANIP_REASM_COUPLING_SHIFT 24 ++#define FM_PCD_MANIP_REASM_LIODN_MASK 0x0000003F ++#define FM_PCD_MANIP_REASM_LIODN_SHIFT 56 ++#define FM_PCD_MANIP_REASM_ELIODN_MASK 0x000003c0 ++#define FM_PCD_MANIP_REASM_ELIODN_SHIFT 38 ++#define FM_PCD_MANIP_REASM_COMMON_INT_BUFFER_IDX_MASK 0x000000FF ++#define FM_PCD_MANIP_REASM_COMMON_INT_BUFFER_IDX_SHIFT 24 ++#define FM_PCD_MANIP_REASM_TIMEOUT_THREAD_THRESH 1024 ++ ++#define FM_PCD_MANIP_IP_MTU_SHIFT 16 ++#define FM_PCD_MANIP_IP_NO_FRAGMENTATION 0xFFFF0000 ++#define FM_PCD_MANIP_IP_CNIA 0x20000000 ++ ++#define FM_PCD_MANIP_IP_FRAG_DF_SHIFT 28 ++#define FM_PCD_MANIP_IP_FRAG_SCRATCH_BPID 24 ++#define FM_PCD_MANIP_IP_FRAG_SG_BDID_EN 0x08000000 ++#define FM_PCD_MANIP_IP_FRAG_SG_BDID_MASK 0xFF000000 ++#define FM_PCD_MANIP_IP_FRAG_SG_BDID_SHIFT 24 ++ ++#define FM_PCD_MANIP_IPSEC_DEC 0x10000000 ++#define FM_PCD_MANIP_IPSEC_VIPV_EN 0x08000000 ++#define FM_PCD_MANIP_IPSEC_ECN_EN 0x04000000 ++#define FM_PCD_MANIP_IPSEC_DSCP_EN 0x02000000 ++#define FM_PCD_MANIP_IPSEC_VIPL_EN 0x01000000 ++#define FM_PCD_MANIP_IPSEC_NADEN 0x20000000 ++ ++#define FM_PCD_MANIP_IPSEC_IP_HDR_LEN_MASK 0x00FF0000 ++#define FM_PCD_MANIP_IPSEC_IP_HDR_LEN_SHIFT 16 ++ ++#define FM_PCD_MANIP_IPSEC_ARW_SIZE_MASK 0xFFFF0000 ++#define FM_PCD_MANIP_IPSEC_ARW_SIZE_SHIFT 16 ++ ++#define e_FM_MANIP_IP_INDX 1 ++ ++#define HMCD_OPCODE_GENERIC_RMV 0x01 ++#define HMCD_OPCODE_GENERIC_INSRT 0x02 ++#define HMCD_OPCODE_GENERIC_REPLACE 0x05 ++#define HMCD_OPCODE_L2_RMV 0x08 ++#define HMCD_OPCODE_L2_INSRT 0x09 ++#define HMCD_OPCODE_VLAN_PRI_UPDATE 0x0B ++#define HMCD_OPCODE_IPV4_UPDATE 0x0C ++#define HMCD_OPCODE_IPV6_UPDATE 0x10 ++#define HMCD_OPCODE_TCP_UDP_UPDATE 0x0E ++#define HMCD_OPCODE_TCP_UDP_CHECKSUM 0x14 ++#define HMCD_OPCODE_REPLACE_IP 0x12 ++#define HMCD_OPCODE_RMV_TILL 0x15 ++#define HMCD_OPCODE_UDP_INSRT 0x16 ++#define HMCD_OPCODE_IP_INSRT 0x17 ++#define HMCD_OPCODE_CAPWAP_RMV 0x18 ++#define HMCD_OPCODE_CAPWAP_INSRT 0x18 ++#define HMCD_OPCODE_GEN_FIELD_REPLACE 0x19 ++ ++#define HMCD_LAST 0x00800000 ++ ++#define HMCD_DSCP_VALUES 64 ++ ++#define HMCD_BASIC_SIZE 4 ++#define HMCD_PTR_SIZE 4 ++#define HMCD_PARAM_SIZE 4 ++#define HMCD_IPV4_ADDR_SIZE 4 ++#define HMCD_IPV6_ADDR_SIZE 0x10 ++#define HMCD_L4_HDR_SIZE 8 ++ ++#define HMCD_CAPWAP_INSRT 0x00010000 ++#define HMCD_INSRT_UDP_LITE 0x00010000 ++#define HMCD_IP_ID_MASK 0x0000FFFF ++#define HMCD_IP_SIZE_MASK 0x0000FF00 ++#define HMCD_IP_SIZE_SHIFT 8 ++#define HMCD_IP_LAST_PID_MASK 0x000000FF ++#define HMCD_IP_OR_QOS 0x00010000 ++#define HMCD_IP_L4_CS_CALC 0x00040000 ++#define HMCD_IP_DF_MODE 0x00400000 ++ ++ ++#define HMCD_OC_SHIFT 24 ++ ++#define HMCD_RMV_OFFSET_SHIFT 0 ++#define HMCD_RMV_SIZE_SHIFT 8 ++ ++#define HMCD_INSRT_OFFSET_SHIFT 0 ++#define HMCD_INSRT_SIZE_SHIFT 8 ++ ++#define HMTD_CFG_TYPE 0x4000 ++#define HMTD_CFG_EXT_HMCT 0x0080 ++#define HMTD_CFG_PRS_AFTER_HM 0x0040 ++#define HMTD_CFG_NEXT_AD_EN 0x0020 ++ ++#define HMCD_RMV_L2_ETHERNET 0 ++#define HMCD_RMV_L2_STACKED_QTAGS 1 ++#define HMCD_RMV_L2_ETHERNET_AND_MPLS 2 ++#define HMCD_RMV_L2_MPLS 3 ++#define HMCD_RMV_L2_PPPOE 4 ++ ++#define HMCD_INSRT_L2_MPLS 0 ++#define HMCD_INSRT_N_UPDATE_L2_MPLS 1 ++#define HMCD_INSRT_L2_PPPOE 2 ++#define HMCD_INSRT_L2_SIZE_SHIFT 24 ++ ++#define HMCD_L2_MODE_SHIFT 16 ++ ++#define HMCD_VLAN_PRI_REP_MODE_SHIFT 16 ++#define HMCD_VLAN_PRI_UPDATE 0 ++#define HMCD_VLAN_PRI_UPDATE_DSCP_TO_VPRI 1 ++ ++#define HMCD_IPV4_UPDATE_TTL 0x00000001 ++#define HMCD_IPV4_UPDATE_TOS 0x00000002 ++#define HMCD_IPV4_UPDATE_DST 0x00000020 ++#define HMCD_IPV4_UPDATE_SRC 0x00000040 ++#define HMCD_IPV4_UPDATE_ID 0x00000080 ++#define HMCD_IPV4_UPDATE_TOS_SHIFT 8 ++ ++#define HMCD_IPV6_UPDATE_HL 0x00000001 ++#define HMCD_IPV6_UPDATE_TC 0x00000002 ++#define HMCD_IPV6_UPDATE_DST 0x00000040 ++#define HMCD_IPV6_UPDATE_SRC 0x00000080 ++#define HMCD_IPV6_UPDATE_TC_SHIFT 8 ++ ++#define HMCD_TCP_UDP_UPDATE_DST 0x00004000 ++#define HMCD_TCP_UDP_UPDATE_SRC 0x00008000 ++#define HMCD_TCP_UDP_UPDATE_SRC_SHIFT 16 ++ ++#define HMCD_IP_REPLACE_REPLACE_IPV4 0x00000000 ++#define HMCD_IP_REPLACE_REPLACE_IPV6 0x00010000 ++#define HMCD_IP_REPLACE_TTL_HL 0x00200000 ++#define HMCD_IP_REPLACE_ID 0x00400000 ++ ++#define HMCD_IP_REPLACE_L3HDRSIZE_SHIFT 24 ++ ++#define HMCD_GEN_FIELD_SIZE_SHIFT 16 ++#define HMCD_GEN_FIELD_SRC_OFF_SHIFT 8 ++#define HMCD_GEN_FIELD_DST_OFF_SHIFT 0 ++#define HMCD_GEN_FIELD_MASK_EN 0x00400000 ++ ++#define HMCD_GEN_FIELD_MASK_OFF_SHIFT 16 ++#define HMCD_GEN_FIELD_MASK_SHIFT 24 ++ ++#define DSCP_TO_VLAN_TABLE_SIZE 32 ++ ++#define MANIP_GET_HMCT_SIZE(h_Manip) (((t_FmPcdManip *)h_Manip)->tableSize) ++#define MANIP_GET_DATA_SIZE(h_Manip) (((t_FmPcdManip *)h_Manip)->dataSize) ++ ++#define MANIP_GET_HMCT_PTR(h_Manip) (((t_FmPcdManip *)h_Manip)->p_Hmct) ++#define MANIP_GET_DATA_PTR(h_Manip) (((t_FmPcdManip *)h_Manip)->p_Data) ++ ++#define MANIP_SET_HMCT_PTR(h_Manip, h_NewPtr) (((t_FmPcdManip *)h_Manip)->p_Hmct = h_NewPtr) ++#define MANIP_SET_DATA_PTR(h_Manip, h_NewPtr) (((t_FmPcdManip *)h_Manip)->p_Data = h_NewPtr) ++ ++#define MANIP_GET_HMTD_PTR(h_Manip) (((t_FmPcdManip *)h_Manip)->h_Ad) ++#define MANIP_DONT_REPARSE(h_Manip) (((t_FmPcdManip *)h_Manip)->dontParseAfterManip) ++#define MANIP_SET_PREV(h_Manip, h_Prev) (((t_FmPcdManip *)h_Manip)->h_PrevManip = h_Prev) ++#define MANIP_GET_OWNERS(h_Manip) (((t_FmPcdManip *)h_Manip)->owner) ++#define MANIP_GET_TYPE(h_Manip) (((t_FmPcdManip *)h_Manip)->type) ++#define MANIP_SET_UNIFIED_TBL_PTR_INDICATION(h_Manip) (((t_FmPcdManip *)h_Manip)->unifiedTablePtr = TRUE) ++#define MANIP_GET_MURAM(h_Manip) (((t_FmPcd *)((t_FmPcdManip *)h_Manip)->h_FmPcd)->h_FmMuram) ++#define MANIP_FREE_HMTD(h_Manip) \ ++ {if (((t_FmPcdManip *)h_Manip)->muramAllocate) \ ++ FM_MURAM_FreeMem(((t_FmPcd *)((t_FmPcdManip *)h_Manip)->h_FmPcd)->h_FmMuram, ((t_FmPcdManip *)h_Manip)->h_Ad);\ ++ else \ ++ XX_Free(((t_FmPcdManip *)h_Manip)->h_Ad); \ ++ ((t_FmPcdManip *)h_Manip)->h_Ad = NULL; \ ++ } ++/* position regarding Manip SW structure */ ++#define MANIP_IS_FIRST(h_Manip) (!(((t_FmPcdManip *)h_Manip)->h_PrevManip)) ++#define MANIP_IS_CASCADED(h_Manip) (((t_FmPcdManip *)h_Manip)->cascaded) ++#define MANIP_IS_UNIFIED(h_Manip) (!(((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_NONE)) ++#define MANIP_IS_UNIFIED_NON_FIRST(h_Manip) ((((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_MID) || \ ++ (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_LAST)) ++#define MANIP_IS_UNIFIED_NON_LAST(h_Manip) ((((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_FIRST) ||\ ++ (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_MID)) ++#define MANIP_IS_UNIFIED_FIRST(h_Manip) (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_FIRST) ++#define MANIP_IS_UNIFIED_LAST(h_Manip) (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_LAST) ++ ++#define MANIP_UPDATE_UNIFIED_POSITION(h_Manip) (((t_FmPcdManip *)h_Manip)->unifiedPosition = \ ++ (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_NONE)? \ ++ e_MANIP_UNIFIED_LAST : e_MANIP_UNIFIED_MID) ++ ++typedef enum e_ManipUnifiedPosition { ++ e_MANIP_UNIFIED_NONE = 0, ++ e_MANIP_UNIFIED_FIRST, ++ e_MANIP_UNIFIED_MID, ++ e_MANIP_UNIFIED_LAST ++} e_ManipUnifiedPosition; ++ ++typedef enum e_ManipInfo { ++ e_MANIP_HMTD, ++ e_MANIP_HMCT, ++ e_MANIP_HANDLER_TABLE_OWNER ++}e_ManipInfo; ++/***********************************************************************/ ++/* Memory map */ ++/***********************************************************************/ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(push,1) ++#endif /* defined(__MWERKS__) && ... */ ++ ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++typedef struct t_CapwapReasmPram { ++ volatile uint32_t mode; ++ volatile uint32_t autoLearnHashTblPtr; ++ volatile uint32_t intStatsTblPtr; ++ volatile uint32_t reasmFrmDescPoolTblPtr; ++ volatile uint32_t reasmFrmDescIndexPoolTblPtr; ++ volatile uint32_t timeOutTblPtr; ++ volatile uint32_t bufferPoolIdAndRisc1SetIndexes; ++ volatile uint32_t risc23SetIndexes; ++ volatile uint32_t risc4SetIndexesAndExtendedStatsTblPtr; ++ volatile uint32_t extendedStatsTblPtr; ++ volatile uint32_t expirationDelay; ++ volatile uint32_t totalProcessedFragCounter; ++ volatile uint32_t totalUnsuccessfulReasmFramesCounter; ++ volatile uint32_t totalDuplicatedFragCounter; ++ volatile uint32_t totalMalformdFragCounter; ++ volatile uint32_t totalTimeOutCounter; ++ volatile uint32_t totalSetBusyCounter; ++ volatile uint32_t totalRfdPoolBusyCounter; ++ volatile uint32_t totalDiscardedFragsCounter; ++ volatile uint32_t totalMoreThan16FramesCounter; ++ volatile uint32_t internalBufferBusy; ++ volatile uint32_t externalBufferBusy; ++ volatile uint32_t reserved1[4]; ++} t_CapwapReasmPram; ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++ ++typedef _Packed struct t_ReassTbl { ++ volatile uint16_t waysNumAndSetSize; ++ volatile uint16_t autoLearnHashKeyMask; ++ volatile uint32_t reassCommonPrmTblPtr; ++ volatile uint32_t liodnAlAndAutoLearnHashTblPtrHi; ++ volatile uint32_t autoLearnHashTblPtrLow; ++ volatile uint32_t liodnSlAndAutoLearnSetLockTblPtrHi; ++ volatile uint32_t autoLearnSetLockTblPtrLow; ++ volatile uint16_t minFragSize; /* Not relevant for CAPWAP*/ ++ volatile uint16_t maxReassemblySize; /* Only relevant for CAPWAP*/ ++ volatile uint32_t totalSuccessfullyReasmFramesCounter; ++ volatile uint32_t totalValidFragmentCounter; ++ volatile uint32_t totalProcessedFragCounter; ++ volatile uint32_t totalMalformdFragCounter; ++ volatile uint32_t totalSetBusyCounter; ++ volatile uint32_t totalDiscardedFragsCounter; ++ volatile uint32_t totalMoreThan16FramesCounter; ++ volatile uint32_t reserved2[2]; ++} _PackedType t_ReassTbl; ++ ++typedef struct t_ReassCommonTbl { ++ volatile uint32_t timeoutModeAndFqid; ++ volatile uint32_t reassFrmDescIndexPoolTblPtr; ++ volatile uint32_t liodnAndReassFrmDescPoolPtrHi; ++ volatile uint32_t reassFrmDescPoolPtrLow; ++ volatile uint32_t timeOutTblPtr; ++ volatile uint32_t expirationDelay; ++ volatile uint32_t internalBufferManagement; ++ volatile uint32_t reserved2; ++ volatile uint32_t totalTimeOutCounter; ++ volatile uint32_t totalRfdPoolBusyCounter; ++ volatile uint32_t totalInternalBufferBusy; ++ volatile uint32_t totalExternalBufferBusy; ++ volatile uint32_t totalSgFragmentCounter; ++ volatile uint32_t totalDmaSemaphoreDepletionCounter; ++ volatile uint32_t totalNCSPCounter; ++ volatile uint32_t discardMask; ++} t_ReassCommonTbl; ++ ++typedef _Packed struct t_Hmtd { ++ volatile uint16_t cfg; ++ volatile uint8_t eliodnOffset; ++ volatile uint8_t extHmcdBasePtrHi; ++ volatile uint32_t hmcdBasePtr; ++ volatile uint16_t nextAdIdx; ++ volatile uint8_t res1; ++ volatile uint8_t opCode; ++ volatile uint32_t res2; ++} _PackedType t_Hmtd; ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(pop) ++#endif /* defined(__MWERKS__) && ... */ ++ ++ ++/***********************************************************************/ ++/* Driver's internal structures */ ++/***********************************************************************/ ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++typedef struct ++{ ++ t_Handle p_AutoLearnHashTbl; ++ t_Handle p_ReassmFrmDescrPoolTbl; ++ t_Handle p_ReassmFrmDescrIndxPoolTbl; ++ t_Handle p_TimeOutTbl; ++ uint16_t maxNumFramesInProcess; ++ uint8_t numOfTasks; ++ //uint8_t poolId; ++ uint8_t prOffset; ++ uint16_t dataOffset; ++ uint8_t sgBpid; ++ uint8_t hwPortId; ++ uint32_t fqidForTimeOutFrames; ++ uint32_t timeoutRoutineRequestTime; ++ uint32_t bitFor1Micro; ++} t_CapwapFragParams; ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++ ++typedef struct ++{ ++ t_AdOfTypeContLookup *p_Frag; ++#if (DPAA_VERSION == 10) ++ uint8_t scratchBpid; ++#endif /* (DPAA_VERSION == 10) */ ++} t_FragParams; ++ ++typedef struct t_ReassmParams ++{ ++ e_NetHeaderType hdr; /* Header selection */ ++ t_ReassCommonTbl *p_ReassCommonTbl; ++ uintptr_t reassFrmDescrIndxPoolTblAddr; ++ uintptr_t reassFrmDescrPoolTblAddr; ++ uintptr_t timeOutTblAddr; ++ uintptr_t internalBufferPoolManagementIndexAddr; ++ uintptr_t internalBufferPoolAddr; ++ uint32_t maxNumFramesInProcess; ++ uint8_t sgBpid; ++ uint8_t dataMemId; ++ uint16_t dataLiodnOffset; ++ uint32_t fqidForTimeOutFrames; ++ e_FmPcdManipReassemTimeOutMode timeOutMode; ++ uint32_t timeoutThresholdForReassmProcess; ++ union { ++ struct { ++ t_Handle h_Ipv4Ad; ++ t_Handle h_Ipv6Ad; ++ bool ipv6Assigned; ++ t_ReassTbl *p_Ipv4ReassTbl; ++ t_ReassTbl *p_Ipv6ReassTbl; ++ uintptr_t ipv4AutoLearnHashTblAddr; ++ uintptr_t ipv6AutoLearnHashTblAddr; ++ uintptr_t ipv4AutoLearnSetLockTblAddr; ++ uintptr_t ipv6AutoLearnSetLockTblAddr; ++ uint16_t minFragSize[2]; ++ e_FmPcdManipReassemWaysNumber numOfFramesPerHashEntry[2]; ++ uint8_t relativeSchemeId[2]; ++ t_Handle h_Ipv4Scheme; ++ t_Handle h_Ipv6Scheme; ++ uint32_t nonConsistentSpFqid; ++ } ip; ++ struct { ++ t_Handle h_Ad; ++ t_ReassTbl *p_ReassTbl; ++ uintptr_t autoLearnHashTblAddr; ++ uintptr_t autoLearnSetLockTblAddr; ++ uint16_t maxRessembledsSize; ++ e_FmPcdManipReassemWaysNumber numOfFramesPerHashEntry; ++ uint8_t relativeSchemeId; ++ t_Handle h_Scheme; ++ } capwap; ++ }; ++} t_ReassmParams; ++ ++typedef struct{ ++ e_FmPcdManipType type; ++ t_FmPcdManipParams manipParams; ++ bool muramAllocate; ++ t_Handle h_Ad; ++ uint32_t opcode; ++ bool rmv; ++ bool insrt; ++ t_Handle h_NextManip; ++ t_Handle h_PrevManip; ++ e_FmPcdManipType nextManipType; ++ /* HdrManip parameters*/ ++ uint8_t *p_Hmct; ++ uint8_t *p_Data; ++ bool dontParseAfterManip; ++ bool fieldUpdate; ++ bool custom; ++ uint16_t tableSize; ++ uint8_t dataSize; ++ bool cascaded; ++ e_ManipUnifiedPosition unifiedPosition; ++ /* end HdrManip */ ++ uint8_t *p_Template; ++ uint16_t owner; ++ uint32_t updateParams; ++ uint32_t shadowUpdateParams; ++ bool frag; ++ bool reassm; ++ uint16_t sizeForFragmentation; ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++ t_Handle h_Frag; ++ t_CapwapFragParams capwapFragParams; ++#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ ++ union { ++ t_ReassmParams reassmParams; ++ t_FragParams fragParams; ++ }; ++ uint8_t icOffset; ++ uint16_t ownerTmp; ++ bool cnia; ++ t_Handle p_StatsTbl; ++ t_Handle h_FmPcd; ++ t_List nodesLst; ++ t_Handle h_Spinlock; ++} t_FmPcdManip; ++ ++typedef struct t_FmPcdCcSavedManipParams ++{ ++ union ++ { ++ struct ++ { ++ uint16_t dataOffset; ++ //uint8_t poolId; ++ }capwapParams; ++ struct ++ { ++ uint16_t dataOffset; ++ uint8_t poolId; ++ }ipParams; ++ }; ++ ++} t_FmPcdCcSavedManipParams; ++ ++ ++#endif /* __FM_MANIP_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.c +new file mode 100644 +index 00000000..91f70a1a +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.c +@@ -0,0 +1,2095 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_pcd.c ++ ++ @Description FM PCD ... ++*//***************************************************************************/ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "string_ext.h" ++#include "xx_ext.h" ++#include "sprint_ext.h" ++#include "debug_ext.h" ++#include "net_ext.h" ++#include "fm_ext.h" ++#include "fm_pcd_ext.h" ++ ++#include "fm_common.h" ++#include "fm_pcd.h" ++#include "fm_pcd_ipc.h" ++#include "fm_hc.h" ++#include "fm_muram_ext.h" ++ ++ ++/****************************************/ ++/* static functions */ ++/****************************************/ ++ ++static t_Error CheckFmPcdParameters(t_FmPcd *p_FmPcd) ++{ ++ if (!p_FmPcd->h_Fm) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("h_Fm has to be initialized")); ++ ++ if (p_FmPcd->guestId == NCSW_MASTER_ID) ++ { ++ if (p_FmPcd->p_FmPcdKg && !p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Something WRONG")); ++ ++ if (p_FmPcd->p_FmPcdPlcr && !p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Something WRONG")); ++ ++ if (!p_FmPcd->f_Exception) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("f_FmPcdExceptions has to be initialized")); ++ ++ if ((!p_FmPcd->f_FmPcdIndexedException) && (p_FmPcd->p_FmPcdPlcr || p_FmPcd->p_FmPcdKg)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("f_FmPcdIndexedException has to be initialized")); ++ ++ if (p_FmPcd->p_FmPcdDriverParam->prsMaxParseCycleLimit > PRS_MAX_CYCLE_LIMIT) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("prsMaxParseCycleLimit has to be less than 8191")); ++ } ++ ++ return E_OK; ++} ++ ++static volatile bool blockingFlag = FALSE; ++static void IpcMsgCompletionCB(t_Handle h_FmPcd, ++ uint8_t *p_Msg, ++ uint8_t *p_Reply, ++ uint32_t replyLength, ++ t_Error status) ++{ ++ UNUSED(h_FmPcd);UNUSED(p_Msg);UNUSED(p_Reply);UNUSED(replyLength);UNUSED(status); ++ blockingFlag = FALSE; ++} ++ ++static t_Error IpcMsgHandlerCB(t_Handle h_FmPcd, ++ uint8_t *p_Msg, ++ uint32_t msgLength, ++ uint8_t *p_Reply, ++ uint32_t *p_ReplyLength) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ t_Error err = E_OK; ++ t_FmPcdIpcMsg *p_IpcMsg = (t_FmPcdIpcMsg*)p_Msg; ++ t_FmPcdIpcReply *p_IpcReply = (t_FmPcdIpcReply*)p_Reply; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((msgLength >= sizeof(uint32_t)), E_INVALID_VALUE); ++ ++#ifdef DISABLE_SANITY_CHECKS ++ UNUSED(msgLength); ++#endif /* DISABLE_SANITY_CHECKS */ ++ ++ ASSERT_COND(p_Msg); ++ ++ memset(p_IpcReply, 0, (sizeof(uint8_t) * FM_PCD_MAX_REPLY_SIZE)); ++ *p_ReplyLength = 0; ++ ++ switch (p_IpcMsg->msgId) ++ { ++ case (FM_PCD_MASTER_IS_ALIVE): ++ *(uint8_t*)(p_IpcReply->replyBody) = 1; ++ p_IpcReply->error = E_OK; ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); ++ break; ++ case (FM_PCD_MASTER_IS_ENABLED): ++ /* count partitions registrations */ ++ if (p_FmPcd->enabled) ++ p_FmPcd->numOfEnabledGuestPartitionsPcds++; ++ *(uint8_t*)(p_IpcReply->replyBody) = (uint8_t)p_FmPcd->enabled; ++ p_IpcReply->error = E_OK; ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); ++ break; ++ case (FM_PCD_GUEST_DISABLE): ++ if (p_FmPcd->numOfEnabledGuestPartitionsPcds) ++ { ++ p_FmPcd->numOfEnabledGuestPartitionsPcds--; ++ p_IpcReply->error = E_OK; ++ } ++ else ++ { ++ REPORT_ERROR(MINOR, E_INVALID_STATE,("Trying to disable an unregistered partition")); ++ p_IpcReply->error = E_INVALID_STATE; ++ } ++ *p_ReplyLength = sizeof(uint32_t); ++ break; ++ case (FM_PCD_GET_COUNTER): ++ { ++ e_FmPcdCounters inCounter; ++ uint32_t outCounter; ++ ++ memcpy((uint8_t*)&inCounter, p_IpcMsg->msgBody, sizeof(uint32_t)); ++ outCounter = FM_PCD_GetCounter(h_FmPcd, inCounter); ++ memcpy(p_IpcReply->replyBody, (uint8_t*)&outCounter, sizeof(uint32_t)); ++ p_IpcReply->error = E_OK; ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t); ++ break; ++ } ++ case (FM_PCD_ALLOC_KG_SCHEMES): ++ { ++ t_FmPcdIpcKgSchemesParams ipcSchemesParams; ++ ++ memcpy((uint8_t*)&ipcSchemesParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgSchemesParams)); ++ err = FmPcdKgAllocSchemes(h_FmPcd, ++ ipcSchemesParams.numOfSchemes, ++ ipcSchemesParams.guestId, ++ p_IpcReply->replyBody); ++ p_IpcReply->error = err; ++ *p_ReplyLength = sizeof(uint32_t) + ipcSchemesParams.numOfSchemes*sizeof(uint8_t); ++ break; ++ } ++ case (FM_PCD_FREE_KG_SCHEMES): ++ { ++ t_FmPcdIpcKgSchemesParams ipcSchemesParams; ++ ++ memcpy((uint8_t*)&ipcSchemesParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgSchemesParams)); ++ err = FmPcdKgFreeSchemes(h_FmPcd, ++ ipcSchemesParams.numOfSchemes, ++ ipcSchemesParams.guestId, ++ ipcSchemesParams.schemesIds); ++ p_IpcReply->error = err; ++ *p_ReplyLength = sizeof(uint32_t); ++ break; ++ } ++ case (FM_PCD_ALLOC_KG_CLSPLAN): ++ { ++ t_FmPcdIpcKgClsPlanParams ipcKgClsPlanParams; ++ ++ memcpy((uint8_t*)&ipcKgClsPlanParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgClsPlanParams)); ++ err = KgAllocClsPlanEntries(h_FmPcd, ++ ipcKgClsPlanParams.numOfClsPlanEntries, ++ ipcKgClsPlanParams.guestId, ++ p_IpcReply->replyBody); ++ p_IpcReply->error = err; ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); ++ break; ++ } ++ case (FM_PCD_FREE_KG_CLSPLAN): ++ { ++ t_FmPcdIpcKgClsPlanParams ipcKgClsPlanParams; ++ ++ memcpy((uint8_t*)&ipcKgClsPlanParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgClsPlanParams)); ++ KgFreeClsPlanEntries(h_FmPcd, ++ ipcKgClsPlanParams.numOfClsPlanEntries, ++ ipcKgClsPlanParams.guestId, ++ ipcKgClsPlanParams.clsPlanBase); ++ *p_ReplyLength = sizeof(uint32_t); ++ break; ++ } ++ case (FM_PCD_ALLOC_PROFILES): ++ { ++ t_FmIpcResourceAllocParams ipcAllocParams; ++ uint16_t base; ++ memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams)); ++ base = PlcrAllocProfilesForPartition(h_FmPcd, ++ ipcAllocParams.base, ++ ipcAllocParams.num, ++ ipcAllocParams.guestId); ++ memcpy(p_IpcReply->replyBody, (uint16_t*)&base, sizeof(uint16_t)); ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint16_t); ++ break; ++ } ++ case (FM_PCD_FREE_PROFILES): ++ { ++ t_FmIpcResourceAllocParams ipcAllocParams; ++ memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams)); ++ PlcrFreeProfilesForPartition(h_FmPcd, ++ ipcAllocParams.base, ++ ipcAllocParams.num, ++ ipcAllocParams.guestId); ++ break; ++ } ++ case (FM_PCD_SET_PORT_PROFILES): ++ { ++ t_FmIpcResourceAllocParams ipcAllocParams; ++ memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams)); ++ PlcrSetPortProfiles(h_FmPcd, ++ ipcAllocParams.guestId, ++ ipcAllocParams.num, ++ ipcAllocParams.base); ++ break; ++ } ++ case (FM_PCD_CLEAR_PORT_PROFILES): ++ { ++ t_FmIpcResourceAllocParams ipcAllocParams; ++ memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams)); ++ PlcrClearPortProfiles(h_FmPcd, ++ ipcAllocParams.guestId); ++ break; ++ } ++ case (FM_PCD_GET_SW_PRS_OFFSET): ++ { ++ t_FmPcdIpcSwPrsLable ipcSwPrsLable; ++ uint32_t swPrsOffset; ++ ++ memcpy((uint8_t*)&ipcSwPrsLable, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcSwPrsLable)); ++ swPrsOffset = ++ FmPcdGetSwPrsOffset(h_FmPcd, ++ (e_NetHeaderType)ipcSwPrsLable.enumHdr, ++ ipcSwPrsLable.indexPerHdr); ++ memcpy(p_IpcReply->replyBody, (uint8_t*)&swPrsOffset, sizeof(uint32_t)); ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t); ++ break; ++ } ++ case (FM_PCD_PRS_INC_PORT_STATS): ++ { ++ t_FmPcdIpcPrsIncludePort ipcPrsIncludePort; ++ ++ memcpy((uint8_t*)&ipcPrsIncludePort, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcPrsIncludePort)); ++ PrsIncludePortInStatistics(h_FmPcd, ++ ipcPrsIncludePort.hardwarePortId, ++ ipcPrsIncludePort.include); ++ break; ++ } ++ default: ++ *p_ReplyLength = 0; ++ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("command not found!!!")); ++ } ++ return E_OK; ++} ++ ++static uint32_t NetEnvLock(t_Handle h_NetEnv) ++{ ++ ASSERT_COND(h_NetEnv); ++ return XX_LockIntrSpinlock(((t_FmPcdNetEnv*)h_NetEnv)->h_Spinlock); ++} ++ ++static void NetEnvUnlock(t_Handle h_NetEnv, uint32_t intFlags) ++{ ++ ASSERT_COND(h_NetEnv); ++ XX_UnlockIntrSpinlock(((t_FmPcdNetEnv*)h_NetEnv)->h_Spinlock, intFlags); ++} ++ ++static void EnqueueLockToFreeLst(t_FmPcd *p_FmPcd, t_FmPcdLock *p_Lock) ++{ ++ uint32_t intFlags; ++ ++ intFlags = XX_LockIntrSpinlock(p_FmPcd->h_Spinlock); ++ LIST_AddToTail(&p_Lock->node, &p_FmPcd->freeLocksLst); ++ XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags); ++} ++ ++static t_FmPcdLock * DequeueLockFromFreeLst(t_FmPcd *p_FmPcd) ++{ ++ t_FmPcdLock *p_Lock = NULL; ++ uint32_t intFlags; ++ ++ intFlags = XX_LockIntrSpinlock(p_FmPcd->h_Spinlock); ++ if (!LIST_IsEmpty(&p_FmPcd->freeLocksLst)) ++ { ++ p_Lock = FM_PCD_LOCK_OBJ(p_FmPcd->freeLocksLst.p_Next); ++ LIST_DelAndInit(&p_Lock->node); ++ } ++ if (p_FmPcd->h_Spinlock) ++ XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags); ++ ++ return p_Lock; ++} ++ ++static void EnqueueLockToAcquiredLst(t_FmPcd *p_FmPcd, t_FmPcdLock *p_Lock) ++{ ++ uint32_t intFlags; ++ ++ intFlags = XX_LockIntrSpinlock(p_FmPcd->h_Spinlock); ++ LIST_AddToTail(&p_Lock->node, &p_FmPcd->acquiredLocksLst); ++ XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags); ++} ++ ++static t_Error FillFreeLocksLst(t_FmPcd *p_FmPcd) ++{ ++ t_FmPcdLock *p_Lock; ++ int i; ++ ++ for (i=0; i<10; i++) ++ { ++ p_Lock = (t_FmPcdLock *)XX_Malloc(sizeof(t_FmPcdLock)); ++ if (!p_Lock) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("FM-PCD lock obj!")); ++ memset(p_Lock, 0, sizeof(t_FmPcdLock)); ++ INIT_LIST(&p_Lock->node); ++ p_Lock->h_Spinlock = XX_InitSpinlock(); ++ if (!p_Lock->h_Spinlock) ++ { ++ XX_Free(p_Lock); ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("FM-PCD spinlock obj!")); ++ } ++ EnqueueLockToFreeLst(p_FmPcd, p_Lock); ++ } ++ ++ return E_OK; ++} ++ ++static void ReleaseFreeLocksLst(t_FmPcd *p_FmPcd) ++{ ++ t_FmPcdLock *p_Lock; ++ ++ p_Lock = DequeueLockFromFreeLst(p_FmPcd); ++ while (p_Lock) ++ { ++ XX_FreeSpinlock(p_Lock->h_Spinlock); ++ XX_Free(p_Lock); ++ p_Lock = DequeueLockFromFreeLst(p_FmPcd); ++ } ++} ++ ++ ++ ++/*****************************************************************************/ ++/* Inter-module API routines */ ++/*****************************************************************************/ ++ ++void FmPcdSetClsPlanGrpId(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint8_t clsPlanGrpId) ++{ ++ ASSERT_COND(p_FmPcd); ++ p_FmPcd->netEnvs[netEnvId].clsPlanGrpId = clsPlanGrpId; ++} ++ ++t_Error PcdGetClsPlanGrpParams(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_GrpParams) ++{ ++ uint8_t netEnvId = p_GrpParams->netEnvId; ++ int i, k, j; ++ ++ ASSERT_COND(p_FmPcd); ++ if (p_FmPcd->netEnvs[netEnvId].clsPlanGrpId != ILLEGAL_CLS_PLAN) ++ { ++ p_GrpParams->grpExists = TRUE; ++ p_GrpParams->clsPlanGrpId = p_FmPcd->netEnvs[netEnvId].clsPlanGrpId; ++ return E_OK; ++ } ++ ++ for (i=0; ((i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) && ++ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE)); i++) ++ { ++ for (k=0; ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) && ++ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE)); k++) ++ { ++ /* if an option exists, add it to the opts list */ ++ if (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt) ++ { ++ /* check if this option already exists, add if it doesn't */ ++ for (j = 0;jnumOfOptions;j++) ++ { ++ if (p_GrpParams->options[j] == p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt) ++ break; ++ } ++ p_GrpParams->optVectors[j] |= p_FmPcd->netEnvs[netEnvId].unitsVectors[i]; ++ if (j == p_GrpParams->numOfOptions) ++ { ++ p_GrpParams->options[p_GrpParams->numOfOptions] = p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt; ++ p_GrpParams->numOfOptions++; ++ } ++ } ++ } ++ } ++ ++ if (p_GrpParams->numOfOptions == 0) ++ { ++ if (p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId != ILLEGAL_CLS_PLAN) ++ { ++ p_GrpParams->grpExists = TRUE; ++ p_GrpParams->clsPlanGrpId = p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId; ++ } ++ } ++ ++ return E_OK; ++ ++} ++ ++t_Error PcdGetVectorForOpt(t_FmPcd *p_FmPcd, uint8_t netEnvId, protocolOpt_t opt, uint32_t *p_Vector) ++{ ++ uint8_t j,k; ++ ++ *p_Vector = 0; ++ ++ ASSERT_COND(p_FmPcd); ++ for (j=0; ((j < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) && ++ (p_FmPcd->netEnvs[netEnvId].units[j].hdrs[0].hdr != HEADER_TYPE_NONE)); j++) ++ { ++ for (k=0; ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) && ++ (p_FmPcd->netEnvs[netEnvId].units[j].hdrs[k].hdr != HEADER_TYPE_NONE)); k++) ++ { ++ if (p_FmPcd->netEnvs[netEnvId].units[j].hdrs[k].opt == opt) ++ *p_Vector |= p_FmPcd->netEnvs[netEnvId].unitsVectors[j]; ++ } ++ } ++ ++ if (!*p_Vector) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Requested option was not defined for this Network Environment Characteristics module")); ++ else ++ return E_OK; ++} ++ ++t_Error PcdGetUnitsVector(t_FmPcd *p_FmPcd, t_NetEnvParams *p_Params) ++{ ++ int i; ++ ++ ASSERT_COND(p_FmPcd); ++ ASSERT_COND(p_Params->netEnvId < FM_MAX_NUM_OF_PORTS); ++ ++ p_Params->vector = 0; ++ for (i=0; inumOfDistinctionUnits ;i++) ++ { ++ if (p_FmPcd->netEnvs[p_Params->netEnvId].units[p_Params->unitIds[i]].hdrs[0].hdr == HEADER_TYPE_NONE) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Requested unit was not defined for this Network Environment Characteristics module")); ++ ASSERT_COND(p_FmPcd->netEnvs[p_Params->netEnvId].unitsVectors[p_Params->unitIds[i]]); ++ p_Params->vector |= p_FmPcd->netEnvs[p_Params->netEnvId].unitsVectors[p_Params->unitIds[i]]; ++ } ++ ++ return E_OK; ++} ++ ++bool PcdNetEnvIsUnitWithoutOpts(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint32_t unitVector) ++{ ++ int i=0, k; ++ ++ ASSERT_COND(p_FmPcd); ++ /* check whether a given unit may be used by non-clsPlan users. */ ++ /* first, recognize the unit by its vector */ ++ while (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE) ++ { ++ if (p_FmPcd->netEnvs[netEnvId].unitsVectors[i] == unitVector) ++ { ++ for (k=0; ++ ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) && ++ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE)); ++ k++) ++ /* check that no option exists */ ++ if ((protocolOpt_t)p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt) ++ return FALSE; ++ break; ++ } ++ i++; ++ } ++ /* assert that a unit was found to mach the vector */ ++ ASSERT_COND(p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); ++ ++ return TRUE; ++} ++bool FmPcdNetEnvIsHdrExist(t_Handle h_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ int i, k; ++ ++ ASSERT_COND(p_FmPcd); ++ ++ for (i=0; ((i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) && ++ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE)); i++) ++ { ++ for (k=0; ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) && ++ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE)); k++) ++ if (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr == hdr) ++ return TRUE; ++ } ++ for (i=0; ((i < FM_PCD_MAX_NUM_OF_ALIAS_HDRS) && ++ (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr != HEADER_TYPE_NONE)); i++) ++ { ++ if (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr == hdr) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++uint8_t FmPcdNetEnvGetUnitId(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr, bool interchangeable, protocolOpt_t opt) ++{ ++ uint8_t i, k; ++ ++ ASSERT_COND(p_FmPcd); ++ ++ if (interchangeable) ++ { ++ for (i=0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) && ++ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++) ++ { ++ for (k=0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) && ++ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++) ++ { ++ if ((p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr == hdr) && ++ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt == opt)) ++ ++ return i; ++ } ++ } ++ } ++ else ++ { ++ for (i=0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) && ++ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++) ++ if ((p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr == hdr) && ++ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].opt == opt) && ++ (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[1].hdr == HEADER_TYPE_NONE)) ++ return i; ++ ++ for (i=0; (i < FM_PCD_MAX_NUM_OF_ALIAS_HDRS) && ++ (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr != HEADER_TYPE_NONE); i++) ++ if ((p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr == hdr) && ++ (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].opt == opt)) ++ return p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].aliasHdr; ++ } ++ ++ return FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS; ++} ++ ++t_Error FmPcdUnregisterReassmPort(t_Handle h_FmPcd, t_Handle h_ReasmCommonPramTbl) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ t_FmPcdCcReassmTimeoutParams ccReassmTimeoutParams = {0}; ++ uint8_t result; ++ t_Error err = E_OK; ++ ++ ASSERT_COND(p_FmPcd); ++ ASSERT_COND(h_ReasmCommonPramTbl); ++ ++ ccReassmTimeoutParams.iprcpt = (uint32_t)(XX_VirtToPhys(h_ReasmCommonPramTbl) - p_FmPcd->physicalMuramBase); ++ ccReassmTimeoutParams.activate = FALSE; /*Disable Timeout Task*/ ++ ++ if ((err = FmHcPcdCcTimeoutReassm(p_FmPcd->h_Hc, &ccReassmTimeoutParams, &result)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ switch (result) ++ { ++ case (0): ++ return E_OK; ++ case (1): ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("")); ++ case (2): ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("")); ++ case (3): ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("Disable Timeout Task with invalid IPRCPT")); ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); ++ } ++ ++ return E_OK; ++} ++ ++e_NetHeaderType FmPcdGetAliasHdr(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr) ++{ ++ int i; ++ ++ ASSERT_COND(p_FmPcd); ++ ASSERT_COND(netEnvId < FM_MAX_NUM_OF_PORTS); ++ ++ for (i=0; (i < FM_PCD_MAX_NUM_OF_ALIAS_HDRS) ++ && (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr != HEADER_TYPE_NONE); i++) ++ { ++ if (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr == hdr) ++ return p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].aliasHdr; ++ } ++ ++ return HEADER_TYPE_NONE; ++} ++ ++void FmPcdPortRegister(t_Handle h_FmPcd, t_Handle h_FmPort, uint8_t hardwarePortId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint16_t swPortIndex = 0; ++ ++ ASSERT_COND(h_FmPcd); ++ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); ++ p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].h_FmPort = h_FmPort; ++} ++ ++uint32_t FmPcdGetLcv(t_Handle h_FmPcd, uint32_t netEnvId, uint8_t hdrNum) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ ASSERT_COND(h_FmPcd); ++ return p_FmPcd->netEnvs[netEnvId].lcvs[hdrNum]; ++} ++ ++uint32_t FmPcdGetMacsecLcv(t_Handle h_FmPcd, uint32_t netEnvId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ ASSERT_COND(h_FmPcd); ++ return p_FmPcd->netEnvs[netEnvId].macsecVector; ++} ++ ++uint8_t FmPcdGetNetEnvId(t_Handle h_NetEnv) ++{ ++ return ((t_FmPcdNetEnv*)h_NetEnv)->netEnvId; ++} ++ ++void FmPcdIncNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId) ++{ ++ uint32_t intFlags; ++ ++ ASSERT_COND(h_FmPcd); ++ ++ intFlags = NetEnvLock(&((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId]); ++ ((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId].owners++; ++ NetEnvUnlock(&((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId], intFlags); ++} ++ ++void FmPcdDecNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId) ++{ ++ uint32_t intFlags; ++ ++ ASSERT_COND(h_FmPcd); ++ ASSERT_COND(((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId].owners); ++ ++ intFlags = NetEnvLock(&((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId]); ++ ((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId].owners--; ++ NetEnvUnlock(&((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId], intFlags); ++} ++ ++uint32_t FmPcdLock(t_Handle h_FmPcd) ++{ ++ ASSERT_COND(h_FmPcd); ++ return XX_LockIntrSpinlock(((t_FmPcd*)h_FmPcd)->h_Spinlock); ++} ++ ++void FmPcdUnlock(t_Handle h_FmPcd, uint32_t intFlags) ++{ ++ ASSERT_COND(h_FmPcd); ++ XX_UnlockIntrSpinlock(((t_FmPcd*)h_FmPcd)->h_Spinlock, intFlags); ++} ++ ++t_FmPcdLock * FmPcdAcquireLock(t_Handle h_FmPcd) ++{ ++ t_FmPcdLock *p_Lock; ++ ASSERT_COND(h_FmPcd); ++ p_Lock = DequeueLockFromFreeLst((t_FmPcd*)h_FmPcd); ++ if (!p_Lock) ++ { ++ FillFreeLocksLst(h_FmPcd); ++ p_Lock = DequeueLockFromFreeLst((t_FmPcd*)h_FmPcd); ++ } ++ ++ if (p_Lock) ++ EnqueueLockToAcquiredLst((t_FmPcd*)h_FmPcd, p_Lock); ++ return p_Lock; ++} ++ ++void FmPcdReleaseLock(t_Handle h_FmPcd, t_FmPcdLock *p_Lock) ++{ ++ uint32_t intFlags; ++ ASSERT_COND(h_FmPcd); ++ intFlags = FmPcdLock(h_FmPcd); ++ LIST_DelAndInit(&p_Lock->node); ++ FmPcdUnlock(h_FmPcd, intFlags); ++ EnqueueLockToFreeLst((t_FmPcd*)h_FmPcd, p_Lock); ++} ++ ++bool FmPcdLockTryLockAll(t_Handle h_FmPcd) ++{ ++ uint32_t intFlags; ++ t_List *p_Pos, *p_SavedPos=NULL; ++ ++ ASSERT_COND(h_FmPcd); ++ intFlags = FmPcdLock(h_FmPcd); ++ LIST_FOR_EACH(p_Pos, &((t_FmPcd*)h_FmPcd)->acquiredLocksLst) ++ { ++ t_FmPcdLock *p_Lock = FM_PCD_LOCK_OBJ(p_Pos); ++ if (!FmPcdLockTryLock(p_Lock)) ++ { ++ p_SavedPos = p_Pos; ++ break; ++ } ++ } ++ if (p_SavedPos) ++ { ++ LIST_FOR_EACH(p_Pos, &((t_FmPcd*)h_FmPcd)->acquiredLocksLst) ++ { ++ t_FmPcdLock *p_Lock = FM_PCD_LOCK_OBJ(p_Pos); ++ if (p_Pos == p_SavedPos) ++ break; ++ FmPcdLockUnlock(p_Lock); ++ } ++ } ++ FmPcdUnlock(h_FmPcd, intFlags); ++ ++ CORE_MemoryBarrier(); ++ ++ if (p_SavedPos) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++void FmPcdLockUnlockAll(t_Handle h_FmPcd) ++{ ++ uint32_t intFlags; ++ t_List *p_Pos; ++ ++ ASSERT_COND(h_FmPcd); ++ intFlags = FmPcdLock(h_FmPcd); ++ LIST_FOR_EACH(p_Pos, &((t_FmPcd*)h_FmPcd)->acquiredLocksLst) ++ { ++ t_FmPcdLock *p_Lock = FM_PCD_LOCK_OBJ(p_Pos); ++ p_Lock->flag = FALSE; ++ } ++ FmPcdUnlock(h_FmPcd, intFlags); ++ ++ CORE_MemoryBarrier(); ++} ++ ++t_Error FmPcdHcSync(t_Handle h_FmPcd) ++{ ++ ASSERT_COND(h_FmPcd); ++ ASSERT_COND(((t_FmPcd*)h_FmPcd)->h_Hc); ++ ++ return FmHcPcdSync(((t_FmPcd*)h_FmPcd)->h_Hc); ++} ++ ++t_Handle FmPcdGetHcHandle(t_Handle h_FmPcd) ++{ ++ ASSERT_COND(h_FmPcd); ++ return ((t_FmPcd*)h_FmPcd)->h_Hc; ++} ++ ++bool FmPcdIsAdvancedOffloadSupported(t_Handle h_FmPcd) ++{ ++ ASSERT_COND(h_FmPcd); ++ return ((t_FmPcd*)h_FmPcd)->advancedOffloadSupport; ++} ++/*********************** End of inter-module routines ************************/ ++ ++ ++/****************************************/ ++/* API Init unit functions */ ++/****************************************/ ++ ++t_Handle FM_PCD_Config(t_FmPcdParams *p_FmPcdParams) ++{ ++ t_FmPcd *p_FmPcd = NULL; ++ t_FmPhysAddr physicalMuramBase; ++ uint8_t i; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmPcdParams, E_INVALID_HANDLE,NULL); ++ ++ p_FmPcd = (t_FmPcd *) XX_Malloc(sizeof(t_FmPcd)); ++ if (!p_FmPcd) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD")); ++ return NULL; ++ } ++ memset(p_FmPcd, 0, sizeof(t_FmPcd)); ++ ++ p_FmPcd->p_FmPcdDriverParam = (t_FmPcdDriverParam *) XX_Malloc(sizeof(t_FmPcdDriverParam)); ++ if (!p_FmPcd->p_FmPcdDriverParam) ++ { ++ XX_Free(p_FmPcd); ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD Driver Param")); ++ return NULL; ++ } ++ memset(p_FmPcd->p_FmPcdDriverParam, 0, sizeof(t_FmPcdDriverParam)); ++ ++ p_FmPcd->h_Fm = p_FmPcdParams->h_Fm; ++ p_FmPcd->guestId = FmGetGuestId(p_FmPcd->h_Fm); ++ p_FmPcd->h_FmMuram = FmGetMuramHandle(p_FmPcd->h_Fm); ++ if (p_FmPcd->h_FmMuram) ++ { ++ FmGetPhysicalMuramBase(p_FmPcdParams->h_Fm, &physicalMuramBase); ++ p_FmPcd->physicalMuramBase = (uint64_t)((uint64_t)(&physicalMuramBase)->low | ((uint64_t)(&physicalMuramBase)->high << 32)); ++ } ++ ++ for (i = 0; inetEnvs[i].clsPlanGrpId = ILLEGAL_CLS_PLAN; ++ ++ if (p_FmPcdParams->useHostCommand) ++ { ++ t_FmHcParams hcParams; ++ ++ memset(&hcParams, 0, sizeof(hcParams)); ++ hcParams.h_Fm = p_FmPcd->h_Fm; ++ hcParams.h_FmPcd = (t_Handle)p_FmPcd; ++ memcpy((uint8_t*)&hcParams.params, (uint8_t*)&p_FmPcdParams->hc, sizeof(t_FmPcdHcParams)); ++ p_FmPcd->h_Hc = FmHcConfigAndInit(&hcParams); ++ if (!p_FmPcd->h_Hc) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD HC")); ++ FM_PCD_Free(p_FmPcd); ++ return NULL; ++ } ++ } ++ else if (p_FmPcd->guestId != NCSW_MASTER_ID) ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("No Host Command defined for a guest partition.")); ++ ++ if (p_FmPcdParams->kgSupport) ++ { ++ p_FmPcd->p_FmPcdKg = (t_FmPcdKg *)KgConfig(p_FmPcd, p_FmPcdParams); ++ if (!p_FmPcd->p_FmPcdKg) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD Keygen")); ++ FM_PCD_Free(p_FmPcd); ++ return NULL; ++ } ++ } ++ ++ if (p_FmPcdParams->plcrSupport) ++ { ++ p_FmPcd->p_FmPcdPlcr = (t_FmPcdPlcr *)PlcrConfig(p_FmPcd, p_FmPcdParams); ++ if (!p_FmPcd->p_FmPcdPlcr) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD Policer")); ++ FM_PCD_Free(p_FmPcd); ++ return NULL; ++ } ++ } ++ ++ if (p_FmPcdParams->prsSupport) ++ { ++ p_FmPcd->p_FmPcdPrs = (t_FmPcdPrs *)PrsConfig(p_FmPcd, p_FmPcdParams); ++ if (!p_FmPcd->p_FmPcdPrs) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD Parser")); ++ FM_PCD_Free(p_FmPcd); ++ return NULL; ++ } ++ } ++ ++ p_FmPcd->h_Spinlock = XX_InitSpinlock(); ++ if (!p_FmPcd->h_Spinlock) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD spinlock")); ++ FM_PCD_Free(p_FmPcd); ++ return NULL; ++ } ++ INIT_LIST(&p_FmPcd->freeLocksLst); ++ INIT_LIST(&p_FmPcd->acquiredLocksLst); ++ ++ p_FmPcd->numOfEnabledGuestPartitionsPcds = 0; ++ ++ p_FmPcd->f_Exception = p_FmPcdParams->f_Exception; ++ p_FmPcd->f_FmPcdIndexedException = p_FmPcdParams->f_ExceptionId; ++ p_FmPcd->h_App = p_FmPcdParams->h_App; ++ ++ p_FmPcd->p_CcShadow = NULL; ++ p_FmPcd->ccShadowSize = 0; ++ p_FmPcd->ccShadowAlign = 0; ++ ++ p_FmPcd->h_ShadowSpinlock = XX_InitSpinlock(); ++ if (!p_FmPcd->h_ShadowSpinlock) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD shadow spinlock")); ++ FM_PCD_Free(p_FmPcd); ++ return NULL; ++ } ++ ++ return p_FmPcd; ++} ++ ++t_Error FM_PCD_Init(t_Handle h_FmPcd) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ t_Error err = E_OK; ++ t_FmPcdIpcMsg msg; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); ++ ++ FM_GetRevision(p_FmPcd->h_Fm, &p_FmPcd->fmRevInfo); ++ ++ if (p_FmPcd->guestId != NCSW_MASTER_ID) ++ { ++ memset(p_FmPcd->fmPcdIpcHandlerModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE); ++ if (Sprint (p_FmPcd->fmPcdIpcHandlerModuleName, "FM_PCD_%d_%d", FmGetId(p_FmPcd->h_Fm), NCSW_MASTER_ID) != 10) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); ++ memset(p_FmPcd->fmPcdModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE); ++ if (Sprint (p_FmPcd->fmPcdModuleName, "FM_PCD_%d_%d",FmGetId(p_FmPcd->h_Fm), p_FmPcd->guestId) != (p_FmPcd->guestId<10 ? 10:11)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); ++ ++ p_FmPcd->h_IpcSession = XX_IpcInitSession(p_FmPcd->fmPcdIpcHandlerModuleName, p_FmPcd->fmPcdModuleName); ++ if (p_FmPcd->h_IpcSession) ++ { ++ t_FmPcdIpcReply reply; ++ uint32_t replyLength; ++ uint8_t isMasterAlive = 0; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_PCD_MASTER_IS_ALIVE; ++ msg.msgBody[0] = p_FmPcd->guestId; ++ blockingFlag = TRUE; ++ ++ do ++ { ++ replyLength = sizeof(uint32_t) + sizeof(isMasterAlive); ++ if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, ++ (uint8_t*)&msg, ++ sizeof(msg.msgId)+sizeof(p_FmPcd->guestId), ++ (uint8_t*)&reply, ++ &replyLength, ++ IpcMsgCompletionCB, ++ h_FmPcd)) != E_OK) ++ REPORT_ERROR(MAJOR, err, NO_MSG); ++ while (blockingFlag) ; ++ if (replyLength != (sizeof(uint32_t) + sizeof(isMasterAlive))) ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ isMasterAlive = *(uint8_t*)(reply.replyBody); ++ } while (!isMasterAlive); ++ } ++ } ++ ++ CHECK_INIT_PARAMETERS(p_FmPcd, CheckFmPcdParameters); ++ ++ if (p_FmPcd->p_FmPcdKg) ++ { ++ err = KgInit(p_FmPcd); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ if (p_FmPcd->p_FmPcdPlcr) ++ { ++ err = PlcrInit(p_FmPcd); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ if (p_FmPcd->p_FmPcdPrs) ++ { ++ err = PrsInit(p_FmPcd); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ if (p_FmPcd->guestId == NCSW_MASTER_ID) ++ { ++ /* register to inter-core messaging mechanism */ ++ memset(p_FmPcd->fmPcdModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE); ++ if (Sprint (p_FmPcd->fmPcdModuleName, "FM_PCD_%d_%d",FmGetId(p_FmPcd->h_Fm),NCSW_MASTER_ID) != 10) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); ++ err = XX_IpcRegisterMsgHandler(p_FmPcd->fmPcdModuleName, IpcMsgHandlerCB, p_FmPcd, FM_PCD_MAX_REPLY_SIZE); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ /* IPv6 Frame-Id used for fragmentation */ ++ p_FmPcd->ipv6FrameIdAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, 4, 4)); ++ if (!p_FmPcd->ipv6FrameIdAddr) ++ { ++ FM_PCD_Free(p_FmPcd); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for IPv6 Frame-Id")); ++ } ++ IOMemSet32(UINT_TO_PTR(p_FmPcd->ipv6FrameIdAddr), 0, 4); ++ ++ /* CAPWAP Frame-Id used for fragmentation */ ++ p_FmPcd->capwapFrameIdAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, 2, 4)); ++ if (!p_FmPcd->capwapFrameIdAddr) ++ { ++ FM_PCD_Free(p_FmPcd); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CAPWAP Frame-Id")); ++ } ++ IOMemSet32(UINT_TO_PTR(p_FmPcd->capwapFrameIdAddr), 0, 2); ++ ++ XX_Free(p_FmPcd->p_FmPcdDriverParam); ++ p_FmPcd->p_FmPcdDriverParam = NULL; ++ ++ FmRegisterPcd(p_FmPcd->h_Fm, p_FmPcd); ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_Free(t_Handle h_FmPcd) ++{ ++ t_FmPcd *p_FmPcd =(t_FmPcd *)h_FmPcd; ++ t_Error err = E_OK; ++ ++ if (p_FmPcd->ipv6FrameIdAddr) ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, UINT_TO_PTR(p_FmPcd->ipv6FrameIdAddr)); ++ ++ if (p_FmPcd->capwapFrameIdAddr) ++ FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, UINT_TO_PTR(p_FmPcd->capwapFrameIdAddr)); ++ ++ if (p_FmPcd->enabled) ++ FM_PCD_Disable(p_FmPcd); ++ ++ if (p_FmPcd->p_FmPcdDriverParam) ++ { ++ XX_Free(p_FmPcd->p_FmPcdDriverParam); ++ p_FmPcd->p_FmPcdDriverParam = NULL; ++ } ++ ++ if (p_FmPcd->p_FmPcdKg) ++ { ++ if ((err = KgFree(p_FmPcd)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ XX_Free(p_FmPcd->p_FmPcdKg); ++ p_FmPcd->p_FmPcdKg = NULL; ++ } ++ ++ if (p_FmPcd->p_FmPcdPlcr) ++ { ++ PlcrFree(p_FmPcd); ++ XX_Free(p_FmPcd->p_FmPcdPlcr); ++ p_FmPcd->p_FmPcdPlcr = NULL; ++ } ++ ++ if (p_FmPcd->p_FmPcdPrs) ++ { ++ if (p_FmPcd->guestId == NCSW_MASTER_ID) ++ PrsFree(p_FmPcd); ++ XX_Free(p_FmPcd->p_FmPcdPrs); ++ p_FmPcd->p_FmPcdPrs = NULL; ++ } ++ ++ if (p_FmPcd->h_Hc) ++ { ++ FmHcFree(p_FmPcd->h_Hc); ++ p_FmPcd->h_Hc = NULL; ++ } ++ ++ XX_IpcUnregisterMsgHandler(p_FmPcd->fmPcdModuleName); ++ ++ FmUnregisterPcd(p_FmPcd->h_Fm); ++ ++ ReleaseFreeLocksLst(p_FmPcd); ++ ++ if (p_FmPcd->h_Spinlock) ++ XX_FreeSpinlock(p_FmPcd->h_Spinlock); ++ ++ if (p_FmPcd->h_ShadowSpinlock) ++ XX_FreeSpinlock(p_FmPcd->h_ShadowSpinlock); ++ ++ XX_Free(p_FmPcd); ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_ConfigException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint32_t bitMask = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ ++ if (p_FmPcd->guestId != NCSW_MASTER_ID) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ConfigException - guest mode!")); ++ ++ GET_FM_PCD_EXCEPTION_FLAG(bitMask, exception); ++ if (bitMask) ++ { ++ if (enable) ++ p_FmPcd->exceptions |= bitMask; ++ else ++ p_FmPcd->exceptions &= ~bitMask; ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_ConfigHcFramesDataMemory(t_Handle h_FmPcd, uint8_t memId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); ++ ++ return FmHcSetFramesDataMemory(p_FmPcd->h_Hc, memId); ++} ++ ++t_Error FM_PCD_Enable(t_Handle h_FmPcd) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); ++ ++ if (p_FmPcd->enabled) ++ return E_OK; ++ ++ if ((p_FmPcd->guestId != NCSW_MASTER_ID) && ++ p_FmPcd->h_IpcSession) ++ { ++ uint8_t enabled; ++ t_FmPcdIpcMsg msg; ++ t_FmPcdIpcReply reply; ++ uint32_t replyLength; ++ ++ memset(&reply, 0, sizeof(reply)); ++ memset(&msg, 0, sizeof(msg)); ++ msg.msgId = FM_PCD_MASTER_IS_ENABLED; ++ replyLength = sizeof(uint32_t) + sizeof(enabled); ++ if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, ++ (uint8_t*)&msg, ++ sizeof(msg.msgId), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ if (replyLength != sizeof(uint32_t) + sizeof(enabled)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ p_FmPcd->enabled = (bool)!!(*(uint8_t*)(reply.replyBody)); ++ if (!p_FmPcd->enabled) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-PCD master should be enabled first!")); ++ ++ return E_OK; ++ } ++ else if (p_FmPcd->guestId != NCSW_MASTER_ID) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("running in guest-mode without IPC!")); ++ ++ if (p_FmPcd->p_FmPcdKg) ++ KgEnable(p_FmPcd); ++ ++ if (p_FmPcd->p_FmPcdPlcr) ++ PlcrEnable(p_FmPcd); ++ ++ if (p_FmPcd->p_FmPcdPrs) ++ PrsEnable(p_FmPcd); ++ ++ p_FmPcd->enabled = TRUE; ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_Disable(t_Handle h_FmPcd) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); ++ ++ if (!p_FmPcd->enabled) ++ return E_OK; ++ ++ if ((p_FmPcd->guestId != NCSW_MASTER_ID) && ++ p_FmPcd->h_IpcSession) ++ { ++ t_FmPcdIpcMsg msg; ++ t_FmPcdIpcReply reply; ++ uint32_t replyLength; ++ ++ memset(&reply, 0, sizeof(reply)); ++ memset(&msg, 0, sizeof(msg)); ++ msg.msgId = FM_PCD_GUEST_DISABLE; ++ replyLength = sizeof(uint32_t); ++ if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, ++ (uint8_t*)&msg, ++ sizeof(msg.msgId), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ if (replyLength != sizeof(uint32_t)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ if (reply.error == E_OK) ++ p_FmPcd->enabled = FALSE; ++ ++ return (t_Error)(reply.error); ++ } ++ else if (p_FmPcd->guestId != NCSW_MASTER_ID) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("running in guest-mode without IPC!")); ++ ++ if (p_FmPcd->numOfEnabledGuestPartitionsPcds != 0) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("Trying to disable a master partition PCD while" ++ "guest partitions are still enabled!")); ++ ++ if (p_FmPcd->p_FmPcdKg) ++ KgDisable(p_FmPcd); ++ ++ if (p_FmPcd->p_FmPcdPlcr) ++ PlcrDisable(p_FmPcd); ++ ++ if (p_FmPcd->p_FmPcdPrs) ++ PrsDisable(p_FmPcd); ++ ++ p_FmPcd->enabled = FALSE; ++ ++ return E_OK; ++} ++ ++t_Handle FM_PCD_NetEnvCharacteristicsSet(t_Handle h_FmPcd, t_FmPcdNetEnvParams *p_NetEnvParams) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint32_t intFlags, specialUnits = 0; ++ uint8_t bitId = 0; ++ uint8_t i, j, k; ++ uint8_t netEnvCurrId; ++ uint8_t ipsecAhUnit = 0,ipsecEspUnit = 0; ++ bool ipsecAhExists = FALSE, ipsecEspExists = FALSE, shim1Selected = FALSE; ++ uint8_t hdrNum; ++ t_FmPcdNetEnvParams *p_ModifiedNetEnvParams; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_STATE, NULL); ++ SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, NULL); ++ SANITY_CHECK_RETURN_VALUE(p_NetEnvParams, E_NULL_POINTER, NULL); ++ ++ intFlags = FmPcdLock(p_FmPcd); ++ ++ /* find a new netEnv */ ++ for (i = 0; i < FM_MAX_NUM_OF_PORTS; i++) ++ if (!p_FmPcd->netEnvs[i].used) ++ break; ++ ++ if (i== FM_MAX_NUM_OF_PORTS) ++ { ++ REPORT_ERROR(MAJOR, E_FULL,("No more than %d netEnv's allowed.", FM_MAX_NUM_OF_PORTS)); ++ FmPcdUnlock(p_FmPcd, intFlags); ++ return NULL; ++ } ++ ++ p_FmPcd->netEnvs[i].used = TRUE; ++ FmPcdUnlock(p_FmPcd, intFlags); ++ ++ /* As anyone doesn't have handle of this netEnv yet, no need ++ to protect it with spinlocks */ ++ ++ p_ModifiedNetEnvParams = (t_FmPcdNetEnvParams *)XX_Malloc(sizeof(t_FmPcdNetEnvParams)); ++ if (!p_ModifiedNetEnvParams) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FmPcdNetEnvParams")); ++ return NULL; ++ } ++ ++ memcpy(p_ModifiedNetEnvParams, p_NetEnvParams, sizeof(t_FmPcdNetEnvParams)); ++ p_NetEnvParams = p_ModifiedNetEnvParams; ++ ++ netEnvCurrId = (uint8_t)i; ++ ++ /* clear from previous use */ ++ memset(&p_FmPcd->netEnvs[netEnvCurrId].units, 0, FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS * sizeof(t_FmPcdIntDistinctionUnit)); ++ memset(&p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs, 0, FM_PCD_MAX_NUM_OF_ALIAS_HDRS * sizeof(t_FmPcdNetEnvAliases)); ++ memcpy(&p_FmPcd->netEnvs[netEnvCurrId].units, p_NetEnvParams->units, p_NetEnvParams->numOfDistinctionUnits*sizeof(t_FmPcdIntDistinctionUnit)); ++ ++ p_FmPcd->netEnvs[netEnvCurrId].netEnvId = netEnvCurrId; ++ p_FmPcd->netEnvs[netEnvCurrId].h_FmPcd = p_FmPcd; ++ ++ p_FmPcd->netEnvs[netEnvCurrId].clsPlanGrpId = ILLEGAL_CLS_PLAN; ++ ++ /* check that header with opt is not interchanged with the same header */ ++ for (i = 0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) ++ && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++) ++ { ++ for (k = 0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) ++ && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++) ++ { ++ /* if an option exists, check that other headers are not the same header ++ without option */ ++ if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt) ++ { ++ for (j = 0; (j < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) ++ && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[j].hdr != HEADER_TYPE_NONE); j++) ++ { ++ if ((p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[j].hdr == p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr) && ++ !p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[j].opt) ++ { ++ REPORT_ERROR(MINOR, E_FULL, ++ ("Illegal unit - header with opt may not be interchangeable with the same header without opt")); ++ XX_Free(p_ModifiedNetEnvParams); ++ return NULL; ++ } ++ } ++ } ++ } ++ } ++ ++ /* Specific headers checking */ ++ for (i = 0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) ++ && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++) ++ { ++ for (k = 0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) ++ && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++) ++ { ++ /* Some headers pairs may not be defined on different units as the parser ++ doesn't distinguish */ ++ /* IPSEC_AH and IPSEC_SPI can't be 2 units, */ ++ /* check that header with opt is not interchanged with the same header */ ++ if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPSEC_AH) ++ { ++ if (ipsecEspExists && (ipsecEspUnit != i)) ++ { ++ REPORT_ERROR(MINOR, E_INVALID_STATE, ("HEADER_TYPE_IPSEC_AH and HEADER_TYPE_IPSEC_ESP may not be defined in separate units")); ++ XX_Free(p_ModifiedNetEnvParams); ++ return NULL; ++ } ++ else ++ { ++ ipsecAhUnit = i; ++ ipsecAhExists = TRUE; ++ } ++ } ++ if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPSEC_ESP) ++ { ++ if (ipsecAhExists && (ipsecAhUnit != i)) ++ { ++ REPORT_ERROR(MINOR, E_INVALID_STATE, ("HEADER_TYPE_IPSEC_AH and HEADER_TYPE_IPSEC_ESP may not be defined in separate units")); ++ XX_Free(p_ModifiedNetEnvParams); ++ return NULL; ++ } ++ else ++ { ++ ipsecEspUnit = i; ++ ipsecEspExists = TRUE; ++ } ++ } ++ /* ENCAP_ESP */ ++ if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_UDP_ENCAP_ESP) ++ { ++ /* IPSec UDP encapsulation is currently set to use SHIM1 */ ++ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_UDP_ENCAP_ESP; ++ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_USER_DEFINED_SHIM1; ++ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_USER_DEFINED_SHIM1; ++ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0; ++ } ++#if (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) ++ /* UDP_LITE */ ++ if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_UDP_LITE) ++ { ++ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_UDP_LITE; ++ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_UDP; ++ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_UDP; ++ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0; ++ } ++#endif /* (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ ++ ++ /* IP FRAG */ ++ if ((p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPv4) && ++ (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt == IPV4_FRAG_1)) ++ { ++ /* If IPv4+Frag, we need to set 2 units - SHIM 2 and IPv4. We first set SHIM2, and than check if ++ * IPv4 exists. If so we don't need to set an extra unit ++ * We consider as "having IPv4" any IPv4 without interchangable headers ++ * but including any options. */ ++ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_IPv4; ++ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].opt = IPV4_FRAG_1; ++ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_USER_DEFINED_SHIM2; ++ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_USER_DEFINED_SHIM2; ++ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0; ++ ++ /* check if IPv4 header exists by itself */ ++ if (FmPcdNetEnvGetUnitId(p_FmPcd, netEnvCurrId, HEADER_TYPE_IPv4, FALSE, 0) == FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) ++ { ++ p_FmPcd->netEnvs[netEnvCurrId].units[p_NetEnvParams->numOfDistinctionUnits].hdrs[0].hdr = HEADER_TYPE_IPv4; ++ p_FmPcd->netEnvs[netEnvCurrId].units[p_NetEnvParams->numOfDistinctionUnits++].hdrs[0].opt = 0; ++ } ++ } ++ if ((p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPv6) && ++ (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt == IPV6_FRAG_1)) ++ { ++ /* If IPv6+Frag, we need to set 2 units - SHIM 2 and IPv6. We first set SHIM2, and than check if ++ * IPv4 exists. If so we don't need to set an extra unit ++ * We consider as "having IPv6" any IPv6 without interchangable headers ++ * but including any options. */ ++ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_IPv6; ++ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].opt = IPV6_FRAG_1; ++ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_USER_DEFINED_SHIM2; ++ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_USER_DEFINED_SHIM2; ++ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0; ++ ++ /* check if IPv6 header exists by itself */ ++ if (FmPcdNetEnvGetUnitId(p_FmPcd, netEnvCurrId, HEADER_TYPE_IPv6, FALSE, 0) == FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) ++ { ++ p_FmPcd->netEnvs[netEnvCurrId].units[p_NetEnvParams->numOfDistinctionUnits].hdrs[0].hdr = HEADER_TYPE_IPv6; ++ p_FmPcd->netEnvs[netEnvCurrId].units[p_NetEnvParams->numOfDistinctionUnits++].hdrs[0].opt = 0; ++ } ++ } ++#if (DPAA_VERSION >= 11) ++ /* CAPWAP FRAG */ ++ if ((p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_CAPWAP) && ++ (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt == CAPWAP_FRAG_1)) ++ { ++ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_CAPWAP; ++ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].opt = CAPWAP_FRAG_1; ++ p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_USER_DEFINED_SHIM2; ++ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_USER_DEFINED_SHIM2; ++ p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0; ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ } ++ } ++ ++ /* if private header (shim), check that no other headers specified */ ++ for (i = 0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) ++ && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++) ++ { ++ if (IS_PRIVATE_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr)) ++ if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[1].hdr != HEADER_TYPE_NONE) ++ { ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("SHIM header may not be interchanged with other headers")); ++ XX_Free(p_ModifiedNetEnvParams); ++ return NULL; ++ } ++ } ++ ++ for (i = 0; i < p_NetEnvParams->numOfDistinctionUnits; i++) ++ { ++ if (IS_PRIVATE_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr)) ++ switch (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr) ++ { ++ case (HEADER_TYPE_USER_DEFINED_SHIM1): ++ if (shim1Selected) ++ { ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("SHIM header cannot be selected with UDP_IPSEC_ESP")); ++ XX_Free(p_ModifiedNetEnvParams); ++ return NULL; ++ } ++ shim1Selected = TRUE; ++ p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i] = 0x00000001; ++ break; ++ case (HEADER_TYPE_USER_DEFINED_SHIM2): ++ p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i] = 0x00000002; ++ break; ++ default: ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Requested SHIM not supported")); ++ } ++ else ++ { ++ p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i] = (uint32_t)(0x80000000 >> bitId++); ++ ++ if (IS_SPECIAL_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr)) ++ p_FmPcd->netEnvs[netEnvCurrId].macsecVector = p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i]; ++ } ++ } ++ ++ /* define a set of hardware parser LCV's according to the defined netenv */ ++ ++ /* set an array of LCV's for each header in the netEnv */ ++ for (i = 0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) ++ && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++) ++ { ++ /* private headers have no LCV in the hard parser */ ++ if (!IS_PRIVATE_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr)) ++ { ++ for (k = 0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) ++ && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++) ++ { ++ hdrNum = GetPrsHdrNum(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr); ++ if ((hdrNum == ILLEGAL_HDR_NUM) || (hdrNum == NO_HDR_NUM)) ++ { ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG); ++ XX_Free(p_ModifiedNetEnvParams); ++ return NULL; ++ } ++ p_FmPcd->netEnvs[netEnvCurrId].lcvs[hdrNum] |= p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i]; ++ } ++ } ++ } ++ XX_Free(p_ModifiedNetEnvParams); ++ ++ p_FmPcd->netEnvs[netEnvCurrId].h_Spinlock = XX_InitSpinlock(); ++ if (!p_FmPcd->netEnvs[netEnvCurrId].h_Spinlock) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Pcd NetEnv spinlock")); ++ return NULL; ++ } ++ return &p_FmPcd->netEnvs[netEnvCurrId]; ++} ++ ++t_Error FM_PCD_NetEnvCharacteristicsDelete(t_Handle h_NetEnv) ++{ ++ t_FmPcdNetEnv *p_NetEnv = (t_FmPcdNetEnv*)h_NetEnv; ++ t_FmPcd *p_FmPcd = p_NetEnv->h_FmPcd; ++ uint32_t intFlags; ++ uint8_t netEnvId = p_NetEnv->netEnvId; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); ++ ++ /* check that no port is bound to this netEnv */ ++ if (p_FmPcd->netEnvs[netEnvId].owners) ++ { ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ++ ("Trying to delete a netEnv that has ports/schemes/trees/clsPlanGrps bound to")); ++ } ++ ++ intFlags = FmPcdLock(p_FmPcd); ++ ++ p_FmPcd->netEnvs[netEnvId].used = FALSE; ++ p_FmPcd->netEnvs[netEnvId].clsPlanGrpId = ILLEGAL_CLS_PLAN; ++ ++ memset(p_FmPcd->netEnvs[netEnvId].units, 0, sizeof(t_FmPcdIntDistinctionUnit)*FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); ++ memset(p_FmPcd->netEnvs[netEnvId].unitsVectors, 0, sizeof(uint32_t)*FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); ++ memset(p_FmPcd->netEnvs[netEnvId].lcvs, 0, sizeof(uint32_t)*FM_PCD_PRS_NUM_OF_HDRS); ++ ++ if (p_FmPcd->netEnvs[netEnvId].h_Spinlock) ++ XX_FreeSpinlock(p_FmPcd->netEnvs[netEnvId].h_Spinlock); ++ ++ FmPcdUnlock(p_FmPcd, intFlags); ++ return E_OK; ++} ++ ++void FM_PCD_HcTxConf(t_Handle h_FmPcd, t_DpaaFD *p_Fd) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ SANITY_CHECK_RETURN(h_FmPcd, E_INVALID_STATE); ++ ++ FmHcTxConf(p_FmPcd->h_Hc, p_Fd); ++} ++ ++t_Error FM_PCD_SetAdvancedOffloadSupport(t_Handle h_FmPcd) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ t_FmCtrlCodeRevisionInfo revInfo; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->enabled, E_INVALID_STATE); ++ ++ if ((err = FM_GetFmanCtrlCodeRevision(p_FmPcd->h_Fm, &revInfo)) != E_OK) ++ { ++ DBG(WARNING, ("FM in guest-mode without IPC, can't validate firmware revision.")); ++ revInfo.packageRev = IP_OFFLOAD_PACKAGE_NUMBER; ++ } ++ if (!IS_OFFLOAD_PACKAGE(revInfo.packageRev)) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Fman ctrl code package")); ++ ++ if (!p_FmPcd->h_Hc) ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("HC must be initialized in this mode")); ++ ++ p_FmPcd->advancedOffloadSupport = TRUE; ++ ++ return E_OK; ++} ++ ++uint32_t FM_PCD_GetCounter(t_Handle h_FmPcd, e_FmPcdCounters counter) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint32_t outCounter = 0; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, 0); ++ SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0); ++ ++ switch (counter) ++ { ++ case (e_FM_PCD_KG_COUNTERS_TOTAL): ++ if (!p_FmPcd->p_FmPcdKg) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("KeyGen is not activated")); ++ return 0; ++ } ++ if ((p_FmPcd->guestId != NCSW_MASTER_ID) && ++ !p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs && ++ !p_FmPcd->h_IpcSession) ++ { ++ REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("running in guest-mode without neither IPC nor mapped register!")); ++ return 0; ++ } ++ break; ++ ++ case (e_FM_PCD_PLCR_COUNTERS_YELLOW): ++ case (e_FM_PCD_PLCR_COUNTERS_RED): ++ case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED): ++ case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW): ++ case (e_FM_PCD_PLCR_COUNTERS_TOTAL): ++ case (e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH): ++ if (!p_FmPcd->p_FmPcdPlcr) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Policer is not activated")); ++ return 0; ++ } ++ if ((p_FmPcd->guestId != NCSW_MASTER_ID) && ++ !p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs && ++ !p_FmPcd->h_IpcSession) ++ { ++ REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("running in \"guest-mode\" without neither IPC nor mapped register!")); ++ return 0; ++ } ++ ++ /* check that counters are enabled */ ++ if (p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs && ++ !(GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr) & FM_PCD_PLCR_GCR_STEN)) ++ { ++ REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled")); ++ return 0; ++ } ++ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs || ++ ((p_FmPcd->guestId != NCSW_MASTER_ID) && p_FmPcd->h_IpcSession)); ++ break; ++ ++ case (e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH): ++ case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED): ++ case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED): ++ case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED): ++ case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED): ++ case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR): ++ case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR): ++ case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR): ++ case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR): ++ case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES): ++ case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES): ++ case (e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES): ++ case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES): ++ case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES): ++ case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES): ++ case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES): ++ case (e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES): ++ if (!p_FmPcd->p_FmPcdPrs) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Parser is not activated")); ++ return 0; ++ } ++ if ((p_FmPcd->guestId != NCSW_MASTER_ID) && ++ !p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs && ++ !p_FmPcd->h_IpcSession) ++ { ++ REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("running in guest-mode without neither IPC nor mapped register!")); ++ return 0; ++ } ++ break; ++ default: ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Unsupported type of counter")); ++ return 0; ++ } ++ ++ if ((p_FmPcd->guestId != NCSW_MASTER_ID) && ++ p_FmPcd->h_IpcSession) ++ { ++ t_FmPcdIpcMsg msg; ++ t_FmPcdIpcReply reply; ++ uint32_t replyLength; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_PCD_GET_COUNTER; ++ memcpy(msg.msgBody, (uint8_t *)&counter, sizeof(uint32_t)); ++ replyLength = sizeof(uint32_t) + sizeof(uint32_t); ++ if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) +sizeof(uint32_t), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ if (replyLength != sizeof(uint32_t) + sizeof(uint32_t)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ ++ memcpy((uint8_t*)&outCounter, reply.replyBody, sizeof(uint32_t)); ++ return outCounter; ++ } ++ ++ switch (counter) ++ { ++ /* Parser statistics */ ++ case (e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH): ++ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_pds); ++ case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED): ++ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l2rrs); ++ case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED): ++ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l3rrs); ++ case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED): ++ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l4rrs); ++ case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED): ++ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_srrs); ++ case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR): ++ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l2rres); ++ case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR): ++ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l3rres); ++ case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR): ++ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l4rres); ++ case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR): ++ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_srres); ++ case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES): ++ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_spcs); ++ case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES): ++ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_spscs); ++ case (e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES): ++ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_hxscs); ++ case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES): ++ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mrcs); ++ case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES): ++ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mrscs); ++ case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES): ++ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mwcs); ++ case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES): ++ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mwscs); ++ case (e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES): ++ return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_fcscs); ++ case (e_FM_PCD_KG_COUNTERS_TOTAL): ++ return GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_tpc); ++ ++ /* Policer statistics */ ++ case (e_FM_PCD_PLCR_COUNTERS_YELLOW): ++ return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ypcnt); ++ case (e_FM_PCD_PLCR_COUNTERS_RED): ++ return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rpcnt); ++ case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED): ++ return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rrpcnt); ++ case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW): ++ return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rypcnt); ++ case (e_FM_PCD_PLCR_COUNTERS_TOTAL): ++ return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_tpcnt); ++ case (e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH): ++ return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_flmcnt); ++ } ++ return 0; ++} ++ ++t_Error FM_PCD_SetException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint32_t bitMask = 0, tmpReg; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); ++ ++ if (p_FmPcd->guestId != NCSW_MASTER_ID) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_SetException - guest mode!")); ++ ++ GET_FM_PCD_EXCEPTION_FLAG(bitMask, exception); ++ ++ if (bitMask) ++ { ++ if (enable) ++ p_FmPcd->exceptions |= bitMask; ++ else ++ p_FmPcd->exceptions &= ~bitMask; ++ ++ switch (exception) ++ { ++ case (e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC): ++ case (e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW): ++ if (!p_FmPcd->p_FmPcdKg) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - keygen is not working")); ++ break; ++ case (e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC): ++ case (e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR): ++ case (e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE): ++ case (e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE): ++ if (!p_FmPcd->p_FmPcdPlcr) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - policer is not working")); ++ break; ++ case (e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC): ++ case (e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC): ++ if (!p_FmPcd->p_FmPcdPrs) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - parser is not working")); ++ break; ++ } ++ ++ switch (exception) ++ { ++ case (e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC): ++ tmpReg = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_eeer); ++ if (enable) ++ tmpReg |= FM_EX_KG_DOUBLE_ECC; ++ else ++ tmpReg &= ~FM_EX_KG_DOUBLE_ECC; ++ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_eeer, tmpReg); ++ break; ++ case (e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW): ++ tmpReg = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_eeer); ++ if (enable) ++ tmpReg |= FM_EX_KG_KEYSIZE_OVERFLOW; ++ else ++ tmpReg &= ~FM_EX_KG_KEYSIZE_OVERFLOW; ++ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_eeer, tmpReg); ++ break; ++ case (e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC): ++ tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_perer); ++ if (enable) ++ tmpReg |= FM_PCD_PRS_DOUBLE_ECC; ++ else ++ tmpReg &= ~FM_PCD_PRS_DOUBLE_ECC; ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_perer, tmpReg); ++ break; ++ case (e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC): ++ tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_pever); ++ if (enable) ++ tmpReg |= FM_PCD_PRS_SINGLE_ECC; ++ else ++ tmpReg &= ~FM_PCD_PRS_SINGLE_ECC; ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_pever, tmpReg); ++ break; ++ case (e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC): ++ tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier); ++ if (enable) ++ tmpReg |= FM_PCD_PLCR_DOUBLE_ECC; ++ else ++ tmpReg &= ~FM_PCD_PLCR_DOUBLE_ECC; ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier, tmpReg); ++ break; ++ case (e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR): ++ tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier); ++ if (enable) ++ tmpReg |= FM_PCD_PLCR_INIT_ENTRY_ERROR; ++ else ++ tmpReg &= ~FM_PCD_PLCR_INIT_ENTRY_ERROR; ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier, tmpReg); ++ break; ++ case (e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE): ++ tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier); ++ if (enable) ++ tmpReg |= FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE; ++ else ++ tmpReg &= ~FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE; ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier, tmpReg); ++ break; ++ case (e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE): ++ tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier); ++ if (enable) ++ tmpReg |= FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE; ++ else ++ tmpReg &= ~FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE; ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier, tmpReg); ++ break; ++ } ++ /* for ECC exceptions driver automatically enables ECC mechanism, if disabled. ++ Driver may disable them automatically, depending on driver's status */ ++ if (enable && ((exception == e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC) | ++ (exception == e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC) | ++ (exception == e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC) | ++ (exception == e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC))) ++ FmEnableRamsEcc(p_FmPcd->h_Fm); ++ if (!enable && ((exception == e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC) | ++ (exception == e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC) | ++ (exception == e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC) | ++ (exception == e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC))) ++ FmDisableRamsEcc(p_FmPcd->h_Fm); ++ } ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_ForceIntr (t_Handle h_FmPcd, e_FmPcdExceptions exception) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); ++ ++ if (p_FmPcd->guestId != NCSW_MASTER_ID) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ForceIntr - guest mode!")); ++ ++ switch (exception) ++ { ++ case (e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC): ++ case (e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW): ++ if (!p_FmPcd->p_FmPcdKg) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - keygen is not working")); ++ break; ++ case (e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC): ++ case (e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR): ++ case (e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE): ++ case (e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE): ++ if (!p_FmPcd->p_FmPcdPlcr) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - policer is not working")); ++ break; ++ case (e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC): ++ case (e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC): ++ if (!p_FmPcd->p_FmPcdPrs) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt -parsrer is not working")); ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid interrupt requested")); ++ } ++ switch (exception) ++ { ++ case e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC: ++ if (!(p_FmPcd->exceptions & FM_PCD_EX_PRS_DOUBLE_ECC)) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); ++ break; ++ case e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC: ++ if (!(p_FmPcd->exceptions & FM_PCD_EX_PRS_SINGLE_ECC)) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); ++ break; ++ case e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC: ++ if (!(p_FmPcd->exceptions & FM_EX_KG_DOUBLE_ECC)) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); ++ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_feer, FM_EX_KG_DOUBLE_ECC); ++ break; ++ case e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW: ++ if (!(p_FmPcd->exceptions & FM_EX_KG_KEYSIZE_OVERFLOW)) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); ++ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_feer, FM_EX_KG_KEYSIZE_OVERFLOW); ++ break; ++ case e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC: ++ if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_DOUBLE_ECC)) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr, FM_PCD_PLCR_DOUBLE_ECC); ++ break; ++ case e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR: ++ if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_INIT_ENTRY_ERROR)) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr, FM_PCD_PLCR_INIT_ENTRY_ERROR); ++ break; ++ case e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE: ++ if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE)) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr, FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE); ++ break; ++ case e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE: ++ if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE)) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr, FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE); ++ break; ++ } ++ ++ return E_OK; ++} ++ ++ ++t_Error FM_PCD_ModifyCounter(t_Handle h_FmPcd, e_FmPcdCounters counter, uint32_t value) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); ++ ++ if (p_FmPcd->guestId != NCSW_MASTER_ID) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ModifyCounter - guest mode!")); ++ ++ switch (counter) ++ { ++ case (e_FM_PCD_KG_COUNTERS_TOTAL): ++ if (!p_FmPcd->p_FmPcdKg) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Invalid counters - KeyGen is not working")); ++ break; ++ case (e_FM_PCD_PLCR_COUNTERS_YELLOW): ++ case (e_FM_PCD_PLCR_COUNTERS_RED): ++ case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED): ++ case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW): ++ case (e_FM_PCD_PLCR_COUNTERS_TOTAL): ++ case (e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH): ++ if (!p_FmPcd->p_FmPcdPlcr) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Invalid counters - Policer is not working")); ++ if (!(GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr) & FM_PCD_PLCR_GCR_STEN)) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled")); ++ break; ++ case (e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH): ++ case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED): ++ case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED): ++ case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED): ++ case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED): ++ case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR): ++ case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR): ++ case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR): ++ case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR): ++ case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES): ++ case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES): ++ case (e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES): ++ case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES): ++ case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES): ++ case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES): ++ case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES): ++ case (e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES): ++ if (!p_FmPcd->p_FmPcdPrs) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported type of counter")); ++ break; ++ default: ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported type of counter")); ++ } ++ switch (counter) ++ { ++ case (e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_pds, value); ++ break; ++ case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l2rrs, value); ++ break; ++ case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l3rrs, value); ++ break; ++ case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l4rrs, value); ++ break; ++ case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_srrs, value); ++ break; ++ case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l2rres, value); ++ break; ++ case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l3rres, value); ++ break; ++ case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l4rres, value); ++ break; ++ case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_srres, value); ++ break; ++ case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_spcs, value); ++ break; ++ case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_spscs, value); ++ break; ++ case (e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_hxscs, value); ++ break; ++ case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mrcs, value); ++ break; ++ case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mrscs, value); ++ break; ++ case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mwcs, value); ++ break; ++ case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mwscs, value); ++ break; ++ case (e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_fcscs, value); ++ break; ++ case (e_FM_PCD_KG_COUNTERS_TOTAL): ++ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_tpc,value); ++ break; ++ ++ /*Policer counters*/ ++ case (e_FM_PCD_PLCR_COUNTERS_YELLOW): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ypcnt, value); ++ break; ++ case (e_FM_PCD_PLCR_COUNTERS_RED): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rpcnt, value); ++ break; ++ case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rrpcnt, value); ++ break; ++ case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rypcnt, value); ++ break; ++ case (e_FM_PCD_PLCR_COUNTERS_TOTAL): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_tpcnt, value); ++ break; ++ case (e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH): ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_flmcnt, value); ++ break; ++ } ++ ++ return E_OK; ++} ++ ++t_Handle FM_PCD_GetHcPort(t_Handle h_FmPcd) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ return FmHcGetPort(p_FmPcd->h_Hc); ++} ++ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.h +new file mode 100644 +index 00000000..27ec9c5b +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.h +@@ -0,0 +1,543 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_pcd.h ++ ++ @Description FM PCD ... ++*//***************************************************************************/ ++#ifndef __FM_PCD_H ++#define __FM_PCD_H ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "list_ext.h" ++#include "fm_pcd_ext.h" ++#include "fm_common.h" ++#include "fsl_fman_prs.h" ++#include "fsl_fman_kg.h" ++ ++#define __ERR_MODULE__ MODULE_FM_PCD ++ ++ ++/****************************/ ++/* Defaults */ ++/****************************/ ++#define DEFAULT_plcrAutoRefresh FALSE ++#define DEFAULT_fmPcdKgErrorExceptions (FM_EX_KG_DOUBLE_ECC | FM_EX_KG_KEYSIZE_OVERFLOW) ++#define DEFAULT_fmPcdPlcrErrorExceptions (FM_PCD_EX_PLCR_DOUBLE_ECC | FM_PCD_EX_PLCR_INIT_ENTRY_ERROR) ++#define DEFAULT_fmPcdPlcrExceptions 0 ++#define DEFAULT_fmPcdPrsErrorExceptions (FM_PCD_EX_PRS_DOUBLE_ECC) ++ ++#define DEFAULT_fmPcdPrsExceptions FM_PCD_EX_PRS_SINGLE_ECC ++#define DEFAULT_numOfUsedProfilesPerWindow 16 ++#define DEFAULT_numOfSharedPlcrProfiles 4 ++ ++/****************************/ ++/* Network defines */ ++/****************************/ ++#define UDP_HEADER_SIZE 8 ++ ++#define ESP_SPI_OFFSET 0 ++#define ESP_SPI_SIZE 4 ++#define ESP_SEQ_NUM_OFFSET ESP_SPI_SIZE ++#define ESP_SEQ_NUM_SIZE 4 ++ ++/****************************/ ++/* General defines */ ++/****************************/ ++#define ILLEGAL_CLS_PLAN 0xff ++#define ILLEGAL_NETENV 0xff ++ ++#define FM_PCD_MAX_NUM_OF_ALIAS_HDRS 3 ++ ++/****************************/ ++/* Error defines */ ++/****************************/ ++ ++#define FM_PCD_EX_PLCR_DOUBLE_ECC 0x20000000 ++#define FM_PCD_EX_PLCR_INIT_ENTRY_ERROR 0x10000000 ++#define FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE 0x08000000 ++#define FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE 0x04000000 ++ ++#define GET_FM_PCD_EXCEPTION_FLAG(bitMask, exception) \ ++switch (exception){ \ ++ case e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC: \ ++ bitMask = FM_EX_KG_DOUBLE_ECC; break; \ ++ case e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC: \ ++ bitMask = FM_PCD_EX_PLCR_DOUBLE_ECC; break; \ ++ case e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW: \ ++ bitMask = FM_EX_KG_KEYSIZE_OVERFLOW; break; \ ++ case e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR: \ ++ bitMask = FM_PCD_EX_PLCR_INIT_ENTRY_ERROR; break; \ ++ case e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE: \ ++ bitMask = FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE; break; \ ++ case e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE: \ ++ bitMask = FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE; break; \ ++ case e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC: \ ++ bitMask = FM_PCD_EX_PRS_DOUBLE_ECC; break; \ ++ case e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC: \ ++ bitMask = FM_PCD_EX_PRS_SINGLE_ECC; break; \ ++ default: bitMask = 0;break;} ++ ++/***********************************************************************/ ++/* Policer defines */ ++/***********************************************************************/ ++#define FM_PCD_PLCR_GCR_STEN 0x40000000 ++#define FM_PCD_PLCR_DOUBLE_ECC 0x80000000 ++#define FM_PCD_PLCR_INIT_ENTRY_ERROR 0x40000000 ++#define FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE 0x80000000 ++#define FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE 0x40000000 ++ ++/***********************************************************************/ ++/* Memory map */ ++/***********************************************************************/ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(push,1) ++#endif /* defined(__MWERKS__) && ... */ ++ ++ ++typedef struct { ++/* General Configuration and Status Registers */ ++ volatile uint32_t fmpl_gcr; /* 0x000 FMPL_GCR - FM Policer General Configuration */ ++ volatile uint32_t fmpl_gsr; /* 0x004 FMPL_GSR - FM Policer Global Status Register */ ++ volatile uint32_t fmpl_evr; /* 0x008 FMPL_EVR - FM Policer Event Register */ ++ volatile uint32_t fmpl_ier; /* 0x00C FMPL_IER - FM Policer Interrupt Enable Register */ ++ volatile uint32_t fmpl_ifr; /* 0x010 FMPL_IFR - FM Policer Interrupt Force Register */ ++ volatile uint32_t fmpl_eevr; /* 0x014 FMPL_EEVR - FM Policer Error Event Register */ ++ volatile uint32_t fmpl_eier; /* 0x018 FMPL_EIER - FM Policer Error Interrupt Enable Register */ ++ volatile uint32_t fmpl_eifr; /* 0x01C FMPL_EIFR - FM Policer Error Interrupt Force Register */ ++/* Global Statistic Counters */ ++ volatile uint32_t fmpl_rpcnt; /* 0x020 FMPL_RPC - FM Policer RED Packets Counter */ ++ volatile uint32_t fmpl_ypcnt; /* 0x024 FMPL_YPC - FM Policer YELLOW Packets Counter */ ++ volatile uint32_t fmpl_rrpcnt; /* 0x028 FMPL_RRPC - FM Policer Recolored RED Packet Counter */ ++ volatile uint32_t fmpl_rypcnt; /* 0x02C FMPL_RYPC - FM Policer Recolored YELLOW Packet Counter */ ++ volatile uint32_t fmpl_tpcnt; /* 0x030 FMPL_TPC - FM Policer Total Packet Counter */ ++ volatile uint32_t fmpl_flmcnt; /* 0x034 FMPL_FLMC - FM Policer Frame Length Mismatch Counter */ ++ volatile uint32_t fmpl_res0[21]; /* 0x038 - 0x08B Reserved */ ++/* Profile RAM Access Registers */ ++ volatile uint32_t fmpl_par; /* 0x08C FMPL_PAR - FM Policer Profile Action Register*/ ++ t_FmPcdPlcrProfileRegs profileRegs; ++/* Error Capture Registers */ ++ volatile uint32_t fmpl_serc; /* 0x100 FMPL_SERC - FM Policer Soft Error Capture */ ++ volatile uint32_t fmpl_upcr; /* 0x104 FMPL_UPCR - FM Policer Uninitialized Profile Capture Register */ ++ volatile uint32_t fmpl_res2; /* 0x108 Reserved */ ++/* Debug Registers */ ++ volatile uint32_t fmpl_res3[61]; /* 0x10C-0x200 Reserved Debug*/ ++/* Profile Selection Mapping Registers Per Port-ID (n=1-11, 16) */ ++ volatile uint32_t fmpl_dpmr; /* 0x200 FMPL_DPMR - FM Policer Default Mapping Register */ ++ volatile uint32_t fmpl_pmr[63]; /*+default 0x204-0x2FF FMPL_PMR1 - FMPL_PMR63, - FM Policer Profile Mapping Registers. ++ (for port-ID 1-11, only for supported Port-ID registers) */ ++} t_FmPcdPlcrRegs; ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(pop) ++#endif /* defined(__MWERKS__) && ... */ ++ ++ ++/***********************************************************************/ ++/* Driver's internal structures */ ++/***********************************************************************/ ++ ++typedef struct { ++ bool known; ++ uint8_t id; ++} t_FmPcdKgSchemesExtractsEntry; ++ ++typedef struct { ++ t_FmPcdKgSchemesExtractsEntry extractsArray[FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY]; ++} t_FmPcdKgSchemesExtracts; ++ ++typedef struct { ++ t_Handle h_Manip; ++ bool keepRes; ++ e_FmPcdEngine nextEngine; ++ uint8_t parseCode; ++} t_FmPcdInfoForManip; ++ ++/**************************************************************************//** ++ @Description A structure of parameters to communicate ++ between the port and PCD regarding the KG scheme. ++*//***************************************************************************/ ++typedef struct { ++ uint8_t netEnvId; /* in */ ++ uint8_t numOfDistinctionUnits; /* in */ ++ uint8_t unitIds[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; /* in */ ++ uint32_t vector; /* out */ ++} t_NetEnvParams; ++ ++typedef struct { ++ bool allocated; ++ uint8_t ownerId; /* guestId for KG in multi-partition only. ++ portId for PLCR in any environment */ ++} t_FmPcdAllocMng; ++ ++typedef struct { ++ volatile bool lock; ++ bool used; ++ uint8_t owners; ++ uint8_t netEnvId; ++ uint8_t guestId; ++ uint8_t baseEntry; ++ uint16_t sizeOfGrp; ++ protocolOpt_t optArray[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)]; ++} t_FmPcdKgClsPlanGrp; ++ ++typedef struct { ++ t_Handle h_FmPcd; ++ uint8_t schemeId; ++ t_FmPcdLock *p_Lock; ++ bool valid; ++ uint8_t netEnvId; ++ uint8_t owners; ++ uint32_t matchVector; ++ uint32_t ccUnits; ++ bool nextRelativePlcrProfile; ++ uint16_t relativeProfileId; ++ uint16_t numOfProfiles; ++ t_FmPcdKgKeyOrder orderedArray; ++ e_FmPcdEngine nextEngine; ++ e_FmPcdDoneAction doneAction; ++ bool requiredActionFlag; ++ uint32_t requiredAction; ++ bool extractedOrs; ++ uint8_t bitOffsetInPlcrProfile; ++ bool directPlcr; ++#if (DPAA_VERSION >= 11) ++ bool vspe; ++#endif ++} t_FmPcdKgScheme; ++ ++typedef union { ++ struct fman_kg_scheme_regs schemeRegs; ++ struct fman_kg_pe_regs portRegs; ++ struct fman_kg_cp_regs clsPlanRegs; ++} u_FmPcdKgIndirectAccessRegs; ++ ++typedef struct { ++ struct fman_kg_regs *p_FmPcdKgRegs; ++ uint32_t schemeExceptionsBitMask; ++ uint8_t numOfSchemes; ++ t_Handle h_HwSpinlock; ++ uint8_t schemesIds[FM_PCD_KG_NUM_OF_SCHEMES]; ++ t_FmPcdKgScheme schemes[FM_PCD_KG_NUM_OF_SCHEMES]; ++ t_FmPcdKgClsPlanGrp clsPlanGrps[FM_MAX_NUM_OF_PORTS]; ++ uint8_t emptyClsPlanGrpId; ++ t_FmPcdAllocMng schemesMng[FM_PCD_KG_NUM_OF_SCHEMES]; /* only for MASTER ! */ ++ t_FmPcdAllocMng clsPlanBlocksMng[FM_PCD_MAX_NUM_OF_CLS_PLANS/CLS_PLAN_NUM_PER_GRP]; ++ u_FmPcdKgIndirectAccessRegs *p_IndirectAccessRegs; ++} t_FmPcdKg; ++ ++typedef struct { ++ uint16_t profilesBase; ++ uint16_t numOfProfiles; ++ t_Handle h_FmPort; ++} t_FmPcdPlcrMapParam; ++ ++typedef struct { ++ uint16_t absoluteProfileId; ++ t_Handle h_FmPcd; ++ bool valid; ++ t_FmPcdLock *p_Lock; ++ t_FmPcdAllocMng profilesMng; ++ bool requiredActionFlag; ++ uint32_t requiredAction; ++ e_FmPcdEngine nextEngineOnGreen; /**< Green next engine type */ ++ u_FmPcdPlcrNextEngineParams paramsOnGreen; /**< Green next engine params */ ++ ++ e_FmPcdEngine nextEngineOnYellow; /**< Yellow next engine type */ ++ u_FmPcdPlcrNextEngineParams paramsOnYellow; /**< Yellow next engine params */ ++ ++ e_FmPcdEngine nextEngineOnRed; /**< Red next engine type */ ++ u_FmPcdPlcrNextEngineParams paramsOnRed; /**< Red next engine params */ ++} t_FmPcdPlcrProfile; ++ ++typedef struct { ++ t_FmPcdPlcrRegs *p_FmPcdPlcrRegs; ++ uint16_t partPlcrProfilesBase; ++ uint16_t partNumOfPlcrProfiles; ++ t_FmPcdPlcrProfile profiles[FM_PCD_PLCR_NUM_ENTRIES]; ++ uint16_t numOfSharedProfiles; ++ uint16_t sharedProfilesIds[FM_PCD_PLCR_NUM_ENTRIES]; ++ t_FmPcdPlcrMapParam portsMapping[FM_MAX_NUM_OF_PORTS]; ++ t_Handle h_HwSpinlock; ++ t_Handle h_SwSpinlock; ++} t_FmPcdPlcr; ++ ++typedef struct { ++ uint32_t *p_SwPrsCode; ++ uint32_t *p_CurrSwPrs; ++ uint8_t currLabel; ++ struct fman_prs_regs *p_FmPcdPrsRegs; ++ t_FmPcdPrsLabelParams labelsTable[FM_PCD_PRS_NUM_OF_LABELS]; ++ uint32_t fmPcdPrsPortIdStatistics; ++} t_FmPcdPrs; ++ ++typedef struct { ++ struct { ++ e_NetHeaderType hdr; ++ protocolOpt_t opt; /* only one option !! */ ++ } hdrs[FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS]; ++} t_FmPcdIntDistinctionUnit; ++ ++typedef struct { ++ e_NetHeaderType hdr; ++ protocolOpt_t opt; /* only one option !! */ ++ e_NetHeaderType aliasHdr; ++} t_FmPcdNetEnvAliases; ++ ++typedef struct { ++ uint8_t netEnvId; ++ t_Handle h_FmPcd; ++ t_Handle h_Spinlock; ++ bool used; ++ uint8_t owners; ++ uint8_t clsPlanGrpId; ++ t_FmPcdIntDistinctionUnit units[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; ++ uint32_t unitsVectors[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; ++ uint32_t lcvs[FM_PCD_PRS_NUM_OF_HDRS]; ++ uint32_t macsecVector; ++ t_FmPcdNetEnvAliases aliasHdrs[FM_PCD_MAX_NUM_OF_ALIAS_HDRS]; ++} t_FmPcdNetEnv; ++ ++typedef struct { ++ struct fman_prs_cfg dfltCfg; ++ bool plcrAutoRefresh; ++ uint16_t prsMaxParseCycleLimit; ++} t_FmPcdDriverParam; ++ ++typedef struct { ++ t_Handle h_Fm; ++ t_Handle h_FmMuram; ++ t_FmRevisionInfo fmRevInfo; ++ ++ uint64_t physicalMuramBase; ++ ++ t_Handle h_Spinlock; ++ t_List freeLocksLst; ++ t_List acquiredLocksLst; ++ ++ t_Handle h_IpcSession; /* relevant for guest only */ ++ bool enabled; ++ uint8_t guestId; /**< Guest Partition Id */ ++ uint8_t numOfEnabledGuestPartitionsPcds; ++ char fmPcdModuleName[MODULE_NAME_SIZE]; ++ char fmPcdIpcHandlerModuleName[MODULE_NAME_SIZE]; /* relevant for guest only - this is the master's name */ ++ t_FmPcdNetEnv netEnvs[FM_MAX_NUM_OF_PORTS]; ++ t_FmPcdKg *p_FmPcdKg; ++ t_FmPcdPlcr *p_FmPcdPlcr; ++ t_FmPcdPrs *p_FmPcdPrs; ++ ++ void *p_CcShadow; /**< CC MURAM shadow */ ++ uint32_t ccShadowSize; ++ uint32_t ccShadowAlign; ++ volatile bool shadowLock; ++ t_Handle h_ShadowSpinlock; ++ ++ t_Handle h_Hc; ++ ++ uint32_t exceptions; ++ t_FmPcdExceptionCallback *f_Exception; ++ t_FmPcdIdExceptionCallback *f_FmPcdIndexedException; ++ t_Handle h_App; ++ uintptr_t ipv6FrameIdAddr; ++ uintptr_t capwapFrameIdAddr; ++ bool advancedOffloadSupport; ++ ++ t_FmPcdDriverParam *p_FmPcdDriverParam; ++} t_FmPcd; ++ ++#if (DPAA_VERSION >= 11) ++typedef uint8_t t_FmPcdFrmReplicUpdateType; ++#define FRM_REPLIC_UPDATE_COUNTER 0x01 ++#define FRM_REPLIC_UPDATE_INFO 0x02 ++#endif /* (DPAA_VERSION >= 11) */ ++/***********************************************************************/ ++/* PCD internal routines */ ++/***********************************************************************/ ++ ++t_Error PcdGetVectorForOpt(t_FmPcd *p_FmPcd, uint8_t netEnvId, protocolOpt_t opt, uint32_t *p_Vector); ++t_Error PcdGetUnitsVector(t_FmPcd *p_FmPcd, t_NetEnvParams *p_Params); ++bool PcdNetEnvIsUnitWithoutOpts(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint32_t unitVector); ++t_Error PcdGetClsPlanGrpParams(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_GrpParams); ++void FmPcdSetClsPlanGrpId(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint8_t clsPlanGrpId); ++e_NetHeaderType FmPcdGetAliasHdr(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr); ++uint8_t FmPcdNetEnvGetUnitIdForSingleHdr(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr); ++uint8_t FmPcdNetEnvGetUnitId(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr, bool interchangeable, protocolOpt_t opt); ++ ++t_Error FmPcdManipBuildIpReassmScheme(t_FmPcd *p_FmPcd, t_Handle h_NetEnv, t_Handle h_CcTree, t_Handle h_Manip, bool isIpv4, uint8_t groupId); ++t_Error FmPcdManipDeleteIpReassmSchemes(t_Handle h_Manip); ++t_Error FmPcdManipBuildCapwapReassmScheme(t_FmPcd *p_FmPcd, t_Handle h_NetEnv, t_Handle h_CcTree, t_Handle h_Manip, uint8_t groupId); ++t_Error FmPcdManipDeleteCapwapReassmSchemes(t_Handle h_Manip); ++bool FmPcdManipIpReassmIsIpv6Hdr(t_Handle h_Manip); ++ ++t_Handle KgConfig( t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams); ++t_Error KgInit(t_FmPcd *p_FmPcd); ++t_Error KgFree(t_FmPcd *p_FmPcd); ++void KgSetClsPlan(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanSet *p_Set); ++bool KgIsSchemeAlwaysDirect(t_Handle h_FmPcd, uint8_t schemeId); ++void KgEnable(t_FmPcd *p_FmPcd); ++void KgDisable(t_FmPcd *p_FmPcd); ++t_Error KgAllocClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t *p_First); ++void KgFreeClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t base); ++ ++/* only for MULTI partittion */ ++t_Error FmPcdKgAllocSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds); ++t_Error FmPcdKgFreeSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds); ++/* only for SINGLE partittion */ ++t_Error KgBindPortToSchemes(t_Handle h_FmPcd , uint8_t hardwarePortId, uint32_t spReg); ++ ++t_FmPcdLock *FmPcdAcquireLock(t_Handle h_FmPcd); ++void FmPcdReleaseLock(t_Handle h_FmPcd, t_FmPcdLock *p_Lock); ++ ++t_Handle PlcrConfig(t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams); ++t_Error PlcrInit(t_FmPcd *p_FmPcd); ++t_Error PlcrFree(t_FmPcd *p_FmPcd); ++void PlcrEnable(t_FmPcd *p_FmPcd); ++void PlcrDisable(t_FmPcd *p_FmPcd); ++uint16_t PlcrAllocProfilesForPartition(t_FmPcd *p_FmPcd, uint16_t base, uint16_t numOfProfiles, uint8_t guestId); ++void PlcrFreeProfilesForPartition(t_FmPcd *p_FmPcd, uint16_t base, uint16_t numOfProfiles, uint8_t guestId); ++t_Error PlcrSetPortProfiles(t_FmPcd *p_FmPcd, ++ uint8_t hardwarePortId, ++ uint16_t numOfProfiles, ++ uint16_t base); ++t_Error PlcrClearPortProfiles(t_FmPcd *p_FmPcd, uint8_t hardwarePortId); ++ ++t_Handle PrsConfig(t_FmPcd *p_FmPcd,t_FmPcdParams *p_FmPcdParams); ++t_Error PrsInit(t_FmPcd *p_FmPcd); ++void PrsEnable(t_FmPcd *p_FmPcd); ++void PrsDisable(t_FmPcd *p_FmPcd); ++void PrsFree(t_FmPcd *p_FmPcd ); ++t_Error PrsIncludePortInStatistics(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, bool include); ++ ++t_Error FmPcdCcGetGrpParams(t_Handle treeId, uint8_t grpId, uint32_t *p_GrpBits, uint8_t *p_GrpBase); ++uint8_t FmPcdCcGetOffset(t_Handle h_CcNode); ++uint8_t FmPcdCcGetParseCode(t_Handle h_CcNode); ++uint16_t FmPcdCcGetNumOfKeys(t_Handle h_CcNode); ++t_Error ValidateNextEngineParams(t_Handle h_FmPcd, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams, e_FmPcdCcStatsMode supportedStatsMode); ++ ++void FmPcdManipUpdateOwner(t_Handle h_Manip, bool add); ++t_Error FmPcdManipCheckParamsForCcNextEngine(t_FmPcdCcNextEngineParams *p_InfoForManip, uint32_t *requiredAction); ++void FmPcdManipUpdateAdResultForCc(t_Handle h_Manip, ++ t_FmPcdCcNextEngineParams *p_CcNextEngineParams, ++ t_Handle p_Ad, ++ t_Handle *p_AdNewPtr); ++void FmPcdManipUpdateAdContLookupForCc(t_Handle h_Manip, t_Handle p_Ad, t_Handle *p_AdNew, uint32_t adTableOffset); ++void FmPcdManipUpdateOwner(t_Handle h_Manip, bool add); ++t_Error FmPcdManipCheckParamsWithCcNodeParams(t_Handle h_Manip, t_Handle h_FmPcdCcNode); ++#ifdef FM_CAPWAP_SUPPORT ++t_Handle FmPcdManipApplSpecificBuild(void); ++bool FmPcdManipIsCapwapApplSpecific(t_Handle h_Manip); ++#endif /* FM_CAPWAP_SUPPORT */ ++#if (DPAA_VERSION >= 11) ++void * FrmReplicGroupGetSourceTableDescriptor(t_Handle h_ReplicGroup); ++void FrmReplicGroupUpdateOwner(t_Handle h_ReplicGroup, bool add); ++void FrmReplicGroupUpdateAd(t_Handle h_ReplicGroup, void *p_Ad, t_Handle *h_AdNew); ++ ++void FmPcdCcGetAdTablesThatPointOnReplicGroup(t_Handle h_Node, ++ t_Handle h_ReplicGroup, ++ t_List *p_AdTables, ++ uint32_t *p_NumOfAdTables); ++#endif /* (DPAA_VERSION >= 11) */ ++ ++void EnqueueNodeInfoToRelevantLst(t_List *p_List, t_CcNodeInformation *p_CcInfo, t_Handle h_Spinlock); ++void DequeueNodeInfoFromRelevantLst(t_List *p_List, t_Handle h_Info, t_Handle h_Spinlock); ++t_CcNodeInformation* FindNodeInfoInReleventLst(t_List *p_List, t_Handle h_Info, t_Handle h_Spinlock); ++t_List *FmPcdManipGetSpinlock(t_Handle h_Manip); ++t_List *FmPcdManipGetNodeLstPointedOnThisManip(t_Handle h_Manip); ++ ++typedef struct ++{ ++ t_Handle h_StatsAd; ++ t_Handle h_StatsCounters; ++#if (DPAA_VERSION >= 11) ++ t_Handle h_StatsFLRs; ++#endif /* (DPAA_VERSION >= 11) */ ++} t_FmPcdCcStatsParams; ++ ++void NextStepAd(t_Handle h_Ad, ++ t_FmPcdCcStatsParams *p_FmPcdCcStatsParams, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams, ++ t_FmPcd *p_FmPcd); ++void ReleaseLst(t_List *p_List); ++ ++static __inline__ t_Handle FmPcdGetMuramHandle(t_Handle h_FmPcd) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ASSERT_COND(p_FmPcd); ++ return p_FmPcd->h_FmMuram; ++} ++ ++static __inline__ uint64_t FmPcdGetMuramPhysBase(t_Handle h_FmPcd) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ASSERT_COND(p_FmPcd); ++ return p_FmPcd->physicalMuramBase; ++} ++ ++static __inline__ uint32_t FmPcdLockSpinlock(t_FmPcdLock *p_Lock) ++{ ++ ASSERT_COND(p_Lock); ++ return XX_LockIntrSpinlock(p_Lock->h_Spinlock); ++} ++ ++static __inline__ void FmPcdUnlockSpinlock(t_FmPcdLock *p_Lock, uint32_t flags) ++{ ++ ASSERT_COND(p_Lock); ++ XX_UnlockIntrSpinlock(p_Lock->h_Spinlock, flags); ++} ++ ++static __inline__ bool FmPcdLockTryLock(t_FmPcdLock *p_Lock) ++{ ++ uint32_t intFlags; ++ ++ ASSERT_COND(p_Lock); ++ intFlags = XX_LockIntrSpinlock(p_Lock->h_Spinlock); ++ if (p_Lock->flag) ++ { ++ XX_UnlockIntrSpinlock(p_Lock->h_Spinlock, intFlags); ++ return FALSE; ++ } ++ p_Lock->flag = TRUE; ++ XX_UnlockIntrSpinlock(p_Lock->h_Spinlock, intFlags); ++ return TRUE; ++} ++ ++static __inline__ void FmPcdLockUnlock(t_FmPcdLock *p_Lock) ++{ ++ ASSERT_COND(p_Lock); ++ p_Lock->flag = FALSE; ++} ++ ++ ++#endif /* __FM_PCD_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd_ipc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd_ipc.h +new file mode 100644 +index 00000000..325d3e33 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd_ipc.h +@@ -0,0 +1,280 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File fm_pcd_ipc.h ++ ++ @Description FM PCD Inter-Partition prototypes, structures and definitions. ++*//***************************************************************************/ ++#ifndef __FM_PCD_IPC_H ++#define __FM_PCD_IPC_H ++ ++#include "std_ext.h" ++ ++ ++/**************************************************************************//** ++ @Group FM_grp Frame Manager API ++ ++ @Description FM API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(push,1) ++#endif /* defined(__MWERKS__) && ... */ ++ ++/**************************************************************************//** ++ @Description Structure for getting a sw parser address according to a label ++ Fields commented 'IN' are passed by the port module to be used ++ by the FM module. ++ Fields commented 'OUT' will be filled by FM before returning to port. ++*//***************************************************************************/ ++typedef _Packed struct t_FmPcdIpcSwPrsLable ++{ ++ uint32_t enumHdr; /**< IN. The existence of this header will invoke ++ the sw parser code. */ ++ uint8_t indexPerHdr; /**< IN. Normally 0, if more than one sw parser ++ attachments for the same header, use this ++ ++ index to distinguish between them. */ ++} _PackedType t_FmPcdIpcSwPrsLable; ++ ++/**************************************************************************//** ++ @Description Structure for port-PCD communication. ++ Fields commented 'IN' are passed by the port module to be used ++ by the FM module. ++ Fields commented 'OUT' will be filled by FM before returning to port. ++ Some fields are optional (depending on configuration) and ++ will be analized by the port and FM modules accordingly. ++*//***************************************************************************/ ++ ++typedef struct t_FmPcdIpcKgSchemesParams ++{ ++ uint8_t guestId; ++ uint8_t numOfSchemes; ++ uint8_t schemesIds[FM_PCD_KG_NUM_OF_SCHEMES]; ++} _PackedType t_FmPcdIpcKgSchemesParams; ++ ++typedef struct t_FmPcdIpcKgClsPlanParams ++{ ++ uint8_t guestId; ++ uint16_t numOfClsPlanEntries; ++ uint8_t clsPlanBase; ++} _PackedType t_FmPcdIpcKgClsPlanParams; ++ ++typedef _Packed struct t_FmPcdIpcPrsIncludePort ++{ ++ uint8_t hardwarePortId; ++ bool include; ++} _PackedType t_FmPcdIpcPrsIncludePort; ++ ++ ++#define FM_PCD_MAX_REPLY_SIZE 16 ++#define FM_PCD_MAX_MSG_SIZE 36 ++#define FM_PCD_MAX_REPLY_BODY_SIZE 36 ++ ++typedef _Packed struct { ++ uint32_t msgId; ++ uint8_t msgBody[FM_PCD_MAX_MSG_SIZE]; ++} _PackedType t_FmPcdIpcMsg; ++ ++typedef _Packed struct t_FmPcdIpcReply { ++ uint32_t error; ++ uint8_t replyBody[FM_PCD_MAX_REPLY_BODY_SIZE]; ++} _PackedType t_FmPcdIpcReply; ++ ++typedef _Packed struct t_FmIpcResourceAllocParams { ++ uint8_t guestId; ++ uint16_t base; ++ uint16_t num; ++}_PackedType t_FmIpcResourceAllocParams; ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(pop) ++#endif /* defined(__MWERKS__) && ... */ ++ ++ ++ ++/**************************************************************************//** ++ @Function FM_PCD_ALLOC_KG_SCHEMES ++ ++ @Description Used by FM PCD front-end in order to allocate KG resources ++ ++ @Param[in/out] t_FmPcdIpcKgAllocParams Pointer ++*//***************************************************************************/ ++#define FM_PCD_ALLOC_KG_SCHEMES 3 ++ ++/**************************************************************************//** ++ @Function FM_PCD_FREE_KG_SCHEMES ++ ++ @Description Used by FM PCD front-end in order to Free KG resources ++ ++ @Param[in/out] t_FmPcdIpcKgSchemesParams Pointer ++*//***************************************************************************/ ++#define FM_PCD_FREE_KG_SCHEMES 4 ++ ++/**************************************************************************//** ++ @Function FM_PCD_ALLOC_PROFILES ++ ++ @Description Used by FM PCD front-end in order to allocate Policer profiles ++ ++ @Param[in/out] t_FmIpcResourceAllocParams Pointer ++*//***************************************************************************/ ++#define FM_PCD_ALLOC_PROFILES 5 ++ ++/**************************************************************************//** ++ @Function FM_PCD_FREE_PROFILES ++ ++ @Description Used by FM PCD front-end in order to Free Policer profiles ++ ++ @Param[in/out] t_FmIpcResourceAllocParams Pointer ++*//***************************************************************************/ ++#define FM_PCD_FREE_PROFILES 6 ++ ++/**************************************************************************//** ++ @Function FM_PCD_SET_PORT_PROFILES ++ ++ @Description Used by FM PCD front-end in order to allocate Policer profiles ++ for specific port ++ ++ @Param[in/out] t_FmIpcResourceAllocParams Pointer ++*//***************************************************************************/ ++#define FM_PCD_SET_PORT_PROFILES 7 ++ ++/**************************************************************************//** ++ @Function FM_PCD_CLEAR_PORT_PROFILES ++ ++ @Description Used by FM PCD front-end in order to allocate Policer profiles ++ for specific port ++ ++ @Param[in/out] t_FmIpcResourceAllocParams Pointer ++*//***************************************************************************/ ++#define FM_PCD_CLEAR_PORT_PROFILES 8 ++ ++/**************************************************************************//** ++ @Function FM_PCD_GET_PHYS_MURAM_BASE ++ ++ @Description Used by FM PCD front-end in order to get MURAM base address ++ ++ @Param[in/out] t_FmPcdIcPhysAddr Pointer ++*//***************************************************************************/ ++#define FM_PCD_GET_PHYS_MURAM_BASE 9 ++ ++/**************************************************************************//** ++ @Function FM_PCD_GET_SW_PRS_OFFSET ++ ++ @Description Used by FM front-end to get the SW parser offset of the start of ++ code relevant to a given label. ++ ++ @Param[in/out] t_FmPcdIpcSwPrsLable Pointer ++*//***************************************************************************/ ++#define FM_PCD_GET_SW_PRS_OFFSET 10 ++ ++/**************************************************************************//** ++ @Function FM_PCD_MASTER_IS_ENABLED ++ ++ @Description Used by FM front-end in order to verify ++ PCD enablement. ++ ++ @Param[in] bool Pointer ++*//***************************************************************************/ ++#define FM_PCD_MASTER_IS_ENABLED 15 ++ ++/**************************************************************************//** ++ @Function FM_PCD_GUEST_DISABLE ++ ++ @Description Used by FM front-end to inform back-end when ++ front-end PCD is disabled ++ ++ @Param[in] None ++*//***************************************************************************/ ++#define FM_PCD_GUEST_DISABLE 16 ++ ++/**************************************************************************//** ++ @Function FM_PCD_FREE_KG_CLSPLAN ++ ++ @Description Used by FM PCD front-end in order to Free KG classification plan entries ++ ++ @Param[in/out] t_FmPcdIpcKgClsPlanParams Pointer ++*//***************************************************************************/ ++#define FM_PCD_FREE_KG_CLSPLAN 22 ++ ++/**************************************************************************//** ++ @Function FM_PCD_ALLOC_KG_CLSPLAN ++ ++ @Description Used by FM PCD front-end in order to allocate KG classification plan entries ++ ++ @Param[in/out] t_FmPcdIpcKgClsPlanParams Pointer ++*//***************************************************************************/ ++#define FM_PCD_ALLOC_KG_CLSPLAN 23 ++ ++/**************************************************************************//** ++ @Function FM_PCD_MASTER_IS_ALIVE ++ ++ @Description Used by FM front-end to check that back-end exists ++ ++ @Param[in] None ++*//***************************************************************************/ ++#define FM_PCD_MASTER_IS_ALIVE 24 ++ ++/**************************************************************************//** ++ @Function FM_PCD_GET_COUNTER ++ ++ @Description Used by FM front-end to read PCD counters ++ ++ @Param[in/out] t_FmPcdIpcGetCounter Pointer ++*//***************************************************************************/ ++#define FM_PCD_GET_COUNTER 25 ++ ++/**************************************************************************//** ++ @Function FM_PCD_PRS_INC_PORT_STATS ++ ++ @Description Used by FM front-end to set/clear statistics for port ++ ++ @Param[in/out] t_FmPcdIpcPrsIncludePort Pointer ++*//***************************************************************************/ ++#define FM_PCD_PRS_INC_PORT_STATS 26 ++ ++#if (DPAA_VERSION >= 11) ++/* TODO - doc */ ++#define FM_PCD_ALLOC_SP 27 ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ ++/** @} */ /* end of FM_PCD_IPC_grp group */ ++/** @} */ /* end of FM_grp group */ ++ ++ ++#endif /* __FM_PCD_IPC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.c +new file mode 100644 +index 00000000..e3753305 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.c +@@ -0,0 +1,1847 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_plcr.c ++ ++ @Description FM PCD POLICER... ++*//***************************************************************************/ ++#include ++#include "std_ext.h" ++#include "error_ext.h" ++#include "string_ext.h" ++#include "debug_ext.h" ++#include "net_ext.h" ++#include "fm_ext.h" ++ ++#include "fm_common.h" ++#include "fm_pcd.h" ++#include "fm_hc.h" ++#include "fm_pcd_ipc.h" ++#include "fm_plcr.h" ++ ++ ++/****************************************/ ++/* static functions */ ++/****************************************/ ++ ++static uint32_t PlcrProfileLock(t_Handle h_Profile) ++{ ++ ASSERT_COND(h_Profile); ++ return FmPcdLockSpinlock(((t_FmPcdPlcrProfile *)h_Profile)->p_Lock); ++} ++ ++static void PlcrProfileUnlock(t_Handle h_Profile, uint32_t intFlags) ++{ ++ ASSERT_COND(h_Profile); ++ FmPcdUnlockSpinlock(((t_FmPcdPlcrProfile *)h_Profile)->p_Lock, intFlags); ++} ++ ++static bool PlcrProfileFlagTryLock(t_Handle h_Profile) ++{ ++ ASSERT_COND(h_Profile); ++ return FmPcdLockTryLock(((t_FmPcdPlcrProfile *)h_Profile)->p_Lock); ++} ++ ++static void PlcrProfileFlagUnlock(t_Handle h_Profile) ++{ ++ ASSERT_COND(h_Profile); ++ FmPcdLockUnlock(((t_FmPcdPlcrProfile *)h_Profile)->p_Lock); ++} ++ ++static uint32_t PlcrHwLock(t_Handle h_FmPcdPlcr) ++{ ++ ASSERT_COND(h_FmPcdPlcr); ++ return XX_LockIntrSpinlock(((t_FmPcdPlcr*)h_FmPcdPlcr)->h_HwSpinlock); ++} ++ ++static void PlcrHwUnlock(t_Handle h_FmPcdPlcr, uint32_t intFlags) ++{ ++ ASSERT_COND(h_FmPcdPlcr); ++ XX_UnlockIntrSpinlock(((t_FmPcdPlcr*)h_FmPcdPlcr)->h_HwSpinlock, intFlags); ++} ++ ++static uint32_t PlcrSwLock(t_Handle h_FmPcdPlcr) ++{ ++ ASSERT_COND(h_FmPcdPlcr); ++ return XX_LockIntrSpinlock(((t_FmPcdPlcr*)h_FmPcdPlcr)->h_SwSpinlock); ++} ++ ++static void PlcrSwUnlock(t_Handle h_FmPcdPlcr, uint32_t intFlags) ++{ ++ ASSERT_COND(h_FmPcdPlcr); ++ XX_UnlockIntrSpinlock(((t_FmPcdPlcr*)h_FmPcdPlcr)->h_SwSpinlock, intFlags); ++} ++ ++static bool IsProfileShared(t_Handle h_FmPcd, uint16_t absoluteProfileId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint16_t i; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, FALSE); ++ ++ for (i=0;ip_FmPcdPlcr->numOfSharedProfiles;i++) ++ if (p_FmPcd->p_FmPcdPlcr->sharedProfilesIds[i] == absoluteProfileId) ++ return TRUE; ++ return FALSE; ++} ++ ++static t_Error SetProfileNia(t_FmPcd *p_FmPcd, e_FmPcdEngine nextEngine, u_FmPcdPlcrNextEngineParams *p_NextEngineParams, uint32_t *nextAction) ++{ ++ uint32_t nia; ++ uint16_t absoluteProfileId; ++ uint8_t relativeSchemeId, physicalSchemeId; ++ ++ nia = FM_PCD_PLCR_NIA_VALID; ++ ++ switch (nextEngine) ++ { ++ case e_FM_PCD_DONE : ++ switch (p_NextEngineParams->action) ++ { ++ case e_FM_PCD_DROP_FRAME : ++ nia |= GET_NIA_BMI_AC_DISCARD_FRAME(p_FmPcd); ++ break; ++ case e_FM_PCD_ENQ_FRAME: ++ nia |= GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd); ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ break; ++ case e_FM_PCD_KG: ++ physicalSchemeId = FmPcdKgGetSchemeId(p_NextEngineParams->h_DirectScheme); ++ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId); ++ if (relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES) ++ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); ++ if (!FmPcdKgIsSchemeValidSw(p_NextEngineParams->h_DirectScheme)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid direct scheme.")); ++ if (!KgIsSchemeAlwaysDirect(p_FmPcd, relativeSchemeId)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Policer Profile may point only to a scheme that is always direct.")); ++ nia |= NIA_ENG_KG | NIA_KG_DIRECT | physicalSchemeId; ++ break; ++ case e_FM_PCD_PLCR: ++ absoluteProfileId = ((t_FmPcdPlcrProfile *)p_NextEngineParams->h_Profile)->absoluteProfileId; ++ if (!IsProfileShared(p_FmPcd, absoluteProfileId)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next profile must be a shared profile")); ++ if (!FmPcdPlcrIsProfileValid(p_FmPcd, absoluteProfileId)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid profile ")); ++ nia |= NIA_ENG_PLCR | NIA_PLCR_ABSOLUTE | absoluteProfileId; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ ++ *nextAction = nia; ++ ++ return E_OK; ++} ++ ++static uint32_t CalcFPP(uint32_t fpp) ++{ ++ if (fpp > 15) ++ return 15 - (0x1f - fpp); ++ else ++ return 16 + fpp; ++} ++ ++static void GetInfoRateReg(e_FmPcdPlcrRateMode rateMode, ++ uint32_t rate, ++ uint64_t tsuInTenthNano, ++ uint32_t fppShift, ++ uint64_t *p_Integer, ++ uint64_t *p_Fraction) ++{ ++ uint64_t tmp, div; ++ ++ if (rateMode == e_FM_PCD_PLCR_BYTE_MODE) ++ { ++ /* now we calculate the initial integer for the bigger rate */ ++ /* from Kbps to Bytes/TSU */ ++ tmp = (uint64_t)rate; ++ tmp *= 1000; /* kb --> b */ ++ tmp *= tsuInTenthNano; /* bps --> bpTsu(in 10nano) */ ++ ++ div = 1000000000; /* nano */ ++ div *= 10; /* 10 nano */ ++ div *= 8; /* bit to byte */ ++ } ++ else ++ { ++ /* now we calculate the initial integer for the bigger rate */ ++ /* from Kbps to Bytes/TSU */ ++ tmp = (uint64_t)rate; ++ tmp *= tsuInTenthNano; /* bps --> bpTsu(in 10nano) */ ++ ++ div = 1000000000; /* nano */ ++ div *= 10; /* 10 nano */ ++ } ++ *p_Integer = div64_u64(tmp<committedInfoRate > p_NonPassthroughAlgParam->peakOrExcessInfoRate) ++ GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->committedInfoRate, tsuInTenthNanos, 0, &integer, &fraction); ++ else ++ GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->peakOrExcessInfoRate, tsuInTenthNanos, 0, &integer, &fraction); ++ ++ /* we shift integer, as in cir/pir it is represented by the MSB 16 bits, and ++ * the LSB bits are for the fraction */ ++ temp = (uint32_t)((integer<<16) & 0x00000000FFFFFFFF); ++ /* temp is effected by the rate. For low rates it may be as low as 0, and then we'll ++ * take max FP = 31. ++ * For high rates it will never exceed the 32 bit reg (after the 16 shift), as it is ++ * limited by the 10G physical port. ++ */ ++ if (temp != 0) ++ { ++ /* In this case, the largest rate integer is non 0, if it does not occupy all (high) 16 ++ * bits of the PIR_EIR we can use this fact and enlarge it to occupy all 16 bits. ++ * The logic is to have as many bits for integer in the higher rates, but if we have "0"s ++ * in the integer part of the cir/pir register, than these bits are wasted. So we want ++ * to use these bits for the fraction. in this way we will have for fraction - the number ++ * of "0" bits and the rest - for integer. ++ * In other words: For each bit we shift it in PIR_EIR, we move the FP in the TS ++ * one bit to the left - preserving the relationship and achieving more bits ++ * for integer in the TS. ++ */ ++ ++ /* count zeroes left of the higher used bit (in order to shift the value such that ++ * unused bits may be used for fraction). ++ */ ++ while ((temp & 0x80000000) == 0) ++ { ++ temp = temp << 1; ++ fppShift++; ++ } ++ if (fppShift > 15) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_SELECTION, ("timeStampPeriod to Information rate ratio is too small")); ++ return; ++ } ++ } ++ else ++ { ++ temp = (uint32_t)fraction; /* fraction will alyas be smaller than 2^16 */ ++ if (!temp) ++ /* integer and fraction are 0, we set FP to its max val */ ++ fppShift = 31; ++ else ++ { ++ /* integer was 0 but fraction is not. FP is 16 for the fraction, ++ * + all left zeroes of the fraction. */ ++ fppShift=16; ++ /* count zeroes left of the higher used bit (in order to shift the value such that ++ * unused bits may be used for fraction). ++ */ ++ while ((temp & 0x8000) == 0) ++ { ++ temp = temp << 1; ++ fppShift++; ++ } ++ } ++ } ++ ++ /* ++ * This means that the FM TS register will now be used so that 'fppShift' bits are for ++ * fraction and the rest for integer */ ++ /* now we re-calculate cir and pir_eir with the calculated FP */ ++ GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->committedInfoRate, tsuInTenthNanos, fppShift, &integer, &fraction); ++ *cir = (uint32_t)(integer << 16 | (fraction & 0xFFFF)); ++ GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->peakOrExcessInfoRate, tsuInTenthNanos, fppShift, &integer, &fraction); ++ *pir_eir = (uint32_t)(integer << 16 | (fraction & 0xFFFF)); ++ ++ *cbs = p_NonPassthroughAlgParam->committedBurstSize; ++ *pbs_ebs = p_NonPassthroughAlgParam->peakOrExcessBurstSize; ++ ++ /* convert FP as it should be written to reg. ++ * 0-15 --> 16-31 ++ * 16-31 --> 0-15 ++ */ ++ *fpp = CalcFPP(fppShift); ++} ++ ++static void WritePar(t_FmPcd *p_FmPcd, uint32_t par) ++{ ++ t_FmPcdPlcrRegs *p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; ++ ++ ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); ++ WRITE_UINT32(p_FmPcdPlcrRegs->fmpl_par, par); ++ ++ while (GET_UINT32(p_FmPcdPlcrRegs->fmpl_par) & FM_PCD_PLCR_PAR_GO) ; ++} ++ ++static t_Error BuildProfileRegs(t_FmPcd *p_FmPcd, ++ t_FmPcdPlcrProfileParams *p_ProfileParams, ++ t_FmPcdPlcrProfileRegs *p_PlcrRegs) ++{ ++ t_Error err = E_OK; ++ uint32_t pemode, gnia, ynia, rnia, bitFor1Micro; ++ ++ ASSERT_COND(p_FmPcd); ++ ++ bitFor1Micro = FmGetTimeStampScale(p_FmPcd->h_Fm); ++ if (bitFor1Micro == 0) ++ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Timestamp scale")); ++ ++/* Set G, Y, R Nia */ ++ err = SetProfileNia(p_FmPcd, p_ProfileParams->nextEngineOnGreen, &(p_ProfileParams->paramsOnGreen), &gnia); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ err = SetProfileNia(p_FmPcd, p_ProfileParams->nextEngineOnYellow, &(p_ProfileParams->paramsOnYellow), &ynia); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ err = SetProfileNia(p_FmPcd, p_ProfileParams->nextEngineOnRed, &(p_ProfileParams->paramsOnRed), &rnia); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++/* Mode fmpl_pemode */ ++ pemode = FM_PCD_PLCR_PEMODE_PI; ++ ++ switch (p_ProfileParams->algSelection) ++ { ++ case e_FM_PCD_PLCR_PASS_THROUGH: ++ p_PlcrRegs->fmpl_pecir = 0; ++ p_PlcrRegs->fmpl_pecbs = 0; ++ p_PlcrRegs->fmpl_pepepir_eir = 0; ++ p_PlcrRegs->fmpl_pepbs_ebs = 0; ++ p_PlcrRegs->fmpl_pelts = 0; ++ p_PlcrRegs->fmpl_pects = 0; ++ p_PlcrRegs->fmpl_pepts_ets = 0; ++ pemode &= ~FM_PCD_PLCR_PEMODE_ALG_MASK; ++ switch (p_ProfileParams->colorMode) ++ { ++ case e_FM_PCD_PLCR_COLOR_BLIND: ++ pemode |= FM_PCD_PLCR_PEMODE_CBLND; ++ switch (p_ProfileParams->color.dfltColor) ++ { ++ case e_FM_PCD_PLCR_GREEN: ++ pemode &= ~FM_PCD_PLCR_PEMODE_DEFC_MASK; ++ break; ++ case e_FM_PCD_PLCR_YELLOW: ++ pemode |= FM_PCD_PLCR_PEMODE_DEFC_Y; ++ break; ++ case e_FM_PCD_PLCR_RED: ++ pemode |= FM_PCD_PLCR_PEMODE_DEFC_R; ++ break; ++ case e_FM_PCD_PLCR_OVERRIDE: ++ pemode |= FM_PCD_PLCR_PEMODE_DEFC_OVERRIDE; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ ++ break; ++ case e_FM_PCD_PLCR_COLOR_AWARE: ++ pemode &= ~FM_PCD_PLCR_PEMODE_CBLND; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ break; ++ ++ case e_FM_PCD_PLCR_RFC_2698: ++ /* Select algorithm MODE[ALG] = "01" */ ++ pemode |= FM_PCD_PLCR_PEMODE_ALG_RFC2698; ++ if (p_ProfileParams->nonPassthroughAlgParams.committedInfoRate > p_ProfileParams->nonPassthroughAlgParams.peakOrExcessInfoRate) ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("in RFC2698 Peak rate must be equal or larger than committedInfoRate.")); ++ goto cont_rfc; ++ case e_FM_PCD_PLCR_RFC_4115: ++ /* Select algorithm MODE[ALG] = "10" */ ++ pemode |= FM_PCD_PLCR_PEMODE_ALG_RFC4115; ++cont_rfc: ++ /* Select Color-Blind / Color-Aware operation (MODE[CBLND]) */ ++ switch (p_ProfileParams->colorMode) ++ { ++ case e_FM_PCD_PLCR_COLOR_BLIND: ++ pemode |= FM_PCD_PLCR_PEMODE_CBLND; ++ break; ++ case e_FM_PCD_PLCR_COLOR_AWARE: ++ pemode &= ~FM_PCD_PLCR_PEMODE_CBLND; ++ /*In color aware more select override color interpretation (MODE[OVCLR]) */ ++ switch (p_ProfileParams->color.override) ++ { ++ case e_FM_PCD_PLCR_GREEN: ++ pemode &= ~FM_PCD_PLCR_PEMODE_OVCLR_MASK; ++ break; ++ case e_FM_PCD_PLCR_YELLOW: ++ pemode |= FM_PCD_PLCR_PEMODE_OVCLR_Y; ++ break; ++ case e_FM_PCD_PLCR_RED: ++ pemode |= FM_PCD_PLCR_PEMODE_OVCLR_R; ++ break; ++ case e_FM_PCD_PLCR_OVERRIDE: ++ pemode |= FM_PCD_PLCR_PEMODE_OVCLR_G_NC; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ /* Select Measurement Unit Mode to BYTE or PACKET (MODE[PKT]) */ ++ switch (p_ProfileParams->nonPassthroughAlgParams.rateMode) ++ { ++ case e_FM_PCD_PLCR_BYTE_MODE : ++ pemode &= ~FM_PCD_PLCR_PEMODE_PKT; ++ switch (p_ProfileParams->nonPassthroughAlgParams.byteModeParams.frameLengthSelection) ++ { ++ case e_FM_PCD_PLCR_L2_FRM_LEN: ++ pemode |= FM_PCD_PLCR_PEMODE_FLS_L2; ++ break; ++ case e_FM_PCD_PLCR_L3_FRM_LEN: ++ pemode |= FM_PCD_PLCR_PEMODE_FLS_L3; ++ break; ++ case e_FM_PCD_PLCR_L4_FRM_LEN: ++ pemode |= FM_PCD_PLCR_PEMODE_FLS_L4; ++ break; ++ case e_FM_PCD_PLCR_FULL_FRM_LEN: ++ pemode |= FM_PCD_PLCR_PEMODE_FLS_FULL; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ switch (p_ProfileParams->nonPassthroughAlgParams.byteModeParams.rollBackFrameSelection) ++ { ++ case e_FM_PCD_PLCR_ROLLBACK_L2_FRM_LEN: ++ pemode &= ~FM_PCD_PLCR_PEMODE_RBFLS; ++ break; ++ case e_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN: ++ pemode |= FM_PCD_PLCR_PEMODE_RBFLS; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ break; ++ case e_FM_PCD_PLCR_PACKET_MODE : ++ pemode |= FM_PCD_PLCR_PEMODE_PKT; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ /* Select timeStamp floating point position (MODE[FPP]) to fit the actual traffic rates. For PACKET ++ mode with low traffic rates move the fixed point to the left to increase fraction accuracy. For BYTE ++ mode with high traffic rates move the fixed point to the right to increase integer accuracy. */ ++ ++ /* Configure Traffic Parameters*/ ++ { ++ uint32_t cir=0, cbs=0, pir_eir=0, pbs_ebs=0, fpp=0; ++ ++ CalcRates(bitFor1Micro, &p_ProfileParams->nonPassthroughAlgParams, &cir, &cbs, &pir_eir, &pbs_ebs, &fpp); ++ ++ /* Set Committed Information Rate (CIR) */ ++ p_PlcrRegs->fmpl_pecir = cir; ++ /* Set Committed Burst Size (CBS). */ ++ p_PlcrRegs->fmpl_pecbs = cbs; ++ /* Set Peak Information Rate (PIR_EIR used as PIR) */ ++ p_PlcrRegs->fmpl_pepepir_eir = pir_eir; ++ /* Set Peak Burst Size (PBS_EBS used as PBS) */ ++ p_PlcrRegs->fmpl_pepbs_ebs = pbs_ebs; ++ ++ /* Initialize the Metering Buckets to be full (write them with 0xFFFFFFFF. */ ++ /* Peak Rate Token Bucket Size (PTS_ETS used as PTS) */ ++ p_PlcrRegs->fmpl_pepts_ets = 0xFFFFFFFF; ++ /* Committed Rate Token Bucket Size (CTS) */ ++ p_PlcrRegs->fmpl_pects = 0xFFFFFFFF; ++ ++ /* Set the FPP based on calculation */ ++ pemode |= (fpp << FM_PCD_PLCR_PEMODE_FPP_SHIFT); ++ } ++ break; /* FM_PCD_PLCR_PEMODE_ALG_RFC2698 , FM_PCD_PLCR_PEMODE_ALG_RFC4115 */ ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ ++ p_PlcrRegs->fmpl_pemode = pemode; ++ ++ p_PlcrRegs->fmpl_pegnia = gnia; ++ p_PlcrRegs->fmpl_peynia = ynia; ++ p_PlcrRegs->fmpl_pernia = rnia; ++ ++ /* Zero Counters */ ++ p_PlcrRegs->fmpl_pegpc = 0; ++ p_PlcrRegs->fmpl_peypc = 0; ++ p_PlcrRegs->fmpl_perpc = 0; ++ p_PlcrRegs->fmpl_perypc = 0; ++ p_PlcrRegs->fmpl_perrpc = 0; ++ ++ return E_OK; ++} ++ ++static t_Error AllocSharedProfiles(t_FmPcd *p_FmPcd, uint16_t numOfProfiles, uint16_t *profilesIds) ++{ ++ uint32_t profilesFound; ++ uint16_t i, k=0; ++ uint32_t intFlags; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ ++ if (!numOfProfiles) ++ return E_OK; ++ ++ if (numOfProfiles>FM_PCD_PLCR_NUM_ENTRIES) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("numProfiles is too big.")); ++ ++ intFlags = PlcrSwLock(p_FmPcd->p_FmPcdPlcr); ++ /* Find numOfProfiles free profiles (may be spread) */ ++ profilesFound = 0; ++ for (i=0;ip_FmPcdPlcr->profiles[i].profilesMng.allocated) ++ { ++ profilesFound++; ++ profilesIds[k] = i; ++ k++; ++ if (profilesFound == numOfProfiles) ++ break; ++ } ++ ++ if (profilesFound != numOfProfiles) ++ { ++ PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); ++ RETURN_ERROR(MAJOR, E_INVALID_STATE,NO_MSG); ++ } ++ ++ for (i = 0;ip_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated = TRUE; ++ p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.ownerId = 0; ++ } ++ PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); ++ ++ return E_OK; ++} ++ ++static void FreeSharedProfiles(t_FmPcd *p_FmPcd, uint16_t numOfProfiles, uint16_t *profilesIds) ++{ ++ uint16_t i; ++ ++ SANITY_CHECK_RETURN(p_FmPcd, E_INVALID_HANDLE); ++ ++ ASSERT_COND(numOfProfiles); ++ ++ for (i=0; i < numOfProfiles; i++) ++ { ++ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated); ++ p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated = FALSE; ++ p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.ownerId = p_FmPcd->guestId; ++ } ++} ++ ++static void UpdateRequiredActionFlag(t_Handle h_FmPcd, uint16_t absoluteProfileId, bool set) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ /* this routine is protected by calling routine */ ++ ++ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); ++ ++ if (set) ++ p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredActionFlag = TRUE; ++ else ++ { ++ p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredAction = 0; ++ p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredActionFlag = FALSE; ++ } ++} ++ ++/*********************************************/ ++/*............Policer Exception..............*/ ++/*********************************************/ ++static void EventsCB(t_Handle h_FmPcd) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ uint32_t event, mask, force; ++ ++ ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); ++ event = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_evr); ++ mask = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier); ++ ++ event &= mask; ++ ++ /* clear the forced events */ ++ force = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr); ++ if (force & event) ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr, force & ~event); ++ ++ ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_evr, event); ++ ++ if (event & FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE) ++ p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE); ++ if (event & FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE) ++ p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE); ++} ++ ++/* ..... */ ++ ++static void ErrorExceptionsCB(t_Handle h_FmPcd) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ uint32_t event, force, captureReg, mask; ++ ++ ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); ++ event = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eevr); ++ mask = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier); ++ ++ event &= mask; ++ ++ /* clear the forced events */ ++ force = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr); ++ if (force & event) ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr, force & ~event); ++ ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eevr, event); ++ ++ if (event & FM_PCD_PLCR_DOUBLE_ECC) ++ p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC); ++ if (event & FM_PCD_PLCR_INIT_ENTRY_ERROR) ++ { ++ captureReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_upcr); ++ /*ASSERT_COND(captureReg & PLCR_ERR_UNINIT_CAP); ++ p_UnInitCapt->profileNum = (uint8_t)(captureReg & PLCR_ERR_UNINIT_NUM_MASK); ++ p_UnInitCapt->portId = (uint8_t)((captureReg & PLCR_ERR_UNINIT_PID_MASK) >>PLCR_ERR_UNINIT_PID_SHIFT) ; ++ p_UnInitCapt->absolute = (bool)(captureReg & PLCR_ERR_UNINIT_ABSOLUTE_MASK);*/ ++ p_FmPcd->f_FmPcdIndexedException(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR,(uint16_t)(captureReg & PLCR_ERR_UNINIT_NUM_MASK)); ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_upcr, PLCR_ERR_UNINIT_CAP); ++ } ++} ++ ++ ++/*****************************************************************************/ ++/* Inter-module API routines */ ++/*****************************************************************************/ ++ ++t_Handle PlcrConfig(t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams) ++{ ++ t_FmPcdPlcr *p_FmPcdPlcr; ++ uint16_t i=0; ++ ++ UNUSED(p_FmPcd); ++ UNUSED(p_FmPcdParams); ++ ++ p_FmPcdPlcr = (t_FmPcdPlcr *) XX_Malloc(sizeof(t_FmPcdPlcr)); ++ if (!p_FmPcdPlcr) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Policer structure allocation FAILED")); ++ return NULL; ++ } ++ memset(p_FmPcdPlcr, 0, sizeof(t_FmPcdPlcr)); ++ if (p_FmPcd->guestId == NCSW_MASTER_ID) ++ { ++ p_FmPcdPlcr->p_FmPcdPlcrRegs = (t_FmPcdPlcrRegs *)UINT_TO_PTR(FmGetPcdPlcrBaseAddr(p_FmPcdParams->h_Fm)); ++ p_FmPcd->p_FmPcdDriverParam->plcrAutoRefresh = DEFAULT_plcrAutoRefresh; ++ p_FmPcd->exceptions |= (DEFAULT_fmPcdPlcrExceptions | DEFAULT_fmPcdPlcrErrorExceptions); ++ } ++ ++ p_FmPcdPlcr->numOfSharedProfiles = DEFAULT_numOfSharedPlcrProfiles; ++ ++ p_FmPcdPlcr->partPlcrProfilesBase = p_FmPcdParams->partPlcrProfilesBase; ++ p_FmPcdPlcr->partNumOfPlcrProfiles = p_FmPcdParams->partNumOfPlcrProfiles; ++ /* for backward compatabilty. if no policer profile, will set automatically to the max */ ++ if ((p_FmPcd->guestId == NCSW_MASTER_ID) && ++ (p_FmPcdPlcr->partNumOfPlcrProfiles == 0)) ++ p_FmPcdPlcr->partNumOfPlcrProfiles = FM_PCD_PLCR_NUM_ENTRIES; ++ ++ for (i=0; iprofiles[i].profilesMng.ownerId = (uint8_t)ILLEGAL_BASE; ++ ++ return p_FmPcdPlcr; ++} ++ ++t_Error PlcrInit(t_FmPcd *p_FmPcd) ++{ ++ t_FmPcdDriverParam *p_Param = p_FmPcd->p_FmPcdDriverParam; ++ t_FmPcdPlcr *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr; ++ t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; ++ t_Error err = E_OK; ++ uint32_t tmpReg32 = 0; ++ uint16_t base; ++ ++ if ((p_FmPcdPlcr->partPlcrProfilesBase + p_FmPcdPlcr->partNumOfPlcrProfiles) > FM_PCD_PLCR_NUM_ENTRIES) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("partPlcrProfilesBase+partNumOfPlcrProfiles out of range!!!")); ++ ++ p_FmPcdPlcr->h_HwSpinlock = XX_InitSpinlock(); ++ if (!p_FmPcdPlcr->h_HwSpinlock) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM Policer HW spinlock")); ++ ++ p_FmPcdPlcr->h_SwSpinlock = XX_InitSpinlock(); ++ if (!p_FmPcdPlcr->h_SwSpinlock) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM Policer SW spinlock")); ++ ++ base = PlcrAllocProfilesForPartition(p_FmPcd, ++ p_FmPcdPlcr->partPlcrProfilesBase, ++ p_FmPcdPlcr->partNumOfPlcrProfiles, ++ p_FmPcd->guestId); ++ if (base == (uint16_t)ILLEGAL_BASE) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); ++ ++ if (p_FmPcdPlcr->numOfSharedProfiles) ++ { ++ err = AllocSharedProfiles(p_FmPcd, ++ p_FmPcdPlcr->numOfSharedProfiles, ++ p_FmPcdPlcr->sharedProfilesIds); ++ if (err) ++ RETURN_ERROR(MAJOR, err,NO_MSG); ++ } ++ ++ if (p_FmPcd->guestId != NCSW_MASTER_ID) ++ return E_OK; ++ ++ /**********************FMPL_GCR******************/ ++ tmpReg32 = 0; ++ tmpReg32 |= FM_PCD_PLCR_GCR_STEN; ++ if (p_Param->plcrAutoRefresh) ++ tmpReg32 |= FM_PCD_PLCR_GCR_DAR; ++ tmpReg32 |= GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd); ++ ++ WRITE_UINT32(p_Regs->fmpl_gcr, tmpReg32); ++ /**********************FMPL_GCR******************/ ++ ++ /**********************FMPL_EEVR******************/ ++ WRITE_UINT32(p_Regs->fmpl_eevr, (FM_PCD_PLCR_DOUBLE_ECC | FM_PCD_PLCR_INIT_ENTRY_ERROR)); ++ /**********************FMPL_EEVR******************/ ++ /**********************FMPL_EIER******************/ ++ tmpReg32 = 0; ++ if (p_FmPcd->exceptions & FM_PCD_EX_PLCR_DOUBLE_ECC) ++ { ++ FmEnableRamsEcc(p_FmPcd->h_Fm); ++ tmpReg32 |= FM_PCD_PLCR_DOUBLE_ECC; ++ } ++ if (p_FmPcd->exceptions & FM_PCD_EX_PLCR_INIT_ENTRY_ERROR) ++ tmpReg32 |= FM_PCD_PLCR_INIT_ENTRY_ERROR; ++ WRITE_UINT32(p_Regs->fmpl_eier, tmpReg32); ++ /**********************FMPL_EIER******************/ ++ ++ /**********************FMPL_EVR******************/ ++ WRITE_UINT32(p_Regs->fmpl_evr, (FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE | FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE)); ++ /**********************FMPL_EVR******************/ ++ /**********************FMPL_IER******************/ ++ tmpReg32 = 0; ++ if (p_FmPcd->exceptions & FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE) ++ tmpReg32 |= FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE; ++ if (p_FmPcd->exceptions & FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE) ++ tmpReg32 |= FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE; ++ WRITE_UINT32(p_Regs->fmpl_ier, tmpReg32); ++ /**********************FMPL_IER******************/ ++ ++ /* register even if no interrupts enabled, to allow future enablement */ ++ FmRegisterIntr(p_FmPcd->h_Fm, ++ e_FM_MOD_PLCR, ++ 0, ++ e_FM_INTR_TYPE_ERR, ++ ErrorExceptionsCB, ++ p_FmPcd); ++ FmRegisterIntr(p_FmPcd->h_Fm, ++ e_FM_MOD_PLCR, ++ 0, ++ e_FM_INTR_TYPE_NORMAL, ++ EventsCB, ++ p_FmPcd); ++ ++ /* driver initializes one DFLT profile at the last entry*/ ++ /**********************FMPL_DPMR******************/ ++ tmpReg32 = 0; ++ WRITE_UINT32(p_Regs->fmpl_dpmr, tmpReg32); ++ p_FmPcd->p_FmPcdPlcr->profiles[0].profilesMng.allocated = TRUE; ++ ++ return E_OK; ++} ++ ++t_Error PlcrFree(t_FmPcd *p_FmPcd) ++{ ++ FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PLCR, 0, e_FM_INTR_TYPE_ERR); ++ FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PLCR, 0, e_FM_INTR_TYPE_NORMAL); ++ ++ if (p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles) ++ FreeSharedProfiles(p_FmPcd, ++ p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles, ++ p_FmPcd->p_FmPcdPlcr->sharedProfilesIds); ++ ++ if (p_FmPcd->p_FmPcdPlcr->partNumOfPlcrProfiles) ++ PlcrFreeProfilesForPartition(p_FmPcd, ++ p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase, ++ p_FmPcd->p_FmPcdPlcr->partNumOfPlcrProfiles, ++ p_FmPcd->guestId); ++ ++ if (p_FmPcd->p_FmPcdPlcr->h_SwSpinlock) ++ XX_FreeSpinlock(p_FmPcd->p_FmPcdPlcr->h_SwSpinlock); ++ ++ if (p_FmPcd->p_FmPcdPlcr->h_HwSpinlock) ++ XX_FreeSpinlock(p_FmPcd->p_FmPcdPlcr->h_HwSpinlock); ++ ++ return E_OK; ++} ++ ++void PlcrEnable(t_FmPcd *p_FmPcd) ++{ ++ t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; ++ ++ WRITE_UINT32(p_Regs->fmpl_gcr, GET_UINT32(p_Regs->fmpl_gcr) | FM_PCD_PLCR_GCR_EN); ++} ++ ++void PlcrDisable(t_FmPcd *p_FmPcd) ++{ ++ t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; ++ ++ WRITE_UINT32(p_Regs->fmpl_gcr, GET_UINT32(p_Regs->fmpl_gcr) & ~FM_PCD_PLCR_GCR_EN); ++} ++ ++uint16_t PlcrAllocProfilesForPartition(t_FmPcd *p_FmPcd, uint16_t base, uint16_t numOfProfiles, uint8_t guestId) ++{ ++ uint32_t intFlags; ++ uint16_t profilesFound = 0; ++ int i = 0; ++ ++ ASSERT_COND(p_FmPcd); ++ ASSERT_COND(p_FmPcd->p_FmPcdPlcr); ++ ++ if (!numOfProfiles) ++ return 0; ++ ++ if ((numOfProfiles > FM_PCD_PLCR_NUM_ENTRIES) || ++ (base + numOfProfiles > FM_PCD_PLCR_NUM_ENTRIES)) ++ return (uint16_t)ILLEGAL_BASE; ++ ++ if (p_FmPcd->h_IpcSession) ++ { ++ t_FmIpcResourceAllocParams ipcAllocParams; ++ t_FmPcdIpcMsg msg; ++ t_FmPcdIpcReply reply; ++ t_Error err; ++ uint32_t replyLength; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams)); ++ ipcAllocParams.guestId = p_FmPcd->guestId; ++ ipcAllocParams.num = p_FmPcd->p_FmPcdPlcr->partNumOfPlcrProfiles; ++ ipcAllocParams.base = p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase; ++ msg.msgId = FM_PCD_ALLOC_PROFILES; ++ memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams)); ++ replyLength = sizeof(uint32_t) + sizeof(uint16_t); ++ err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL); ++ if ((err != E_OK) || ++ (replyLength != (sizeof(uint32_t) + sizeof(uint16_t)))) ++ { ++ REPORT_ERROR(MAJOR, err, NO_MSG); ++ return (uint16_t)ILLEGAL_BASE; ++ } ++ else ++ memcpy((uint8_t*)&p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase, reply.replyBody, sizeof(uint16_t)); ++ if (p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase == (uint16_t)ILLEGAL_BASE) ++ { ++ REPORT_ERROR(MAJOR, err, NO_MSG); ++ return (uint16_t)ILLEGAL_BASE; ++ } ++ } ++ else if (p_FmPcd->guestId != NCSW_MASTER_ID) ++ { ++ DBG(WARNING, ("FM Guest mode, without IPC - can't validate Policer-profiles range!")); ++ return (uint16_t)ILLEGAL_BASE; ++ } ++ ++ intFlags = XX_LockIntrSpinlock(p_FmPcd->h_Spinlock); ++ for (i=base; i<(base+numOfProfiles); i++) ++ if (p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId == (uint8_t)ILLEGAL_BASE) ++ profilesFound++; ++ else ++ break; ++ ++ if (profilesFound == numOfProfiles) ++ for (i=base; i<(base+numOfProfiles); i++) ++ p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = guestId; ++ else ++ { ++ XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags); ++ return (uint16_t)ILLEGAL_BASE; ++ } ++ XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags); ++ ++ return base; ++} ++ ++void PlcrFreeProfilesForPartition(t_FmPcd *p_FmPcd, uint16_t base, uint16_t numOfProfiles, uint8_t guestId) ++{ ++ int i = 0; ++ ++ ASSERT_COND(p_FmPcd); ++ ASSERT_COND(p_FmPcd->p_FmPcdPlcr); ++ ++ if (p_FmPcd->h_IpcSession) ++ { ++ t_FmIpcResourceAllocParams ipcAllocParams; ++ t_FmPcdIpcMsg msg; ++ t_Error err; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams)); ++ ipcAllocParams.guestId = p_FmPcd->guestId; ++ ipcAllocParams.num = p_FmPcd->p_FmPcdPlcr->partNumOfPlcrProfiles; ++ ipcAllocParams.base = p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase; ++ msg.msgId = FM_PCD_FREE_PROFILES; ++ memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams)); ++ err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams), ++ NULL, ++ NULL, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ REPORT_ERROR(MAJOR, err, NO_MSG); ++ return; ++ } ++ else if (p_FmPcd->guestId != NCSW_MASTER_ID) ++ { ++ DBG(WARNING, ("FM Guest mode, without IPC - can't validate Policer-profiles range!")); ++ return; ++ } ++ ++ for (i=base; i<(base+numOfProfiles); i++) ++ { ++ if (p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId == guestId) ++ p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = (uint8_t)ILLEGAL_BASE; ++ else ++ DBG(WARNING, ("Request for freeing storage profile window which wasn't allocated to this partition")); ++ } ++} ++ ++t_Error PlcrSetPortProfiles(t_FmPcd *p_FmPcd, ++ uint8_t hardwarePortId, ++ uint16_t numOfProfiles, ++ uint16_t base) ++{ ++ t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; ++ uint32_t log2Num, tmpReg32; ++ ++ if ((p_FmPcd->guestId != NCSW_MASTER_ID) && ++ !p_Regs && ++ p_FmPcd->h_IpcSession) ++ { ++ t_FmIpcResourceAllocParams ipcAllocParams; ++ t_FmPcdIpcMsg msg; ++ t_Error err; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams)); ++ ipcAllocParams.guestId = hardwarePortId; ++ ipcAllocParams.num = numOfProfiles; ++ ipcAllocParams.base = base; ++ msg.msgId = FM_PCD_SET_PORT_PROFILES; ++ memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams)); ++ err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams), ++ NULL, ++ NULL, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ return E_OK; ++ } ++ else if (!p_Regs) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("Either IPC or 'baseAddress' is required!")); ++ ++ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); ++ ++ if (GET_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1]) & FM_PCD_PLCR_PMR_V) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("The requesting port has already an allocated profiles window.")); ++ ++ /**********************FMPL_PMRx******************/ ++ LOG2((uint64_t)numOfProfiles, log2Num); ++ tmpReg32 = base; ++ tmpReg32 |= log2Num << 16; ++ tmpReg32 |= FM_PCD_PLCR_PMR_V; ++ WRITE_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1], tmpReg32); ++ ++ return E_OK; ++} ++ ++t_Error PlcrClearPortProfiles(t_FmPcd *p_FmPcd, uint8_t hardwarePortId) ++{ ++ t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; ++ ++ if ((p_FmPcd->guestId != NCSW_MASTER_ID) && ++ !p_Regs && ++ p_FmPcd->h_IpcSession) ++ { ++ t_FmIpcResourceAllocParams ipcAllocParams; ++ t_FmPcdIpcMsg msg; ++ t_Error err; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams)); ++ ipcAllocParams.guestId = hardwarePortId; ++ msg.msgId = FM_PCD_CLEAR_PORT_PROFILES; ++ memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams)); ++ err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams), ++ NULL, ++ NULL, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ return E_OK; ++ } ++ else if (!p_Regs) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("Either IPC or 'baseAddress' is required!")); ++ ++ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); ++ WRITE_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1], 0); ++ ++ return E_OK; ++} ++ ++t_Error FmPcdPlcrAllocProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId, uint16_t numOfProfiles) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ t_Error err = E_OK; ++ uint32_t profilesFound; ++ uint32_t intFlags; ++ uint16_t i, first, swPortIndex = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ ++ if (!numOfProfiles) ++ return E_OK; ++ ++ ASSERT_COND(hardwarePortId); ++ ++ if (numOfProfiles>FM_PCD_PLCR_NUM_ENTRIES) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("numProfiles is too big.")); ++ ++ if (!POWER_OF_2(numOfProfiles)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numProfiles must be a power of 2.")); ++ ++ first = 0; ++ profilesFound = 0; ++ intFlags = PlcrSwLock(p_FmPcd->p_FmPcdPlcr); ++ ++ for (i=0; ip_FmPcdPlcr->profiles[i].profilesMng.allocated) ++ { ++ profilesFound++; ++ i++; ++ if (profilesFound == numOfProfiles) ++ break; ++ } ++ else ++ { ++ profilesFound = 0; ++ /* advance i to the next aligned address */ ++ i = first = (uint16_t)(first + numOfProfiles); ++ } ++ } ++ ++ if (profilesFound == numOfProfiles) ++ { ++ for (i=first; ip_FmPcdPlcr->profiles[i].profilesMng.allocated = TRUE; ++ p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = hardwarePortId; ++ } ++ } ++ else ++ { ++ PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); ++ RETURN_ERROR(MINOR, E_FULL, ("No profiles.")); ++ } ++ PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); ++ ++ err = PlcrSetPortProfiles(p_FmPcd, hardwarePortId, numOfProfiles, first); ++ if (err) ++ { ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); ++ ++ p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles = numOfProfiles; ++ p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase = first; ++ ++ return E_OK; ++} ++ ++t_Error FmPcdPlcrFreeProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ t_Error err = E_OK; ++ uint32_t intFlags; ++ uint16_t i, swPortIndex = 0; ++ ++ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); ++ ++ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); ++ ++ err = PlcrClearPortProfiles(p_FmPcd, hardwarePortId); ++ if (err) ++ RETURN_ERROR(MAJOR, err,NO_MSG); ++ ++ intFlags = PlcrSwLock(p_FmPcd->p_FmPcdPlcr); ++ for (i=p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase; ++ i<(p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase + ++ p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles); ++ i++) ++ { ++ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId == hardwarePortId); ++ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated); ++ ++ p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated = FALSE; ++ p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = p_FmPcd->guestId; ++ } ++ PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); ++ ++ p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles = 0; ++ p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase = 0; ++ ++ return E_OK; ++} ++ ++t_Error FmPcdPlcrCcGetSetParams(t_Handle h_FmPcd, uint16_t profileIndx ,uint32_t requiredAction) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ t_FmPcdPlcr *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr; ++ t_FmPcdPlcrRegs *p_FmPcdPlcrRegs = p_FmPcdPlcr->p_FmPcdPlcrRegs; ++ uint32_t tmpReg32, intFlags; ++ t_Error err; ++ ++ /* Calling function locked all PCD modules, so no need to lock here */ ++ ++ if (profileIndx >= FM_PCD_PLCR_NUM_ENTRIES) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Policer profile out of range")); ++ ++ if (!FmPcdPlcrIsProfileValid(p_FmPcd, profileIndx)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Policer profile is not valid")); ++ ++ /*intFlags = PlcrProfileLock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx]);*/ ++ ++ if (p_FmPcd->h_Hc) ++ { ++ err = FmHcPcdPlcrCcGetSetParams(p_FmPcd->h_Hc, profileIndx, requiredAction); ++ ++ UpdateRequiredActionFlag(p_FmPcd, profileIndx, TRUE); ++ FmPcdPlcrUpdateRequiredAction(p_FmPcd, profileIndx, requiredAction); ++ ++ /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/ ++ return err; ++ } ++ ++ /* lock the HW because once we read the registers we don't want them to be changed ++ * by another access. (We can copy to a tmp location and release the lock!) */ ++ ++ intFlags = PlcrHwLock(p_FmPcdPlcr); ++ WritePar(p_FmPcd, FmPcdPlcrBuildReadPlcrActionReg(profileIndx)); ++ ++ if (!p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].requiredActionFlag || ++ !(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].requiredAction & requiredAction)) ++ { ++ if (requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) ++ { ++ if ((p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnGreen!= e_FM_PCD_DONE) || ++ (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnYellow!= e_FM_PCD_DONE) || ++ (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnRed!= e_FM_PCD_DONE)) ++ { ++ PlcrHwUnlock(p_FmPcdPlcr, intFlags); ++ /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/ ++ RETURN_ERROR (MAJOR, E_OK, ("In this case the next engine can be e_FM_PCD_DONE")); ++ } ++ ++ if (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnGreen.action == e_FM_PCD_ENQ_FRAME) ++ { ++ tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia); ++ if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) ++ { ++ PlcrHwUnlock(p_FmPcdPlcr, intFlags); ++ /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/ ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); ++ } ++ tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia, tmpReg32); ++ tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx); ++ tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEGNIA; ++ WritePar(p_FmPcd, tmpReg32); ++ } ++ ++ if (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnYellow.action == e_FM_PCD_ENQ_FRAME) ++ { ++ tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia); ++ if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) ++ { ++ PlcrHwUnlock(p_FmPcdPlcr, intFlags); ++ /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/ ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); ++ } ++ tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia, tmpReg32); ++ tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx); ++ tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEYNIA; ++ WritePar(p_FmPcd, tmpReg32); ++ PlcrHwUnlock(p_FmPcdPlcr, intFlags); ++ } ++ ++ if (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnRed.action == e_FM_PCD_ENQ_FRAME) ++ { ++ tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia); ++ if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) ++ { ++ PlcrHwUnlock(p_FmPcdPlcr, intFlags); ++ /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/ ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); ++ } ++ tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia, tmpReg32); ++ tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx); ++ tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PERNIA; ++ WritePar(p_FmPcd, tmpReg32); ++ ++ } ++ } ++ } ++ PlcrHwUnlock(p_FmPcdPlcr, intFlags); ++ ++ UpdateRequiredActionFlag(p_FmPcd, profileIndx, TRUE); ++ FmPcdPlcrUpdateRequiredAction(p_FmPcd, profileIndx, requiredAction); ++ ++ /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/ ++ ++ return E_OK; ++} ++ ++uint32_t FmPcdPlcrGetRequiredActionFlag(t_Handle h_FmPcd, uint16_t absoluteProfileId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); ++ ++ return p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredActionFlag; ++} ++ ++uint32_t FmPcdPlcrGetRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); ++ ++ return p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredAction; ++} ++ ++bool FmPcdPlcrIsProfileValid(t_Handle h_FmPcd, uint16_t absoluteProfileId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ t_FmPcdPlcr *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr; ++ ++ ASSERT_COND(absoluteProfileId < FM_PCD_PLCR_NUM_ENTRIES); ++ ++ return p_FmPcdPlcr->profiles[absoluteProfileId].valid; ++} ++ ++void FmPcdPlcrValidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint32_t intFlags; ++ ++ ASSERT_COND(!p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); ++ ++ intFlags = PlcrProfileLock(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId]); ++ p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid = TRUE; ++ PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId], intFlags); ++} ++ ++void FmPcdPlcrInvalidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint32_t intFlags; ++ ++ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); ++ ++ intFlags = PlcrProfileLock(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId]); ++ p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid = FALSE; ++ PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId], intFlags); ++} ++ ++uint16_t FmPcdPlcrProfileGetAbsoluteId(t_Handle h_Profile) ++{ ++ return ((t_FmPcdPlcrProfile*)h_Profile)->absoluteProfileId; ++} ++ ++t_Error FmPcdPlcrGetAbsoluteIdByProfileParams(t_Handle h_FmPcd, ++ e_FmPcdProfileTypeSelection profileType, ++ t_Handle h_FmPort, ++ uint16_t relativeProfile, ++ uint16_t *p_AbsoluteId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ t_FmPcdPlcr *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr; ++ uint8_t i; ++ ++ switch (profileType) ++ { ++ case e_FM_PCD_PLCR_PORT_PRIVATE: ++ /* get port PCD id from port handle */ ++ for (i=0;ip_FmPcdPlcr->portsMapping[i].h_FmPort == h_FmPort) ++ break; ++ if (i == FM_MAX_NUM_OF_PORTS) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE , ("Invalid port handle.")); ++ ++ if (!p_FmPcd->p_FmPcdPlcr->portsMapping[i].numOfProfiles) ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Port has no allocated profiles")); ++ if (relativeProfile >= p_FmPcd->p_FmPcdPlcr->portsMapping[i].numOfProfiles) ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Profile id is out of range")); ++ *p_AbsoluteId = (uint16_t)(p_FmPcd->p_FmPcdPlcr->portsMapping[i].profilesBase + relativeProfile); ++ break; ++ case e_FM_PCD_PLCR_SHARED: ++ if (relativeProfile >= p_FmPcdPlcr->numOfSharedProfiles) ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Profile id is out of range")); ++ *p_AbsoluteId = (uint16_t)(p_FmPcdPlcr->sharedProfilesIds[relativeProfile]); ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Invalid policer profile type")); ++ } ++ ++ return E_OK; ++} ++ ++uint16_t FmPcdPlcrGetPortProfilesBase(t_Handle h_FmPcd, uint8_t hardwarePortId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ uint16_t swPortIndex = 0; ++ ++ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); ++ ++ return p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase; ++} ++ ++uint16_t FmPcdPlcrGetPortNumOfProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ uint16_t swPortIndex = 0; ++ ++ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); ++ ++ return p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles; ++ ++} ++uint32_t FmPcdPlcrBuildWritePlcrActionReg(uint16_t absoluteProfileId) ++{ ++ return (uint32_t)(FM_PCD_PLCR_PAR_GO | ++ ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT)); ++} ++ ++uint32_t FmPcdPlcrBuildWritePlcrActionRegs(uint16_t absoluteProfileId) ++{ ++ return (uint32_t)(FM_PCD_PLCR_PAR_GO | ++ ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT) | ++ FM_PCD_PLCR_PAR_PWSEL_MASK); ++} ++ ++bool FmPcdPlcrHwProfileIsValid(uint32_t profileModeReg) ++{ ++ ++ if (profileModeReg & FM_PCD_PLCR_PEMODE_PI) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++uint32_t FmPcdPlcrBuildReadPlcrActionReg(uint16_t absoluteProfileId) ++{ ++ return (uint32_t)(FM_PCD_PLCR_PAR_GO | ++ FM_PCD_PLCR_PAR_R | ++ ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT) | ++ FM_PCD_PLCR_PAR_PWSEL_MASK); ++} ++ ++uint32_t FmPcdPlcrBuildCounterProfileReg(e_FmPcdPlcrProfileCounters counter) ++{ ++ switch (counter) ++ { ++ case (e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER): ++ return FM_PCD_PLCR_PAR_PWSEL_PEGPC; ++ case (e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER): ++ return FM_PCD_PLCR_PAR_PWSEL_PEYPC; ++ case (e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER) : ++ return FM_PCD_PLCR_PAR_PWSEL_PERPC; ++ case (e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER) : ++ return FM_PCD_PLCR_PAR_PWSEL_PERYPC; ++ case (e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER) : ++ return FM_PCD_PLCR_PAR_PWSEL_PERRPC; ++ default: ++ REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ return 0; ++ } ++} ++ ++uint32_t FmPcdPlcrBuildNiaProfileReg(bool green, bool yellow, bool red) ++{ ++ ++ uint32_t tmpReg32 = 0; ++ ++ if (green) ++ tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEGNIA; ++ if (yellow) ++ tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEYNIA; ++ if (red) ++ tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PERNIA; ++ ++ return tmpReg32; ++} ++ ++void FmPcdPlcrUpdateRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId, uint32_t requiredAction) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ /* this routine is protected by calling routine */ ++ ++ ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); ++ ++ p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredAction |= requiredAction; ++} ++ ++/*********************** End of inter-module routines ************************/ ++ ++ ++/**************************************************/ ++/*............Policer API.........................*/ ++/**************************************************/ ++ ++t_Error FM_PCD_ConfigPlcrAutoRefreshMode(t_Handle h_FmPcd, bool enable) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE); ++ ++ if (!FmIsMaster(p_FmPcd->h_Fm)) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ConfigPlcrAutoRefreshMode - guest mode!")); ++ ++ p_FmPcd->p_FmPcdDriverParam->plcrAutoRefresh = enable; ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_ConfigPlcrNumOfSharedProfiles(t_Handle h_FmPcd, uint16_t numOfSharedPlcrProfiles) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE); ++ ++ p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles = numOfSharedPlcrProfiles; ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_SetPlcrStatistics(t_Handle h_FmPcd, bool enable) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint32_t tmpReg32; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE); ++ ++ if (!FmIsMaster(p_FmPcd->h_Fm)) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_SetPlcrStatistics - guest mode!")); ++ ++ tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr); ++ if (enable) ++ tmpReg32 |= FM_PCD_PLCR_GCR_STEN; ++ else ++ tmpReg32 &= ~FM_PCD_PLCR_GCR_STEN; ++ ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr, tmpReg32); ++ return E_OK; ++} ++ ++t_Handle FM_PCD_PlcrProfileSet(t_Handle h_FmPcd, ++ t_FmPcdPlcrProfileParams *p_ProfileParams) ++{ ++ t_FmPcd *p_FmPcd; ++ t_FmPcdPlcrRegs *p_FmPcdPlcrRegs; ++ t_FmPcdPlcrProfileRegs plcrProfileReg; ++ uint32_t intFlags; ++ uint16_t absoluteProfileId; ++ t_Error err = E_OK; ++ uint32_t tmpReg32; ++ t_FmPcdPlcrProfile *p_Profile; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL); ++ ++ if (p_ProfileParams->modify) ++ { ++ p_Profile = (t_FmPcdPlcrProfile *)p_ProfileParams->id.h_Profile; ++ p_FmPcd = p_Profile->h_FmPcd; ++ absoluteProfileId = p_Profile->absoluteProfileId; ++ if (absoluteProfileId >= FM_PCD_PLCR_NUM_ENTRIES) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big ")); ++ return NULL; ++ } ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE, NULL); ++ ++ /* Try lock profile using flag */ ++ if (!PlcrProfileFlagTryLock(p_Profile)) ++ { ++ DBG(TRACE, ("Profile Try Lock - BUSY")); ++ /* Signal to caller BUSY condition */ ++ p_ProfileParams->id.h_Profile = NULL; ++ return NULL; ++ } ++ } ++ else ++ { ++ p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE, NULL); ++ ++ /* SMP: needs to be protected only if another core now changes the windows */ ++ err = FmPcdPlcrGetAbsoluteIdByProfileParams(h_FmPcd, ++ p_ProfileParams->id.newParams.profileType, ++ p_ProfileParams->id.newParams.h_FmPort, ++ p_ProfileParams->id.newParams.relativeProfileId, ++ &absoluteProfileId); ++ if (err) ++ { ++ REPORT_ERROR(MAJOR, err, NO_MSG); ++ return NULL; ++ } ++ ++ if (absoluteProfileId >= FM_PCD_PLCR_NUM_ENTRIES) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big ")); ++ return NULL; ++ } ++ ++ if (FmPcdPlcrIsProfileValid(p_FmPcd, absoluteProfileId)) ++ { ++ REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Policer Profile is already used")); ++ return NULL; ++ } ++ ++ /* initialize profile struct */ ++ p_Profile = &p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId]; ++ ++ p_Profile->h_FmPcd = p_FmPcd; ++ p_Profile->absoluteProfileId = absoluteProfileId; ++ ++ p_Profile->p_Lock = FmPcdAcquireLock(p_FmPcd); ++ if (!p_Profile->p_Lock) ++ REPORT_ERROR(MAJOR, E_NOT_AVAILABLE, ("FM Policer Profile lock obj!")); ++ } ++ ++ SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, NULL); ++ ++ p_Profile->nextEngineOnGreen = p_ProfileParams->nextEngineOnGreen; ++ memcpy(&p_Profile->paramsOnGreen, &(p_ProfileParams->paramsOnGreen), sizeof(u_FmPcdPlcrNextEngineParams)); ++ ++ p_Profile->nextEngineOnYellow = p_ProfileParams->nextEngineOnYellow; ++ memcpy(&p_Profile->paramsOnYellow, &(p_ProfileParams->paramsOnYellow), sizeof(u_FmPcdPlcrNextEngineParams)); ++ ++ p_Profile->nextEngineOnRed = p_ProfileParams->nextEngineOnRed; ++ memcpy(&p_Profile->paramsOnRed, &(p_ProfileParams->paramsOnRed), sizeof(u_FmPcdPlcrNextEngineParams)); ++ ++ memset(&plcrProfileReg, 0, sizeof(t_FmPcdPlcrProfileRegs)); ++ ++ /* build the policer profile registers */ ++ err = BuildProfileRegs(h_FmPcd, p_ProfileParams, &plcrProfileReg); ++ if (err) ++ { ++ REPORT_ERROR(MAJOR, err, NO_MSG); ++ if (p_ProfileParams->modify) ++ /* unlock */ ++ PlcrProfileFlagUnlock(p_Profile); ++ if (!p_ProfileParams->modify && ++ p_Profile->p_Lock) ++ /* release allocated Profile lock */ ++ FmPcdReleaseLock(p_FmPcd, p_Profile->p_Lock); ++ return NULL; ++ } ++ ++ if (p_FmPcd->h_Hc) ++ { ++ err = FmHcPcdPlcrSetProfile(p_FmPcd->h_Hc, (t_Handle)p_Profile, &plcrProfileReg); ++ if (p_ProfileParams->modify) ++ PlcrProfileFlagUnlock(p_Profile); ++ if (err) ++ { ++ /* release the allocated scheme lock */ ++ if (!p_ProfileParams->modify && ++ p_Profile->p_Lock) ++ FmPcdReleaseLock(p_FmPcd, p_Profile->p_Lock); ++ ++ return NULL; ++ } ++ if (!p_ProfileParams->modify) ++ FmPcdPlcrValidateProfileSw(p_FmPcd,absoluteProfileId); ++ return (t_Handle)p_Profile; ++ } ++ ++ p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; ++ SANITY_CHECK_RETURN_VALUE(p_FmPcdPlcrRegs, E_INVALID_HANDLE, NULL); ++ ++ intFlags = PlcrHwLock(p_FmPcd->p_FmPcdPlcr); ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pemode , plcrProfileReg.fmpl_pemode); ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia , plcrProfileReg.fmpl_pegnia); ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia , plcrProfileReg.fmpl_peynia); ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia , plcrProfileReg.fmpl_pernia); ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pecir , plcrProfileReg.fmpl_pecir); ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pecbs , plcrProfileReg.fmpl_pecbs); ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepepir_eir,plcrProfileReg.fmpl_pepepir_eir); ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepbs_ebs,plcrProfileReg.fmpl_pepbs_ebs); ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pelts , plcrProfileReg.fmpl_pelts); ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pects , plcrProfileReg.fmpl_pects); ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepts_ets,plcrProfileReg.fmpl_pepts_ets); ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc , plcrProfileReg.fmpl_pegpc); ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc , plcrProfileReg.fmpl_peypc); ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc , plcrProfileReg.fmpl_perpc); ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc , plcrProfileReg.fmpl_perypc); ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc , plcrProfileReg.fmpl_perrpc); ++ ++ tmpReg32 = FmPcdPlcrBuildWritePlcrActionRegs(absoluteProfileId); ++ WritePar(p_FmPcd, tmpReg32); ++ ++ PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); ++ ++ if (!p_ProfileParams->modify) ++ FmPcdPlcrValidateProfileSw(p_FmPcd,absoluteProfileId); ++ else ++ PlcrProfileFlagUnlock(p_Profile); ++ ++ return (t_Handle)p_Profile; ++} ++ ++t_Error FM_PCD_PlcrProfileDelete(t_Handle h_Profile) ++{ ++ t_FmPcdPlcrProfile *p_Profile = (t_FmPcdPlcrProfile*)h_Profile; ++ t_FmPcd *p_FmPcd; ++ uint16_t profileIndx; ++ uint32_t tmpReg32, intFlags; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Profile, E_INVALID_HANDLE); ++ p_FmPcd = p_Profile->h_FmPcd; ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ ++ profileIndx = p_Profile->absoluteProfileId; ++ ++ UpdateRequiredActionFlag(p_FmPcd, profileIndx, FALSE); ++ ++ FmPcdPlcrInvalidateProfileSw(p_FmPcd,profileIndx); ++ ++ if (p_FmPcd->h_Hc) ++ { ++ err = FmHcPcdPlcrDeleteProfile(p_FmPcd->h_Hc, h_Profile); ++ if (p_Profile->p_Lock) ++ /* release allocated Profile lock */ ++ FmPcdReleaseLock(p_FmPcd, p_Profile->p_Lock); ++ ++ return err; ++ } ++ ++ intFlags = PlcrHwLock(p_FmPcd->p_FmPcdPlcr); ++ WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->profileRegs.fmpl_pemode, ~FM_PCD_PLCR_PEMODE_PI); ++ ++ tmpReg32 = FmPcdPlcrBuildWritePlcrActionRegs(profileIndx); ++ WritePar(p_FmPcd, tmpReg32); ++ PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); ++ ++ ++ if (p_Profile->p_Lock) ++ /* release allocated Profile lock */ ++ FmPcdReleaseLock(p_FmPcd, p_Profile->p_Lock); ++ ++ /* we do not memset profile as all its fields are being re-initialized at "set", ++ * plus its allocation information is still valid. */ ++ return E_OK; ++} ++ ++/***************************************************/ ++/*............Policer Profile Counter..............*/ ++/***************************************************/ ++uint32_t FM_PCD_PlcrProfileGetCounter(t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter) ++{ ++ t_FmPcdPlcrProfile *p_Profile = (t_FmPcdPlcrProfile*)h_Profile; ++ t_FmPcd *p_FmPcd; ++ uint16_t profileIndx; ++ uint32_t intFlags, counterVal = 0; ++ t_FmPcdPlcrRegs *p_FmPcdPlcrRegs; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Profile, E_INVALID_HANDLE); ++ p_FmPcd = p_Profile->h_FmPcd; ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ ++ if (p_FmPcd->h_Hc) ++ return FmHcPcdPlcrGetProfileCounter(p_FmPcd->h_Hc, h_Profile, counter); ++ ++ p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; ++ SANITY_CHECK_RETURN_VALUE(p_FmPcdPlcrRegs, E_INVALID_HANDLE, 0); ++ ++ profileIndx = p_Profile->absoluteProfileId; ++ ++ if (profileIndx >= FM_PCD_PLCR_NUM_ENTRIES) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big ")); ++ return 0; ++ } ++ intFlags = PlcrHwLock(p_FmPcd->p_FmPcdPlcr); ++ WritePar(p_FmPcd, FmPcdPlcrBuildReadPlcrActionReg(profileIndx)); ++ ++ switch (counter) ++ { ++ case e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER: ++ counterVal = (GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc)); ++ break; ++ case e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER: ++ counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc); ++ break; ++ case e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER: ++ counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc); ++ break; ++ case e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER: ++ counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc); ++ break; ++ case e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER: ++ counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc); ++ break; ++ default: ++ REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ break; ++ } ++ PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); ++ ++ return counterVal; ++} ++ ++t_Error FM_PCD_PlcrProfileSetCounter(t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter, uint32_t value) ++{ ++ t_FmPcdPlcrProfile *p_Profile = (t_FmPcdPlcrProfile*)h_Profile; ++ t_FmPcd *p_FmPcd; ++ uint16_t profileIndx; ++ uint32_t tmpReg32, intFlags; ++ t_FmPcdPlcrRegs *p_FmPcdPlcrRegs; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Profile, E_INVALID_HANDLE); ++ ++ p_FmPcd = p_Profile->h_FmPcd; ++ profileIndx = p_Profile->absoluteProfileId; ++ ++ if (p_FmPcd->h_Hc) ++ return FmHcPcdPlcrSetProfileCounter(p_FmPcd->h_Hc, h_Profile, counter, value); ++ ++ p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; ++ SANITY_CHECK_RETURN_ERROR(p_FmPcdPlcrRegs, E_INVALID_HANDLE); ++ ++ intFlags = PlcrHwLock(p_FmPcd->p_FmPcdPlcr); ++ switch (counter) ++ { ++ case e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER: ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc, value); ++ break; ++ case e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER: ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc, value); ++ break; ++ case e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER: ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc, value); ++ break; ++ case e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER: ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc ,value); ++ break; ++ case e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER: ++ WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc ,value); ++ break; ++ default: ++ PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ ++ /* Activate the atomic write action by writing FMPL_PAR with: GO=1, RW=1, PSI=0, PNUM = ++ * Profile Number, PWSEL=0xFFFF (select all words). ++ */ ++ tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx); ++ tmpReg32 |= FmPcdPlcrBuildCounterProfileReg(counter); ++ WritePar(p_FmPcd, tmpReg32); ++ PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); ++ ++ return E_OK; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.h +new file mode 100644 +index 00000000..2bb8b969 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.h +@@ -0,0 +1,165 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_plcr.h ++ ++ @Description FM Policer private header ++*//***************************************************************************/ ++#ifndef __FM_PLCR_H ++#define __FM_PLCR_H ++ ++#include "std_ext.h" ++ ++ ++/***********************************************************************/ ++/* Policer defines */ ++/***********************************************************************/ ++ ++#define FM_PCD_PLCR_PAR_GO 0x80000000 ++#define FM_PCD_PLCR_PAR_PWSEL_MASK 0x0000FFFF ++#define FM_PCD_PLCR_PAR_R 0x40000000 ++ ++/* shifts */ ++#define FM_PCD_PLCR_PAR_PNUM_SHIFT 16 ++ ++/* masks */ ++#define FM_PCD_PLCR_PEMODE_PI 0x80000000 ++#define FM_PCD_PLCR_PEMODE_CBLND 0x40000000 ++#define FM_PCD_PLCR_PEMODE_ALG_MASK 0x30000000 ++#define FM_PCD_PLCR_PEMODE_ALG_RFC2698 0x10000000 ++#define FM_PCD_PLCR_PEMODE_ALG_RFC4115 0x20000000 ++#define FM_PCD_PLCR_PEMODE_DEFC_MASK 0x0C000000 ++#define FM_PCD_PLCR_PEMODE_DEFC_Y 0x04000000 ++#define FM_PCD_PLCR_PEMODE_DEFC_R 0x08000000 ++#define FM_PCD_PLCR_PEMODE_DEFC_OVERRIDE 0x0C000000 ++#define FM_PCD_PLCR_PEMODE_OVCLR_MASK 0x03000000 ++#define FM_PCD_PLCR_PEMODE_OVCLR_Y 0x01000000 ++#define FM_PCD_PLCR_PEMODE_OVCLR_R 0x02000000 ++#define FM_PCD_PLCR_PEMODE_OVCLR_G_NC 0x03000000 ++#define FM_PCD_PLCR_PEMODE_PKT 0x00800000 ++#define FM_PCD_PLCR_PEMODE_FPP_MASK 0x001F0000 ++#define FM_PCD_PLCR_PEMODE_FPP_SHIFT 16 ++#define FM_PCD_PLCR_PEMODE_FLS_MASK 0x0000F000 ++#define FM_PCD_PLCR_PEMODE_FLS_L2 0x00003000 ++#define FM_PCD_PLCR_PEMODE_FLS_L3 0x0000B000 ++#define FM_PCD_PLCR_PEMODE_FLS_L4 0x0000E000 ++#define FM_PCD_PLCR_PEMODE_FLS_FULL 0x0000F000 ++#define FM_PCD_PLCR_PEMODE_RBFLS 0x00000800 ++#define FM_PCD_PLCR_PEMODE_TRA 0x00000004 ++#define FM_PCD_PLCR_PEMODE_TRB 0x00000002 ++#define FM_PCD_PLCR_PEMODE_TRC 0x00000001 ++#define FM_PCD_PLCR_DOUBLE_ECC 0x80000000 ++#define FM_PCD_PLCR_INIT_ENTRY_ERROR 0x40000000 ++#define FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE 0x80000000 ++#define FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE 0x40000000 ++ ++#define FM_PCD_PLCR_NIA_VALID 0x80000000 ++ ++#define FM_PCD_PLCR_GCR_EN 0x80000000 ++#define FM_PCD_PLCR_GCR_STEN 0x40000000 ++#define FM_PCD_PLCR_GCR_DAR 0x20000000 ++#define FM_PCD_PLCR_GCR_DEFNIA 0x00FFFFFF ++#define FM_PCD_PLCR_NIA_ABS 0x00000100 ++ ++#define FM_PCD_PLCR_GSR_BSY 0x80000000 ++#define FM_PCD_PLCR_GSR_DQS 0x60000000 ++#define FM_PCD_PLCR_GSR_RPB 0x20000000 ++#define FM_PCD_PLCR_GSR_FQS 0x0C000000 ++#define FM_PCD_PLCR_GSR_LPALG 0x0000C000 ++#define FM_PCD_PLCR_GSR_LPCA 0x00003000 ++#define FM_PCD_PLCR_GSR_LPNUM 0x000000FF ++ ++#define FM_PCD_PLCR_EVR_PSIC 0x80000000 ++#define FM_PCD_PLCR_EVR_AAC 0x40000000 ++ ++#define FM_PCD_PLCR_PAR_PSI 0x20000000 ++#define FM_PCD_PLCR_PAR_PNUM 0x00FF0000 ++/* PWSEL Selctive select options */ ++#define FM_PCD_PLCR_PAR_PWSEL_PEMODE 0x00008000 /* 0 */ ++#define FM_PCD_PLCR_PAR_PWSEL_PEGNIA 0x00004000 /* 1 */ ++#define FM_PCD_PLCR_PAR_PWSEL_PEYNIA 0x00002000 /* 2 */ ++#define FM_PCD_PLCR_PAR_PWSEL_PERNIA 0x00001000 /* 3 */ ++#define FM_PCD_PLCR_PAR_PWSEL_PECIR 0x00000800 /* 4 */ ++#define FM_PCD_PLCR_PAR_PWSEL_PECBS 0x00000400 /* 5 */ ++#define FM_PCD_PLCR_PAR_PWSEL_PEPIR_EIR 0x00000200 /* 6 */ ++#define FM_PCD_PLCR_PAR_PWSEL_PEPBS_EBS 0x00000100 /* 7 */ ++#define FM_PCD_PLCR_PAR_PWSEL_PELTS 0x00000080 /* 8 */ ++#define FM_PCD_PLCR_PAR_PWSEL_PECTS 0x00000040 /* 9 */ ++#define FM_PCD_PLCR_PAR_PWSEL_PEPTS_ETS 0x00000020 /* 10 */ ++#define FM_PCD_PLCR_PAR_PWSEL_PEGPC 0x00000010 /* 11 */ ++#define FM_PCD_PLCR_PAR_PWSEL_PEYPC 0x00000008 /* 12 */ ++#define FM_PCD_PLCR_PAR_PWSEL_PERPC 0x00000004 /* 13 */ ++#define FM_PCD_PLCR_PAR_PWSEL_PERYPC 0x00000002 /* 14 */ ++#define FM_PCD_PLCR_PAR_PWSEL_PERRPC 0x00000001 /* 15 */ ++ ++#define FM_PCD_PLCR_PAR_PMR_BRN_1TO1 0x0000 /* - Full bit replacement. {PBNUM[0:N-1] ++ 1-> 2^N specific locations. */ ++#define FM_PCD_PLCR_PAR_PMR_BRN_2TO2 0x1 /* - {PBNUM[0:N-2],PNUM[N-1]}. ++ 2-> 2^(N-1) base locations. */ ++#define FM_PCD_PLCR_PAR_PMR_BRN_4TO4 0x2 /* - {PBNUM[0:N-3],PNUM[N-2:N-1]}. ++ 4-> 2^(N-2) base locations. */ ++#define FM_PCD_PLCR_PAR_PMR_BRN_8TO8 0x3 /* - {PBNUM[0:N-4],PNUM[N-3:N-1]}. ++ 8->2^(N-3) base locations. */ ++#define FM_PCD_PLCR_PAR_PMR_BRN_16TO16 0x4 /* - {PBNUM[0:N-5],PNUM[N-4:N-1]}. ++ 16-> 2^(N-4) base locations. */ ++#define FM_PCD_PLCR_PAR_PMR_BRN_32TO32 0x5 /* {PBNUM[0:N-6],PNUM[N-5:N-1]}. ++ 32-> 2^(N-5) base locations. */ ++#define FM_PCD_PLCR_PAR_PMR_BRN_64TO64 0x6 /* {PBNUM[0:N-7],PNUM[N-6:N-1]}. ++ 64-> 2^(N-6) base locations. */ ++#define FM_PCD_PLCR_PAR_PMR_BRN_128TO128 0x7 /* {PBNUM[0:N-8],PNUM[N-7:N-1]}. ++ 128-> 2^(N-7) base locations. */ ++#define FM_PCD_PLCR_PAR_PMR_BRN_256TO256 0x8 /* - No bit replacement for N=8. {PNUM[N-8:N-1]}. ++ When N=8 this option maps all 256 profiles by the DISPATCH bus into one group. */ ++ ++#define FM_PCD_PLCR_PMR_V 0x80000000 ++#define PLCR_ERR_ECC_CAP 0x80000000 ++#define PLCR_ERR_ECC_TYPE_DOUBLE 0x40000000 ++#define PLCR_ERR_ECC_PNUM_MASK 0x00000FF0 ++#define PLCR_ERR_ECC_OFFSET_MASK 0x0000000F ++ ++#define PLCR_ERR_UNINIT_CAP 0x80000000 ++#define PLCR_ERR_UNINIT_NUM_MASK 0x000000FF ++#define PLCR_ERR_UNINIT_PID_MASK 0x003f0000 ++#define PLCR_ERR_UNINIT_ABSOLUTE_MASK 0x00008000 ++ ++/* shifts */ ++#define PLCR_ERR_ECC_PNUM_SHIFT 4 ++#define PLCR_ERR_UNINIT_PID_SHIFT 16 ++ ++#define FM_PCD_PLCR_PMR_BRN_SHIFT 16 ++ ++#define PLCR_PORT_WINDOW_SIZE(hardwarePortId) ++ ++ ++#endif /* __FM_PLCR_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.c +new file mode 100644 +index 00000000..ff4f0a2f +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.c +@@ -0,0 +1,423 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_pcd.c ++ ++ @Description FM PCD ... ++*//***************************************************************************/ ++#include ++#include "std_ext.h" ++#include "error_ext.h" ++#include "string_ext.h" ++#include "debug_ext.h" ++#include "net_ext.h" ++ ++#include "fm_common.h" ++#include "fm_pcd.h" ++#include "fm_pcd_ipc.h" ++#include "fm_prs.h" ++#include "fsl_fman_prs.h" ++ ++ ++static void PcdPrsErrorException(t_Handle h_FmPcd) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ uint32_t event, ev_mask; ++ struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; ++ ++ ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); ++ ev_mask = fman_prs_get_err_ev_mask(PrsRegs); ++ ++ event = fman_prs_get_err_event(PrsRegs, ev_mask); ++ ++ fman_prs_ack_err_event(PrsRegs, event); ++ ++ DBG(TRACE, ("parser error - 0x%08x\n",event)); ++ ++ if(event & FM_PCD_PRS_DOUBLE_ECC) ++ p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC); ++} ++ ++static void PcdPrsException(t_Handle h_FmPcd) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ uint32_t event, ev_mask; ++ struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; ++ ++ ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); ++ ev_mask = fman_prs_get_expt_ev_mask(PrsRegs); ++ event = fman_prs_get_expt_event(PrsRegs, ev_mask); ++ ++ ASSERT_COND(event & FM_PCD_PRS_SINGLE_ECC); ++ ++ DBG(TRACE, ("parser event - 0x%08x\n",event)); ++ ++ fman_prs_ack_expt_event(PrsRegs, event); ++ ++ p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC); ++} ++ ++t_Handle PrsConfig(t_FmPcd *p_FmPcd,t_FmPcdParams *p_FmPcdParams) ++{ ++ t_FmPcdPrs *p_FmPcdPrs; ++ uintptr_t baseAddr; ++ ++ UNUSED(p_FmPcd); ++ UNUSED(p_FmPcdParams); ++ ++ p_FmPcdPrs = (t_FmPcdPrs *) XX_Malloc(sizeof(t_FmPcdPrs)); ++ if (!p_FmPcdPrs) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Parser structure allocation FAILED")); ++ return NULL; ++ } ++ memset(p_FmPcdPrs, 0, sizeof(t_FmPcdPrs)); ++ fman_prs_defconfig(&p_FmPcd->p_FmPcdDriverParam->dfltCfg); ++ ++ if (p_FmPcd->guestId == NCSW_MASTER_ID) ++ { ++ baseAddr = FmGetPcdPrsBaseAddr(p_FmPcdParams->h_Fm); ++ p_FmPcdPrs->p_SwPrsCode = (uint32_t *)UINT_TO_PTR(baseAddr); ++ p_FmPcdPrs->p_FmPcdPrsRegs = (struct fman_prs_regs *)UINT_TO_PTR(baseAddr + PRS_REGS_OFFSET); ++ } ++ ++ p_FmPcdPrs->fmPcdPrsPortIdStatistics = p_FmPcd->p_FmPcdDriverParam->dfltCfg.port_id_stat; ++ p_FmPcd->p_FmPcdDriverParam->prsMaxParseCycleLimit = p_FmPcd->p_FmPcdDriverParam->dfltCfg.max_prs_cyc_lim; ++ p_FmPcd->exceptions |= p_FmPcd->p_FmPcdDriverParam->dfltCfg.prs_exceptions; ++ ++ return p_FmPcdPrs; ++} ++ ++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) ++ static uint8_t swPrsPatch[] = SW_PRS_UDP_LITE_PATCH; ++#else ++ static uint8_t swPrsPatch[] = SW_PRS_OFFLOAD_PATCH; ++#endif /* FM_CAPWAP_SUPPORT */ ++ ++t_Error PrsInit(t_FmPcd *p_FmPcd) ++{ ++ t_FmPcdDriverParam *p_Param = p_FmPcd->p_FmPcdDriverParam; ++ uint32_t *p_TmpCode; ++ uint32_t *p_LoadTarget = (uint32_t *)PTR_MOVE(p_FmPcd->p_FmPcdPrs->p_SwPrsCode, ++ FM_PCD_SW_PRS_SIZE-FM_PCD_PRS_SW_PATCHES_SIZE); ++ struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; ++ uint32_t i; ++ ++ ASSERT_COND(sizeof(swPrsPatch) <= (FM_PCD_PRS_SW_PATCHES_SIZE-FM_PCD_PRS_SW_TAIL_SIZE)); ++ ++ /* nothing to do in guest-partition */ ++ if (p_FmPcd->guestId != NCSW_MASTER_ID) ++ return E_OK; ++ ++ p_TmpCode = (uint32_t *)XX_MallocSmart(ROUND_UP(sizeof(swPrsPatch),4), 0, sizeof(uint32_t)); ++ if (!p_TmpCode) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Tmp Sw-Parser code allocation FAILED")); ++ memset((uint8_t *)p_TmpCode, 0, ROUND_UP(sizeof(swPrsPatch),4)); ++ memcpy((uint8_t *)p_TmpCode, (uint8_t *)swPrsPatch, sizeof(swPrsPatch)); ++ ++ fman_prs_init(PrsRegs, &p_Param->dfltCfg); ++ ++ /* register even if no interrupts enabled, to allow future enablement */ ++ FmRegisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_ERR, PcdPrsErrorException, p_FmPcd); ++ ++ /* register even if no interrupts enabled, to allow future enablement */ ++ FmRegisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_NORMAL, PcdPrsException, p_FmPcd); ++ ++ if(p_FmPcd->exceptions & FM_PCD_EX_PRS_SINGLE_ECC) ++ FmEnableRamsEcc(p_FmPcd->h_Fm); ++ ++ if(p_FmPcd->exceptions & FM_PCD_EX_PRS_DOUBLE_ECC) ++ FmEnableRamsEcc(p_FmPcd->h_Fm); ++ ++ /* load sw parser Ip-Frag patch */ ++ for (i=0; iguestId == NCSW_MASTER_ID); ++ FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_ERR); ++ /* register even if no interrupts enabled, to allow future enablement */ ++ FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_NORMAL); ++} ++ ++void PrsEnable(t_FmPcd *p_FmPcd) ++{ ++ struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; ++ ++ ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); ++ fman_prs_enable(PrsRegs); ++} ++ ++void PrsDisable(t_FmPcd *p_FmPcd) ++{ ++ struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; ++ ++ ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); ++ fman_prs_disable(PrsRegs); ++} ++ ++int PrsIsEnabled(t_FmPcd *p_FmPcd) ++{ ++ struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; ++ ++ ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); ++ return fman_prs_is_enabled(PrsRegs); ++} ++ ++t_Error PrsIncludePortInStatistics(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, bool include) ++{ ++ struct fman_prs_regs *PrsRegs; ++ uint32_t bitMask = 0; ++ uint8_t prsPortId; ++ ++ SANITY_CHECK_RETURN_ERROR((hardwarePortId >=1 && hardwarePortId <= 16), E_INVALID_VALUE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPrs, E_INVALID_HANDLE); ++ ++ PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; ++ ++ GET_FM_PCD_PRS_PORT_ID(prsPortId, hardwarePortId); ++ GET_FM_PCD_INDEX_FLAG(bitMask, prsPortId); ++ ++ if (include) ++ p_FmPcd->p_FmPcdPrs->fmPcdPrsPortIdStatistics |= bitMask; ++ else ++ p_FmPcd->p_FmPcdPrs->fmPcdPrsPortIdStatistics &= ~bitMask; ++ ++ fman_prs_set_stst_port_msk(PrsRegs, ++ p_FmPcd->p_FmPcdPrs->fmPcdPrsPortIdStatistics); ++ ++ return E_OK; ++} ++ ++t_Error FmPcdPrsIncludePortInStatistics(t_Handle h_FmPcd, uint8_t hardwarePortId, bool include) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR((hardwarePortId >=1 && hardwarePortId <= 16), E_INVALID_VALUE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPrs, E_INVALID_HANDLE); ++ ++ if ((p_FmPcd->guestId != NCSW_MASTER_ID) && ++ p_FmPcd->h_IpcSession) ++ { ++ t_FmPcdIpcPrsIncludePort prsIncludePortParams; ++ t_FmPcdIpcMsg msg; ++ ++ prsIncludePortParams.hardwarePortId = hardwarePortId; ++ prsIncludePortParams.include = include; ++ memset(&msg, 0, sizeof(msg)); ++ msg.msgId = FM_PCD_PRS_INC_PORT_STATS; ++ memcpy(msg.msgBody, &prsIncludePortParams, sizeof(prsIncludePortParams)); ++ err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) +sizeof(prsIncludePortParams), ++ NULL, ++ NULL, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ return E_OK; ++ } ++ else if (p_FmPcd->guestId != NCSW_MASTER_ID) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("running in guest-mode without IPC!")); ++ ++ return PrsIncludePortInStatistics(p_FmPcd, hardwarePortId, include); ++} ++ ++uint32_t FmPcdGetSwPrsOffset(t_Handle h_FmPcd, e_NetHeaderType hdr, uint8_t indexPerHdr) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; ++ t_FmPcdPrsLabelParams *p_Label; ++ int i; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, 0); ++ SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE, 0); ++ ++ if ((p_FmPcd->guestId != NCSW_MASTER_ID) && ++ p_FmPcd->h_IpcSession) ++ { ++ t_Error err = E_OK; ++ t_FmPcdIpcSwPrsLable labelParams; ++ t_FmPcdIpcMsg msg; ++ uint32_t prsOffset = 0; ++ t_FmPcdIpcReply reply; ++ uint32_t replyLength; ++ ++ memset(&reply, 0, sizeof(reply)); ++ memset(&msg, 0, sizeof(msg)); ++ labelParams.enumHdr = (uint32_t)hdr; ++ labelParams.indexPerHdr = indexPerHdr; ++ msg.msgId = FM_PCD_GET_SW_PRS_OFFSET; ++ memcpy(msg.msgBody, &labelParams, sizeof(labelParams)); ++ replyLength = sizeof(uint32_t) + sizeof(uint32_t); ++ err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) +sizeof(labelParams), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ if (replyLength != sizeof(uint32_t) + sizeof(uint32_t)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ ++ memcpy((uint8_t*)&prsOffset, reply.replyBody, sizeof(uint32_t)); ++ return prsOffset; ++ } ++ else if (p_FmPcd->guestId != NCSW_MASTER_ID) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("running in guest-mode without IPC!")); ++ ++ ASSERT_COND(p_FmPcd->p_FmPcdPrs->currLabel < FM_PCD_PRS_NUM_OF_LABELS); ++ ++ for (i=0; ip_FmPcdPrs->currLabel; i++) ++ { ++ p_Label = &p_FmPcd->p_FmPcdPrs->labelsTable[i]; ++ ++ if ((hdr == p_Label->hdr) && (indexPerHdr == p_Label->indexPerHdr)) ++ return p_Label->instructionOffset; ++ } ++ ++ REPORT_ERROR(MAJOR, E_NOT_FOUND, ("Sw Parser attachment Not found")); ++ return (uint32_t)ILLEGAL_BASE; ++} ++ ++void FM_PCD_SetPrsStatistics(t_Handle h_FmPcd, bool enable) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ struct fman_prs_regs *PrsRegs; ++ ++ SANITY_CHECK_RETURN(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN(p_FmPcd->p_FmPcdPrs, E_INVALID_HANDLE); ++ ++ PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; ++ ++ ++ if(p_FmPcd->guestId != NCSW_MASTER_ID) ++ { ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_SetPrsStatistics - guest mode!")); ++ return; ++ } ++ ++ fman_prs_set_stst(PrsRegs, enable); ++} ++ ++t_Error FM_PCD_PrsLoadSw(t_Handle h_FmPcd, t_FmPcdPrsSwParams *p_SwPrs) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ uint32_t *p_LoadTarget; ++ uint32_t *p_TmpCode; ++ int i; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPrs, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_SwPrs, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPcd->enabled, E_INVALID_HANDLE); ++ ++ if (p_FmPcd->guestId != NCSW_MASTER_ID) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM in guest-mode!")); ++ ++ if (!p_SwPrs->override) ++ { ++ if(p_FmPcd->p_FmPcdPrs->p_CurrSwPrs > p_FmPcd->p_FmPcdPrs->p_SwPrsCode + p_SwPrs->base*2/4) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("SW parser base must be larger than current loaded code")); ++ } ++ else ++ p_FmPcd->p_FmPcdPrs->currLabel = 0; ++ ++ if (p_SwPrs->size > FM_PCD_SW_PRS_SIZE - FM_PCD_PRS_SW_TAIL_SIZE - p_SwPrs->base*2) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("p_SwPrs->size may not be larger than MAX_SW_PRS_CODE_SIZE")); ++ ++ if (p_FmPcd->p_FmPcdPrs->currLabel + p_SwPrs->numOfLabels > FM_PCD_PRS_NUM_OF_LABELS) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceeded number of labels allowed ")); ++ ++ p_TmpCode = (uint32_t *)XX_MallocSmart(ROUND_UP(p_SwPrs->size,4), 0, sizeof(uint32_t)); ++ if (!p_TmpCode) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Tmp Sw-Parser code allocation FAILED")); ++ memset((uint8_t *)p_TmpCode, 0, ROUND_UP(p_SwPrs->size,4)); ++ memcpy((uint8_t *)p_TmpCode, p_SwPrs->p_Code, p_SwPrs->size); ++ ++ /* save sw parser labels */ ++ memcpy(&p_FmPcd->p_FmPcdPrs->labelsTable[p_FmPcd->p_FmPcdPrs->currLabel], ++ p_SwPrs->labelsTable, ++ p_SwPrs->numOfLabels*sizeof(t_FmPcdPrsLabelParams)); ++ p_FmPcd->p_FmPcdPrs->currLabel += p_SwPrs->numOfLabels; ++ ++ /* load sw parser code */ ++ p_LoadTarget = p_FmPcd->p_FmPcdPrs->p_SwPrsCode + p_SwPrs->base*2/4; ++ ++ for(i=0; isize, 4); i++) ++ WRITE_UINT32(p_LoadTarget[i], GET_UINT32(p_TmpCode[i])); ++ ++ p_FmPcd->p_FmPcdPrs->p_CurrSwPrs = ++ p_FmPcd->p_FmPcdPrs->p_SwPrsCode + p_SwPrs->base*2/4 + ROUND_UP(p_SwPrs->size,4); ++ ++ /* copy data parameters */ ++ for (i=0;ip_FmPcdPrs->p_SwPrsCode+PRS_SW_DATA/4+i), p_SwPrs->swPrsDataParams[i]); ++ ++ /* Clear last 4 bytes */ ++ WRITE_UINT32(*(p_FmPcd->p_FmPcdPrs->p_SwPrsCode+(PRS_SW_DATA-FM_PCD_PRS_SW_TAIL_SIZE)/4), 0); ++ ++ XX_FreeSmart(p_TmpCode); ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_ConfigPrsMaxCycleLimit(t_Handle h_FmPcd,uint16_t value) ++{ ++ t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); ++ ++ if(p_FmPcd->guestId != NCSW_MASTER_ID) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ConfigPrsMaxCycleLimit - guest mode!")); ++ ++ p_FmPcd->p_FmPcdDriverParam->prsMaxParseCycleLimit = value; ++ ++ return E_OK; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.h +new file mode 100644 +index 00000000..056f225e +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.h +@@ -0,0 +1,316 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_prs.h ++ ++ @Description FM Parser private header ++ *//***************************************************************************/ ++#ifndef __FM_PRS_H ++#define __FM_PRS_H ++ ++#include "std_ext.h" ++ ++/***********************************************************************/ ++/* SW parser IP_FRAG patch */ ++/***********************************************************************/ ++ ++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) ++#define SW_PRS_UDP_LITE_PATCH \ ++{\ ++ 0x31,0x52,0x00,0xDA,0xFC,0x00,0x00,0x00,0x00,0x00, \ ++ 0x00,0x00,0x50,0x2C,0x40,0x00,0x31,0x92,0x50,0x2C, \ ++ 0x00,0x88,0x18,0x2F,0x00,0x01,0x1B,0xFE,0x18,0x71, \ ++ 0x02,0x1F,0x00,0x08,0x00,0x83,0x02,0x1F,0x00,0x20, \ ++ 0x28,0x1B,0x00,0x05,0x29,0x1F,0x30,0xD0,0x60,0x4F, \ ++ 0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F,0x00,0x52, \ ++ 0x00,0x01,0x07,0x01,0x60,0x3B,0x00,0x00,0x30,0xD0, \ ++ 0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, \ ++ 0x40,0x4C,0x00,0x00,0x02,0x8F,0x00,0x00,0x30,0xF2, \ ++ 0x00,0x06,0x18,0x5D,0x00,0x00,0x9F,0xFF,0x30,0xF2, \ ++ 0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0,0x00,0x52, \ ++ 0x00,0x08,0x28,0x1A,0x60,0x37,0x00,0x00,0x30,0xF2, \ ++ 0x18,0x5D,0x06,0x00,0x29,0x1E,0x30,0xF2,0x2F,0x0E, \ ++ 0x30,0x72,0x00,0x00,0x9B,0x8F,0x00,0x06,0x2F,0x0E, \ ++ 0x32,0xF1,0x32,0xB0,0x00,0x4F,0x00,0x57,0x00,0x28, \ ++ 0x00,0x00,0x97,0x9E,0x00,0x4E,0x30,0x72,0x00,0x06, \ ++ 0x2F,0x0E,0x32,0xC1,0x32,0xF0,0x00,0x4A,0x00,0x80, \ ++ 0x00,0x02,0x00,0x00,0x97,0x9E,0x40,0x7E,0x00,0x08, \ ++ 0x08,0x16,0x00,0x54,0x00,0x01,0x1B,0xFE,0x00,0x00, \ ++ 0x9F,0x9E,0x40,0xB3,0x00,0x00,0x02,0x1F,0x00,0x08, \ ++ 0x28,0x1B,0x30,0x73,0x29,0x1F,0x30,0xD0,0x60,0x9F, \ ++ 0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F,0x00,0x52, \ ++ 0x00,0x01,0x07,0x01,0x60,0x8B,0x00,0x00,0x30,0xD0, \ ++ 0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, \ ++ 0x40,0x9C,0x00,0x00,0x02,0x8F,0x00,0x00,0x30,0xF2, \ ++ 0x00,0x06,0x18,0xAD,0x00,0x00,0x9F,0xFF,0x30,0xF2, \ ++ 0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0,0x00,0x52, \ ++ 0x00,0x08,0x28,0x1A,0x60,0x87,0x00,0x00,0x30,0xF2, \ ++ 0x18,0xAD,0x06,0x00,0x29,0x1E,0x30,0xF2,0x50,0xB3, \ ++ 0xFF,0xFF,0x18,0xB8,0x08,0x16,0x00,0x54,0x00,0x01, \ ++ 0x1B,0xFE,0x18,0xC5,0x32,0xF1,0x28,0x5D,0x32,0xF1, \ ++ 0x00,0x55,0x00,0x08,0x28,0x5F,0x00,0x00,0x8F,0x9F, \ ++ 0x29,0x33,0x08,0x16,0x00,0x49,0x00,0x01,0x1B,0xFF, \ ++ 0x00,0x01,0x1B,0xFF \ ++} ++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ ++ ++#if (DPAA_VERSION == 10) ++/* Version: 106.1.9 */ ++#define SW_PRS_OFFLOAD_PATCH \ ++{ \ ++ 0x31,0x52,0x00,0xDA,0x0A,0x00,0x00,0x00,0x00,0x00, \ ++ 0x00,0x00,0x43,0x0A,0x00,0x00,0x00,0x01,0x1B,0xFE, \ ++ 0x00,0x00,0x99,0x00,0x53,0x13,0x00,0x00,0x00,0x00, \ ++ 0x9F,0x98,0x53,0x13,0x00,0x00,0x1B,0x23,0x33,0xF1, \ ++ 0x00,0xF9,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, \ ++ 0x28,0x7F,0x00,0x03,0x00,0x02,0x00,0x00,0x00,0x01, \ ++ 0x32,0xC1,0x32,0xF0,0x00,0x4A,0x00,0x80,0x1F,0xFF, \ ++ 0x00,0x01,0x1B,0xFE,0x31,0x52,0x00,0xDA,0x06,0x00, \ ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x43,0x2F,0x00,0x00, \ ++ 0x00,0x01,0x1B,0xFE,0x31,0x52,0x00,0xDA,0x00,0x40, \ ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x53,0x95,0x00,0x00, \ ++ 0x00,0x00,0x9B,0x8F,0x2F,0x0F,0x32,0xC1,0x00,0x55, \ ++ 0x00,0x28,0x28,0x43,0x30,0x7E,0x43,0x45,0x00,0x00, \ ++ 0x30,0x7E,0x43,0x45,0x00,0x3C,0x1B,0x5D,0x32,0x11, \ ++ 0x32,0xC0,0x00,0x4F,0x00,0x81,0x00,0x00,0x83,0x8F, \ ++ 0x2F,0x0F,0x06,0x00,0x32,0x11,0x32,0xC0,0x00,0x4F, \ ++ 0x00,0x55,0x00,0x01,0x00,0x81,0x32,0x11,0x00,0x00, \ ++ 0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04,0x00,0x4D, \ ++ 0x28,0x43,0x06,0x00,0x1B,0x3E,0x30,0x7E,0x53,0x79, \ ++ 0x00,0x2B,0x32,0x11,0x32,0xC0,0x00,0x4F,0x00,0x81, \ ++ 0x00,0x00,0x87,0x8F,0x28,0x23,0x06,0x00,0x32,0x11, \ ++ 0x32,0xC0,0x00,0x4F,0x00,0x55,0x00,0x01,0x00,0x81, \ ++ 0x32,0x11,0x00,0x00,0x83,0x8E,0x00,0x50,0x00,0x01, \ ++ 0x01,0x04,0x00,0x4D,0x28,0x43,0x06,0x00,0x00,0x01, \ ++ 0x1B,0xFE,0x00,0x00,0x9B,0x8E,0x53,0x90,0x00,0x00, \ ++ 0x06,0x29,0x00,0x00,0x83,0x8F,0x28,0x23,0x06,0x00, \ ++ 0x06,0x29,0x32,0xC1,0x00,0x55,0x00,0x28,0x00,0x00, \ ++ 0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04,0x00,0x4D, \ ++ 0x28,0x43,0x06,0x00,0x00,0x01,0x1B,0xFE,0x32,0xC1, \ ++ 0x00,0x55,0x00,0x28,0x28,0x43,0x1B,0xCF,0x00,0x00, \ ++ 0x9B,0x8F,0x2F,0x0F,0x32,0xC1,0x00,0x55,0x00,0x28, \ ++ 0x28,0x43,0x30,0x7E,0x43,0xBF,0x00,0x2C,0x32,0x11, \ ++ 0x32,0xC0,0x00,0x4F,0x00,0x81,0x00,0x00,0x87,0x8F, \ ++ 0x28,0x23,0x06,0x00,0x32,0x11,0x32,0xC0,0x00,0x4F, \ ++ 0x00,0x81,0x00,0x00,0x83,0x8F,0x2F,0x0F,0x06,0x00, \ ++ 0x32,0x11,0x32,0xC0,0x00,0x4F,0x00,0x55,0x00,0x01, \ ++ 0x00,0x81,0x32,0x11,0x00,0x00,0x83,0x8E,0x00,0x50, \ ++ 0x00,0x01,0x01,0x04,0x00,0x4D,0x28,0x43,0x06,0x00, \ ++ 0x1B,0x9C,0x33,0xF1,0x00,0xF9,0x00,0x01,0x00,0x00, \ ++ 0x00,0x00,0x00,0x00,0x28,0x7F,0x00,0x03,0x00,0x02, \ ++ 0x00,0x00,0x00,0x01,0x32,0xC1,0x32,0xF0,0x00,0x4A, \ ++ 0x00,0x80,0x1F,0xFF,0x00,0x01,0x1B,0xFE, \ ++} ++ ++#else ++#define SW_PRS_OFFLOAD_PATCH \ ++{ \ ++ 0x31,0x52,0x00,0xDA,0x0E,0x4F,0x00,0x00,0x00,0x00, \ ++ 0x00,0x00,0x51,0x16,0x08,0x4B,0x31,0x53,0x00,0xFB, \ ++ 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x29,0x2B, \ ++ 0x33,0xF1,0x00,0xFB,0x00,0xDF,0x00,0x00,0x00,0x00, \ ++ 0x00,0x00,0x28,0x7F,0x31,0x52,0x00,0xDA,0x0A,0x00, \ ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x20,0x00,0x00, \ ++ 0x00,0x01,0x1B,0xFE,0x00,0x00,0x99,0x00,0x51,0x29, \ ++ 0x00,0x00,0x00,0x00,0x9F,0x98,0x51,0x29,0x00,0x00, \ ++ 0x19,0x44,0x09,0x5F,0x00,0x20,0x00,0x00,0x09,0x4F, \ ++ 0x00,0x20,0x00,0x00,0x34,0xB7,0x00,0xF9,0x00,0x00, \ ++ 0x01,0x00,0x00,0x00,0x00,0x00,0x2B,0x97,0x31,0xB3, \ ++ 0x29,0x8F,0x33,0xF1,0x00,0xF9,0x00,0x01,0x00,0x00, \ ++ 0x00,0x00,0x00,0x00,0x28,0x7F,0x00,0x03,0x00,0x02, \ ++ 0x00,0x00,0x00,0x01,0x1B,0xFE,0x00,0x01,0x1B,0xFE, \ ++ 0x31,0x52,0x00,0xDA,0xFC,0x00,0x00,0x00,0x00,0x00, \ ++ 0x00,0x00,0x51,0x52,0x40,0x00,0x31,0x92,0x51,0x52, \ ++ 0x00,0x88,0x19,0x55,0x08,0x05,0x00,0x00,0x19,0x99, \ ++ 0x02,0x1F,0x00,0x08,0x00,0x83,0x02,0x1F,0x00,0x20, \ ++ 0x28,0x1B,0x00,0x05,0x29,0x1F,0x30,0xD0,0x61,0x75, \ ++ 0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F,0x00,0x52, \ ++ 0x00,0x01,0x07,0x01,0x61,0x61,0x00,0x00,0x30,0xD0, \ ++ 0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, \ ++ 0x41,0x72,0x00,0x00,0x02,0x8F,0x00,0x00,0x30,0xF2, \ ++ 0x00,0x06,0x19,0x83,0x00,0x00,0x9F,0xFF,0x30,0xF2, \ ++ 0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0,0x00,0x52, \ ++ 0x00,0x08,0x28,0x1A,0x61,0x5D,0x00,0x00,0x30,0xF2, \ ++ 0x19,0x83,0x06,0x00,0x29,0x1E,0x30,0xF2,0x29,0x0E, \ ++ 0x30,0x72,0x00,0x00,0x9B,0x8F,0x00,0x06,0x29,0x0E, \ ++ 0x32,0xF1,0x32,0xB0,0x00,0x4F,0x00,0x57,0x00,0x28, \ ++ 0x00,0x00,0x97,0x9E,0x00,0x4E,0x30,0x72,0x00,0x06, \ ++ 0x29,0x0E,0x08,0x05,0x00,0x01,0x31,0x52,0x00,0xDA, \ ++ 0x0E,0x4F,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0xAF, \ ++ 0x04,0x4B,0x31,0x53,0x00,0xFB,0xFF,0xF0,0x00,0x00, \ ++ 0x00,0x00,0x00,0x00,0x29,0x2B,0x33,0xF1,0x00,0xFB, \ ++ 0x00,0xDF,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x7F, \ ++ 0x31,0x52,0x00,0xDA,0x06,0x00,0x00,0x00,0x00,0x00, \ ++ 0x00,0x00,0x41,0xB9,0x00,0x00,0x00,0x01,0x1B,0xFE, \ ++ 0x31,0x52,0x00,0xDA,0x00,0x40,0x00,0x00,0x00,0x00, \ ++ 0x00,0x00,0x42,0x06,0x00,0x00,0x00,0x00,0x9B,0x8F, \ ++ 0x28,0x01,0x32,0xC1,0x00,0x55,0x00,0x28,0x28,0x43, \ ++ 0x30,0x00,0x41,0xEB,0x00,0x2C,0x32,0x11,0x32,0xC0, \ ++ 0x00,0x4F,0x00,0x81,0x00,0x00,0x87,0x8F,0x28,0x23, \ ++ 0x06,0x00,0x32,0x11,0x32,0xC0,0x00,0x4F,0x00,0x81, \ ++ 0x00,0x00,0x83,0x8F,0x28,0x01,0x06,0x00,0x32,0x11, \ ++ 0x32,0xC0,0x00,0x4F,0x00,0x55,0x00,0x01,0x00,0x81, \ ++ 0x32,0x11,0x00,0x00,0x83,0x8E,0x00,0x50,0x00,0x01, \ ++ 0x01,0x04,0x00,0x4D,0x28,0x43,0x06,0x00,0x19,0xC8, \ ++ 0x09,0x5F,0x00,0x20,0x00,0x00,0x09,0x4F,0x00,0x20, \ ++ 0x00,0x00,0x34,0xB7,0x00,0xF9,0x00,0x00,0x01,0x00, \ ++ 0x00,0x00,0x00,0x00,0x2B,0x97,0x31,0xB3,0x29,0x8F, \ ++ 0x33,0xF1,0x00,0xF9,0x00,0x01,0x00,0x00,0x00,0x00, \ ++ 0x00,0x00,0x28,0x7F,0x00,0x03,0x00,0x02,0x00,0x00, \ ++ 0x00,0x01,0x1B,0xFE,0x30,0x50,0x52,0x0B,0x00,0x00, \ ++ 0x00,0x01,0x1B,0xFE,0x32,0xF1,0x32,0xC0,0x00,0x4F, \ ++ 0x00,0x81,0x00,0x02,0x00,0x00,0x97,0x9E,0x42,0x18, \ ++ 0x00,0x08,0x08,0x16,0x00,0x54,0x00,0x01,0x1B,0xFE, \ ++ 0x00,0x00,0x9F,0x9E,0x42,0x4D,0x00,0x00,0x02,0x1F, \ ++ 0x00,0x08,0x28,0x1B,0x30,0x73,0x29,0x1F,0x30,0xD0, \ ++ 0x62,0x39,0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F, \ ++ 0x00,0x52,0x00,0x01,0x07,0x01,0x62,0x25,0x00,0x00, \ ++ 0x30,0xD0,0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00, \ ++ 0x00,0x00,0x42,0x36,0x00,0x00,0x02,0x8F,0x00,0x00, \ ++ 0x30,0xF2,0x00,0x06,0x1A,0x47,0x00,0x00,0x9F,0xFF, \ ++ 0x30,0xF2,0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0, \ ++ 0x00,0x52,0x00,0x08,0x28,0x1A,0x62,0x21,0x00,0x00, \ ++ 0x30,0xF2,0x1A,0x47,0x06,0x00,0x29,0x1E,0x30,0xF2, \ ++ 0x52,0x4D,0xFF,0xFF,0x1A,0x52,0x08,0x16,0x00,0x54, \ ++ 0x00,0x01,0x1B,0xFE,0x1A,0x5F,0x32,0xF1,0x28,0x5D, \ ++ 0x32,0xF1,0x00,0x55,0x00,0x08,0x28,0x5F,0x00,0x00, \ ++ 0x8F,0x9F,0x29,0x33,0x08,0x16,0x00,0x49,0x00,0x01, \ ++ 0x1B,0xFF,0x00,0x01,0x1B,0xFF,0x31,0x52,0x00,0xDA, \ ++ 0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x6D, \ ++ 0x40,0x00,0x31,0x92,0x52,0x6D,0x00,0x88,0x1A,0x70, \ ++ 0x08,0x05,0x00,0x00,0x1A,0xB4,0x02,0x1F,0x00,0x08, \ ++ 0x00,0x83,0x02,0x1F,0x00,0x20,0x28,0x1B,0x00,0x05, \ ++ 0x29,0x1F,0x30,0xD0,0x62,0x90,0x00,0x07,0x00,0x05, \ ++ 0x00,0x00,0xC3,0x8F,0x00,0x52,0x00,0x01,0x07,0x01, \ ++ 0x62,0x7C,0x00,0x00,0x30,0xD0,0x00,0xDA,0x00,0x01, \ ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x8D,0x00,0x00, \ ++ 0x02,0x8F,0x00,0x00,0x30,0xF2,0x00,0x06,0x1A,0x9E, \ ++ 0x00,0x00,0x9F,0xFF,0x30,0xF2,0x00,0x06,0x29,0x1E, \ ++ 0x07,0x08,0x30,0xD0,0x00,0x52,0x00,0x08,0x28,0x1A, \ ++ 0x62,0x78,0x00,0x00,0x30,0xF2,0x1A,0x9E,0x06,0x00, \ ++ 0x29,0x1E,0x30,0xF2,0x29,0x0E,0x30,0x72,0x00,0x00, \ ++ 0x9B,0x8F,0x00,0x06,0x29,0x0E,0x32,0xF1,0x32,0xB0, \ ++ 0x00,0x4F,0x00,0x57,0x00,0x28,0x00,0x00,0x97,0x9E, \ ++ 0x00,0x4E,0x30,0x72,0x00,0x06,0x29,0x0E,0x08,0x05, \ ++ 0x00,0x01,0x31,0x52,0x00,0xDA,0x0E,0x4F,0x00,0x00, \ ++ 0x00,0x00,0x00,0x00,0x52,0xCA,0x04,0x4B,0x31,0x53, \ ++ 0x00,0xFB,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00, \ ++ 0x29,0x2B,0x33,0xF1,0x00,0xFB,0x00,0xDF,0x00,0x00, \ ++ 0x00,0x00,0x00,0x00,0x28,0x7F,0x31,0x52,0x00,0xDA, \ ++ 0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0xD4, \ ++ 0x00,0x00,0x00,0x01,0x1B,0xFE,0x31,0x52,0x00,0xDA, \ ++ 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x53,0x37, \ ++ 0x00,0x00,0x00,0x00,0x9B,0x8F,0x28,0x01,0x32,0xC1, \ ++ 0x00,0x55,0x00,0x28,0x28,0x43,0x30,0x00,0x42,0xEA, \ ++ 0x00,0x00,0x30,0x00,0x42,0xEA,0x00,0x3C,0x1B,0x02, \ ++ 0x32,0x11,0x32,0xC0,0x00,0x4F,0x00,0x81,0x00,0x00, \ ++ 0x83,0x8F,0x28,0x01,0x06,0x00,0x32,0x11,0x32,0xC0, \ ++ 0x00,0x4F,0x00,0x55,0x00,0x01,0x00,0x81,0x32,0x11, \ ++ 0x00,0x00,0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04, \ ++ 0x00,0x4D,0x28,0x43,0x06,0x00,0x1A,0xE3,0x30,0x00, \ ++ 0x43,0x20,0x00,0x2B,0x00,0x00,0x9B,0x8E,0x43,0x0E, \ ++ 0x00,0x00,0x32,0xC1,0x00,0x55,0x00,0x28,0x28,0x43, \ ++ 0x1B,0x1F,0x06,0x29,0x00,0x00,0x83,0x8F,0x28,0x23, \ ++ 0x06,0x00,0x06,0x29,0x32,0xC1,0x00,0x55,0x00,0x28, \ ++ 0x00,0x00,0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04, \ ++ 0x00,0x4D,0x28,0x43,0x06,0x00,0x1B,0x37,0x32,0x11, \ ++ 0x32,0xC0,0x00,0x4F,0x00,0x81,0x00,0x00,0x87,0x8F, \ ++ 0x28,0x23,0x06,0x00,0x32,0x11,0x32,0xC0,0x00,0x4F, \ ++ 0x00,0x55,0x00,0x01,0x00,0x81,0x32,0x11,0x00,0x00, \ ++ 0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04,0x00,0x4D, \ ++ 0x28,0x43,0x06,0x00,0x30,0x50,0x53,0x3C,0x00,0x00, \ ++ 0x00,0x01,0x1B,0xFE,0x32,0xF1,0x32,0xC0,0x00,0x4F, \ ++ 0x00,0x81,0x00,0x02,0x00,0x00,0x97,0x9E,0x43,0x49, \ ++ 0x00,0x08,0x08,0x16,0x00,0x54,0x00,0x01,0x1B,0xFE, \ ++ 0x00,0x00,0x9F,0x9E,0x43,0x7E,0x00,0x00,0x02,0x1F, \ ++ 0x00,0x08,0x28,0x1B,0x30,0x73,0x29,0x1F,0x30,0xD0, \ ++ 0x63,0x6A,0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F, \ ++ 0x00,0x52,0x00,0x01,0x07,0x01,0x63,0x56,0x00,0x00, \ ++ 0x30,0xD0,0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00, \ ++ 0x00,0x00,0x43,0x67,0x00,0x00,0x02,0x8F,0x00,0x00, \ ++ 0x30,0xF2,0x00,0x06,0x1B,0x78,0x00,0x00,0x9F,0xFF, \ ++ 0x30,0xF2,0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0, \ ++ 0x00,0x52,0x00,0x08,0x28,0x1A,0x63,0x52,0x00,0x00, \ ++ 0x30,0xF2,0x1B,0x78,0x06,0x00,0x29,0x1E,0x30,0xF2, \ ++ 0x53,0x7E,0xFF,0xFF,0x1B,0x83,0x08,0x16,0x00,0x54, \ ++ 0x00,0x01,0x1B,0xFE,0x1B,0x90,0x32,0xF1,0x28,0x5D, \ ++ 0x32,0xF1,0x00,0x55,0x00,0x08,0x28,0x5F,0x00,0x00, \ ++ 0x8F,0x9F,0x29,0x33,0x08,0x16,0x00,0x49,0x00,0x01, \ ++ 0x1B,0xFF,0x00,0x01,0x1B,0xFF,0x08,0x07,0x00,0x02, \ ++ 0x00,0x00,0x8D,0x80,0x53,0x9C,0x00,0x01,0x30,0x71, \ ++ 0x00,0x55,0x00,0x01,0x28,0x0F,0x00,0x00,0x8D,0x00, \ ++ 0x53,0xA4,0x00,0x01,0x30,0x71,0x00,0x55,0x00,0x01, \ ++ 0x28,0x0F,0x00,0x00,0x83,0x8E,0x53,0xB9,0x00,0x00, \ ++ 0x00,0x00,0x86,0x08,0x30,0x71,0x00,0x7B,0x03,0xB9, \ ++ 0x33,0xB4,0x00,0xDA,0xFF,0xFF,0x00,0x0F,0x00,0x00, \ ++ 0x00,0x00,0x00,0x00,0x86,0x09,0x01,0x03,0x00,0x7D, \ ++ 0x03,0xB9,0x1B,0xC8,0x33,0xD1,0x00,0xF9,0x00,0x10, \ ++ 0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x7B,0x09,0x5F, \ ++ 0x00,0x1A,0x00,0x00,0x09,0x4F,0x00,0x1A,0x00,0x00, \ ++ 0x00,0x01,0x1B,0xFF,0x00,0x00,0x8C,0x00,0x53,0xF0, \ ++ 0x00,0x01,0x34,0xF5,0x00,0xFB,0xFF,0xFF,0x00,0x7F, \ ++ 0x00,0x00,0x00,0x00,0x2A,0x9F,0x00,0x00,0x93,0x8F, \ ++ 0x28,0x49,0x00,0x00,0x97,0x8F,0x28,0x4B,0x34,0x61, \ ++ 0x28,0x4D,0x34,0x71,0x28,0x4F,0x34,0xB7,0x00,0xF9, \ ++ 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x2B,0x97, \ ++ 0x33,0xF1,0x00,0xF9,0x00,0x01,0x00,0x00,0x00,0x00, \ ++ 0x00,0x00,0x28,0x7F,0x00,0x03,0x00,0x02,0x00,0x00, \ ++ 0x00,0x01,0x1B,0xFF,0x00,0x01,0x1B,0xFF, \ ++} ++#endif /* (DPAA_VERSION == 10) */ ++ ++/****************************/ ++/* Parser defines */ ++/****************************/ ++#define FM_PCD_PRS_SW_TAIL_SIZE 4 /**< Number of bytes that must be cleared at ++ the end of the SW parser area */ ++ ++/* masks */ ++#define PRS_ERR_CAP 0x80000000 ++#define PRS_ERR_TYPE_DOUBLE 0x40000000 ++#define PRS_ERR_SINGLE_ECC_CNT_MASK 0x00FF0000 ++#define PRS_ERR_ADDR_MASK 0x000001FF ++ ++/* others */ ++#define PRS_MAX_CYCLE_LIMIT 8191 ++#define PRS_SW_DATA 0x00000800 ++#define PRS_REGS_OFFSET 0x00000840 ++ ++#define GET_FM_PCD_PRS_PORT_ID(prsPortId,hardwarePortId) \ ++ prsPortId = (uint8_t)(hardwarePortId & 0x0f) ++ ++#define GET_FM_PCD_INDEX_FLAG(bitMask, prsPortId) \ ++ bitMask = 0x80000000>>prsPortId ++ ++#endif /* __FM_PRS_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.c +new file mode 100644 +index 00000000..ee82f730 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.c +@@ -0,0 +1,984 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_replic.c ++ ++ @Description FM frame replicator ++*//***************************************************************************/ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "string_ext.h" ++#include "debug_ext.h" ++#include "fm_pcd_ext.h" ++#include "fm_muram_ext.h" ++#include "fm_common.h" ++#include "fm_hc.h" ++#include "fm_replic.h" ++#include "fm_cc.h" ++#include "list_ext.h" ++ ++ ++/****************************************/ ++/* static functions */ ++/****************************************/ ++static uint8_t GetMemberPosition(t_FmPcdFrmReplicGroup *p_ReplicGroup, ++ uint32_t memberIndex, ++ bool isAddOperation) ++{ ++ uint8_t memberPosition; ++ uint32_t lastMemberIndex; ++ ++ ASSERT_COND(p_ReplicGroup); ++ ++ /* the last member index is different between add and remove operation - ++ in case of remove - this is exactly the last member index ++ in case of add - this is the last member index + 1 - e.g. ++ if we have 4 members, the index of the actual last member is 3(because the ++ index starts from 0) therefore in order to add a new member as the last ++ member we shall use memberIndex = 4 and not 3 ++ */ ++ if (isAddOperation) ++ lastMemberIndex = p_ReplicGroup->numOfEntries; ++ else ++ lastMemberIndex = p_ReplicGroup->numOfEntries-1; ++ ++ /* last */ ++ if (memberIndex == lastMemberIndex) ++ memberPosition = FRM_REPLIC_LAST_MEMBER_INDEX; ++ else ++ { ++ /* first */ ++ if (memberIndex == 0) ++ memberPosition = FRM_REPLIC_FIRST_MEMBER_INDEX; ++ else ++ { ++ /* middle */ ++ ASSERT_COND(memberIndex < lastMemberIndex); ++ memberPosition = FRM_REPLIC_MIDDLE_MEMBER_INDEX; ++ } ++ } ++ return memberPosition; ++} ++ ++static t_Error MemberCheckParams(t_Handle h_FmPcd, ++ t_FmPcdCcNextEngineParams *p_MemberParams) ++{ ++ t_Error err; ++ ++ ++ if ((p_MemberParams->nextEngine != e_FM_PCD_DONE) && ++ (p_MemberParams->nextEngine != e_FM_PCD_KG) && ++ (p_MemberParams->nextEngine != e_FM_PCD_PLCR)) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Next engine of a member should be MatchTable(cc) or Done or Policer")); ++ ++ /* check the regular parameters of the next engine */ ++ err = ValidateNextEngineParams(h_FmPcd, p_MemberParams, e_FM_PCD_CC_STATS_MODE_NONE); ++ if (err) ++ RETURN_ERROR(MAJOR, err, ("member next engine parameters")); ++ ++ return E_OK; ++} ++ ++static t_Error CheckParams(t_Handle h_FmPcd, ++ t_FmPcdFrmReplicGroupParams *p_ReplicGroupParam) ++{ ++ int i; ++ t_Error err; ++ ++ /* check that max num of entries is at least 2 */ ++ if (!IN_RANGE(2, p_ReplicGroupParam->maxNumOfEntries, FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES)) ++ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ("maxNumOfEntries in the frame replicator parameters should be 2-%d",FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES)); ++ ++ /* check that number of entries is greater than zero */ ++ if (!p_ReplicGroupParam->numOfEntries) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOFEntries in the frame replicator group should be greater than zero")); ++ ++ /* check that max num of entries is equal or greater than number of entries */ ++ if (p_ReplicGroupParam->maxNumOfEntries < p_ReplicGroupParam->numOfEntries) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("maxNumOfEntries should be equal or greater than numOfEntries")); ++ ++ for (i=0; inumOfEntries; i++) ++ { ++ err = MemberCheckParams(h_FmPcd, &p_ReplicGroupParam->nextEngineParams[i]); ++ if (err) ++ RETURN_ERROR(MAJOR, err, ("member check parameters")); ++ } ++ return E_OK; ++} ++ ++static t_FmPcdFrmReplicMember *GetAvailableMember(t_FmPcdFrmReplicGroup *p_ReplicGroup) ++{ ++ t_FmPcdFrmReplicMember *p_ReplicMember = NULL; ++ t_List *p_Next; ++ ++ if (!LIST_IsEmpty(&p_ReplicGroup->availableMembersList)) ++ { ++ p_Next = LIST_FIRST(&p_ReplicGroup->availableMembersList); ++ p_ReplicMember = LIST_OBJECT(p_Next, t_FmPcdFrmReplicMember, node); ++ ASSERT_COND(p_ReplicMember); ++ LIST_DelAndInit(p_Next); ++ } ++ return p_ReplicMember; ++} ++ ++static void PutAvailableMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, ++ t_FmPcdFrmReplicMember *p_ReplicMember) ++{ ++ LIST_AddToTail(&p_ReplicMember->node, &p_ReplicGroup->availableMembersList); ++} ++ ++static void AddMemberToList(t_FmPcdFrmReplicGroup *p_ReplicGroup, ++ t_FmPcdFrmReplicMember *p_CurrentMember, ++ t_List *p_ListHead) ++{ ++ LIST_Add(&p_CurrentMember->node, p_ListHead); ++ ++ p_ReplicGroup->numOfEntries++; ++} ++ ++static void RemoveMemberFromList(t_FmPcdFrmReplicGroup *p_ReplicGroup, ++ t_FmPcdFrmReplicMember *p_CurrentMember) ++{ ++ ASSERT_COND(p_ReplicGroup->numOfEntries); ++ LIST_DelAndInit(&p_CurrentMember->node); ++ p_ReplicGroup->numOfEntries--; ++} ++ ++static void LinkSourceToMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, ++ t_AdOfTypeContLookup *p_SourceTd, ++ t_FmPcdFrmReplicMember *p_ReplicMember) ++{ ++ t_FmPcd *p_FmPcd; ++ ++ ASSERT_COND(p_SourceTd); ++ ASSERT_COND(p_ReplicMember); ++ ASSERT_COND(p_ReplicGroup); ++ ASSERT_COND(p_ReplicGroup->h_FmPcd); ++ ++ /* Link the first member in the group to the source TD */ ++ p_FmPcd = p_ReplicGroup->h_FmPcd; ++ ++ WRITE_UINT32(p_SourceTd->matchTblPtr, ++ (uint32_t)(XX_VirtToPhys(p_ReplicMember->p_MemberAd) - ++ p_FmPcd->physicalMuramBase)); ++} ++ ++static void LinkMemberToMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, ++ t_FmPcdFrmReplicMember *p_CurrentMember, ++ t_FmPcdFrmReplicMember *p_NextMember) ++{ ++ t_AdOfTypeResult *p_CurrReplicAd = (t_AdOfTypeResult*)p_CurrentMember->p_MemberAd; ++ t_AdOfTypeResult *p_NextReplicAd = NULL; ++ t_FmPcd *p_FmPcd; ++ uint32_t offset = 0; ++ ++ /* Check if the next member exists or it's NULL (- means that this is the last member) */ ++ if (p_NextMember) ++ { ++ p_NextReplicAd = (t_AdOfTypeResult*)p_NextMember->p_MemberAd; ++ p_FmPcd = p_ReplicGroup->h_FmPcd; ++ offset = (XX_VirtToPhys(p_NextReplicAd) - (p_FmPcd->physicalMuramBase)); ++ offset = ((offset>>NEXT_FRM_REPLIC_ADDR_SHIFT)<< NEXT_FRM_REPLIC_MEMBER_INDEX_SHIFT); ++ } ++ ++ /* link the current AD to point to the AD of the next member */ ++ WRITE_UINT32(p_CurrReplicAd->res, offset); ++} ++ ++static t_Error ModifyDescriptor(t_FmPcdFrmReplicGroup *p_ReplicGroup, ++ void *p_OldDescriptor, ++ void *p_NewDescriptor) ++{ ++ t_Handle h_Hc; ++ t_Error err; ++ t_FmPcd *p_FmPcd; ++ ++ ASSERT_COND(p_ReplicGroup); ++ ASSERT_COND(p_ReplicGroup->h_FmPcd); ++ ASSERT_COND(p_OldDescriptor); ++ ASSERT_COND(p_NewDescriptor); ++ ++ p_FmPcd = p_ReplicGroup->h_FmPcd; ++ h_Hc = FmPcdGetHcHandle(p_FmPcd); ++ if (!h_Hc) ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("Host command")); ++ ++ err = FmHcPcdCcDoDynamicChange(h_Hc, ++ (uint32_t)(XX_VirtToPhys(p_OldDescriptor) - p_FmPcd->physicalMuramBase), ++ (uint32_t)(XX_VirtToPhys(p_NewDescriptor) - p_FmPcd->physicalMuramBase)); ++ if (err) ++ RETURN_ERROR(MAJOR, err, ("Dynamic change host command")); ++ ++ return E_OK; ++} ++ ++static void FillReplicAdOfTypeResult(void *p_ReplicAd, bool last) ++{ ++ t_AdOfTypeResult *p_CurrReplicAd = (t_AdOfTypeResult*)p_ReplicAd; ++ uint32_t tmp; ++ ++ tmp = GET_UINT32(p_CurrReplicAd->plcrProfile); ++ if (last) ++ /* clear the NL bit in case it's the last member in the group*/ ++ WRITE_UINT32(p_CurrReplicAd->plcrProfile,(tmp & ~FRM_REPLIC_NL_BIT)); ++ else ++ /* set the NL bit in case it's not the last member in the group */ ++ WRITE_UINT32(p_CurrReplicAd->plcrProfile, (tmp |FRM_REPLIC_NL_BIT)); ++ ++ /* set FR bit in the action descriptor */ ++ tmp = GET_UINT32(p_CurrReplicAd->nia); ++ WRITE_UINT32(p_CurrReplicAd->nia, ++ (tmp | FRM_REPLIC_FR_BIT | FM_PCD_AD_RESULT_EXTENDED_MODE )); ++} ++ ++static void BuildSourceTd(void *p_Ad) ++{ ++ t_AdOfTypeContLookup *p_SourceTd; ++ ++ ASSERT_COND(p_Ad); ++ ++ p_SourceTd = (t_AdOfTypeContLookup *)p_Ad; ++ ++ IOMemSet32((uint8_t*)p_SourceTd, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ /* initialize the source table descriptor */ ++ WRITE_UINT32(p_SourceTd->ccAdBase, FM_PCD_AD_CONT_LOOKUP_TYPE); ++ WRITE_UINT32(p_SourceTd->pcAndOffsets, FRM_REPLIC_SOURCE_TD_OPCODE); ++} ++ ++static t_Error BuildShadowAndModifyDescriptor(t_FmPcdFrmReplicGroup *p_ReplicGroup, ++ t_FmPcdFrmReplicMember *p_NextMember, ++ t_FmPcdFrmReplicMember *p_CurrentMember, ++ bool sourceDescriptor, ++ bool last) ++{ ++ t_FmPcd *p_FmPcd; ++ t_FmPcdFrmReplicMember shadowMember; ++ t_Error err; ++ ++ ASSERT_COND(p_ReplicGroup); ++ ASSERT_COND(p_ReplicGroup->h_FmPcd); ++ ++ p_FmPcd = p_ReplicGroup->h_FmPcd; ++ ASSERT_COND(p_FmPcd->p_CcShadow); ++ ++ if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) ++ return ERROR_CODE(E_BUSY); ++ ++ if (sourceDescriptor) ++ { ++ BuildSourceTd(p_FmPcd->p_CcShadow); ++ LinkSourceToMember(p_ReplicGroup, p_FmPcd->p_CcShadow, p_NextMember); ++ ++ /* Modify the source table descriptor according to the prepared shadow descriptor */ ++ err = ModifyDescriptor(p_ReplicGroup, ++ p_ReplicGroup->p_SourceTd, ++ p_FmPcd->p_CcShadow/* new prepared source td */); ++ ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ if (err) ++ RETURN_ERROR(MAJOR, err, ("Modify source Descriptor in BuildShadowAndModifyDescriptor")); ++ ++ } ++ else ++ { ++ IO2IOCpy32(p_FmPcd->p_CcShadow, ++ p_CurrentMember->p_MemberAd, ++ FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ /* update the last bit in the shadow ad */ ++ FillReplicAdOfTypeResult(p_FmPcd->p_CcShadow, last); ++ ++ shadowMember.p_MemberAd = p_FmPcd->p_CcShadow; ++ ++ /* update the next FR member index */ ++ LinkMemberToMember(p_ReplicGroup, &shadowMember, p_NextMember); ++ ++ /* Modify the next member according to the prepared shadow descriptor */ ++ err = ModifyDescriptor(p_ReplicGroup, ++ p_CurrentMember->p_MemberAd, ++ p_FmPcd->p_CcShadow); ++ ++ RELEASE_LOCK(p_FmPcd->shadowLock); ++ if (err) ++ RETURN_ERROR(MAJOR, err, ("Modify Descriptor in BuildShadowAndModifyDescriptor")); ++ } ++ ++ ++ return E_OK; ++} ++ ++static t_FmPcdFrmReplicMember* GetMemberByIndex(t_FmPcdFrmReplicGroup *p_ReplicGroup, ++ uint16_t memberIndex) ++{ ++ int i=0; ++ t_List *p_Pos; ++ t_FmPcdFrmReplicMember *p_Member = NULL; ++ ++ LIST_FOR_EACH(p_Pos, &p_ReplicGroup->membersList) ++ { ++ if (i == memberIndex) ++ { ++ p_Member = LIST_OBJECT(p_Pos, t_FmPcdFrmReplicMember, node); ++ return p_Member; ++ } ++ i++; ++ } ++ return p_Member; ++} ++ ++static t_Error AllocMember(t_FmPcdFrmReplicGroup *p_ReplicGroup) ++{ ++ t_FmPcdFrmReplicMember *p_CurrentMember; ++ t_Handle h_Muram; ++ ++ ASSERT_COND(p_ReplicGroup); ++ ++ h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd); ++ ASSERT_COND(h_Muram); ++ ++ /* Initialize an internal structure of a member to add to the available members list */ ++ p_CurrentMember = (t_FmPcdFrmReplicMember *)XX_Malloc(sizeof(t_FmPcdFrmReplicMember)); ++ if (!p_CurrentMember) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Frame replicator member")); ++ ++ memset(p_CurrentMember, 0 ,sizeof(t_FmPcdFrmReplicMember)); ++ ++ /* Allocate the member AD */ ++ p_CurrentMember->p_MemberAd = ++ (t_AdOfTypeResult*)FM_MURAM_AllocMem(h_Muram, ++ FM_PCD_CC_AD_ENTRY_SIZE, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!p_CurrentMember->p_MemberAd) ++ { ++ XX_Free(p_CurrentMember); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("member AD table")); ++ } ++ IOMemSet32((uint8_t*)p_CurrentMember->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ /* Add the new member to the available members list */ ++ LIST_AddToTail(&p_CurrentMember->node, &(p_ReplicGroup->availableMembersList)); ++ ++ return E_OK; ++} ++ ++static t_FmPcdFrmReplicMember* InitMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, ++ t_FmPcdCcNextEngineParams *p_MemberParams, ++ bool last) ++{ ++ t_FmPcdFrmReplicMember *p_CurrentMember = NULL; ++ ++ ASSERT_COND(p_ReplicGroup); ++ ++ /* Get an available member from the internal members list */ ++ p_CurrentMember = GetAvailableMember(p_ReplicGroup); ++ if (!p_CurrentMember) ++ { ++ REPORT_ERROR(MAJOR, E_NOT_FOUND, ("Available member")); ++ return NULL; ++ } ++ p_CurrentMember->h_Manip = NULL; ++ ++ /* clear the Ad of the new member */ ++ IOMemSet32((uint8_t*)p_CurrentMember->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ INIT_LIST(&p_CurrentMember->node); ++ ++ /* Initialize the Ad of the member */ ++ NextStepAd(p_CurrentMember->p_MemberAd, ++ NULL, ++ p_MemberParams, ++ p_ReplicGroup->h_FmPcd); ++ ++ /* save Manip handle (for free needs) */ ++ if (p_MemberParams->h_Manip) ++ p_CurrentMember->h_Manip = p_MemberParams->h_Manip; ++ ++ /* Initialize the relevant frame replicator fields in the AD */ ++ FillReplicAdOfTypeResult(p_CurrentMember->p_MemberAd, last); ++ ++ return p_CurrentMember; ++} ++ ++static void FreeMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, ++ t_FmPcdFrmReplicMember *p_Member) ++{ ++ /* Note: Can't free the member AD just returns the member to the available ++ member list - therefore only memset the AD */ ++ ++ /* zero the AD */ ++ IOMemSet32(p_Member->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); ++ ++ ++ /* return the member to the available members list */ ++ PutAvailableMember(p_ReplicGroup, p_Member); ++} ++ ++static t_Error RemoveMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, ++ uint16_t memberIndex) ++{ ++ t_FmPcd *p_FmPcd = NULL; ++ t_FmPcdFrmReplicMember *p_CurrentMember = NULL, *p_PreviousMember = NULL, *p_NextMember = NULL; ++ t_Error err; ++ uint8_t memberPosition; ++ ++ p_FmPcd = p_ReplicGroup->h_FmPcd; ++ ASSERT_COND(p_FmPcd); ++ UNUSED(p_FmPcd); ++ ++ p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex); ++ ASSERT_COND(p_CurrentMember); ++ ++ /* determine the member position in the group */ ++ memberPosition = GetMemberPosition(p_ReplicGroup, ++ memberIndex, ++ FALSE/*remove operation*/); ++ ++ switch (memberPosition) ++ { ++ case FRM_REPLIC_FIRST_MEMBER_INDEX: ++ p_NextMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex+1)); ++ ASSERT_COND(p_NextMember); ++ ++ /* update the source td itself by using a host command */ ++ err = BuildShadowAndModifyDescriptor(p_ReplicGroup, ++ p_NextMember, ++ NULL, ++ TRUE/*sourceDescriptor*/, ++ FALSE/*last*/); ++ break; ++ ++ case FRM_REPLIC_MIDDLE_MEMBER_INDEX: ++ p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1)); ++ ASSERT_COND(p_PreviousMember); ++ ++ p_NextMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex+1)); ++ ASSERT_COND(p_NextMember); ++ ++ err = BuildShadowAndModifyDescriptor(p_ReplicGroup, ++ p_NextMember, ++ p_PreviousMember, ++ FALSE/*sourceDescriptor*/, ++ FALSE/*last*/); ++ ++ break; ++ ++ case FRM_REPLIC_LAST_MEMBER_INDEX: ++ p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1)); ++ ASSERT_COND(p_PreviousMember); ++ ++ err = BuildShadowAndModifyDescriptor(p_ReplicGroup, ++ NULL, ++ p_PreviousMember, ++ FALSE/*sourceDescriptor*/, ++ TRUE/*last*/); ++ break; ++ ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member position in remove member")); ++ } ++ ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ if (p_CurrentMember->h_Manip) ++ { ++ FmPcdManipUpdateOwner(p_CurrentMember->h_Manip, FALSE); ++ p_CurrentMember->h_Manip = NULL; ++ } ++ ++ /* remove the member from the driver internal members list */ ++ RemoveMemberFromList(p_ReplicGroup, p_CurrentMember); ++ ++ /* return the member to the available members list */ ++ FreeMember(p_ReplicGroup, p_CurrentMember); ++ ++ return E_OK; ++} ++ ++static void DeleteGroup(t_FmPcdFrmReplicGroup *p_ReplicGroup) ++{ ++ int i, j; ++ t_Handle h_Muram; ++ t_FmPcdFrmReplicMember *p_Member, *p_CurrentMember; ++ ++ if (p_ReplicGroup) ++ { ++ ASSERT_COND(p_ReplicGroup->h_FmPcd); ++ h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd); ++ ASSERT_COND(h_Muram); ++ ++ /* free the source table descriptor */ ++ if (p_ReplicGroup->p_SourceTd) ++ { ++ FM_MURAM_FreeMem(h_Muram, p_ReplicGroup->p_SourceTd); ++ p_ReplicGroup->p_SourceTd = NULL; ++ } ++ ++ /* Remove all members from the members linked list (hw and sw) and ++ return the members to the available members list */ ++ if (p_ReplicGroup->numOfEntries) ++ { ++ j = p_ReplicGroup->numOfEntries-1; ++ ++ /* manually removal of the member because there are no owners of ++ this group */ ++ for (i=j; i>=0; i--) ++ { ++ p_CurrentMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)i/*memberIndex*/); ++ ASSERT_COND(p_CurrentMember); ++ ++ if (p_CurrentMember->h_Manip) ++ { ++ FmPcdManipUpdateOwner(p_CurrentMember->h_Manip, FALSE); ++ p_CurrentMember->h_Manip = NULL; ++ } ++ ++ /* remove the member from the internal driver members list */ ++ RemoveMemberFromList(p_ReplicGroup, p_CurrentMember); ++ ++ /* return the member to the available members list */ ++ FreeMember(p_ReplicGroup, p_CurrentMember); ++ } ++ } ++ ++ /* Free members AD */ ++ for (i=0; imaxNumOfEntries; i++) ++ { ++ p_Member = GetAvailableMember(p_ReplicGroup); ++ ASSERT_COND(p_Member); ++ if (p_Member->p_MemberAd) ++ { ++ FM_MURAM_FreeMem(h_Muram, p_Member->p_MemberAd); ++ p_Member->p_MemberAd = NULL; ++ } ++ XX_Free(p_Member); ++ } ++ ++ /* release the group lock */ ++ if (p_ReplicGroup->p_Lock) ++ FmPcdReleaseLock(p_ReplicGroup->h_FmPcd, p_ReplicGroup->p_Lock); ++ ++ /* free the replicator group */ ++ XX_Free(p_ReplicGroup); ++ } ++} ++ ++ ++/*****************************************************************************/ ++/* Inter-module API routines */ ++/*****************************************************************************/ ++ ++/* NOTE: the inter-module routines are locked by cc in case of using them */ ++void * FrmReplicGroupGetSourceTableDescriptor(t_Handle h_ReplicGroup) ++{ ++ t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; ++ ASSERT_COND(p_ReplicGroup); ++ ++ return (p_ReplicGroup->p_SourceTd); ++} ++ ++void FrmReplicGroupUpdateAd(t_Handle h_ReplicGroup, ++ void *p_Ad, ++ t_Handle *h_AdNew) ++{ ++ t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; ++ t_AdOfTypeResult *p_AdResult = (t_AdOfTypeResult*)p_Ad; ++ t_FmPcd *p_FmPcd; ++ ++ ASSERT_COND(p_ReplicGroup); ++ p_FmPcd = p_ReplicGroup->h_FmPcd; ++ ++ /* build a bypass ad */ ++ WRITE_UINT32(p_AdResult->fqid, FM_PCD_AD_BYPASS_TYPE | ++ (uint32_t)((XX_VirtToPhys(p_ReplicGroup->p_SourceTd)) - p_FmPcd->physicalMuramBase)); ++ ++ *h_AdNew = NULL; ++} ++ ++void FrmReplicGroupUpdateOwner(t_Handle h_ReplicGroup, ++ bool add) ++{ ++ t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; ++ ASSERT_COND(p_ReplicGroup); ++ ++ /* update the group owner counter */ ++ if (add) ++ p_ReplicGroup->owners++; ++ else ++ { ++ ASSERT_COND(p_ReplicGroup->owners); ++ p_ReplicGroup->owners--; ++ } ++} ++ ++t_Error FrmReplicGroupTryLock(t_Handle h_ReplicGroup) ++{ ++ t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; ++ ++ ASSERT_COND(h_ReplicGroup); ++ ++ if (FmPcdLockTryLock(p_ReplicGroup->p_Lock)) ++ return E_OK; ++ ++ return ERROR_CODE(E_BUSY); ++} ++ ++void FrmReplicGroupUnlock(t_Handle h_ReplicGroup) ++{ ++ t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; ++ ++ ASSERT_COND(h_ReplicGroup); ++ ++ FmPcdLockUnlock(p_ReplicGroup->p_Lock); ++} ++/*********************** End of inter-module routines ************************/ ++ ++ ++/****************************************/ ++/* API Init unit functions */ ++/****************************************/ ++t_Handle FM_PCD_FrmReplicSetGroup(t_Handle h_FmPcd, ++ t_FmPcdFrmReplicGroupParams *p_ReplicGroupParam) ++{ ++ t_FmPcdFrmReplicGroup *p_ReplicGroup; ++ t_FmPcdFrmReplicMember *p_CurrentMember, *p_NextMember = NULL; ++ int i; ++ t_Error err; ++ bool last = FALSE; ++ t_Handle h_Muram; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(p_ReplicGroupParam, E_INVALID_HANDLE, NULL); ++ ++ if (!FmPcdIsAdvancedOffloadSupported(h_FmPcd)) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Advanced-offload must be enabled")); ++ return NULL; ++ } ++ ++ err = CheckParams(h_FmPcd, p_ReplicGroupParam); ++ if (err) ++ { ++ REPORT_ERROR(MAJOR, err, (NO_MSG)); ++ return NULL; ++ } ++ ++ p_ReplicGroup = (t_FmPcdFrmReplicGroup*)XX_Malloc(sizeof(t_FmPcdFrmReplicGroup)); ++ if (!p_ReplicGroup) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory")); ++ return NULL; ++ } ++ memset(p_ReplicGroup, 0, sizeof(t_FmPcdFrmReplicGroup)); ++ ++ /* initialize lists for internal driver use */ ++ INIT_LIST(&p_ReplicGroup->availableMembersList); ++ INIT_LIST(&p_ReplicGroup->membersList); ++ ++ p_ReplicGroup->h_FmPcd = h_FmPcd; ++ ++ h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd); ++ ASSERT_COND(h_Muram); ++ ++ /* initialize the group lock */ ++ p_ReplicGroup->p_Lock = FmPcdAcquireLock(p_ReplicGroup->h_FmPcd); ++ if (!p_ReplicGroup->p_Lock) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Replic group lock")); ++ DeleteGroup(p_ReplicGroup); ++ return NULL; ++ } ++ ++ /* Allocate the frame replicator source table descriptor */ ++ p_ReplicGroup->p_SourceTd = ++ (t_Handle)FM_MURAM_AllocMem(h_Muram, ++ FM_PCD_CC_AD_ENTRY_SIZE, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (!p_ReplicGroup->p_SourceTd) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("frame replicator source table descriptor")); ++ DeleteGroup(p_ReplicGroup); ++ return NULL; ++ } ++ ++ /* update the shadow size - required for the host commands */ ++ err = FmPcdUpdateCcShadow(p_ReplicGroup->h_FmPcd, ++ FM_PCD_CC_AD_ENTRY_SIZE, ++ FM_PCD_CC_AD_TABLE_ALIGN); ++ if (err) ++ { ++ REPORT_ERROR(MAJOR, err, ("Update CC shadow")); ++ DeleteGroup(p_ReplicGroup); ++ return NULL; ++ } ++ ++ p_ReplicGroup->maxNumOfEntries = p_ReplicGroupParam->maxNumOfEntries; ++ ++ /* Allocate the maximal number of members ADs and Statistics AD for the group ++ It prevents allocation of Muram in run-time */ ++ for (i=0; imaxNumOfEntries; i++) ++ { ++ err = AllocMember(p_ReplicGroup); ++ if (err) ++ { ++ REPORT_ERROR(MAJOR, err, ("allocate a new member")); ++ DeleteGroup(p_ReplicGroup); ++ return NULL; ++ } ++ } ++ ++ /* Initialize the members linked lists: ++ (hw - the one that is used by the FMan controller and ++ sw - the one that is managed by the driver internally) */ ++ for (i=(p_ReplicGroupParam->numOfEntries-1); i>=0; i--) ++ { ++ /* check if this is the last member in the group */ ++ if (i == (p_ReplicGroupParam->numOfEntries-1)) ++ last = TRUE; ++ else ++ last = FALSE; ++ ++ /* Initialize a new member */ ++ p_CurrentMember = InitMember(p_ReplicGroup, ++ &(p_ReplicGroupParam->nextEngineParams[i]), ++ last); ++ if (!p_CurrentMember) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_HANDLE, ("No available member")); ++ DeleteGroup(p_ReplicGroup); ++ return NULL; ++ } ++ ++ /* Build the members group - link two consecutive members in the hw linked list */ ++ LinkMemberToMember(p_ReplicGroup, p_CurrentMember, p_NextMember); ++ ++ /* update the driver internal members list to be compatible to the hw members linked list */ ++ AddMemberToList(p_ReplicGroup, p_CurrentMember, &p_ReplicGroup->membersList); ++ ++ p_NextMember = p_CurrentMember; ++ } ++ ++ /* initialize the source table descriptor */ ++ BuildSourceTd(p_ReplicGroup->p_SourceTd); ++ ++ /* link the source table descriptor to point to the first member in the group */ ++ LinkSourceToMember(p_ReplicGroup, p_ReplicGroup->p_SourceTd, p_NextMember); ++ ++ return p_ReplicGroup; ++} ++ ++t_Error FM_PCD_FrmReplicDeleteGroup(t_Handle h_ReplicGroup) ++{ ++ t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; ++ ++ SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE); ++ ++ if (p_ReplicGroup->owners) ++ RETURN_ERROR(MAJOR, ++ E_INVALID_STATE, ++ ("the group has owners and can't be deleted")); ++ ++ DeleteGroup(p_ReplicGroup); ++ ++ return E_OK; ++} ++ ++ ++/*****************************************************************************/ ++/* API Run-time Frame replicator Control unit functions */ ++/*****************************************************************************/ ++t_Error FM_PCD_FrmReplicAddMember(t_Handle h_ReplicGroup, ++ uint16_t memberIndex, ++ t_FmPcdCcNextEngineParams *p_MemberParams) ++{ ++ t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup*) h_ReplicGroup; ++ t_FmPcdFrmReplicMember *p_NewMember, *p_CurrentMember = NULL, *p_PreviousMember = NULL; ++ t_Error err; ++ uint8_t memberPosition; ++ ++ SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_MemberParams, E_INVALID_HANDLE); ++ ++ /* group lock */ ++ err = FrmReplicGroupTryLock(p_ReplicGroup); ++ if (GET_ERROR_TYPE(err) == E_BUSY) ++ return ERROR_CODE(E_BUSY); ++ ++ if (memberIndex > p_ReplicGroup->numOfEntries) ++ { ++ /* unlock */ ++ FrmReplicGroupUnlock(p_ReplicGroup); ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ++ ("memberIndex is greater than the members in the list")); ++ } ++ ++ if (memberIndex >= p_ReplicGroup->maxNumOfEntries) ++ { ++ /* unlock */ ++ FrmReplicGroupUnlock(p_ReplicGroup); ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("memberIndex is greater than the allowed number of members in the group")); ++ } ++ ++ if ((p_ReplicGroup->numOfEntries + 1) > FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES) ++ { ++ /* unlock */ ++ FrmReplicGroupUnlock(p_ReplicGroup); ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("numOfEntries with new entry can not be larger than %d\n", ++ FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES)); ++ } ++ ++ err = MemberCheckParams(p_ReplicGroup->h_FmPcd, p_MemberParams); ++ if (err) ++ { ++ /* unlock */ ++ FrmReplicGroupUnlock(p_ReplicGroup); ++ RETURN_ERROR(MAJOR, err, ("member check parameters in add operation")); ++ } ++ /* determine the member position in the group */ ++ memberPosition = GetMemberPosition(p_ReplicGroup, ++ memberIndex, ++ TRUE/* add operation */); ++ ++ /* Initialize a new member */ ++ p_NewMember = InitMember(p_ReplicGroup, ++ p_MemberParams, ++ (memberPosition == FRM_REPLIC_LAST_MEMBER_INDEX ? TRUE : FALSE)); ++ if (!p_NewMember) ++ { ++ /* unlock */ ++ FrmReplicGroupUnlock(p_ReplicGroup); ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("No available member")); ++ } ++ ++ switch (memberPosition) ++ { ++ case FRM_REPLIC_FIRST_MEMBER_INDEX: ++ p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex); ++ ASSERT_COND(p_CurrentMember); ++ ++ LinkMemberToMember(p_ReplicGroup, p_NewMember, p_CurrentMember); ++ ++ /* update the internal group source TD */ ++ LinkSourceToMember(p_ReplicGroup, ++ p_ReplicGroup->p_SourceTd, ++ p_NewMember); ++ ++ /* add member to the internal sw member list */ ++ AddMemberToList(p_ReplicGroup, ++ p_NewMember, ++ &p_ReplicGroup->membersList); ++ break; ++ ++ case FRM_REPLIC_MIDDLE_MEMBER_INDEX: ++ p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex); ++ ASSERT_COND(p_CurrentMember); ++ ++ p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1)); ++ ASSERT_COND(p_PreviousMember); ++ ++ LinkMemberToMember(p_ReplicGroup, p_NewMember, p_CurrentMember); ++ LinkMemberToMember(p_ReplicGroup, p_PreviousMember, p_NewMember); ++ ++ AddMemberToList(p_ReplicGroup, p_NewMember, &p_PreviousMember->node); ++ break; ++ ++ case FRM_REPLIC_LAST_MEMBER_INDEX: ++ p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1)); ++ ASSERT_COND(p_PreviousMember); ++ ++ LinkMemberToMember(p_ReplicGroup, p_PreviousMember, p_NewMember); ++ FillReplicAdOfTypeResult(p_PreviousMember->p_MemberAd, FALSE/*last*/); ++ ++ /* add the new member to the internal sw member list */ ++ AddMemberToList(p_ReplicGroup, p_NewMember, &p_PreviousMember->node); ++ break; ++ ++ default: ++ /* unlock */ ++ FrmReplicGroupUnlock(p_ReplicGroup); ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member position in add member")); ++ ++ } ++ ++ /* unlock */ ++ FrmReplicGroupUnlock(p_ReplicGroup); ++ ++ return E_OK; ++} ++ ++t_Error FM_PCD_FrmReplicRemoveMember(t_Handle h_ReplicGroup, ++ uint16_t memberIndex) ++{ ++ t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup*) h_ReplicGroup; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE); ++ ++ /* lock */ ++ err = FrmReplicGroupTryLock(p_ReplicGroup); ++ if (GET_ERROR_TYPE(err) == E_BUSY) ++ return ERROR_CODE(E_BUSY); ++ ++ if (memberIndex >= p_ReplicGroup->numOfEntries) ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member index to remove")); ++ ++ /* Design decision: group must contain at least one member ++ No possibility to remove the last member from the group */ ++ if (p_ReplicGroup->numOfEntries == 1) ++ RETURN_ERROR(MAJOR, E_CONFLICT, ("Can't remove the last member. At least one member should be related to a group.")); ++ ++ err = RemoveMember(p_ReplicGroup, memberIndex); ++ ++ /* unlock */ ++ FrmReplicGroupUnlock(p_ReplicGroup); ++ ++ switch (GET_ERROR_TYPE(err)) ++ { ++ case E_OK: ++ return E_OK; ++ ++ case E_BUSY: ++ DBG(TRACE, ("E_BUSY error")); ++ return ERROR_CODE(E_BUSY); ++ ++ default: ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++} ++ ++/*********************** End of API routines ************************/ ++ ++ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.h +new file mode 100644 +index 00000000..0e8e8bc0 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.h +@@ -0,0 +1,101 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_replic.h ++ ++ @Description FM frame replicator ++*//***************************************************************************/ ++#ifndef __FM_REPLIC_H ++#define __FM_REPLIC_H ++ ++#include "std_ext.h" ++#include "error_ext.h" ++ ++ ++#define FRM_REPLIC_SOURCE_TD_OPCODE 0x75 ++#define NEXT_FRM_REPLIC_ADDR_SHIFT 4 ++#define NEXT_FRM_REPLIC_MEMBER_INDEX_SHIFT 16 ++#define FRM_REPLIC_FR_BIT 0x08000000 ++#define FRM_REPLIC_NL_BIT 0x10000000 ++#define FRM_REPLIC_INVALID_MEMBER_INDEX 0xffff ++#define FRM_REPLIC_FIRST_MEMBER_INDEX 0 ++ ++#define FRM_REPLIC_MIDDLE_MEMBER_INDEX 1 ++#define FRM_REPLIC_LAST_MEMBER_INDEX 2 ++ ++#define SOURCE_TD_ITSELF_OPTION 0x01 ++#define SOURCE_TD_COPY_OPTION 0x02 ++#define SOURCE_TD_ITSELF_AND_COPY_OPTION SOURCE_TD_ITSELF_OPTION | SOURCE_TD_COPY_OPTION ++#define SOURCE_TD_NONE 0x04 ++ ++/*typedef enum e_SourceTdOption ++{ ++ e_SOURCE_TD_NONE = 0, ++ e_SOURCE_TD_ITSELF_OPTION = 1, ++ e_SOURCE_TD_COPY_OPTION = 2, ++ e_SOURCE_TD_ITSELF_AND_COPY_OPTION = e_SOURCE_TD_ITSELF_OPTION | e_SOURCE_TD_COPY_OPTION ++} e_SourceTdOption; ++*/ ++ ++typedef struct ++{ ++ volatile uint32_t type; ++ volatile uint32_t frGroupPointer; ++ volatile uint32_t operationCode; ++ volatile uint32_t reserved; ++} t_FrmReplicGroupSourceAd; ++ ++typedef struct t_FmPcdFrmReplicMember ++{ ++ void *p_MemberAd; /**< pointer to the member AD */ ++ void *p_StatisticsAd;/**< pointer to the statistics AD of the member */ ++ t_Handle h_Manip; /**< manip handle - need for free routines */ ++ t_List node; ++} t_FmPcdFrmReplicMember; ++ ++typedef struct t_FmPcdFrmReplicGroup ++{ ++ t_Handle h_FmPcd; ++ ++ uint8_t maxNumOfEntries;/**< maximal number of members in the group */ ++ uint8_t numOfEntries; /**< actual number of members in the group */ ++ uint16_t owners; /**< how many keys share this frame replicator group */ ++ void *p_SourceTd; /**< pointer to the frame replicator source table descriptor */ ++ t_List membersList; /**< the members list - should reflect the order of the members as in the hw linked list*/ ++ t_List availableMembersList;/**< list of all the available members in the group */ ++ t_FmPcdLock *p_Lock; ++} t_FmPcdFrmReplicGroup; ++ ++ ++#endif /* __FM_REPLIC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_kg.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_kg.c +new file mode 100644 +index 00000000..49b86e8e +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_kg.c +@@ -0,0 +1,888 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "fsl_fman_kg.h" ++ ++/****************************************/ ++/* static functions */ ++/****************************************/ ++ ++ ++static uint32_t build_ar_bind_scheme(uint8_t hwport_id, bool write) ++{ ++ uint32_t rw; ++ ++ rw = write ? (uint32_t)FM_KG_KGAR_WRITE : (uint32_t)FM_KG_KGAR_READ; ++ ++ return (uint32_t)(FM_KG_KGAR_GO | ++ rw | ++ FM_PCD_KG_KGAR_SEL_PORT_ENTRY | ++ hwport_id | ++ FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP); ++} ++ ++static void clear_pe_all_scheme(struct fman_kg_regs *regs, uint8_t hwport_id) ++{ ++ uint32_t ar; ++ ++ fman_kg_write_sp(regs, 0xffffffff, 0); ++ ++ ar = build_ar_bind_scheme(hwport_id, TRUE); ++ fman_kg_write_ar_wait(regs, ar); ++} ++ ++static uint32_t build_ar_bind_cls_plan(uint8_t hwport_id, bool write) ++{ ++ uint32_t rw; ++ ++ rw = write ? (uint32_t)FM_KG_KGAR_WRITE : (uint32_t)FM_KG_KGAR_READ; ++ ++ return (uint32_t)(FM_KG_KGAR_GO | ++ rw | ++ FM_PCD_KG_KGAR_SEL_PORT_ENTRY | ++ hwport_id | ++ FM_PCD_KG_KGAR_SEL_PORT_WSEL_CPP); ++} ++ ++static void clear_pe_all_cls_plan(struct fman_kg_regs *regs, uint8_t hwport_id) ++{ ++ uint32_t ar; ++ ++ fman_kg_write_cpp(regs, 0); ++ ++ ar = build_ar_bind_cls_plan(hwport_id, TRUE); ++ fman_kg_write_ar_wait(regs, ar); ++} ++ ++static uint8_t get_gen_ht_code(enum fman_kg_gen_extract_src src, ++ bool no_validation, ++ uint8_t *offset) ++{ ++ int code; ++ ++ switch (src) { ++ case E_FMAN_KG_GEN_EXTRACT_ETH: ++ code = no_validation ? 0x73 : 0x3; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_ETYPE: ++ code = no_validation ? 0x77 : 0x7; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_SNAP: ++ code = no_validation ? 0x74 : 0x4; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_VLAN_TCI_1: ++ code = no_validation ? 0x75 : 0x5; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_VLAN_TCI_N: ++ code = no_validation ? 0x76 : 0x6; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_PPPoE: ++ code = no_validation ? 0x78 : 0x8; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_MPLS_1: ++ code = no_validation ? 0x79 : 0x9; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_MPLS_2: ++ code = no_validation ? FM_KG_SCH_GEN_HT_INVALID : 0x19; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_MPLS_3: ++ code = no_validation ? FM_KG_SCH_GEN_HT_INVALID : 0x29; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_MPLS_N: ++ code = no_validation ? 0x7a : 0xa; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_IPv4_1: ++ code = no_validation ? 0x7b : 0xb; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_IPv6_1: ++ code = no_validation ? 0x7b : 0x1b; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_IPv4_2: ++ code = no_validation ? 0x7c : 0xc; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_IPv6_2: ++ code = no_validation ? 0x7c : 0x1c; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_MINENCAP: ++ code = no_validation ? 0x7c : 0x2c; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_IP_PID: ++ code = no_validation ? 0x72 : 0x2; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_GRE: ++ code = no_validation ? 0x7d : 0xd; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_TCP: ++ code = no_validation ? 0x7e : 0xe; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_UDP: ++ code = no_validation ? 0x7e : 0x1e; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_SCTP: ++ code = no_validation ? 0x7e : 0x3e; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_DCCP: ++ code = no_validation ? 0x7e : 0x4e; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_IPSEC_AH: ++ code = no_validation ? 0x7e : 0x2e; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_IPSEC_ESP: ++ code = no_validation ? 0x7e : 0x6e; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_SHIM_1: ++ code = 0x70; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_SHIM_2: ++ code = 0x71; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_FROM_DFLT: ++ code = 0x10; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_FROM_FRAME_START: ++ code = 0x40; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_FROM_PARSE_RESULT: ++ code = 0x20; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_FROM_END_OF_PARSE: ++ code = 0x7f; ++ break; ++ ++ case E_FMAN_KG_GEN_EXTRACT_FROM_FQID: ++ code = 0x20; ++ *offset += 0x20; ++ break; ++ ++ default: ++ code = FM_KG_SCH_GEN_HT_INVALID; ++ } ++ ++ return (uint8_t)code; ++} ++ ++static uint32_t build_ar_scheme(uint8_t scheme, ++ uint8_t hwport_id, ++ bool update_counter, ++ bool write) ++{ ++ uint32_t rw; ++ ++ rw = (uint32_t)(write ? FM_KG_KGAR_WRITE : FM_KG_KGAR_READ); ++ ++ return (uint32_t)(FM_KG_KGAR_GO | ++ rw | ++ FM_KG_KGAR_SEL_SCHEME_ENTRY | ++ hwport_id | ++ ((uint32_t)scheme << FM_KG_KGAR_NUM_SHIFT) | ++ (update_counter ? FM_KG_KGAR_SCM_WSEL_UPDATE_CNT : 0)); ++} ++ ++static uint32_t build_ar_cls_plan(uint8_t grp, ++ uint8_t entries_mask, ++ uint8_t hwport_id, ++ bool write) ++{ ++ uint32_t rw; ++ ++ rw = (uint32_t)(write ? FM_KG_KGAR_WRITE : FM_KG_KGAR_READ); ++ ++ return (uint32_t)(FM_KG_KGAR_GO | ++ rw | ++ FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY | ++ hwport_id | ++ ((uint32_t)grp << FM_KG_KGAR_NUM_SHIFT) | ++ ((uint32_t)entries_mask << FM_KG_KGAR_WSEL_SHIFT)); ++} ++ ++int fman_kg_write_ar_wait(struct fman_kg_regs *regs, uint32_t fmkg_ar) ++{ ++ iowrite32be(fmkg_ar, ®s->fmkg_ar); ++ /* Wait for GO to be idle and read error */ ++ while ((fmkg_ar = ioread32be(®s->fmkg_ar)) & FM_KG_KGAR_GO) ; ++ if (fmkg_ar & FM_PCD_KG_KGAR_ERR) ++ return -EINVAL; ++ return 0; ++} ++ ++void fman_kg_write_sp(struct fman_kg_regs *regs, uint32_t sp, bool add) ++{ ++ ++ struct fman_kg_pe_regs *kgpe_regs; ++ uint32_t tmp; ++ ++ kgpe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]); ++ tmp = ioread32be(&kgpe_regs->fmkg_pe_sp); ++ ++ if (add) ++ tmp |= sp; ++ else /* clear */ ++ tmp &= ~sp; ++ ++ iowrite32be(tmp, &kgpe_regs->fmkg_pe_sp); ++ ++} ++ ++void fman_kg_write_cpp(struct fman_kg_regs *regs, uint32_t cpp) ++{ ++ struct fman_kg_pe_regs *kgpe_regs; ++ ++ kgpe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]); ++ ++ iowrite32be(cpp, &kgpe_regs->fmkg_pe_cpp); ++} ++ ++void fman_kg_get_event(struct fman_kg_regs *regs, ++ uint32_t *event, ++ uint32_t *scheme_idx) ++{ ++ uint32_t mask, force; ++ ++ *event = ioread32be(®s->fmkg_eer); ++ mask = ioread32be(®s->fmkg_eeer); ++ *scheme_idx = ioread32be(®s->fmkg_seer); ++ *scheme_idx &= ioread32be(®s->fmkg_seeer); ++ ++ *event &= mask; ++ ++ /* clear the forced events */ ++ force = ioread32be(®s->fmkg_feer); ++ if (force & *event) ++ iowrite32be(force & ~*event ,®s->fmkg_feer); ++ ++ iowrite32be(*event, ®s->fmkg_eer); ++ iowrite32be(*scheme_idx, ®s->fmkg_seer); ++} ++ ++ ++void fman_kg_init(struct fman_kg_regs *regs, ++ uint32_t exceptions, ++ uint32_t dflt_nia) ++{ ++ uint32_t tmp; ++ int i; ++ ++ iowrite32be(FM_EX_KG_DOUBLE_ECC | FM_EX_KG_KEYSIZE_OVERFLOW, ++ ®s->fmkg_eer); ++ ++ tmp = 0; ++ if (exceptions & FM_EX_KG_DOUBLE_ECC) ++ tmp |= FM_EX_KG_DOUBLE_ECC; ++ ++ if (exceptions & FM_EX_KG_KEYSIZE_OVERFLOW) ++ tmp |= FM_EX_KG_KEYSIZE_OVERFLOW; ++ ++ iowrite32be(tmp, ®s->fmkg_eeer); ++ iowrite32be(0, ®s->fmkg_fdor); ++ iowrite32be(0, ®s->fmkg_gdv0r); ++ iowrite32be(0, ®s->fmkg_gdv1r); ++ iowrite32be(dflt_nia, ®s->fmkg_gcr); ++ ++ /* Clear binding between ports to schemes and classification plans ++ * so that all ports are not bound to any scheme/classification plan */ ++ for (i = 0; i < FMAN_MAX_NUM_OF_HW_PORTS; i++) { ++ clear_pe_all_scheme(regs, (uint8_t)i); ++ clear_pe_all_cls_plan(regs, (uint8_t)i); ++ } ++} ++ ++void fman_kg_enable_scheme_interrupts(struct fman_kg_regs *regs) ++{ ++ /* enable and enable all scheme interrupts */ ++ iowrite32be(0xFFFFFFFF, ®s->fmkg_seer); ++ iowrite32be(0xFFFFFFFF, ®s->fmkg_seeer); ++} ++ ++void fman_kg_enable(struct fman_kg_regs *regs) ++{ ++ iowrite32be(ioread32be(®s->fmkg_gcr) | FM_KG_KGGCR_EN, ++ ®s->fmkg_gcr); ++} ++ ++void fman_kg_disable(struct fman_kg_regs *regs) ++{ ++ iowrite32be(ioread32be(®s->fmkg_gcr) & ~FM_KG_KGGCR_EN, ++ ®s->fmkg_gcr); ++} ++ ++void fman_kg_set_data_after_prs(struct fman_kg_regs *regs, uint8_t offset) ++{ ++ iowrite32be(offset, ®s->fmkg_fdor); ++} ++ ++void fman_kg_set_dflt_val(struct fman_kg_regs *regs, ++ uint8_t def_id, ++ uint32_t val) ++{ ++ if(def_id == 0) ++ iowrite32be(val, ®s->fmkg_gdv0r); ++ else ++ iowrite32be(val, ®s->fmkg_gdv1r); ++} ++ ++ ++void fman_kg_set_exception(struct fman_kg_regs *regs, ++ uint32_t exception, ++ bool enable) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->fmkg_eeer); ++ ++ if (enable) { ++ tmp |= exception; ++ } else { ++ tmp &= ~exception; ++ } ++ ++ iowrite32be(tmp, ®s->fmkg_eeer); ++} ++ ++void fman_kg_get_exception(struct fman_kg_regs *regs, ++ uint32_t *events, ++ uint32_t *scheme_ids, ++ bool clear) ++{ ++ uint32_t mask; ++ ++ *events = ioread32be(®s->fmkg_eer); ++ mask = ioread32be(®s->fmkg_eeer); ++ *events &= mask; ++ ++ *scheme_ids = 0; ++ ++ if (*events & FM_EX_KG_KEYSIZE_OVERFLOW) { ++ *scheme_ids = ioread32be(®s->fmkg_seer); ++ mask = ioread32be(®s->fmkg_seeer); ++ *scheme_ids &= mask; ++ } ++ ++ if (clear) { ++ iowrite32be(*scheme_ids, ®s->fmkg_seer); ++ iowrite32be(*events, ®s->fmkg_eer); ++ } ++} ++ ++void fman_kg_get_capture(struct fman_kg_regs *regs, ++ struct fman_kg_ex_ecc_attr *ecc_attr, ++ bool clear) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->fmkg_serc); ++ ++ if (tmp & KG_FMKG_SERC_CAP) { ++ /* Captured data is valid */ ++ ecc_attr->valid = TRUE; ++ ecc_attr->double_ecc = ++ (bool)((tmp & KG_FMKG_SERC_CET) ? TRUE : FALSE); ++ ecc_attr->single_ecc_count = ++ (uint8_t)((tmp & KG_FMKG_SERC_CNT_MSK) >> ++ KG_FMKG_SERC_CNT_SHIFT); ++ ecc_attr->addr = (uint16_t)(tmp & KG_FMKG_SERC_ADDR_MSK); ++ ++ if (clear) ++ iowrite32be(KG_FMKG_SERC_CAP, ®s->fmkg_serc); ++ } else { ++ /* No ECC error is captured */ ++ ecc_attr->valid = FALSE; ++ } ++} ++ ++int fman_kg_build_scheme(struct fman_kg_scheme_params *params, ++ struct fman_kg_scheme_regs *scheme_regs) ++{ ++ struct fman_kg_extract_params *extract_params; ++ struct fman_kg_gen_extract_params *gen_params; ++ uint32_t tmp_reg, i, select, mask, fqb; ++ uint8_t offset, shift, ht; ++ ++ /* Zero out all registers so no need to care about unused ones */ ++ memset(scheme_regs, 0, sizeof(struct fman_kg_scheme_regs)); ++ ++ /* Mode register */ ++ tmp_reg = fm_kg_build_nia(params->next_engine, ++ params->next_engine_action); ++ if (tmp_reg == KG_NIA_INVALID) { ++ return -EINVAL; ++ } ++ ++ if (params->next_engine == E_FMAN_PCD_PLCR) { ++ tmp_reg |= FMAN_KG_SCH_MODE_NIA_PLCR; ++ } ++ else if (params->next_engine == E_FMAN_PCD_CC) { ++ tmp_reg |= (uint32_t)params->cc_params.base_offset << ++ FMAN_KG_SCH_MODE_CCOBASE_SHIFT; ++ } ++ ++ tmp_reg |= FMAN_KG_SCH_MODE_EN; ++ scheme_regs->kgse_mode = tmp_reg; ++ ++ /* Match vector */ ++ scheme_regs->kgse_mv = params->match_vector; ++ ++ extract_params = ¶ms->extract_params; ++ ++ /* Scheme default values registers */ ++ scheme_regs->kgse_dv0 = extract_params->def_scheme_0; ++ scheme_regs->kgse_dv1 = extract_params->def_scheme_1; ++ ++ /* Extract Known Fields Command register */ ++ scheme_regs->kgse_ekfc = extract_params->known_fields; ++ ++ /* Entry Extract Known Default Value register */ ++ tmp_reg = 0; ++ tmp_reg |= extract_params->known_fields_def.mac_addr << ++ FMAN_KG_SCH_DEF_MAC_ADDR_SHIFT; ++ tmp_reg |= extract_params->known_fields_def.vlan_tci << ++ FMAN_KG_SCH_DEF_VLAN_TCI_SHIFT; ++ tmp_reg |= extract_params->known_fields_def.etype << ++ FMAN_KG_SCH_DEF_ETYPE_SHIFT; ++ tmp_reg |= extract_params->known_fields_def.ppp_sid << ++ FMAN_KG_SCH_DEF_PPP_SID_SHIFT; ++ tmp_reg |= extract_params->known_fields_def.ppp_pid << ++ FMAN_KG_SCH_DEF_PPP_PID_SHIFT; ++ tmp_reg |= extract_params->known_fields_def.mpls << ++ FMAN_KG_SCH_DEF_MPLS_SHIFT; ++ tmp_reg |= extract_params->known_fields_def.ip_addr << ++ FMAN_KG_SCH_DEF_IP_ADDR_SHIFT; ++ tmp_reg |= extract_params->known_fields_def.ptype << ++ FMAN_KG_SCH_DEF_PTYPE_SHIFT; ++ tmp_reg |= extract_params->known_fields_def.ip_tos_tc << ++ FMAN_KG_SCH_DEF_IP_TOS_TC_SHIFT; ++ tmp_reg |= extract_params->known_fields_def.ipv6_fl << ++ FMAN_KG_SCH_DEF_IPv6_FL_SHIFT; ++ tmp_reg |= extract_params->known_fields_def.ipsec_spi << ++ FMAN_KG_SCH_DEF_IPSEC_SPI_SHIFT; ++ tmp_reg |= extract_params->known_fields_def.l4_port << ++ FMAN_KG_SCH_DEF_L4_PORT_SHIFT; ++ tmp_reg |= extract_params->known_fields_def.tcp_flg << ++ FMAN_KG_SCH_DEF_TCP_FLG_SHIFT; ++ ++ scheme_regs->kgse_ekdv = tmp_reg; ++ ++ /* Generic extract registers */ ++ if (extract_params->gen_extract_num > FM_KG_NUM_OF_GENERIC_REGS) { ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < extract_params->gen_extract_num; i++) { ++ gen_params = extract_params->gen_extract + i; ++ ++ tmp_reg = FMAN_KG_SCH_GEN_VALID; ++ tmp_reg |= (uint32_t)gen_params->def_val << ++ FMAN_KG_SCH_GEN_DEF_SHIFT; ++ ++ if (gen_params->type == E_FMAN_KG_HASH_EXTRACT) { ++ if ((gen_params->extract > FMAN_KG_SCH_GEN_SIZE_MAX) || ++ (gen_params->extract == 0)) { ++ return -EINVAL; ++ } ++ } else { ++ tmp_reg |= FMAN_KG_SCH_GEN_OR; ++ } ++ ++ tmp_reg |= (uint32_t)gen_params->extract << ++ FMAN_KG_SCH_GEN_SIZE_SHIFT; ++ tmp_reg |= (uint32_t)gen_params->mask << ++ FMAN_KG_SCH_GEN_MASK_SHIFT; ++ ++ offset = gen_params->offset; ++ ht = get_gen_ht_code(gen_params->src, ++ gen_params->no_validation, ++ &offset); ++ tmp_reg |= (uint32_t)ht << FMAN_KG_SCH_GEN_HT_SHIFT; ++ tmp_reg |= offset; ++ ++ scheme_regs->kgse_gec[i] = tmp_reg; ++ } ++ ++ /* Masks registers */ ++ if (extract_params->masks_num > FM_KG_EXTRACT_MASKS_NUM) { ++ return -EINVAL; ++ } ++ ++ select = 0; ++ mask = 0; ++ fqb = 0; ++ for (i = 0; i < extract_params->masks_num; i++) { ++ /* MCSx fields */ ++ KG_GET_MASK_SEL_SHIFT(shift, i); ++ if (extract_params->masks[i].is_known) { ++ /* Mask known field */ ++ select |= extract_params->masks[i].field_or_gen_idx << ++ shift; ++ } else { ++ /* Mask generic extract */ ++ select |= (extract_params->masks[i].field_or_gen_idx + ++ FM_KG_MASK_SEL_GEN_BASE) << shift; ++ } ++ ++ /* MOx fields - spread between se_bmch and se_fqb registers */ ++ KG_GET_MASK_OFFSET_SHIFT(shift, i); ++ if (i < 2) { ++ select |= (uint32_t)extract_params->masks[i].offset << ++ shift; ++ } else { ++ fqb |= (uint32_t)extract_params->masks[i].offset << ++ shift; ++ } ++ ++ /* BMx fields */ ++ KG_GET_MASK_SHIFT(shift, i); ++ mask |= (uint32_t)extract_params->masks[i].mask << shift; ++ } ++ ++ /* Finish with rest of BMx fileds - ++ * don't mask bits for unused masks by setting ++ * corresponding BMx field = 0xFF */ ++ for (i = extract_params->masks_num; i < FM_KG_EXTRACT_MASKS_NUM; i++) { ++ KG_GET_MASK_SHIFT(shift, i); ++ mask |= 0xFF << shift; ++ } ++ ++ scheme_regs->kgse_bmch = select; ++ scheme_regs->kgse_bmcl = mask; ++ ++ /* Finish with FQB register initialization. ++ * Check fqid is 24-bit value. */ ++ if (params->base_fqid & ~0x00FFFFFF) { ++ return -EINVAL; ++ } ++ ++ fqb |= params->base_fqid; ++ scheme_regs->kgse_fqb = fqb; ++ ++ /* Hash Configuration register */ ++ tmp_reg = 0; ++ if (params->hash_params.use_hash) { ++ /* Check hash mask is 24-bit value */ ++ if (params->hash_params.mask & ~0x00FFFFFF) { ++ return -EINVAL; ++ } ++ ++ /* Hash function produces 64-bit value, 24 bits of that ++ * are used to generate fq_id and policer profile. ++ * Thus, maximal shift is 40 bits to allow 24 bits out of 64. ++ */ ++ if (params->hash_params.shift_r > FMAN_KG_SCH_HASH_HSHIFT_MAX) { ++ return -EINVAL; ++ } ++ ++ tmp_reg |= params->hash_params.mask; ++ tmp_reg |= (uint32_t)params->hash_params.shift_r << ++ FMAN_KG_SCH_HASH_HSHIFT_SHIFT; ++ ++ if (params->hash_params.sym) { ++ tmp_reg |= FMAN_KG_SCH_HASH_SYM; ++ } ++ ++ } ++ ++ if (params->bypass_fqid_gen) { ++ tmp_reg |= FMAN_KG_SCH_HASH_NO_FQID_GEN; ++ } ++ ++ scheme_regs->kgse_hc = tmp_reg; ++ ++ /* Policer Profile register */ ++ if (params->policer_params.bypass_pp_gen) { ++ tmp_reg = 0; ++ } else { ++ /* Lower 8 bits of 24-bits extracted from hash result ++ * are used for policer profile generation. ++ * That leaves maximum shift value = 23. */ ++ if (params->policer_params.shift > FMAN_KG_SCH_PP_SHIFT_MAX) { ++ return -EINVAL; ++ } ++ ++ tmp_reg = params->policer_params.base; ++ tmp_reg |= ((uint32_t)params->policer_params.shift << ++ FMAN_KG_SCH_PP_SH_SHIFT) & ++ FMAN_KG_SCH_PP_SH_MASK; ++ tmp_reg |= ((uint32_t)params->policer_params.shift << ++ FMAN_KG_SCH_PP_SL_SHIFT) & ++ FMAN_KG_SCH_PP_SL_MASK; ++ tmp_reg |= (uint32_t)params->policer_params.mask << ++ FMAN_KG_SCH_PP_MASK_SHIFT; ++ } ++ ++ scheme_regs->kgse_ppc = tmp_reg; ++ ++ /* Coarse Classification Bit Select register */ ++ if (params->next_engine == E_FMAN_PCD_CC) { ++ scheme_regs->kgse_ccbs = params->cc_params.qlcv_bits_sel; ++ } ++ ++ /* Packets Counter register */ ++ if (params->update_counter) { ++ scheme_regs->kgse_spc = params->counter_value; ++ } ++ ++ return 0; ++} ++ ++int fman_kg_write_scheme(struct fman_kg_regs *regs, ++ uint8_t scheme_id, ++ uint8_t hwport_id, ++ struct fman_kg_scheme_regs *scheme_regs, ++ bool update_counter) ++{ ++ struct fman_kg_scheme_regs *kgse_regs; ++ uint32_t tmp_reg; ++ int err, i; ++ ++ /* Write indirect scheme registers */ ++ kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]); ++ ++ iowrite32be(scheme_regs->kgse_mode, &kgse_regs->kgse_mode); ++ iowrite32be(scheme_regs->kgse_ekfc, &kgse_regs->kgse_ekfc); ++ iowrite32be(scheme_regs->kgse_ekdv, &kgse_regs->kgse_ekdv); ++ iowrite32be(scheme_regs->kgse_bmch, &kgse_regs->kgse_bmch); ++ iowrite32be(scheme_regs->kgse_bmcl, &kgse_regs->kgse_bmcl); ++ iowrite32be(scheme_regs->kgse_fqb, &kgse_regs->kgse_fqb); ++ iowrite32be(scheme_regs->kgse_hc, &kgse_regs->kgse_hc); ++ iowrite32be(scheme_regs->kgse_ppc, &kgse_regs->kgse_ppc); ++ iowrite32be(scheme_regs->kgse_spc, &kgse_regs->kgse_spc); ++ iowrite32be(scheme_regs->kgse_dv0, &kgse_regs->kgse_dv0); ++ iowrite32be(scheme_regs->kgse_dv1, &kgse_regs->kgse_dv1); ++ iowrite32be(scheme_regs->kgse_ccbs, &kgse_regs->kgse_ccbs); ++ iowrite32be(scheme_regs->kgse_mv, &kgse_regs->kgse_mv); ++ ++ for (i = 0 ; i < FM_KG_NUM_OF_GENERIC_REGS ; i++) ++ iowrite32be(scheme_regs->kgse_gec[i], &kgse_regs->kgse_gec[i]); ++ ++ /* Write AR (Action register) */ ++ tmp_reg = build_ar_scheme(scheme_id, hwport_id, update_counter, TRUE); ++ err = fman_kg_write_ar_wait(regs, tmp_reg); ++ return err; ++} ++ ++int fman_kg_delete_scheme(struct fman_kg_regs *regs, ++ uint8_t scheme_id, ++ uint8_t hwport_id) ++{ ++ struct fman_kg_scheme_regs *kgse_regs; ++ uint32_t tmp_reg; ++ int err, i; ++ ++ kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]); ++ ++ /* Clear all registers including enable bit in mode register */ ++ for (i = 0; i < (sizeof(struct fman_kg_scheme_regs)) / 4; ++i) { ++ iowrite32be(0, ((uint32_t *)kgse_regs + i)); ++ } ++ ++ /* Write AR (Action register) */ ++ tmp_reg = build_ar_scheme(scheme_id, hwport_id, FALSE, TRUE); ++ err = fman_kg_write_ar_wait(regs, tmp_reg); ++ return err; ++} ++ ++int fman_kg_get_scheme_counter(struct fman_kg_regs *regs, ++ uint8_t scheme_id, ++ uint8_t hwport_id, ++ uint32_t *counter) ++{ ++ struct fman_kg_scheme_regs *kgse_regs; ++ uint32_t tmp_reg; ++ int err; ++ ++ kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]); ++ ++ tmp_reg = build_ar_scheme(scheme_id, hwport_id, TRUE, FALSE); ++ err = fman_kg_write_ar_wait(regs, tmp_reg); ++ ++ if (err != 0) ++ return err; ++ ++ *counter = ioread32be(&kgse_regs->kgse_spc); ++ ++ return 0; ++} ++ ++int fman_kg_set_scheme_counter(struct fman_kg_regs *regs, ++ uint8_t scheme_id, ++ uint8_t hwport_id, ++ uint32_t counter) ++{ ++ struct fman_kg_scheme_regs *kgse_regs; ++ uint32_t tmp_reg; ++ int err; ++ ++ kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]); ++ ++ tmp_reg = build_ar_scheme(scheme_id, hwport_id, TRUE, FALSE); ++ ++ err = fman_kg_write_ar_wait(regs, tmp_reg); ++ if (err != 0) ++ return err; ++ ++ /* Keygen indirect access memory contains all scheme_id registers ++ * by now. Change only counter value. */ ++ iowrite32be(counter, &kgse_regs->kgse_spc); ++ ++ /* Write back scheme registers */ ++ tmp_reg = build_ar_scheme(scheme_id, hwport_id, TRUE, TRUE); ++ err = fman_kg_write_ar_wait(regs, tmp_reg); ++ ++ return err; ++} ++ ++uint32_t fman_kg_get_schemes_total_counter(struct fman_kg_regs *regs) ++{ ++ return ioread32be(®s->fmkg_tpc); ++} ++ ++int fman_kg_build_cls_plan(struct fman_kg_cls_plan_params *params, ++ struct fman_kg_cp_regs *cls_plan_regs) ++{ ++ uint8_t entries_set, entry_bit; ++ int i; ++ ++ /* Zero out all group's register */ ++ memset(cls_plan_regs, 0, sizeof(struct fman_kg_cp_regs)); ++ ++ /* Go over all classification entries in params->entries_mask and ++ * configure the corresponding cpe register */ ++ entries_set = params->entries_mask; ++ for (i = 0; entries_set; i++) { ++ entry_bit = (uint8_t)(0x80 >> i); ++ if ((entry_bit & entries_set) == 0) ++ continue; ++ entries_set ^= entry_bit; ++ cls_plan_regs->kgcpe[i] = params->mask_vector[i]; ++ } ++ ++ return 0; ++} ++ ++int fman_kg_write_cls_plan(struct fman_kg_regs *regs, ++ uint8_t grp_id, ++ uint8_t entries_mask, ++ uint8_t hwport_id, ++ struct fman_kg_cp_regs *cls_plan_regs) ++{ ++ struct fman_kg_cp_regs *kgcpe_regs; ++ uint32_t tmp_reg; ++ int i, err; ++ ++ /* Check group index is valid and the group isn't empty */ ++ if (grp_id >= FM_KG_CLS_PLAN_GRPS_NUM) ++ return -EINVAL; ++ ++ /* Write indirect classification plan registers */ ++ kgcpe_regs = (struct fman_kg_cp_regs *)&(regs->fmkg_indirect[0]); ++ ++ for (i = 0; i < FM_KG_NUM_CLS_PLAN_ENTR; i++) { ++ iowrite32be(cls_plan_regs->kgcpe[i], &kgcpe_regs->kgcpe[i]); ++ } ++ ++ tmp_reg = build_ar_cls_plan(grp_id, entries_mask, hwport_id, TRUE); ++ err = fman_kg_write_ar_wait(regs, tmp_reg); ++ return err; ++} ++ ++int fman_kg_write_bind_schemes(struct fman_kg_regs *regs, ++ uint8_t hwport_id, ++ uint32_t schemes) ++{ ++ struct fman_kg_pe_regs *kg_pe_regs; ++ uint32_t tmp_reg; ++ int err; ++ ++ kg_pe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]); ++ ++ iowrite32be(schemes, &kg_pe_regs->fmkg_pe_sp); ++ ++ tmp_reg = build_ar_bind_scheme(hwport_id, TRUE); ++ err = fman_kg_write_ar_wait(regs, tmp_reg); ++ return err; ++} ++ ++int fman_kg_build_bind_cls_plans(uint8_t grp_base, ++ uint8_t grp_mask, ++ uint32_t *bind_cls_plans) ++{ ++ /* Check grp_base and grp_mask are 5-bits values */ ++ if ((grp_base & ~0x0000001F) || (grp_mask & ~0x0000001F)) ++ return -EINVAL; ++ ++ *bind_cls_plans = (uint32_t) ((grp_mask << FMAN_KG_PE_CPP_MASK_SHIFT) | grp_base); ++ return 0; ++} ++ ++ ++int fman_kg_write_bind_cls_plans(struct fman_kg_regs *regs, ++ uint8_t hwport_id, ++ uint32_t bind_cls_plans) ++{ ++ struct fman_kg_pe_regs *kg_pe_regs; ++ uint32_t tmp_reg; ++ int err; ++ ++ kg_pe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]); ++ ++ iowrite32be(bind_cls_plans, &kg_pe_regs->fmkg_pe_cpp); ++ ++ tmp_reg = build_ar_bind_cls_plan(hwport_id, TRUE); ++ err = fman_kg_write_ar_wait(regs, tmp_reg); ++ return err; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_prs.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_prs.c +new file mode 100644 +index 00000000..108779db +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_prs.c +@@ -0,0 +1,129 @@ ++/* ++ * Copyright 2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "fsl_fman_prs.h" ++ ++uint32_t fman_prs_get_err_event(struct fman_prs_regs *regs, uint32_t ev_mask) ++{ ++ return ioread32be(®s->fmpr_perr) & ev_mask; ++} ++ ++uint32_t fman_prs_get_err_ev_mask(struct fman_prs_regs *regs) ++{ ++ return ioread32be(®s->fmpr_perer); ++} ++ ++void fman_prs_ack_err_event(struct fman_prs_regs *regs, uint32_t event) ++{ ++ iowrite32be(event, ®s->fmpr_perr); ++} ++ ++uint32_t fman_prs_get_expt_event(struct fman_prs_regs *regs, uint32_t ev_mask) ++{ ++ return ioread32be(®s->fmpr_pevr) & ev_mask; ++} ++ ++uint32_t fman_prs_get_expt_ev_mask(struct fman_prs_regs *regs) ++{ ++ return ioread32be(®s->fmpr_pever); ++} ++ ++void fman_prs_ack_expt_event(struct fman_prs_regs *regs, uint32_t event) ++{ ++ iowrite32be(event, ®s->fmpr_pevr); ++} ++ ++void fman_prs_defconfig(struct fman_prs_cfg *cfg) ++{ ++ cfg->port_id_stat = 0; ++ cfg->max_prs_cyc_lim = DEFAULT_MAX_PRS_CYC_LIM; ++ cfg->prs_exceptions = 0x03000000; ++} ++ ++int fman_prs_init(struct fman_prs_regs *regs, struct fman_prs_cfg *cfg) ++{ ++ uint32_t tmp; ++ ++ iowrite32be(cfg->max_prs_cyc_lim, ®s->fmpr_rpclim); ++ iowrite32be((FM_PCD_PRS_SINGLE_ECC | FM_PCD_PRS_PORT_IDLE_STS), ++ ®s->fmpr_pevr); ++ ++ if (cfg->prs_exceptions & FM_PCD_EX_PRS_SINGLE_ECC) ++ iowrite32be(FM_PCD_PRS_SINGLE_ECC, ®s->fmpr_pever); ++ else ++ iowrite32be(0, ®s->fmpr_pever); ++ ++ iowrite32be(FM_PCD_PRS_DOUBLE_ECC, ®s->fmpr_perr); ++ ++ tmp = 0; ++ if (cfg->prs_exceptions & FM_PCD_EX_PRS_DOUBLE_ECC) ++ tmp |= FM_PCD_PRS_DOUBLE_ECC; ++ iowrite32be(tmp, ®s->fmpr_perer); ++ ++ iowrite32be(cfg->port_id_stat, ®s->fmpr_ppsc); ++ ++ return 0; ++} ++ ++void fman_prs_enable(struct fman_prs_regs *regs) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->fmpr_rpimac) | FM_PCD_PRS_RPIMAC_EN; ++ iowrite32be(tmp, ®s->fmpr_rpimac); ++} ++ ++void fman_prs_disable(struct fman_prs_regs *regs) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(®s->fmpr_rpimac) & ~FM_PCD_PRS_RPIMAC_EN; ++ iowrite32be(tmp, ®s->fmpr_rpimac); ++} ++ ++int fman_prs_is_enabled(struct fman_prs_regs *regs) ++{ ++ return ioread32be(®s->fmpr_rpimac) & FM_PCD_PRS_RPIMAC_EN; ++} ++ ++void fman_prs_set_stst_port_msk(struct fman_prs_regs *regs, uint32_t pid_msk) ++{ ++ iowrite32be(pid_msk, ®s->fmpr_ppsc); ++} ++ ++void fman_prs_set_stst(struct fman_prs_regs *regs, bool enable) ++{ ++ if (enable) ++ iowrite32be(FM_PCD_PRS_PPSC_ALL_PORTS, ®s->fmpr_ppsc); ++ else ++ iowrite32be(0, ®s->fmpr_ppsc); ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/Makefile +new file mode 100644 +index 00000000..7d928e0a +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/Makefile +@@ -0,0 +1,15 @@ ++# ++# Makefile for the Freescale Ethernet controllers ++# ++ccflags-y += -DVERSION=\"\" ++# ++#Include netcomm SW specific definitions ++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk ++ ++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc ++ ++ccflags-y += -I$(NCSW_FM_INC) ++ ++obj-y += fsl-ncsw-Pcd.o ++ ++fsl-ncsw-Pcd-objs := fm_port.o fm_port_im.o fman_port.o +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c +new file mode 100644 +index 00000000..ec6e0ed5 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c +@@ -0,0 +1,6436 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_port.c ++ ++ @Description FM driver routines implementation. ++ *//***************************************************************************/ ++#include "error_ext.h" ++#include "std_ext.h" ++#include "string_ext.h" ++#include "sprint_ext.h" ++#include "debug_ext.h" ++#include "fm_muram_ext.h" ++ ++#include "fman_common.h" ++#include "fm_port.h" ++#include "fm_port_dsar.h" ++#include "common/general.h" ++ ++/****************************************/ ++/* static functions */ ++/****************************************/ ++static t_Error FmPortConfigAutoResForDeepSleepSupport1(t_FmPort *p_FmPort); ++ ++static t_Error CheckInitParameters(t_FmPort *p_FmPort) ++{ ++ t_FmPortDriverParam *p_Params = p_FmPort->p_FmPortDriverParam; ++ struct fman_port_cfg *p_DfltConfig = &p_Params->dfltCfg; ++ t_Error ans = E_OK; ++ uint32_t unusedMask; ++ ++ if (p_FmPort->imEn) ++ { ++ if (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) ++ if (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth ++ > 2) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("fifoDeqPipelineDepth for IM 10G can't be larger than 2")); ++ ++ if ((ans = FmPortImCheckInitParameters(p_FmPort)) != E_OK) ++ return ERROR_CODE(ans); ++ } ++ else ++ { ++ /****************************************/ ++ /* Rx only */ ++ /****************************************/ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) ++ { ++ /* external buffer pools */ ++ if (!p_Params->extBufPools.numOfPoolsUsed) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("extBufPools.numOfPoolsUsed=0. At least one buffer pool must be defined")); ++ ++ if (FmSpCheckBufPoolsParams(&p_Params->extBufPools, ++ p_Params->p_BackupBmPools, ++ &p_Params->bufPoolDepletion) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); ++ ++ /* Check that part of IC that needs copying is small enough to enter start margin */ ++ if (p_Params->intContext.size ++ && (p_Params->intContext.size ++ + p_Params->intContext.extBufOffset ++ > p_Params->bufMargins.startMargins)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("intContext.size is larger than start margins")); ++ ++ if ((p_Params->liodnOffset != (uint16_t)DPAA_LIODN_DONT_OVERRIDE) ++ && (p_Params->liodnOffset & ~FM_LIODN_OFFSET_MASK)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1)); ++ ++#ifdef FM_NO_BACKUP_POOLS ++ if ((p_FmPort->fmRevInfo.majorRev != 4) && (p_FmPort->fmRevInfo.majorRev < 6)) ++ if (p_FmPort->p_FmPortDriverParam->p_BackupBmPools) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("BackupBmPools")); ++#endif /* FM_NO_BACKUP_POOLS */ ++ } ++ ++ /****************************************/ ++ /* Non Rx ports */ ++ /****************************************/ ++ else ++ { ++ if (p_Params->deqSubPortal >= FM_MAX_NUM_OF_SUB_PORTALS) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ (" deqSubPortal has to be in the range of 0 - %d", FM_MAX_NUM_OF_SUB_PORTALS)); ++ ++ /* to protect HW internal-context from overwrite */ ++ if ((p_Params->intContext.size) ++ && (p_Params->intContext.intContextOffset ++ < MIN_TX_INT_OFFSET)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("non-Rx intContext.intContextOffset can't be smaller than %d", MIN_TX_INT_OFFSET)); ++ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_TX) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) ++ /* in O/H DEFAULT_notSupported indicates that it is not supported and should not be checked */ ++ || (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth ++ != DEFAULT_notSupported)) ++ { ++ /* Check that not larger than 8 */ ++ if ((!p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth) ++ || (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth ++ > MAX_FIFO_PIPELINE_DEPTH)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("fifoDeqPipelineDepth can't be larger than %d", MAX_FIFO_PIPELINE_DEPTH)); ++ } ++ } ++ ++ /****************************************/ ++ /* Rx Or Offline Parsing */ ++ /****************************************/ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ++ { ++ if (!p_Params->dfltFqid) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("dfltFqid must be between 1 and 2^24-1")); ++#if defined(FM_CAPWAP_SUPPORT) && defined(FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004) ++ if (p_FmPort->p_FmPortDriverParam->bufferPrefixContent.manipExtraSpace % 16) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufferPrefixContent.manipExtraSpace has to be devidable by 16")); ++#endif /* defined(FM_CAPWAP_SUPPORT) && ... */ ++ } ++ ++ /****************************************/ ++ /* All ports */ ++ /****************************************/ ++ /* common BMI registers values */ ++ /* Check that Queue Id is not larger than 2^24, and is not 0 */ ++ if ((p_Params->errFqid & ~0x00FFFFFF) || !p_Params->errFqid) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("errFqid must be between 1 and 2^24-1")); ++ if (p_Params->dfltFqid & ~0x00FFFFFF) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("dfltFqid must be between 1 and 2^24-1")); ++ } ++ ++ /****************************************/ ++ /* Rx only */ ++ /****************************************/ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) ++ { ++ if (p_DfltConfig->rx_pri_elevation % BMI_FIFO_UNITS) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("rxFifoPriElevationLevel has to be divisible by %d", BMI_FIFO_UNITS)); ++ if ((p_DfltConfig->rx_pri_elevation < BMI_FIFO_UNITS) ++ || (p_DfltConfig->rx_pri_elevation > MAX_PORT_FIFO_SIZE)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("rxFifoPriElevationLevel has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE)); ++ if (p_DfltConfig->rx_fifo_thr % BMI_FIFO_UNITS) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("rxFifoThreshold has to be divisible by %d", BMI_FIFO_UNITS)); ++ if ((p_DfltConfig->rx_fifo_thr < BMI_FIFO_UNITS) ++ || (p_DfltConfig->rx_fifo_thr > MAX_PORT_FIFO_SIZE)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("rxFifoThreshold has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE)); ++ ++ /* Check that not larger than 16 */ ++ if (p_DfltConfig->rx_cut_end_bytes > FRAME_END_DATA_SIZE) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("cutBytesFromEnd can't be larger than %d", FRAME_END_DATA_SIZE)); ++ ++ if (FmSpCheckBufMargins(&p_Params->bufMargins) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); ++ ++ /* extra FIFO size (allowed only to Rx ports) */ ++ if (p_Params->setSizeOfFifo ++ && (p_FmPort->fifoBufs.extra % BMI_FIFO_UNITS)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("fifoBufs.extra has to be divisible by %d", BMI_FIFO_UNITS)); ++ ++ if (p_Params->bufPoolDepletion.poolsGrpModeEnable ++ && !p_Params->bufPoolDepletion.numOfPools) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("bufPoolDepletion.numOfPools can not be 0 when poolsGrpModeEnable=TRUE")); ++#ifdef FM_CSI_CFED_LIMIT ++ if (p_FmPort->fmRevInfo.majorRev == 4) ++ { ++ /* Check that not larger than 16 */ ++ if (p_DfltConfig->rx_cut_end_bytes + p_DfltConfig->checksum_bytes_ignore > FRAME_END_DATA_SIZE) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("cheksumLastBytesIgnore + cutBytesFromEnd can't be larger than %d", FRAME_END_DATA_SIZE)); ++ } ++#endif /* FM_CSI_CFED_LIMIT */ ++ } ++ ++ /****************************************/ ++ /* Non Rx ports */ ++ /****************************************/ ++ /* extra FIFO size (allowed only to Rx ports) */ ++ else ++ if (p_FmPort->fifoBufs.extra) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ (" No fifoBufs.extra for non Rx ports")); ++ ++ /****************************************/ ++ /* Tx only */ ++ /****************************************/ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_TX) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)) ++ { ++ if (p_DfltConfig->tx_fifo_min_level % BMI_FIFO_UNITS) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("txFifoMinFillLevel has to be divisible by %d", BMI_FIFO_UNITS)); ++ if (p_DfltConfig->tx_fifo_min_level > (MAX_PORT_FIFO_SIZE - 256)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("txFifoMinFillLevel has to be in the range of 0 - %d", (MAX_PORT_FIFO_SIZE - 256))); ++ if (p_DfltConfig->tx_fifo_low_comf_level % BMI_FIFO_UNITS) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("txFifoLowComfLevel has to be divisible by %d", BMI_FIFO_UNITS)); ++ if ((p_DfltConfig->tx_fifo_low_comf_level < BMI_FIFO_UNITS) ++ || (p_DfltConfig->tx_fifo_low_comf_level > MAX_PORT_FIFO_SIZE)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("txFifoLowComfLevel has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE)); ++ ++ if (p_FmPort->portType == e_FM_PORT_TYPE_TX) ++ if (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth ++ > 2) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("fifoDeqPipelineDepth for 1G can't be larger than 2")); ++ } ++ ++ /****************************************/ ++ /* Non Tx Ports */ ++ /****************************************/ ++ /* If discard override was selected , no frames may be discarded. */ ++ else ++ if (p_DfltConfig->discard_override && p_Params->errorsToDiscard) ++ RETURN_ERROR( ++ MAJOR, ++ E_CONFLICT, ++ ("errorsToDiscard is not empty, but frmDiscardOverride selected (all discarded frames to be enqueued to error queue).")); ++ ++ /****************************************/ ++ /* Rx and Offline parsing */ ++ /****************************************/ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ++ { ++ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ unusedMask = BMI_STATUS_OP_MASK_UNUSED; ++ else ++ unusedMask = BMI_STATUS_RX_MASK_UNUSED; ++ ++ /* Check that no common bits with BMI_STATUS_MASK_UNUSED */ ++ if (p_Params->errorsToDiscard & unusedMask) ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ++ ("errorsToDiscard contains undefined bits")); ++ } ++ ++ /****************************************/ ++ /* Offline Ports */ ++ /****************************************/ ++#ifdef FM_OP_OPEN_DMA_MIN_LIMIT ++ if ((p_FmPort->fmRevInfo.majorRev >= 6) ++ && (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ && p_Params->setNumOfOpenDmas ++ && (p_FmPort->openDmas.num < MIN_NUM_OF_OP_DMAS)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("For Offline port, openDmas.num can't be smaller than %d", MIN_NUM_OF_OP_DMAS)); ++#endif /* FM_OP_OPEN_DMA_MIN_LIMIT */ ++ ++ /****************************************/ ++ /* Offline & HC Ports */ ++ /****************************************/ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) ++ { ++#ifndef FM_FRAME_END_PARAMS_FOR_OP ++ if ((p_FmPort->fmRevInfo.majorRev < 6) && ++ (p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore != DEFAULT_notSupported)) ++ /* this is an indication that user called config for this mode which is not supported in this integration */ ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("cheksumLastBytesIgnore is available for Rx & Tx ports only")); ++#endif /* !FM_FRAME_END_PARAMS_FOR_OP */ ++ ++#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP ++ if ((!((p_FmPort->fmRevInfo.majorRev == 4) || ++ (p_FmPort->fmRevInfo.majorRev >= 6))) && ++ (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth != DEFAULT_notSupported)) ++ /* this is an indication that user called config for this mode which is not supported in this integration */ ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("fifoDeqPipelineDepth is available for Tx ports only")); ++#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */ ++ } ++ ++ /****************************************/ ++ /* All ports */ ++ /****************************************/ ++ /* Check that not larger than 16 */ ++ if ((p_Params->cheksumLastBytesIgnore > FRAME_END_DATA_SIZE) ++ && ((p_Params->cheksumLastBytesIgnore != DEFAULT_notSupported))) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("cheksumLastBytesIgnore can't be larger than %d", FRAME_END_DATA_SIZE)); ++ ++ if (FmSpCheckIntContextParams(&p_Params->intContext) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); ++ ++ /* common BMI registers values */ ++ if (p_Params->setNumOfTasks ++ && ((!p_FmPort->tasks.num) ++ || (p_FmPort->tasks.num > MAX_NUM_OF_TASKS))) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("tasks.num can't be larger than %d", MAX_NUM_OF_TASKS)); ++ if (p_Params->setNumOfTasks ++ && (p_FmPort->tasks.extra > MAX_NUM_OF_EXTRA_TASKS)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("tasks.extra can't be larger than %d", MAX_NUM_OF_EXTRA_TASKS)); ++ if (p_Params->setNumOfOpenDmas ++ && ((!p_FmPort->openDmas.num) ++ || (p_FmPort->openDmas.num > MAX_NUM_OF_DMAS))) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("openDmas.num can't be larger than %d", MAX_NUM_OF_DMAS)); ++ if (p_Params->setNumOfOpenDmas ++ && (p_FmPort->openDmas.extra > MAX_NUM_OF_EXTRA_DMAS)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("openDmas.extra can't be larger than %d", MAX_NUM_OF_EXTRA_DMAS)); ++ if (p_Params->setSizeOfFifo ++ && (!p_FmPort->fifoBufs.num ++ || (p_FmPort->fifoBufs.num > MAX_PORT_FIFO_SIZE))) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("fifoBufs.num has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE)); ++ if (p_Params->setSizeOfFifo && (p_FmPort->fifoBufs.num % BMI_FIFO_UNITS)) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("fifoBufs.num has to be divisible by %d", BMI_FIFO_UNITS)); ++ ++#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT ++ if (p_FmPort->fmRevInfo.majorRev == 4) ++ if (p_FmPort->p_FmPortDriverParam->deqPrefetchOption != DEFAULT_notSupported) ++ /* this is an indication that user called config for this mode which is not supported in this integration */ ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("deqPrefetchOption")); ++#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ ++ ++ return E_OK; ++} ++ ++static t_Error VerifySizeOfFifo(t_FmPort *p_FmPort) ++{ ++ uint32_t minFifoSizeRequired = 0, optFifoSizeForB2B = 0; ++ ++ /*************************/ ++ /* TX PORTS */ ++ /*************************/ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_TX) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)) ++ { ++ minFifoSizeRequired = ++ (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS) ++ + (3 * BMI_FIFO_UNITS)); ++ if (!p_FmPort->imEn) ++ minFifoSizeRequired += ++ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth ++ * BMI_FIFO_UNITS; ++ ++ optFifoSizeForB2B = minFifoSizeRequired; ++ ++ /* Add some margin for back-to-back capability to improve performance, ++ allows the hardware to pipeline new frame dma while the previous ++ frame not yet transmitted. */ ++ if (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) ++ optFifoSizeForB2B += 3 * BMI_FIFO_UNITS; ++ else ++ optFifoSizeForB2B += 2 * BMI_FIFO_UNITS; ++ } ++ ++ /*************************/ ++ /* RX IM PORTS */ ++ /*************************/ ++ else ++ if (((p_FmPort->portType == e_FM_PORT_TYPE_RX) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) ++ && p_FmPort->imEn) ++ { ++ optFifoSizeForB2B = ++ minFifoSizeRequired = ++ (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS) ++ + (4 * BMI_FIFO_UNITS)); ++ } ++ ++ /*************************/ ++ /* RX non-IM PORTS */ ++ /*************************/ ++ else ++ if (((p_FmPort->portType == e_FM_PORT_TYPE_RX) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) ++ && !p_FmPort->imEn) ++ { ++ if (p_FmPort->fmRevInfo.majorRev == 4) ++ { ++ if (p_FmPort->rxPoolsParams.numOfPools == 1) ++ minFifoSizeRequired = 8 * BMI_FIFO_UNITS; ++ else ++ minFifoSizeRequired = ++ (uint32_t)(ROUND_UP(p_FmPort->rxPoolsParams.secondLargestBufSize, BMI_FIFO_UNITS) ++ + (7 * BMI_FIFO_UNITS)); ++ } ++ else ++ { ++#if (DPAA_VERSION >= 11) ++ minFifoSizeRequired = ++ (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS) ++ + (5 * BMI_FIFO_UNITS)); ++ /* 4 according to spec + 1 for FOF>0 */ ++#else ++ minFifoSizeRequired = (uint32_t) ++ (ROUND_UP(MIN(p_FmPort->maxFrameLength, p_FmPort->rxPoolsParams.largestBufSize), BMI_FIFO_UNITS) ++ + (7*BMI_FIFO_UNITS)); ++#endif /* (DPAA_VERSION >= 11) */ ++ } ++ ++ optFifoSizeForB2B = minFifoSizeRequired; ++ ++ /* Add some margin for back-to-back capability to improve performance, ++ allows the hardware to pipeline new frame dma while the previous ++ frame not yet transmitted. */ ++ if (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) ++ optFifoSizeForB2B += 8 * BMI_FIFO_UNITS; ++ else ++ optFifoSizeForB2B += 3 * BMI_FIFO_UNITS; ++ } ++ ++ /* For O/H ports, check fifo size and update if necessary */ ++ else ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) ++ { ++#if (DPAA_VERSION >= 11) ++ optFifoSizeForB2B = ++ minFifoSizeRequired = ++ (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS) ++ + ((p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth ++ + 5) * BMI_FIFO_UNITS)); ++ /* 4 according to spec + 1 for FOF>0 */ ++#else ++ optFifoSizeForB2B = minFifoSizeRequired = (uint32_t)((p_FmPort->tasks.num + 2) * BMI_FIFO_UNITS); ++#endif /* (DPAA_VERSION >= 11) */ ++ } ++ ++ ASSERT_COND(minFifoSizeRequired > 0); ++ ASSERT_COND(optFifoSizeForB2B >= minFifoSizeRequired); ++ ++ /* Verify the size */ ++ if (p_FmPort->fifoBufs.num < minFifoSizeRequired) ++ DBG(INFO, ++ ("FIFO size is %d and should be enlarged to %d bytes",p_FmPort->fifoBufs.num, minFifoSizeRequired)); ++ else if (p_FmPort->fifoBufs.num < optFifoSizeForB2B) ++ DBG(INFO, ++ ("For back-to-back frames processing, FIFO size is %d and needs to enlarge to %d bytes", p_FmPort->fifoBufs.num, optFifoSizeForB2B)); ++ ++ return E_OK; ++} ++ ++static void FmPortDriverParamFree(t_FmPort *p_FmPort) ++{ ++ if (p_FmPort->p_FmPortDriverParam) ++ { ++ XX_Free(p_FmPort->p_FmPortDriverParam); ++ p_FmPort->p_FmPortDriverParam = NULL; ++ } ++} ++ ++static t_Error SetExtBufferPools(t_FmPort *p_FmPort) ++{ ++ t_FmExtPools *p_ExtBufPools = &p_FmPort->p_FmPortDriverParam->extBufPools; ++ t_FmBufPoolDepletion *p_BufPoolDepletion = ++ &p_FmPort->p_FmPortDriverParam->bufPoolDepletion; ++ uint8_t orderedArray[FM_PORT_MAX_NUM_OF_EXT_POOLS]; ++ uint16_t sizesArray[BM_MAX_NUM_OF_POOLS]; ++ int i = 0, j = 0, err; ++ struct fman_port_bpools bpools; ++ ++ memset(&orderedArray, 0, sizeof(uint8_t) * FM_PORT_MAX_NUM_OF_EXT_POOLS); ++ memset(&sizesArray, 0, sizeof(uint16_t) * BM_MAX_NUM_OF_POOLS); ++ memcpy(&p_FmPort->extBufPools, p_ExtBufPools, sizeof(t_FmExtPools)); ++ ++ FmSpSetBufPoolsInAscOrderOfBufSizes(p_ExtBufPools, orderedArray, ++ sizesArray); ++ ++ /* Prepare flibs bpools structure */ ++ memset(&bpools, 0, sizeof(struct fman_port_bpools)); ++ bpools.count = p_ExtBufPools->numOfPoolsUsed; ++ bpools.counters_enable = TRUE; ++ for (i = 0; i < p_ExtBufPools->numOfPoolsUsed; i++) ++ { ++ bpools.bpool[i].bpid = orderedArray[i]; ++ bpools.bpool[i].size = sizesArray[orderedArray[i]]; ++ /* functionality available only for some derivatives (limited by config) */ ++ if (p_FmPort->p_FmPortDriverParam->p_BackupBmPools) ++ for (j = 0; ++ j ++ < p_FmPort->p_FmPortDriverParam->p_BackupBmPools->numOfBackupPools; ++ j++) ++ if (orderedArray[i] ++ == p_FmPort->p_FmPortDriverParam->p_BackupBmPools->poolIds[j]) ++ { ++ bpools.bpool[i].is_backup = TRUE; ++ break; ++ } ++ } ++ ++ /* save pools parameters for later use */ ++ p_FmPort->rxPoolsParams.numOfPools = p_ExtBufPools->numOfPoolsUsed; ++ p_FmPort->rxPoolsParams.largestBufSize = ++ sizesArray[orderedArray[p_ExtBufPools->numOfPoolsUsed - 1]]; ++ p_FmPort->rxPoolsParams.secondLargestBufSize = ++ sizesArray[orderedArray[p_ExtBufPools->numOfPoolsUsed - 2]]; ++ ++ /* FMBM_RMPD reg. - pool depletion */ ++ if (p_BufPoolDepletion->poolsGrpModeEnable) ++ { ++ bpools.grp_bp_depleted_num = p_BufPoolDepletion->numOfPools; ++ for (i = 0; i < BM_MAX_NUM_OF_POOLS; i++) ++ { ++ if (p_BufPoolDepletion->poolsToConsider[i]) ++ { ++ for (j = 0; j < p_ExtBufPools->numOfPoolsUsed; j++) ++ { ++ if (i == orderedArray[j]) ++ { ++ bpools.bpool[j].grp_bp_depleted = TRUE; ++ break; ++ } ++ } ++ } ++ } ++ } ++ ++ if (p_BufPoolDepletion->singlePoolModeEnable) ++ { ++ for (i = 0; i < BM_MAX_NUM_OF_POOLS; i++) ++ { ++ if (p_BufPoolDepletion->poolsToConsiderForSingleMode[i]) ++ { ++ for (j = 0; j < p_ExtBufPools->numOfPoolsUsed; j++) ++ { ++ if (i == orderedArray[j]) ++ { ++ bpools.bpool[j].single_bp_depleted = TRUE; ++ break; ++ } ++ } ++ } ++ } ++ } ++ ++#if (DPAA_VERSION >= 11) ++ /* fill QbbPEV */ ++ if (p_BufPoolDepletion->poolsGrpModeEnable ++ || p_BufPoolDepletion->singlePoolModeEnable) ++ { ++ for (i = 0; i < FM_MAX_NUM_OF_PFC_PRIORITIES; i++) ++ { ++ if (p_BufPoolDepletion->pfcPrioritiesEn[i] == TRUE) ++ { ++ bpools.bpool[i].pfc_priorities_en = TRUE; ++ } ++ } ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ /* Issue flibs function */ ++ err = fman_port_set_bpools(&p_FmPort->port, &bpools); ++ if (err != 0) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_bpools")); ++ ++ if (p_FmPort->p_FmPortDriverParam->p_BackupBmPools) ++ XX_Free(p_FmPort->p_FmPortDriverParam->p_BackupBmPools); ++ ++ return E_OK; ++} ++ ++static t_Error ClearPerfCnts(t_FmPort *p_FmPort) ++{ ++ if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_QUEUE_UTIL, 0); ++ FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL, 0); ++ FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL, 0); ++ FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL, 0); ++ return E_OK; ++} ++ ++static t_Error InitLowLevelDriver(t_FmPort *p_FmPort) ++{ ++ t_FmPortDriverParam *p_DriverParams = p_FmPort->p_FmPortDriverParam; ++ struct fman_port_params portParams; ++ uint32_t tmpVal; ++ t_Error err; ++ ++ /* Set up flibs parameters and issue init function */ ++ ++ memset(&portParams, 0, sizeof(struct fman_port_params)); ++ portParams.discard_mask = p_DriverParams->errorsToDiscard; ++ portParams.dflt_fqid = p_DriverParams->dfltFqid; ++ portParams.err_fqid = p_DriverParams->errFqid; ++ portParams.deq_sp = p_DriverParams->deqSubPortal; ++ portParams.dont_release_buf = p_DriverParams->dontReleaseBuf; ++ switch (p_FmPort->portType) ++ { ++ case (e_FM_PORT_TYPE_RX_10G): ++ case (e_FM_PORT_TYPE_RX): ++ portParams.err_mask = (RX_ERRS_TO_ENQ & ~portParams.discard_mask); ++ if (!p_FmPort->imEn) ++ { ++ if (p_DriverParams->forwardReuseIntContext) ++ p_DriverParams->dfltCfg.rx_fd_bits = ++ (uint8_t)(BMI_PORT_RFNE_FRWD_RPD >> 24); ++ } ++ break; ++ ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ portParams.err_mask = (OP_ERRS_TO_ENQ & ~portParams.discard_mask); ++ break; ++ break; ++ ++ default: ++ break; ++ } ++ ++ tmpVal = ++ (uint32_t)( ++ (p_FmPort->internalBufferOffset % OFFSET_UNITS) ? (p_FmPort->internalBufferOffset ++ / OFFSET_UNITS + 1) : ++ (p_FmPort->internalBufferOffset / OFFSET_UNITS)); ++ p_FmPort->internalBufferOffset = (uint8_t)(tmpVal * OFFSET_UNITS); ++ p_DriverParams->dfltCfg.int_buf_start_margin = ++ p_FmPort->internalBufferOffset; ++ ++ p_DriverParams->dfltCfg.ext_buf_start_margin = ++ p_DriverParams->bufMargins.startMargins; ++ p_DriverParams->dfltCfg.ext_buf_end_margin = ++ p_DriverParams->bufMargins.endMargins; ++ ++ p_DriverParams->dfltCfg.ic_ext_offset = ++ p_DriverParams->intContext.extBufOffset; ++ p_DriverParams->dfltCfg.ic_int_offset = ++ p_DriverParams->intContext.intContextOffset; ++ p_DriverParams->dfltCfg.ic_size = p_DriverParams->intContext.size; ++ ++ p_DriverParams->dfltCfg.stats_counters_enable = TRUE; ++ p_DriverParams->dfltCfg.perf_counters_enable = TRUE; ++ p_DriverParams->dfltCfg.queue_counters_enable = TRUE; ++ ++ p_DriverParams->dfltCfg.perf_cnt_params.task_val = ++ (uint8_t)p_FmPort->tasks.num; ++ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING || ++ p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)p_DriverParams->dfltCfg.perf_cnt_params.queue_val = 0; ++ else ++ p_DriverParams->dfltCfg.perf_cnt_params.queue_val = 1; ++ p_DriverParams->dfltCfg.perf_cnt_params.dma_val = ++ (uint8_t)p_FmPort->openDmas.num; ++ p_DriverParams->dfltCfg.perf_cnt_params.fifo_val = p_FmPort->fifoBufs.num; ++ ++ if (0 ++ != fman_port_init(&p_FmPort->port, &p_DriverParams->dfltCfg, ++ &portParams)) ++ RETURN_ERROR(MAJOR, E_NO_DEVICE, ("fman_port_init")); ++ ++ if (p_FmPort->imEn && ((err = FmPortImInit(p_FmPort)) != E_OK)) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ else ++ { ++ // from QMIInit ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) ++ { ++ if (p_DriverParams->deqPrefetchOption == e_FM_PORT_DEQ_NO_PREFETCH) ++ FmSetPortPreFetchConfiguration(p_FmPort->h_Fm, p_FmPort->portId, ++ FALSE); ++ else ++ FmSetPortPreFetchConfiguration(p_FmPort->h_Fm, p_FmPort->portId, ++ TRUE); ++ } ++ } ++ /* The code bellow is a trick so the FM will not release the buffer ++ to BM nor will try to enqueue the frame to QM */ ++ if (((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_TX)) && (!p_FmPort->imEn)) ++ { ++ if (!p_DriverParams->dfltFqid && p_DriverParams->dontReleaseBuf) ++ { ++ /* override fmbm_tcfqid 0 with a false non-0 value. This will force FM to ++ * act according to tfene. Otherwise, if fmbm_tcfqid is 0 the FM will release ++ * buffers to BM regardless of fmbm_tfene ++ */ ++ WRITE_UINT32(p_FmPort->port.bmi_regs->tx.fmbm_tcfqid, 0xFFFFFF); ++ WRITE_UINT32(p_FmPort->port.bmi_regs->tx.fmbm_tfene, ++ NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE); ++ } ++ } ++ ++ return E_OK; ++} ++ ++static bool CheckRxBmiCounter(t_FmPort *p_FmPort, e_FmPortCounters counter) ++{ ++ UNUSED(p_FmPort); ++ ++ switch (counter) ++ { ++ case (e_FM_PORT_COUNTERS_CYCLE): ++ case (e_FM_PORT_COUNTERS_TASK_UTIL): ++ case (e_FM_PORT_COUNTERS_QUEUE_UTIL): ++ case (e_FM_PORT_COUNTERS_DMA_UTIL): ++ case (e_FM_PORT_COUNTERS_FIFO_UTIL): ++ case (e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION): ++ case (e_FM_PORT_COUNTERS_FRAME): ++ case (e_FM_PORT_COUNTERS_DISCARD_FRAME): ++ case (e_FM_PORT_COUNTERS_RX_BAD_FRAME): ++ case (e_FM_PORT_COUNTERS_RX_LARGE_FRAME): ++ case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME): ++ case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR): ++ case (e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD): ++ case (e_FM_PORT_COUNTERS_DEALLOC_BUF): ++ case (e_FM_PORT_COUNTERS_PREPARE_TO_ENQUEUE_COUNTER): ++ return TRUE; ++ default: ++ return FALSE; ++ } ++} ++ ++static bool CheckTxBmiCounter(t_FmPort *p_FmPort, e_FmPortCounters counter) ++{ ++ UNUSED(p_FmPort); ++ ++ switch (counter) ++ { ++ case (e_FM_PORT_COUNTERS_CYCLE): ++ case (e_FM_PORT_COUNTERS_TASK_UTIL): ++ case (e_FM_PORT_COUNTERS_QUEUE_UTIL): ++ case (e_FM_PORT_COUNTERS_DMA_UTIL): ++ case (e_FM_PORT_COUNTERS_FIFO_UTIL): ++ case (e_FM_PORT_COUNTERS_FRAME): ++ case (e_FM_PORT_COUNTERS_DISCARD_FRAME): ++ case (e_FM_PORT_COUNTERS_LENGTH_ERR): ++ case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT): ++ case (e_FM_PORT_COUNTERS_DEALLOC_BUF): ++ return TRUE; ++ default: ++ return FALSE; ++ } ++} ++ ++static bool CheckOhBmiCounter(t_FmPort *p_FmPort, e_FmPortCounters counter) ++{ ++ switch (counter) ++ { ++ case (e_FM_PORT_COUNTERS_CYCLE): ++ case (e_FM_PORT_COUNTERS_TASK_UTIL): ++ case (e_FM_PORT_COUNTERS_DMA_UTIL): ++ case (e_FM_PORT_COUNTERS_FIFO_UTIL): ++ case (e_FM_PORT_COUNTERS_FRAME): ++ case (e_FM_PORT_COUNTERS_DISCARD_FRAME): ++ case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR): ++ case (e_FM_PORT_COUNTERS_WRED_DISCARD): ++ case (e_FM_PORT_COUNTERS_LENGTH_ERR): ++ case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT): ++ case (e_FM_PORT_COUNTERS_DEALLOC_BUF): ++ return TRUE; ++ case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME): ++ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) ++ return FALSE; ++ else ++ return TRUE; ++ default: ++ return FALSE; ++ } ++} ++ ++static t_Error BmiPortCheckAndGetCounterType( ++ t_FmPort *p_FmPort, e_FmPortCounters counter, ++ enum fman_port_stats_counters *p_StatsType, ++ enum fman_port_perf_counters *p_PerfType, bool *p_IsStats) ++{ ++ volatile uint32_t *p_Reg; ++ bool isValid; ++ ++ switch (p_FmPort->portType) ++ { ++ case (e_FM_PORT_TYPE_RX_10G): ++ case (e_FM_PORT_TYPE_RX): ++ p_Reg = &p_FmPort->port.bmi_regs->rx.fmbm_rstc; ++ isValid = CheckRxBmiCounter(p_FmPort, counter); ++ break; ++ case (e_FM_PORT_TYPE_TX_10G): ++ case (e_FM_PORT_TYPE_TX): ++ p_Reg = &p_FmPort->port.bmi_regs->tx.fmbm_tstc; ++ isValid = CheckTxBmiCounter(p_FmPort, counter); ++ break; ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ case (e_FM_PORT_TYPE_OH_HOST_COMMAND): ++ p_Reg = &p_FmPort->port.bmi_regs->oh.fmbm_ostc; ++ isValid = CheckOhBmiCounter(p_FmPort, counter); ++ break; ++ default: ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported port type")); ++ } ++ ++ if (!isValid) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ++ ("Requested counter is not available for this port type")); ++ ++ /* check that counters are enabled */ ++ switch (counter) ++ { ++ case (e_FM_PORT_COUNTERS_CYCLE): ++ case (e_FM_PORT_COUNTERS_TASK_UTIL): ++ case (e_FM_PORT_COUNTERS_QUEUE_UTIL): ++ case (e_FM_PORT_COUNTERS_DMA_UTIL): ++ case (e_FM_PORT_COUNTERS_FIFO_UTIL): ++ case (e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION): ++ /* performance counters - may be read when disabled */ ++ *p_IsStats = FALSE; ++ break; ++ case (e_FM_PORT_COUNTERS_FRAME): ++ case (e_FM_PORT_COUNTERS_DISCARD_FRAME): ++ case (e_FM_PORT_COUNTERS_DEALLOC_BUF): ++ case (e_FM_PORT_COUNTERS_RX_BAD_FRAME): ++ case (e_FM_PORT_COUNTERS_RX_LARGE_FRAME): ++ case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME): ++ case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR): ++ case (e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD): ++ case (e_FM_PORT_COUNTERS_LENGTH_ERR): ++ case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT): ++ case (e_FM_PORT_COUNTERS_WRED_DISCARD): ++ *p_IsStats = TRUE; ++ if (!(GET_UINT32(*p_Reg) & BMI_COUNTERS_EN)) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ++ ("Requested counter was not enabled")); ++ break; ++ default: ++ break; ++ } ++ ++ /* Set counter */ ++ switch (counter) ++ { ++ case (e_FM_PORT_COUNTERS_CYCLE): ++ *p_PerfType = E_FMAN_PORT_PERF_CNT_CYCLE; ++ break; ++ case (e_FM_PORT_COUNTERS_TASK_UTIL): ++ *p_PerfType = E_FMAN_PORT_PERF_CNT_TASK_UTIL; ++ break; ++ case (e_FM_PORT_COUNTERS_QUEUE_UTIL): ++ *p_PerfType = E_FMAN_PORT_PERF_CNT_QUEUE_UTIL; ++ break; ++ case (e_FM_PORT_COUNTERS_DMA_UTIL): ++ *p_PerfType = E_FMAN_PORT_PERF_CNT_DMA_UTIL; ++ break; ++ case (e_FM_PORT_COUNTERS_FIFO_UTIL): ++ *p_PerfType = E_FMAN_PORT_PERF_CNT_FIFO_UTIL; ++ break; ++ case (e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION): ++ *p_PerfType = E_FMAN_PORT_PERF_CNT_RX_PAUSE; ++ break; ++ case (e_FM_PORT_COUNTERS_FRAME): ++ *p_StatsType = E_FMAN_PORT_STATS_CNT_FRAME; ++ break; ++ case (e_FM_PORT_COUNTERS_DISCARD_FRAME): ++ *p_StatsType = E_FMAN_PORT_STATS_CNT_DISCARD; ++ break; ++ case (e_FM_PORT_COUNTERS_DEALLOC_BUF): ++ *p_StatsType = E_FMAN_PORT_STATS_CNT_DEALLOC_BUF; ++ break; ++ case (e_FM_PORT_COUNTERS_RX_BAD_FRAME): ++ *p_StatsType = E_FMAN_PORT_STATS_CNT_RX_BAD_FRAME; ++ break; ++ case (e_FM_PORT_COUNTERS_RX_LARGE_FRAME): ++ *p_StatsType = E_FMAN_PORT_STATS_CNT_RX_LARGE_FRAME; ++ break; ++ case (e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD): ++ *p_StatsType = E_FMAN_PORT_STATS_CNT_RX_OUT_OF_BUF; ++ break; ++ case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME): ++ *p_StatsType = E_FMAN_PORT_STATS_CNT_FILTERED_FRAME; ++ break; ++ case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR): ++ *p_StatsType = E_FMAN_PORT_STATS_CNT_DMA_ERR; ++ break; ++ case (e_FM_PORT_COUNTERS_WRED_DISCARD): ++ *p_StatsType = E_FMAN_PORT_STATS_CNT_WRED_DISCARD; ++ break; ++ case (e_FM_PORT_COUNTERS_LENGTH_ERR): ++ *p_StatsType = E_FMAN_PORT_STATS_CNT_LEN_ERR; ++ break; ++ case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT): ++ *p_StatsType = E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT; ++ break; ++ default: ++ break; ++ } ++ ++ return E_OK; ++} ++ ++static t_Error AdditionalPrsParams(t_FmPort *p_FmPort, ++ t_FmPcdPrsAdditionalHdrParams *p_HdrParams, ++ uint32_t *p_SoftSeqAttachReg) ++{ ++ uint8_t hdrNum, Ipv4HdrNum; ++ u_FmPcdHdrPrsOpts *p_prsOpts; ++ uint32_t tmpReg = *p_SoftSeqAttachReg, tmpPrsOffset; ++ ++ if (IS_PRIVATE_HEADER(p_HdrParams->hdr) ++ || IS_SPECIAL_HEADER(p_HdrParams->hdr)) ++ RETURN_ERROR( ++ MAJOR, E_NOT_SUPPORTED, ++ ("No additional parameters for private or special headers.")); ++ ++ if (p_HdrParams->errDisable) ++ tmpReg |= PRS_HDR_ERROR_DIS; ++ ++ /* Set parser options */ ++ if (p_HdrParams->usePrsOpts) ++ { ++ p_prsOpts = &p_HdrParams->prsOpts; ++ switch (p_HdrParams->hdr) ++ { ++ case (HEADER_TYPE_MPLS): ++ if (p_prsOpts->mplsPrsOptions.labelInterpretationEnable) ++ tmpReg |= PRS_HDR_MPLS_LBL_INTER_EN; ++ hdrNum = GetPrsHdrNum(p_prsOpts->mplsPrsOptions.nextParse); ++ if (hdrNum == ILLEGAL_HDR_NUM) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); ++ Ipv4HdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); ++ if (hdrNum < Ipv4HdrNum) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("Header must be equal or higher than IPv4")); ++ tmpReg |= ((uint32_t)hdrNum * PRS_HDR_ENTRY_SIZE) ++ << PRS_HDR_MPLS_NEXT_HDR_SHIFT; ++ break; ++ case (HEADER_TYPE_PPPoE): ++ if (p_prsOpts->pppoePrsOptions.enableMTUCheck) ++ tmpReg |= PRS_HDR_PPPOE_MTU_CHECK_EN; ++ break; ++ case (HEADER_TYPE_IPv6): ++ if (p_prsOpts->ipv6PrsOptions.routingHdrEnable) ++ tmpReg |= PRS_HDR_IPV6_ROUTE_HDR_EN; ++ break; ++ case (HEADER_TYPE_TCP): ++ if (p_prsOpts->tcpPrsOptions.padIgnoreChecksum) ++ tmpReg |= PRS_HDR_TCP_PAD_REMOVAL; ++ else ++ tmpReg &= ~PRS_HDR_TCP_PAD_REMOVAL; ++ break; ++ case (HEADER_TYPE_UDP): ++ if (p_prsOpts->udpPrsOptions.padIgnoreChecksum) ++ tmpReg |= PRS_HDR_UDP_PAD_REMOVAL; ++ else ++ tmpReg &= ~PRS_HDR_UDP_PAD_REMOVAL; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid header")); ++ } ++ } ++ ++ /* set software parsing (address is divided in 2 since parser uses 2 byte access. */ ++ if (p_HdrParams->swPrsEnable) ++ { ++ tmpPrsOffset = FmPcdGetSwPrsOffset(p_FmPort->h_FmPcd, p_HdrParams->hdr, ++ p_HdrParams->indexPerHdr); ++ if (tmpPrsOffset == ILLEGAL_BASE) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); ++ tmpReg |= (PRS_HDR_SW_PRS_EN | tmpPrsOffset); ++ } ++ *p_SoftSeqAttachReg = tmpReg; ++ ++ return E_OK; ++} ++ ++static uint32_t GetPortSchemeBindParams( ++ t_Handle h_FmPort, t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ uint32_t walking1Mask = 0x80000000, tmp; ++ uint8_t idx = 0; ++ ++ p_SchemeBind->netEnvId = p_FmPort->netEnvId; ++ p_SchemeBind->hardwarePortId = p_FmPort->hardwarePortId; ++ p_SchemeBind->useClsPlan = p_FmPort->useClsPlan; ++ p_SchemeBind->numOfSchemes = 0; ++ tmp = p_FmPort->schemesPerPortVector; ++ if (tmp) ++ { ++ while (tmp) ++ { ++ if (tmp & walking1Mask) ++ { ++ p_SchemeBind->schemesIds[p_SchemeBind->numOfSchemes] = idx; ++ p_SchemeBind->numOfSchemes++; ++ tmp &= ~walking1Mask; ++ } ++ walking1Mask >>= 1; ++ idx++; ++ } ++ } ++ ++ return tmp; ++} ++ ++static void FmPortCheckNApplyMacsec(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ volatile uint32_t *p_BmiCfgReg = NULL; ++ uint32_t macsecEn = BMI_PORT_CFG_EN_MACSEC; ++ uint32_t lcv, walking1Mask = 0x80000000; ++ uint8_t cnt = 0; ++ ++ ASSERT_COND(p_FmPort); ++ ASSERT_COND(p_FmPort->h_FmPcd); ++ ASSERT_COND(!p_FmPort->p_FmPortDriverParam); ++ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) ++ return; ++ ++ p_BmiCfgReg = &p_FmPort->port.bmi_regs->rx.fmbm_rcfg; ++ /* get LCV for MACSEC */ ++ if ((lcv = FmPcdGetMacsecLcv(p_FmPort->h_FmPcd, p_FmPort->netEnvId)) ++ != 0) ++ { ++ while (!(lcv & walking1Mask)) ++ { ++ cnt++; ++ walking1Mask >>= 1; ++ } ++ ++ macsecEn |= (uint32_t)cnt << BMI_PORT_CFG_MS_SEL_SHIFT; ++ WRITE_UINT32(*p_BmiCfgReg, GET_UINT32(*p_BmiCfgReg) | macsecEn); ++ } ++} ++ ++static t_Error SetPcd(t_FmPort *p_FmPort, t_FmPortPcdParams *p_PcdParams) ++{ ++ t_Error err = E_OK; ++ uint32_t tmpReg; ++ volatile uint32_t *p_BmiNia = NULL; ++ volatile uint32_t *p_BmiPrsNia = NULL; ++ volatile uint32_t *p_BmiPrsStartOffset = NULL; ++ volatile uint32_t *p_BmiInitPrsResult = NULL; ++ volatile uint32_t *p_BmiCcBase = NULL; ++ uint16_t hdrNum, L3HdrNum, greHdrNum; ++ int i; ++ bool isEmptyClsPlanGrp; ++ uint32_t tmpHxs[FM_PCD_PRS_NUM_OF_HDRS]; ++ uint16_t absoluteProfileId; ++ uint8_t physicalSchemeId; ++ uint32_t ccTreePhysOffset; ++ t_FmPcdKgInterModuleBindPortToSchemes schemeBind; ++ uint32_t initialSwPrs = 0; ++ ++ ASSERT_COND(p_FmPort); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ if (p_FmPort->imEn) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for non-independant mode ports only")); ++ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for Rx and offline parsing ports only")); ++ ++ p_FmPort->netEnvId = FmPcdGetNetEnvId(p_PcdParams->h_NetEnv); ++ ++ p_FmPort->pcdEngines = 0; ++ ++ /* initialize p_FmPort->pcdEngines field in port's structure */ ++ switch (p_PcdParams->pcdSupport) ++ { ++ case (e_FM_PORT_PCD_SUPPORT_NONE): ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("No PCD configuration required if e_FM_PORT_PCD_SUPPORT_NONE selected")); ++ case (e_FM_PORT_PCD_SUPPORT_PRS_ONLY): ++ p_FmPort->pcdEngines |= FM_PCD_PRS; ++ break; ++ case (e_FM_PORT_PCD_SUPPORT_PLCR_ONLY): ++ p_FmPort->pcdEngines |= FM_PCD_PLCR; ++ break; ++ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR): ++ p_FmPort->pcdEngines |= FM_PCD_PRS; ++ p_FmPort->pcdEngines |= FM_PCD_PLCR; ++ break; ++ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG): ++ p_FmPort->pcdEngines |= FM_PCD_PRS; ++ p_FmPort->pcdEngines |= FM_PCD_KG; ++ break; ++ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC): ++ p_FmPort->pcdEngines |= FM_PCD_PRS; ++ p_FmPort->pcdEngines |= FM_PCD_CC; ++ p_FmPort->pcdEngines |= FM_PCD_KG; ++ break; ++ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR): ++ p_FmPort->pcdEngines |= FM_PCD_PRS; ++ p_FmPort->pcdEngines |= FM_PCD_KG; ++ p_FmPort->pcdEngines |= FM_PCD_CC; ++ p_FmPort->pcdEngines |= FM_PCD_PLCR; ++ break; ++ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC): ++ p_FmPort->pcdEngines |= FM_PCD_PRS; ++ p_FmPort->pcdEngines |= FM_PCD_CC; ++ break; ++ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC_AND_PLCR): ++ p_FmPort->pcdEngines |= FM_PCD_PRS; ++ p_FmPort->pcdEngines |= FM_PCD_CC; ++ p_FmPort->pcdEngines |= FM_PCD_PLCR; ++ break; ++ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR): ++ p_FmPort->pcdEngines |= FM_PCD_PRS; ++ p_FmPort->pcdEngines |= FM_PCD_KG; ++ p_FmPort->pcdEngines |= FM_PCD_PLCR; ++ break; ++ case (e_FM_PORT_PCD_SUPPORT_CC_ONLY): ++ p_FmPort->pcdEngines |= FM_PCD_CC; ++ break; ++#ifdef FM_CAPWAP_SUPPORT ++ case (e_FM_PORT_PCD_SUPPORT_CC_AND_KG): ++ p_FmPort->pcdEngines |= FM_PCD_CC; ++ p_FmPort->pcdEngines |= FM_PCD_KG; ++ break; ++ case (e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR): ++ p_FmPort->pcdEngines |= FM_PCD_CC; ++ p_FmPort->pcdEngines |= FM_PCD_KG; ++ p_FmPort->pcdEngines |= FM_PCD_PLCR; ++ break; ++#endif /* FM_CAPWAP_SUPPORT */ ++ ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid pcdSupport")); ++ } ++ ++ if ((p_FmPort->pcdEngines & FM_PCD_PRS) ++ && (p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams ++ > FM_PCD_PRS_NUM_OF_HDRS)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("Port parser numOfHdrsWithAdditionalParams may not exceed %d", FM_PCD_PRS_NUM_OF_HDRS)); ++ ++ /* check that parameters exist for each and only each defined engine */ ++ if ((!!(p_FmPort->pcdEngines & FM_PCD_PRS) != !!p_PcdParams->p_PrsParams) ++ || (!!(p_FmPort->pcdEngines & FM_PCD_KG) ++ != !!p_PcdParams->p_KgParams) ++ || (!!(p_FmPort->pcdEngines & FM_PCD_CC) ++ != !!p_PcdParams->p_CcParams)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("PCD initialization structure is not consistent with pcdSupport")); ++ ++ /* get PCD registers pointers */ ++ switch (p_FmPort->portType) ++ { ++ case (e_FM_PORT_TYPE_RX_10G): ++ case (e_FM_PORT_TYPE_RX): ++ p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; ++ p_BmiPrsNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfpne; ++ p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->rx.fmbm_rpso; ++ p_BmiInitPrsResult = &p_FmPort->port.bmi_regs->rx.fmbm_rprai[0]; ++ p_BmiCcBase = &p_FmPort->port.bmi_regs->rx.fmbm_rccb; ++ break; ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; ++ p_BmiPrsNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofpne; ++ p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->oh.fmbm_opso; ++ p_BmiInitPrsResult = &p_FmPort->port.bmi_regs->oh.fmbm_oprai[0]; ++ p_BmiCcBase = &p_FmPort->port.bmi_regs->oh.fmbm_occb; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); ++ } ++ ++ /* set PCD port parameter */ ++ if (p_FmPort->pcdEngines & FM_PCD_CC) ++ { ++ err = FmPcdCcBindTree(p_FmPort->h_FmPcd, p_PcdParams, ++ p_PcdParams->p_CcParams->h_CcTree, ++ &ccTreePhysOffset, p_FmPort); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ WRITE_UINT32(*p_BmiCcBase, ccTreePhysOffset); ++ p_FmPort->ccTreeId = p_PcdParams->p_CcParams->h_CcTree; ++ } ++ ++ if (p_FmPort->pcdEngines & FM_PCD_KG) ++ { ++ if (p_PcdParams->p_KgParams->numOfSchemes == 0) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("For ports using Keygen, at least one scheme must be bound. ")); ++ ++ err = FmPcdKgSetOrBindToClsPlanGrp(p_FmPort->h_FmPcd, ++ p_FmPort->hardwarePortId, ++ p_FmPort->netEnvId, ++ p_FmPort->optArray, ++ &p_FmPort->clsPlanGrpId, ++ &isEmptyClsPlanGrp); ++ if (err) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("FmPcdKgSetOrBindToClsPlanGrp failed. ")); ++ ++ p_FmPort->useClsPlan = !isEmptyClsPlanGrp; ++ ++ schemeBind.netEnvId = p_FmPort->netEnvId; ++ schemeBind.hardwarePortId = p_FmPort->hardwarePortId; ++ schemeBind.numOfSchemes = p_PcdParams->p_KgParams->numOfSchemes; ++ schemeBind.useClsPlan = p_FmPort->useClsPlan; ++ ++ /* for each scheme */ ++ for (i = 0; i < p_PcdParams->p_KgParams->numOfSchemes; i++) ++ { ++ ASSERT_COND(p_PcdParams->p_KgParams->h_Schemes[i]); ++ physicalSchemeId = FmPcdKgGetSchemeId( ++ p_PcdParams->p_KgParams->h_Schemes[i]); ++ schemeBind.schemesIds[i] = physicalSchemeId; ++ /* build vector */ ++ p_FmPort->schemesPerPortVector |= 1 ++ << (31 - (uint32_t)physicalSchemeId); ++#if (DPAA_VERSION >= 11) ++ /*because of the state that VSPE is defined per port - all PCD path should be according to this requirement ++ if !VSPE - in port, for relevant scheme VSPE can not be set*/ ++ if (!p_FmPort->vspe ++ && FmPcdKgGetVspe((p_PcdParams->p_KgParams->h_Schemes[i]))) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("VSPE is not at port level")); ++#endif /* (DPAA_VERSION >= 11) */ ++ } ++ ++ err = FmPcdKgBindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ /***************************/ ++ /* configure NIA after BMI */ ++ /***************************/ ++ /* rfne may contain FDCS bits, so first we read them. */ ++ p_FmPort->savedBmiNia = GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK; ++ ++ /* If policer is used directly after BMI or PRS */ ++ if ((p_FmPort->pcdEngines & FM_PCD_PLCR) ++ && ((p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_PLCR_ONLY) ++ || (p_PcdParams->pcdSupport ++ == e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR))) ++ { ++ if (!p_PcdParams->p_PlcrParams->h_Profile) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("Profile should be initialized")); ++ ++ absoluteProfileId = (uint16_t)FmPcdPlcrProfileGetAbsoluteId( ++ p_PcdParams->p_PlcrParams->h_Profile); ++ ++ if (!FmPcdPlcrIsProfileValid(p_FmPort->h_FmPcd, absoluteProfileId)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("Private port profile not valid.")); ++ ++ tmpReg = (uint32_t)(absoluteProfileId | NIA_PLCR_ABSOLUTE); ++ ++ if (p_FmPort->pcdEngines & FM_PCD_PRS) /* e_FM_PCD_SUPPORT_PRS_AND_PLCR */ ++ /* update BMI HPNIA */ ++ WRITE_UINT32(*p_BmiPrsNia, (uint32_t)(NIA_ENG_PLCR | tmpReg)); ++ else ++ /* e_FM_PCD_SUPPORT_PLCR_ONLY */ ++ /* update BMI NIA */ ++ p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_PLCR); ++ } ++ ++ /* if CC is used directly after BMI */ ++ if ((p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_ONLY) ++#ifdef FM_CAPWAP_SUPPORT ++ || (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_AND_KG) ++ || (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR) ++#endif /* FM_CAPWAP_SUPPORT */ ++ ) ++ { ++ if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_OPERATION, ++ ("e_FM_PORT_PCD_SUPPORT_CC_xx available for offline parsing ports only")); ++ p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC); ++ /* check that prs start offset == RIM[FOF] */ ++ } ++ ++ if (p_FmPort->pcdEngines & FM_PCD_PRS) ++ { ++ ASSERT_COND(p_PcdParams->p_PrsParams); ++#if (DPAA_VERSION >= 11) ++ if (p_PcdParams->p_PrsParams->firstPrsHdr == HEADER_TYPE_CAPWAP) ++ hdrNum = OFFLOAD_SW_PATCH_CAPWAP_LABEL; ++ else ++ { ++#endif /* (DPAA_VERSION >= 11) */ ++ /* if PRS is used it is always first */ ++ hdrNum = GetPrsHdrNum(p_PcdParams->p_PrsParams->firstPrsHdr); ++ if (hdrNum == ILLEGAL_HDR_NUM) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unsupported header.")); ++#if (DPAA_VERSION >= 11) ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_PRS | (uint32_t)(hdrNum)); ++ /* set after parser NIA */ ++ tmpReg = 0; ++ switch (p_PcdParams->pcdSupport) ++ { ++ case (e_FM_PORT_PCD_SUPPORT_PRS_ONLY): ++ WRITE_UINT32(*p_BmiPrsNia, ++ GET_NIA_BMI_AC_ENQ_FRAME(p_FmPort->h_FmPcd)); ++ break; ++ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC): ++ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR): ++ tmpReg = NIA_KG_CC_EN; ++ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG): ++ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR): ++ if (p_PcdParams->p_KgParams->directScheme) ++ { ++ physicalSchemeId = FmPcdKgGetSchemeId( ++ p_PcdParams->p_KgParams->h_DirectScheme); ++ /* check that this scheme was bound to this port */ ++ for (i = 0; i < p_PcdParams->p_KgParams->numOfSchemes; i++) ++ if (p_PcdParams->p_KgParams->h_DirectScheme ++ == p_PcdParams->p_KgParams->h_Schemes[i]) ++ break; ++ if (i == p_PcdParams->p_KgParams->numOfSchemes) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("Direct scheme is not one of the port selected schemes.")); ++ tmpReg |= (uint32_t)(NIA_KG_DIRECT | physicalSchemeId); ++ } ++ WRITE_UINT32(*p_BmiPrsNia, NIA_ENG_KG | tmpReg); ++ break; ++ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC): ++ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC_AND_PLCR): ++ WRITE_UINT32(*p_BmiPrsNia, ++ (uint32_t)(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC)); ++ break; ++ case (e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR): ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid PCD support")); ++ } ++ ++ /* set start parsing offset */ ++ WRITE_UINT32(*p_BmiPrsStartOffset, ++ p_PcdParams->p_PrsParams->parsingOffset); ++ ++ /************************************/ ++ /* Parser port parameters */ ++ /************************************/ ++ /* stop before configuring */ ++ WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, PRS_CAC_STOP); ++ /* wait for parser to be in idle state */ ++ while (GET_UINT32(p_FmPort->p_FmPortPrsRegs->pcac) & PRS_CAC_ACTIVE) ++ ; ++ ++ /* set soft seq attachment register */ ++ memset(tmpHxs, 0, FM_PCD_PRS_NUM_OF_HDRS * sizeof(uint32_t)); ++ ++ /* set protocol options */ ++ for (i = 0; p_FmPort->optArray[i]; i++) ++ switch (p_FmPort->optArray[i]) ++ { ++ case (ETH_BROADCAST): ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_ETH); ++ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_ETH_BC_SHIFT; ++ break; ++ case (ETH_MULTICAST): ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_ETH); ++ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_ETH_MC_SHIFT; ++ break; ++ case (VLAN_STACKED): ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_VLAN); ++ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_VLAN_STACKED_SHIFT; ++ break; ++ case (MPLS_STACKED): ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_MPLS); ++ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_MPLS_STACKED_SHIFT; ++ break; ++ case (IPV4_BROADCAST_1): ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); ++ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_1_BC_SHIFT; ++ break; ++ case (IPV4_MULTICAST_1): ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); ++ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_1_MC_SHIFT; ++ break; ++ case (IPV4_UNICAST_2): ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); ++ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_2_UC_SHIFT; ++ break; ++ case (IPV4_MULTICAST_BROADCAST_2): ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); ++ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_2_MC_BC_SHIFT; ++ break; ++ case (IPV6_MULTICAST_1): ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); ++ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV6_1_MC_SHIFT; ++ break; ++ case (IPV6_UNICAST_2): ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); ++ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV6_2_UC_SHIFT; ++ break; ++ case (IPV6_MULTICAST_2): ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); ++ tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV6_2_MC_SHIFT; ++ break; ++ } ++ ++ if (FmPcdNetEnvIsHdrExist(p_FmPort->h_FmPcd, p_FmPort->netEnvId, ++ HEADER_TYPE_UDP_ENCAP_ESP)) ++ { ++ if (p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams == FM_PCD_PRS_NUM_OF_HDRS) ++ RETURN_ERROR( ++ MINOR, E_INVALID_VALUE, ++ ("If HEADER_TYPE_UDP_ENCAP_ESP is used, numOfHdrsWithAdditionalParams may be up to FM_PCD_PRS_NUM_OF_HDRS - 1")); ++ ++ p_PcdParams->p_PrsParams->additionalParams[p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams].hdr = ++ HEADER_TYPE_UDP; ++ p_PcdParams->p_PrsParams->additionalParams[p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams].swPrsEnable = ++ TRUE; ++ p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams++; ++ } ++ ++ /* set MPLS default next header - HW reset workaround */ ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_MPLS); ++ tmpHxs[hdrNum] |= PRS_HDR_MPLS_LBL_INTER_EN; ++ L3HdrNum = GetPrsHdrNum(HEADER_TYPE_USER_DEFINED_L3); ++ tmpHxs[hdrNum] |= (uint32_t)L3HdrNum << PRS_HDR_MPLS_NEXT_HDR_SHIFT; ++ ++ /* for GRE, disable errors */ ++ greHdrNum = GetPrsHdrNum(HEADER_TYPE_GRE); ++ tmpHxs[greHdrNum] |= PRS_HDR_ERROR_DIS; ++ ++ /* For UDP remove PAD from L4 checksum calculation */ ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_UDP); ++ tmpHxs[hdrNum] |= PRS_HDR_UDP_PAD_REMOVAL; ++ /* For TCP remove PAD from L4 checksum calculation */ ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_TCP); ++ tmpHxs[hdrNum] |= PRS_HDR_TCP_PAD_REMOVAL; ++ ++ /* config additional params for specific headers */ ++ for (i = 0; i < p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams; ++ i++) ++ { ++ /* case for using sw parser as the initial NIA address, before ++ * HW parsing ++ */ ++ if ((p_PcdParams->p_PrsParams->additionalParams[i].hdr == HEADER_TYPE_NONE) && ++ p_PcdParams->p_PrsParams->additionalParams[i].swPrsEnable) ++ { ++ initialSwPrs = FmPcdGetSwPrsOffset(p_FmPort->h_FmPcd, HEADER_TYPE_NONE, ++ p_PcdParams->p_PrsParams->additionalParams[i].indexPerHdr); ++ if (initialSwPrs == ILLEGAL_BASE) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); ++ ++ /* clear parser first HXS */ ++ p_FmPort->savedBmiNia &= ~BMI_RFNE_HXS_MASK; /* 0x000000FF */ ++ /* rewrite with soft parser start */ ++ p_FmPort->savedBmiNia |= initialSwPrs; ++ continue; ++ } ++ ++ hdrNum = ++ GetPrsHdrNum(p_PcdParams->p_PrsParams->additionalParams[i].hdr); ++ if (hdrNum == ILLEGAL_HDR_NUM) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); ++ if (hdrNum == NO_HDR_NUM) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("Private headers may not use additional parameters")); ++ ++ err = AdditionalPrsParams( ++ p_FmPort, &p_PcdParams->p_PrsParams->additionalParams[i], ++ &tmpHxs[hdrNum]); ++ if (err) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); ++ } ++ ++ /* Check if ip-reassembly port - need to link sw-parser code */ ++ if (p_FmPort->h_IpReassemblyManip) ++ { ++ /* link to sw parser code for IP Frag - only if no other code is applied. */ ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); ++ if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) ++ tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv4_IPR_LABEL); ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); ++ if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) ++ tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPR_LABEL); ++ } else { ++ if (FmPcdNetEnvIsHdrExist(p_FmPort->h_FmPcd, p_FmPort->netEnvId, HEADER_TYPE_UDP_LITE)) ++ { ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); ++ if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) ++ tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPF_LABEL); ++ } else if ((FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd) ++ && (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING))) ++ { ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); ++ if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) ++ tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPF_LABEL); ++ } ++ } ++ ++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) ++ if (FmPcdNetEnvIsHdrExist(p_FmPort->h_FmPcd, p_FmPort->netEnvId, ++ HEADER_TYPE_UDP_LITE)) ++ { ++ /* link to sw parser code for udp lite - only if no other code is applied. */ ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); ++ if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) ++ tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | UDP_LITE_SW_PATCH_LABEL); ++ } ++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ ++ for (i = 0; i < FM_PCD_PRS_NUM_OF_HDRS; i++) ++ { ++ /* For all header set LCV as taken from netEnv*/ ++ WRITE_UINT32( ++ p_FmPort->p_FmPortPrsRegs->hdrs[i].lcv, ++ FmPcdGetLcv(p_FmPort->h_FmPcd, p_FmPort->netEnvId, (uint8_t)i)); ++ /* set HXS register according to default+Additional params+protocol options */ ++ WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->hdrs[i].softSeqAttach, ++ tmpHxs[i]); ++ } ++ ++ /* set tpid. */ ++ tmpReg = PRS_TPID_DFLT; ++ if (p_PcdParams->p_PrsParams->setVlanTpid1) ++ { ++ tmpReg &= PRS_TPID2_MASK; ++ tmpReg |= (uint32_t)p_PcdParams->p_PrsParams->vlanTpid1 ++ << PRS_PCTPID_SHIFT; ++ } ++ if (p_PcdParams->p_PrsParams->setVlanTpid2) ++ { ++ tmpReg &= PRS_TPID1_MASK; ++ tmpReg |= (uint32_t)p_PcdParams->p_PrsParams->vlanTpid2; ++ }WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pctpid, tmpReg); ++ ++ /* enable parser */ ++ WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, 0); ++ ++ if (p_PcdParams->p_PrsParams->prsResultPrivateInfo) ++ p_FmPort->privateInfo = ++ p_PcdParams->p_PrsParams->prsResultPrivateInfo; ++ ++ } /* end parser */ ++ else { ++ if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd) ++ && (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ++ { ++ hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); ++ WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->hdrs[hdrNum].softSeqAttach, ++ (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPF_LABEL)); ++ } ++ ++ WRITE_UINT32(*p_BmiPrsStartOffset, 0); ++ ++ p_FmPort->privateInfo = 0; ++ } ++ ++ FmPortCheckNApplyMacsec(p_FmPort); ++ ++ WRITE_UINT32( ++ *p_BmiPrsStartOffset, ++ GET_UINT32(*p_BmiPrsStartOffset) + p_FmPort->internalBufferOffset); ++ ++ /* set initial parser result - used for all engines */ ++ for (i = 0; i < FM_PORT_PRS_RESULT_NUM_OF_WORDS; i++) ++ { ++ if (!i) ++ WRITE_UINT32( ++ *(p_BmiInitPrsResult), ++ (uint32_t)(((uint32_t)p_FmPort->privateInfo << BMI_PR_PORTID_SHIFT) | BMI_PRS_RESULT_HIGH)); ++ else ++ { ++ if (i < FM_PORT_PRS_RESULT_NUM_OF_WORDS / 2) ++ WRITE_UINT32(*(p_BmiInitPrsResult+i), BMI_PRS_RESULT_HIGH); ++ else ++ WRITE_UINT32(*(p_BmiInitPrsResult+i), BMI_PRS_RESULT_LOW); ++ } ++ } ++ ++ return E_OK; ++} ++ ++static t_Error DeletePcd(t_FmPort *p_FmPort) ++{ ++ t_Error err = E_OK; ++ volatile uint32_t *p_BmiNia = NULL; ++ volatile uint32_t *p_BmiPrsStartOffset = NULL; ++ ++ ASSERT_COND(p_FmPort); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ if (p_FmPort->imEn) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for non-independant mode ports only")); ++ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ++ RETURN_ERROR( MAJOR, E_INVALID_OPERATION, ++ ("available for Rx and offline parsing ports only")); ++ ++ if (!p_FmPort->pcdEngines) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("called for non PCD port")); ++ ++ /* get PCD registers pointers */ ++ switch (p_FmPort->portType) ++ { ++ case (e_FM_PORT_TYPE_RX_10G): ++ case (e_FM_PORT_TYPE_RX): ++ p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; ++ p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->rx.fmbm_rpso; ++ break; ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; ++ p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->oh.fmbm_opso; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); ++ } ++ ++ if ((GET_UINT32(*p_BmiNia) & GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME()) ++ != GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME()) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("port has to be detached previousely")); ++ ++ WRITE_UINT32(*p_BmiPrsStartOffset, 0); ++ ++ /* "cut" PCD out of the port's flow - go to BMI */ ++ /* WRITE_UINT32(*p_BmiNia, (p_FmPort->savedBmiNia & BMI_RFNE_FDCS_MASK) | (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)); */ ++ ++ if (p_FmPort->pcdEngines & FM_PCD_PRS) ++ { ++ /* stop parser */ ++ WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, PRS_CAC_STOP); ++ /* wait for parser to be in idle state */ ++ while (GET_UINT32(p_FmPort->p_FmPortPrsRegs->pcac) & PRS_CAC_ACTIVE) ++ ; ++ } ++ ++ if (p_FmPort->pcdEngines & FM_PCD_KG) ++ { ++ t_FmPcdKgInterModuleBindPortToSchemes schemeBind; ++ ++ /* unbind all schemes */ ++ p_FmPort->schemesPerPortVector = GetPortSchemeBindParams(p_FmPort, ++ &schemeBind); ++ ++ err = FmPcdKgUnbindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ err = FmPcdKgDeleteOrUnbindPortToClsPlanGrp(p_FmPort->h_FmPcd, ++ p_FmPort->hardwarePortId, ++ p_FmPort->clsPlanGrpId); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ p_FmPort->useClsPlan = FALSE; ++ } ++ ++ if (p_FmPort->pcdEngines & FM_PCD_CC) ++ { ++ /* unbind - we need to get the treeId too */ ++ err = FmPcdCcUnbindTree(p_FmPort->h_FmPcd, p_FmPort->ccTreeId); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ p_FmPort->pcdEngines = 0; ++ ++ return E_OK; ++} ++ ++static t_Error AttachPCD(t_FmPort *p_FmPort) ++{ ++ volatile uint32_t *p_BmiNia = NULL; ++ ++ ASSERT_COND(p_FmPort); ++ ++ /* get PCD registers pointers */ ++ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; ++ else ++ p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; ++ ++ /* check that current NIA is BMI to BMI */ ++ if ((GET_UINT32(*p_BmiNia) & ~BMI_RFNE_FDCS_MASK) ++ != GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME()) ++ RETURN_ERROR( MAJOR, E_INVALID_OPERATION, ++ ("may be called only for ports in BMI-to-BMI state.")); ++ ++ if (p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY) ++ if (FmSetNumOfRiscsPerPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId, 1, ++ p_FmPort->orFmanCtrl) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ ++ if (p_FmPort->requiredAction & UPDATE_NIA_CMNE) ++ { ++ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ocmne, ++ p_FmPort->savedBmiCmne); ++ else ++ WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rcmne, ++ p_FmPort->savedBmiCmne); ++ } ++ ++ if (p_FmPort->requiredAction & UPDATE_NIA_PNEN) ++ WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnen, ++ p_FmPort->savedQmiPnen); ++ ++ if (p_FmPort->requiredAction & UPDATE_NIA_FENE) ++ { ++ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofene, ++ p_FmPort->savedBmiFene); ++ else ++ WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfene, ++ p_FmPort->savedBmiFene); ++ } ++ ++ if (p_FmPort->requiredAction & UPDATE_NIA_FPNE) ++ { ++ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofpne, ++ p_FmPort->savedBmiFpne); ++ else ++ WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfpne, ++ p_FmPort->savedBmiFpne); ++ } ++ ++ if (p_FmPort->requiredAction & UPDATE_OFP_DPTE) ++ { ++ ASSERT_COND(p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING); ++ ++ WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofp, ++ p_FmPort->savedBmiOfp); ++ } ++ ++ WRITE_UINT32(*p_BmiNia, p_FmPort->savedBmiNia); ++ ++ if (p_FmPort->requiredAction & UPDATE_NIA_PNDN) ++ { ++ p_FmPort->origNonRxQmiRegsPndn = ++ GET_UINT32(p_FmPort->port.qmi_regs->fmqm_pndn); ++ WRITE_UINT32(p_FmPort->port.qmi_regs->fmqm_pndn, ++ p_FmPort->savedNonRxQmiRegsPndn); ++ } ++ ++ return E_OK; ++} ++ ++static t_Error DetachPCD(t_FmPort *p_FmPort) ++{ ++ volatile uint32_t *p_BmiNia = NULL; ++ ++ ASSERT_COND(p_FmPort); ++ ++ /* get PCD registers pointers */ ++ if (p_FmPort->requiredAction & UPDATE_NIA_PNDN) ++ WRITE_UINT32(p_FmPort->port.qmi_regs->fmqm_pndn, ++ p_FmPort->origNonRxQmiRegsPndn); ++ ++ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; ++ else ++ p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; ++ ++ WRITE_UINT32( ++ *p_BmiNia, ++ (p_FmPort->savedBmiNia & BMI_RFNE_FDCS_MASK) | GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME()); ++ ++ if (FmPcdGetHcHandle(p_FmPort->h_FmPcd)) ++ FmPcdHcSync(p_FmPort->h_FmPcd); ++ ++ if (p_FmPort->requiredAction & UPDATE_NIA_FENE) ++ { ++ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofene, ++ NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR); ++ else ++ WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfene, ++ NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR); ++ } ++ ++ if (p_FmPort->requiredAction & UPDATE_NIA_PNEN) ++ WRITE_UINT32(p_FmPort->port.qmi_regs->fmqm_pnen, ++ NIA_ENG_BMI | NIA_BMI_AC_RELEASE); ++ ++ if (p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY) ++ if (FmSetNumOfRiscsPerPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId, 2, ++ p_FmPort->orFmanCtrl) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ ++ p_FmPort->requiredAction = 0; ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++/* Inter-module API routines */ ++/*****************************************************************************/ ++void FmPortSetMacsecCmd(t_Handle h_FmPort, uint8_t dfltSci) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ volatile uint32_t *p_BmiCfgReg = NULL; ++ uint32_t tmpReg; ++ ++ SANITY_CHECK_RETURN(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN(p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_TX)) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_OPERATION, ("The routine is relevant for Tx ports only")); ++ return; ++ } ++ ++ p_BmiCfgReg = &p_FmPort->port.bmi_regs->tx.fmbm_tfca; ++ tmpReg = GET_UINT32(*p_BmiCfgReg) & ~BMI_CMD_ATTR_MACCMD_MASK; ++ tmpReg |= BMI_CMD_ATTR_MACCMD_SECURED; ++ tmpReg |= (((uint32_t)dfltSci << BMI_CMD_ATTR_MACCMD_SC_SHIFT) ++ & BMI_CMD_ATTR_MACCMD_SC_MASK); ++ ++ WRITE_UINT32(*p_BmiCfgReg, tmpReg); ++} ++ ++uint8_t FmPortGetNetEnvId(t_Handle h_FmPort) ++{ ++ return ((t_FmPort*)h_FmPort)->netEnvId; ++} ++ ++uint8_t FmPortGetHardwarePortId(t_Handle h_FmPort) ++{ ++ return ((t_FmPort*)h_FmPort)->hardwarePortId; ++} ++ ++uint32_t FmPortGetPcdEngines(t_Handle h_FmPort) ++{ ++ return ((t_FmPort*)h_FmPort)->pcdEngines; ++} ++ ++#if (DPAA_VERSION >= 11) ++t_Error FmPortSetGprFunc(t_Handle h_FmPort, e_FmPortGprFuncType gprFunc, ++ void **p_Value) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ uint32_t muramPageOffset; ++ ++ ASSERT_COND(p_FmPort); ++ ASSERT_COND(p_Value); ++ ++ if (p_FmPort->gprFunc != e_FM_PORT_GPR_EMPTY) ++ { ++ if (p_FmPort->gprFunc != gprFunc) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("gpr was assigned with different func")); ++ } ++ else ++ { ++ switch (gprFunc) ++ { ++ case (e_FM_PORT_GPR_MURAM_PAGE): ++ p_FmPort->p_ParamsPage = FM_MURAM_AllocMem(p_FmPort->h_FmMuram, ++ 256, 8); ++ if (!p_FmPort->p_ParamsPage) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for page")); ++ ++ IOMemSet32(p_FmPort->p_ParamsPage, 0, 256); ++ muramPageOffset = ++ (uint32_t)(XX_VirtToPhys(p_FmPort->p_ParamsPage) ++ - p_FmPort->fmMuramPhysBaseAddr); ++ switch (p_FmPort->portType) ++ { ++ case (e_FM_PORT_TYPE_RX_10G): ++ case (e_FM_PORT_TYPE_RX): ++ WRITE_UINT32( ++ p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr, ++ muramPageOffset); ++ break; ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ WRITE_UINT32( ++ p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ogpr, ++ muramPageOffset); ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("Invalid port type")); ++ } ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ p_FmPort->gprFunc = gprFunc; ++ } ++ ++ switch (p_FmPort->gprFunc) ++ { ++ case (e_FM_PORT_GPR_MURAM_PAGE): ++ *p_Value = p_FmPort->p_ParamsPage; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ ++ return E_OK; ++} ++#endif /* (DPAA_VERSION >= 11) */ ++ ++t_Error FmPortGetSetCcParams(t_Handle h_FmPort, ++ t_FmPortGetSetCcParams *p_CcParams) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ int tmpInt; ++ volatile uint32_t *p_BmiPrsStartOffset = NULL; ++ ++ /* this function called from Cc for pass and receive parameters port params between CC and PORT*/ ++ ++ if ((p_CcParams->getCcParams.type & OFFSET_OF_PR) ++ && (p_FmPort->bufferOffsets.prsResultOffset != ILLEGAL_BASE)) ++ { ++ p_CcParams->getCcParams.prOffset = ++ (uint8_t)p_FmPort->bufferOffsets.prsResultOffset; ++ p_CcParams->getCcParams.type &= ~OFFSET_OF_PR; ++ } ++ if (p_CcParams->getCcParams.type & HW_PORT_ID) ++ { ++ p_CcParams->getCcParams.hardwarePortId = ++ (uint8_t)p_FmPort->hardwarePortId; ++ p_CcParams->getCcParams.type &= ~HW_PORT_ID; ++ } ++ if ((p_CcParams->getCcParams.type & OFFSET_OF_DATA) ++ && (p_FmPort->bufferOffsets.dataOffset != ILLEGAL_BASE)) ++ { ++ p_CcParams->getCcParams.dataOffset = ++ (uint16_t)p_FmPort->bufferOffsets.dataOffset; ++ p_CcParams->getCcParams.type &= ~OFFSET_OF_DATA; ++ } ++ if (p_CcParams->getCcParams.type & NUM_OF_TASKS) ++ { ++ p_CcParams->getCcParams.numOfTasks = (uint8_t)p_FmPort->tasks.num; ++ p_CcParams->getCcParams.type &= ~NUM_OF_TASKS; ++ } ++ if (p_CcParams->getCcParams.type & NUM_OF_EXTRA_TASKS) ++ { ++ p_CcParams->getCcParams.numOfExtraTasks = ++ (uint8_t)p_FmPort->tasks.extra; ++ p_CcParams->getCcParams.type &= ~NUM_OF_EXTRA_TASKS; ++ } ++ if (p_CcParams->getCcParams.type & FM_REV) ++ { ++ p_CcParams->getCcParams.revInfo.majorRev = p_FmPort->fmRevInfo.majorRev; ++ p_CcParams->getCcParams.revInfo.minorRev = p_FmPort->fmRevInfo.minorRev; ++ p_CcParams->getCcParams.type &= ~FM_REV; ++ } ++ if (p_CcParams->getCcParams.type & DISCARD_MASK) ++ { ++ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ p_CcParams->getCcParams.discardMask = ++ GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm); ++ else ++ p_CcParams->getCcParams.discardMask = ++ GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm); ++ p_CcParams->getCcParams.type &= ~DISCARD_MASK; ++ } ++ if (p_CcParams->getCcParams.type & MANIP_EXTRA_SPACE) ++ { ++ p_CcParams->getCcParams.internalBufferOffset = ++ p_FmPort->internalBufferOffset; ++ p_CcParams->getCcParams.type &= ~MANIP_EXTRA_SPACE; ++ } ++ if (p_CcParams->getCcParams.type & GET_NIA_FPNE) ++ { ++ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ p_CcParams->getCcParams.nia = ++ GET_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofpne); ++ else ++ p_CcParams->getCcParams.nia = ++ GET_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfpne); ++ p_CcParams->getCcParams.type &= ~GET_NIA_FPNE; ++ } ++ if (p_CcParams->getCcParams.type & GET_NIA_PNDN) ++ { ++ if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); ++ p_CcParams->getCcParams.nia = ++ GET_UINT32(p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndn); ++ p_CcParams->getCcParams.type &= ~GET_NIA_PNDN; ++ } ++ ++ if ((p_CcParams->setCcParams.type & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY) ++ && !(p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY)) ++ { ++ p_FmPort->requiredAction |= UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY; ++ p_FmPort->orFmanCtrl = p_CcParams->setCcParams.orFmanCtrl; ++ } ++ ++ if ((p_CcParams->setCcParams.type & UPDATE_NIA_PNEN) ++ && !(p_FmPort->requiredAction & UPDATE_NIA_PNEN)) ++ { ++ p_FmPort->savedQmiPnen = p_CcParams->setCcParams.nia; ++ p_FmPort->requiredAction |= UPDATE_NIA_PNEN; ++ } ++ else ++ if (p_CcParams->setCcParams.type & UPDATE_NIA_PNEN) ++ { ++ if (p_FmPort->savedQmiPnen != p_CcParams->setCcParams.nia) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("PNEN was defined previously different")); ++ } ++ ++ if ((p_CcParams->setCcParams.type & UPDATE_NIA_PNDN) ++ && !(p_FmPort->requiredAction & UPDATE_NIA_PNDN)) ++ { ++ p_FmPort->savedNonRxQmiRegsPndn = p_CcParams->setCcParams.nia; ++ p_FmPort->requiredAction |= UPDATE_NIA_PNDN; ++ } ++ else ++ if (p_CcParams->setCcParams.type & UPDATE_NIA_PNDN) ++ { ++ if (p_FmPort->savedNonRxQmiRegsPndn != p_CcParams->setCcParams.nia) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("PNDN was defined previously different")); ++ } ++ ++ if ((p_CcParams->setCcParams.type & UPDATE_NIA_FENE) ++ && (p_CcParams->setCcParams.overwrite ++ || !(p_FmPort->requiredAction & UPDATE_NIA_FENE))) ++ { ++ p_FmPort->savedBmiFene = p_CcParams->setCcParams.nia; ++ p_FmPort->requiredAction |= UPDATE_NIA_FENE; ++ } ++ else ++ if (p_CcParams->setCcParams.type & UPDATE_NIA_FENE) ++ { ++ if (p_FmPort->savedBmiFene != p_CcParams->setCcParams.nia) ++ RETURN_ERROR( MAJOR, E_INVALID_STATE, ++ ("xFENE was defined previously different")); ++ } ++ ++ if ((p_CcParams->setCcParams.type & UPDATE_NIA_FPNE) ++ && !(p_FmPort->requiredAction & UPDATE_NIA_FPNE)) ++ { ++ p_FmPort->savedBmiFpne = p_CcParams->setCcParams.nia; ++ p_FmPort->requiredAction |= UPDATE_NIA_FPNE; ++ } ++ else ++ if (p_CcParams->setCcParams.type & UPDATE_NIA_FPNE) ++ { ++ if (p_FmPort->savedBmiFpne != p_CcParams->setCcParams.nia) ++ RETURN_ERROR( MAJOR, E_INVALID_STATE, ++ ("xFPNE was defined previously different")); ++ } ++ ++ if ((p_CcParams->setCcParams.type & UPDATE_NIA_CMNE) ++ && !(p_FmPort->requiredAction & UPDATE_NIA_CMNE)) ++ { ++ p_FmPort->savedBmiCmne = p_CcParams->setCcParams.nia; ++ p_FmPort->requiredAction |= UPDATE_NIA_CMNE; ++ } ++ else ++ if (p_CcParams->setCcParams.type & UPDATE_NIA_CMNE) ++ { ++ if (p_FmPort->savedBmiCmne != p_CcParams->setCcParams.nia) ++ RETURN_ERROR( MAJOR, E_INVALID_STATE, ++ ("xCMNE was defined previously different")); ++ } ++ ++ if ((p_CcParams->setCcParams.type & UPDATE_PSO) ++ && !(p_FmPort->requiredAction & UPDATE_PSO)) ++ { ++ /* get PCD registers pointers */ ++ switch (p_FmPort->portType) ++ { ++ case (e_FM_PORT_TYPE_RX_10G): ++ case (e_FM_PORT_TYPE_RX): ++ p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->rx.fmbm_rpso; ++ break; ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->oh.fmbm_opso; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); ++ } ++ ++ /* set start parsing offset */ ++ tmpInt = (int)GET_UINT32(*p_BmiPrsStartOffset) ++ + p_CcParams->setCcParams.psoSize; ++ if (tmpInt > 0) ++ WRITE_UINT32(*p_BmiPrsStartOffset, (uint32_t)tmpInt); ++ ++ p_FmPort->requiredAction |= UPDATE_PSO; ++ p_FmPort->savedPrsStartOffset = p_CcParams->setCcParams.psoSize; ++ } ++ else ++ if (p_CcParams->setCcParams.type & UPDATE_PSO) ++ { ++ if (p_FmPort->savedPrsStartOffset ++ != p_CcParams->setCcParams.psoSize) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("parser start offset was defoned previousley different")); ++ } ++ ++ if ((p_CcParams->setCcParams.type & UPDATE_OFP_DPTE) ++ && !(p_FmPort->requiredAction & UPDATE_OFP_DPTE)) ++ { ++ if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); ++ p_FmPort->savedBmiOfp = GET_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofp); ++ p_FmPort->savedBmiOfp &= ~BMI_FIFO_PIPELINE_DEPTH_MASK; ++ p_FmPort->savedBmiOfp |= p_CcParams->setCcParams.ofpDpde ++ << BMI_FIFO_PIPELINE_DEPTH_SHIFT; ++ p_FmPort->requiredAction |= UPDATE_OFP_DPTE; ++ } ++ ++ return E_OK; ++} ++/*********************** End of inter-module routines ************************/ ++ ++/****************************************/ ++/* API Init unit functions */ ++/****************************************/ ++ ++t_Handle FM_PORT_Config(t_FmPortParams *p_FmPortParams) ++{ ++ t_FmPort *p_FmPort; ++ uintptr_t baseAddr = p_FmPortParams->baseAddr; ++ uint32_t tmpReg; ++ ++ /* Allocate FM structure */ ++ p_FmPort = (t_FmPort *)XX_Malloc(sizeof(t_FmPort)); ++ if (!p_FmPort) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Port driver structure")); ++ return NULL; ++ } ++ memset(p_FmPort, 0, sizeof(t_FmPort)); ++ ++ /* Allocate the FM driver's parameters structure */ ++ p_FmPort->p_FmPortDriverParam = (t_FmPortDriverParam *)XX_Malloc( ++ sizeof(t_FmPortDriverParam)); ++ if (!p_FmPort->p_FmPortDriverParam) ++ { ++ XX_Free(p_FmPort); ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Port driver parameters")); ++ return NULL; ++ } ++ memset(p_FmPort->p_FmPortDriverParam, 0, sizeof(t_FmPortDriverParam)); ++ ++ /* Initialize FM port parameters which will be kept by the driver */ ++ p_FmPort->portType = p_FmPortParams->portType; ++ p_FmPort->portId = p_FmPortParams->portId; ++ p_FmPort->pcdEngines = FM_PCD_NONE; ++ p_FmPort->f_Exception = p_FmPortParams->f_Exception; ++ p_FmPort->h_App = p_FmPortParams->h_App; ++ p_FmPort->h_Fm = p_FmPortParams->h_Fm; ++ ++ /* get FM revision */ ++ FM_GetRevision(p_FmPort->h_Fm, &p_FmPort->fmRevInfo); ++ ++ /* calculate global portId number */ ++ p_FmPort->hardwarePortId = SwPortIdToHwPortId(p_FmPort->portType, ++ p_FmPortParams->portId, ++ p_FmPort->fmRevInfo.majorRev, ++ p_FmPort->fmRevInfo.minorRev); ++ ++ if (p_FmPort->fmRevInfo.majorRev >= 6) ++ { ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) ++ && (p_FmPortParams->portId != FM_OH_PORT_ID)) ++ DBG(WARNING, ++ ("Port ID %d is recommended for HC port. Overwriting HW defaults to be suitable for HC.", ++ FM_OH_PORT_ID)); ++ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ && (p_FmPortParams->portId == FM_OH_PORT_ID)) ++ DBG(WARNING, ("Use non-zero portId for OP port due to insufficient resources on portId 0.")); ++ } ++ ++ /* Set up FM port parameters for initialization phase only */ ++ ++ /* First, fill in flibs struct */ ++ fman_port_defconfig(&p_FmPort->p_FmPortDriverParam->dfltCfg, ++ (enum fman_port_type)p_FmPort->portType); ++ /* Overwrite some integration specific parameters */ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.rx_pri_elevation = ++ DEFAULT_PORT_rxFifoPriElevationLevel; ++ p_FmPort->p_FmPortDriverParam->dfltCfg.rx_fifo_thr = ++ DEFAULT_PORT_rxFifoThreshold; ++ ++#if defined(FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675) || defined(FM_ERROR_VSP_NO_MATCH_SW006) ++ p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006675 = TRUE; ++#else ++ p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006675 = FALSE; ++#endif ++ if ((p_FmPort->fmRevInfo.majorRev == 6) ++ && (p_FmPort->fmRevInfo.minorRev == 0)) ++ p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006320 = TRUE; ++ else ++ p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006320 = FALSE; ++ ++ /* Excessive Threshold register - exists for pre-FMv3 chips only */ ++ if (p_FmPort->fmRevInfo.majorRev < 6) ++ { ++#ifdef FM_NO_RESTRICT_ON_ACCESS_RSRC ++ p_FmPort->p_FmPortDriverParam->dfltCfg.excessive_threshold_register = ++ TRUE; ++#endif ++ p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_rebm_has_sgd = FALSE; ++ p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_tfne_has_features = FALSE; ++ } ++ else ++ { ++ p_FmPort->p_FmPortDriverParam->dfltCfg.excessive_threshold_register = ++ FALSE; ++ p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_rebm_has_sgd = TRUE; ++ p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_tfne_has_features = TRUE; ++ } ++ if (p_FmPort->fmRevInfo.majorRev == 4) ++ p_FmPort->p_FmPortDriverParam->dfltCfg.qmi_deq_options_support = FALSE; ++ else ++ p_FmPort->p_FmPortDriverParam->dfltCfg.qmi_deq_options_support = TRUE; ++ ++ /* Continue with other parameters */ ++ p_FmPort->p_FmPortDriverParam->baseAddr = baseAddr; ++ /* set memory map pointers */ ++ p_FmPort->p_FmPortQmiRegs = ++ (t_FmPortQmiRegs *)UINT_TO_PTR(baseAddr + QMI_PORT_REGS_OFFSET); ++ p_FmPort->p_FmPortBmiRegs = ++ (u_FmPortBmiRegs *)UINT_TO_PTR(baseAddr + BMI_PORT_REGS_OFFSET); ++ p_FmPort->p_FmPortPrsRegs = ++ (t_FmPortPrsRegs *)UINT_TO_PTR(baseAddr + PRS_PORT_REGS_OFFSET); ++ ++ p_FmPort->p_FmPortDriverParam->bufferPrefixContent.privDataSize = ++ DEFAULT_PORT_bufferPrefixContent_privDataSize; ++ p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passPrsResult = ++ DEFAULT_PORT_bufferPrefixContent_passPrsResult; ++ p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passTimeStamp = ++ DEFAULT_PORT_bufferPrefixContent_passTimeStamp; ++ p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passAllOtherPCDInfo = ++ DEFAULT_PORT_bufferPrefixContent_passTimeStamp; ++ p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign = ++ DEFAULT_PORT_bufferPrefixContent_dataAlign; ++ /* p_FmPort->p_FmPortDriverParam->dmaSwapData = (e_FmDmaSwapOption)DEFAULT_PORT_dmaSwapData; ++ p_FmPort->p_FmPortDriverParam->dmaIntContextCacheAttr = (e_FmDmaCacheOption)DEFAULT_PORT_dmaIntContextCacheAttr; ++ p_FmPort->p_FmPortDriverParam->dmaHeaderCacheAttr = (e_FmDmaCacheOption)DEFAULT_PORT_dmaHeaderCacheAttr; ++ p_FmPort->p_FmPortDriverParam->dmaScatterGatherCacheAttr = (e_FmDmaCacheOption)DEFAULT_PORT_dmaScatterGatherCacheAttr; ++ p_FmPort->p_FmPortDriverParam->dmaWriteOptimize = DEFAULT_PORT_dmaWriteOptimize; ++ */ ++ p_FmPort->p_FmPortDriverParam->liodnBase = p_FmPortParams->liodnBase; ++ p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore = ++ DEFAULT_PORT_cheksumLastBytesIgnore; ++ ++ p_FmPort->maxFrameLength = DEFAULT_PORT_maxFrameLength; ++ /* resource distribution. */ ++ p_FmPort->fifoBufs.num = DEFAULT_PORT_numOfFifoBufs(p_FmPort->portType) ++ * BMI_FIFO_UNITS; ++ p_FmPort->fifoBufs.extra = DEFAULT_PORT_extraNumOfFifoBufs ++ * BMI_FIFO_UNITS; ++ p_FmPort->openDmas.num = DEFAULT_PORT_numOfOpenDmas(p_FmPort->portType); ++ p_FmPort->openDmas.extra = ++ DEFAULT_PORT_extraNumOfOpenDmas(p_FmPort->portType); ++ p_FmPort->tasks.num = DEFAULT_PORT_numOfTasks(p_FmPort->portType); ++ p_FmPort->tasks.extra = DEFAULT_PORT_extraNumOfTasks(p_FmPort->portType); ++ ++ ++#ifdef FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 ++ if ((p_FmPort->fmRevInfo.majorRev == 6) ++ && (p_FmPort->fmRevInfo.minorRev == 0) ++ && ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_TX))) ++ { ++ p_FmPort->openDmas.num = 16; ++ p_FmPort->openDmas.extra = 0; ++ } ++#endif /* FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 */ ++ ++ /* Port type specific initialization: */ ++ switch (p_FmPort->portType) ++ { ++ case (e_FM_PORT_TYPE_RX): ++ case (e_FM_PORT_TYPE_RX_10G): ++ /* Initialize FM port parameters for initialization phase only */ ++ p_FmPort->p_FmPortDriverParam->cutBytesFromEnd = ++ DEFAULT_PORT_cutBytesFromEnd; ++ p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = FALSE; ++ p_FmPort->p_FmPortDriverParam->frmDiscardOverride = ++ DEFAULT_PORT_frmDiscardOverride; ++ ++ tmpReg = ++ GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfp); ++ p_FmPort->p_FmPortDriverParam->rxFifoPriElevationLevel = ++ (((tmpReg & BMI_RX_FIFO_PRI_ELEVATION_MASK) ++ >> BMI_RX_FIFO_PRI_ELEVATION_SHIFT) + 1) ++ * BMI_FIFO_UNITS; ++ p_FmPort->p_FmPortDriverParam->rxFifoThreshold = (((tmpReg ++ & BMI_RX_FIFO_THRESHOLD_MASK) ++ >> BMI_RX_FIFO_THRESHOLD_SHIFT) + 1) * BMI_FIFO_UNITS; ++ ++ p_FmPort->p_FmPortDriverParam->bufMargins.endMargins = ++ DEFAULT_PORT_BufMargins_endMargins; ++ p_FmPort->p_FmPortDriverParam->errorsToDiscard = ++ DEFAULT_PORT_errorsToDiscard; ++ p_FmPort->p_FmPortDriverParam->forwardReuseIntContext = ++ DEFAULT_PORT_forwardIntContextReuse; ++#if (DPAA_VERSION >= 11) ++ p_FmPort->p_FmPortDriverParam->noScatherGather = ++ DEFAULT_PORT_noScatherGather; ++#endif /* (DPAA_VERSION >= 11) */ ++ break; ++ ++ case (e_FM_PORT_TYPE_TX): ++ p_FmPort->p_FmPortDriverParam->dontReleaseBuf = FALSE; ++#ifdef FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 ++ tmpReg = 0x00001013; ++ WRITE_UINT32( p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfp, ++ tmpReg); ++#endif /* FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 */ ++ case (e_FM_PORT_TYPE_TX_10G): ++ tmpReg = ++ GET_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfp); ++ p_FmPort->p_FmPortDriverParam->txFifoMinFillLevel = ((tmpReg ++ & BMI_TX_FIFO_MIN_FILL_MASK) ++ >> BMI_TX_FIFO_MIN_FILL_SHIFT) * BMI_FIFO_UNITS; ++ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = ++ (uint8_t)(((tmpReg & BMI_FIFO_PIPELINE_DEPTH_MASK) ++ >> BMI_FIFO_PIPELINE_DEPTH_SHIFT) + 1); ++ p_FmPort->p_FmPortDriverParam->txFifoLowComfLevel = (((tmpReg ++ & BMI_TX_LOW_COMF_MASK) >> BMI_TX_LOW_COMF_SHIFT) + 1) ++ * BMI_FIFO_UNITS; ++ ++ p_FmPort->p_FmPortDriverParam->deqType = DEFAULT_PORT_deqType; ++ p_FmPort->p_FmPortDriverParam->deqPrefetchOption = ++ DEFAULT_PORT_deqPrefetchOption; ++ p_FmPort->p_FmPortDriverParam->deqHighPriority = ++ (bool)((p_FmPort->portType == e_FM_PORT_TYPE_TX) ? DEFAULT_PORT_deqHighPriority_1G : ++ DEFAULT_PORT_deqHighPriority_10G); ++ p_FmPort->p_FmPortDriverParam->deqByteCnt = ++ (uint16_t)( ++ (p_FmPort->portType == e_FM_PORT_TYPE_TX) ? DEFAULT_PORT_deqByteCnt_1G : ++ DEFAULT_PORT_deqByteCnt_10G); ++ break; ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ p_FmPort->p_FmPortDriverParam->errorsToDiscard = ++ DEFAULT_PORT_errorsToDiscard; ++#if (DPAA_VERSION >= 11) ++ p_FmPort->p_FmPortDriverParam->noScatherGather = ++ DEFAULT_PORT_noScatherGather; ++#endif /* (DPAA_VERSION >= 11) */ ++ case (e_FM_PORT_TYPE_OH_HOST_COMMAND): ++ p_FmPort->p_FmPortDriverParam->deqPrefetchOption = ++ DEFAULT_PORT_deqPrefetchOption_HC; ++ p_FmPort->p_FmPortDriverParam->deqHighPriority = ++ DEFAULT_PORT_deqHighPriority_1G; ++ p_FmPort->p_FmPortDriverParam->deqType = DEFAULT_PORT_deqType; ++ p_FmPort->p_FmPortDriverParam->deqByteCnt = ++ DEFAULT_PORT_deqByteCnt_1G; ++ ++ tmpReg = ++ GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofp); ++ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = ++ (uint8_t)(((tmpReg & BMI_FIFO_PIPELINE_DEPTH_MASK) ++ >> BMI_FIFO_PIPELINE_DEPTH_SHIFT) + 1); ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) ++ && (p_FmPortParams->portId != FM_OH_PORT_ID)) ++ { ++ /* Overwrite HC defaults */ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = ++ DEFAULT_PORT_fifoDeqPipelineDepth_OH; ++ } ++ ++#ifndef FM_FRAME_END_PARAMS_FOR_OP ++ if (p_FmPort->fmRevInfo.majorRev < 6) ++ p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore = DEFAULT_notSupported; ++#endif /* !FM_FRAME_END_PARAMS_FOR_OP */ ++ ++#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP ++ if (!((p_FmPort->fmRevInfo.majorRev == 4) || ++ (p_FmPort->fmRevInfo.majorRev >= 6))) ++ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = DEFAULT_notSupported; ++#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */ ++ break; ++ ++ default: ++ XX_Free(p_FmPort->p_FmPortDriverParam); ++ XX_Free(p_FmPort); ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); ++ return NULL; ++ } ++#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT ++ if (p_FmPort->fmRevInfo.majorRev == 4) ++ p_FmPort->p_FmPortDriverParam->deqPrefetchOption = (e_FmPortDeqPrefetchOption)DEFAULT_notSupported; ++#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ ++ ++ p_FmPort->imEn = p_FmPortParams->independentModeEnable; ++ ++ if (p_FmPort->imEn) ++ { ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_TX) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)) ++ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = ++ DEFAULT_PORT_fifoDeqPipelineDepth_IM; ++ FmPortConfigIM(p_FmPort, p_FmPortParams); ++ } ++ else ++ { ++ switch (p_FmPort->portType) ++ { ++ case (e_FM_PORT_TYPE_RX): ++ case (e_FM_PORT_TYPE_RX_10G): ++ /* Initialize FM port parameters for initialization phase only */ ++ memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools, ++ &p_FmPortParams->specificParams.rxParams.extBufPools, ++ sizeof(t_FmExtPools)); ++ p_FmPort->p_FmPortDriverParam->errFqid = ++ p_FmPortParams->specificParams.rxParams.errFqid; ++ p_FmPort->p_FmPortDriverParam->dfltFqid = ++ p_FmPortParams->specificParams.rxParams.dfltFqid; ++ p_FmPort->p_FmPortDriverParam->liodnOffset = ++ p_FmPortParams->specificParams.rxParams.liodnOffset; ++ break; ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ case (e_FM_PORT_TYPE_TX): ++ case (e_FM_PORT_TYPE_TX_10G): ++ case (e_FM_PORT_TYPE_OH_HOST_COMMAND): ++ p_FmPort->p_FmPortDriverParam->errFqid = ++ p_FmPortParams->specificParams.nonRxParams.errFqid; ++ p_FmPort->p_FmPortDriverParam->deqSubPortal = ++ (uint8_t)(p_FmPortParams->specificParams.nonRxParams.qmChannel ++ & QMI_DEQ_CFG_SUBPORTAL_MASK); ++ p_FmPort->p_FmPortDriverParam->dfltFqid = ++ p_FmPortParams->specificParams.nonRxParams.dfltFqid; ++ break; ++ default: ++ XX_Free(p_FmPort->p_FmPortDriverParam); ++ XX_Free(p_FmPort); ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); ++ return NULL; ++ } ++ } ++ ++ memset(p_FmPort->name, 0, (sizeof(char)) * MODULE_NAME_SIZE); ++ if (Sprint( ++ p_FmPort->name, ++ "FM-%d-port-%s-%d", ++ FmGetId(p_FmPort->h_Fm), ++ ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING ++ || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) ? "OH" : ++ (p_FmPort->portType == e_FM_PORT_TYPE_RX ? "1g-RX" : ++ (p_FmPort->portType == e_FM_PORT_TYPE_TX ? "1g-TX" : ++ (p_FmPort->portType ++ == e_FM_PORT_TYPE_RX_10G ? "10g-RX" : ++ "10g-TX")))), ++ p_FmPort->portId) == 0) ++ { ++ XX_Free(p_FmPort->p_FmPortDriverParam); ++ XX_Free(p_FmPort); ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); ++ return NULL; ++ } ++ ++ p_FmPort->h_Spinlock = XX_InitSpinlock(); ++ if (!p_FmPort->h_Spinlock) ++ { ++ XX_Free(p_FmPort->p_FmPortDriverParam); ++ XX_Free(p_FmPort); ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); ++ return NULL; ++ } ++ ++ return p_FmPort; ++} ++ ++t_FmPort *rx_port = 0; ++t_FmPort *tx_port = 0; ++ ++/**************************************************************************//** ++ @Function FM_PORT_Init ++ ++ @Description Initializes the FM module ++ ++ @Param[in] h_FmPort - FM module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++ *//***************************************************************************/ ++t_Error FM_PORT_Init(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_FmPortDriverParam *p_DriverParams; ++ t_Error errCode; ++ t_FmInterModulePortInitParams fmParams; ++ t_FmRevisionInfo revInfo; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ errCode = FmSpBuildBufferStructure( ++ &p_FmPort->p_FmPortDriverParam->intContext, ++ &p_FmPort->p_FmPortDriverParam->bufferPrefixContent, ++ &p_FmPort->p_FmPortDriverParam->bufMargins, ++ &p_FmPort->bufferOffsets, &p_FmPort->internalBufferOffset); ++ if (errCode != E_OK) ++ RETURN_ERROR(MAJOR, errCode, NO_MSG); ++#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 ++ if ((p_FmPort->p_FmPortDriverParam->bcbWorkaround) && ++ (p_FmPort->portType == e_FM_PORT_TYPE_RX)) ++ { ++ p_FmPort->p_FmPortDriverParam->errorsToDiscard |= FM_PORT_FRM_ERR_PHYSICAL; ++ if (!p_FmPort->fifoBufs.num) ++ p_FmPort->fifoBufs.num = DEFAULT_PORT_numOfFifoBufs(p_FmPort->portType)*BMI_FIFO_UNITS; ++ p_FmPort->fifoBufs.num += 4*KILOBYTE; ++ } ++#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */ ++ ++ CHECK_INIT_PARAMETERS(p_FmPort, CheckInitParameters); ++ ++ p_DriverParams = p_FmPort->p_FmPortDriverParam; ++ ++ /* Set up flibs port structure */ ++ memset(&p_FmPort->port, 0, sizeof(struct fman_port)); ++ p_FmPort->port.type = (enum fman_port_type)p_FmPort->portType; ++ FM_GetRevision(p_FmPort->h_Fm, &revInfo); ++ p_FmPort->port.fm_rev_maj = revInfo.majorRev; ++ p_FmPort->port.fm_rev_min = revInfo.minorRev; ++ p_FmPort->port.bmi_regs = ++ (union fman_port_bmi_regs *)UINT_TO_PTR(p_DriverParams->baseAddr + BMI_PORT_REGS_OFFSET); ++ p_FmPort->port.qmi_regs = ++ (struct fman_port_qmi_regs *)UINT_TO_PTR(p_DriverParams->baseAddr + QMI_PORT_REGS_OFFSET); ++ p_FmPort->port.ext_pools_num = (uint8_t)((revInfo.majorRev == 4) ? 4 : 8); ++ p_FmPort->port.im_en = p_FmPort->imEn; ++ p_FmPort->p_FmPortPrsRegs = ++ (t_FmPortPrsRegs *)UINT_TO_PTR(p_DriverParams->baseAddr + PRS_PORT_REGS_OFFSET); ++ ++ if (((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) && !p_FmPort->imEn) ++ { ++ /* Call the external Buffer routine which also checks fifo ++ size and updates it if necessary */ ++ /* define external buffer pools and pool depletion*/ ++ errCode = SetExtBufferPools(p_FmPort); ++ if (errCode) ++ RETURN_ERROR(MAJOR, errCode, NO_MSG); ++ /* check if the largest external buffer pool is large enough */ ++ if (p_DriverParams->bufMargins.startMargins + MIN_EXT_BUF_SIZE ++ + p_DriverParams->bufMargins.endMargins ++ > p_FmPort->rxPoolsParams.largestBufSize) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("bufMargins.startMargins (%d) + minimum buf size (64) + bufMargins.endMargins (%d) is larger than maximum external buffer size (%d)", p_DriverParams->bufMargins.startMargins, p_DriverParams->bufMargins.endMargins, p_FmPort->rxPoolsParams.largestBufSize)); ++ } ++ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ { ++ { ++#ifdef FM_NO_OP_OBSERVED_POOLS ++ t_FmRevisionInfo revInfo; ++ ++ FM_GetRevision(p_FmPort->h_Fm, &revInfo); ++ if ((revInfo.majorRev == 4) && (p_DriverParams->enBufPoolDepletion)) ++#endif /* FM_NO_OP_OBSERVED_POOLS */ ++ { ++ /* define external buffer pools */ ++ errCode = SetExtBufferPools(p_FmPort); ++ if (errCode) ++ RETURN_ERROR(MAJOR, errCode, NO_MSG); ++ } ++ } ++ } ++ ++ /************************************************************/ ++ /* Call FM module routine for communicating parameters */ ++ /************************************************************/ ++ memset(&fmParams, 0, sizeof(fmParams)); ++ fmParams.hardwarePortId = p_FmPort->hardwarePortId; ++ fmParams.portType = (e_FmPortType)p_FmPort->portType; ++ fmParams.numOfTasks = (uint8_t)p_FmPort->tasks.num; ++ fmParams.numOfExtraTasks = (uint8_t)p_FmPort->tasks.extra; ++ fmParams.numOfOpenDmas = (uint8_t)p_FmPort->openDmas.num; ++ fmParams.numOfExtraOpenDmas = (uint8_t)p_FmPort->openDmas.extra; ++ ++ if (p_FmPort->fifoBufs.num) ++ { ++ errCode = VerifySizeOfFifo(p_FmPort); ++ if (errCode != E_OK) ++ RETURN_ERROR(MAJOR, errCode, NO_MSG); ++ } ++ fmParams.sizeOfFifo = p_FmPort->fifoBufs.num; ++ fmParams.extraSizeOfFifo = p_FmPort->fifoBufs.extra; ++ fmParams.independentMode = p_FmPort->imEn; ++ fmParams.liodnOffset = p_DriverParams->liodnOffset; ++ fmParams.liodnBase = p_DriverParams->liodnBase; ++ fmParams.deqPipelineDepth = ++ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth; ++ fmParams.maxFrameLength = p_FmPort->maxFrameLength; ++#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) || ++ (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) ++ { ++ if (!((p_FmPort->fmRevInfo.majorRev == 4) || ++ (p_FmPort->fmRevInfo.majorRev >= 6))) ++ /* HC ports do not have fifoDeqPipelineDepth, but it is needed only ++ * for deq threshold calculation. ++ */ ++ fmParams.deqPipelineDepth = 2; ++ } ++#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */ ++ ++ errCode = FmGetSetPortParams(p_FmPort->h_Fm, &fmParams); ++ if (errCode) ++ RETURN_ERROR(MAJOR, errCode, NO_MSG); ++ ++ /* get params for use in init */ ++ p_FmPort->fmMuramPhysBaseAddr = ++ (uint64_t)((uint64_t)(fmParams.fmMuramPhysBaseAddr.low) ++ | ((uint64_t)(fmParams.fmMuramPhysBaseAddr.high) << 32)); ++ p_FmPort->h_FmMuram = FmGetMuramHandle(p_FmPort->h_Fm); ++ ++ errCode = InitLowLevelDriver(p_FmPort); ++ if (errCode != E_OK) ++ RETURN_ERROR(MAJOR, errCode, NO_MSG); ++ ++ FmPortDriverParamFree(p_FmPort); ++ ++#if (DPAA_VERSION >= 11) ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ++ { ++ t_FmPcdCtrlParamsPage *p_ParamsPage; ++ ++ FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE, ++ (void**)&p_ParamsPage); ++ ASSERT_COND(p_ParamsPage); ++ ++ WRITE_UINT32(p_ParamsPage->misc, FM_CTL_PARAMS_PAGE_ALWAYS_ON); ++#ifdef FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675 ++ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ { ++ WRITE_UINT32( ++ p_ParamsPage->misc, ++ (GET_UINT32(p_ParamsPage->misc) | FM_CTL_PARAMS_PAGE_OP_FIX_EN)); ++ WRITE_UINT32( ++ p_ParamsPage->discardMask, ++ GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm)); ++ } ++#endif /* FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675 */ ++#ifdef FM_ERROR_VSP_NO_MATCH_SW006 ++ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ WRITE_UINT32( ++ p_ParamsPage->errorsDiscardMask, ++ (GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm) | GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsem))); ++ else ++ WRITE_UINT32( ++ p_ParamsPage->errorsDiscardMask, ++ (GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm) | GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsem))); ++#endif /* FM_ERROR_VSP_NO_MATCH_SW006 */ ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ if (p_FmPort->deepSleepVars.autoResMaxSizes) ++ FmPortConfigAutoResForDeepSleepSupport1(p_FmPort); ++ return E_OK; ++} ++ ++/**************************************************************************//** ++ @Function FM_PORT_Free ++ ++ @Description Frees all resources that were assigned to FM module. ++ ++ Calling this routine invalidates the descriptor. ++ ++ @Param[in] h_FmPort - FM module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++ *//***************************************************************************/ ++t_Error FM_PORT_Free(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_FmInterModulePortFreeParams fmParams; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ ++ if (p_FmPort->pcdEngines) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("Trying to free a port with PCD. FM_PORT_DeletePCD must be called first.")); ++ ++ if (p_FmPort->enabled) ++ { ++ if (FM_PORT_Disable(p_FmPort) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM_PORT_Disable FAILED")); ++ } ++ ++ if (p_FmPort->imEn) ++ FmPortImFree(p_FmPort); ++ ++ FmPortDriverParamFree(p_FmPort); ++ ++ memset(&fmParams, 0, sizeof(fmParams)); ++ fmParams.hardwarePortId = p_FmPort->hardwarePortId; ++ fmParams.portType = (e_FmPortType)p_FmPort->portType; ++ fmParams.deqPipelineDepth = ++ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth; ++ ++ FmFreePortParams(p_FmPort->h_Fm, &fmParams); ++ ++#if (DPAA_VERSION >= 11) ++ if (FmVSPFreeForPort(p_FmPort->h_Fm, p_FmPort->portType, p_FmPort->portId) ++ != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("VSP free of port FAILED")); ++ ++ if (p_FmPort->p_ParamsPage) ++ FM_MURAM_FreeMem(p_FmPort->h_FmMuram, p_FmPort->p_ParamsPage); ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ if (p_FmPort->h_Spinlock) ++ XX_FreeSpinlock(p_FmPort->h_Spinlock); ++ ++ XX_Free(p_FmPort); ++ ++ return E_OK; ++} ++ ++/*************************************************/ ++/* API Advanced Init unit functions */ ++/*************************************************/ ++ ++t_Error FM_PORT_ConfigNumOfOpenDmas(t_Handle h_FmPort, t_FmPortRsrc *p_OpenDmas) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ p_FmPort->p_FmPortDriverParam->setNumOfOpenDmas = TRUE; ++ memcpy(&p_FmPort->openDmas, p_OpenDmas, sizeof(t_FmPortRsrc)); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ memcpy(&p_FmPort->tasks, p_NumOfTasks, sizeof(t_FmPortRsrc)); ++ p_FmPort->p_FmPortDriverParam->setNumOfTasks = TRUE; ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ p_FmPort->p_FmPortDriverParam->setSizeOfFifo = TRUE; ++ memcpy(&p_FmPort->fifoBufs, p_SizeOfFifo, sizeof(t_FmPortRsrc)); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigDeqHighPriority(t_Handle h_FmPort, bool highPri) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("not available for Rx ports")); ++ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.deq_high_pri = highPri; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigDeqType(t_Handle h_FmPort, e_FmPortDeqType deqType) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("not available for Rx ports")); ++ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.deq_type = ++ (enum fman_port_deq_type)deqType; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigDeqPrefetchOption( ++ t_Handle h_FmPort, e_FmPortDeqPrefetchOption deqPrefetchOption) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("not available for Rx ports")); ++ p_FmPort->p_FmPortDriverParam->dfltCfg.deq_prefetch_opt = ++ (enum fman_port_deq_prefetch)deqPrefetchOption; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigBackupPools(t_Handle h_FmPort, ++ t_FmBackupBmPools *p_BackupBmPools) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for Rx ports only")); ++ ++ p_FmPort->p_FmPortDriverParam->p_BackupBmPools = ++ (t_FmBackupBmPools *)XX_Malloc(sizeof(t_FmBackupBmPools)); ++ if (!p_FmPort->p_FmPortDriverParam->p_BackupBmPools) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_BackupBmPools allocation failed")); ++ memcpy(p_FmPort->p_FmPortDriverParam->p_BackupBmPools, p_BackupBmPools, ++ sizeof(t_FmBackupBmPools)); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigDeqByteCnt(t_Handle h_FmPort, uint16_t deqByteCnt) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("not available for Rx ports")); ++ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.deq_byte_cnt = deqByteCnt; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigBufferPrefixContent( ++ t_Handle h_FmPort, t_FmBufferPrefixContent *p_FmBufferPrefixContent) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ memcpy(&p_FmPort->p_FmPortDriverParam->bufferPrefixContent, ++ p_FmBufferPrefixContent, sizeof(t_FmBufferPrefixContent)); ++ /* if dataAlign was not initialized by user, we return to driver's default */ ++ if (!p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign) ++ p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign = ++ DEFAULT_PORT_bufferPrefixContent_dataAlign; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigCheksumLastBytesIgnore(t_Handle h_FmPort, ++ uint8_t checksumLastBytesIgnore) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.checksum_bytes_ignore = ++ checksumLastBytesIgnore; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigCutBytesFromEnd(t_Handle h_FmPort, ++ uint8_t cutBytesFromEnd) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for Rx ports only")); ++ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.rx_cut_end_bytes = cutBytesFromEnd; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigPoolDepletion(t_Handle h_FmPort, ++ t_FmBufPoolDepletion *p_BufPoolDepletion) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for Rx ports only")); ++ ++ p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = TRUE; ++ memcpy(&p_FmPort->p_FmPortDriverParam->bufPoolDepletion, p_BufPoolDepletion, ++ sizeof(t_FmBufPoolDepletion)); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigObservedPoolDepletion( ++ t_Handle h_FmPort, ++ t_FmPortObservedBufPoolDepletion *p_FmPortObservedBufPoolDepletion) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for OP ports only")); ++ ++ p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = TRUE; ++ memcpy(&p_FmPort->p_FmPortDriverParam->bufPoolDepletion, ++ &p_FmPortObservedBufPoolDepletion->poolDepletionParams, ++ sizeof(t_FmBufPoolDepletion)); ++ memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools, ++ &p_FmPortObservedBufPoolDepletion->poolsParams, ++ sizeof(t_FmExtPools)); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigExtBufPools(t_Handle h_FmPort, t_FmExtPools *p_FmExtPools) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for OP ports only")); ++ ++ memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools, p_FmExtPools, ++ sizeof(t_FmExtPools)); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigDontReleaseTxBufToBM(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_TX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for Tx ports only")); ++ ++ p_FmPort->p_FmPortDriverParam->dontReleaseBuf = TRUE; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigDfltColor(t_Handle h_FmPort, e_FmPortColor color) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ p_FmPort->p_FmPortDriverParam->dfltCfg.color = (enum fman_port_color)color; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigSyncReq(t_Handle h_FmPort, bool syncReq) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_TX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("Not available for Tx ports")); ++ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.sync_req = syncReq; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigFrmDiscardOverride(t_Handle h_FmPort, bool override) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_TX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("Not available for Tx ports")); ++ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.discard_override = override; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigErrorsToDiscard(t_Handle h_FmPort, ++ fmPortFrameErrSelect_t errs) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ++ RETURN_ERROR( MAJOR, E_INVALID_OPERATION, ++ ("available for Rx and offline parsing ports only")); ++ ++ p_FmPort->p_FmPortDriverParam->errorsToDiscard = errs; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigDmaSwapData(t_Handle h_FmPort, e_FmDmaSwapOption swapData) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.dma_swap_data = ++ (enum fman_port_dma_swap)swapData; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigDmaIcCacheAttr(t_Handle h_FmPort, ++ e_FmDmaCacheOption intContextCacheAttr) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.dma_ic_stash_on = ++ (bool)(intContextCacheAttr == e_FM_DMA_STASH); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigDmaHdrAttr(t_Handle h_FmPort, ++ e_FmDmaCacheOption headerCacheAttr) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.dma_header_stash_on = ++ (bool)(headerCacheAttr == e_FM_DMA_STASH); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigDmaScatterGatherAttr( ++ t_Handle h_FmPort, e_FmDmaCacheOption scatterGatherCacheAttr) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.dma_sg_stash_on = ++ (bool)(scatterGatherCacheAttr == e_FM_DMA_STASH); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigDmaWriteOptimize(t_Handle h_FmPort, bool optimize) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_TX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("Not available for Tx ports")); ++ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.dma_write_optimize = optimize; ++ ++ return E_OK; ++} ++ ++#if (DPAA_VERSION >= 11) ++t_Error FM_PORT_ConfigNoScatherGather(t_Handle h_FmPort, bool noScatherGather) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ UNUSED(noScatherGather); ++ UNUSED(p_FmPort); ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ p_FmPort->p_FmPortDriverParam->noScatherGather = noScatherGather; ++ ++ return E_OK; ++} ++#endif /* (DPAA_VERSION >= 11) */ ++ ++t_Error FM_PORT_ConfigForwardReuseIntContext(t_Handle h_FmPort, ++ bool forwardReuse) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for Rx ports only")); ++ ++ p_FmPort->p_FmPortDriverParam->forwardReuseIntContext = forwardReuse; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigMaxFrameLength(t_Handle h_FmPort, uint16_t length) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ p_FmPort->maxFrameLength = length; ++ ++ return E_OK; ++} ++ ++#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 ++t_Error FM_PORT_ConfigBCBWorkaround(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ p_FmPort->p_FmPortDriverParam->bcbWorkaround = TRUE; ++ ++ return E_OK; ++} ++#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */ ++ ++/****************************************************/ ++/* Hidden-DEBUG Only API */ ++/****************************************************/ ++ ++t_Error FM_PORT_ConfigTxFifoMinFillLevel(t_Handle h_FmPort, ++ uint32_t minFillLevel) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_TX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for Tx ports only")); ++ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_min_level = minFillLevel; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigFifoDeqPipelineDepth(t_Handle h_FmPort, ++ uint8_t deqPipelineDepth) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("Not available for Rx ports")); ++ ++ if (p_FmPort->imEn) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("Not available for IM ports!")); ++ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = ++ deqPipelineDepth; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigTxFifoLowComfLevel(t_Handle h_FmPort, ++ uint32_t fifoLowComfLevel) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_TX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for Tx ports only")); ++ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_low_comf_level = ++ fifoLowComfLevel; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigRxFifoThreshold(t_Handle h_FmPort, uint32_t fifoThreshold) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for Rx ports only")); ++ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.rx_fifo_thr = fifoThreshold; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigRxFifoPriElevationLevel(t_Handle h_FmPort, ++ uint32_t priElevationLevel) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for Rx ports only")); ++ ++ p_FmPort->p_FmPortDriverParam->dfltCfg.rx_pri_elevation = priElevationLevel; ++ ++ return E_OK; ++} ++/****************************************************/ ++/* API Run-time Control unit functions */ ++/****************************************************/ ++ ++t_Error FM_PORT_SetNumOfOpenDmas(t_Handle h_FmPort, ++ t_FmPortRsrc *p_NumOfOpenDmas) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ if ((!p_NumOfOpenDmas->num) || (p_NumOfOpenDmas->num > MAX_NUM_OF_DMAS)) ++ RETURN_ERROR( MAJOR, E_INVALID_VALUE, ++ ("openDmas-num can't be larger than %d", MAX_NUM_OF_DMAS)); ++ if (p_NumOfOpenDmas->extra > MAX_NUM_OF_EXTRA_DMAS) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("openDmas-extra can't be larger than %d", MAX_NUM_OF_EXTRA_DMAS)); ++ err = FmSetNumOfOpenDmas(p_FmPort->h_Fm, p_FmPort->hardwarePortId, ++ (uint8_t*)&p_NumOfOpenDmas->num, ++ (uint8_t*)&p_NumOfOpenDmas->extra, FALSE); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ memcpy(&p_FmPort->openDmas, p_NumOfOpenDmas, sizeof(t_FmPortRsrc)); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_SetNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ /* only driver uses host command port, so ASSERT rather than RETURN_ERROR */ ++ ASSERT_COND(p_FmPort->portType != e_FM_PORT_TYPE_OH_HOST_COMMAND); ++ ++ if ((!p_NumOfTasks->num) || (p_NumOfTasks->num > MAX_NUM_OF_TASKS)) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("NumOfTasks-num can't be larger than %d", MAX_NUM_OF_TASKS)); ++ if (p_NumOfTasks->extra > MAX_NUM_OF_EXTRA_TASKS) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("NumOfTasks-extra can't be larger than %d", MAX_NUM_OF_EXTRA_TASKS)); ++ ++ err = FmSetNumOfTasks(p_FmPort->h_Fm, p_FmPort->hardwarePortId, ++ (uint8_t*)&p_NumOfTasks->num, ++ (uint8_t*)&p_NumOfTasks->extra, FALSE); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ /* update driver's struct */ ++ memcpy(&p_FmPort->tasks, p_NumOfTasks, sizeof(t_FmPortRsrc)); ++ return E_OK; ++} ++ ++t_Error FM_PORT_SetSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ if (!p_SizeOfFifo->num || (p_SizeOfFifo->num > MAX_PORT_FIFO_SIZE)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("SizeOfFifo-num has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE)); ++ if (p_SizeOfFifo->num % BMI_FIFO_UNITS) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("SizeOfFifo-num has to be divisible by %d", BMI_FIFO_UNITS)); ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) ++ { ++ /* extra FIFO size (allowed only to Rx ports) */ ++ if (p_SizeOfFifo->extra % BMI_FIFO_UNITS) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("SizeOfFifo-extra has to be divisible by %d", BMI_FIFO_UNITS)); ++ } ++ else ++ if (p_SizeOfFifo->extra) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ (" No SizeOfFifo-extra for non Rx ports")); ++ ++ memcpy(&p_FmPort->fifoBufs, p_SizeOfFifo, sizeof(t_FmPortRsrc)); ++ ++ /* we do not change user's parameter */ ++ err = VerifySizeOfFifo(p_FmPort); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ err = FmSetSizeOfFifo(p_FmPort->h_Fm, p_FmPort->hardwarePortId, ++ &p_SizeOfFifo->num, &p_SizeOfFifo->extra, FALSE); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ return E_OK; ++} ++ ++uint32_t FM_PORT_GetBufferDataOffset(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0); ++ SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, ++ 0); ++ ++ return p_FmPort->bufferOffsets.dataOffset; ++} ++ ++uint8_t * FM_PORT_GetBufferICInfo(t_Handle h_FmPort, char *p_Data) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, ++ NULL); ++ ++ if (p_FmPort->bufferOffsets.pcdInfoOffset == ILLEGAL_BASE) ++ return NULL; ++ ++ return (uint8_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.pcdInfoOffset); ++} ++ ++t_FmPrsResult * FM_PORT_GetBufferPrsResult(t_Handle h_FmPort, char *p_Data) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, ++ NULL); ++ ++ if (p_FmPort->bufferOffsets.prsResultOffset == ILLEGAL_BASE) ++ return NULL; ++ ++ return (t_FmPrsResult *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.prsResultOffset); ++} ++ ++uint64_t * FM_PORT_GetBufferTimeStamp(t_Handle h_FmPort, char *p_Data) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, ++ NULL); ++ ++ if (p_FmPort->bufferOffsets.timeStampOffset == ILLEGAL_BASE) ++ return NULL; ++ ++ return (uint64_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.timeStampOffset); ++} ++ ++uint8_t * FM_PORT_GetBufferHashResult(t_Handle h_FmPort, char *p_Data) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, ++ NULL); ++ ++ if (p_FmPort->bufferOffsets.hashResultOffset == ILLEGAL_BASE) ++ return NULL; ++ ++ return (uint8_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.hashResultOffset); ++} ++ ++t_Error FM_PORT_Disable(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ int err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ if (p_FmPort->imEn) ++ FmPortImDisable(p_FmPort); ++ ++ err = fman_port_disable(&p_FmPort->port); ++ if (err == -EBUSY) ++ { ++ DBG(WARNING, ("%s: BMI or QMI is Busy. Port forced down", ++ p_FmPort->name)); ++ } ++ else ++ if (err != 0) ++ { ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_disable")); ++ } ++ ++ p_FmPort->enabled = FALSE; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_Enable(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ int err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ /* Used by FM_PORT_Free routine as indication ++ if to disable port. Thus set it to TRUE prior ++ to enabling itself. This way if part of enable ++ process fails there will be still things ++ to disable during Free. For example, if BMI ++ enable succeeded but QMI failed, still BMI ++ needs to be disabled by Free. */ ++ p_FmPort->enabled = TRUE; ++ ++ if (p_FmPort->imEn) ++ FmPortImEnable(p_FmPort); ++ ++ err = fman_port_enable(&p_FmPort->port); ++ if (err != 0) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_enable")); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_SetRateLimit(t_Handle h_FmPort, t_FmPortRateLimit *p_RateLimit) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ uint8_t factor, countUnitBit; ++ uint16_t baseGran; ++ struct fman_port_rate_limiter params; ++ int err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ switch (p_FmPort->portType) ++ { ++ case (e_FM_PORT_TYPE_TX_10G): ++ case (e_FM_PORT_TYPE_TX): ++ baseGran = BMI_RATE_LIMIT_GRAN_TX; ++ break; ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ baseGran = BMI_RATE_LIMIT_GRAN_OP; ++ break; ++ default: ++ RETURN_ERROR( MAJOR, E_INVALID_OPERATION, ++ ("available for Tx and Offline parsing ports only")); ++ } ++ ++ countUnitBit = (uint8_t)FmGetTimeStampScale(p_FmPort->h_Fm); /* TimeStamp per nano seconds units */ ++ /* normally, we use 1 usec as the reference count */ ++ factor = 1; ++ /* if ratelimit is too small for a 1usec factor, multiply the factor */ ++ while (p_RateLimit->rateLimit < baseGran / factor) ++ { ++ if (countUnitBit == 31) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Rate limit is too small")); ++ ++ countUnitBit++; ++ factor <<= 1; ++ } ++ /* if ratelimit is too large for a 1usec factor, it is also larger than max rate*/ ++ if (p_RateLimit->rateLimit ++ > ((uint32_t)baseGran * (1 << 10) * (uint32_t)factor)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Rate limit is too large")); ++ ++ if (!p_RateLimit->maxBurstSize ++ || (p_RateLimit->maxBurstSize > BMI_RATE_LIMIT_MAX_BURST_SIZE)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("maxBurstSize must be between 1K and %dk", BMI_RATE_LIMIT_MAX_BURST_SIZE)); ++ ++ params.count_1micro_bit = (uint8_t)FmGetTimeStampScale(p_FmPort->h_Fm); ++ params.high_burst_size_gran = FALSE; ++ params.burst_size = p_RateLimit->maxBurstSize; ++ params.rate = p_RateLimit->rateLimit; ++ params.rate_factor = E_FMAN_PORT_RATE_DOWN_NONE; ++ ++ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ { ++#ifndef FM_NO_ADVANCED_RATE_LIMITER ++ ++ if ((p_FmPort->fmRevInfo.majorRev == 4) ++ || (p_FmPort->fmRevInfo.majorRev >= 6)) ++ { ++ params.high_burst_size_gran = TRUE; ++ } ++ else ++#endif /* ! FM_NO_ADVANCED_RATE_LIMITER */ ++ { ++ if (p_RateLimit->rateLimitDivider ++ != e_FM_PORT_DUAL_RATE_LIMITER_NONE) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ++ ("FM_PORT_ConfigDualRateLimitScaleDown")); ++ ++ if (p_RateLimit->maxBurstSize % 1000) ++ { ++ p_RateLimit->maxBurstSize = ++ (uint16_t)((p_RateLimit->maxBurstSize / 1000) + 1); ++ DBG(WARNING, ("rateLimit.maxBurstSize rounded up to %d", (p_RateLimit->maxBurstSize/1000+1)*1000)); ++ } ++ else ++ p_RateLimit->maxBurstSize = (uint16_t)(p_RateLimit->maxBurstSize ++ / 1000); ++ } ++ params.rate_factor = ++ (enum fman_port_rate_limiter_scale_down)p_RateLimit->rateLimitDivider; ++ params.burst_size = p_RateLimit->maxBurstSize; ++ } ++ ++ err = fman_port_set_rate_limiter(&p_FmPort->port, ¶ms); ++ if (err != 0) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_rate_limiter")); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_DeleteRateLimit(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ int err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) ++ RETURN_ERROR( MAJOR, E_INVALID_OPERATION, ++ ("available for Tx and Offline parsing ports only")); ++ ++ err = fman_port_delete_rate_limiter(&p_FmPort->port); ++ if (err != 0) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_rate_limiter")); ++ return E_OK; ++} ++ ++t_Error FM_PORT_SetPfcPrioritiesMappingToQmanWQ(t_Handle h_FmPort, uint8_t prio, ++ uint8_t wq) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ uint32_t tmpReg; ++ uint32_t wqTmpReg; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_TX) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("PFC mapping is available for Tx ports only")); ++ ++ if (prio > 7) ++ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ++ ("PFC priority (%d) is out of range (0-7)", prio)); ++ if (wq > 7) ++ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ++ ("WQ (%d) is out of range (0-7)", wq)); ++ ++ tmpReg = GET_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tpfcm[0]); ++ tmpReg &= ~(0xf << ((7 - prio) * 4)); ++ wqTmpReg = ((uint32_t)wq << ((7 - prio) * 4)); ++ tmpReg |= wqTmpReg; ++ ++ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tpfcm[0], ++ tmpReg); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_SetFrameQueueCounters(t_Handle h_FmPort, bool enable) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ fman_port_set_queue_cnt_mode(&p_FmPort->port, enable); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_SetPerformanceCounters(t_Handle h_FmPort, bool enable) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ int err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ err = fman_port_set_perf_cnt_mode(&p_FmPort->port, enable); ++ if (err != 0) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_perf_cnt_mode")); ++ return E_OK; ++} ++ ++t_Error FM_PORT_SetPerformanceCountersParams( ++ t_Handle h_FmPort, t_FmPortPerformanceCnt *p_FmPortPerformanceCnt) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ struct fman_port_perf_cnt_params params; ++ int err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ ++ /* check parameters */ ++ if (!p_FmPortPerformanceCnt->taskCompVal ++ || (p_FmPortPerformanceCnt->taskCompVal > p_FmPort->tasks.num)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("taskCompVal (%d) has to be in the range of 1 - %d (current value)!", p_FmPortPerformanceCnt->taskCompVal, p_FmPort->tasks.num)); ++ if (!p_FmPortPerformanceCnt->dmaCompVal ++ || (p_FmPortPerformanceCnt->dmaCompVal > p_FmPort->openDmas.num)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("dmaCompVal (%d) has to be in the range of 1 - %d (current value)!", p_FmPortPerformanceCnt->dmaCompVal, p_FmPort->openDmas.num)); ++ if (!p_FmPortPerformanceCnt->fifoCompVal ++ || (p_FmPortPerformanceCnt->fifoCompVal > p_FmPort->fifoBufs.num)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("fifoCompVal (%d) has to be in the range of 256 - %d (current value)!", p_FmPortPerformanceCnt->fifoCompVal, p_FmPort->fifoBufs.num)); ++ if (p_FmPortPerformanceCnt->fifoCompVal % BMI_FIFO_UNITS) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("fifoCompVal (%d) has to be divisible by %d", p_FmPortPerformanceCnt->fifoCompVal, BMI_FIFO_UNITS)); ++ ++ switch (p_FmPort->portType) ++ { ++ case (e_FM_PORT_TYPE_RX_10G): ++ case (e_FM_PORT_TYPE_RX): ++ if (!p_FmPortPerformanceCnt->queueCompVal ++ || (p_FmPortPerformanceCnt->queueCompVal ++ > MAX_PERFORMANCE_RX_QUEUE_COMP)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("performanceCnt.queueCompVal for Rx has to be in the range of 1 - %d", MAX_PERFORMANCE_RX_QUEUE_COMP)); ++ break; ++ case (e_FM_PORT_TYPE_TX_10G): ++ case (e_FM_PORT_TYPE_TX): ++ if (!p_FmPortPerformanceCnt->queueCompVal ++ || (p_FmPortPerformanceCnt->queueCompVal ++ > MAX_PERFORMANCE_TX_QUEUE_COMP)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("performanceCnt.queueCompVal for Tx has to be in the range of 1 - %d", MAX_PERFORMANCE_TX_QUEUE_COMP)); ++ break; ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ case (e_FM_PORT_TYPE_OH_HOST_COMMAND): ++ if (p_FmPortPerformanceCnt->queueCompVal) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("performanceCnt.queueCompVal is not relevant for H/O ports.")); ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); ++ } ++ ++ params.task_val = p_FmPortPerformanceCnt->taskCompVal; ++ params.queue_val = p_FmPortPerformanceCnt->queueCompVal; ++ params.dma_val = p_FmPortPerformanceCnt->dmaCompVal; ++ params.fifo_val = p_FmPortPerformanceCnt->fifoCompVal; ++ ++ err = fman_port_set_perf_cnt_params(&p_FmPort->port, ¶ms); ++ if (err != 0) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_perf_cnt_params")); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_AnalyzePerformanceParams(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_FmPortPerformanceCnt currParams, savedParams; ++ t_Error err; ++ bool underTest, failed = FALSE; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ ++ XX_Print("Analyzing Performance parameters for port (type %d, id%d)\n", ++ p_FmPort->portType, p_FmPort->portId); ++ ++ currParams.taskCompVal = (uint8_t)p_FmPort->tasks.num; ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) ++ currParams.queueCompVal = 0; ++ else ++ currParams.queueCompVal = 1; ++ currParams.dmaCompVal = (uint8_t)p_FmPort->openDmas.num; ++ currParams.fifoCompVal = p_FmPort->fifoBufs.num; ++ ++ FM_PORT_SetPerformanceCounters(p_FmPort, FALSE); ++ ClearPerfCnts(p_FmPort); ++ if ((err = FM_PORT_SetPerformanceCountersParams(p_FmPort, &currParams)) ++ != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ FM_PORT_SetPerformanceCounters(p_FmPort, TRUE); ++ XX_UDelay(1000000); ++ FM_PORT_SetPerformanceCounters(p_FmPort, FALSE); ++ if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL)) ++ { ++ XX_Print( ++ "Max num of defined port tasks (%d) utilized - Please enlarge\n", ++ p_FmPort->tasks.num); ++ failed = TRUE; ++ } ++ if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL)) ++ { ++ XX_Print( ++ "Max num of defined port openDmas (%d) utilized - Please enlarge\n", ++ p_FmPort->openDmas.num); ++ failed = TRUE; ++ } ++ if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL)) ++ { ++ XX_Print( ++ "Max size of defined port fifo (%d) utilized - Please enlarge\n", ++ p_FmPort->fifoBufs.num); ++ failed = TRUE; ++ } ++ if (failed) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ ++ memset(&savedParams, 0, sizeof(savedParams)); ++ while (TRUE) ++ { ++ underTest = FALSE; ++ if ((currParams.taskCompVal != 1) && !savedParams.taskCompVal) ++ { ++ currParams.taskCompVal--; ++ underTest = TRUE; ++ } ++ if ((currParams.dmaCompVal != 1) && !savedParams.dmaCompVal) ++ { ++ currParams.dmaCompVal--; ++ underTest = TRUE; ++ } ++ if ((currParams.fifoCompVal != BMI_FIFO_UNITS) ++ && !savedParams.fifoCompVal) ++ { ++ currParams.fifoCompVal -= BMI_FIFO_UNITS; ++ underTest = TRUE; ++ } ++ if (!underTest) ++ break; ++ ++ ClearPerfCnts(p_FmPort); ++ if ((err = FM_PORT_SetPerformanceCountersParams(p_FmPort, &currParams)) ++ != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ FM_PORT_SetPerformanceCounters(p_FmPort, TRUE); ++ XX_UDelay(1000000); ++ FM_PORT_SetPerformanceCounters(p_FmPort, FALSE); ++ ++ if (!savedParams.taskCompVal ++ && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL)) ++ savedParams.taskCompVal = (uint8_t)(currParams.taskCompVal + 2); ++ if (!savedParams.dmaCompVal ++ && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL)) ++ savedParams.dmaCompVal = (uint8_t)(currParams.dmaCompVal + 2); ++ if (!savedParams.fifoCompVal ++ && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL)) ++ savedParams.fifoCompVal = currParams.fifoCompVal ++ + (2 * BMI_FIFO_UNITS); ++ } ++ ++ XX_Print("best vals: tasks %d, dmas %d, fifos %d\n", ++ savedParams.taskCompVal, savedParams.dmaCompVal, ++ savedParams.fifoCompVal); ++ return E_OK; ++} ++ ++t_Error FM_PORT_SetStatisticsCounters(t_Handle h_FmPort, bool enable) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ int err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ err = fman_port_set_stats_cnt_mode(&p_FmPort->port, enable); ++ if (err != 0) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_stats_cnt_mode")); ++ return E_OK; ++} ++ ++t_Error FM_PORT_SetErrorsRoute(t_Handle h_FmPort, fmPortFrameErrSelect_t errs) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ volatile uint32_t *p_ErrDiscard = NULL; ++ int err; ++ ++ UNUSED(p_ErrDiscard); ++ err = fman_port_set_err_mask(&p_FmPort->port, (uint32_t)errs); ++ if (err != 0) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_err_mask")); ++ ++#ifdef FM_ERROR_VSP_NO_MATCH_SW006 ++ if (p_FmPort->fmRevInfo.majorRev >= 6) ++ { ++ t_FmPcdCtrlParamsPage *p_ParamsPage; ++ ++ FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE, ++ (void**)&p_ParamsPage); ++ ASSERT_COND(p_ParamsPage); ++ switch (p_FmPort->portType) ++ { ++ case (e_FM_PORT_TYPE_RX_10G): ++ case (e_FM_PORT_TYPE_RX): ++ p_ErrDiscard = ++ &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm; ++ break; ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ p_ErrDiscard = ++ &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm; ++ break; ++ default: ++ RETURN_ERROR( ++ MAJOR, E_INVALID_OPERATION, ++ ("available for Rx and offline parsing ports only")); ++ } ++ WRITE_UINT32(p_ParamsPage->errorsDiscardMask, ++ GET_UINT32(*p_ErrDiscard) | errs); ++ } ++#endif /* FM_ERROR_VSP_NO_MATCH_SW006 */ ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_SetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId, ++ bool enable) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ int err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(poolIdp_FmPortDriverParam, E_INVALID_STATE); ++ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for Rx ports only")); ++ ++ err = fman_port_set_bpool_cnt_mode(&p_FmPort->port, poolId, enable); ++ if (err != 0) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_bpool_cnt_mode")); ++ return E_OK; ++} ++ ++t_Error FM_PORT_GetBmiCounters(t_Handle h_FmPort, t_FmPortBmiStats *p_BmiStats) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)){ ++ p_BmiStats->cntCycle = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_CYCLE); ++ /* fmbm_rccn */ ++ p_BmiStats->cntTaskUtil = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL); ++ /* fmbm_rtuc */ ++ p_BmiStats->cntQueueUtil = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_QUEUE_UTIL); ++ /* fmbm_rrquc */ ++ p_BmiStats->cntDmaUtil = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL); ++ /* fmbm_rduc */ ++ p_BmiStats->cntFifoUtil = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL); ++ /* fmbm_rfuc */ ++ p_BmiStats->cntRxPauseActivation = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION); ++ /* fmbm_rpac */ ++ p_BmiStats->cntFrame = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FRAME); ++ /* fmbm_rfrc */ ++ p_BmiStats->cntDiscardFrame = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DISCARD_FRAME); ++ /* fmbm_rfdc */ ++ p_BmiStats->cntDeallocBuf = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DEALLOC_BUF); ++ /* fmbm_rbdc */ ++ p_BmiStats->cntRxBadFrame = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_BAD_FRAME); ++ /* fmbm_rfbc */ ++ p_BmiStats->cntRxLargeFrame = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_LARGE_FRAME); ++ /* fmbm_rlfc */ ++ p_BmiStats->cntRxFilterFrame = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_FILTER_FRAME); ++ /* fmbm_rffc */ ++ p_BmiStats->cntRxListDmaErr = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR); ++ /* fmbm_rfldec */ ++ p_BmiStats->cntRxOutOfBuffersDiscard = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD); ++ /* fmbm_rodc */ ++ p_BmiStats->cntWredDiscard = 0; ++ p_BmiStats->cntLengthErr = 0; ++ p_BmiStats->cntUnsupportedFormat = 0; ++ } ++ else if ((p_FmPort->portType == e_FM_PORT_TYPE_TX) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)){ ++ p_BmiStats->cntCycle = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_CYCLE); ++ /* fmbm_tccn */ ++ p_BmiStats->cntTaskUtil = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL); ++ /* fmbm_ttuc */ ++ p_BmiStats->cntQueueUtil = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_QUEUE_UTIL); ++ /* fmbm_ttcquc */ ++ p_BmiStats->cntDmaUtil = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL); ++ /* fmbm_tduc */ ++ p_BmiStats->cntFifoUtil = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL); ++ /* fmbm_tfuc */ ++ p_BmiStats->cntRxPauseActivation = 0; ++ p_BmiStats->cntFrame = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FRAME); ++ /* fmbm_tfrc */ ++ p_BmiStats->cntDiscardFrame = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DISCARD_FRAME); ++ /* fmbm_tfdc */ ++ p_BmiStats->cntDeallocBuf = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DEALLOC_BUF); ++ /* fmbm_tbdc */ ++ p_BmiStats->cntRxBadFrame = 0; ++ p_BmiStats->cntRxLargeFrame = 0; ++ p_BmiStats->cntRxFilterFrame = 0; ++ p_BmiStats->cntRxListDmaErr = 0; ++ p_BmiStats->cntRxOutOfBuffersDiscard = 0; ++ p_BmiStats->cntWredDiscard = 0; ++ p_BmiStats->cntLengthErr = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_LENGTH_ERR); ++ /* fmbm_tfledc */ ++ p_BmiStats->cntUnsupportedFormat = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT); ++ /* fmbm_tfufdc */ ++ } ++ else if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) { ++ p_BmiStats->cntCycle = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_CYCLE); ++ /* fmbm_occn */ ++ p_BmiStats->cntTaskUtil = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL); ++ /* fmbm_otuc */ ++ p_BmiStats->cntQueueUtil = 0; ++ p_BmiStats->cntDmaUtil = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL); ++ /* fmbm_oduc */ ++ p_BmiStats->cntFifoUtil = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL); ++ /* fmbm_ofuc*/ ++ p_BmiStats->cntRxPauseActivation = 0; ++ p_BmiStats->cntFrame = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FRAME); ++ /* fmbm_ofrc */ ++ p_BmiStats->cntDiscardFrame = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DISCARD_FRAME); ++ /* fmbm_ofdc */ ++ p_BmiStats->cntDeallocBuf = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DEALLOC_BUF); ++ /* fmbm_obdc*/ ++ p_BmiStats->cntRxBadFrame = 0; ++ p_BmiStats->cntRxLargeFrame = 0; ++ p_BmiStats->cntRxFilterFrame = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_FILTER_FRAME); ++ /* fmbm_offc */ ++ p_BmiStats->cntRxListDmaErr = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR); ++ /* fmbm_ofldec */ ++ p_BmiStats->cntRxOutOfBuffersDiscard = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD); ++ /* fmbm_rodc */ ++ p_BmiStats->cntWredDiscard = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_WRED_DISCARD); ++ /* fmbm_ofwdc */ ++ p_BmiStats->cntLengthErr = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_LENGTH_ERR); ++ /* fmbm_ofledc */ ++ p_BmiStats->cntUnsupportedFormat = ++ FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT); ++ /* fmbm_ofufdc */ ++ } ++ return E_OK; ++} ++ ++uint32_t FM_PORT_GetCounter(t_Handle h_FmPort, e_FmPortCounters counter) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ bool bmiCounter = FALSE; ++ enum fman_port_stats_counters statsType; ++ enum fman_port_perf_counters perfType; ++ enum fman_port_qmi_counters queueType; ++ bool isStats; ++ t_Error errCode; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ switch (counter) ++ { ++ case (e_FM_PORT_COUNTERS_DEQ_TOTAL): ++ case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT): ++ case (e_FM_PORT_COUNTERS_DEQ_CONFIRM): ++ /* check that counter is available for the port type */ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) ++ { ++ REPORT_ERROR(MINOR, E_INVALID_STATE, ++ ("Requested counter is not available for Rx ports")); ++ return 0; ++ } ++ bmiCounter = FALSE; ++ break; ++ case (e_FM_PORT_COUNTERS_ENQ_TOTAL): ++ bmiCounter = FALSE; ++ break; ++ default: /* BMI counters (or error - will be checked in BMI routine )*/ ++ bmiCounter = TRUE; ++ break; ++ } ++ ++ if (bmiCounter) ++ { ++ errCode = BmiPortCheckAndGetCounterType(p_FmPort, counter, &statsType, ++ &perfType, &isStats); ++ if (errCode != E_OK) ++ { ++ REPORT_ERROR(MINOR, errCode, NO_MSG); ++ return 0; ++ } ++ if (isStats) ++ return fman_port_get_stats_counter(&p_FmPort->port, statsType); ++ else ++ return fman_port_get_perf_counter(&p_FmPort->port, perfType); ++ } ++ else /* QMI counter */ ++ { ++ /* check that counters are enabled */ ++ if (!(GET_UINT32(p_FmPort->port.qmi_regs->fmqm_pnc) ++ & QMI_PORT_CFG_EN_COUNTERS)) ++ ++ { ++ REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled")); ++ return 0; ++ } ++ ++ /* Set counter */ ++ switch (counter) ++ { ++ case (e_FM_PORT_COUNTERS_ENQ_TOTAL): ++ queueType = E_FMAN_PORT_ENQ_TOTAL; ++ break; ++ case (e_FM_PORT_COUNTERS_DEQ_TOTAL): ++ queueType = E_FMAN_PORT_DEQ_TOTAL; ++ break; ++ case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT): ++ queueType = E_FMAN_PORT_DEQ_FROM_DFLT; ++ break; ++ case (e_FM_PORT_COUNTERS_DEQ_CONFIRM): ++ queueType = E_FMAN_PORT_DEQ_CONFIRM; ++ break; ++ default: ++ REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available")); ++ return 0; ++ } ++ ++ return fman_port_get_qmi_counter(&p_FmPort->port, queueType); ++ } ++ ++ return 0; ++} ++ ++t_Error FM_PORT_ModifyCounter(t_Handle h_FmPort, e_FmPortCounters counter, ++ uint32_t value) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ bool bmiCounter = FALSE; ++ enum fman_port_stats_counters statsType; ++ enum fman_port_perf_counters perfType; ++ enum fman_port_qmi_counters queueType; ++ bool isStats; ++ t_Error errCode; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ switch (counter) ++ { ++ case (e_FM_PORT_COUNTERS_DEQ_TOTAL): ++ case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT): ++ case (e_FM_PORT_COUNTERS_DEQ_CONFIRM): ++ /* check that counter is available for the port type */ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) ++ || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) ++ RETURN_ERROR( ++ MINOR, E_INVALID_STATE, ++ ("Requested counter is not available for Rx ports")); ++ case (e_FM_PORT_COUNTERS_ENQ_TOTAL): ++ bmiCounter = FALSE; ++ break; ++ default: /* BMI counters (or error - will be checked in BMI routine )*/ ++ bmiCounter = TRUE; ++ break; ++ } ++ ++ if (bmiCounter) ++ { ++ errCode = BmiPortCheckAndGetCounterType(p_FmPort, counter, &statsType, ++ &perfType, &isStats); ++ if (errCode != E_OK) ++ { ++ RETURN_ERROR(MINOR, errCode, NO_MSG); ++ } ++ if (isStats) ++ fman_port_set_stats_counter(&p_FmPort->port, statsType, value); ++ else ++ fman_port_set_perf_counter(&p_FmPort->port, perfType, value); ++ } ++ else /* QMI counter */ ++ { ++ /* check that counters are enabled */ ++ if (!(GET_UINT32(p_FmPort->port.qmi_regs->fmqm_pnc) ++ & QMI_PORT_CFG_EN_COUNTERS)) ++ { ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ++ ("Requested counter was not enabled")); ++ } ++ ++ /* Set counter */ ++ switch (counter) ++ { ++ case (e_FM_PORT_COUNTERS_ENQ_TOTAL): ++ queueType = E_FMAN_PORT_ENQ_TOTAL; ++ break; ++ case (e_FM_PORT_COUNTERS_DEQ_TOTAL): ++ queueType = E_FMAN_PORT_DEQ_TOTAL; ++ break; ++ case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT): ++ queueType = E_FMAN_PORT_DEQ_FROM_DFLT; ++ break; ++ case (e_FM_PORT_COUNTERS_DEQ_CONFIRM): ++ queueType = E_FMAN_PORT_DEQ_CONFIRM; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("Requested counter is not available")); ++ } ++ ++ fman_port_set_qmi_counter(&p_FmPort->port, queueType, value); ++ } ++ ++ return E_OK; ++} ++ ++uint32_t FM_PORT_GetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX) ++ && (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) ++ { ++ REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available for non-Rx ports")); ++ return 0; ++ } ++ return fman_port_get_bpool_counter(&p_FmPort->port, poolId); ++} ++ ++t_Error FM_PORT_ModifyAllocBufCounter(t_Handle h_FmPort, uint8_t poolId, ++ uint32_t value) ++{ ++ t_FmPort *p_FmPort = (t_FmPort *)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX) ++ && (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) ++ RETURN_ERROR( MINOR, E_INVALID_STATE, ++ ("Requested counter is not available for non-Rx ports")); ++ ++ fman_port_set_bpool_counter(&p_FmPort->port, poolId, value); ++ return E_OK; ++} ++bool FM_PORT_IsStalled(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_Error err; ++ bool isStalled; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, FALSE); ++ SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, ++ FALSE); ++ ++ err = FmIsPortStalled(p_FmPort->h_Fm, p_FmPort->hardwarePortId, &isStalled); ++ if (err != E_OK) ++ { ++ REPORT_ERROR(MAJOR, err, NO_MSG); ++ return TRUE; ++ } ++ return isStalled; ++} ++ ++t_Error FM_PORT_ReleaseStalled(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ return FmResumeStalledPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId); ++} ++ ++t_Error FM_PORT_SetRxL4ChecksumVerify(t_Handle h_FmPort, bool l4Checksum) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ int err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for Rx ports only")); ++ ++ if (l4Checksum) ++ err = fman_port_modify_rx_fd_bits( ++ &p_FmPort->port, (uint8_t)(BMI_PORT_RFNE_FRWD_DCL4C >> 24), ++ TRUE); ++ else ++ err = fman_port_modify_rx_fd_bits( ++ &p_FmPort->port, (uint8_t)(BMI_PORT_RFNE_FRWD_DCL4C >> 24), ++ FALSE); ++ if (err != 0) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_modify_rx_fd_bits")); ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++/* API Run-time PCD Control unit functions */ ++/*****************************************************************************/ ++ ++#if (DPAA_VERSION >= 11) ++t_Error FM_PORT_VSPAlloc(t_Handle h_FmPort, t_FmPortVSPAllocParams *p_VSPParams) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_Error err = E_OK; ++ volatile uint32_t *p_BmiStorageProfileId = NULL, *p_BmiVspe = NULL; ++ uint32_t tmpReg = 0, tmp = 0; ++ uint16_t hwStoragePrflId; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->h_Fm, E_INVALID_HANDLE); ++ /*for numOfProfiles = 0 don't call this function*/ ++ SANITY_CHECK_RETURN_ERROR(p_VSPParams->numOfProfiles, E_INVALID_VALUE); ++ /*dfltRelativeId should be in the range of numOfProfiles*/ ++ SANITY_CHECK_RETURN_ERROR( ++ p_VSPParams->dfltRelativeId < p_VSPParams->numOfProfiles, ++ E_INVALID_VALUE); ++ /*p_FmPort should be from Rx type or OP*/ ++ SANITY_CHECK_RETURN_ERROR( ++ ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) || (p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)), ++ E_INVALID_VALUE); ++ /*port should be disabled*/ ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->enabled, E_INVALID_STATE); ++ /*if its called for Rx port relevant Tx Port should be passed (initialized) too and it should be disabled*/ ++ SANITY_CHECK_RETURN_ERROR( ++ ((p_VSPParams->h_FmTxPort && !((t_FmPort *)(p_VSPParams->h_FmTxPort))->enabled) || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)), ++ E_INVALID_VALUE); ++ /*should be called before SetPCD - this port should be without PCD*/ ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->pcdEngines, E_INVALID_STATE); ++ ++ /*alloc window of VSPs for this port*/ ++ err = FmVSPAllocForPort(p_FmPort->h_Fm, p_FmPort->portType, ++ p_FmPort->portId, p_VSPParams->numOfProfiles); ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ /*get absolute VSP ID for dfltRelative*/ ++ err = FmVSPGetAbsoluteProfileId(p_FmPort->h_Fm, p_FmPort->portType, ++ p_FmPort->portId, ++ p_VSPParams->dfltRelativeId, ++ &hwStoragePrflId); ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ /*fill relevant registers for p_FmPort and relative TxPort in the case p_FmPort from Rx type*/ ++ switch (p_FmPort->portType) ++ { ++ case (e_FM_PORT_TYPE_RX_10G): ++ case (e_FM_PORT_TYPE_RX): ++ p_BmiStorageProfileId = ++ &(((t_FmPort *)(p_VSPParams->h_FmTxPort))->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfqid); ++ p_BmiVspe = ++ &(((t_FmPort *)(p_VSPParams->h_FmTxPort))->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfne); ++ ++ tmpReg = GET_UINT32(*p_BmiStorageProfileId) & ~BMI_SP_ID_MASK; ++ tmpReg |= (uint32_t)hwStoragePrflId << BMI_SP_ID_SHIFT; ++ WRITE_UINT32(*p_BmiStorageProfileId, tmpReg); ++ ++ tmpReg = GET_UINT32(*p_BmiVspe); ++ WRITE_UINT32(*p_BmiVspe, tmpReg | BMI_SP_EN); ++ ++ p_BmiStorageProfileId = ++ &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfqid; ++ p_BmiVspe = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rpp; ++ hwStoragePrflId = p_VSPParams->dfltRelativeId; ++ break; ++ ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ tmpReg = NIA_ENG_BMI | NIA_BMI_AC_FETCH_ALL_FRAME; ++ WRITE_UINT32( p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndn, ++ tmpReg); ++ ++ p_BmiStorageProfileId = ++ &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofqid; ++ p_BmiVspe = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_opp; ++ tmp |= BMI_EBD_EN; ++ break; ++ ++ default: ++ RETURN_ERROR( MAJOR, E_INVALID_OPERATION, ++ ("available for Rx and offline parsing ports only")); ++ } ++ ++ p_FmPort->vspe = TRUE; ++ p_FmPort->dfltRelativeId = p_VSPParams->dfltRelativeId; ++ ++ tmpReg = GET_UINT32(*p_BmiStorageProfileId) & ~BMI_SP_ID_MASK; ++ tmpReg |= (uint32_t)hwStoragePrflId << BMI_SP_ID_SHIFT; ++ WRITE_UINT32(*p_BmiStorageProfileId, tmpReg); ++ ++ tmpReg = GET_UINT32(*p_BmiVspe); ++ WRITE_UINT32(*p_BmiVspe, tmpReg | BMI_SP_EN | tmp); ++ return E_OK; ++} ++#endif /* (DPAA_VERSION >= 11) */ ++ ++t_Error FM_PORT_PcdPlcrAllocProfiles(t_Handle h_FmPort, uint16_t numOfProfiles) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_Error err = E_OK; ++ ++ p_FmPort->h_FmPcd = FmGetPcdHandle(p_FmPort->h_Fm); ++ ASSERT_COND(p_FmPort->h_FmPcd); ++ ++ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) ++ { ++ DBG(TRACE, ("FM Port Try Lock - BUSY")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ if (numOfProfiles) ++ { ++ err = FmPcdPlcrAllocProfiles(p_FmPort->h_FmPcd, ++ p_FmPort->hardwarePortId, numOfProfiles); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ /* set the port handle within the PCD policer, even if no profiles defined */ ++ FmPcdPortRegister(p_FmPort->h_FmPcd, h_FmPort, p_FmPort->hardwarePortId); ++ ++ RELEASE_LOCK(p_FmPort->lock); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_PcdPlcrFreeProfiles(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_Error err = E_OK; ++ ++ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) ++ { ++ DBG(TRACE, ("FM Port Try Lock - BUSY")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = FmPcdPlcrFreeProfiles(p_FmPort->h_FmPcd, p_FmPort->hardwarePortId); ++ ++ RELEASE_LOCK(p_FmPort->lock); ++ ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_PcdKgModifyInitialScheme(t_Handle h_FmPort, ++ t_FmPcdKgSchemeSelect *p_FmPcdKgScheme) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ volatile uint32_t *p_BmiHpnia = NULL; ++ uint32_t tmpReg; ++ uint8_t relativeSchemeId; ++ uint8_t physicalSchemeId; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG, ++ E_INVALID_STATE); ++ ++ tmpReg = (uint32_t)((p_FmPort->pcdEngines & FM_PCD_CC) ? NIA_KG_CC_EN : 0); ++ switch (p_FmPort->portType) ++ { ++ case (e_FM_PORT_TYPE_RX_10G): ++ case (e_FM_PORT_TYPE_RX): ++ p_BmiHpnia = &p_FmPort->port.bmi_regs->rx.fmbm_rfpne; ++ break; ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ p_BmiHpnia = &p_FmPort->port.bmi_regs->oh.fmbm_ofpne; ++ break; ++ default: ++ RETURN_ERROR( MAJOR, E_INVALID_OPERATION, ++ ("available for Rx and offline parsing ports only")); ++ } ++ ++ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) ++ { ++ DBG(TRACE, ("FM Port Try Lock - BUSY")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ /* if we want to change to direct scheme, we need to check that this scheme is valid */ ++ if (p_FmPcdKgScheme->direct) ++ { ++ physicalSchemeId = FmPcdKgGetSchemeId(p_FmPcdKgScheme->h_DirectScheme); ++ /* check that this scheme is bound to this port */ ++ if (!(p_FmPort->schemesPerPortVector ++ & (uint32_t)(1 << (31 - (uint32_t)physicalSchemeId)))) ++ { ++ RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR( ++ MAJOR, E_INVALID_STATE, ++ ("called with a scheme that is not bound to this port")); ++ } ++ ++ relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPort->h_FmPcd, ++ physicalSchemeId); ++ if (relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES) ++ { ++ RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ++ ("called with invalid Scheme ")); ++ } ++ ++ if (!FmPcdKgIsSchemeValidSw(p_FmPcdKgScheme->h_DirectScheme)) ++ { ++ RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("called with uninitialized Scheme ")); ++ } ++ ++ WRITE_UINT32( ++ *p_BmiHpnia, ++ NIA_ENG_KG | tmpReg | NIA_KG_DIRECT | (uint32_t)physicalSchemeId); ++ } ++ else ++ /* change to indirect scheme */ ++ WRITE_UINT32(*p_BmiHpnia, NIA_ENG_KG | tmpReg); ++ RELEASE_LOCK(p_FmPort->lock); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_PcdPlcrModifyInitialProfile(t_Handle h_FmPort, ++ t_Handle h_Profile) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ volatile uint32_t *p_BmiNia; ++ volatile uint32_t *p_BmiHpnia; ++ uint32_t tmpReg; ++ uint16_t absoluteProfileId = FmPcdPlcrProfileGetAbsoluteId(h_Profile); ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_PLCR, ++ E_INVALID_STATE); ++ ++ /* check relevance of this routine - only when policer is used ++ directly after BMI or Parser */ ++ if ((p_FmPort->pcdEngines & FM_PCD_KG) ++ || (p_FmPort->pcdEngines & FM_PCD_CC)) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("relevant only when PCD support mode is e_FM_PCD_SUPPORT_PLCR_ONLY or e_FM_PCD_SUPPORT_PRS_AND_PLCR")); ++ ++ switch (p_FmPort->portType) ++ { ++ case (e_FM_PORT_TYPE_RX_10G): ++ case (e_FM_PORT_TYPE_RX): ++ p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; ++ p_BmiHpnia = &p_FmPort->port.bmi_regs->rx.fmbm_rfpne; ++ tmpReg = GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK; ++ break; ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; ++ p_BmiHpnia = &p_FmPort->port.bmi_regs->oh.fmbm_ofpne; ++ tmpReg = 0; ++ break; ++ default: ++ RETURN_ERROR( MAJOR, E_INVALID_OPERATION, ++ ("available for Rx and offline parsing ports only")); ++ } ++ ++ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) ++ { ++ DBG(TRACE, ("FM Port Try Lock - BUSY")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ if (!FmPcdPlcrIsProfileValid(p_FmPort->h_FmPcd, absoluteProfileId)) ++ { ++ RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Invalid profile")); ++ } ++ ++ tmpReg |= (uint32_t)(NIA_ENG_PLCR | NIA_PLCR_ABSOLUTE | absoluteProfileId); ++ ++ if (p_FmPort->pcdEngines & FM_PCD_PRS) /* e_FM_PCD_SUPPORT_PRS_AND_PLCR */ ++ { ++ /* update BMI HPNIA */ ++ WRITE_UINT32(*p_BmiHpnia, tmpReg); ++ } ++ else /* e_FM_PCD_SUPPORT_PLCR_ONLY */ ++ { ++ /* rfne may contain FDCS bits, so first we read them. */ ++ tmpReg |= (GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK); ++ /* update BMI NIA */ ++ WRITE_UINT32(*p_BmiNia, tmpReg); ++ }RELEASE_LOCK(p_FmPort->lock); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_PcdCcModifyTree(t_Handle h_FmPort, t_Handle h_CcTree) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_Error err = E_OK; ++ volatile uint32_t *p_BmiCcBase = NULL; ++ volatile uint32_t *p_BmiNia = NULL; ++ uint32_t ccTreePhysOffset; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(h_CcTree, E_INVALID_HANDLE); ++ ++ if (p_FmPort->imEn) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for non-independent mode ports only")); ++ ++ /* get PCD registers pointers */ ++ switch (p_FmPort->portType) ++ { ++ case (e_FM_PORT_TYPE_RX_10G): ++ case (e_FM_PORT_TYPE_RX): ++ p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; ++ break; ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; ++ break; ++ default: ++ RETURN_ERROR( MAJOR, E_INVALID_OPERATION, ++ ("available for Rx and offline parsing ports only")); ++ } ++ ++ /* check that current NIA is BMI to BMI */ ++ if ((GET_UINT32(*p_BmiNia) & ~BMI_RFNE_FDCS_MASK) ++ != GET_NIA_BMI_AC_ENQ_FRAME(p_FmPort->h_FmPcd)) ++ RETURN_ERROR( MAJOR, E_INVALID_OPERATION, ++ ("may be called only for ports in BMI-to-BMI state.")); ++ ++ if (p_FmPort->pcdEngines & FM_PCD_CC) ++ { ++ if (p_FmPort->h_IpReassemblyManip) ++ { ++ err = FmPcdCcTreeAddIPR(p_FmPort->h_FmPcd, h_CcTree, NULL, ++ p_FmPort->h_IpReassemblyManip, FALSE); ++ if (err != E_OK) ++ { ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ } ++ else ++ if (p_FmPort->h_CapwapReassemblyManip) ++ { ++ err = FmPcdCcTreeAddCPR(p_FmPort->h_FmPcd, h_CcTree, NULL, ++ p_FmPort->h_CapwapReassemblyManip, ++ FALSE); ++ if (err != E_OK) ++ { ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ } ++ switch (p_FmPort->portType) ++ { ++ case (e_FM_PORT_TYPE_RX_10G): ++ case (e_FM_PORT_TYPE_RX): ++ p_BmiCcBase = &p_FmPort->port.bmi_regs->rx.fmbm_rccb; ++ break; ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ p_BmiCcBase = &p_FmPort->port.bmi_regs->oh.fmbm_occb; ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); ++ } ++ ++ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) ++ { ++ DBG(TRACE, ("FM Port Try Lock - BUSY")); ++ return ERROR_CODE(E_BUSY); ++ } ++ err = FmPcdCcBindTree(p_FmPort->h_FmPcd, NULL, h_CcTree, ++ &ccTreePhysOffset, h_FmPort); ++ if (err) ++ { ++ RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ }WRITE_UINT32(*p_BmiCcBase, ccTreePhysOffset); ++ ++ p_FmPort->ccTreeId = h_CcTree; ++ RELEASE_LOCK(p_FmPort->lock); ++ } ++ else ++ RETURN_ERROR( MAJOR, E_INVALID_STATE, ++ ("Coarse Classification not defined for this port.")); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_AttachPCD(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ if (p_FmPort->imEn) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for non-independent mode ports only")); ++ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ++ RETURN_ERROR( MAJOR, E_INVALID_OPERATION, ++ ("available for Rx and offline parsing ports only")); ++ ++ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) ++ { ++ DBG(TRACE, ("FM Port Try Lock - BUSY")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ if (p_FmPort->h_ReassemblyTree) ++ p_FmPort->pcdEngines |= FM_PCD_CC; ++ ++ err = AttachPCD(h_FmPort); ++ RELEASE_LOCK(p_FmPort->lock); ++ ++ return err; ++} ++ ++t_Error FM_PORT_DetachPCD(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ if (p_FmPort->imEn) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for non-independent mode ports only")); ++ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ++ RETURN_ERROR( MAJOR, E_INVALID_OPERATION, ++ ("available for Rx and offline parsing ports only")); ++ ++ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) ++ { ++ DBG(TRACE, ("FM Port Try Lock - BUSY")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = DetachPCD(h_FmPort); ++ if (err != E_OK) ++ { ++ RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ if (p_FmPort->h_ReassemblyTree) ++ p_FmPort->pcdEngines &= ~FM_PCD_CC; ++ RELEASE_LOCK(p_FmPort->lock); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_SetPCD(t_Handle h_FmPort, t_FmPortPcdParams *p_PcdParam) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_Error err = E_OK; ++ t_FmPortPcdParams modifiedPcdParams, *p_PcdParams; ++ t_FmPcdCcTreeParams *p_FmPcdCcTreeParams; ++ t_FmPortPcdCcParams fmPortPcdCcParams; ++ t_FmPortGetSetCcParams fmPortGetSetCcParams; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_PcdParam, E_NULL_POINTER); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ if (p_FmPort->imEn) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for non-independent mode ports only")); ++ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ++ RETURN_ERROR( MAJOR, E_INVALID_OPERATION, ++ ("available for Rx and offline parsing ports only")); ++ ++ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) ++ { ++ DBG(TRACE, ("FM Port Try Lock - BUSY")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ p_FmPort->h_FmPcd = FmGetPcdHandle(p_FmPort->h_Fm); ++ ASSERT_COND(p_FmPort->h_FmPcd); ++ ++ if (p_PcdParam->p_CcParams && !p_PcdParam->p_CcParams->h_CcTree) ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ++ ("Tree handle must be given if CC is required")); ++ ++ memcpy(&modifiedPcdParams, p_PcdParam, sizeof(t_FmPortPcdParams)); ++ p_PcdParams = &modifiedPcdParams; ++ if ((p_PcdParams->h_IpReassemblyManip) ++#if (DPAA_VERSION >= 11) ++ || (p_PcdParams->h_CapwapReassemblyManip) ++#endif /* (DPAA_VERSION >= 11) */ ++ ) ++ { ++ if ((p_PcdParams->pcdSupport != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG) ++ && (p_PcdParams->pcdSupport ++ != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC) ++ && (p_PcdParams->pcdSupport ++ != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR) ++ && (p_PcdParams->pcdSupport ++ != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR)) ++ { ++ RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR( MAJOR, E_INVALID_STATE, ++ ("pcdSupport must have KG for supporting Reassembly")); ++ } ++ p_FmPort->h_IpReassemblyManip = p_PcdParams->h_IpReassemblyManip; ++#if (DPAA_VERSION >= 11) ++ if ((p_PcdParams->h_IpReassemblyManip) ++ && (p_PcdParams->h_CapwapReassemblyManip)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("Either IP-R or CAPWAP-R is allowed")); ++ if ((p_PcdParams->h_CapwapReassemblyManip) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("CAPWAP-R is allowed only on offline-port")); ++ if (p_PcdParams->h_CapwapReassemblyManip) ++ p_FmPort->h_CapwapReassemblyManip = ++ p_PcdParams->h_CapwapReassemblyManip; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ if (!p_PcdParams->p_CcParams) ++ { ++ if (!((p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_PRS_AND_KG) ++ || (p_PcdParams->pcdSupport ++ == e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR))) ++ { ++ RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_STATE, ++ ("PCD initialization structure is not consistent with pcdSupport")); ++ } ++ ++ /* No user-tree, need to build internal tree */ ++ p_FmPcdCcTreeParams = (t_FmPcdCcTreeParams*)XX_Malloc( ++ sizeof(t_FmPcdCcTreeParams)); ++ if (!p_FmPcdCcTreeParams) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_FmPcdCcTreeParams")); ++ memset(p_FmPcdCcTreeParams, 0, sizeof(t_FmPcdCcTreeParams)); ++ p_FmPcdCcTreeParams->h_NetEnv = p_PcdParams->h_NetEnv; ++ p_FmPort->h_ReassemblyTree = FM_PCD_CcRootBuild( ++ p_FmPort->h_FmPcd, p_FmPcdCcTreeParams); ++ ++ if (!p_FmPort->h_ReassemblyTree) ++ { ++ RELEASE_LOCK(p_FmPort->lock); ++ XX_Free(p_FmPcdCcTreeParams); ++ RETURN_ERROR( MAJOR, E_INVALID_HANDLE, ++ ("FM_PCD_CcBuildTree for Reassembly failed")); ++ } ++ if (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_PRS_AND_KG) ++ p_PcdParams->pcdSupport = ++ e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC; ++ else ++ p_PcdParams->pcdSupport = ++ e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR; ++ ++ memset(&fmPortPcdCcParams, 0, sizeof(t_FmPortPcdCcParams)); ++ fmPortPcdCcParams.h_CcTree = p_FmPort->h_ReassemblyTree; ++ p_PcdParams->p_CcParams = &fmPortPcdCcParams; ++ XX_Free(p_FmPcdCcTreeParams); ++ } ++ ++ if (p_FmPort->h_IpReassemblyManip) ++ err = FmPcdCcTreeAddIPR(p_FmPort->h_FmPcd, ++ p_PcdParams->p_CcParams->h_CcTree, ++ p_PcdParams->h_NetEnv, ++ p_FmPort->h_IpReassemblyManip, TRUE); ++#if (DPAA_VERSION >= 11) ++ else ++ if (p_FmPort->h_CapwapReassemblyManip) ++ err = FmPcdCcTreeAddCPR(p_FmPort->h_FmPcd, ++ p_PcdParams->p_CcParams->h_CcTree, ++ p_PcdParams->h_NetEnv, ++ p_FmPort->h_CapwapReassemblyManip, ++ TRUE); ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ if (err != E_OK) ++ { ++ if (p_FmPort->h_ReassemblyTree) ++ { ++ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); ++ p_FmPort->h_ReassemblyTree = NULL; ++ }RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ } ++ ++ if (!FmPcdLockTryLockAll(p_FmPort->h_FmPcd)) ++ { ++ if (p_FmPort->h_ReassemblyTree) ++ { ++ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); ++ p_FmPort->h_ReassemblyTree = NULL; ++ }RELEASE_LOCK(p_FmPort->lock); ++ DBG(TRACE, ("Try LockAll - BUSY")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = SetPcd(h_FmPort, p_PcdParams); ++ if (err) ++ { ++ if (p_FmPort->h_ReassemblyTree) ++ { ++ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); ++ p_FmPort->h_ReassemblyTree = NULL; ++ } ++ FmPcdLockUnlockAll(p_FmPort->h_FmPcd); ++ RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ if ((p_FmPort->pcdEngines & FM_PCD_PRS) ++ && (p_PcdParams->p_PrsParams->includeInPrsStatistics)) ++ { ++ err = FmPcdPrsIncludePortInStatistics(p_FmPort->h_FmPcd, ++ p_FmPort->hardwarePortId, TRUE); ++ if (err) ++ { ++ DeletePcd(p_FmPort); ++ if (p_FmPort->h_ReassemblyTree) ++ { ++ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); ++ p_FmPort->h_ReassemblyTree = NULL; ++ } ++ FmPcdLockUnlockAll(p_FmPort->h_FmPcd); ++ RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ p_FmPort->includeInPrsStatistics = TRUE; ++ } ++ ++ FmPcdIncNetEnvOwners(p_FmPort->h_FmPcd, p_FmPort->netEnvId); ++ ++ if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)) ++ { ++ memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams)); ++ ++ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ { ++#ifdef FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004 ++ if ((p_FmPort->fmRevInfo.majorRev < 6) && ++ (p_FmPort->pcdEngines & FM_PCD_KG)) ++ { ++ int i; ++ for (i = 0; ip_KgParams->numOfSchemes; i++) ++ /* The following function must be locked */ ++ FmPcdKgCcGetSetParams(p_FmPort->h_FmPcd, ++ p_PcdParams->p_KgParams->h_Schemes[i], ++ UPDATE_KG_NIA_CC_WA, ++ 0); ++ } ++#endif /* FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004 */ ++ ++#if (DPAA_VERSION >= 11) ++ { ++ t_FmPcdCtrlParamsPage *p_ParamsPage; ++ ++ FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE, ++ (void**)&p_ParamsPage); ++ ASSERT_COND(p_ParamsPage); ++ WRITE_UINT32(p_ParamsPage->postBmiFetchNia, ++ p_FmPort->savedBmiNia); ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ /* Set post-bmi-fetch nia */ ++ p_FmPort->savedBmiNia &= BMI_RFNE_FDCS_MASK; ++ p_FmPort->savedBmiNia |= (NIA_FM_CTL_AC_POST_BMI_FETCH ++ | NIA_ENG_FM_CTL); ++ ++ /* Set pre-bmi-fetch nia */ ++ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNDN; ++#if (DPAA_VERSION >= 11) ++ fmPortGetSetCcParams.setCcParams.nia = ++ (NIA_FM_CTL_AC_PRE_BMI_FETCH_FULL_FRAME | NIA_ENG_FM_CTL); ++#else ++ fmPortGetSetCcParams.setCcParams.nia = (NIA_FM_CTL_AC_PRE_BMI_FETCH_HEADER | NIA_ENG_FM_CTL); ++#endif /* (DPAA_VERSION >= 11) */ ++ if ((err = FmPortGetSetCcParams(p_FmPort, &fmPortGetSetCcParams)) ++ != E_OK) ++ { ++ DeletePcd(p_FmPort); ++ if (p_FmPort->h_ReassemblyTree) ++ { ++ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); ++ p_FmPort->h_ReassemblyTree = NULL; ++ } ++ FmPcdLockUnlockAll(p_FmPort->h_FmPcd); ++ RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ } ++ ++ FmPcdLockUnlockAll(p_FmPort->h_FmPcd); ++ ++ /* Set pop-to-next-step nia */ ++#if (DPAA_VERSION == 10) ++ if (p_FmPort->fmRevInfo.majorRev < 6) ++ { ++ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN; ++ fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL; ++ } ++ else ++ { ++#endif /* (DPAA_VERSION == 10) */ ++ fmPortGetSetCcParams.getCcParams.type = GET_NIA_FPNE; ++#if (DPAA_VERSION == 10) ++ } ++#endif /* (DPAA_VERSION == 10) */ ++ if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) ++ != E_OK) ++ { ++ DeletePcd(p_FmPort); ++ if (p_FmPort->h_ReassemblyTree) ++ { ++ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); ++ p_FmPort->h_ReassemblyTree = NULL; ++ }RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ /* Set post-bmi-prepare-to-enq nia */ ++ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_FENE; ++ fmPortGetSetCcParams.setCcParams.nia = (NIA_FM_CTL_AC_POST_BMI_ENQ ++ | NIA_ENG_FM_CTL); ++ if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) ++ != E_OK) ++ { ++ DeletePcd(p_FmPort); ++ if (p_FmPort->h_ReassemblyTree) ++ { ++ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); ++ p_FmPort->h_ReassemblyTree = NULL; ++ }RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ if ((p_FmPort->h_IpReassemblyManip) ++ || (p_FmPort->h_CapwapReassemblyManip)) ++ { ++#if (DPAA_VERSION == 10) ++ if (p_FmPort->fmRevInfo.majorRev < 6) ++ { ++ /* Overwrite post-bmi-prepare-to-enq nia */ ++ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_FENE; ++ fmPortGetSetCcParams.setCcParams.nia = (NIA_FM_CTL_AC_POST_BMI_ENQ_ORR | NIA_ENG_FM_CTL | NIA_ORDER_RESTOR); ++ fmPortGetSetCcParams.setCcParams.overwrite = TRUE; ++ } ++ else ++ { ++#endif /* (DPAA_VERSION == 10) */ ++ /* Set the ORR bit (for order-restoration) */ ++ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_FPNE; ++ fmPortGetSetCcParams.setCcParams.nia = ++ fmPortGetSetCcParams.getCcParams.nia | NIA_ORDER_RESTOR; ++#if (DPAA_VERSION == 10) ++ } ++#endif /* (DPAA_VERSION == 10) */ ++ if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) ++ != E_OK) ++ { ++ DeletePcd(p_FmPort); ++ if (p_FmPort->h_ReassemblyTree) ++ { ++ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); ++ p_FmPort->h_ReassemblyTree = NULL; ++ }RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ } ++ } ++ else ++ FmPcdLockUnlockAll(p_FmPort->h_FmPcd); ++ ++#if (DPAA_VERSION >= 11) ++ { ++ t_FmPcdCtrlParamsPage *p_ParamsPage; ++ ++ memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams)); ++ ++ fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_CMNE; ++ if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)) ++ fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP ++ | NIA_ENG_FM_CTL; ++ else ++ fmPortGetSetCcParams.setCcParams.nia = ++ NIA_FM_CTL_AC_NO_IPACC_POP_TO_N_STEP | NIA_ENG_FM_CTL; ++ if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) ++ != E_OK) ++ { ++ DeletePcd(p_FmPort); ++ if (p_FmPort->h_ReassemblyTree) ++ { ++ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); ++ p_FmPort->h_ReassemblyTree = NULL; ++ }RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE, ++ (void**)&p_ParamsPage); ++ ASSERT_COND(p_ParamsPage); ++ ++ if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)) ++ WRITE_UINT32( ++ p_ParamsPage->misc, ++ GET_UINT32(p_ParamsPage->misc) | FM_CTL_PARAMS_PAGE_OFFLOAD_SUPPORT_EN); ++ ++ if ((p_FmPort->h_IpReassemblyManip) ++ || (p_FmPort->h_CapwapReassemblyManip)) ++ { ++ if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ WRITE_UINT32( ++ p_ParamsPage->discardMask, ++ GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm)); ++ else ++ WRITE_UINT32( ++ p_ParamsPage->discardMask, ++ GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm)); ++ } ++#ifdef FM_ERROR_VSP_NO_MATCH_SW006 ++ if (p_FmPort->vspe) ++ WRITE_UINT32( ++ p_ParamsPage->misc, ++ GET_UINT32(p_ParamsPage->misc) | (p_FmPort->dfltRelativeId & FM_CTL_PARAMS_PAGE_ERROR_VSP_MASK)); ++#endif /* FM_ERROR_VSP_NO_MATCH_SW006 */ ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ err = AttachPCD(h_FmPort); ++ if (err) ++ { ++ DeletePcd(p_FmPort); ++ if (p_FmPort->h_ReassemblyTree) ++ { ++ FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); ++ p_FmPort->h_ReassemblyTree = NULL; ++ }RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ RELEASE_LOCK(p_FmPort->lock); ++ ++ return err; ++} ++ ++t_Error FM_PORT_DeletePCD(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ ++ if (p_FmPort->imEn) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ++ ("available for non-independant mode ports only")); ++ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ++ RETURN_ERROR( MAJOR, E_INVALID_OPERATION, ++ ("available for Rx and offline parsing ports only")); ++ ++ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) ++ { ++ DBG(TRACE, ("FM Port Try Lock - BUSY")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = DetachPCD(h_FmPort); ++ if (err) ++ { ++ RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ FmPcdDecNetEnvOwners(p_FmPort->h_FmPcd, p_FmPort->netEnvId); ++ ++ /* we do it anyway, instead of checking if included */ ++ if ((p_FmPort->pcdEngines & FM_PCD_PRS) && p_FmPort->includeInPrsStatistics) ++ { ++ FmPcdPrsIncludePortInStatistics(p_FmPort->h_FmPcd, ++ p_FmPort->hardwarePortId, FALSE); ++ p_FmPort->includeInPrsStatistics = FALSE; ++ } ++ ++ if (!FmPcdLockTryLockAll(p_FmPort->h_FmPcd)) ++ { ++ RELEASE_LOCK(p_FmPort->lock); ++ DBG(TRACE, ("Try LockAll - BUSY")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = DeletePcd(h_FmPort); ++ FmPcdLockUnlockAll(p_FmPort->h_FmPcd); ++ if (err) ++ { ++ RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ if (p_FmPort->h_ReassemblyTree) ++ { ++ err = FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); ++ if (err) ++ { ++ RELEASE_LOCK(p_FmPort->lock); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ p_FmPort->h_ReassemblyTree = NULL; ++ }RELEASE_LOCK(p_FmPort->lock); ++ ++ return err; ++} ++ ++t_Error FM_PORT_PcdKgBindSchemes(t_Handle h_FmPort, ++ t_FmPcdPortSchemesParams *p_PortScheme) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_FmPcdKgInterModuleBindPortToSchemes schemeBind; ++ t_Error err = E_OK; ++ uint32_t tmpScmVec = 0; ++ int i; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG, ++ E_INVALID_STATE); ++ ++ schemeBind.netEnvId = p_FmPort->netEnvId; ++ schemeBind.hardwarePortId = p_FmPort->hardwarePortId; ++ schemeBind.numOfSchemes = p_PortScheme->numOfSchemes; ++ schemeBind.useClsPlan = p_FmPort->useClsPlan; ++ for (i = 0; i < schemeBind.numOfSchemes; i++) ++ { ++ schemeBind.schemesIds[i] = FmPcdKgGetSchemeId( ++ p_PortScheme->h_Schemes[i]); ++ /* build vector */ ++ tmpScmVec |= 1 << (31 - (uint32_t)schemeBind.schemesIds[i]); ++ } ++ ++ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) ++ { ++ DBG(TRACE, ("FM Port Try Lock - BUSY")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = FmPcdKgBindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind); ++ if (err == E_OK) ++ p_FmPort->schemesPerPortVector |= tmpScmVec; ++ ++#ifdef FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004 ++ if ((FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)) && ++ (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) && ++ (p_FmPort->fmRevInfo.majorRev < 6)) ++ { ++ for (i=0; inumOfSchemes; i++) ++ FmPcdKgCcGetSetParams(p_FmPort->h_FmPcd, p_PortScheme->h_Schemes[i], UPDATE_KG_NIA_CC_WA, 0); ++ } ++#endif /* FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004 */ ++ ++ RELEASE_LOCK(p_FmPort->lock); ++ ++ return err; ++} ++ ++t_Error FM_PORT_PcdKgUnbindSchemes(t_Handle h_FmPort, ++ t_FmPcdPortSchemesParams *p_PortScheme) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_FmPcdKgInterModuleBindPortToSchemes schemeBind; ++ t_Error err = E_OK; ++ uint32_t tmpScmVec = 0; ++ int i; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG, ++ E_INVALID_STATE); ++ ++ schemeBind.netEnvId = p_FmPort->netEnvId; ++ schemeBind.hardwarePortId = p_FmPort->hardwarePortId; ++ schemeBind.numOfSchemes = p_PortScheme->numOfSchemes; ++ for (i = 0; i < schemeBind.numOfSchemes; i++) ++ { ++ schemeBind.schemesIds[i] = FmPcdKgGetSchemeId( ++ p_PortScheme->h_Schemes[i]); ++ /* build vector */ ++ tmpScmVec |= 1 << (31 - (uint32_t)schemeBind.schemesIds[i]); ++ } ++ ++ if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) ++ { ++ DBG(TRACE, ("FM Port Try Lock - BUSY")); ++ return ERROR_CODE(E_BUSY); ++ } ++ ++ err = FmPcdKgUnbindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind); ++ if (err == E_OK) ++ p_FmPort->schemesPerPortVector &= ~tmpScmVec; ++ RELEASE_LOCK(p_FmPort->lock); ++ ++ return err; ++} ++ ++t_Error FM_PORT_AddCongestionGrps(t_Handle h_FmPort, ++ t_FmPortCongestionGrps *p_CongestionGrps) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ uint8_t priorityTmpArray[FM_PORT_NUM_OF_CONGESTION_GRPS]; ++ uint8_t mod, index; ++ uint32_t i, grpsMap[FMAN_PORT_CG_MAP_NUM]; ++ int err; ++#if (DPAA_VERSION >= 11) ++ int j; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ ++ /* un-necessary check of the indexes; probably will be needed in the future when there ++ will be more CGs available .... ++ for (i=0; inumOfCongestionGrpsToConsider; i++) ++ if (p_CongestionGrps->congestionGrpsToConsider[i] >= FM_PORT_NUM_OF_CONGESTION_GRPS) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("CG id!")); ++ */ ++ ++#ifdef FM_NO_OP_OBSERVED_CGS ++ if ((p_FmPort->fmRevInfo.majorRev != 4) && ++ (p_FmPort->fmRevInfo.majorRev < 6)) ++ { ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && ++ (p_FmPort->portType != e_FM_PORT_TYPE_RX)) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Available for Rx ports only")); ++ } ++ else ++#endif /* FM_NO_OP_OBSERVED_CGS */ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ++ ("Available for Rx & OP ports only")); ++ ++ /* Prepare groups map array */ ++ memset(grpsMap, 0, FMAN_PORT_CG_MAP_NUM * sizeof(uint32_t)); ++ for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++) ++ { ++ index = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] / 32); ++ mod = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] % 32); ++ if (p_FmPort->fmRevInfo.majorRev != 4) ++ grpsMap[7 - index] |= (uint32_t)(1 << mod); ++ else ++ grpsMap[0] |= (uint32_t)(1 << mod); ++ } ++ ++ memset(&priorityTmpArray, 0, ++ FM_PORT_NUM_OF_CONGESTION_GRPS * sizeof(uint8_t)); ++ ++ for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++) ++ { ++#if (DPAA_VERSION >= 11) ++ for (j = 0; j < FM_MAX_NUM_OF_PFC_PRIORITIES; j++) ++ if (p_CongestionGrps->pfcPrioritiesEn[i][j]) ++ priorityTmpArray[p_CongestionGrps->congestionGrpsToConsider[i]] |= ++ (0x01 << (FM_MAX_NUM_OF_PFC_PRIORITIES - j - 1)); ++#endif /* (DPAA_VERSION >= 11) */ ++ } ++ ++#if (DPAA_VERSION >= 11) ++ for (i = 0; i < FM_PORT_NUM_OF_CONGESTION_GRPS; i++) ++ { ++ err = FmSetCongestionGroupPFCpriority(p_FmPort->h_Fm, i, ++ priorityTmpArray[i]); ++ if (err) ++ return err; ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ err = fman_port_add_congestion_grps(&p_FmPort->port, grpsMap); ++ if (err != 0) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_add_congestion_grps")); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_RemoveCongestionGrps(t_Handle h_FmPort, ++ t_FmPortCongestionGrps *p_CongestionGrps) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ uint8_t mod, index; ++ uint32_t i, grpsMap[FMAN_PORT_CG_MAP_NUM]; ++ int err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ ++ { ++#ifdef FM_NO_OP_OBSERVED_CGS ++ t_FmRevisionInfo revInfo; ++ ++ FM_GetRevision(p_FmPort->h_Fm, &revInfo); ++ if (revInfo.majorRev != 4) ++ { ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && ++ (p_FmPort->portType != e_FM_PORT_TYPE_RX)) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Available for Rx ports only")); ++ } ++ else ++#endif /* FM_NO_OP_OBSERVED_CGS */ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_RX) ++ && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ++ ("Available for Rx & OP ports only")); ++ } ++ ++ /* Prepare groups map array */ ++ memset(grpsMap, 0, FMAN_PORT_CG_MAP_NUM * sizeof(uint32_t)); ++ for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++) ++ { ++ index = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] / 32); ++ mod = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] % 32); ++ if (p_FmPort->fmRevInfo.majorRev != 4) ++ grpsMap[7 - index] |= (uint32_t)(1 << mod); ++ else ++ grpsMap[0] |= (uint32_t)(1 << mod); ++ } ++ ++#if (DPAA_VERSION >= 11) ++ for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++) ++ { ++ t_Error err = FmSetCongestionGroupPFCpriority( ++ p_FmPort->h_Fm, p_CongestionGrps->congestionGrpsToConsider[i], ++ 0); ++ if (err) ++ return err; ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ err = fman_port_remove_congestion_grps(&p_FmPort->port, grpsMap); ++ if (err != 0) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("fman_port_remove_congestion_grps")); ++ return E_OK; ++} ++ ++#if (DPAA_VERSION >= 11) ++t_Error FM_PORT_GetIPv4OptionsCount(t_Handle h_FmPort, ++ uint32_t *p_Ipv4OptionsCount) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR( ++ (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING), ++ E_INVALID_VALUE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_ParamsPage, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_Ipv4OptionsCount, E_NULL_POINTER); ++ ++ *p_Ipv4OptionsCount = GET_UINT32(p_FmPort->p_ParamsPage->ipfOptionsCounter); ++ ++ return E_OK; ++} ++#endif /* (DPAA_VERSION >= 11) */ ++ ++t_Error FM_PORT_ConfigDsarSupport(t_Handle h_FmPortRx, ++ t_FmPortDsarTablesSizes *params) ++{ ++ t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx; ++ p_FmPort->deepSleepVars.autoResMaxSizes = XX_Malloc( ++ sizeof(struct t_FmPortDsarTablesSizes)); ++ memcpy(p_FmPort->deepSleepVars.autoResMaxSizes, params, ++ sizeof(struct t_FmPortDsarTablesSizes)); ++ return E_OK; ++} ++ ++static t_Error FmPortConfigAutoResForDeepSleepSupport1(t_FmPort *p_FmPort) ++{ ++ uint32_t *param_page; ++ t_FmPortDsarTablesSizes *params = p_FmPort->deepSleepVars.autoResMaxSizes; ++ t_ArCommonDesc *ArCommonDescPtr; ++ uint32_t size = sizeof(t_ArCommonDesc); ++ // ARP ++ // should put here if (params->max_num_of_arp_entries)? ++ size = ROUND_UP(size,4); ++ size += sizeof(t_DsarArpDescriptor); ++ size += sizeof(t_DsarArpBindingEntry) * params->maxNumOfArpEntries; ++ size += sizeof(t_DsarArpStatistics); ++ //ICMPV4 ++ size = ROUND_UP(size,4); ++ size += sizeof(t_DsarIcmpV4Descriptor); ++ size += sizeof(t_DsarIcmpV4BindingEntry) * params->maxNumOfEchoIpv4Entries; ++ size += sizeof(t_DsarIcmpV4Statistics); ++ //ICMPV6 ++ size = ROUND_UP(size,4); ++ size += sizeof(t_DsarIcmpV6Descriptor); ++ size += sizeof(t_DsarIcmpV6BindingEntry) * params->maxNumOfEchoIpv6Entries; ++ size += sizeof(t_DsarIcmpV6Statistics); ++ //ND ++ size = ROUND_UP(size,4); ++ size += sizeof(t_DsarNdDescriptor); ++ size += sizeof(t_DsarIcmpV6BindingEntry) * params->maxNumOfNdpEntries; ++ size += sizeof(t_DsarIcmpV6Statistics); ++ //SNMP ++ size = ROUND_UP(size,4); ++ size += sizeof(t_DsarSnmpDescriptor); ++ size += sizeof(t_DsarSnmpIpv4AddrTblEntry) ++ * params->maxNumOfSnmpIPV4Entries; ++ size += sizeof(t_DsarSnmpIpv6AddrTblEntry) ++ * params->maxNumOfSnmpIPV6Entries; ++ size += sizeof(t_OidsTblEntry) * params->maxNumOfSnmpOidEntries; ++ size += params->maxNumOfSnmpOidChar; ++ size += sizeof(t_DsarIcmpV6Statistics); ++ //filters ++ size = ROUND_UP(size,4); ++ size += params->maxNumOfIpProtFiltering; ++ size = ROUND_UP(size,4); ++ size += params->maxNumOfUdpPortFiltering * sizeof(t_PortTblEntry); ++ size = ROUND_UP(size,4); ++ size += params->maxNumOfTcpPortFiltering * sizeof(t_PortTblEntry); ++ ++ // add here for more protocols ++ ++ // statistics ++ size = ROUND_UP(size,4); ++ size += sizeof(t_ArStatistics); ++ ++ ArCommonDescPtr = FM_MURAM_AllocMem(p_FmPort->h_FmMuram, size, 0x10); ++ ++ param_page = ++ XX_PhysToVirt( ++ p_FmPort->fmMuramPhysBaseAddr ++ + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr)); ++ WRITE_UINT32( ++ *param_page, ++ (uint32_t)(XX_VirtToPhys(ArCommonDescPtr) - p_FmPort->fmMuramPhysBaseAddr)); ++ return E_OK; ++} ++ ++t_FmPortDsarTablesSizes* FM_PORT_GetDsarTablesMaxSizes(t_Handle h_FmPortRx) ++{ ++ t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx; ++ return p_FmPort->deepSleepVars.autoResMaxSizes; ++} ++ ++struct arOffsets ++{ ++ uint32_t arp; ++ uint32_t nd; ++ uint32_t icmpv4; ++ uint32_t icmpv6; ++ uint32_t snmp; ++ uint32_t stats; ++ uint32_t filtIp; ++ uint32_t filtUdp; ++ uint32_t filtTcp; ++}; ++ ++static uint32_t AR_ComputeOffsets(struct arOffsets* of, ++ struct t_FmPortDsarParams *params, ++ t_FmPort *p_FmPort) ++{ ++ uint32_t size = sizeof(t_ArCommonDesc); ++ // ARP ++ if (params->p_AutoResArpInfo) ++ { ++ size = ROUND_UP(size,4); ++ of->arp = size; ++ size += sizeof(t_DsarArpDescriptor); ++ size += sizeof(t_DsarArpBindingEntry) ++ * params->p_AutoResArpInfo->tableSize; ++ size += sizeof(t_DsarArpStatistics); ++ } ++ // ICMPV4 ++ if (params->p_AutoResEchoIpv4Info) ++ { ++ size = ROUND_UP(size,4); ++ of->icmpv4 = size; ++ size += sizeof(t_DsarIcmpV4Descriptor); ++ size += sizeof(t_DsarIcmpV4BindingEntry) ++ * params->p_AutoResEchoIpv4Info->tableSize; ++ size += sizeof(t_DsarIcmpV4Statistics); ++ } ++ // ICMPV6 ++ if (params->p_AutoResEchoIpv6Info) ++ { ++ size = ROUND_UP(size,4); ++ of->icmpv6 = size; ++ size += sizeof(t_DsarIcmpV6Descriptor); ++ size += sizeof(t_DsarIcmpV6BindingEntry) ++ * params->p_AutoResEchoIpv6Info->tableSize; ++ size += sizeof(t_DsarIcmpV6Statistics); ++ } ++ // ND ++ if (params->p_AutoResNdpInfo) ++ { ++ size = ROUND_UP(size,4); ++ of->nd = size; ++ size += sizeof(t_DsarNdDescriptor); ++ size += sizeof(t_DsarIcmpV6BindingEntry) ++ * (params->p_AutoResNdpInfo->tableSizeAssigned ++ + params->p_AutoResNdpInfo->tableSizeTmp); ++ size += sizeof(t_DsarIcmpV6Statistics); ++ } ++ // SNMP ++ if (params->p_AutoResSnmpInfo) ++ { ++ size = ROUND_UP(size,4); ++ of->snmp = size; ++ size += sizeof(t_DsarSnmpDescriptor); ++ size += sizeof(t_DsarSnmpIpv4AddrTblEntry) ++ * params->p_AutoResSnmpInfo->numOfIpv4Addresses; ++ size += sizeof(t_DsarSnmpIpv6AddrTblEntry) ++ * params->p_AutoResSnmpInfo->numOfIpv6Addresses; ++ size += sizeof(t_OidsTblEntry) * params->p_AutoResSnmpInfo->oidsTblSize; ++ size += p_FmPort->deepSleepVars.autoResMaxSizes->maxNumOfSnmpOidChar; ++ size += sizeof(t_DsarIcmpV6Statistics); ++ } ++ //filters ++ size = ROUND_UP(size,4); ++ if (params->p_AutoResFilteringInfo) ++ { ++ of->filtIp = size; ++ size += params->p_AutoResFilteringInfo->ipProtTableSize; ++ size = ROUND_UP(size,4); ++ of->filtUdp = size; ++ size += params->p_AutoResFilteringInfo->udpPortsTableSize ++ * sizeof(t_PortTblEntry); ++ size = ROUND_UP(size,4); ++ of->filtTcp = size; ++ size += params->p_AutoResFilteringInfo->tcpPortsTableSize ++ * sizeof(t_PortTblEntry); ++ } ++ // add here for more protocols ++ // statistics ++ size = ROUND_UP(size,4); ++ of->stats = size; ++ size += sizeof(t_ArStatistics); ++ return size; ++} ++ ++uint32_t* ARDesc; ++void PrsEnable(t_Handle p_FmPcd); ++void PrsDisable(t_Handle p_FmPcd); ++int PrsIsEnabled(t_Handle p_FmPcd); ++t_Handle FM_PCD_GetHcPort(t_Handle h_FmPcd); ++ ++static t_Error DsarCheckParams(t_FmPortDsarParams *params, ++ t_FmPortDsarTablesSizes *sizes) ++{ ++ bool macInit = FALSE; ++ uint8_t mac[6]; ++ int i = 0; ++ ++ // check table sizes ++ if (params->p_AutoResArpInfo ++ && sizes->maxNumOfArpEntries < params->p_AutoResArpInfo->tableSize) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("DSAR: Arp table size exceeds the configured maximum size.")); ++ if (params->p_AutoResEchoIpv4Info ++ && sizes->maxNumOfEchoIpv4Entries ++ < params->p_AutoResEchoIpv4Info->tableSize) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("DSAR: EchoIpv4 table size exceeds the configured maximum size.")); ++ if (params->p_AutoResNdpInfo ++ && sizes->maxNumOfNdpEntries ++ < params->p_AutoResNdpInfo->tableSizeAssigned ++ + params->p_AutoResNdpInfo->tableSizeTmp) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("DSAR: NDP table size exceeds the configured maximum size.")); ++ if (params->p_AutoResEchoIpv6Info ++ && sizes->maxNumOfEchoIpv6Entries ++ < params->p_AutoResEchoIpv6Info->tableSize) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("DSAR: EchoIpv6 table size exceeds the configured maximum size.")); ++ if (params->p_AutoResSnmpInfo ++ && sizes->maxNumOfSnmpOidEntries ++ < params->p_AutoResSnmpInfo->oidsTblSize) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("DSAR: Snmp Oid table size exceeds the configured maximum size.")); ++ if (params->p_AutoResSnmpInfo ++ && sizes->maxNumOfSnmpIPV4Entries ++ < params->p_AutoResSnmpInfo->numOfIpv4Addresses) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("DSAR: Snmp ipv4 table size exceeds the configured maximum size.")); ++ if (params->p_AutoResSnmpInfo ++ && sizes->maxNumOfSnmpIPV6Entries ++ < params->p_AutoResSnmpInfo->numOfIpv6Addresses) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("DSAR: Snmp ipv6 table size exceeds the configured maximum size.")); ++ if (params->p_AutoResFilteringInfo) ++ { ++ if (sizes->maxNumOfIpProtFiltering ++ < params->p_AutoResFilteringInfo->ipProtTableSize) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("DSAR: ip filter table size exceeds the configured maximum size.")); ++ if (sizes->maxNumOfTcpPortFiltering ++ < params->p_AutoResFilteringInfo->udpPortsTableSize) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("DSAR: udp filter table size exceeds the configured maximum size.")); ++ if (sizes->maxNumOfUdpPortFiltering ++ < params->p_AutoResFilteringInfo->tcpPortsTableSize) ++ RETURN_ERROR( ++ MAJOR, ++ E_INVALID_VALUE, ++ ("DSAR: tcp filter table size exceeds the configured maximum size.")); ++ } ++ /* check only 1 MAC address is configured (this is what ucode currently supports) */ ++ if (params->p_AutoResArpInfo && params->p_AutoResArpInfo->tableSize) ++ { ++ memcpy(mac, params->p_AutoResArpInfo->p_AutoResTable[0].mac, 6); ++ i = 1; ++ macInit = TRUE; ++ ++ for (; i < params->p_AutoResArpInfo->tableSize; i++) ++ if (memcmp(mac, params->p_AutoResArpInfo->p_AutoResTable[i].mac, 6)) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("DSAR: Only 1 mac address is currently supported.")); ++ } ++ if (params->p_AutoResEchoIpv4Info ++ && params->p_AutoResEchoIpv4Info->tableSize) ++ { ++ i = 0; ++ if (!macInit) ++ { ++ memcpy(mac, params->p_AutoResEchoIpv4Info->p_AutoResTable[0].mac, ++ 6); ++ i = 1; ++ macInit = TRUE; ++ } ++ for (; i < params->p_AutoResEchoIpv4Info->tableSize; i++) ++ if (memcmp(mac, ++ params->p_AutoResEchoIpv4Info->p_AutoResTable[i].mac, 6)) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("DSAR: Only 1 mac address is currently supported.")); ++ } ++ if (params->p_AutoResEchoIpv6Info ++ && params->p_AutoResEchoIpv6Info->tableSize) ++ { ++ i = 0; ++ if (!macInit) ++ { ++ memcpy(mac, params->p_AutoResEchoIpv6Info->p_AutoResTable[0].mac, ++ 6); ++ i = 1; ++ macInit = TRUE; ++ } ++ for (; i < params->p_AutoResEchoIpv6Info->tableSize; i++) ++ if (memcmp(mac, ++ params->p_AutoResEchoIpv6Info->p_AutoResTable[i].mac, 6)) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("DSAR: Only 1 mac address is currently supported.")); ++ } ++ if (params->p_AutoResNdpInfo && params->p_AutoResNdpInfo->tableSizeAssigned) ++ { ++ i = 0; ++ if (!macInit) ++ { ++ memcpy(mac, params->p_AutoResNdpInfo->p_AutoResTableAssigned[0].mac, ++ 6); ++ i = 1; ++ macInit = TRUE; ++ } ++ for (; i < params->p_AutoResNdpInfo->tableSizeAssigned; i++) ++ if (memcmp(mac, ++ params->p_AutoResNdpInfo->p_AutoResTableAssigned[i].mac, ++ 6)) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("DSAR: Only 1 mac address is currently supported.")); ++ } ++ if (params->p_AutoResNdpInfo && params->p_AutoResNdpInfo->tableSizeTmp) ++ { ++ i = 0; ++ if (!macInit) ++ { ++ memcpy(mac, params->p_AutoResNdpInfo->p_AutoResTableTmp[0].mac, 6); ++ i = 1; ++ } ++ for (; i < params->p_AutoResNdpInfo->tableSizeTmp; i++) ++ if (memcmp(mac, params->p_AutoResNdpInfo->p_AutoResTableTmp[i].mac, ++ 6)) ++ RETURN_ERROR( ++ MAJOR, E_INVALID_VALUE, ++ ("DSAR: Only 1 mac address is currently supported.")); ++ } ++ return E_OK; ++} ++ ++static int GetBERLen(uint8_t* buf) ++{ ++ if (*buf & 0x80) ++ { ++ if ((*buf & 0x7F) == 1) ++ return buf[1]; ++ else ++ return *(uint16_t*)&buf[1]; // assuming max len is 2 ++ } ++ else ++ return buf[0]; ++} ++#define TOTAL_BER_LEN(len) (len < 128) ? len + 2 : len + 3 ++ ++#define SCFG_FMCLKDPSLPCR_ADDR 0xFFE0FC00C ++#define SCFG_FMCLKDPSLPCR_DS_VAL 0x08402000 ++#define SCFG_FMCLKDPSLPCR_NORMAL_VAL 0x00402000 ++static int fm_soc_suspend(void) ++{ ++ uint32_t *fmclk, tmp32; ++ fmclk = ioremap(SCFG_FMCLKDPSLPCR_ADDR, 4); ++ tmp32 = GET_UINT32(*fmclk); ++ WRITE_UINT32(*fmclk, SCFG_FMCLKDPSLPCR_DS_VAL); ++ tmp32 = GET_UINT32(*fmclk); ++ iounmap(fmclk); ++ return 0; ++} ++ ++void fm_clk_down(void) ++{ ++ uint32_t *fmclk, tmp32; ++ fmclk = ioremap(SCFG_FMCLKDPSLPCR_ADDR, 4); ++ tmp32 = GET_UINT32(*fmclk); ++ WRITE_UINT32(*fmclk, SCFG_FMCLKDPSLPCR_DS_VAL | 0x40000000); ++ tmp32 = GET_UINT32(*fmclk); ++ iounmap(fmclk); ++} ++ ++t_Error FM_PORT_EnterDsar(t_Handle h_FmPortRx, t_FmPortDsarParams *params) ++{ ++ int i, j; ++ t_Error err; ++ uint32_t nia; ++ t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx; ++ t_FmPort *p_FmPortTx = (t_FmPort *)params->h_FmPortTx; ++ t_DsarArpDescriptor *ArpDescriptor; ++ t_DsarIcmpV4Descriptor* ICMPV4Descriptor; ++ t_DsarIcmpV6Descriptor* ICMPV6Descriptor; ++ t_DsarNdDescriptor* NDDescriptor; ++ ++ uint64_t fmMuramVirtBaseAddr = (uint64_t)PTR_TO_UINT(XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr)); ++ uint32_t *param_page = XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr)); ++ t_ArCommonDesc *ArCommonDescPtr = (t_ArCommonDesc*)(XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(*param_page))); ++ struct arOffsets* of; ++ uint8_t tmp = 0; ++ t_FmGetSetParams fmGetSetParams; ++ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); ++ fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP; ++ fmGetSetParams.setParams.sleep = 1; ++ ++ err = DsarCheckParams(params, p_FmPort->deepSleepVars.autoResMaxSizes); ++ if (err != E_OK) ++ return err; ++ ++ p_FmPort->deepSleepVars.autoResOffsets = XX_Malloc(sizeof(struct arOffsets)); ++ of = (struct arOffsets *)p_FmPort->deepSleepVars.autoResOffsets; ++ IOMemSet32(ArCommonDescPtr, 0, AR_ComputeOffsets(of, params, p_FmPort)); ++ ++ // common ++ WRITE_UINT8(ArCommonDescPtr->arTxPort, p_FmPortTx->hardwarePortId); ++ nia = GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne); // bmi nia ++ if ((nia & 0x007C0000) == 0x00440000) // bmi nia is parser ++ WRITE_UINT32(ArCommonDescPtr->activeHPNIA, GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne)); ++ else ++ WRITE_UINT32(ArCommonDescPtr->activeHPNIA, nia); ++ WRITE_UINT16(ArCommonDescPtr->snmpPort, 161); ++ ++ // ARP ++ if (params->p_AutoResArpInfo) ++ { ++ t_DsarArpBindingEntry* arp_bindings; ++ ArpDescriptor = (t_DsarArpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->arp); ++ WRITE_UINT32(ArCommonDescPtr->p_ArpDescriptor, PTR_TO_UINT(ArpDescriptor) - fmMuramVirtBaseAddr); ++ arp_bindings = (t_DsarArpBindingEntry*)(PTR_TO_UINT(ArpDescriptor) + sizeof(t_DsarArpDescriptor)); ++ if (params->p_AutoResArpInfo->enableConflictDetection) ++ WRITE_UINT16(ArpDescriptor->control, 1); ++ else ++ WRITE_UINT16(ArpDescriptor->control, 0); ++ if (params->p_AutoResArpInfo->tableSize) ++ { ++ t_FmPortDsarArpEntry* arp_entry = params->p_AutoResArpInfo->p_AutoResTable; ++ WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&arp_entry[0].mac[0]); ++ WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&arp_entry[0].mac[2]); ++ WRITE_UINT16(ArpDescriptor->numOfBindings, params->p_AutoResArpInfo->tableSize); ++ ++ for (i = 0; i < params->p_AutoResArpInfo->tableSize; i++) ++ { ++ WRITE_UINT32(arp_bindings[i].ipv4Addr, arp_entry[i].ipAddress); ++ if (arp_entry[i].isVlan) ++ WRITE_UINT16(arp_bindings[i].vlanId, arp_entry[i].vid & 0xFFF); ++ } ++ WRITE_UINT32(ArpDescriptor->p_Bindings, PTR_TO_UINT(arp_bindings) - fmMuramVirtBaseAddr); ++ } ++ WRITE_UINT32(ArpDescriptor->p_Statistics, PTR_TO_UINT(arp_bindings) + ++ sizeof(t_DsarArpBindingEntry) * params->p_AutoResArpInfo->tableSize - fmMuramVirtBaseAddr); ++ } ++ ++ // ICMPV4 ++ if (params->p_AutoResEchoIpv4Info) ++ { ++ t_DsarIcmpV4BindingEntry* icmpv4_bindings; ++ ICMPV4Descriptor = (t_DsarIcmpV4Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv4); ++ WRITE_UINT32(ArCommonDescPtr->p_IcmpV4Descriptor, PTR_TO_UINT(ICMPV4Descriptor) - fmMuramVirtBaseAddr); ++ icmpv4_bindings = (t_DsarIcmpV4BindingEntry*)(PTR_TO_UINT(ICMPV4Descriptor) + sizeof(t_DsarIcmpV4Descriptor)); ++ WRITE_UINT16(ICMPV4Descriptor->control, 0); ++ if (params->p_AutoResEchoIpv4Info->tableSize) ++ { ++ t_FmPortDsarArpEntry* arp_entry = params->p_AutoResEchoIpv4Info->p_AutoResTable; ++ WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&arp_entry[0].mac[0]); ++ WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&arp_entry[0].mac[2]); ++ WRITE_UINT16(ICMPV4Descriptor->numOfBindings, params->p_AutoResEchoIpv4Info->tableSize); ++ ++ for (i = 0; i < params->p_AutoResEchoIpv4Info->tableSize; i++) ++ { ++ WRITE_UINT32(icmpv4_bindings[i].ipv4Addr, arp_entry[i].ipAddress); ++ if (arp_entry[i].isVlan) ++ WRITE_UINT16(icmpv4_bindings[i].vlanId, arp_entry[i].vid & 0xFFF); ++ } ++ WRITE_UINT32(ICMPV4Descriptor->p_Bindings, PTR_TO_UINT(icmpv4_bindings) - fmMuramVirtBaseAddr); ++ } ++ WRITE_UINT32(ICMPV4Descriptor->p_Statistics, PTR_TO_UINT(icmpv4_bindings) + ++ sizeof(t_DsarIcmpV4BindingEntry) * params->p_AutoResEchoIpv4Info->tableSize - fmMuramVirtBaseAddr); ++ } ++ ++ // ICMPV6 ++ if (params->p_AutoResEchoIpv6Info) ++ { ++ t_DsarIcmpV6BindingEntry* icmpv6_bindings; ++ ICMPV6Descriptor = (t_DsarIcmpV6Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv6); ++ WRITE_UINT32(ArCommonDescPtr->p_IcmpV6Descriptor, PTR_TO_UINT(ICMPV6Descriptor) - fmMuramVirtBaseAddr); ++ icmpv6_bindings = (t_DsarIcmpV6BindingEntry*)(PTR_TO_UINT(ICMPV6Descriptor) + sizeof(t_DsarIcmpV6Descriptor)); ++ WRITE_UINT16(ICMPV6Descriptor->control, 0); ++ if (params->p_AutoResEchoIpv6Info->tableSize) ++ { ++ t_FmPortDsarNdpEntry* ndp_entry = params->p_AutoResEchoIpv6Info->p_AutoResTable; ++ WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&ndp_entry[0].mac[0]); ++ WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&ndp_entry[0].mac[2]); ++ WRITE_UINT16(ICMPV6Descriptor->numOfBindings, params->p_AutoResEchoIpv6Info->tableSize); ++ ++ for (i = 0; i < params->p_AutoResEchoIpv6Info->tableSize; i++) ++ { ++ for (j = 0; j < 4; j++) ++ WRITE_UINT32(icmpv6_bindings[i].ipv6Addr[j], ndp_entry[i].ipAddress[j]); ++ if (ndp_entry[i].isVlan) ++ WRITE_UINT16(*(uint16_t*)&icmpv6_bindings[i].ipv6Addr[4], ndp_entry[i].vid & 0xFFF); // writing vlan ++ } ++ WRITE_UINT32(ICMPV6Descriptor->p_Bindings, PTR_TO_UINT(icmpv6_bindings) - fmMuramVirtBaseAddr); ++ } ++ WRITE_UINT32(ICMPV6Descriptor->p_Statistics, PTR_TO_UINT(icmpv6_bindings) + ++ sizeof(t_DsarIcmpV6BindingEntry) * params->p_AutoResEchoIpv6Info->tableSize - fmMuramVirtBaseAddr); ++ } ++ ++ // ND ++ if (params->p_AutoResNdpInfo) ++ { ++ t_DsarIcmpV6BindingEntry* icmpv6_bindings; ++ NDDescriptor = (t_DsarNdDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->nd); ++ WRITE_UINT32(ArCommonDescPtr->p_NdDescriptor, PTR_TO_UINT(NDDescriptor) - fmMuramVirtBaseAddr); ++ icmpv6_bindings = (t_DsarIcmpV6BindingEntry*)(PTR_TO_UINT(NDDescriptor) + sizeof(t_DsarNdDescriptor)); ++ if (params->p_AutoResNdpInfo->enableConflictDetection) ++ WRITE_UINT16(NDDescriptor->control, 1); ++ else ++ WRITE_UINT16(NDDescriptor->control, 0); ++ if (params->p_AutoResNdpInfo->tableSizeAssigned + params->p_AutoResNdpInfo->tableSizeTmp) ++ { ++ t_FmPortDsarNdpEntry* ndp_entry = params->p_AutoResNdpInfo->p_AutoResTableAssigned; ++ WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&ndp_entry[0].mac[0]); ++ WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&ndp_entry[0].mac[2]); ++ WRITE_UINT16(NDDescriptor->numOfBindings, params->p_AutoResNdpInfo->tableSizeAssigned ++ + params->p_AutoResNdpInfo->tableSizeTmp); ++ ++ for (i = 0; i < params->p_AutoResNdpInfo->tableSizeAssigned; i++) ++ { ++ for (j = 0; j < 4; j++) ++ WRITE_UINT32(icmpv6_bindings[i].ipv6Addr[j], ndp_entry[i].ipAddress[j]); ++ if (ndp_entry[i].isVlan) ++ WRITE_UINT16(*(uint16_t*)&icmpv6_bindings[i].ipv6Addr[4], ndp_entry[i].vid & 0xFFF); // writing vlan ++ } ++ ndp_entry = params->p_AutoResNdpInfo->p_AutoResTableTmp; ++ for (i = 0; i < params->p_AutoResNdpInfo->tableSizeTmp; i++) ++ { ++ for (j = 0; j < 4; j++) ++ WRITE_UINT32(icmpv6_bindings[i + params->p_AutoResNdpInfo->tableSizeAssigned].ipv6Addr[j], ndp_entry[i].ipAddress[j]); ++ if (ndp_entry[i].isVlan) ++ WRITE_UINT16(*(uint16_t*)&icmpv6_bindings[i + params->p_AutoResNdpInfo->tableSizeAssigned].ipv6Addr[4], ndp_entry[i].vid & 0xFFF); // writing vlan ++ } ++ WRITE_UINT32(NDDescriptor->p_Bindings, PTR_TO_UINT(icmpv6_bindings) - fmMuramVirtBaseAddr); ++ } ++ WRITE_UINT32(NDDescriptor->p_Statistics, PTR_TO_UINT(icmpv6_bindings) + sizeof(t_DsarIcmpV6BindingEntry) ++ * (params->p_AutoResNdpInfo->tableSizeAssigned + params->p_AutoResNdpInfo->tableSizeTmp) ++ - fmMuramVirtBaseAddr); ++ WRITE_UINT32(NDDescriptor->solicitedAddr, 0xFFFFFFFF); ++ } ++ ++ // SNMP ++ if (params->p_AutoResSnmpInfo) ++ { ++ t_FmPortDsarSnmpInfo *snmpSrc = params->p_AutoResSnmpInfo; ++ t_DsarSnmpIpv4AddrTblEntry* snmpIpv4Addr; ++ t_DsarSnmpIpv6AddrTblEntry* snmpIpv6Addr; ++ t_OidsTblEntry* snmpOid; ++ uint8_t *charPointer; ++ int len; ++ t_DsarSnmpDescriptor* SnmpDescriptor = (t_DsarSnmpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->snmp); ++ WRITE_UINT32(ArCommonDescPtr->p_SnmpDescriptor, PTR_TO_UINT(SnmpDescriptor) - fmMuramVirtBaseAddr); ++ WRITE_UINT16(SnmpDescriptor->control, snmpSrc->control); ++ WRITE_UINT16(SnmpDescriptor->maxSnmpMsgLength, snmpSrc->maxSnmpMsgLength); ++ snmpIpv4Addr = (t_DsarSnmpIpv4AddrTblEntry*)(PTR_TO_UINT(SnmpDescriptor) + sizeof(t_DsarSnmpDescriptor)); ++ if (snmpSrc->numOfIpv4Addresses) ++ { ++ t_FmPortDsarSnmpIpv4AddrTblEntry* snmpIpv4AddrSrc = snmpSrc->p_Ipv4AddrTbl; ++ WRITE_UINT16(SnmpDescriptor->numOfIpv4Addresses, snmpSrc->numOfIpv4Addresses); ++ for (i = 0; i < snmpSrc->numOfIpv4Addresses; i++) ++ { ++ WRITE_UINT32(snmpIpv4Addr[i].ipv4Addr, snmpIpv4AddrSrc[i].ipv4Addr); ++ if (snmpIpv4AddrSrc[i].isVlan) ++ WRITE_UINT16(snmpIpv4Addr[i].vlanId, snmpIpv4AddrSrc[i].vid & 0xFFF); ++ } ++ WRITE_UINT32(SnmpDescriptor->p_Ipv4AddrTbl, PTR_TO_UINT(snmpIpv4Addr) - fmMuramVirtBaseAddr); ++ } ++ snmpIpv6Addr = (t_DsarSnmpIpv6AddrTblEntry*)(PTR_TO_UINT(snmpIpv4Addr) ++ + sizeof(t_DsarSnmpIpv4AddrTblEntry) * snmpSrc->numOfIpv4Addresses); ++ if (snmpSrc->numOfIpv6Addresses) ++ { ++ t_FmPortDsarSnmpIpv6AddrTblEntry* snmpIpv6AddrSrc = snmpSrc->p_Ipv6AddrTbl; ++ WRITE_UINT16(SnmpDescriptor->numOfIpv6Addresses, snmpSrc->numOfIpv6Addresses); ++ for (i = 0; i < snmpSrc->numOfIpv6Addresses; i++) ++ { ++ for (j = 0; j < 4; j++) ++ WRITE_UINT32(snmpIpv6Addr[i].ipv6Addr[j], snmpIpv6AddrSrc[i].ipv6Addr[j]); ++ if (snmpIpv6AddrSrc[i].isVlan) ++ WRITE_UINT16(snmpIpv6Addr[i].vlanId, snmpIpv6AddrSrc[i].vid & 0xFFF); ++ } ++ WRITE_UINT32(SnmpDescriptor->p_Ipv6AddrTbl, PTR_TO_UINT(snmpIpv6Addr) - fmMuramVirtBaseAddr); ++ } ++ snmpOid = (t_OidsTblEntry*)(PTR_TO_UINT(snmpIpv6Addr) ++ + sizeof(t_DsarSnmpIpv6AddrTblEntry) * snmpSrc->numOfIpv6Addresses); ++ charPointer = (uint8_t*)(PTR_TO_UINT(snmpOid) ++ + sizeof(t_OidsTblEntry) * snmpSrc->oidsTblSize); ++ len = TOTAL_BER_LEN(GetBERLen(&snmpSrc->p_RdOnlyCommunityStr[1])); ++ Mem2IOCpy32(charPointer, snmpSrc->p_RdOnlyCommunityStr, len); ++ WRITE_UINT32(SnmpDescriptor->p_RdOnlyCommunityStr, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr); ++ charPointer += len; ++ len = TOTAL_BER_LEN(GetBERLen(&snmpSrc->p_RdWrCommunityStr[1])); ++ Mem2IOCpy32(charPointer, snmpSrc->p_RdWrCommunityStr, len); ++ WRITE_UINT32(SnmpDescriptor->p_RdWrCommunityStr, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr); ++ charPointer += len; ++ WRITE_UINT32(SnmpDescriptor->oidsTblSize, snmpSrc->oidsTblSize); ++ WRITE_UINT32(SnmpDescriptor->p_OidsTbl, PTR_TO_UINT(snmpOid) - fmMuramVirtBaseAddr); ++ for (i = 0; i < snmpSrc->oidsTblSize; i++) ++ { ++ WRITE_UINT16(snmpOid->oidSize, snmpSrc->p_OidsTbl[i].oidSize); ++ WRITE_UINT16(snmpOid->resSize, snmpSrc->p_OidsTbl[i].resSize); ++ Mem2IOCpy32(charPointer, snmpSrc->p_OidsTbl[i].oidVal, snmpSrc->p_OidsTbl[i].oidSize); ++ WRITE_UINT32(snmpOid->p_Oid, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr); ++ charPointer += snmpSrc->p_OidsTbl[i].oidSize; ++ if (snmpSrc->p_OidsTbl[i].resSize <= 4) ++ WRITE_UINT32(snmpOid->resValOrPtr, *snmpSrc->p_OidsTbl[i].resVal); ++ else ++ { ++ Mem2IOCpy32(charPointer, snmpSrc->p_OidsTbl[i].resVal, snmpSrc->p_OidsTbl[i].resSize); ++ WRITE_UINT32(snmpOid->resValOrPtr, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr); ++ charPointer += snmpSrc->p_OidsTbl[i].resSize; ++ } ++ snmpOid++; ++ } ++ charPointer = UINT_TO_PTR(ROUND_UP(PTR_TO_UINT(charPointer),4)); ++ WRITE_UINT32(SnmpDescriptor->p_Statistics, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr); ++ } ++ ++ // filtering ++ if (params->p_AutoResFilteringInfo) ++ { ++ if (params->p_AutoResFilteringInfo->ipProtPassOnHit) ++ tmp |= IP_PROT_TBL_PASS_MASK; ++ if (params->p_AutoResFilteringInfo->udpPortPassOnHit) ++ tmp |= UDP_PORT_TBL_PASS_MASK; ++ if (params->p_AutoResFilteringInfo->tcpPortPassOnHit) ++ tmp |= TCP_PORT_TBL_PASS_MASK; ++ WRITE_UINT8(ArCommonDescPtr->filterControl, tmp); ++ WRITE_UINT16(ArCommonDescPtr->tcpControlPass, params->p_AutoResFilteringInfo->tcpFlagsMask); ++ ++ // ip filtering ++ if (params->p_AutoResFilteringInfo->ipProtTableSize) ++ { ++ uint8_t* ip_tbl = (uint8_t*)(PTR_TO_UINT(ArCommonDescPtr) + of->filtIp); ++ WRITE_UINT8(ArCommonDescPtr->ipProtocolTblSize, params->p_AutoResFilteringInfo->ipProtTableSize); ++ for (i = 0; i < params->p_AutoResFilteringInfo->ipProtTableSize; i++) ++ WRITE_UINT8(ip_tbl[i], params->p_AutoResFilteringInfo->p_IpProtTablePtr[i]); ++ WRITE_UINT32(ArCommonDescPtr->p_IpProtocolFiltTbl, PTR_TO_UINT(ip_tbl) - fmMuramVirtBaseAddr); ++ } ++ ++ // udp filtering ++ if (params->p_AutoResFilteringInfo->udpPortsTableSize) ++ { ++ t_PortTblEntry* udp_tbl = (t_PortTblEntry*)(PTR_TO_UINT(ArCommonDescPtr) + of->filtUdp); ++ WRITE_UINT8(ArCommonDescPtr->udpPortTblSize, params->p_AutoResFilteringInfo->udpPortsTableSize); ++ for (i = 0; i < params->p_AutoResFilteringInfo->udpPortsTableSize; i++) ++ { ++ WRITE_UINT32(udp_tbl[i].Ports, ++ (params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].srcPort << 16) + ++ params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].dstPort); ++ WRITE_UINT32(udp_tbl[i].PortsMask, ++ (params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].srcPortMask << 16) + ++ params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].dstPortMask); ++ } ++ WRITE_UINT32(ArCommonDescPtr->p_UdpPortFiltTbl, PTR_TO_UINT(udp_tbl) - fmMuramVirtBaseAddr); ++ } ++ ++ // tcp filtering ++ if (params->p_AutoResFilteringInfo->tcpPortsTableSize) ++ { ++ t_PortTblEntry* tcp_tbl = (t_PortTblEntry*)(PTR_TO_UINT(ArCommonDescPtr) + of->filtTcp); ++ WRITE_UINT8(ArCommonDescPtr->tcpPortTblSize, params->p_AutoResFilteringInfo->tcpPortsTableSize); ++ for (i = 0; i < params->p_AutoResFilteringInfo->tcpPortsTableSize; i++) ++ { ++ WRITE_UINT32(tcp_tbl[i].Ports, ++ (params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].srcPort << 16) + ++ params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].dstPort); ++ WRITE_UINT32(tcp_tbl[i].PortsMask, ++ (params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].srcPortMask << 16) + ++ params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].dstPortMask); ++ } ++ WRITE_UINT32(ArCommonDescPtr->p_TcpPortFiltTbl, PTR_TO_UINT(tcp_tbl) - fmMuramVirtBaseAddr); ++ } ++ } ++ // common stats ++ WRITE_UINT32(ArCommonDescPtr->p_ArStats, PTR_TO_UINT(ArCommonDescPtr) + of->stats - fmMuramVirtBaseAddr); ++ ++ // get into Deep Sleep sequence: ++ ++ // Ensures that FMan do not enter the idle state. This is done by programing ++ // FMDPSLPCR[FM_STOP] to one. ++ fm_soc_suspend(); ++ ++ ARDesc = UINT_TO_PTR(XX_VirtToPhys(ArCommonDescPtr)); ++ return E_OK; ++ ++} ++ ++void FM_ChangeClock(t_Handle h_Fm, int hardwarePortId); ++t_Error FM_PORT_EnterDsarFinal(t_Handle h_DsarRxPort, t_Handle h_DsarTxPort) ++{ ++ t_FmGetSetParams fmGetSetParams; ++ t_FmPort *p_FmPort = (t_FmPort *)h_DsarRxPort; ++ t_FmPort *p_FmPortTx = (t_FmPort *)h_DsarTxPort; ++ t_Handle *h_FmPcd = FmGetPcd(p_FmPort->h_Fm); ++ t_FmPort *p_FmPortHc = FM_PCD_GetHcPort(h_FmPcd); ++ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); ++ fmGetSetParams.setParams.type = UPDATE_FM_CLD; ++ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); ++ ++ /* Issue graceful stop to HC port */ ++ FM_PORT_Disable(p_FmPortHc); ++ ++ // config tx port ++ p_FmPort->deepSleepVars.fmbm_tcfg = GET_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg); ++ WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg, GET_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg) | BMI_PORT_CFG_IM | BMI_PORT_CFG_EN); ++ // ???? ++ p_FmPort->deepSleepVars.fmbm_tcmne = GET_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcmne); ++ WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcmne, 0xE); ++ // Stage 7:echo ++ p_FmPort->deepSleepVars.fmbm_rfpne = GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne); ++ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne, 0x2E); ++ if (!PrsIsEnabled(h_FmPcd)) ++ { ++ p_FmPort->deepSleepVars.dsarEnabledParser = TRUE; ++ PrsEnable(h_FmPcd); ++ } ++ else ++ p_FmPort->deepSleepVars.dsarEnabledParser = FALSE; ++ ++ p_FmPort->deepSleepVars.fmbm_rfne = GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne); ++ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne, 0x440000); ++ ++ // save rcfg for restoring: accumulate mode is changed by ucode ++ p_FmPort->deepSleepVars.fmbm_rcfg = GET_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rcfg); ++ WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rcfg, p_FmPort->deepSleepVars.fmbm_rcfg | BMI_PORT_CFG_AM); ++ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); ++ fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP; ++ fmGetSetParams.setParams.sleep = 1; ++ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); ++ ++// ***** issue external request sync command ++ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); ++ fmGetSetParams.setParams.type = UPDATE_FPM_EXTC; ++ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); ++ // get ++ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); ++ fmGetSetParams.getParams.type = GET_FMFP_EXTC; ++ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); ++ if (fmGetSetParams.getParams.fmfp_extc != 0) ++ { ++ // clear ++ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); ++ fmGetSetParams.setParams.type = UPDATE_FPM_EXTC_CLEAR; ++ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); ++} ++ ++ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); ++ fmGetSetParams.getParams.type = GET_FMFP_EXTC | GET_FM_NPI; ++ do ++ { ++ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); ++ } while (fmGetSetParams.getParams.fmfp_extc != 0 && fmGetSetParams.getParams.fm_npi == 0); ++ if (fmGetSetParams.getParams.fm_npi != 0) ++ XX_Print("FM: Sync did not finish\n"); ++ ++ // check that all stoped ++ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); ++ fmGetSetParams.getParams.type = GET_FMQM_GS | GET_FM_NPI; ++ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); ++ while (fmGetSetParams.getParams.fmqm_gs & 0xF0000000) ++ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); ++ if (fmGetSetParams.getParams.fmqm_gs == 0 && fmGetSetParams.getParams.fm_npi == 0) ++ XX_Print("FM: Sleeping\n"); ++// FM_ChangeClock(p_FmPort->h_Fm, p_FmPort->hardwarePortId); ++ ++ return E_OK; ++} ++ ++EXPORT_SYMBOL(FM_PORT_EnterDsarFinal); ++ ++void FM_PORT_Dsar_DumpRegs() ++{ ++ uint32_t* hh = XX_PhysToVirt(PTR_TO_UINT(ARDesc)); ++ DUMP_MEMORY(hh, 0x220); ++} ++ ++void FM_PORT_ExitDsar(t_Handle h_FmPortRx, t_Handle h_FmPortTx) ++{ ++ t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx; ++ t_FmPort *p_FmPortTx = (t_FmPort *)h_FmPortTx; ++ t_Handle *h_FmPcd = FmGetPcd(p_FmPort->h_Fm); ++ t_FmPort *p_FmPortHc = FM_PCD_GetHcPort(h_FmPcd); ++ t_FmGetSetParams fmGetSetParams; ++ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); ++ fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP; ++ fmGetSetParams.setParams.sleep = 0; ++ if (p_FmPort->deepSleepVars.autoResOffsets) ++ { ++ XX_Free(p_FmPort->deepSleepVars.autoResOffsets); ++ p_FmPort->deepSleepVars.autoResOffsets = 0; ++ } ++ ++ if (p_FmPort->deepSleepVars.dsarEnabledParser) ++ PrsDisable(FmGetPcd(p_FmPort->h_Fm)); ++ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne, p_FmPort->deepSleepVars.fmbm_rfpne); ++ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne, p_FmPort->deepSleepVars.fmbm_rfne); ++ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rcfg, p_FmPort->deepSleepVars.fmbm_rcfg); ++ FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); ++ WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcmne, p_FmPort->deepSleepVars.fmbm_tcmne); ++ WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg, p_FmPort->deepSleepVars.fmbm_tcfg); ++ FM_PORT_Enable(p_FmPortHc); ++} ++ ++bool FM_PORT_IsInDsar(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort *)h_FmPort; ++ return PTR_TO_UINT(p_FmPort->deepSleepVars.autoResOffsets); ++} ++ ++t_Error FM_PORT_GetDsarStats(t_Handle h_FmPortRx, t_FmPortDsarStats *stats) ++{ ++ t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx; ++ struct arOffsets *of = (struct arOffsets*)p_FmPort->deepSleepVars.autoResOffsets; ++ uint8_t* fmMuramVirtBaseAddr = XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr); ++ uint32_t *param_page = XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr)); ++ t_ArCommonDesc *ArCommonDescPtr = (t_ArCommonDesc*)(XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(*param_page))); ++ t_DsarArpDescriptor *ArpDescriptor = (t_DsarArpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->arp); ++ t_DsarArpStatistics* arp_stats = (t_DsarArpStatistics*)(PTR_TO_UINT(ArpDescriptor->p_Statistics) + fmMuramVirtBaseAddr); ++ t_DsarIcmpV4Descriptor* ICMPV4Descriptor = (t_DsarIcmpV4Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv4); ++ t_DsarIcmpV4Statistics* icmpv4_stats = (t_DsarIcmpV4Statistics*)(PTR_TO_UINT(ICMPV4Descriptor->p_Statistics) + fmMuramVirtBaseAddr); ++ t_DsarNdDescriptor* NDDescriptor = (t_DsarNdDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->nd); ++ t_NdStatistics* nd_stats = (t_NdStatistics*)(PTR_TO_UINT(NDDescriptor->p_Statistics) + fmMuramVirtBaseAddr); ++ t_DsarIcmpV6Descriptor* ICMPV6Descriptor = (t_DsarIcmpV6Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv6); ++ t_DsarIcmpV6Statistics* icmpv6_stats = (t_DsarIcmpV6Statistics*)(PTR_TO_UINT(ICMPV6Descriptor->p_Statistics) + fmMuramVirtBaseAddr); ++ t_DsarSnmpDescriptor* SnmpDescriptor = (t_DsarSnmpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->snmp); ++ t_DsarSnmpStatistics* snmp_stats = (t_DsarSnmpStatistics*)(PTR_TO_UINT(SnmpDescriptor->p_Statistics) + fmMuramVirtBaseAddr); ++ stats->arpArCnt = arp_stats->arCnt; ++ stats->echoIcmpv4ArCnt = icmpv4_stats->arCnt; ++ stats->ndpArCnt = nd_stats->arCnt; ++ stats->echoIcmpv6ArCnt = icmpv6_stats->arCnt; ++ stats->snmpGetCnt = snmp_stats->snmpGetReqCnt; ++ stats->snmpGetNextCnt = snmp_stats->snmpGetNextReqCnt; ++ return E_OK; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.h +new file mode 100644 +index 00000000..85986f55 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.h +@@ -0,0 +1,999 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_port.h ++ ++ @Description FM Port internal structures and definitions. ++*//***************************************************************************/ ++#ifndef __FM_PORT_H ++#define __FM_PORT_H ++ ++#include "error_ext.h" ++#include "std_ext.h" ++#include "fm_port_ext.h" ++ ++#include "fm_common.h" ++#include "fm_sp_common.h" ++#include "fsl_fman_sp.h" ++#include "fm_port_ext.h" ++#include "fsl_fman_port.h" ++ ++#define __ERR_MODULE__ MODULE_FM_PORT ++ ++ ++#define MIN_EXT_BUF_SIZE 64 ++#define DATA_ALIGNMENT 64 ++#define MAX_LIODN_OFFSET 64 ++#define MAX_PORT_FIFO_SIZE MIN(BMI_MAX_FIFO_SIZE, 1024*BMI_FIFO_UNITS) ++ ++/**************************************************************************//** ++ @Description Memory Map defines ++*//***************************************************************************/ ++#define BMI_PORT_REGS_OFFSET 0 ++#define QMI_PORT_REGS_OFFSET 0x400 ++#define PRS_PORT_REGS_OFFSET 0x800 ++ ++/**************************************************************************//** ++ @Description defaults ++*//***************************************************************************/ ++#define DEFAULT_PORT_deqHighPriority_1G FALSE ++#define DEFAULT_PORT_deqHighPriority_10G TRUE ++#define DEFAULT_PORT_deqType e_FM_PORT_DEQ_TYPE1 ++#define DEFAULT_PORT_deqPrefetchOption e_FM_PORT_DEQ_FULL_PREFETCH ++#define DEFAULT_PORT_deqPrefetchOption_HC e_FM_PORT_DEQ_NO_PREFETCH ++#define DEFAULT_PORT_deqByteCnt_10G 0x1400 ++#define DEFAULT_PORT_deqByteCnt_1G 0x400 ++#define DEFAULT_PORT_bufferPrefixContent_privDataSize DEFAULT_FM_SP_bufferPrefixContent_privDataSize ++#define DEFAULT_PORT_bufferPrefixContent_passPrsResult DEFAULT_FM_SP_bufferPrefixContent_passPrsResult ++#define DEFAULT_PORT_bufferPrefixContent_passTimeStamp DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp ++#define DEFAULT_PORT_bufferPrefixContent_allOtherPCDInfo DEFAULT_FM_SP_bufferPrefixContent_allOtherPCDInfo ++#define DEFAULT_PORT_bufferPrefixContent_dataAlign DEFAULT_FM_SP_bufferPrefixContent_dataAlign ++#define DEFAULT_PORT_cheksumLastBytesIgnore 0 ++#define DEFAULT_PORT_cutBytesFromEnd 4 ++#define DEFAULT_PORT_fifoDeqPipelineDepth_IM 2 ++ ++#define DEFAULT_PORT_frmDiscardOverride FALSE ++ ++#define DEFAULT_PORT_dmaSwapData (e_FmDmaSwapOption)DEFAULT_FMAN_SP_DMA_SWAP_DATA ++#define DEFAULT_PORT_dmaIntContextCacheAttr (e_FmDmaCacheOption)DEFAULT_FMAN_SP_DMA_INT_CONTEXT_CACHE_ATTR ++#define DEFAULT_PORT_dmaHeaderCacheAttr (e_FmDmaCacheOption)DEFAULT_FMAN_SP_DMA_HEADER_CACHE_ATTR ++#define DEFAULT_PORT_dmaScatterGatherCacheAttr (e_FmDmaCacheOption)DEFAULT_FMAN_SP_DMA_SCATTER_GATHER_CACHE_ATTR ++#define DEFAULT_PORT_dmaWriteOptimize DEFAULT_FMAN_SP_DMA_WRITE_OPTIMIZE ++ ++#define DEFAULT_PORT_noScatherGather DEFAULT_FMAN_SP_NO_SCATTER_GATHER ++#define DEFAULT_PORT_forwardIntContextReuse FALSE ++#define DEFAULT_PORT_BufMargins_startMargins 32 ++#define DEFAULT_PORT_BufMargins_endMargins 0 ++#define DEFAULT_PORT_syncReq TRUE ++#define DEFAULT_PORT_syncReqForHc FALSE ++#define DEFAULT_PORT_color e_FM_PORT_COLOR_GREEN ++#define DEFAULT_PORT_errorsToDiscard FM_PORT_FRM_ERR_CLS_DISCARD ++/* #define DEFAULT_PORT_dualRateLimitScaleDown e_FM_PORT_DUAL_RATE_LIMITER_NONE */ ++/* #define DEFAULT_PORT_rateLimitBurstSizeHighGranularity FALSE */ ++#define DEFAULT_PORT_exception IM_EV_BSY ++#define DEFAULT_PORT_maxFrameLength 9600 ++ ++#define DEFAULT_notSupported 0xff ++ ++#if (DPAA_VERSION < 11) ++#define DEFAULT_PORT_rxFifoPriElevationLevel MAX_PORT_FIFO_SIZE ++#define DEFAULT_PORT_rxFifoThreshold (MAX_PORT_FIFO_SIZE*3/4) ++ ++#define DEFAULT_PORT_txFifoMinFillLevel 0 ++#define DEFAULT_PORT_txFifoLowComfLevel (5*KILOBYTE) ++#define DEFAULT_PORT_fifoDeqPipelineDepth_1G 1 ++#define DEFAULT_PORT_fifoDeqPipelineDepth_10G 4 ++ ++#define DEFAULT_PORT_fifoDeqPipelineDepth_OH 2 ++ ++/* Host command port MUST NOT be changed to more than 1 !!! */ ++#define DEFAULT_PORT_numOfTasks(type) \ ++ (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) || \ ++ ((type) == e_FM_PORT_TYPE_TX_10G)) ? 16 : \ ++ ((((type) == e_FM_PORT_TYPE_RX) || \ ++ ((type) == e_FM_PORT_TYPE_TX) || \ ++ ((type) == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ? 3 : 1)) ++ ++#define DEFAULT_PORT_extraNumOfTasks(type) \ ++ (uint32_t)(((type) == e_FM_PORT_TYPE_RX_10G) ? 8 : \ ++ (((type) == e_FM_PORT_TYPE_RX) ? 2 : 0)) ++ ++#define DEFAULT_PORT_numOfOpenDmas(type) \ ++ (uint32_t)((((type) == e_FM_PORT_TYPE_TX_10G) || \ ++ ((type) == e_FM_PORT_TYPE_RX_10G)) ? 8 : 1 ) ++ ++#define DEFAULT_PORT_extraNumOfOpenDmas(type) \ ++ (uint32_t)(((type) == e_FM_PORT_TYPE_RX_10G) ? 8 : \ ++ (((type) == e_FM_PORT_TYPE_RX) ? 1 : 0)) ++ ++#define DEFAULT_PORT_numOfFifoBufs(type) \ ++ (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) || \ ++ ((type) == e_FM_PORT_TYPE_TX_10G)) ? 48 : \ ++ ((type) == e_FM_PORT_TYPE_RX) ? 45 : \ ++ ((type) == e_FM_PORT_TYPE_TX) ? 44 : 8) ++ ++#define DEFAULT_PORT_extraNumOfFifoBufs 0 ++ ++#else /* (DPAA_VERSION < 11) */ ++/* Defaults are registers' reset values */ ++#define DEFAULT_PORT_rxFifoPriElevationLevel MAX_PORT_FIFO_SIZE ++#define DEFAULT_PORT_rxFifoThreshold MAX_PORT_FIFO_SIZE ++ ++#define DEFAULT_PORT_txFifoMinFillLevel 0 ++#define DEFAULT_PORT_txFifoLowComfLevel (5 * KILOBYTE) ++#define DEFAULT_PORT_fifoDeqPipelineDepth_1G 2 ++#define DEFAULT_PORT_fifoDeqPipelineDepth_10G 4 ++ ++#define DEFAULT_PORT_fifoDeqPipelineDepth_OH 2 ++ ++#define DEFAULT_PORT_numOfTasks(type) \ ++ (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) || \ ++ ((type) == e_FM_PORT_TYPE_TX_10G)) ? 14 : \ ++ (((type) == e_FM_PORT_TYPE_RX) || \ ++ ((type) == e_FM_PORT_TYPE_TX)) ? 4 : \ ++ ((type) == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ? 6 : 1) ++ ++#define DEFAULT_PORT_extraNumOfTasks(type) 0 ++ ++#define DEFAULT_PORT_numOfOpenDmas(type) \ ++ (uint32_t)(((type) == e_FM_PORT_TYPE_RX_10G) ? 8 : \ ++ ((type) == e_FM_PORT_TYPE_TX_10G) ? 12 : \ ++ ((type) == e_FM_PORT_TYPE_RX) ? 2 : \ ++ ((type) == e_FM_PORT_TYPE_TX) ? 3 : \ ++ ((type) == e_FM_PORT_TYPE_OH_HOST_COMMAND) ? 2 : 4) ++ ++#define DEFAULT_PORT_extraNumOfOpenDmas(type) 0 ++ ++#define DEFAULT_PORT_numOfFifoBufs(type) \ ++ (uint32_t) (((type) == e_FM_PORT_TYPE_RX_10G) ? 96 : \ ++ ((type) == e_FM_PORT_TYPE_TX_10G) ? 64 : \ ++ ((type) == e_FM_PORT_TYPE_OH_HOST_COMMAND) ? 10 : 50) ++ ++#define DEFAULT_PORT_extraNumOfFifoBufs 0 ++ ++#endif /* (DPAA_VERSION < 11) */ ++ ++#define DEFAULT_PORT_txBdRingLength 16 ++#define DEFAULT_PORT_rxBdRingLength 128 ++#define DEFAULT_PORT_ImfwExtStructsMemId 0 ++#define DEFAULT_PORT_ImfwExtStructsMemAttr MEMORY_ATTR_CACHEABLE ++ ++#define FM_PORT_CG_REG_NUM(_cgId) (((FM_PORT_NUM_OF_CONGESTION_GRPS/32)-1)-_cgId/32) ++ ++/**************************************************************************//** ++ @Collection PCD Engines ++*//***************************************************************************/ ++typedef uint32_t fmPcdEngines_t; /**< options as defined below: */ ++ ++#define FM_PCD_NONE 0 /**< No PCD Engine indicated */ ++#define FM_PCD_PRS 0x80000000 /**< Parser indicated */ ++#define FM_PCD_KG 0x40000000 /**< Keygen indicated */ ++#define FM_PCD_CC 0x20000000 /**< Coarse classification indicated */ ++#define FM_PCD_PLCR 0x10000000 /**< Policer indicated */ ++#define FM_PCD_MANIP 0x08000000 /**< Manipulation indicated */ ++/* @} */ ++ ++#define FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS 8 ++#define FM_PORT_MAX_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS 256 ++#define FM_PORT_CG_REG_NUM(_cgId) (((FM_PORT_NUM_OF_CONGESTION_GRPS/32)-1)-_cgId/32) ++ ++#define FM_OH_PORT_ID 0 ++ ++/***********************************************************************/ ++/* SW parser OFFLOAD labels (offsets) */ ++/***********************************************************************/ ++#if (DPAA_VERSION == 10) ++#define OFFLOAD_SW_PATCH_IPv4_IPR_LABEL 0x300 ++#define OFFLOAD_SW_PATCH_IPv6_IPR_LABEL 0x325 ++#define OFFLOAD_SW_PATCH_IPv6_IPF_LABEL 0x325 ++#else ++#define OFFLOAD_SW_PATCH_IPv4_IPR_LABEL 0x100 ++/* Will be used for: ++ * 1. identify fragments ++ * 2. udp-lite ++ */ ++#define OFFLOAD_SW_PATCH_IPv6_IPR_LABEL 0x146 ++/* Will be used for: ++ * 1. will identify the fragmentable area ++ * 2. udp-lite ++ */ ++#define OFFLOAD_SW_PATCH_IPv6_IPF_LABEL 0x261 ++#define OFFLOAD_SW_PATCH_CAPWAP_LABEL 0x38d ++#endif /* (DPAA_VERSION == 10) */ ++ ++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) ++#define UDP_LITE_SW_PATCH_LABEL 0x2E0 ++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ ++ ++ ++/**************************************************************************//** ++ @Description Memory Mapped Registers ++*//***************************************************************************/ ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(push,1) ++#endif /* defined(__MWERKS__) && ... */ ++ ++typedef struct ++{ ++ volatile uint32_t fmbm_rcfg; /**< Rx Configuration */ ++ volatile uint32_t fmbm_rst; /**< Rx Status */ ++ volatile uint32_t fmbm_rda; /**< Rx DMA attributes*/ ++ volatile uint32_t fmbm_rfp; /**< Rx FIFO Parameters*/ ++ volatile uint32_t fmbm_rfed; /**< Rx Frame End Data*/ ++ volatile uint32_t fmbm_ricp; /**< Rx Internal Context Parameters*/ ++ volatile uint32_t fmbm_rim; /**< Rx Internal Buffer Margins*/ ++ volatile uint32_t fmbm_rebm; /**< Rx External Buffer Margins*/ ++ volatile uint32_t fmbm_rfne; /**< Rx Frame Next Engine*/ ++ volatile uint32_t fmbm_rfca; /**< Rx Frame Command Attributes.*/ ++ volatile uint32_t fmbm_rfpne; /**< Rx Frame Parser Next Engine*/ ++ volatile uint32_t fmbm_rpso; /**< Rx Parse Start Offset*/ ++ volatile uint32_t fmbm_rpp; /**< Rx Policer Profile */ ++ volatile uint32_t fmbm_rccb; /**< Rx Coarse Classification Base */ ++ volatile uint32_t fmbm_reth; /**< Rx Excessive Threshold */ ++ volatile uint32_t reserved1[0x01];/**< (0x03C) */ ++ volatile uint32_t fmbm_rprai[FM_PORT_PRS_RESULT_NUM_OF_WORDS]; ++ /**< Rx Parse Results Array Initialization*/ ++ volatile uint32_t fmbm_rfqid; /**< Rx Frame Queue ID*/ ++ volatile uint32_t fmbm_refqid; /**< Rx Error Frame Queue ID*/ ++ volatile uint32_t fmbm_rfsdm; /**< Rx Frame Status Discard Mask*/ ++ volatile uint32_t fmbm_rfsem; /**< Rx Frame Status Error Mask*/ ++ volatile uint32_t fmbm_rfene; /**< Rx Frame Enqueue Next Engine */ ++ volatile uint32_t reserved2[0x02];/**< (0x074-0x078) */ ++ volatile uint32_t fmbm_rcmne; /**< Rx Frame Continuous Mode Next Engine */ ++ volatile uint32_t reserved3[0x20];/**< (0x080 0x0FF) */ ++ volatile uint32_t fmbm_ebmpi[FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS]; ++ /**< Buffer Manager pool Information-*/ ++ volatile uint32_t fmbm_acnt[FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS]; ++ /**< Allocate Counter-*/ ++ volatile uint32_t reserved4[0x08]; ++ /**< 0x130/0x140 - 0x15F reserved -*/ ++ volatile uint32_t fmbm_rcgm[FM_PORT_MAX_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS/32]; ++ /**< Congestion Group Map*/ ++ volatile uint32_t fmbm_rmpd; /**< BM Pool Depletion */ ++ volatile uint32_t reserved5[0x1F];/**< (0x184 0x1FF) */ ++ volatile uint32_t fmbm_rstc; /**< Rx Statistics Counters*/ ++ volatile uint32_t fmbm_rfrc; /**< Rx Frame Counter*/ ++ volatile uint32_t fmbm_rfbc; /**< Rx Bad Frames Counter*/ ++ volatile uint32_t fmbm_rlfc; /**< Rx Large Frames Counter*/ ++ volatile uint32_t fmbm_rffc; /**< Rx Filter Frames Counter*/ ++ volatile uint32_t fmbm_rfcd; /**< Rx Frame Discard Counter*/ ++ volatile uint32_t fmbm_rfldec; /**< Rx Frames List DMA Error Counter*/ ++ volatile uint32_t fmbm_rodc; /**< Rx Out of Buffers Discard Counter-*/ ++ volatile uint32_t fmbm_rbdc; /**< Rx Buffers Deallocate Counter-*/ ++ volatile uint32_t fmbm_rpec; /**< Rx RX Prepare to enqueue Counter-*/ ++ volatile uint32_t reserved6[0x16];/**< (0x228 0x27F) */ ++ volatile uint32_t fmbm_rpc; /**< Rx Performance Counters*/ ++ volatile uint32_t fmbm_rpcp; /**< Rx Performance Count Parameters*/ ++ volatile uint32_t fmbm_rccn; /**< Rx Cycle Counter*/ ++ volatile uint32_t fmbm_rtuc; /**< Rx Tasks Utilization Counter*/ ++ volatile uint32_t fmbm_rrquc; /**< Rx Receive Queue Utilization Counter*/ ++ volatile uint32_t fmbm_rduc; /**< Rx DMA Utilization Counter*/ ++ volatile uint32_t fmbm_rfuc; /**< Rx FIFO Utilization Counter*/ ++ volatile uint32_t fmbm_rpac; /**< Rx Pause Activation Counter*/ ++ volatile uint32_t reserved7[0x18];/**< (0x2A0-0x2FF) */ ++ volatile uint32_t fmbm_rdcfg[0x3];/**< Rx Debug-*/ ++ volatile uint32_t fmbm_rgpr; /**< Rx General Purpose Register. */ ++ volatile uint32_t reserved8[0x3a];/**< (0x310-0x3FF) */ ++} t_FmPortRxBmiRegs; ++ ++typedef struct ++{ ++ volatile uint32_t fmbm_tcfg; /**< Tx Configuration */ ++ volatile uint32_t fmbm_tst; /**< Tx Status */ ++ volatile uint32_t fmbm_tda; /**< Tx DMA attributes */ ++ volatile uint32_t fmbm_tfp; /**< Tx FIFO Parameters */ ++ volatile uint32_t fmbm_tfed; /**< Tx Frame End Data */ ++ volatile uint32_t fmbm_ticp; /**< Tx Internal Context Parameters */ ++ volatile uint32_t fmbm_tfdne; /**< Tx Frame Dequeue Next Engine. */ ++ volatile uint32_t fmbm_tfca; /**< Tx Frame Command attribute. */ ++ volatile uint32_t fmbm_tcfqid; /**< Tx Confirmation Frame Queue ID. */ ++ volatile uint32_t fmbm_tfeqid; /**< Tx Frame Error Queue ID */ ++ volatile uint32_t fmbm_tfene; /**< Tx Frame Enqueue Next Engine */ ++ volatile uint32_t fmbm_trlmts; /**< Tx Rate Limiter Scale */ ++ volatile uint32_t fmbm_trlmt; /**< Tx Rate Limiter */ ++ volatile uint32_t fmbm_tccb; /**< Tx Coarse Classification Base */ ++ volatile uint32_t reserved0[0x0e];/**< (0x038-0x070) */ ++ volatile uint32_t fmbm_tfne; /**< Tx Frame Next Engine */ ++ volatile uint32_t fmbm_tpfcm[0x02];/**< Tx Priority based Flow Control (PFC) Mapping */ ++ volatile uint32_t fmbm_tcmne; /**< Tx Frame Continuous Mode Next Engine */ ++ volatile uint32_t reserved2[0x60];/**< (0x080-0x200) */ ++ volatile uint32_t fmbm_tstc; /**< Tx Statistics Counters */ ++ volatile uint32_t fmbm_tfrc; /**< Tx Frame Counter */ ++ volatile uint32_t fmbm_tfdc; /**< Tx Frames Discard Counter */ ++ volatile uint32_t fmbm_tfledc; /**< Tx Frame Length error discard counter */ ++ volatile uint32_t fmbm_tfufdc; /**< Tx Frame unsupported format discard Counter */ ++ volatile uint32_t fmbm_tbdc; /**< Tx Buffers Deallocate Counter */ ++ volatile uint32_t reserved3[0x1A];/**< (0x218-0x280) */ ++ volatile uint32_t fmbm_tpc; /**< Tx Performance Counters*/ ++ volatile uint32_t fmbm_tpcp; /**< Tx Performance Count Parameters*/ ++ volatile uint32_t fmbm_tccn; /**< Tx Cycle Counter*/ ++ volatile uint32_t fmbm_ttuc; /**< Tx Tasks Utilization Counter*/ ++ volatile uint32_t fmbm_ttcquc; /**< Tx Transmit Confirm Queue Utilization Counter*/ ++ volatile uint32_t fmbm_tduc; /**< Tx DMA Utilization Counter*/ ++ volatile uint32_t fmbm_tfuc; /**< Tx FIFO Utilization Counter*/ ++ volatile uint32_t reserved4[16]; /**< (0x29C-0x2FF) */ ++ volatile uint32_t fmbm_tdcfg[0x3];/**< Tx Debug-*/ ++ volatile uint32_t fmbm_tgpr; /**< O/H General Purpose Register */ ++ volatile uint32_t reserved5[0x3a];/**< (0x310-0x3FF) */ ++} t_FmPortTxBmiRegs; ++ ++typedef struct ++{ ++ volatile uint32_t fmbm_ocfg; /**< O/H Configuration */ ++ volatile uint32_t fmbm_ost; /**< O/H Status */ ++ volatile uint32_t fmbm_oda; /**< O/H DMA attributes */ ++ volatile uint32_t fmbm_oicp; /**< O/H Internal Context Parameters */ ++ volatile uint32_t fmbm_ofdne; /**< O/H Frame Dequeue Next Engine */ ++ volatile uint32_t fmbm_ofne; /**< O/H Frame Next Engine */ ++ volatile uint32_t fmbm_ofca; /**< O/H Frame Command Attributes. */ ++ volatile uint32_t fmbm_ofpne; /**< O/H Frame Parser Next Engine */ ++ volatile uint32_t fmbm_opso; /**< O/H Parse Start Offset */ ++ volatile uint32_t fmbm_opp; /**< O/H Policer Profile */ ++ volatile uint32_t fmbm_occb; /**< O/H Coarse Classification base */ ++ volatile uint32_t fmbm_oim; /**< O/H Internal margins*/ ++ volatile uint32_t fmbm_ofp; /**< O/H Fifo Parameters*/ ++ volatile uint32_t fmbm_ofed; /**< O/H Frame End Data*/ ++ volatile uint32_t reserved0[2]; /**< (0x038 - 0x03F) */ ++ volatile uint32_t fmbm_oprai[FM_PORT_PRS_RESULT_NUM_OF_WORDS]; ++ /**< O/H Parse Results Array Initialization */ ++ volatile uint32_t fmbm_ofqid; /**< O/H Frame Queue ID */ ++ volatile uint32_t fmbm_oefqid; /**< O/H Error Frame Queue ID */ ++ volatile uint32_t fmbm_ofsdm; /**< O/H Frame Status Discard Mask */ ++ volatile uint32_t fmbm_ofsem; /**< O/H Frame Status Error Mask */ ++ volatile uint32_t fmbm_ofene; /**< O/H Frame Enqueue Next Engine */ ++ volatile uint32_t fmbm_orlmts; /**< O/H Rate Limiter Scale */ ++ volatile uint32_t fmbm_orlmt; /**< O/H Rate Limiter */ ++ volatile uint32_t fmbm_ocmne; /**< O/H Continuous Mode Next Engine */ ++ volatile uint32_t reserved1[0x20];/**< (0x080 - 0x0FF) */ ++ volatile uint32_t fmbm_oebmpi[2]; /**< Buffer Manager Observed Pool Information */ ++ volatile uint32_t reserved2[0x16];/**< (0x108 - 0x15F) */ ++ volatile uint32_t fmbm_ocgm; /**< Observed Congestion Group Map */ ++ volatile uint32_t reserved3[0x7]; /**< (0x164 - 0x17F) */ ++ volatile uint32_t fmbm_ompd; /**< Observed BMan Pool Depletion */ ++ volatile uint32_t reserved4[0x1F];/**< (0x184 - 0x1FF) */ ++ volatile uint32_t fmbm_ostc; /**< O/H Statistics Counters */ ++ volatile uint32_t fmbm_ofrc; /**< O/H Frame Counter */ ++ volatile uint32_t fmbm_ofdc; /**< O/H Frames Discard Counter */ ++ volatile uint32_t fmbm_ofledc; /**< O/H Frames Length Error Discard Counter */ ++ volatile uint32_t fmbm_ofufdc; /**< O/H Frames Unsupported Format Discard Counter */ ++ volatile uint32_t fmbm_offc; /**< O/H Filter Frames Counter */ ++ volatile uint32_t fmbm_ofwdc; /**< - Rx Frames WRED Discard Counter */ ++ volatile uint32_t fmbm_ofldec; /**< O/H Frames List DMA Error Counter */ ++ volatile uint32_t fmbm_obdc; /**< O/H Buffers Deallocate Counter */ ++ volatile uint32_t fmbm_oodc; /**< O/H Out of Buffers Discard Counter */ ++ volatile uint32_t fmbm_opec; /**< O/H Prepare to enqueue Counter */ ++ volatile uint32_t reserved5[0x15];/**< ( - 0x27F) */ ++ volatile uint32_t fmbm_opc; /**< O/H Performance Counters */ ++ volatile uint32_t fmbm_opcp; /**< O/H Performance Count Parameters */ ++ volatile uint32_t fmbm_occn; /**< O/H Cycle Counter */ ++ volatile uint32_t fmbm_otuc; /**< O/H Tasks Utilization Counter */ ++ volatile uint32_t fmbm_oduc; /**< O/H DMA Utilization Counter */ ++ volatile uint32_t fmbm_ofuc; /**< O/H FIFO Utilization Counter */ ++ volatile uint32_t reserved6[26]; /**< (0x298-0x2FF) */ ++ volatile uint32_t fmbm_odcfg[0x3];/**< O/H Debug (only 1 in P1023) */ ++ volatile uint32_t fmbm_ogpr; /**< O/H General Purpose Register. */ ++ volatile uint32_t reserved7[0x3a];/**< (0x310 0x3FF) */ ++} t_FmPortOhBmiRegs; ++ ++typedef union ++{ ++ t_FmPortRxBmiRegs rxPortBmiRegs; ++ t_FmPortTxBmiRegs txPortBmiRegs; ++ t_FmPortOhBmiRegs ohPortBmiRegs; ++} u_FmPortBmiRegs; ++ ++typedef struct ++{ ++ volatile uint32_t reserved1[2]; /**< 0xn024 - 0x02B */ ++ volatile uint32_t fmqm_pndn; /**< PortID n Dequeue NIA Register */ ++ volatile uint32_t fmqm_pndc; /**< PortID n Dequeue Config Register */ ++ volatile uint32_t fmqm_pndtfc; /**< PortID n Dequeue Total Frame Counter */ ++ volatile uint32_t fmqm_pndfdc; /**< PortID n Dequeue FQID from Default Counter */ ++ volatile uint32_t fmqm_pndcc; /**< PortID n Dequeue Confirm Counter */ ++} t_FmPortNonRxQmiRegs; ++ ++typedef struct ++{ ++ volatile uint32_t fmqm_pnc; /**< PortID n Configuration Register */ ++ volatile uint32_t fmqm_pns; /**< PortID n Status Register */ ++ volatile uint32_t fmqm_pnts; /**< PortID n Task Status Register */ ++ volatile uint32_t reserved0[4]; /**< 0xn00C - 0xn01B */ ++ volatile uint32_t fmqm_pnen; /**< PortID n Enqueue NIA Register */ ++ volatile uint32_t fmqm_pnetfc; /**< PortID n Enqueue Total Frame Counter */ ++ t_FmPortNonRxQmiRegs nonRxQmiRegs; /**< Registers for Tx Hc & Op ports */ ++} t_FmPortQmiRegs; ++ ++typedef struct ++{ ++ struct ++ { ++ volatile uint32_t softSeqAttach; /**< Soft Sequence Attachment */ ++ volatile uint32_t lcv; /**< Line-up Enable Confirmation Mask */ ++ } hdrs[FM_PCD_PRS_NUM_OF_HDRS]; ++ volatile uint32_t reserved0[0xde]; ++ volatile uint32_t pcac; /**< Parse Internal Memory Configuration Access Control Register */ ++ volatile uint32_t pctpid; /**< Parse Internal Memory Configured TPID Register */ ++} t_FmPortPrsRegs; ++ ++/**************************************************************************//* ++ @Description Basic buffer descriptor (BD) structure ++*//***************************************************************************/ ++typedef _Packed struct ++{ ++ volatile uint16_t status; ++ volatile uint16_t length; ++ volatile uint8_t reserved0[0x6]; ++ volatile uint8_t reserved1[0x1]; ++ volatile t_FmPhysAddr buff; ++} _PackedType t_FmImBd; ++ ++typedef _Packed struct ++{ ++ volatile uint16_t gen; /**< tbd */ ++ volatile uint8_t reserved0[0x1]; ++ volatile t_FmPhysAddr bdRingBase; /**< tbd */ ++ volatile uint16_t bdRingSize; /**< tbd */ ++ volatile uint16_t offsetIn; /**< tbd */ ++ volatile uint16_t offsetOut; /**< tbd */ ++ volatile uint8_t reserved1[0x12]; /**< 0x0e - 0x1f */ ++} _PackedType t_FmPortImQd; ++ ++typedef _Packed struct ++{ ++ volatile uint32_t mode; /**< Mode register */ ++ volatile uint32_t rxQdPtr; /**< tbd */ ++ volatile uint32_t txQdPtr; /**< tbd */ ++ volatile uint16_t mrblr; /**< tbd */ ++ volatile uint16_t rxQdBsyCnt; /**< tbd */ ++ volatile uint8_t reserved0[0x10]; /**< 0x10 - 0x1f */ ++ t_FmPortImQd rxQd; ++ t_FmPortImQd txQd; ++ volatile uint8_t reserved1[0xa0]; /**< 0x60 - 0xff */ ++} _PackedType t_FmPortImPram; ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(pop) ++#endif /* defined(__MWERKS__) && ... */ ++ ++ ++/**************************************************************************//** ++ @Description Registers bit fields ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description BMI defines ++*//***************************************************************************/ ++#if (DPAA_VERSION >= 11) ++#define BMI_SP_ID_MASK 0xff000000 ++#define BMI_SP_ID_SHIFT 24 ++#define BMI_SP_EN 0x01000000 ++#endif /* (DPAA_VERSION >= 11) */ ++ ++#define BMI_PORT_CFG_EN 0x80000000 ++#define BMI_PORT_CFG_EN_MACSEC 0x00800000 ++#define BMI_PORT_CFG_FDOVR 0x02000000 ++#define BMI_PORT_CFG_IM 0x01000000 ++#define BMI_PORT_CFG_AM 0x00000040 ++#define BMI_PORT_STATUS_BSY 0x80000000 ++#define BMI_COUNTERS_EN 0x80000000 ++ ++#define BMI_PORT_RFNE_FRWD_DCL4C 0x10000000 ++#define BMI_PORT_RFNE_FRWD_RPD 0x40000000 ++#define BMI_RFNE_FDCS_MASK 0xFF000000 ++#define BMI_RFNE_HXS_MASK 0x000000FF ++ ++#define BMI_CMD_MR_LEAC 0x00200000 ++#define BMI_CMD_MR_SLEAC 0x00100000 ++#define BMI_CMD_MR_MA 0x00080000 ++#define BMI_CMD_MR_DEAS 0x00040000 ++#define BMI_CMD_RX_MR_DEF (BMI_CMD_MR_LEAC | \ ++ BMI_CMD_MR_SLEAC | \ ++ BMI_CMD_MR_MA | \ ++ BMI_CMD_MR_DEAS) ++#define BMI_CMD_ATTR_ORDER 0x80000000 ++#define BMI_CMD_ATTR_SYNC 0x02000000 ++#define BMI_CMD_ATTR_MODE_MISS_ALLIGN_ADDR_EN 0x00080000 ++#define BMI_CMD_ATTR_MACCMD_MASK 0x0000ff00 ++#define BMI_CMD_ATTR_MACCMD_OVERRIDE 0x00008000 ++#define BMI_CMD_ATTR_MACCMD_SECURED 0x00001000 ++#define BMI_CMD_ATTR_MACCMD_SC_MASK 0x00000f00 ++ ++#define BMI_EXT_BUF_POOL_ID_MASK 0x003F0000 ++#define BMI_STATUS_RX_MASK_UNUSED (uint32_t)(~(FM_PORT_FRM_ERR_DMA | \ ++ FM_PORT_FRM_ERR_PHYSICAL | \ ++ FM_PORT_FRM_ERR_SIZE | \ ++ FM_PORT_FRM_ERR_CLS_DISCARD | \ ++ FM_PORT_FRM_ERR_EXTRACTION | \ ++ FM_PORT_FRM_ERR_NO_SCHEME | \ ++ FM_PORT_FRM_ERR_COLOR_RED | \ ++ FM_PORT_FRM_ERR_COLOR_YELLOW | \ ++ FM_PORT_FRM_ERR_ILL_PLCR | \ ++ FM_PORT_FRM_ERR_PLCR_FRAME_LEN | \ ++ FM_PORT_FRM_ERR_PRS_TIMEOUT | \ ++ FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | \ ++ FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED | \ ++ FM_PORT_FRM_ERR_PRS_HDR_ERR | \ ++ FM_PORT_FRM_ERR_IPRE | \ ++ FM_PORT_FRM_ERR_IPR_NCSP | \ ++ FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW)) ++ ++#define BMI_STATUS_OP_MASK_UNUSED (uint32_t)(BMI_STATUS_RX_MASK_UNUSED & \ ++ ~(FM_PORT_FRM_ERR_LENGTH | \ ++ FM_PORT_FRM_ERR_NON_FM | \ ++ FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT)) ++ ++#define BMI_RATE_LIMIT_EN 0x80000000 ++#define BMI_RATE_LIMIT_BURST_SIZE_GRAN 0x80000000 ++#define BMI_RATE_LIMIT_SCALE_BY_2 0x00000001 ++#define BMI_RATE_LIMIT_SCALE_BY_4 0x00000002 ++#define BMI_RATE_LIMIT_SCALE_BY_8 0x00000003 ++ ++#define BMI_RX_FIFO_THRESHOLD_BC 0x80000000 ++ ++#define BMI_PRS_RESULT_HIGH 0x00000000 ++#define BMI_PRS_RESULT_LOW 0xFFFFFFFF ++ ++ ++#define RX_ERRS_TO_ENQ (FM_PORT_FRM_ERR_DMA | \ ++ FM_PORT_FRM_ERR_PHYSICAL | \ ++ FM_PORT_FRM_ERR_SIZE | \ ++ FM_PORT_FRM_ERR_EXTRACTION | \ ++ FM_PORT_FRM_ERR_NO_SCHEME | \ ++ FM_PORT_FRM_ERR_ILL_PLCR | \ ++ FM_PORT_FRM_ERR_PLCR_FRAME_LEN | \ ++ FM_PORT_FRM_ERR_PRS_TIMEOUT | \ ++ FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | \ ++ FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED | \ ++ FM_PORT_FRM_ERR_PRS_HDR_ERR | \ ++ FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW | \ ++ FM_PORT_FRM_ERR_IPRE) ++ ++#define OP_ERRS_TO_ENQ (RX_ERRS_TO_ENQ | \ ++ FM_PORT_FRM_ERR_LENGTH | \ ++ FM_PORT_FRM_ERR_NON_FM | \ ++ FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT) ++ ++ ++#define BMI_RX_FIFO_PRI_ELEVATION_MASK 0x03FF0000 ++#define BMI_RX_FIFO_THRESHOLD_MASK 0x000003FF ++#define BMI_TX_FIFO_MIN_FILL_MASK 0x03FF0000 ++#define BMI_FIFO_PIPELINE_DEPTH_MASK 0x0000F000 ++#define BMI_TX_LOW_COMF_MASK 0x000003FF ++ ++/* shifts */ ++#define BMI_PORT_CFG_MS_SEL_SHIFT 16 ++#define BMI_DMA_ATTR_IC_CACHE_SHIFT FMAN_SP_DMA_ATTR_IC_CACHE_SHIFT ++#define BMI_DMA_ATTR_HDR_CACHE_SHIFT FMAN_SP_DMA_ATTR_HDR_CACHE_SHIFT ++#define BMI_DMA_ATTR_SG_CACHE_SHIFT FMAN_SP_DMA_ATTR_SG_CACHE_SHIFT ++ ++#define BMI_IM_FOF_SHIFT 28 ++#define BMI_PR_PORTID_SHIFT 24 ++ ++#define BMI_RX_FIFO_PRI_ELEVATION_SHIFT 16 ++#define BMI_RX_FIFO_THRESHOLD_SHIFT 0 ++ ++#define BMI_RX_FRAME_END_CS_IGNORE_SHIFT 24 ++#define BMI_RX_FRAME_END_CUT_SHIFT 16 ++ ++#define BMI_IC_SIZE_SHIFT FMAN_SP_IC_SIZE_SHIFT ++ ++#define BMI_INT_BUF_MARG_SHIFT 28 ++ ++#define BMI_EXT_BUF_MARG_END_SHIFT FMAN_SP_EXT_BUF_MARG_END_SHIFT ++ ++#define BMI_CMD_ATTR_COLOR_SHIFT 26 ++#define BMI_CMD_ATTR_COM_MODE_SHIFT 16 ++#define BMI_CMD_ATTR_MACCMD_SHIFT 8 ++#define BMI_CMD_ATTR_MACCMD_OVERRIDE_SHIFT 15 ++#define BMI_CMD_ATTR_MACCMD_SECURED_SHIFT 12 ++#define BMI_CMD_ATTR_MACCMD_SC_SHIFT 8 ++ ++#define BMI_POOL_DEP_NUM_OF_POOLS_VECTOR_SHIFT 24 ++ ++#define BMI_TX_FIFO_MIN_FILL_SHIFT 16 ++#define BMI_TX_LOW_COMF_SHIFT 0 ++ ++#define BMI_PERFORMANCE_TASK_COMP_SHIFT 24 ++#define BMI_PERFORMANCE_PORT_COMP_SHIFT 16 ++#define BMI_PERFORMANCE_DMA_COMP_SHIFT 12 ++#define BMI_PERFORMANCE_FIFO_COMP_SHIFT 0 ++ ++#define BMI_MAX_BURST_SHIFT 16 ++#define BMI_COUNT_RATE_UNIT_SHIFT 16 ++ ++/* sizes */ ++#define FRAME_END_DATA_SIZE 16 ++#define FRAME_OFFSET_UNITS 16 ++#define MIN_TX_INT_OFFSET 16 ++#define MAX_FRAME_OFFSET 64 ++#define MAX_FIFO_PIPELINE_DEPTH 8 ++#define MAX_PERFORMANCE_TASK_COMP 64 ++#define MAX_PERFORMANCE_TX_QUEUE_COMP 8 ++#define MAX_PERFORMANCE_RX_QUEUE_COMP 64 ++#define MAX_PERFORMANCE_DMA_COMP 16 ++#define MAX_NUM_OF_TASKS 64 ++#define MAX_NUM_OF_EXTRA_TASKS 8 ++#define MAX_NUM_OF_DMAS 16 ++#define MAX_NUM_OF_EXTRA_DMAS 8 ++#define MAX_BURST_SIZE 1024 ++#define MIN_NUM_OF_OP_DMAS 2 ++ ++ ++/**************************************************************************//** ++ @Description QMI defines ++*//***************************************************************************/ ++/* masks */ ++#define QMI_PORT_CFG_EN 0x80000000 ++#define QMI_PORT_CFG_EN_COUNTERS 0x10000000 ++#define QMI_PORT_STATUS_DEQ_TNUM_BSY 0x80000000 ++#define QMI_PORT_STATUS_DEQ_FD_BSY 0x20000000 ++ ++#define QMI_DEQ_CFG_PREFETCH_NO_TNUM 0x02000000 ++#define QMI_DEQ_CFG_PREFETCH_WAITING_TNUM 0 ++#define QMI_DEQ_CFG_PREFETCH_1_FRAME 0 ++#define QMI_DEQ_CFG_PREFETCH_3_FRAMES 0x01000000 ++ ++#define QMI_DEQ_CFG_PRI 0x80000000 ++#define QMI_DEQ_CFG_TYPE1 0x10000000 ++#define QMI_DEQ_CFG_TYPE2 0x20000000 ++#define QMI_DEQ_CFG_TYPE3 0x30000000 ++ ++#define QMI_DEQ_CFG_SUBPORTAL_MASK 0x1f ++#define QMI_DEQ_CFG_SUBPORTAL_SHIFT 20 ++ ++/**************************************************************************//** ++ @Description PARSER defines ++*//***************************************************************************/ ++/* masks */ ++#define PRS_HDR_ERROR_DIS 0x00000800 ++#define PRS_HDR_SW_PRS_EN 0x00000400 ++#define PRS_CP_OFFSET_MASK 0x0000000F ++#define PRS_TPID1_MASK 0xFFFF0000 ++#define PRS_TPID2_MASK 0x0000FFFF ++#define PRS_TPID_DFLT 0x91009100 ++ ++#define PRS_HDR_MPLS_LBL_INTER_EN 0x00200000 ++#define PRS_HDR_IPV6_ROUTE_HDR_EN 0x00008000 ++#define PRS_HDR_PPPOE_MTU_CHECK_EN 0x80000000 ++#define PRS_HDR_UDP_PAD_REMOVAL 0x80000000 ++#define PRS_HDR_TCP_PAD_REMOVAL 0x80000000 ++#define PRS_CAC_STOP 0x00000001 ++#define PRS_CAC_ACTIVE 0x00000100 ++ ++/* shifts */ ++#define PRS_PCTPID_SHIFT 16 ++#define PRS_HDR_MPLS_NEXT_HDR_SHIFT 22 ++#define PRS_HDR_ETH_BC_SHIFT 28 ++#define PRS_HDR_ETH_MC_SHIFT 24 ++#define PRS_HDR_VLAN_STACKED_SHIFT 16 ++#define PRS_HDR_MPLS_STACKED_SHIFT 16 ++#define PRS_HDR_IPV4_1_BC_SHIFT 28 ++#define PRS_HDR_IPV4_1_MC_SHIFT 24 ++#define PRS_HDR_IPV4_2_UC_SHIFT 20 ++#define PRS_HDR_IPV4_2_MC_BC_SHIFT 16 ++#define PRS_HDR_IPV6_1_MC_SHIFT 24 ++#define PRS_HDR_IPV6_2_UC_SHIFT 20 ++#define PRS_HDR_IPV6_2_MC_SHIFT 16 ++ ++#define PRS_HDR_ETH_BC_MASK 0x0fffffff ++#define PRS_HDR_ETH_MC_MASK 0xf0ffffff ++#define PRS_HDR_VLAN_STACKED_MASK 0xfff0ffff ++#define PRS_HDR_MPLS_STACKED_MASK 0xfff0ffff ++#define PRS_HDR_IPV4_1_BC_MASK 0x0fffffff ++#define PRS_HDR_IPV4_1_MC_MASK 0xf0ffffff ++#define PRS_HDR_IPV4_2_UC_MASK 0xff0fffff ++#define PRS_HDR_IPV4_2_MC_BC_MASK 0xfff0ffff ++#define PRS_HDR_IPV6_1_MC_MASK 0xf0ffffff ++#define PRS_HDR_IPV6_2_UC_MASK 0xff0fffff ++#define PRS_HDR_IPV6_2_MC_MASK 0xfff0ffff ++ ++/* others */ ++#define PRS_HDR_ENTRY_SIZE 8 ++#define DEFAULT_CLS_PLAN_VECTOR 0xFFFFFFFF ++ ++#define IPSEC_SW_PATCH_START 0x20 ++#define SCTP_SW_PATCH_START 0x4D ++#define DCCP_SW_PATCH_START 0x41 ++ ++/**************************************************************************//** ++ @Description IM defines ++*//***************************************************************************/ ++#define BD_R_E 0x80000000 ++#define BD_L 0x08000000 ++ ++#define BD_RX_CRE 0x00080000 ++#define BD_RX_FTL 0x00040000 ++#define BD_RX_FTS 0x00020000 ++#define BD_RX_OV 0x00010000 ++ ++#define BD_RX_ERRORS (BD_RX_CRE | BD_RX_FTL | BD_RX_FTS | BD_RX_OV) ++ ++#define FM_IM_SIZEOF_BD sizeof(t_FmImBd) ++ ++#define BD_STATUS_MASK 0xffff0000 ++#define BD_LENGTH_MASK 0x0000ffff ++ ++#define BD_STATUS_AND_LENGTH_SET(bd, val) WRITE_UINT32(*(volatile uint32_t*)(bd), (val)) ++ ++#define BD_STATUS_AND_LENGTH(bd) GET_UINT32(*(volatile uint32_t*)(bd)) ++ ++#define BD_GET(id) &p_FmPort->im.p_BdRing[id] ++ ++#define IM_ILEGAL_BD_ID 0xffff ++ ++/* others */ ++#define IM_PRAM_ALIGN 0x100 ++ ++/* masks */ ++#define IM_MODE_GBL 0x20000000 ++#define IM_MODE_BO_MASK 0x18000000 ++#define IM_MODE_BO_SHIFT 3 ++#define IM_MODE_GRC_STP 0x00800000 ++ ++#define IM_MODE_SET_BO(val) (uint32_t)((val << (31-IM_MODE_BO_SHIFT)) & IM_MODE_BO_MASK) ++ ++#define IM_RXQD_BSYINTM 0x0008 ++#define IM_RXQD_RXFINTM 0x0010 ++#define IM_RXQD_FPMEVT_SEL_MASK 0x0003 ++ ++#define IM_EV_BSY 0x40000000 ++#define IM_EV_RX 0x80000000 ++ ++ ++/**************************************************************************//** ++ @Description Additional defines ++*//***************************************************************************/ ++ ++typedef struct { ++ t_Handle h_FmMuram; ++ t_FmPortImPram *p_FmPortImPram; ++ uint8_t fwExtStructsMemId; ++ uint32_t fwExtStructsMemAttr; ++ uint16_t bdRingSize; ++ t_FmImBd *p_BdRing; ++ t_Handle *p_BdShadow; ++ uint16_t currBdId; ++ uint16_t firstBdOfFrameId; ++ ++ /* Rx port parameters */ ++ uint8_t dataMemId; /**< Memory partition ID for data buffers */ ++ uint32_t dataMemAttributes; /**< Memory attributes for data buffers */ ++ t_BufferPoolInfo rxPool; ++ uint16_t mrblr; ++ uint16_t rxFrameAccumLength; ++ t_FmPortImRxStoreCallback *f_RxStore; ++ ++ /* Tx port parameters */ ++ uint32_t txFirstBdStatus; ++ t_FmPortImTxConfCallback *f_TxConf; ++} t_FmMacIm; ++ ++ ++typedef struct { ++ struct fman_port_cfg dfltCfg; ++ uint32_t dfltFqid; ++ uint32_t confFqid; ++ uint32_t errFqid; ++ uintptr_t baseAddr; ++ uint8_t deqSubPortal; ++ bool deqHighPriority; ++ e_FmPortDeqType deqType; ++ e_FmPortDeqPrefetchOption deqPrefetchOption; ++ uint16_t deqByteCnt; ++ uint8_t cheksumLastBytesIgnore; ++ uint8_t cutBytesFromEnd; ++ t_FmBufPoolDepletion bufPoolDepletion; ++ uint8_t pipelineDepth; ++ uint16_t fifoLowComfLevel; ++ bool frmDiscardOverride; ++ bool enRateLimit; ++ t_FmPortRateLimit rateLimit; ++ e_FmPortDualRateLimiterScaleDown rateLimitDivider; ++ bool enBufPoolDepletion; ++ uint16_t liodnOffset; ++ uint16_t liodnBase; ++ t_FmExtPools extBufPools; ++ e_FmDmaSwapOption dmaSwapData; ++ e_FmDmaCacheOption dmaIntContextCacheAttr; ++ e_FmDmaCacheOption dmaHeaderCacheAttr; ++ e_FmDmaCacheOption dmaScatterGatherCacheAttr; ++ bool dmaReadOptimize; ++ bool dmaWriteOptimize; ++ uint32_t txFifoMinFillLevel; ++ uint32_t txFifoLowComfLevel; ++ uint32_t rxFifoPriElevationLevel; ++ uint32_t rxFifoThreshold; ++ t_FmSpBufMargins bufMargins; ++ t_FmSpIntContextDataCopy intContext; ++ bool syncReq; ++ e_FmPortColor color; ++ fmPortFrameErrSelect_t errorsToDiscard; ++ fmPortFrameErrSelect_t errorsToEnq; ++ bool forwardReuseIntContext; ++ t_FmBufferPrefixContent bufferPrefixContent; ++ t_FmBackupBmPools *p_BackupBmPools; ++ bool dontReleaseBuf; ++ bool setNumOfTasks; ++ bool setNumOfOpenDmas; ++ bool setSizeOfFifo; ++#if (DPAA_VERSION >= 11) ++ bool noScatherGather; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 ++ bool bcbWorkaround; ++#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */ ++} t_FmPortDriverParam; ++ ++ ++typedef struct t_FmPortRxPoolsParams ++{ ++ uint8_t numOfPools; ++ uint16_t secondLargestBufSize; ++ uint16_t largestBufSize; ++} t_FmPortRxPoolsParams; ++ ++typedef struct t_FmPortDsarVars { ++ t_Handle *autoResOffsets; ++ t_FmPortDsarTablesSizes *autoResMaxSizes; ++ uint32_t fmbm_tcfg; ++ uint32_t fmbm_tcmne; ++ uint32_t fmbm_rfne; ++ uint32_t fmbm_rfpne; ++ uint32_t fmbm_rcfg; ++ bool dsarEnabledParser; ++} t_FmPortDsarVars; ++typedef struct { ++ struct fman_port port; ++ t_Handle h_Fm; ++ t_Handle h_FmPcd; ++ t_Handle h_FmMuram; ++ t_FmRevisionInfo fmRevInfo; ++ uint8_t portId; ++ e_FmPortType portType; ++ int enabled; ++ char name[MODULE_NAME_SIZE]; ++ uint8_t hardwarePortId; ++ uint16_t fmClkFreq; ++ t_FmPortQmiRegs *p_FmPortQmiRegs; ++ u_FmPortBmiRegs *p_FmPortBmiRegs; ++ t_FmPortPrsRegs *p_FmPortPrsRegs; ++ fmPcdEngines_t pcdEngines; ++ uint32_t savedBmiNia; ++ uint8_t netEnvId; ++ uint32_t optArray[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)]; ++ uint32_t lcvs[FM_PCD_PRS_NUM_OF_HDRS]; ++ uint8_t privateInfo; ++ uint32_t schemesPerPortVector; ++ bool useClsPlan; ++ uint8_t clsPlanGrpId; ++ t_Handle ccTreeId; ++ t_Handle completeArg; ++ void (*f_Complete)(t_Handle arg); ++ t_FmSpBufferOffsets bufferOffsets; ++ /* Independent-Mode parameters support */ ++ bool imEn; ++ t_FmMacIm im; ++ volatile bool lock; ++ t_Handle h_Spinlock; ++ t_FmPortExceptionCallback *f_Exception; ++ t_Handle h_App; ++ uint8_t internalBufferOffset; ++ uint8_t fmanCtrlEventId; ++ uint32_t exceptions; ++ bool polling; ++ t_FmExtPools extBufPools; ++ uint32_t requiredAction; ++ uint32_t savedQmiPnen; ++ uint32_t savedBmiFene; ++ uint32_t savedBmiFpne; ++ uint32_t savedBmiCmne; ++ uint32_t savedBmiOfp; ++ uint32_t savedNonRxQmiRegsPndn; ++ uint32_t origNonRxQmiRegsPndn; ++ int savedPrsStartOffset; ++ bool includeInPrsStatistics; ++ uint16_t maxFrameLength; ++ t_FmFmanCtrl orFmanCtrl; ++ t_FmPortRsrc openDmas; ++ t_FmPortRsrc tasks; ++ t_FmPortRsrc fifoBufs; ++ t_FmPortRxPoolsParams rxPoolsParams; ++// bool explicitUserSizeOfFifo; ++ t_Handle h_IpReassemblyManip; ++ t_Handle h_CapwapReassemblyManip; ++ t_Handle h_ReassemblyTree; ++ uint64_t fmMuramPhysBaseAddr; ++#if (DPAA_VERSION >= 11) ++ bool vspe; ++ uint8_t dfltRelativeId; ++ e_FmPortGprFuncType gprFunc; ++ t_FmPcdCtrlParamsPage *p_ParamsPage; ++#endif /* (DPAA_VERSION >= 11) */ ++ t_FmPortDsarVars deepSleepVars; ++ t_FmPortDriverParam *p_FmPortDriverParam; ++} t_FmPort; ++ ++ ++void FmPortConfigIM (t_FmPort *p_FmPort, t_FmPortParams *p_FmPortParams); ++t_Error FmPortImCheckInitParameters(t_FmPort *p_FmPort); ++ ++t_Error FmPortImInit(t_FmPort *p_FmPort); ++void FmPortImFree(t_FmPort *p_FmPort); ++ ++t_Error FmPortImEnable (t_FmPort *p_FmPort); ++t_Error FmPortImDisable (t_FmPort *p_FmPort); ++t_Error FmPortImRx (t_FmPort *p_FmPort); ++ ++void FmPortSetMacsecLcv(t_Handle h_FmPort); ++void FmPortSetMacsecCmd(t_Handle h_FmPort, uint8_t dfltSci); ++ ++ ++t_Error FM_PORT_SetNumOfOpenDmas(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfOpenDmas); ++t_Error FM_PORT_SetNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks); ++t_Error FM_PORT_SetSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo); ++ ++static __inline__ uint8_t * BdBufferGet (t_PhysToVirt *f_PhysToVirt, t_FmImBd *p_Bd) ++{ ++ uint64_t physAddr = (uint64_t)((uint64_t)GET_UINT8(p_Bd->buff.high) << 32); ++ physAddr |= GET_UINT32(p_Bd->buff.low); ++ ++ return (uint8_t *)f_PhysToVirt((physAddress_t)(physAddr)); ++} ++ ++static __inline__ void SET_ADDR(volatile t_FmPhysAddr *fmPhysAddr, uint64_t value) ++{ ++ WRITE_UINT8(fmPhysAddr->high,(uint8_t)((value & 0x000000ff00000000LL) >> 32)); ++ WRITE_UINT32(fmPhysAddr->low,(uint32_t)value); ++} ++ ++static __inline__ void BdBufferSet(t_VirtToPhys *f_VirtToPhys, t_FmImBd *p_Bd, uint8_t *p_Buffer) ++{ ++ uint64_t physAddr = (uint64_t)(f_VirtToPhys(p_Buffer)); ++ SET_ADDR(&p_Bd->buff, physAddr); ++} ++ ++static __inline__ uint16_t GetNextBdId(t_FmPort *p_FmPort, uint16_t id) ++{ ++ if (id < p_FmPort->im.bdRingSize-1) ++ return (uint16_t)(id+1); ++ else ++ return 0; ++} ++ ++void FM_PORT_Dsar_DumpRegs(void); ++ ++ ++#endif /* __FM_PORT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_dsar.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_dsar.h +new file mode 100755 +index 00000000..95619eff +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_dsar.h +@@ -0,0 +1,494 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/**************************************************************************//** ++ @File fm_port_dsar.h ++ ++ @Description Deep Sleep Auto Response project - common module header file. ++ ++ Author - Eyal Harari ++ ++ @Cautions See the FMan Controller spec and design document for more information. ++*//***************************************************************************/ ++ ++#ifndef __FM_PORT_DSAR_H_ ++#define __FM_PORT_DSAR_H_ ++ ++#define DSAR_GETSER_MASK 0xFF0000FF ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(push,1) ++#endif /* defined(__MWERKS__) && ... */ ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response VLAN-IPv4 Binding Table (for ARP/ICMPv4) ++ Refer to the FMan Controller spec for more details. ++*//***************************************************************************/ ++typedef _Packed struct ++{ ++ uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */ ++ uint16_t vlanId; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */ ++ /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */ ++ uint16_t reserved; ++} _PackedType t_DsarArpBindingEntry; ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response Address Resolution Protocol Statistics Descriptor ++ Refer to the FMan Controller spec for more details. ++ 0x00 INVAL_CNT Invalid ARP IPv4-Ethernet counter ++ 0x04 ECHO_CNT Echo counter ++ 0x08 CD_CNT Conflict Detection counter ++ 0x0C AR_CNT Auto-Response counter ++ 0x10 RATM_CNT Replies Addressed To Me counter ++ 0x14 UKOP_CNT Unknown Operation counter ++ 0x18 NMTP_CNT Not my TPA counter ++ 0x1C NMVLAN_CNT Not My VLAN counter ++*//***************************************************************************/ ++typedef _Packed struct ++{ ++ uint32_t invalCnt; /**< Invalid ARP IPv4-Ethernet counter. */ ++ uint32_t echoCnt; /**< Echo counter. */ ++ uint32_t cdCnt; /**< Conflict Detection counter. */ ++ uint32_t arCnt; /**< Auto-Response counter. */ ++ uint32_t ratmCnt; /**< Replies Addressed To Me counter. */ ++ uint32_t ukopCnt; /**< Unknown Operation counter. */ ++ uint32_t nmtpCnt; /**< Not my TPA counter. */ ++ uint32_t nmVlanCnt; /**< Not My VLAN counter */ ++} _PackedType t_DsarArpStatistics; ++ ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response Address Resolution Protocol Descriptor ++ 0x0 0-15 Control bits [0-15]. Bit 15 = CDEN. ++ 0x2 0-15 NumOfBindings Number of entries in the binding list. ++ 0x4 0-15 BindingsPointer Bindings Pointer. This points to an IPv4-MAC Addresses Bindings list. ++ 0x6 0-15 ++ 0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ARP Descriptors statistics data structure. ++ 0xA 0-15 ++ 0xC 0-15 Reserved Reserved. Must be cleared. ++ 0xE 015 ++ ++*//***************************************************************************/ ++typedef _Packed struct ++{ ++ uint16_t control; /** Control bits [0-15]. Bit 15 = CDEN */ ++ uint16_t numOfBindings; /**< Number of VLAN-IPv4 */ ++ uint32_t p_Bindings; /**< VLAN-IPv4 Bindings table pointer. */ ++ uint32_t p_Statistics; /**< Statistics Data Structure pointer. */ ++ uint32_t reserved1; /**< Reserved. */ ++} _PackedType t_DsarArpDescriptor; ++ ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response VLAN-IPv4 Binding Table (for ARP/ICMPv4) ++ Refer to the FMan Controller spec for more details. ++*//***************************************************************************/ ++typedef _Packed struct ++{ ++ uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */ ++ uint16_t vlanId; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */ ++ /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */ ++ uint16_t reserved; ++} _PackedType t_DsarIcmpV4BindingEntry; ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response ICMPv4 Statistics Descriptor ++ Refer to the FMan Controller spec for more details. ++ 0x00 INVAL_CNT Invalid ICMPv4 header counter ++ 0x04 NMVLAN_CNT Not My VLAN counter ++ 0x08 NMIP_CNT Not My IP counter ++ 0x0C AR_CNT Auto-Response counter ++ 0x10 CSERR_CNT Checksum Error counter ++ 0x14 Reserved Reserved ++ 0x18 Reserved Reserved ++ 0x1C Reserved Reserved ++ ++*//***************************************************************************/ ++typedef _Packed struct ++{ ++ uint32_t invalCnt; /**< Invalid ICMPv4 Echo counter. */ ++ uint32_t nmVlanCnt; /**< Not My VLAN counter */ ++ uint32_t nmIpCnt; /**< Not My IP counter */ ++ uint32_t arCnt; /**< Auto-Response counter */ ++ uint32_t cserrCnt; /**< Checksum Error counter */ ++ uint32_t reserved0; /**< Reserved */ ++ uint32_t reserved1; /**< Reserved */ ++ uint32_t reserved2; /**< Reserved */ ++} _PackedType t_DsarIcmpV4Statistics; ++ ++ ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response ICMPv4 Descriptor ++ 0x0 0-15 Control bits [0-15] ++ 0x2 0-15 NumOfBindings Number of entries in the binding list. ++ 0x4 0-15 BindingsPointer Bindings Pointer. This points to an VLAN-IPv4 Addresses Bindings list. ++ 0x6 0-15 ++ 0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ICMPv4 statistics data structure. ++ 0xA 0-15 ++ 0xC 0-15 Reserved Reserved. Must be cleared. ++ 0xE 015 ++ ++*//***************************************************************************/ ++typedef _Packed struct ++{ ++ uint16_t control; /** Control bits [0-15]. */ ++ uint16_t numOfBindings; /**< Number of VLAN-IPv4 */ ++ uint32_t p_Bindings; /**< VLAN-IPv4 Bindings table pointer. */ ++ uint32_t p_Statistics; /**< Statistics Data Structure pointer. */ ++ uint32_t reserved1; /**< Reserved. */ ++} _PackedType t_DsarIcmpV4Descriptor; ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response VLAN-IPv4 Binding Table (for ARP/ICMPv4) ++ The 4 left-most bits (15:12) of the VlanId parameter are control flags. ++ Flags[3:1] (VlanId[15:13]): Reserved, should be cleared. ++ Flags[0] (VlanId[12]): Temporary address. ++ • 0 - Assigned IP address. ++ • 1- Temporary (tentative) IP address. ++ Refer to the FMan Controller spec for more details. ++*//***************************************************************************/ ++typedef _Packed struct ++{ ++ uint32_t ipv6Addr[4]; /*!< 3 * 32 bit IPv4 Address. */ ++ uint16_t resFlags:4; /*!< reserved flags. should be cleared */ ++ uint16_t vlanId:12; /*!< 12 bits VLAN ID. */ ++ /*!< This field should be 0x000 for an entry with no VLAN tag or a null VLAN ID. */ ++ uint16_t reserved; ++} _PackedType t_DsarIcmpV6BindingEntry; ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response ICMPv4 Statistics Descriptor ++ Refer to the FMan Controller spec for more details. ++ 0x00 INVAL_CNT Invalid ICMPv4 header counter ++ 0x04 NMVLAN_CNT Not My VLAN counter ++ 0x08 NMIP_CNT Not My IP counter ++ 0x0C AR_CNT Auto-Response counter ++ 0x10 CSERR_CNT Checksum Error counter ++ 0x14 MCAST_CNT Multicast counter ++ 0x18 Reserved Reserved ++ 0x1C Reserved Reserved ++ ++*//***************************************************************************/ ++typedef _Packed struct ++{ ++ uint32_t invalCnt; /**< Invalid ICMPv4 Echo counter. */ ++ uint32_t nmVlanCnt; /**< Not My VLAN counter */ ++ uint32_t nmIpCnt; /**< Not My IP counter */ ++ uint32_t arCnt; /**< Auto-Response counter */ ++ uint32_t reserved1; /**< Reserved */ ++ uint32_t reserved2; /**< Reserved */ ++ uint32_t reserved3; /**< Reserved */ ++ uint32_t reserved4; /**< Reserved */ ++} _PackedType t_DsarIcmpV6Statistics; ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response Neighbor Discovery Statistics Descriptor ++ 0x00 INVAL_CNT Invalid Neighbor Discovery message counter ++ 0x04 NMVLAN_CNT Not My VLAN counter ++ 0x08 NMIP_CNT Not My IP counter ++ 0x0C AR_CNT Auto-Response counter ++ 0x10 CSERR_CNT Checksum Error counter ++ 0x14 USADVERT_CNT Unsolicited Neighbor Advertisements counter ++ 0x18 NMMCAST_CNT Not My Multicast group counter ++ 0x1C NSLLA_CNT No Source Link-Layer Address counter. Indicates that there was a match on a Target ++ Address of a packet that its source IP address is a unicast address, but the ICMPv6 ++ Source Link-layer Address option is omitted ++*//***************************************************************************/ ++typedef _Packed struct ++{ ++ uint32_t invalCnt; /**< Invalid ICMPv4 Echo counter. */ ++ uint32_t nmVlanCnt; /**< Not My VLAN counter */ ++ uint32_t nmIpCnt; /**< Not My IP counter */ ++ uint32_t arCnt; /**< Auto-Response counter */ ++ uint32_t reserved1; /**< Reserved */ ++ uint32_t usadvertCnt; /**< Unsolicited Neighbor Advertisements counter */ ++ uint32_t nmmcastCnt; /**< Not My Multicast group counter */ ++ uint32_t nsllaCnt; /**< No Source Link-Layer Address counter */ ++} _PackedType t_NdStatistics; ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response ICMPv6 Descriptor ++ 0x0 0-15 Control bits [0-15] ++ 0x2 0-15 NumOfBindings Number of entries in the binding list. ++ 0x4 0-15 BindingsPointer Bindings Pointer. This points to an VLAN-IPv4 Addresses Bindings list. ++ 0x6 0-15 ++ 0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ICMPv4 statistics data structure. ++ 0xA 0-15 ++ 0xC 0-15 Reserved Reserved. Must be cleared. ++ 0xE 015 ++ ++*//***************************************************************************/ ++typedef _Packed struct ++{ ++ uint16_t control; /** Control bits [0-15]. */ ++ uint16_t numOfBindings; /**< Number of VLAN-IPv6 */ ++ uint32_t p_Bindings; /**< VLAN-IPv4 Bindings table pointer. */ ++ uint32_t p_Statistics; /**< Statistics Data Structure pointer. */ ++ uint32_t reserved1; /**< Reserved. */ ++} _PackedType t_DsarIcmpV6Descriptor; ++ ++ ++/**************************************************************************//** ++ @Description Internet Control Message Protocol (ICMPv6) Echo message header ++ The fields names are taken from RFC 4443. ++*//***************************************************************************/ ++/* 0 1 2 3 */ ++/* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 */ ++/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ ++/* | Type | Code | Checksum | */ ++/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ ++/* | Identifier | Sequence Number | */ ++/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ ++/* | Data ... */ ++/* +-+-+-+-+- */ ++typedef _Packed struct ++{ ++ uint8_t type; ++ uint8_t code; ++ uint16_t checksum; ++ uint16_t identifier; ++ uint16_t sequenceNumber; ++} _PackedType t_IcmpV6EchoHdr; ++ ++/**************************************************************************//** ++ @Description Internet Control Message Protocol (ICMPv6) ++ Neighbor Solicitation/Advertisement header ++ The fields names are taken from RFC 4861. ++ The R/S/O fields are valid for Neighbor Advertisement only ++*//***************************************************************************/ ++/* 0 1 2 3 ++ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | Type | Code | Checksum | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * |R|S|O| Reserved | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | | ++ * + + ++ * | | ++ * + Target Address + ++ * | | ++ * + + ++ * | | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | Options ... ++ * +-+-+-+-+-+-+-+-+-+-+-+- ++ * ++ * Options Format: ++ * 0 1 2 3 ++ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | Type | Length | Link-Layer Address ... | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ * | Link-Layer Address | ++ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++*/ ++typedef _Packed struct ++{ ++ uint8_t type; ++ uint8_t code; ++ uint16_t checksum; ++ uint32_t router:1; ++ uint32_t solicited:1; ++ uint32_t override:1; ++ uint32_t reserved:29; ++ uint32_t targetAddr[4]; ++ uint8_t optionType; ++ uint8_t optionLength; ++ uint8_t linkLayerAddr[6]; ++} _PackedType t_IcmpV6NdHdr; ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response ICMPv6 Descriptor ++ 0x0 0-15 Control bits [0-15] ++ 0x2 0-15 NumOfBindings Number of entries in the binding list. ++ 0x4 0-15 BindingsPointer Bindings Pointer. This points to an VLAN-IPv4 Addresses Bindings list. ++ 0x6 0-15 ++ 0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ICMPv4 statistics data structure. ++ 0xA 0-15 ++ 0xC 0-15 Reserved Reserved. Must be cleared. ++ 0xE 015 ++ ++*//***************************************************************************/ ++typedef _Packed struct ++{ ++ uint16_t control; /** Control bits [0-15]. */ ++ uint16_t numOfBindings; /**< Number of VLAN-IPv6 */ ++ uint32_t p_Bindings; /**< VLAN-IPv4 Bindings table pointer. */ ++ uint32_t p_Statistics; /**< Statistics Data Structure pointer. */ ++ uint32_t solicitedAddr; /**< Solicited Node Multicast Group Address */ ++} _PackedType t_DsarNdDescriptor; ++ ++/**************************************************************************//** ++@Description Deep Sleep Auto Response SNMP OIDs table entry ++ ++*//***************************************************************************/ ++typedef struct { ++ uint16_t oidSize; /**< Size in octets of the OID. */ ++ uint16_t resSize; /**< Size in octets of the value that is attached to the OID. */ ++ uint32_t p_Oid; /**< Pointer to the OID. OID is encoded in BER but type and length are excluded. */ ++ uint32_t resValOrPtr; /**< Value (for up to 4 octets) or pointer to the Value. Encoded in BER. */ ++ uint32_t reserved; ++} t_OidsTblEntry; ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response SNMP IPv4 Addresses Table Entry ++ Refer to the FMan Controller spec for more details. ++*//***************************************************************************/ ++typedef struct ++{ ++ uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */ ++ uint16_t vlanId; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */ ++ /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */ ++ uint16_t reserved; ++} t_DsarSnmpIpv4AddrTblEntry; ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response SNMP IPv6 Addresses Table Entry ++ Refer to the FMan Controller spec for more details. ++*//***************************************************************************/ ++#pragma pack(push,1) ++typedef struct ++{ ++ uint32_t ipv6Addr[4]; /*!< 4 * 32 bit IPv6 Address. */ ++ uint16_t vlanId; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */ ++ /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */ ++ uint16_t reserved; ++} t_DsarSnmpIpv6AddrTblEntry; ++#pragma pack(pop) ++ ++/**************************************************************************//** ++@Description Deep Sleep Auto Response SNMP statistics table ++ ++*//***************************************************************************/ ++typedef struct { ++ uint32_t snmpErrCnt; /**< Counts SNMP errors (wrong version, BER encoding, format). */ ++ uint32_t snmpCommunityErrCnt; /**< Counts messages that were dropped due to insufficient permission. */ ++ uint32_t snmpTotalDiscardCnt; /**< Counts any message that was dropped. */ ++ uint32_t snmpGetReqCnt; /**< Counts the number of get-request messages */ ++ uint32_t snmpGetNextReqCnt; /**< Counts the number of get-next-request messages */ ++} t_DsarSnmpStatistics; ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response SNMP Descriptor ++ ++*//***************************************************************************/ ++typedef struct ++{ ++ uint16_t control; /**< Control bits [0-15]. */ ++ uint16_t maxSnmpMsgLength; /**< Maximal allowed SNMP message length. */ ++ uint16_t numOfIpv4Addresses; /**< Number of entries in IPv4 addresses table. */ ++ uint16_t numOfIpv6Addresses; /**< Number of entries in IPv6 addresses table. */ ++ uint32_t p_Ipv4AddrTbl; /**< Pointer to IPv4 addresses table. */ ++ uint32_t p_Ipv6AddrTbl; /**< Pointer to IPv6 addresses table. */ ++ uint32_t p_RdOnlyCommunityStr; /**< Pointer to the Read Only Community String. */ ++ uint32_t p_RdWrCommunityStr; /**< Pointer to the Read Write Community String. */ ++ uint32_t p_OidsTbl; /**< Pointer to OIDs table. */ ++ uint32_t oidsTblSize; /**< Number of entries in OIDs table. */ ++ uint32_t p_Statistics; /**< Pointer to SNMP statistics table. */ ++} t_DsarSnmpDescriptor; ++ ++/**************************************************************************//** ++@Description Deep Sleep Auto Response (Common) Statistics ++ ++*//***************************************************************************/ ++typedef _Packed struct { ++ uint32_t dsarDiscarded; ++ uint32_t dsarErrDiscarded; ++ uint32_t dsarFragDiscarded; ++ uint32_t dsarTunnelDiscarded; ++ uint32_t dsarArpDiscarded; ++ uint32_t dsarIpDiscarded; ++ uint32_t dsarTcpDiscarded; ++ uint32_t dsarUdpDiscarded; ++ uint32_t dsarIcmpV6ChecksumErr; /* ICMPv6 Checksum Error counter */ ++ uint32_t dsarIcmpV6OtherType; /* ICMPv6 'Other' type (not Echo or Neighbor Solicitaion/Advertisement counter */ ++ uint32_t dsarIcmpV4OtherType; /* ICMPv4 'Other' type (not Echo) counter */ ++} _PackedType t_ArStatistics; ++ ++ ++/**************************************************************************//** ++@Description Deep Sleep Auto Response TCP/UDP port filter table entry ++ ++*//***************************************************************************/ ++typedef _Packed struct { ++ uint32_t Ports; ++ uint32_t PortsMask; ++} _PackedType t_PortTblEntry; ++ ++ ++ ++/**************************************************************************//** ++@Description Deep Sleep Auto Response Common Parameters Descriptor ++ ++*//***************************************************************************/ ++typedef _Packed struct { ++ uint8_t arTxPort; /* 0x00 0-7 Auto Response Transmit Port number */ ++ uint8_t controlBits; /* 0x00 8-15 Auto Response control bits */ ++ uint16_t res1; /* 0x00 16-31 Reserved */ ++ uint32_t activeHPNIA; /* 0x04 0-31 Active mode Hardware Parser NIA */ ++ uint16_t snmpPort; /* 0x08 0-15 SNMP Port. */ ++ uint8_t macStationAddr[6]; /* 0x08 16-31 and 0x0C 0-31 MAC Station Address */ ++ uint8_t res2; /* 0x10 0-7 Reserved */ ++ uint8_t filterControl; /* 0x10 8-15 Filtering Control Bits. */ ++ uint16_t tcpControlPass; /* 0x10 16-31 TCP control pass flags */ ++ uint8_t ipProtocolTblSize; /* 0x14 0-7 IP Protocol Table Size. */ ++ uint8_t udpPortTblSize; /* 0x14 8-15 UDP Port Table Size. */ ++ uint8_t tcpPortTblSize; /* 0x14 16-23 TCP Port Table Size. */ ++ uint8_t res3; /* 0x14 24-31 Reserved */ ++ uint32_t p_IpProtocolFiltTbl; /* 0x18 0-31 Pointer to IP Protocol Filter Table */ ++ uint32_t p_UdpPortFiltTbl; /* 0x1C 0-31 Pointer to UDP Port Filter Table */ ++ uint32_t p_TcpPortFiltTbl; /* 0x20 0-31 Pointer to TCP Port Filter Table */ ++ uint32_t res4; /* 0x24 Reserved */ ++ uint32_t p_ArpDescriptor; /* 0x28 0-31 ARP Descriptor Pointer. */ ++ uint32_t p_NdDescriptor; /* 0x2C 0-31 Neighbor Discovery Descriptor. */ ++ uint32_t p_IcmpV4Descriptor; /* 0x30 0-31 ICMPv4 Descriptor pointer. */ ++ uint32_t p_IcmpV6Descriptor; /* 0x34 0-31 ICMPv6 Descriptor pointer. */ ++ uint32_t p_SnmpDescriptor; /* 0x38 0-31 SNMP Descriptor pointer. */ ++ uint32_t p_ArStats; /* 0x3C 0-31 Pointer to Auto Response Statistics */ ++} _PackedType t_ArCommonDesc; ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(pop) ++#endif /* defined(__MWERKS__) && ... */ ++ ++/* t_ArCommonDesc.filterControl bits */ ++#define IP_PROT_TBL_PASS_MASK 0x08 ++#define UDP_PORT_TBL_PASS_MASK 0x04 ++#define TCP_PORT_TBL_PASS_MASK 0x02 ++ ++/* Offset of TCF flags within TCP packet */ ++#define TCP_FLAGS_OFFSET 12 ++ ++ ++#endif /* __FM_PORT_DSAR_H_ */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_im.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_im.c +new file mode 100644 +index 00000000..8de8f5fd +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_im.c +@@ -0,0 +1,753 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_port_im.c ++ ++ @Description FM Port Independent-Mode ... ++*//***************************************************************************/ ++#include "std_ext.h" ++#include "string_ext.h" ++#include "error_ext.h" ++#include "memcpy_ext.h" ++#include "fm_muram_ext.h" ++ ++#include "fm_port.h" ++ ++ ++#define TX_CONF_STATUS_UNSENT 0x1 ++ ++ ++typedef enum e_TxConfType ++{ ++ e_TX_CONF_TYPE_CHECK = 0 /**< check if all the buffers were touched by the muxator, no confirmation callback */ ++ ,e_TX_CONF_TYPE_CALLBACK = 1 /**< confirm to user all the available sent buffers */ ++ ,e_TX_CONF_TYPE_FLUSH = 3 /**< confirm all buffers plus the unsent one with an appropriate status */ ++} e_TxConfType; ++ ++ ++static void ImException(t_Handle h_FmPort, uint32_t event) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ ASSERT_COND(((event & (IM_EV_RX | IM_EV_BSY)) && FmIsMaster(p_FmPort->h_Fm)) || ++ !FmIsMaster(p_FmPort->h_Fm)); ++ ++ if (event & IM_EV_RX) ++ FmPortImRx(p_FmPort); ++ if ((event & IM_EV_BSY) && p_FmPort->f_Exception) ++ p_FmPort->f_Exception(p_FmPort->h_App, e_FM_PORT_EXCEPTION_IM_BUSY); ++} ++ ++ ++static t_Error TxConf(t_FmPort *p_FmPort, e_TxConfType confType) ++{ ++ t_Error retVal = E_BUSY; ++ uint32_t bdStatus; ++ uint16_t savedStartBdId, confBdId; ++ ++ ASSERT_COND(p_FmPort); ++ ++ /* ++ if (confType==e_TX_CONF_TYPE_CHECK) ++ return (WfqEntryIsQueueEmpty(p_FmPort->im.h_WfqEntry) ? E_OK : E_BUSY); ++ */ ++ ++ confBdId = savedStartBdId = p_FmPort->im.currBdId; ++ bdStatus = BD_STATUS_AND_LENGTH(BD_GET(confBdId)); ++ ++ /* If R bit is set, we don't enter, or we break. ++ we run till we get to R, or complete the loop */ ++ while ((!(bdStatus & BD_R_E) || (confType == e_TX_CONF_TYPE_FLUSH)) && (retVal != E_OK)) ++ { ++ if (confType & e_TX_CONF_TYPE_CALLBACK) /* if it is confirmation with user callbacks */ ++ BD_STATUS_AND_LENGTH_SET(BD_GET(confBdId), 0); ++ ++ /* case 1: R bit is 0 and Length is set -> confirm! */ ++ if ((confType & e_TX_CONF_TYPE_CALLBACK) && (bdStatus & BD_LENGTH_MASK)) ++ { ++ if (p_FmPort->im.f_TxConf) ++ { ++ if ((confType == e_TX_CONF_TYPE_FLUSH) && (bdStatus & BD_R_E)) ++ p_FmPort->im.f_TxConf(p_FmPort->h_App, ++ BdBufferGet(XX_PhysToVirt, BD_GET(confBdId)), ++ TX_CONF_STATUS_UNSENT, ++ p_FmPort->im.p_BdShadow[confBdId]); ++ else ++ p_FmPort->im.f_TxConf(p_FmPort->h_App, ++ BdBufferGet(XX_PhysToVirt, BD_GET(confBdId)), ++ 0, ++ p_FmPort->im.p_BdShadow[confBdId]); ++ } ++ } ++ /* case 2: R bit is 0 and Length is 0 -> not used yet, nop! */ ++ ++ confBdId = GetNextBdId(p_FmPort, confBdId); ++ if (confBdId == savedStartBdId) ++ retVal = E_OK; ++ bdStatus = BD_STATUS_AND_LENGTH(BD_GET(confBdId)); ++ } ++ ++ return retVal; ++} ++ ++t_Error FmPortImEnable(t_FmPort *p_FmPort) ++{ ++ uint32_t tmpReg = GET_UINT32(p_FmPort->im.p_FmPortImPram->mode); ++ WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, (uint32_t)(tmpReg & ~IM_MODE_GRC_STP)); ++ return E_OK; ++} ++ ++t_Error FmPortImDisable(t_FmPort *p_FmPort) ++{ ++ uint32_t tmpReg = GET_UINT32(p_FmPort->im.p_FmPortImPram->mode); ++ WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, (uint32_t)(tmpReg | IM_MODE_GRC_STP)); ++ return E_OK; ++} ++ ++t_Error FmPortImRx(t_FmPort *p_FmPort) ++{ ++ t_Handle h_CurrUserPriv, h_NewUserPriv; ++ uint32_t bdStatus; ++ volatile uint8_t buffPos; ++ uint16_t length; ++ uint16_t errors; ++ uint8_t *p_CurData, *p_Data; ++ uint32_t flags; ++ ++ ASSERT_COND(p_FmPort); ++ ++ flags = XX_LockIntrSpinlock(p_FmPort->h_Spinlock); ++ if (p_FmPort->lock) ++ { ++ XX_UnlockIntrSpinlock(p_FmPort->h_Spinlock, flags); ++ return E_OK; ++ } ++ p_FmPort->lock = TRUE; ++ XX_UnlockIntrSpinlock(p_FmPort->h_Spinlock, flags); ++ ++ bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); ++ ++ while (!(bdStatus & BD_R_E)) /* while there is data in the Rx BD */ ++ { ++ if ((p_Data = p_FmPort->im.rxPool.f_GetBuf(p_FmPort->im.rxPool.h_BufferPool, &h_NewUserPriv)) == NULL) ++ { ++ p_FmPort->lock = FALSE; ++ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Data buffer")); ++ } ++ ++ if (p_FmPort->im.firstBdOfFrameId == IM_ILEGAL_BD_ID) ++ p_FmPort->im.firstBdOfFrameId = p_FmPort->im.currBdId; ++ ++ p_CurData = BdBufferGet(p_FmPort->im.rxPool.f_PhysToVirt, BD_GET(p_FmPort->im.currBdId)); ++ h_CurrUserPriv = p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]; ++ length = (uint16_t)((bdStatus & BD_L) ? ++ ((bdStatus & BD_LENGTH_MASK) - p_FmPort->im.rxFrameAccumLength): ++ (bdStatus & BD_LENGTH_MASK)); ++ p_FmPort->im.rxFrameAccumLength += length; ++ ++ /* determine whether buffer is first, last, first and last (single */ ++ /* buffer frame) or middle (not first and not last) */ ++ buffPos = (uint8_t)((p_FmPort->im.currBdId == p_FmPort->im.firstBdOfFrameId) ? ++ ((bdStatus & BD_L) ? SINGLE_BUF : FIRST_BUF) : ++ ((bdStatus & BD_L) ? LAST_BUF : MIDDLE_BUF)); ++ ++ if (bdStatus & BD_L) ++ { ++ p_FmPort->im.rxFrameAccumLength = 0; ++ p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; ++ } ++ ++ BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, BD_GET(p_FmPort->im.currBdId), p_Data); ++ ++ BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), BD_R_E); ++ ++ errors = (uint16_t)((bdStatus & BD_RX_ERRORS) >> 16); ++ p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId] = h_NewUserPriv; ++ ++ p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); ++ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.offsetOut, (uint16_t)(p_FmPort->im.currBdId<<4)); ++ /* Pass the buffer if one of the conditions is true: ++ - There are no errors ++ - This is a part of a larger frame ( the application has already received some buffers ) */ ++ if ((buffPos != SINGLE_BUF) || !errors) ++ { ++ if (p_FmPort->im.f_RxStore(p_FmPort->h_App, ++ p_CurData, ++ length, ++ errors, ++ buffPos, ++ h_CurrUserPriv) == e_RX_STORE_RESPONSE_PAUSE) ++ break; ++ } ++ else if (p_FmPort->im.rxPool.f_PutBuf(p_FmPort->im.rxPool.h_BufferPool, ++ p_CurData, ++ h_CurrUserPriv)) ++ { ++ p_FmPort->lock = FALSE; ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Failed freeing data buffer")); ++ } ++ ++ bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); ++ } ++ p_FmPort->lock = FALSE; ++ return E_OK; ++} ++ ++void FmPortConfigIM (t_FmPort *p_FmPort, t_FmPortParams *p_FmPortParams) ++{ ++ ASSERT_COND(p_FmPort); ++ ++ SANITY_CHECK_RETURN(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ p_FmPort->im.h_FmMuram = p_FmPortParams->specificParams.imRxTxParams.h_FmMuram; ++ p_FmPort->p_FmPortDriverParam->liodnOffset = p_FmPortParams->specificParams.imRxTxParams.liodnOffset; ++ p_FmPort->im.dataMemId = p_FmPortParams->specificParams.imRxTxParams.dataMemId; ++ p_FmPort->im.dataMemAttributes = p_FmPortParams->specificParams.imRxTxParams.dataMemAttributes; ++ ++ p_FmPort->im.fwExtStructsMemId = DEFAULT_PORT_ImfwExtStructsMemId; ++ p_FmPort->im.fwExtStructsMemAttr = DEFAULT_PORT_ImfwExtStructsMemAttr; ++ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || ++ (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) ++ { ++ p_FmPort->im.rxPool.h_BufferPool = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.h_BufferPool; ++ p_FmPort->im.rxPool.f_GetBuf = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_GetBuf; ++ p_FmPort->im.rxPool.f_PutBuf = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_PutBuf; ++ p_FmPort->im.rxPool.bufferSize = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.bufferSize; ++ p_FmPort->im.rxPool.f_PhysToVirt = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_PhysToVirt; ++ if (!p_FmPort->im.rxPool.f_PhysToVirt) ++ p_FmPort->im.rxPool.f_PhysToVirt = XX_PhysToVirt; ++ p_FmPort->im.rxPool.f_VirtToPhys = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_VirtToPhys; ++ if (!p_FmPort->im.rxPool.f_VirtToPhys) ++ p_FmPort->im.rxPool.f_VirtToPhys = XX_VirtToPhys; ++ p_FmPort->im.f_RxStore = p_FmPortParams->specificParams.imRxTxParams.f_RxStore; ++ ++ p_FmPort->im.mrblr = 0x8000; ++ while (p_FmPort->im.mrblr) ++ { ++ if (p_FmPort->im.rxPool.bufferSize & p_FmPort->im.mrblr) ++ break; ++ p_FmPort->im.mrblr >>= 1; ++ } ++ if (p_FmPort->im.mrblr != p_FmPort->im.rxPool.bufferSize) ++ DBG(WARNING, ("Max-Rx-Buffer-Length set to %d", p_FmPort->im.mrblr)); ++ p_FmPort->im.bdRingSize = DEFAULT_PORT_rxBdRingLength; ++ p_FmPort->exceptions = DEFAULT_PORT_exception; ++ if (FmIsMaster(p_FmPort->h_Fm)) ++ p_FmPort->polling = FALSE; ++ else ++ p_FmPort->polling = TRUE; ++ p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; ++ } ++ else ++ { ++ p_FmPort->im.f_TxConf = p_FmPortParams->specificParams.imRxTxParams.f_TxConf; ++ ++ p_FmPort->im.bdRingSize = DEFAULT_PORT_txBdRingLength; ++ } ++} ++ ++t_Error FmPortImCheckInitParameters(t_FmPort *p_FmPort) ++{ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX) && ++ (p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && ++ (p_FmPort->portType != e_FM_PORT_TYPE_TX) && ++ (p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); ++ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || ++ (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) ++ { ++ if (!POWER_OF_2(p_FmPort->im.mrblr)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("max Rx buffer length must be power of 2!!!")); ++ if (p_FmPort->im.mrblr < 256) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("max Rx buffer length must at least 256!!!")); ++ if (p_FmPort->p_FmPortDriverParam->liodnOffset & ~FM_LIODN_OFFSET_MASK) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1)); ++ } ++ ++ return E_OK; ++} ++ ++t_Error FmPortImInit(t_FmPort *p_FmPort) ++{ ++ t_FmImBd *p_Bd=NULL; ++ t_Handle h_BufContext; ++ uint64_t tmpPhysBase; ++ uint16_t log2Num; ++ uint8_t *p_Data/*, *p_Tmp*/; ++ int i; ++ t_Error err; ++ uint16_t tmpReg16; ++ uint32_t tmpReg32; ++ ++ ASSERT_COND(p_FmPort); ++ ++ p_FmPort->im.p_FmPortImPram = ++ (t_FmPortImPram *)FM_MURAM_AllocMem(p_FmPort->im.h_FmMuram, sizeof(t_FmPortImPram), IM_PRAM_ALIGN); ++ if (!p_FmPort->im.p_FmPortImPram) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Parameter-RAM!!!")); ++ WRITE_BLOCK(p_FmPort->im.p_FmPortImPram, 0, sizeof(t_FmPortImPram)); ++ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || ++ (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) ++ { ++ p_FmPort->im.p_BdRing = ++ (t_FmImBd *)XX_MallocSmart((uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize), ++ p_FmPort->im.fwExtStructsMemId, ++ 4); ++ if (!p_FmPort->im.p_BdRing) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD ring!!!")); ++ IOMemSet32(p_FmPort->im.p_BdRing, 0, (uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); ++ ++ p_FmPort->im.p_BdShadow = (t_Handle *)XX_Malloc((uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); ++ if (!p_FmPort->im.p_BdShadow) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD shadow!!!")); ++ memset(p_FmPort->im.p_BdShadow, 0, (uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); ++ ++ /* Initialize the Rx-BD ring */ ++ for (i=0; iim.bdRingSize; i++) ++ { ++ p_Bd = BD_GET(i); ++ BD_STATUS_AND_LENGTH_SET (p_Bd, BD_R_E); ++ ++ if ((p_Data = p_FmPort->im.rxPool.f_GetBuf(p_FmPort->im.rxPool.h_BufferPool, &h_BufContext)) == NULL) ++ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Data buffer")); ++ BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, p_Bd, p_Data); ++ p_FmPort->im.p_BdShadow[i] = h_BufContext; ++ } ++ ++ if ((p_FmPort->im.dataMemAttributes & MEMORY_ATTR_CACHEABLE) || ++ (p_FmPort->im.fwExtStructsMemAttr & MEMORY_ATTR_CACHEABLE)) ++ WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_GBL | IM_MODE_SET_BO(2)); ++ else ++ WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_SET_BO(2)); ++ ++ WRITE_UINT32(p_FmPort->im.p_FmPortImPram->rxQdPtr, ++ (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - ++ p_FmPort->fmMuramPhysBaseAddr + 0x20)); ++ ++ LOG2((uint64_t)p_FmPort->im.mrblr, log2Num); ++ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->mrblr, log2Num); ++ ++ /* Initialize Rx QD */ ++ tmpPhysBase = (uint64_t)(XX_VirtToPhys(p_FmPort->im.p_BdRing)); ++ SET_ADDR(&p_FmPort->im.p_FmPortImPram->rxQd.bdRingBase, tmpPhysBase); ++ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.bdRingSize, (uint16_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); ++ ++ /* Update the IM PRAM address in the BMI */ ++ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfqid, ++ (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - ++ p_FmPort->fmMuramPhysBaseAddr)); ++ if (!p_FmPort->polling || p_FmPort->exceptions) ++ { ++ /* Allocate, configure and register interrupts */ ++ err = FmAllocFmanCtrlEventReg(p_FmPort->h_Fm, &p_FmPort->fmanCtrlEventId); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ ASSERT_COND(!(p_FmPort->fmanCtrlEventId & ~IM_RXQD_FPMEVT_SEL_MASK)); ++ tmpReg16 = (uint16_t)(p_FmPort->fmanCtrlEventId & IM_RXQD_FPMEVT_SEL_MASK); ++ tmpReg32 = 0; ++ ++ if (p_FmPort->exceptions & IM_EV_BSY) ++ { ++ tmpReg16 |= IM_RXQD_BSYINTM; ++ tmpReg32 |= IM_EV_BSY; ++ } ++ if (!p_FmPort->polling) ++ { ++ tmpReg16 |= IM_RXQD_RXFINTM; ++ tmpReg32 |= IM_EV_RX; ++ } ++ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); ++ ++ FmRegisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, ImException , (t_Handle)p_FmPort); ++ ++ FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); ++ } ++ else ++ p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; ++ } ++ else ++ { ++ p_FmPort->im.p_BdRing = (t_FmImBd *)XX_MallocSmart((uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize), p_FmPort->im.fwExtStructsMemId, 4); ++ if (!p_FmPort->im.p_BdRing) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Tx BD ring!!!")); ++ IOMemSet32(p_FmPort->im.p_BdRing, 0, (uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); ++ ++ p_FmPort->im.p_BdShadow = (t_Handle *)XX_Malloc((uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); ++ if (!p_FmPort->im.p_BdShadow) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD shadow!!!")); ++ memset(p_FmPort->im.p_BdShadow, 0, (uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); ++ p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; ++ ++ if ((p_FmPort->im.dataMemAttributes & MEMORY_ATTR_CACHEABLE) || ++ (p_FmPort->im.fwExtStructsMemAttr & MEMORY_ATTR_CACHEABLE)) ++ WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_GBL | IM_MODE_SET_BO(2)); ++ else ++ WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_SET_BO(2)); ++ ++ WRITE_UINT32(p_FmPort->im.p_FmPortImPram->txQdPtr, ++ (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - ++ p_FmPort->fmMuramPhysBaseAddr + 0x40)); ++ ++ /* Initialize Tx QD */ ++ tmpPhysBase = (uint64_t)(XX_VirtToPhys(p_FmPort->im.p_BdRing)); ++ SET_ADDR(&p_FmPort->im.p_FmPortImPram->txQd.bdRingBase, tmpPhysBase); ++ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->txQd.bdRingSize, (uint16_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); ++ ++ /* Update the IM PRAM address in the BMI */ ++ WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfqid, ++ (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - ++ p_FmPort->fmMuramPhysBaseAddr)); ++ } ++ ++ ++ return E_OK; ++} ++ ++void FmPortImFree(t_FmPort *p_FmPort) ++{ ++ uint32_t bdStatus; ++ uint8_t *p_CurData; ++ ++ ASSERT_COND(p_FmPort); ++ ASSERT_COND(p_FmPort->im.p_FmPortImPram); ++ ++ if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || ++ (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) ++ { ++ if (!p_FmPort->polling || p_FmPort->exceptions) ++ { ++ /* Deallocate and unregister interrupts */ ++ FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, 0); ++ ++ FmFreeFmanCtrlEventReg(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); ++ ++ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, 0); ++ ++ FmUnregisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); ++ } ++ /* Try first clean what has received */ ++ FmPortImRx(p_FmPort); ++ ++ /* Now, get rid of the the empty buffer! */ ++ bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); ++ ++ while (bdStatus & BD_R_E) /* while there is data in the Rx BD */ ++ { ++ p_CurData = BdBufferGet(p_FmPort->im.rxPool.f_PhysToVirt, BD_GET(p_FmPort->im.currBdId)); ++ ++ BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, BD_GET(p_FmPort->im.currBdId), NULL); ++ BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), 0); ++ ++ p_FmPort->im.rxPool.f_PutBuf(p_FmPort->im.rxPool.h_BufferPool, ++ p_CurData, ++ p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]); ++ ++ p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); ++ bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); ++ } ++ } ++ else ++ TxConf(p_FmPort, e_TX_CONF_TYPE_FLUSH); ++ ++ FM_MURAM_FreeMem(p_FmPort->im.h_FmMuram, p_FmPort->im.p_FmPortImPram); ++ ++ if (p_FmPort->im.p_BdShadow) ++ XX_Free(p_FmPort->im.p_BdShadow); ++ ++ if (p_FmPort->im.p_BdRing) ++ XX_FreeSmart(p_FmPort->im.p_BdRing); ++} ++ ++ ++t_Error FM_PORT_ConfigIMMaxRxBufLength(t_Handle h_FmPort, uint16_t newVal) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ p_FmPort->im.mrblr = newVal; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigIMRxBdRingLength(t_Handle h_FmPort, uint16_t newVal) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ p_FmPort->im.bdRingSize = newVal; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigIMTxBdRingLength(t_Handle h_FmPort, uint16_t newVal) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ p_FmPort->im.bdRingSize = newVal; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigIMFmanCtrlExternalStructsMemory(t_Handle h_FmPort, ++ uint8_t memId, ++ uint32_t memAttributes) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ p_FmPort->im.fwExtStructsMemId = memId; ++ p_FmPort->im.fwExtStructsMemAttr = memAttributes; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ConfigIMPolling(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Available for Rx ports only")); ++ ++ if (!FmIsMaster(p_FmPort->h_Fm)) ++ RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Available on master-partition only;" ++ "in guest-partitions, IM is always in polling!")); ++ ++ p_FmPort->polling = TRUE; ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_SetIMExceptions(t_Handle h_FmPort, e_FmPortExceptions exception, bool enable) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ t_Error err; ++ uint16_t tmpReg16; ++ uint32_t tmpReg32; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ if (exception == e_FM_PORT_EXCEPTION_IM_BUSY) ++ { ++ if (enable) ++ { ++ p_FmPort->exceptions |= IM_EV_BSY; ++ if (p_FmPort->fmanCtrlEventId == (uint8_t)NO_IRQ) ++ { ++ /* Allocate, configure and register interrupts */ ++ err = FmAllocFmanCtrlEventReg(p_FmPort->h_Fm, &p_FmPort->fmanCtrlEventId); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ASSERT_COND(!(p_FmPort->fmanCtrlEventId & ~IM_RXQD_FPMEVT_SEL_MASK)); ++ ++ FmRegisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, ImException, (t_Handle)p_FmPort); ++ tmpReg16 = (uint16_t)((p_FmPort->fmanCtrlEventId & IM_RXQD_FPMEVT_SEL_MASK) | IM_RXQD_BSYINTM); ++ tmpReg32 = IM_EV_BSY; ++ } ++ else ++ { ++ tmpReg16 = (uint16_t)(GET_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen) | IM_RXQD_BSYINTM); ++ tmpReg32 = FmGetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId) | IM_EV_BSY; ++ } ++ ++ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); ++ FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); ++ } ++ else ++ { ++ p_FmPort->exceptions &= ~IM_EV_BSY; ++ if (!p_FmPort->exceptions && p_FmPort->polling) ++ { ++ FmFreeFmanCtrlEventReg(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); ++ FmUnregisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); ++ FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, 0); ++ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, 0); ++ p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; ++ } ++ else ++ { ++ tmpReg16 = (uint16_t)(GET_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen) & ~IM_RXQD_BSYINTM); ++ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); ++ tmpReg32 = FmGetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId) & ~IM_EV_BSY; ++ FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); ++ } ++ } ++ } ++ else ++ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("Invalid exception.")); ++ ++ return E_OK; ++} ++ ++t_Error FM_PORT_ImTx( t_Handle h_FmPort, ++ uint8_t *p_Data, ++ uint16_t length, ++ bool lastBuffer, ++ t_Handle h_BufContext) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ uint16_t nextBdId; ++ uint32_t bdStatus, nextBdStatus; ++ bool firstBuffer; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); ++ nextBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); ++ nextBdStatus = BD_STATUS_AND_LENGTH(BD_GET(nextBdId)); ++ ++ if (!(bdStatus & BD_R_E) && !(nextBdStatus & BD_R_E)) ++ { ++ /* Confirm the current BD - BD is available */ ++ if ((bdStatus & BD_LENGTH_MASK) && (p_FmPort->im.f_TxConf)) ++ p_FmPort->im.f_TxConf (p_FmPort->h_App, ++ BdBufferGet(XX_PhysToVirt, BD_GET(p_FmPort->im.currBdId)), ++ 0, ++ p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]); ++ ++ bdStatus = length; ++ ++ /* if this is the first BD of a frame */ ++ if (p_FmPort->im.firstBdOfFrameId == IM_ILEGAL_BD_ID) ++ { ++ firstBuffer = TRUE; ++ p_FmPort->im.txFirstBdStatus = (bdStatus | BD_R_E); ++ ++ if (!lastBuffer) ++ p_FmPort->im.firstBdOfFrameId = p_FmPort->im.currBdId; ++ } ++ else ++ firstBuffer = FALSE; ++ ++ BdBufferSet(XX_VirtToPhys, BD_GET(p_FmPort->im.currBdId), p_Data); ++ p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId] = h_BufContext; ++ ++ /* deal with last */ ++ if (lastBuffer) ++ { ++ /* if single buffer frame */ ++ if (firstBuffer) ++ BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), p_FmPort->im.txFirstBdStatus | BD_L); ++ else ++ { ++ /* Set the last BD of the frame */ ++ BD_STATUS_AND_LENGTH_SET (BD_GET(p_FmPort->im.currBdId), (bdStatus | BD_R_E | BD_L)); ++ /* Set the first BD of the frame */ ++ BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.firstBdOfFrameId), p_FmPort->im.txFirstBdStatus); ++ p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; ++ } ++ WRITE_UINT16(p_FmPort->im.p_FmPortImPram->txQd.offsetIn, (uint16_t)(GetNextBdId(p_FmPort, p_FmPort->im.currBdId)<<4)); ++ } ++ else if (!firstBuffer) /* mid frame buffer */ ++ BD_STATUS_AND_LENGTH_SET (BD_GET(p_FmPort->im.currBdId), bdStatus | BD_R_E); ++ ++ p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); ++ } ++ else ++ { ++ /* Discard current frame. Return error. */ ++ if (p_FmPort->im.firstBdOfFrameId != IM_ILEGAL_BD_ID) ++ { ++ /* Error: No free BD */ ++ /* Response: Discard current frame. Return error. */ ++ uint16_t cleanBdId = p_FmPort->im.firstBdOfFrameId; ++ ++ ASSERT_COND(p_FmPort->im.firstBdOfFrameId != p_FmPort->im.currBdId); ++ ++ /* Since firstInFrame is not NULL, one buffer at least has already been ++ inserted into the BD ring. Using do-while covers the situation of a ++ frame spanned throughout the whole Tx BD ring (p_CleanBd is incremented ++ prior to testing whether or not it's equal to TxBd). */ ++ do ++ { ++ BD_STATUS_AND_LENGTH_SET(BD_GET(cleanBdId), 0); ++ /* Advance BD pointer */ ++ cleanBdId = GetNextBdId(p_FmPort, cleanBdId); ++ } while (cleanBdId != p_FmPort->im.currBdId); ++ ++ p_FmPort->im.currBdId = cleanBdId; ++ p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; ++ } ++ ++ return ERROR_CODE(E_FULL); ++ } ++ ++ return E_OK; ++} ++ ++void FM_PORT_ImTxConf(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN(p_FmPort->imEn, E_INVALID_STATE); ++ SANITY_CHECK_RETURN(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ TxConf(p_FmPort, e_TX_CONF_TYPE_CALLBACK); ++} ++ ++t_Error FM_PORT_ImRx(t_Handle h_FmPort) ++{ ++ t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); ++ ++ return FmPortImRx(p_FmPort); ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c +new file mode 100755 +index 00000000..60acbf34 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c +@@ -0,0 +1,1568 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#include "common/general.h" ++ ++#include "fman_common.h" ++#include "fsl_fman_port.h" ++ ++ ++/* problem Eyal: the following should not be here*/ ++#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME 0x00000028 ++ ++static uint32_t get_no_pcd_nia_bmi_ac_enc_frame(struct fman_port_cfg *cfg) ++{ ++ if (cfg->errata_A006675) ++ return NIA_ENG_FM_CTL | ++ NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME; ++ else ++ return NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME; ++} ++ ++static int init_bmi_rx(struct fman_port *port, ++ struct fman_port_cfg *cfg, ++ struct fman_port_params *params) ++{ ++ struct fman_port_rx_bmi_regs *regs = &port->bmi_regs->rx; ++ uint32_t tmp; ++ ++ /* Rx Configuration register */ ++ tmp = 0; ++ if (port->im_en) ++ tmp |= BMI_PORT_CFG_IM; ++ else if (cfg->discard_override) ++ tmp |= BMI_PORT_CFG_FDOVR; ++ iowrite32be(tmp, ®s->fmbm_rcfg); ++ ++ /* DMA attributes */ ++ tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT; ++ if (cfg->dma_ic_stash_on) ++ tmp |= BMI_DMA_ATTR_IC_STASH_ON; ++ if (cfg->dma_header_stash_on) ++ tmp |= BMI_DMA_ATTR_HDR_STASH_ON; ++ if (cfg->dma_sg_stash_on) ++ tmp |= BMI_DMA_ATTR_SG_STASH_ON; ++ if (cfg->dma_write_optimize) ++ tmp |= BMI_DMA_ATTR_WRITE_OPTIMIZE; ++ iowrite32be(tmp, ®s->fmbm_rda); ++ ++ /* Rx FIFO parameters */ ++ tmp = (cfg->rx_pri_elevation / FMAN_PORT_BMI_FIFO_UNITS - 1) << ++ BMI_RX_FIFO_PRI_ELEVATION_SHIFT; ++ tmp |= cfg->rx_fifo_thr / FMAN_PORT_BMI_FIFO_UNITS - 1; ++ iowrite32be(tmp, ®s->fmbm_rfp); ++ ++ if (cfg->excessive_threshold_register) ++ /* always allow access to the extra resources */ ++ iowrite32be(BMI_RX_FIFO_THRESHOLD_ETHE, ®s->fmbm_reth); ++ ++ /* Frame end data */ ++ tmp = (uint32_t)cfg->checksum_bytes_ignore << ++ BMI_RX_FRAME_END_CS_IGNORE_SHIFT; ++ tmp |= (uint32_t)cfg->rx_cut_end_bytes << ++ BMI_RX_FRAME_END_CUT_SHIFT; ++ if (cfg->errata_A006320) ++ tmp &= 0xffe0ffff; ++ iowrite32be(tmp, ®s->fmbm_rfed); ++ ++ /* Internal context parameters */ ++ tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) << ++ BMI_IC_TO_EXT_SHIFT; ++ tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) << ++ BMI_IC_FROM_INT_SHIFT; ++ tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS; ++ iowrite32be(tmp, ®s->fmbm_ricp); ++ ++ /* Internal buffer offset */ ++ tmp = ((uint32_t)cfg->int_buf_start_margin / FMAN_PORT_IC_OFFSET_UNITS) ++ << BMI_INT_BUF_MARG_SHIFT; ++ iowrite32be(tmp, ®s->fmbm_rim); ++ ++ /* External buffer margins */ ++ if (!port->im_en) ++ { ++ tmp = (uint32_t)cfg->ext_buf_start_margin << ++ BMI_EXT_BUF_MARG_START_SHIFT; ++ tmp |= (uint32_t)cfg->ext_buf_end_margin; ++ if (cfg->fmbm_rebm_has_sgd && cfg->no_scatter_gather) ++ tmp |= BMI_SG_DISABLE; ++ iowrite32be(tmp, ®s->fmbm_rebm); ++ } ++ ++ /* Frame attributes */ ++ tmp = BMI_CMD_RX_MR_DEF; ++ if (!port->im_en) ++ { ++ tmp |= BMI_CMD_ATTR_ORDER; ++ tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT; ++ if (cfg->sync_req) ++ tmp |= BMI_CMD_ATTR_SYNC; ++ } ++ iowrite32be(tmp, ®s->fmbm_rfca); ++ ++ /* NIA */ ++ if (port->im_en) ++ tmp = NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_RX; ++ else ++ { ++ tmp = (uint32_t)cfg->rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT; ++ tmp |= get_no_pcd_nia_bmi_ac_enc_frame(cfg); ++ } ++ iowrite32be(tmp, ®s->fmbm_rfne); ++ ++ /* Enqueue NIA */ ++ iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, ®s->fmbm_rfene); ++ ++ /* Default/error queues */ ++ if (!port->im_en) ++ { ++ iowrite32be((params->dflt_fqid & 0x00FFFFFF), ®s->fmbm_rfqid); ++ iowrite32be((params->err_fqid & 0x00FFFFFF), ®s->fmbm_refqid); ++ } ++ ++ /* Discard/error masks */ ++ iowrite32be(params->discard_mask, ®s->fmbm_rfsdm); ++ iowrite32be(params->err_mask, ®s->fmbm_rfsem); ++ ++ /* Statistics counters */ ++ tmp = 0; ++ if (cfg->stats_counters_enable) ++ tmp = BMI_COUNTERS_EN; ++ iowrite32be(tmp, ®s->fmbm_rstc); ++ ++ /* Performance counters */ ++ fman_port_set_perf_cnt_params(port, &cfg->perf_cnt_params); ++ tmp = 0; ++ if (cfg->perf_counters_enable) ++ tmp = BMI_COUNTERS_EN; ++ iowrite32be(tmp, ®s->fmbm_rpc); ++ ++ return 0; ++} ++ ++static int init_bmi_tx(struct fman_port *port, ++ struct fman_port_cfg *cfg, ++ struct fman_port_params *params) ++{ ++ struct fman_port_tx_bmi_regs *regs = &port->bmi_regs->tx; ++ uint32_t tmp; ++ ++ /* Tx Configuration register */ ++ tmp = 0; ++ if (port->im_en) ++ tmp |= BMI_PORT_CFG_IM; ++ iowrite32be(tmp, ®s->fmbm_tcfg); ++ ++ /* DMA attributes */ ++ tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT; ++ if (cfg->dma_ic_stash_on) ++ tmp |= BMI_DMA_ATTR_IC_STASH_ON; ++ if (cfg->dma_header_stash_on) ++ tmp |= BMI_DMA_ATTR_HDR_STASH_ON; ++ if (cfg->dma_sg_stash_on) ++ tmp |= BMI_DMA_ATTR_SG_STASH_ON; ++ iowrite32be(tmp, ®s->fmbm_tda); ++ ++ /* Tx FIFO parameters */ ++ tmp = (cfg->tx_fifo_min_level / FMAN_PORT_BMI_FIFO_UNITS) << ++ BMI_TX_FIFO_MIN_FILL_SHIFT; ++ tmp |= ((uint32_t)cfg->tx_fifo_deq_pipeline_depth - 1) << ++ BMI_FIFO_PIPELINE_DEPTH_SHIFT; ++ tmp |= (uint32_t)(cfg->tx_fifo_low_comf_level / ++ FMAN_PORT_BMI_FIFO_UNITS - 1); ++ iowrite32be(tmp, ®s->fmbm_tfp); ++ ++ /* Frame end data */ ++ tmp = (uint32_t)cfg->checksum_bytes_ignore << ++ BMI_FRAME_END_CS_IGNORE_SHIFT; ++ iowrite32be(tmp, ®s->fmbm_tfed); ++ ++ /* Internal context parameters */ ++ if (!port->im_en) ++ { ++ tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) << ++ BMI_IC_TO_EXT_SHIFT; ++ tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) << ++ BMI_IC_FROM_INT_SHIFT; ++ tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS; ++ iowrite32be(tmp, ®s->fmbm_ticp); ++ } ++ /* Frame attributes */ ++ tmp = BMI_CMD_TX_MR_DEF; ++ if (port->im_en) ++ tmp |= BMI_CMD_MR_DEAS; ++ else ++ { ++ tmp |= BMI_CMD_ATTR_ORDER; ++ tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT; ++ } ++ iowrite32be(tmp, ®s->fmbm_tfca); ++ ++ /* Dequeue NIA + enqueue NIA */ ++ if (port->im_en) ++ { ++ iowrite32be(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_TX, ®s->fmbm_tfdne); ++ iowrite32be(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_TX, ®s->fmbm_tfene); ++ } ++ else ++ { ++ iowrite32be(NIA_ENG_QMI_DEQ, ®s->fmbm_tfdne); ++ iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, ®s->fmbm_tfene); ++ if (cfg->fmbm_tfne_has_features) ++ iowrite32be(!params->dflt_fqid ? ++ BMI_EBD_EN | NIA_BMI_AC_FETCH_ALL_FRAME : ++ NIA_BMI_AC_FETCH_ALL_FRAME, ®s->fmbm_tfne); ++ if (!params->dflt_fqid && params->dont_release_buf) ++ { ++ iowrite32be(0x00FFFFFF, ®s->fmbm_tcfqid); ++ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE, ®s->fmbm_tfene); ++ if (cfg->fmbm_tfne_has_features) ++ iowrite32be(ioread32be(®s->fmbm_tfne) & ~BMI_EBD_EN, ®s->fmbm_tfne); ++ } ++ } ++ ++ /* Confirmation/error queues */ ++ if (!port->im_en) ++ { ++ if (params->dflt_fqid || !params->dont_release_buf) ++ iowrite32be(params->dflt_fqid & 0x00FFFFFF, ®s->fmbm_tcfqid); ++ iowrite32be((params->err_fqid & 0x00FFFFFF), ®s->fmbm_tefqid); ++ } ++ /* Statistics counters */ ++ tmp = 0; ++ if (cfg->stats_counters_enable) ++ tmp = BMI_COUNTERS_EN; ++ iowrite32be(tmp, ®s->fmbm_tstc); ++ ++ /* Performance counters */ ++ fman_port_set_perf_cnt_params(port, &cfg->perf_cnt_params); ++ tmp = 0; ++ if (cfg->perf_counters_enable) ++ tmp = BMI_COUNTERS_EN; ++ iowrite32be(tmp, ®s->fmbm_tpc); ++ ++ return 0; ++} ++ ++static int init_bmi_oh(struct fman_port *port, ++ struct fman_port_cfg *cfg, ++ struct fman_port_params *params) ++{ ++ struct fman_port_oh_bmi_regs *regs = &port->bmi_regs->oh; ++ uint32_t tmp; ++ ++ /* OP Configuration register */ ++ tmp = 0; ++ if (cfg->discard_override) ++ tmp |= BMI_PORT_CFG_FDOVR; ++ iowrite32be(tmp, ®s->fmbm_ocfg); ++ ++ /* DMA attributes */ ++ tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT; ++ if (cfg->dma_ic_stash_on) ++ tmp |= BMI_DMA_ATTR_IC_STASH_ON; ++ if (cfg->dma_header_stash_on) ++ tmp |= BMI_DMA_ATTR_HDR_STASH_ON; ++ if (cfg->dma_sg_stash_on) ++ tmp |= BMI_DMA_ATTR_SG_STASH_ON; ++ if (cfg->dma_write_optimize) ++ tmp |= BMI_DMA_ATTR_WRITE_OPTIMIZE; ++ iowrite32be(tmp, ®s->fmbm_oda); ++ ++ /* Tx FIFO parameters */ ++ tmp = ((uint32_t)cfg->tx_fifo_deq_pipeline_depth - 1) << ++ BMI_FIFO_PIPELINE_DEPTH_SHIFT; ++ iowrite32be(tmp, ®s->fmbm_ofp); ++ ++ /* Internal context parameters */ ++ tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) << ++ BMI_IC_TO_EXT_SHIFT; ++ tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) << ++ BMI_IC_FROM_INT_SHIFT; ++ tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS; ++ iowrite32be(tmp, ®s->fmbm_oicp); ++ ++ /* Frame attributes */ ++ tmp = BMI_CMD_OP_MR_DEF; ++ tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT; ++ if (cfg->sync_req) ++ tmp |= BMI_CMD_ATTR_SYNC; ++ if (port->type == E_FMAN_PORT_TYPE_OP) ++ tmp |= BMI_CMD_ATTR_ORDER; ++ iowrite32be(tmp, ®s->fmbm_ofca); ++ ++ /* Internal buffer offset */ ++ tmp = ((uint32_t)cfg->int_buf_start_margin / FMAN_PORT_IC_OFFSET_UNITS) ++ << BMI_INT_BUF_MARG_SHIFT; ++ iowrite32be(tmp, ®s->fmbm_oim); ++ ++ /* Dequeue NIA */ ++ iowrite32be(NIA_ENG_QMI_DEQ, ®s->fmbm_ofdne); ++ ++ /* NIA and Enqueue NIA */ ++ if (port->type == E_FMAN_PORT_TYPE_HC) { ++ iowrite32be(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_HC, ++ ®s->fmbm_ofne); ++ iowrite32be(NIA_ENG_QMI_ENQ, ®s->fmbm_ofene); ++ } else { ++ iowrite32be(get_no_pcd_nia_bmi_ac_enc_frame(cfg), ++ ®s->fmbm_ofne); ++ iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, ++ ®s->fmbm_ofene); ++ } ++ ++ /* Default/error queues */ ++ iowrite32be((params->dflt_fqid & 0x00FFFFFF), ®s->fmbm_ofqid); ++ iowrite32be((params->err_fqid & 0x00FFFFFF), ®s->fmbm_oefqid); ++ ++ /* Discard/error masks */ ++ if (port->type == E_FMAN_PORT_TYPE_OP) { ++ iowrite32be(params->discard_mask, ®s->fmbm_ofsdm); ++ iowrite32be(params->err_mask, ®s->fmbm_ofsem); ++ } ++ ++ /* Statistics counters */ ++ tmp = 0; ++ if (cfg->stats_counters_enable) ++ tmp = BMI_COUNTERS_EN; ++ iowrite32be(tmp, ®s->fmbm_ostc); ++ ++ /* Performance counters */ ++ fman_port_set_perf_cnt_params(port, &cfg->perf_cnt_params); ++ tmp = 0; ++ if (cfg->perf_counters_enable) ++ tmp = BMI_COUNTERS_EN; ++ iowrite32be(tmp, ®s->fmbm_opc); ++ ++ return 0; ++} ++ ++static int init_qmi(struct fman_port *port, ++ struct fman_port_cfg *cfg, ++ struct fman_port_params *params) ++{ ++ struct fman_port_qmi_regs *regs = port->qmi_regs; ++ uint32_t tmp; ++ ++ tmp = 0; ++ if (cfg->queue_counters_enable) ++ tmp |= QMI_PORT_CFG_EN_COUNTERS; ++ iowrite32be(tmp, ®s->fmqm_pnc); ++ ++ /* Rx port configuration */ ++ if ((port->type == E_FMAN_PORT_TYPE_RX) || ++ (port->type == E_FMAN_PORT_TYPE_RX_10G)) { ++ /* Enqueue NIA */ ++ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_RELEASE, ®s->fmqm_pnen); ++ return 0; ++ } ++ ++ /* Continue with Tx and O/H port configuration */ ++ if ((port->type == E_FMAN_PORT_TYPE_TX) || ++ (port->type == E_FMAN_PORT_TYPE_TX_10G)) { ++ /* Enqueue NIA */ ++ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE, ++ ®s->fmqm_pnen); ++ /* Dequeue NIA */ ++ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX, ®s->fmqm_pndn); ++ } else { ++ /* Enqueue NIA */ ++ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_RELEASE, ®s->fmqm_pnen); ++ /* Dequeue NIA */ ++ iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_FETCH, ®s->fmqm_pndn); ++ } ++ ++ /* Dequeue Configuration register */ ++ tmp = 0; ++ if (cfg->deq_high_pri) ++ tmp |= QMI_DEQ_CFG_PRI; ++ ++ switch (cfg->deq_type) { ++ case E_FMAN_PORT_DEQ_BY_PRI: ++ tmp |= QMI_DEQ_CFG_TYPE1; ++ break; ++ case E_FMAN_PORT_DEQ_ACTIVE_FQ: ++ tmp |= QMI_DEQ_CFG_TYPE2; ++ break; ++ case E_FMAN_PORT_DEQ_ACTIVE_FQ_NO_ICS: ++ tmp |= QMI_DEQ_CFG_TYPE3; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (cfg->qmi_deq_options_support) { ++ if ((port->type == E_FMAN_PORT_TYPE_HC) && ++ (cfg->deq_prefetch_opt != E_FMAN_PORT_DEQ_NO_PREFETCH)) ++ return -EINVAL; ++ ++ switch (cfg->deq_prefetch_opt) { ++ case E_FMAN_PORT_DEQ_NO_PREFETCH: ++ break; ++ case E_FMAN_PORT_DEQ_PART_PREFETCH: ++ tmp |= QMI_DEQ_CFG_PREFETCH_PARTIAL; ++ break; ++ case E_FMAN_PORT_DEQ_FULL_PREFETCH: ++ tmp |= QMI_DEQ_CFG_PREFETCH_FULL; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ tmp |= (uint32_t)(params->deq_sp & QMI_DEQ_CFG_SP_MASK) << ++ QMI_DEQ_CFG_SP_SHIFT; ++ tmp |= cfg->deq_byte_cnt; ++ iowrite32be(tmp, ®s->fmqm_pndc); ++ ++ return 0; ++} ++ ++static void get_rx_stats_reg(struct fman_port *port, ++ enum fman_port_stats_counters counter, ++ uint32_t **stats_reg) ++{ ++ struct fman_port_rx_bmi_regs *regs = &port->bmi_regs->rx; ++ ++ switch (counter) { ++ case E_FMAN_PORT_STATS_CNT_FRAME: ++ *stats_reg = ®s->fmbm_rfrc; ++ break; ++ case E_FMAN_PORT_STATS_CNT_DISCARD: ++ *stats_reg = ®s->fmbm_rfdc; ++ break; ++ case E_FMAN_PORT_STATS_CNT_DEALLOC_BUF: ++ *stats_reg = ®s->fmbm_rbdc; ++ break; ++ case E_FMAN_PORT_STATS_CNT_RX_BAD_FRAME: ++ *stats_reg = ®s->fmbm_rfbc; ++ break; ++ case E_FMAN_PORT_STATS_CNT_RX_LARGE_FRAME: ++ *stats_reg = ®s->fmbm_rlfc; ++ break; ++ case E_FMAN_PORT_STATS_CNT_RX_OUT_OF_BUF: ++ *stats_reg = ®s->fmbm_rodc; ++ break; ++ case E_FMAN_PORT_STATS_CNT_FILTERED_FRAME: ++ *stats_reg = ®s->fmbm_rffc; ++ break; ++ case E_FMAN_PORT_STATS_CNT_DMA_ERR: ++ *stats_reg = ®s->fmbm_rfldec; ++ break; ++ default: ++ *stats_reg = NULL; ++ } ++} ++ ++static void get_tx_stats_reg(struct fman_port *port, ++ enum fman_port_stats_counters counter, ++ uint32_t **stats_reg) ++{ ++ struct fman_port_tx_bmi_regs *regs = &port->bmi_regs->tx; ++ ++ switch (counter) { ++ case E_FMAN_PORT_STATS_CNT_FRAME: ++ *stats_reg = ®s->fmbm_tfrc; ++ break; ++ case E_FMAN_PORT_STATS_CNT_DISCARD: ++ *stats_reg = ®s->fmbm_tfdc; ++ break; ++ case E_FMAN_PORT_STATS_CNT_DEALLOC_BUF: ++ *stats_reg = ®s->fmbm_tbdc; ++ break; ++ case E_FMAN_PORT_STATS_CNT_LEN_ERR: ++ *stats_reg = ®s->fmbm_tfledc; ++ break; ++ case E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT: ++ *stats_reg = ®s->fmbm_tfufdc; ++ break; ++ default: ++ *stats_reg = NULL; ++ } ++} ++ ++static void get_oh_stats_reg(struct fman_port *port, ++ enum fman_port_stats_counters counter, ++ uint32_t **stats_reg) ++{ ++ struct fman_port_oh_bmi_regs *regs = &port->bmi_regs->oh; ++ ++ switch (counter) { ++ case E_FMAN_PORT_STATS_CNT_FRAME: ++ *stats_reg = ®s->fmbm_ofrc; ++ break; ++ case E_FMAN_PORT_STATS_CNT_DISCARD: ++ *stats_reg = ®s->fmbm_ofdc; ++ break; ++ case E_FMAN_PORT_STATS_CNT_DEALLOC_BUF: ++ *stats_reg = ®s->fmbm_obdc; ++ break; ++ case E_FMAN_PORT_STATS_CNT_FILTERED_FRAME: ++ *stats_reg = ®s->fmbm_offc; ++ break; ++ case E_FMAN_PORT_STATS_CNT_DMA_ERR: ++ *stats_reg = ®s->fmbm_ofldec; ++ break; ++ case E_FMAN_PORT_STATS_CNT_LEN_ERR: ++ *stats_reg = ®s->fmbm_ofledc; ++ break; ++ case E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT: ++ *stats_reg = ®s->fmbm_ofufdc; ++ break; ++ case E_FMAN_PORT_STATS_CNT_WRED_DISCARD: ++ *stats_reg = ®s->fmbm_ofwdc; ++ break; ++ default: ++ *stats_reg = NULL; ++ } ++} ++ ++static void get_rx_perf_reg(struct fman_port *port, ++ enum fman_port_perf_counters counter, ++ uint32_t **perf_reg) ++{ ++ struct fman_port_rx_bmi_regs *regs = &port->bmi_regs->rx; ++ ++ switch (counter) { ++ case E_FMAN_PORT_PERF_CNT_CYCLE: ++ *perf_reg = ®s->fmbm_rccn; ++ break; ++ case E_FMAN_PORT_PERF_CNT_TASK_UTIL: ++ *perf_reg = ®s->fmbm_rtuc; ++ break; ++ case E_FMAN_PORT_PERF_CNT_QUEUE_UTIL: ++ *perf_reg = ®s->fmbm_rrquc; ++ break; ++ case E_FMAN_PORT_PERF_CNT_DMA_UTIL: ++ *perf_reg = ®s->fmbm_rduc; ++ break; ++ case E_FMAN_PORT_PERF_CNT_FIFO_UTIL: ++ *perf_reg = ®s->fmbm_rfuc; ++ break; ++ case E_FMAN_PORT_PERF_CNT_RX_PAUSE: ++ *perf_reg = ®s->fmbm_rpac; ++ break; ++ default: ++ *perf_reg = NULL; ++ } ++} ++ ++static void get_tx_perf_reg(struct fman_port *port, ++ enum fman_port_perf_counters counter, ++ uint32_t **perf_reg) ++{ ++ struct fman_port_tx_bmi_regs *regs = &port->bmi_regs->tx; ++ ++ switch (counter) { ++ case E_FMAN_PORT_PERF_CNT_CYCLE: ++ *perf_reg = ®s->fmbm_tccn; ++ break; ++ case E_FMAN_PORT_PERF_CNT_TASK_UTIL: ++ *perf_reg = ®s->fmbm_ttuc; ++ break; ++ case E_FMAN_PORT_PERF_CNT_QUEUE_UTIL: ++ *perf_reg = ®s->fmbm_ttcquc; ++ break; ++ case E_FMAN_PORT_PERF_CNT_DMA_UTIL: ++ *perf_reg = ®s->fmbm_tduc; ++ break; ++ case E_FMAN_PORT_PERF_CNT_FIFO_UTIL: ++ *perf_reg = ®s->fmbm_tfuc; ++ break; ++ default: ++ *perf_reg = NULL; ++ } ++} ++ ++static void get_oh_perf_reg(struct fman_port *port, ++ enum fman_port_perf_counters counter, ++ uint32_t **perf_reg) ++{ ++ struct fman_port_oh_bmi_regs *regs = &port->bmi_regs->oh; ++ ++ switch (counter) { ++ case E_FMAN_PORT_PERF_CNT_CYCLE: ++ *perf_reg = ®s->fmbm_occn; ++ break; ++ case E_FMAN_PORT_PERF_CNT_TASK_UTIL: ++ *perf_reg = ®s->fmbm_otuc; ++ break; ++ case E_FMAN_PORT_PERF_CNT_DMA_UTIL: ++ *perf_reg = ®s->fmbm_oduc; ++ break; ++ case E_FMAN_PORT_PERF_CNT_FIFO_UTIL: ++ *perf_reg = ®s->fmbm_ofuc; ++ break; ++ default: ++ *perf_reg = NULL; ++ } ++} ++ ++static void get_qmi_counter_reg(struct fman_port *port, ++ enum fman_port_qmi_counters counter, ++ uint32_t **queue_reg) ++{ ++ struct fman_port_qmi_regs *regs = port->qmi_regs; ++ ++ switch (counter) { ++ case E_FMAN_PORT_ENQ_TOTAL: ++ *queue_reg = ®s->fmqm_pnetfc; ++ break; ++ case E_FMAN_PORT_DEQ_TOTAL: ++ if ((port->type == E_FMAN_PORT_TYPE_RX) || ++ (port->type == E_FMAN_PORT_TYPE_RX_10G)) ++ /* Counter not available for Rx ports */ ++ *queue_reg = NULL; ++ else ++ *queue_reg = ®s->fmqm_pndtfc; ++ break; ++ case E_FMAN_PORT_DEQ_FROM_DFLT: ++ if ((port->type == E_FMAN_PORT_TYPE_RX) || ++ (port->type == E_FMAN_PORT_TYPE_RX_10G)) ++ /* Counter not available for Rx ports */ ++ *queue_reg = NULL; ++ else ++ *queue_reg = ®s->fmqm_pndfdc; ++ break; ++ case E_FMAN_PORT_DEQ_CONFIRM: ++ if ((port->type == E_FMAN_PORT_TYPE_RX) || ++ (port->type == E_FMAN_PORT_TYPE_RX_10G)) ++ /* Counter not available for Rx ports */ ++ *queue_reg = NULL; ++ else ++ *queue_reg = ®s->fmqm_pndcc; ++ break; ++ default: ++ *queue_reg = NULL; ++ } ++} ++ ++void fman_port_defconfig(struct fman_port_cfg *cfg, enum fman_port_type type) ++{ ++ cfg->dma_swap_data = E_FMAN_PORT_DMA_NO_SWAP; ++ cfg->dma_ic_stash_on = FALSE; ++ cfg->dma_header_stash_on = FALSE; ++ cfg->dma_sg_stash_on = FALSE; ++ cfg->dma_write_optimize = TRUE; ++ cfg->color = E_FMAN_PORT_COLOR_GREEN; ++ cfg->discard_override = FALSE; ++ cfg->checksum_bytes_ignore = 0; ++ cfg->rx_cut_end_bytes = 4; ++ cfg->rx_pri_elevation = ((0x3FF + 1) * FMAN_PORT_BMI_FIFO_UNITS); ++ cfg->rx_fifo_thr = ((0x3FF + 1) * FMAN_PORT_BMI_FIFO_UNITS); ++ cfg->rx_fd_bits = 0; ++ cfg->ic_ext_offset = 0; ++ cfg->ic_int_offset = 0; ++ cfg->ic_size = 0; ++ cfg->int_buf_start_margin = 0; ++ cfg->ext_buf_start_margin = 0; ++ cfg->ext_buf_end_margin = 0; ++ cfg->tx_fifo_min_level = 0; ++ cfg->tx_fifo_low_comf_level = (5 * KILOBYTE); ++ cfg->stats_counters_enable = TRUE; ++ cfg->perf_counters_enable = TRUE; ++ cfg->deq_type = E_FMAN_PORT_DEQ_BY_PRI; ++ ++ if (type == E_FMAN_PORT_TYPE_HC) { ++ cfg->sync_req = FALSE; ++ cfg->deq_prefetch_opt = E_FMAN_PORT_DEQ_NO_PREFETCH; ++ } else { ++ cfg->sync_req = TRUE; ++ cfg->deq_prefetch_opt = E_FMAN_PORT_DEQ_FULL_PREFETCH; ++ } ++ ++ if (type == E_FMAN_PORT_TYPE_TX_10G) { ++ cfg->tx_fifo_deq_pipeline_depth = 4; ++ cfg->deq_high_pri = TRUE; ++ cfg->deq_byte_cnt = 0x1400; ++ } else { ++ if ((type == E_FMAN_PORT_TYPE_HC) || ++ (type == E_FMAN_PORT_TYPE_OP)) ++ cfg->tx_fifo_deq_pipeline_depth = 2; ++ else ++ cfg->tx_fifo_deq_pipeline_depth = 1; ++ ++ cfg->deq_high_pri = FALSE; ++ cfg->deq_byte_cnt = 0x400; ++ } ++ cfg->no_scatter_gather = DEFAULT_FMAN_SP_NO_SCATTER_GATHER; ++} ++ ++static uint8_t fman_port_find_bpool(struct fman_port *port, uint8_t bpid) ++{ ++ uint32_t *bp_reg, tmp; ++ uint8_t i, id; ++ ++ /* Find the pool */ ++ bp_reg = port->bmi_regs->rx.fmbm_ebmpi; ++ for (i = 0; ++ (i < port->ext_pools_num && (i < FMAN_PORT_MAX_EXT_POOLS_NUM)); ++ i++) { ++ tmp = ioread32be(&bp_reg[i]); ++ id = (uint8_t)((tmp & BMI_EXT_BUF_POOL_ID_MASK) >> ++ BMI_EXT_BUF_POOL_ID_SHIFT); ++ ++ if (id == bpid) ++ break; ++ } ++ ++ return i; ++} ++ ++int fman_port_init(struct fman_port *port, ++ struct fman_port_cfg *cfg, ++ struct fman_port_params *params) ++{ ++ int err; ++ ++ /* Init BMI registers */ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ err = init_bmi_rx(port, cfg, params); ++ break; ++ case E_FMAN_PORT_TYPE_TX: ++ case E_FMAN_PORT_TYPE_TX_10G: ++ err = init_bmi_tx(port, cfg, params); ++ break; ++ case E_FMAN_PORT_TYPE_OP: ++ case E_FMAN_PORT_TYPE_HC: ++ err = init_bmi_oh(port, cfg, params); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (err) ++ return err; ++ ++ /* Init QMI registers */ ++ if (!port->im_en) ++ { ++ err = init_qmi(port, cfg, params); ++ return err; ++ } ++ return 0; ++} ++ ++int fman_port_enable(struct fman_port *port) ++{ ++ uint32_t *bmi_cfg_reg, tmp; ++ bool rx_port; ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ bmi_cfg_reg = &port->bmi_regs->rx.fmbm_rcfg; ++ rx_port = TRUE; ++ break; ++ case E_FMAN_PORT_TYPE_TX: ++ case E_FMAN_PORT_TYPE_TX_10G: ++ bmi_cfg_reg = &port->bmi_regs->tx.fmbm_tcfg; ++ rx_port = FALSE; ++ break; ++ case E_FMAN_PORT_TYPE_OP: ++ case E_FMAN_PORT_TYPE_HC: ++ bmi_cfg_reg = &port->bmi_regs->oh.fmbm_ocfg; ++ rx_port = FALSE; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* Enable QMI */ ++ if (!rx_port) { ++ tmp = ioread32be(&port->qmi_regs->fmqm_pnc) | QMI_PORT_CFG_EN; ++ iowrite32be(tmp, &port->qmi_regs->fmqm_pnc); ++ } ++ ++ /* Enable BMI */ ++ tmp = ioread32be(bmi_cfg_reg) | BMI_PORT_CFG_EN; ++ iowrite32be(tmp, bmi_cfg_reg); ++ ++ return 0; ++} ++ ++int fman_port_disable(const struct fman_port *port) ++{ ++ uint32_t *bmi_cfg_reg, *bmi_status_reg, tmp; ++ bool rx_port, failure = FALSE; ++ int count; ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ bmi_cfg_reg = &port->bmi_regs->rx.fmbm_rcfg; ++ bmi_status_reg = &port->bmi_regs->rx.fmbm_rst; ++ rx_port = TRUE; ++ break; ++ case E_FMAN_PORT_TYPE_TX: ++ case E_FMAN_PORT_TYPE_TX_10G: ++ bmi_cfg_reg = &port->bmi_regs->tx.fmbm_tcfg; ++ bmi_status_reg = &port->bmi_regs->tx.fmbm_tst; ++ rx_port = FALSE; ++ break; ++ case E_FMAN_PORT_TYPE_OP: ++ case E_FMAN_PORT_TYPE_HC: ++ bmi_cfg_reg = &port->bmi_regs->oh.fmbm_ocfg; ++ bmi_status_reg = &port->bmi_regs->oh.fmbm_ost; ++ rx_port = FALSE; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* Disable QMI */ ++ if (!rx_port) { ++ tmp = ioread32be(&port->qmi_regs->fmqm_pnc) & ~QMI_PORT_CFG_EN; ++ iowrite32be(tmp, &port->qmi_regs->fmqm_pnc); ++ ++ /* Wait for QMI to finish FD handling */ ++ count = 100; ++ do { ++ udelay(10); ++ tmp = ioread32be(&port->qmi_regs->fmqm_pns); ++ } while ((tmp & QMI_PORT_STATUS_DEQ_FD_BSY) && --count); ++ ++ if (count == 0) ++ { ++ /* Timeout */ ++ failure = TRUE; ++ } ++ } ++ ++ /* Disable BMI */ ++ tmp = ioread32be(bmi_cfg_reg) & ~BMI_PORT_CFG_EN; ++ iowrite32be(tmp, bmi_cfg_reg); ++ ++ /* Wait for graceful stop end */ ++ count = 500; ++ do { ++ udelay(10); ++ tmp = ioread32be(bmi_status_reg); ++ } while ((tmp & BMI_PORT_STATUS_BSY) && --count); ++ ++ if (count == 0) ++ { ++ /* Timeout */ ++ failure = TRUE; ++ } ++ ++ if (failure) ++ return -EBUSY; ++ ++ return 0; ++} ++ ++int fman_port_set_bpools(const struct fman_port *port, ++ const struct fman_port_bpools *bp) ++{ ++ uint32_t tmp, *bp_reg, *bp_depl_reg; ++ uint8_t i, max_bp_num; ++ bool grp_depl_used = FALSE, rx_port; ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ max_bp_num = port->ext_pools_num; ++ rx_port = TRUE; ++ bp_reg = port->bmi_regs->rx.fmbm_ebmpi; ++ bp_depl_reg = &port->bmi_regs->rx.fmbm_mpd; ++ break; ++ case E_FMAN_PORT_TYPE_OP: ++ if (port->fm_rev_maj != 4) ++ return -EINVAL; ++ max_bp_num = FMAN_PORT_OBS_EXT_POOLS_NUM; ++ rx_port = FALSE; ++ bp_reg = port->bmi_regs->oh.fmbm_oebmpi; ++ bp_depl_reg = &port->bmi_regs->oh.fmbm_ompd; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (rx_port) { ++ /* Check buffers are provided in ascending order */ ++ for (i = 0; ++ (i < (bp->count-1) && (i < FMAN_PORT_MAX_EXT_POOLS_NUM - 1)); ++ i++) { ++ if (bp->bpool[i].size > bp->bpool[i+1].size) ++ return -EINVAL; ++ } ++ } ++ ++ /* Set up external buffers pools */ ++ for (i = 0; i < bp->count; i++) { ++ tmp = BMI_EXT_BUF_POOL_VALID; ++ tmp |= ((uint32_t)bp->bpool[i].bpid << ++ BMI_EXT_BUF_POOL_ID_SHIFT) & BMI_EXT_BUF_POOL_ID_MASK; ++ ++ if (rx_port) { ++ if (bp->counters_enable) ++ tmp |= BMI_EXT_BUF_POOL_EN_COUNTER; ++ ++ if (bp->bpool[i].is_backup) ++ tmp |= BMI_EXT_BUF_POOL_BACKUP; ++ ++ tmp |= (uint32_t)bp->bpool[i].size; ++ } ++ ++ iowrite32be(tmp, &bp_reg[i]); ++ } ++ ++ /* Clear unused pools */ ++ for (i = bp->count; i < max_bp_num; i++) ++ iowrite32be(0, &bp_reg[i]); ++ ++ /* Pools depletion */ ++ tmp = 0; ++ for (i = 0; i < FMAN_PORT_MAX_EXT_POOLS_NUM; i++) { ++ if (bp->bpool[i].grp_bp_depleted) { ++ grp_depl_used = TRUE; ++ tmp |= 0x80000000 >> i; ++ } ++ ++ if (bp->bpool[i].single_bp_depleted) ++ tmp |= 0x80 >> i; ++ ++ if (bp->bpool[i].pfc_priorities_en) ++ tmp |= 0x0100 << i; ++ } ++ ++ if (grp_depl_used) ++ tmp |= ((uint32_t)bp->grp_bp_depleted_num - 1) << ++ BMI_POOL_DEP_NUM_OF_POOLS_SHIFT; ++ ++ iowrite32be(tmp, bp_depl_reg); ++ return 0; ++} ++ ++int fman_port_set_rate_limiter(struct fman_port *port, ++ struct fman_port_rate_limiter *rate_limiter) ++{ ++ uint32_t *rate_limit_reg, *rate_limit_scale_reg; ++ uint32_t granularity, tmp; ++ uint8_t usec_bit, factor; ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_TX: ++ case E_FMAN_PORT_TYPE_TX_10G: ++ rate_limit_reg = &port->bmi_regs->tx.fmbm_trlmt; ++ rate_limit_scale_reg = &port->bmi_regs->tx.fmbm_trlmts; ++ granularity = BMI_RATE_LIMIT_GRAN_TX; ++ break; ++ case E_FMAN_PORT_TYPE_OP: ++ rate_limit_reg = &port->bmi_regs->oh.fmbm_orlmt; ++ rate_limit_scale_reg = &port->bmi_regs->oh.fmbm_orlmts; ++ granularity = BMI_RATE_LIMIT_GRAN_OP; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* Factor is per 1 usec count */ ++ factor = 1; ++ usec_bit = rate_limiter->count_1micro_bit; ++ ++ /* If rate limit is too small for an 1usec factor, adjust timestamp ++ * scale and multiply the factor */ ++ while (rate_limiter->rate < (granularity / factor)) { ++ if (usec_bit == 31) ++ /* Can't configure rate limiter - rate is too small */ ++ return -EINVAL; ++ ++ usec_bit++; ++ factor <<= 1; ++ } ++ ++ /* Figure out register value. The "while" above quarantees that ++ * (rate_limiter->rate * factor / granularity) >= 1 */ ++ tmp = (uint32_t)(rate_limiter->rate * factor / granularity - 1); ++ ++ /* Check rate limit isn't too large */ ++ if (tmp >= BMI_RATE_LIMIT_MAX_RATE_IN_GRAN_UNITS) ++ return -EINVAL; ++ ++ /* Check burst size is in allowed range */ ++ if ((rate_limiter->burst_size == 0) || ++ (rate_limiter->burst_size > ++ BMI_RATE_LIMIT_MAX_BURST_SIZE)) ++ return -EINVAL; ++ ++ tmp |= (uint32_t)(rate_limiter->burst_size - 1) << ++ BMI_RATE_LIMIT_MAX_BURST_SHIFT; ++ ++ if ((port->type == E_FMAN_PORT_TYPE_OP) && ++ (port->fm_rev_maj == 4)) { ++ if (rate_limiter->high_burst_size_gran) ++ tmp |= BMI_RATE_LIMIT_HIGH_BURST_SIZE_GRAN; ++ } ++ ++ iowrite32be(tmp, rate_limit_reg); ++ ++ /* Set up rate limiter scale register */ ++ tmp = BMI_RATE_LIMIT_SCALE_EN; ++ tmp |= (31 - (uint32_t)usec_bit) << BMI_RATE_LIMIT_SCALE_TSBS_SHIFT; ++ ++ if ((port->type == E_FMAN_PORT_TYPE_OP) && ++ (port->fm_rev_maj == 4)) ++ tmp |= rate_limiter->rate_factor; ++ ++ iowrite32be(tmp, rate_limit_scale_reg); ++ ++ return 0; ++} ++ ++int fman_port_delete_rate_limiter(struct fman_port *port) ++{ ++ uint32_t *rate_limit_scale_reg; ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_TX: ++ case E_FMAN_PORT_TYPE_TX_10G: ++ rate_limit_scale_reg = &port->bmi_regs->tx.fmbm_trlmts; ++ break; ++ case E_FMAN_PORT_TYPE_OP: ++ rate_limit_scale_reg = &port->bmi_regs->oh.fmbm_orlmts; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ iowrite32be(0, rate_limit_scale_reg); ++ return 0; ++} ++ ++int fman_port_set_err_mask(struct fman_port *port, uint32_t err_mask) ++{ ++ uint32_t *err_mask_reg; ++ ++ /* Obtain register address */ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ err_mask_reg = &port->bmi_regs->rx.fmbm_rfsem; ++ break; ++ case E_FMAN_PORT_TYPE_OP: ++ err_mask_reg = &port->bmi_regs->oh.fmbm_ofsem; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ iowrite32be(err_mask, err_mask_reg); ++ return 0; ++} ++ ++int fman_port_set_discard_mask(struct fman_port *port, uint32_t discard_mask) ++{ ++ uint32_t *discard_mask_reg; ++ ++ /* Obtain register address */ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ discard_mask_reg = &port->bmi_regs->rx.fmbm_rfsdm; ++ break; ++ case E_FMAN_PORT_TYPE_OP: ++ discard_mask_reg = &port->bmi_regs->oh.fmbm_ofsdm; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ iowrite32be(discard_mask, discard_mask_reg); ++ return 0; ++} ++ ++int fman_port_modify_rx_fd_bits(struct fman_port *port, ++ uint8_t rx_fd_bits, ++ bool add) ++{ ++ uint32_t tmp; ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ tmp = ioread32be(&port->bmi_regs->rx.fmbm_rfne); ++ ++ if (add) ++ tmp |= (uint32_t)rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT; ++ else ++ tmp &= ~((uint32_t)rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT); ++ ++ iowrite32be(tmp, &port->bmi_regs->rx.fmbm_rfne); ++ return 0; ++} ++ ++int fman_port_set_perf_cnt_params(struct fman_port *port, ++ struct fman_port_perf_cnt_params *params) ++{ ++ uint32_t *pcp_reg, tmp; ++ ++ /* Obtain register address and check parameters are in range */ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ pcp_reg = &port->bmi_regs->rx.fmbm_rpcp; ++ if ((params->queue_val == 0) || ++ (params->queue_val > MAX_PERFORMANCE_RX_QUEUE_COMP)) ++ return -EINVAL; ++ break; ++ case E_FMAN_PORT_TYPE_TX: ++ case E_FMAN_PORT_TYPE_TX_10G: ++ pcp_reg = &port->bmi_regs->tx.fmbm_tpcp; ++ if ((params->queue_val == 0) || ++ (params->queue_val > MAX_PERFORMANCE_TX_QUEUE_COMP)) ++ return -EINVAL; ++ break; ++ case E_FMAN_PORT_TYPE_OP: ++ case E_FMAN_PORT_TYPE_HC: ++ pcp_reg = &port->bmi_regs->oh.fmbm_opcp; ++ if (params->queue_val != 0) ++ return -EINVAL; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if ((params->task_val == 0) || ++ (params->task_val > MAX_PERFORMANCE_TASK_COMP)) ++ return -EINVAL; ++ if ((params->dma_val == 0) || ++ (params->dma_val > MAX_PERFORMANCE_DMA_COMP)) ++ return -EINVAL; ++ if ((params->fifo_val == 0) || ++ ((params->fifo_val / FMAN_PORT_BMI_FIFO_UNITS) > ++ MAX_PERFORMANCE_FIFO_COMP)) ++ return -EINVAL; ++ tmp = (uint32_t)(params->task_val - 1) << ++ BMI_PERFORMANCE_TASK_COMP_SHIFT; ++ tmp |= (uint32_t)(params->dma_val - 1) << ++ BMI_PERFORMANCE_DMA_COMP_SHIFT; ++ tmp |= (uint32_t)(params->fifo_val / FMAN_PORT_BMI_FIFO_UNITS - 1); ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ case E_FMAN_PORT_TYPE_TX: ++ case E_FMAN_PORT_TYPE_TX_10G: ++ tmp |= (uint32_t)(params->queue_val - 1) << ++ BMI_PERFORMANCE_QUEUE_COMP_SHIFT; ++ break; ++ default: ++ break; ++ } ++ ++ ++ iowrite32be(tmp, pcp_reg); ++ return 0; ++} ++ ++int fman_port_set_stats_cnt_mode(struct fman_port *port, bool enable) ++{ ++ uint32_t *stats_reg, tmp; ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ stats_reg = &port->bmi_regs->rx.fmbm_rstc; ++ break; ++ case E_FMAN_PORT_TYPE_TX: ++ case E_FMAN_PORT_TYPE_TX_10G: ++ stats_reg = &port->bmi_regs->tx.fmbm_tstc; ++ break; ++ case E_FMAN_PORT_TYPE_OP: ++ case E_FMAN_PORT_TYPE_HC: ++ stats_reg = &port->bmi_regs->oh.fmbm_ostc; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ tmp = ioread32be(stats_reg); ++ ++ if (enable) ++ tmp |= BMI_COUNTERS_EN; ++ else ++ tmp &= ~BMI_COUNTERS_EN; ++ ++ iowrite32be(tmp, stats_reg); ++ return 0; ++} ++ ++int fman_port_set_perf_cnt_mode(struct fman_port *port, bool enable) ++{ ++ uint32_t *stats_reg, tmp; ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ stats_reg = &port->bmi_regs->rx.fmbm_rpc; ++ break; ++ case E_FMAN_PORT_TYPE_TX: ++ case E_FMAN_PORT_TYPE_TX_10G: ++ stats_reg = &port->bmi_regs->tx.fmbm_tpc; ++ break; ++ case E_FMAN_PORT_TYPE_OP: ++ case E_FMAN_PORT_TYPE_HC: ++ stats_reg = &port->bmi_regs->oh.fmbm_opc; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ tmp = ioread32be(stats_reg); ++ ++ if (enable) ++ tmp |= BMI_COUNTERS_EN; ++ else ++ tmp &= ~BMI_COUNTERS_EN; ++ ++ iowrite32be(tmp, stats_reg); ++ return 0; ++} ++ ++int fman_port_set_queue_cnt_mode(struct fman_port *port, bool enable) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(&port->qmi_regs->fmqm_pnc); ++ ++ if (enable) ++ tmp |= QMI_PORT_CFG_EN_COUNTERS; ++ else ++ tmp &= ~QMI_PORT_CFG_EN_COUNTERS; ++ ++ iowrite32be(tmp, &port->qmi_regs->fmqm_pnc); ++ return 0; ++} ++ ++int fman_port_set_bpool_cnt_mode(struct fman_port *port, ++ uint8_t bpid, ++ bool enable) ++{ ++ uint8_t index; ++ uint32_t tmp; ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* Find the pool */ ++ index = fman_port_find_bpool(port, bpid); ++ if (index == port->ext_pools_num || index == FMAN_PORT_MAX_EXT_POOLS_NUM) ++ /* Not found */ ++ return -EINVAL; ++ ++ tmp = ioread32be(&port->bmi_regs->rx.fmbm_ebmpi[index]); ++ ++ if (enable) ++ tmp |= BMI_EXT_BUF_POOL_EN_COUNTER; ++ else ++ tmp &= ~BMI_EXT_BUF_POOL_EN_COUNTER; ++ ++ iowrite32be(tmp, &port->bmi_regs->rx.fmbm_ebmpi[index]); ++ return 0; ++} ++ ++uint32_t fman_port_get_stats_counter(struct fman_port *port, ++ enum fman_port_stats_counters counter) ++{ ++ uint32_t *stats_reg, ret_val; ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ get_rx_stats_reg(port, counter, &stats_reg); ++ break; ++ case E_FMAN_PORT_TYPE_TX: ++ case E_FMAN_PORT_TYPE_TX_10G: ++ get_tx_stats_reg(port, counter, &stats_reg); ++ break; ++ case E_FMAN_PORT_TYPE_OP: ++ case E_FMAN_PORT_TYPE_HC: ++ get_oh_stats_reg(port, counter, &stats_reg); ++ break; ++ default: ++ stats_reg = NULL; ++ } ++ ++ if (stats_reg == NULL) ++ return 0; ++ ++ ret_val = ioread32be(stats_reg); ++ return ret_val; ++} ++ ++void fman_port_set_stats_counter(struct fman_port *port, ++ enum fman_port_stats_counters counter, ++ uint32_t value) ++{ ++ uint32_t *stats_reg; ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ get_rx_stats_reg(port, counter, &stats_reg); ++ break; ++ case E_FMAN_PORT_TYPE_TX: ++ case E_FMAN_PORT_TYPE_TX_10G: ++ get_tx_stats_reg(port, counter, &stats_reg); ++ break; ++ case E_FMAN_PORT_TYPE_OP: ++ case E_FMAN_PORT_TYPE_HC: ++ get_oh_stats_reg(port, counter, &stats_reg); ++ break; ++ default: ++ stats_reg = NULL; ++ } ++ ++ if (stats_reg == NULL) ++ return; ++ ++ iowrite32be(value, stats_reg); ++} ++ ++uint32_t fman_port_get_perf_counter(struct fman_port *port, ++ enum fman_port_perf_counters counter) ++{ ++ uint32_t *perf_reg, ret_val; ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ get_rx_perf_reg(port, counter, &perf_reg); ++ break; ++ case E_FMAN_PORT_TYPE_TX: ++ case E_FMAN_PORT_TYPE_TX_10G: ++ get_tx_perf_reg(port, counter, &perf_reg); ++ break; ++ case E_FMAN_PORT_TYPE_OP: ++ case E_FMAN_PORT_TYPE_HC: ++ get_oh_perf_reg(port, counter, &perf_reg); ++ break; ++ default: ++ perf_reg = NULL; ++ } ++ ++ if (perf_reg == NULL) ++ return 0; ++ ++ ret_val = ioread32be(perf_reg); ++ return ret_val; ++} ++ ++void fman_port_set_perf_counter(struct fman_port *port, ++ enum fman_port_perf_counters counter, ++ uint32_t value) ++{ ++ uint32_t *perf_reg; ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ get_rx_perf_reg(port, counter, &perf_reg); ++ break; ++ case E_FMAN_PORT_TYPE_TX: ++ case E_FMAN_PORT_TYPE_TX_10G: ++ get_tx_perf_reg(port, counter, &perf_reg); ++ break; ++ case E_FMAN_PORT_TYPE_OP: ++ case E_FMAN_PORT_TYPE_HC: ++ get_oh_perf_reg(port, counter, &perf_reg); ++ break; ++ default: ++ perf_reg = NULL; ++ } ++ ++ if (perf_reg == NULL) ++ return; ++ ++ iowrite32be(value, perf_reg); ++} ++ ++uint32_t fman_port_get_qmi_counter(struct fman_port *port, ++ enum fman_port_qmi_counters counter) ++{ ++ uint32_t *queue_reg, ret_val; ++ ++ get_qmi_counter_reg(port, counter, &queue_reg); ++ ++ if (queue_reg == NULL) ++ return 0; ++ ++ ret_val = ioread32be(queue_reg); ++ return ret_val; ++} ++ ++void fman_port_set_qmi_counter(struct fman_port *port, ++ enum fman_port_qmi_counters counter, ++ uint32_t value) ++{ ++ uint32_t *queue_reg; ++ ++ get_qmi_counter_reg(port, counter, &queue_reg); ++ ++ if (queue_reg == NULL) ++ return; ++ ++ iowrite32be(value, queue_reg); ++} ++ ++uint32_t fman_port_get_bpool_counter(struct fman_port *port, uint8_t bpid) ++{ ++ uint8_t index; ++ uint32_t ret_val; ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ break; ++ default: ++ return 0; ++ } ++ ++ /* Find the pool */ ++ index = fman_port_find_bpool(port, bpid); ++ if (index == port->ext_pools_num || index == FMAN_PORT_MAX_EXT_POOLS_NUM) ++ /* Not found */ ++ return 0; ++ ++ ret_val = ioread32be(&port->bmi_regs->rx.fmbm_acnt[index]); ++ return ret_val; ++} ++ ++void fman_port_set_bpool_counter(struct fman_port *port, ++ uint8_t bpid, ++ uint32_t value) ++{ ++ uint8_t index; ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ break; ++ default: ++ return; ++ } ++ ++ /* Find the pool */ ++ index = fman_port_find_bpool(port, bpid); ++ if (index == port->ext_pools_num || index == FMAN_PORT_MAX_EXT_POOLS_NUM) ++ /* Not found */ ++ return; ++ ++ iowrite32be(value, &port->bmi_regs->rx.fmbm_acnt[index]); ++} ++ ++int fman_port_add_congestion_grps(struct fman_port *port, ++ uint32_t grps_map[FMAN_PORT_CG_MAP_NUM]) ++{ ++ int i; ++ uint32_t tmp, *grp_map_reg; ++ uint8_t max_grp_map_num; ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ if (port->fm_rev_maj == 4) ++ max_grp_map_num = 1; ++ else ++ max_grp_map_num = FMAN_PORT_CG_MAP_NUM; ++ grp_map_reg = port->bmi_regs->rx.fmbm_rcgm; ++ break; ++ case E_FMAN_PORT_TYPE_OP: ++ max_grp_map_num = 1; ++ if (port->fm_rev_maj != 4) ++ return -EINVAL; ++ grp_map_reg = port->bmi_regs->oh.fmbm_ocgm; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ for (i = (max_grp_map_num - 1); i >= 0; i--) { ++ if (grps_map[i] == 0) ++ continue; ++ tmp = ioread32be(&grp_map_reg[i]); ++ tmp |= grps_map[i]; ++ iowrite32be(tmp, &grp_map_reg[i]); ++ } ++ ++ return 0; ++} ++ ++int fman_port_remove_congestion_grps(struct fman_port *port, ++ uint32_t grps_map[FMAN_PORT_CG_MAP_NUM]) ++{ ++ int i; ++ uint32_t tmp, *grp_map_reg; ++ uint8_t max_grp_map_num; ++ ++ switch (port->type) { ++ case E_FMAN_PORT_TYPE_RX: ++ case E_FMAN_PORT_TYPE_RX_10G: ++ if (port->fm_rev_maj == 4) ++ max_grp_map_num = 1; ++ else ++ max_grp_map_num = FMAN_PORT_CG_MAP_NUM; ++ grp_map_reg = port->bmi_regs->rx.fmbm_rcgm; ++ break; ++ case E_FMAN_PORT_TYPE_OP: ++ max_grp_map_num = 1; ++ if (port->fm_rev_maj != 4) ++ return -EINVAL; ++ grp_map_reg = port->bmi_regs->oh.fmbm_ocgm; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ for (i = (max_grp_map_num - 1); i >= 0; i--) { ++ if (grps_map[i] == 0) ++ continue; ++ tmp = ioread32be(&grp_map_reg[i]); ++ tmp &= ~grps_map[i]; ++ iowrite32be(tmp, &grp_map_reg[i]); ++ } ++ return 0; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/Makefile +new file mode 100644 +index 00000000..d2c21d34 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/Makefile +@@ -0,0 +1,15 @@ ++# ++# Makefile for the Freescale Ethernet controllers ++# ++ccflags-y += -DVERSION=\"\" ++# ++#Include netcomm SW specific definitions ++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk ++ ++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc ++ ++ccflags-y += -I$(NCSW_FM_INC) ++ ++obj-y += fsl-ncsw-RTC.o ++ ++fsl-ncsw-RTC-objs := fm_rtc.o fman_rtc.o +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.c +new file mode 100644 +index 00000000..99de427b +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.c +@@ -0,0 +1,692 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_rtc.c ++ ++ @Description FM RTC driver implementation. ++ ++ @Cautions None ++*//***************************************************************************/ ++#include ++#include "error_ext.h" ++#include "debug_ext.h" ++#include "string_ext.h" ++#include "part_ext.h" ++#include "xx_ext.h" ++#include "ncsw_ext.h" ++ ++#include "fm_rtc.h" ++#include "fm_common.h" ++ ++ ++ ++/*****************************************************************************/ ++static t_Error CheckInitParameters(t_FmRtc *p_Rtc) ++{ ++ struct rtc_cfg *p_RtcDriverParam = p_Rtc->p_RtcDriverParam; ++ int i; ++ ++ if ((p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_EXTERNAL) && ++ (p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_SYSTEM) && ++ (p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_OSCILATOR)) ++ RETURN_ERROR(MAJOR, E_INVALID_CLOCK, ("Source clock undefined")); ++ ++ if (p_Rtc->outputClockDivisor == 0) ++ { ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("Divisor for output clock (should be positive)")); ++ } ++ ++ for (i=0; i < FM_RTC_NUM_OF_ALARMS; i++) ++ { ++ if ((p_RtcDriverParam->alarm_polarity[i] != E_FMAN_RTC_ALARM_POLARITY_ACTIVE_LOW) && ++ (p_RtcDriverParam->alarm_polarity[i] != E_FMAN_RTC_ALARM_POLARITY_ACTIVE_HIGH)) ++ { ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm %d signal polarity", i)); ++ } ++ } ++ for (i=0; i < FM_RTC_NUM_OF_EXT_TRIGGERS; i++) ++ { ++ if ((p_RtcDriverParam->trigger_polarity[i] != E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE) && ++ (p_RtcDriverParam->trigger_polarity[i] != E_FMAN_RTC_TRIGGER_ON_RISING_EDGE)) ++ { ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Trigger %d signal polarity", i)); ++ } ++ } ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++static void RtcExceptions(t_Handle h_FmRtc) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ struct rtc_regs *p_MemMap; ++ register uint32_t events; ++ ++ ASSERT_COND(p_Rtc); ++ p_MemMap = p_Rtc->p_MemMap; ++ ++ events = fman_rtc_check_and_clear_event(p_MemMap); ++ if (events & FMAN_RTC_TMR_TEVENT_ALM1) ++ { ++ if (p_Rtc->alarmParams[0].clearOnExpiration) ++ { ++ fman_rtc_set_timer_alarm_l(p_MemMap, 0, 0); ++ fman_rtc_disable_interupt(p_MemMap, FMAN_RTC_TMR_TEVENT_ALM1); ++ } ++ ASSERT_COND(p_Rtc->alarmParams[0].f_AlarmCallback); ++ p_Rtc->alarmParams[0].f_AlarmCallback(p_Rtc->h_App, 0); ++ } ++ if (events & FMAN_RTC_TMR_TEVENT_ALM2) ++ { ++ if (p_Rtc->alarmParams[1].clearOnExpiration) ++ { ++ fman_rtc_set_timer_alarm_l(p_MemMap, 1, 0); ++ fman_rtc_disable_interupt(p_MemMap, FMAN_RTC_TMR_TEVENT_ALM2); ++ } ++ ASSERT_COND(p_Rtc->alarmParams[1].f_AlarmCallback); ++ p_Rtc->alarmParams[1].f_AlarmCallback(p_Rtc->h_App, 1); ++ } ++ if (events & FMAN_RTC_TMR_TEVENT_PP1) ++ { ++ ASSERT_COND(p_Rtc->periodicPulseParams[0].f_PeriodicPulseCallback); ++ p_Rtc->periodicPulseParams[0].f_PeriodicPulseCallback(p_Rtc->h_App, 0); ++ } ++ if (events & FMAN_RTC_TMR_TEVENT_PP2) ++ { ++ ASSERT_COND(p_Rtc->periodicPulseParams[1].f_PeriodicPulseCallback); ++ p_Rtc->periodicPulseParams[1].f_PeriodicPulseCallback(p_Rtc->h_App, 1); ++ } ++ if (events & FMAN_RTC_TMR_TEVENT_ETS1) ++ { ++ ASSERT_COND(p_Rtc->externalTriggerParams[0].f_ExternalTriggerCallback); ++ p_Rtc->externalTriggerParams[0].f_ExternalTriggerCallback(p_Rtc->h_App, 0); ++ } ++ if (events & FMAN_RTC_TMR_TEVENT_ETS2) ++ { ++ ASSERT_COND(p_Rtc->externalTriggerParams[1].f_ExternalTriggerCallback); ++ p_Rtc->externalTriggerParams[1].f_ExternalTriggerCallback(p_Rtc->h_App, 1); ++ } ++} ++ ++ ++/*****************************************************************************/ ++t_Handle FM_RTC_Config(t_FmRtcParams *p_FmRtcParam) ++{ ++ t_FmRtc *p_Rtc; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmRtcParam, E_NULL_POINTER, NULL); ++ ++ /* Allocate memory for the FM RTC driver parameters */ ++ p_Rtc = (t_FmRtc *)XX_Malloc(sizeof(t_FmRtc)); ++ if (!p_Rtc) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM RTC driver structure")); ++ return NULL; ++ } ++ ++ memset(p_Rtc, 0, sizeof(t_FmRtc)); ++ ++ /* Allocate memory for the FM RTC driver parameters */ ++ p_Rtc->p_RtcDriverParam = (struct rtc_cfg *)XX_Malloc(sizeof(struct rtc_cfg)); ++ if (!p_Rtc->p_RtcDriverParam) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM RTC driver parameters")); ++ XX_Free(p_Rtc); ++ return NULL; ++ } ++ ++ memset(p_Rtc->p_RtcDriverParam, 0, sizeof(struct rtc_cfg)); ++ ++ /* Store RTC configuration parameters */ ++ p_Rtc->h_Fm = p_FmRtcParam->h_Fm; ++ ++ /* Set default RTC configuration parameters */ ++ fman_rtc_defconfig(p_Rtc->p_RtcDriverParam); ++ ++ p_Rtc->outputClockDivisor = DEFAULT_OUTPUT_CLOCK_DIVISOR; ++ p_Rtc->p_RtcDriverParam->bypass = DEFAULT_BYPASS; ++ p_Rtc->clockPeriodNanoSec = DEFAULT_CLOCK_PERIOD; /* 1 usec */ ++ ++ ++ /* Store RTC parameters in the RTC control structure */ ++ p_Rtc->p_MemMap = (struct rtc_regs *)UINT_TO_PTR(p_FmRtcParam->baseAddress); ++ p_Rtc->h_App = p_FmRtcParam->h_App; ++ ++ return p_Rtc; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_Init(t_Handle h_FmRtc) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ struct rtc_cfg *p_RtcDriverParam; ++ struct rtc_regs *p_MemMap; ++ uint32_t freqCompensation = 0; ++ uint64_t tmpDouble; ++ bool init_freq_comp = FALSE; ++ ++ p_RtcDriverParam = p_Rtc->p_RtcDriverParam; ++ p_MemMap = p_Rtc->p_MemMap; ++ ++ if (CheckInitParameters(p_Rtc)!=E_OK) ++ RETURN_ERROR(MAJOR, E_CONFLICT, ++ ("Init Parameters are not Valid")); ++ ++ /* TODO check that no timestamping MACs are working in this stage. */ ++ ++ /* find source clock frequency in Mhz */ ++ if (p_Rtc->p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_SYSTEM) ++ p_Rtc->srcClkFreqMhz = p_Rtc->p_RtcDriverParam->ext_src_clk_freq; ++ else ++ p_Rtc->srcClkFreqMhz = (uint32_t)(FmGetMacClockFreq(p_Rtc->h_Fm)); ++ ++ /* if timer in Master mode Initialize TMR_CTRL */ ++ /* We want the counter (TMR_CNT) to count in nano-seconds */ ++ if (!p_RtcDriverParam->timer_slave_mode && p_Rtc->p_RtcDriverParam->bypass) ++ p_Rtc->clockPeriodNanoSec = (1000 / p_Rtc->srcClkFreqMhz); ++ else ++ { ++ /* Initialize TMR_ADD with the initial frequency compensation value: ++ freqCompensation = (2^32 / frequency ratio) */ ++ /* frequency ratio = sorce clock/rtc clock = ++ * (p_Rtc->srcClkFreqMhz*1000000))/ 1/(p_Rtc->clockPeriodNanoSec * 1000000000) */ ++ init_freq_comp = TRUE; ++ freqCompensation = (uint32_t)DIV_CEIL(ACCUMULATOR_OVERFLOW * 1000, ++ p_Rtc->clockPeriodNanoSec * p_Rtc->srcClkFreqMhz); ++ } ++ ++ /* check the legality of the relation between source and destination clocks */ ++ /* should be larger than 1.0001 */ ++ tmpDouble = 10000 * (uint64_t)p_Rtc->clockPeriodNanoSec * (uint64_t)p_Rtc->srcClkFreqMhz; ++ if ((tmpDouble) <= 10001) ++ RETURN_ERROR(MAJOR, E_CONFLICT, ++ ("Invalid relation between source and destination clocks. Should be larger than 1.0001")); ++ ++ fman_rtc_init(p_RtcDriverParam, ++ p_MemMap, ++ FM_RTC_NUM_OF_ALARMS, ++ FM_RTC_NUM_OF_PERIODIC_PULSES, ++ FM_RTC_NUM_OF_EXT_TRIGGERS, ++ init_freq_comp, ++ freqCompensation, ++ p_Rtc->outputClockDivisor); ++ ++ /* Register the FM RTC interrupt */ ++ FmRegisterIntr(p_Rtc->h_Fm, e_FM_MOD_TMR, 0, e_FM_INTR_TYPE_NORMAL, RtcExceptions , p_Rtc); ++ ++ /* Free parameters structures */ ++ XX_Free(p_Rtc->p_RtcDriverParam); ++ p_Rtc->p_RtcDriverParam = NULL; ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_Free(t_Handle h_FmRtc) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ ++ if (p_Rtc->p_RtcDriverParam) ++ { ++ XX_Free(p_Rtc->p_RtcDriverParam); ++ } ++ else ++ { ++ FM_RTC_Disable(h_FmRtc); ++ } ++ ++ /* Unregister FM RTC interrupt */ ++ FmUnregisterIntr(p_Rtc->h_Fm, e_FM_MOD_TMR, 0, e_FM_INTR_TYPE_NORMAL); ++ XX_Free(p_Rtc); ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_ConfigSourceClock(t_Handle h_FmRtc, ++ e_FmSrcClk srcClk, ++ uint32_t freqInMhz) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ p_Rtc->p_RtcDriverParam->src_clk = (enum fman_src_clock)srcClk; ++ if (srcClk != e_FM_RTC_SOURCE_CLOCK_SYSTEM) ++ p_Rtc->p_RtcDriverParam->ext_src_clk_freq = freqInMhz; ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_ConfigPeriod(t_Handle h_FmRtc, uint32_t period) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ p_Rtc->clockPeriodNanoSec = period; ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_ConfigFrequencyBypass(t_Handle h_FmRtc, bool enabled) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ p_Rtc->p_RtcDriverParam->bypass = enabled; ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_ConfigInvertedInputClockPhase(t_Handle h_FmRtc, bool inverted) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ p_Rtc->p_RtcDriverParam->invert_input_clk_phase = inverted; ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_ConfigInvertedOutputClockPhase(t_Handle h_FmRtc, bool inverted) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ p_Rtc->p_RtcDriverParam->invert_output_clk_phase = inverted; ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_ConfigOutputClockDivisor(t_Handle h_FmRtc, uint16_t divisor) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ p_Rtc->outputClockDivisor = divisor; ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_ConfigPulseRealignment(t_Handle h_FmRtc, bool enable) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ p_Rtc->p_RtcDriverParam->pulse_realign = enable; ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_ConfigAlarmPolarity(t_Handle h_FmRtc, ++ uint8_t alarmId, ++ e_FmRtcAlarmPolarity alarmPolarity) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ if (alarmId >= FM_RTC_NUM_OF_ALARMS) ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm ID")); ++ ++ p_Rtc->p_RtcDriverParam->alarm_polarity[alarmId] = ++ (enum fman_rtc_alarm_polarity)alarmPolarity; ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_ConfigExternalTriggerPolarity(t_Handle h_FmRtc, ++ uint8_t triggerId, ++ e_FmRtcTriggerPolarity triggerPolarity) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ if (triggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS) ++ { ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External trigger ID")); ++ } ++ ++ p_Rtc->p_RtcDriverParam->trigger_polarity[triggerId] = ++ (enum fman_rtc_trigger_polarity)triggerPolarity; ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_Enable(t_Handle h_FmRtc, bool resetClock) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ fman_rtc_enable(p_Rtc->p_MemMap, resetClock); ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_Disable(t_Handle h_FmRtc) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ /* TODO A check must be added here, that no timestamping MAC's ++ * are working in this stage. */ ++ fman_rtc_disable(p_Rtc->p_MemMap); ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_SetClockOffset(t_Handle h_FmRtc, int64_t offset) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ fman_rtc_set_timer_offset(p_Rtc->p_MemMap, offset); ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_SetAlarm(t_Handle h_FmRtc, t_FmRtcAlarmParams *p_FmRtcAlarmParams) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ uint64_t tmpAlarm; ++ bool enable = FALSE; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ if (p_FmRtcAlarmParams->alarmId >= FM_RTC_NUM_OF_ALARMS) ++ { ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm ID")); ++ } ++ ++ if (p_FmRtcAlarmParams->alarmTime < p_Rtc->clockPeriodNanoSec) ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ++ ("Alarm time must be equal or larger than RTC period - %d nanoseconds", ++ p_Rtc->clockPeriodNanoSec)); ++ tmpAlarm = p_FmRtcAlarmParams->alarmTime; ++ if (do_div(tmpAlarm, p_Rtc->clockPeriodNanoSec)) ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ++ ("Alarm time must be a multiple of RTC period - %d nanoseconds", ++ p_Rtc->clockPeriodNanoSec)); ++ ++ if (p_FmRtcAlarmParams->f_AlarmCallback) ++ { ++ p_Rtc->alarmParams[p_FmRtcAlarmParams->alarmId].f_AlarmCallback = p_FmRtcAlarmParams->f_AlarmCallback; ++ p_Rtc->alarmParams[p_FmRtcAlarmParams->alarmId].clearOnExpiration = p_FmRtcAlarmParams->clearOnExpiration; ++ enable = TRUE; ++ } ++ ++ fman_rtc_set_alarm(p_Rtc->p_MemMap, p_FmRtcAlarmParams->alarmId, (unsigned long)tmpAlarm, enable); ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_SetPeriodicPulse(t_Handle h_FmRtc, t_FmRtcPeriodicPulseParams *p_FmRtcPeriodicPulseParams) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ bool enable = FALSE; ++ uint64_t tmpFiper; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ if (p_FmRtcPeriodicPulseParams->periodicPulseId >= FM_RTC_NUM_OF_PERIODIC_PULSES) ++ { ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse ID")); ++ } ++ if (fman_rtc_is_enabled(p_Rtc->p_MemMap)) ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Can't set Periodic pulse when RTC is enabled.")); ++ if (p_FmRtcPeriodicPulseParams->periodicPulsePeriod < p_Rtc->clockPeriodNanoSec) ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ++ ("Periodic pulse must be equal or larger than RTC period - %d nanoseconds", ++ p_Rtc->clockPeriodNanoSec)); ++ tmpFiper = p_FmRtcPeriodicPulseParams->periodicPulsePeriod; ++ if (do_div(tmpFiper, p_Rtc->clockPeriodNanoSec)) ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ++ ("Periodic pulse must be a multiple of RTC period - %d nanoseconds", ++ p_Rtc->clockPeriodNanoSec)); ++ if (tmpFiper & 0xffffffff00000000LL) ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ++ ("Periodic pulse/RTC Period must be smaller than 4294967296", ++ p_Rtc->clockPeriodNanoSec)); ++ ++ if (p_FmRtcPeriodicPulseParams->f_PeriodicPulseCallback) ++ { ++ p_Rtc->periodicPulseParams[p_FmRtcPeriodicPulseParams->periodicPulseId].f_PeriodicPulseCallback = ++ p_FmRtcPeriodicPulseParams->f_PeriodicPulseCallback; ++ enable = TRUE; ++ } ++ fman_rtc_set_periodic_pulse(p_Rtc->p_MemMap, p_FmRtcPeriodicPulseParams->periodicPulseId, (uint32_t)tmpFiper, enable); ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_ClearPeriodicPulse(t_Handle h_FmRtc, uint8_t periodicPulseId) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ if (periodicPulseId >= FM_RTC_NUM_OF_PERIODIC_PULSES) ++ { ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse ID")); ++ } ++ ++ p_Rtc->periodicPulseParams[periodicPulseId].f_PeriodicPulseCallback = NULL; ++ fman_rtc_clear_periodic_pulse(p_Rtc->p_MemMap, periodicPulseId); ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_SetExternalTrigger(t_Handle h_FmRtc, t_FmRtcExternalTriggerParams *p_FmRtcExternalTriggerParams) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ bool enable = FALSE; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ if (p_FmRtcExternalTriggerParams->externalTriggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS) ++ { ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External Trigger ID")); ++ } ++ ++ if (p_FmRtcExternalTriggerParams->f_ExternalTriggerCallback) ++ { ++ p_Rtc->externalTriggerParams[p_FmRtcExternalTriggerParams->externalTriggerId].f_ExternalTriggerCallback = p_FmRtcExternalTriggerParams->f_ExternalTriggerCallback; ++ enable = TRUE; ++ } ++ ++ fman_rtc_set_ext_trigger(p_Rtc->p_MemMap, p_FmRtcExternalTriggerParams->externalTriggerId, enable, p_FmRtcExternalTriggerParams->usePulseAsInput); ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_ClearExternalTrigger(t_Handle h_FmRtc, uint8_t externalTriggerId) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ if (externalTriggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS) ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External Trigger ID")); ++ ++ p_Rtc->externalTriggerParams[externalTriggerId].f_ExternalTriggerCallback = NULL; ++ ++ fman_rtc_clear_external_trigger(p_Rtc->p_MemMap, externalTriggerId); ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_GetExternalTriggerTimeStamp(t_Handle h_FmRtc, ++ uint8_t triggerId, ++ uint64_t *p_TimeStamp) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ if (triggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS) ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External trigger ID")); ++ ++ *p_TimeStamp = fman_rtc_get_trigger_stamp(p_Rtc->p_MemMap, triggerId)*p_Rtc->clockPeriodNanoSec; ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_GetCurrentTime(t_Handle h_FmRtc, uint64_t *p_Ts) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ *p_Ts = fman_rtc_get_timer(p_Rtc->p_MemMap)*p_Rtc->clockPeriodNanoSec; ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_SetCurrentTime(t_Handle h_FmRtc, uint64_t ts) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ do_div(ts, p_Rtc->clockPeriodNanoSec); ++ fman_rtc_set_timer(p_Rtc->p_MemMap, (int64_t)ts); ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_GetFreqCompensation(t_Handle h_FmRtc, uint32_t *p_Compensation) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ *p_Compensation = fman_rtc_get_frequency_compensation(p_Rtc->p_MemMap); ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_SetFreqCompensation(t_Handle h_FmRtc, uint32_t freqCompensation) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ /* set the new freqCompensation */ ++ fman_rtc_set_frequency_compensation(p_Rtc->p_MemMap, freqCompensation); ++ ++ return E_OK; ++} ++ ++#ifdef CONFIG_PTP_1588_CLOCK_DPAA ++/*****************************************************************************/ ++t_Error FM_RTC_EnableInterrupt(t_Handle h_FmRtc, uint32_t events) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ /* enable interrupt */ ++ fman_rtc_enable_interupt(p_Rtc->p_MemMap, events); ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++t_Error FM_RTC_DisableInterrupt(t_Handle h_FmRtc, uint32_t events) ++{ ++ t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); ++ ++ /* disable interrupt */ ++ fman_rtc_disable_interupt(p_Rtc->p_MemMap, events); ++ ++ return E_OK; ++} ++#endif +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.h +new file mode 100644 +index 00000000..843ca008 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.h +@@ -0,0 +1,96 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_rtc.h ++ ++ @Description Memory map and internal definitions for FM RTC IEEE1588 Timer driver. ++ ++ @Cautions None ++*//***************************************************************************/ ++ ++#ifndef __FM_RTC_H__ ++#define __FM_RTC_H__ ++ ++#include "std_ext.h" ++#include "fm_rtc_ext.h" ++ ++ ++#define __ERR_MODULE__ MODULE_FM_RTC ++ ++/* General definitions */ ++ ++#define ACCUMULATOR_OVERFLOW ((uint64_t)(1LL << 32)) ++#define DEFAULT_OUTPUT_CLOCK_DIVISOR 0x00000002 ++#define DEFAULT_BYPASS FALSE ++#define DEFAULT_CLOCK_PERIOD 1000 ++ ++ ++ ++typedef struct t_FmRtcAlarm ++{ ++ t_FmRtcExceptionsCallback *f_AlarmCallback; ++ bool clearOnExpiration; ++} t_FmRtcAlarm; ++ ++typedef struct t_FmRtcPeriodicPulse ++{ ++ t_FmRtcExceptionsCallback *f_PeriodicPulseCallback; ++} t_FmRtcPeriodicPulse; ++ ++typedef struct t_FmRtcExternalTrigger ++{ ++ t_FmRtcExceptionsCallback *f_ExternalTriggerCallback; ++} t_FmRtcExternalTrigger; ++ ++ ++/**************************************************************************//** ++ @Description RTC FM driver control structure. ++*//***************************************************************************/ ++typedef struct t_FmRtc ++{ ++ t_Part *p_Part; /**< Pointer to the integration device */ ++ t_Handle h_Fm; ++ t_Handle h_App; /**< Application handle */ ++ struct rtc_regs *p_MemMap; ++ uint32_t clockPeriodNanoSec; /**< RTC clock period in nano-seconds (for FS mode) */ ++ uint32_t srcClkFreqMhz; ++ uint16_t outputClockDivisor; /**< Output clock divisor (for FS mode) */ ++ t_FmRtcAlarm alarmParams[FM_RTC_NUM_OF_ALARMS]; ++ t_FmRtcPeriodicPulse periodicPulseParams[FM_RTC_NUM_OF_PERIODIC_PULSES]; ++ t_FmRtcExternalTrigger externalTriggerParams[FM_RTC_NUM_OF_EXT_TRIGGERS]; ++ struct rtc_cfg *p_RtcDriverParam; /**< RTC Driver parameters (for Init phase) */ ++} t_FmRtc; ++ ++ ++#endif /* __FM_RTC_H__ */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fman_rtc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fman_rtc.c +new file mode 100755 +index 00000000..acdf507e +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fman_rtc.c +@@ -0,0 +1,334 @@ ++/* ++ * Copyright 2008-2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "fsl_fman_rtc.h" ++ ++void fman_rtc_defconfig(struct rtc_cfg *cfg) ++{ ++ int i; ++ cfg->src_clk = DEFAULT_SRC_CLOCK; ++ cfg->invert_input_clk_phase = DEFAULT_INVERT_INPUT_CLK_PHASE; ++ cfg->invert_output_clk_phase = DEFAULT_INVERT_OUTPUT_CLK_PHASE; ++ cfg->pulse_realign = DEFAULT_PULSE_REALIGN; ++ for (i = 0; i < FMAN_RTC_MAX_NUM_OF_ALARMS; i++) ++ cfg->alarm_polarity[i] = DEFAULT_ALARM_POLARITY; ++ for (i = 0; i < FMAN_RTC_MAX_NUM_OF_EXT_TRIGGERS; i++) ++ cfg->trigger_polarity[i] = DEFAULT_TRIGGER_POLARITY; ++} ++ ++uint32_t fman_rtc_get_events(struct rtc_regs *regs) ++{ ++ return ioread32be(®s->tmr_tevent); ++} ++ ++uint32_t fman_rtc_get_event(struct rtc_regs *regs, uint32_t ev_mask) ++{ ++ return ioread32be(®s->tmr_tevent) & ev_mask; ++} ++ ++uint32_t fman_rtc_get_interrupt_mask(struct rtc_regs *regs) ++{ ++ return ioread32be(®s->tmr_temask); ++} ++ ++void fman_rtc_set_interrupt_mask(struct rtc_regs *regs, uint32_t mask) ++{ ++ iowrite32be(mask, ®s->tmr_temask); ++} ++ ++void fman_rtc_ack_event(struct rtc_regs *regs, uint32_t events) ++{ ++ iowrite32be(events, ®s->tmr_tevent); ++} ++ ++uint32_t fman_rtc_check_and_clear_event(struct rtc_regs *regs) ++{ ++ uint32_t event; ++ ++ event = ioread32be(®s->tmr_tevent); ++ event &= ioread32be(®s->tmr_temask); ++ ++ if (event) ++ iowrite32be(event, ®s->tmr_tevent); ++ return event; ++} ++ ++uint32_t fman_rtc_get_frequency_compensation(struct rtc_regs *regs) ++{ ++ return ioread32be(®s->tmr_add); ++} ++ ++void fman_rtc_set_frequency_compensation(struct rtc_regs *regs, uint32_t val) ++{ ++ iowrite32be(val, ®s->tmr_add); ++} ++ ++void fman_rtc_enable_interupt(struct rtc_regs *regs, uint32_t events) ++{ ++ fman_rtc_set_interrupt_mask(regs, fman_rtc_get_interrupt_mask(regs) | events); ++} ++ ++void fman_rtc_disable_interupt(struct rtc_regs *regs, uint32_t events) ++{ ++ fman_rtc_set_interrupt_mask(regs, fman_rtc_get_interrupt_mask(regs) & ~events); ++} ++ ++void fman_rtc_set_timer_alarm_l(struct rtc_regs *regs, int index, uint32_t val) ++{ ++ iowrite32be(val, ®s->tmr_alarm[index].tmr_alarm_l); ++} ++ ++void fman_rtc_set_timer_fiper(struct rtc_regs *regs, int index, uint32_t val) ++{ ++ iowrite32be(val, ®s->tmr_fiper[index]); ++} ++ ++void fman_rtc_set_timer_alarm(struct rtc_regs *regs, int index, int64_t val) ++{ ++ iowrite32be((uint32_t)val, ®s->tmr_alarm[index].tmr_alarm_l); ++ iowrite32be((uint32_t)(val >> 32), ®s->tmr_alarm[index].tmr_alarm_h); ++} ++ ++void fman_rtc_set_timer_offset(struct rtc_regs *regs, int64_t val) ++{ ++ iowrite32be((uint32_t)val, ®s->tmr_off_l); ++ iowrite32be((uint32_t)(val >> 32), ®s->tmr_off_h); ++} ++ ++uint64_t fman_rtc_get_trigger_stamp(struct rtc_regs *regs, int id) ++{ ++ uint64_t time; ++ /* TMR_CNT_L must be read first to get an accurate value */ ++ time = (uint64_t)ioread32be(®s->tmr_etts[id].tmr_etts_l); ++ time |= ((uint64_t)ioread32be(®s->tmr_etts[id].tmr_etts_h) ++ << 32); ++ ++ return time; ++} ++ ++uint32_t fman_rtc_get_timer_ctrl(struct rtc_regs *regs) ++{ ++ return ioread32be(®s->tmr_ctrl); ++} ++ ++void fman_rtc_set_timer_ctrl(struct rtc_regs *regs, uint32_t val) ++{ ++ iowrite32be(val, ®s->tmr_ctrl); ++} ++ ++void fman_rtc_timers_soft_reset(struct rtc_regs *regs) ++{ ++ fman_rtc_set_timer_ctrl(regs, FMAN_RTC_TMR_CTRL_TMSR); ++ udelay(10); ++ fman_rtc_set_timer_ctrl(regs, 0); ++} ++ ++void fman_rtc_init(struct rtc_cfg *cfg, struct rtc_regs *regs, int num_alarms, ++ int num_fipers, int num_ext_triggers, bool init_freq_comp, ++ uint32_t freq_compensation, uint32_t output_clock_divisor) ++{ ++ uint32_t tmr_ctrl; ++ int i; ++ ++ fman_rtc_timers_soft_reset(regs); ++ ++ /* Set the source clock */ ++ switch (cfg->src_clk) { ++ case E_FMAN_RTC_SOURCE_CLOCK_SYSTEM: ++ tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_MAC_CLK; ++ break; ++ case E_FMAN_RTC_SOURCE_CLOCK_OSCILATOR: ++ tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_OSC_CLK; ++ break; ++ default: ++ /* Use a clock from the External TMR reference clock.*/ ++ tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_EXT_CLK; ++ break; ++ } ++ ++ /* whatever period the user picked, the timestamp will advance in '1' ++ * every time the period passed. */ ++ tmr_ctrl |= ((1 << FMAN_RTC_TMR_CTRL_TCLK_PERIOD_SHIFT) & ++ FMAN_RTC_TMR_CTRL_TCLK_PERIOD_MASK); ++ ++ if (cfg->invert_input_clk_phase) ++ tmr_ctrl |= FMAN_RTC_TMR_CTRL_CIPH; ++ if (cfg->invert_output_clk_phase) ++ tmr_ctrl |= FMAN_RTC_TMR_CTRL_COPH; ++ ++ for (i = 0; i < num_alarms; i++) { ++ if (cfg->alarm_polarity[i] == ++ E_FMAN_RTC_ALARM_POLARITY_ACTIVE_LOW) ++ tmr_ctrl |= (FMAN_RTC_TMR_CTRL_ALMP1 >> i); ++ } ++ ++ for (i = 0; i < num_ext_triggers; i++) ++ if (cfg->trigger_polarity[i] == ++ E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE) ++ tmr_ctrl |= (FMAN_RTC_TMR_CTRL_ETEP1 << i); ++ ++ if (!cfg->timer_slave_mode && cfg->bypass) ++ tmr_ctrl |= FMAN_RTC_TMR_CTRL_BYP; ++ ++ fman_rtc_set_timer_ctrl(regs, tmr_ctrl); ++ if (init_freq_comp) ++ fman_rtc_set_frequency_compensation(regs, freq_compensation); ++ ++ /* Clear TMR_ALARM registers */ ++ for (i = 0; i < num_alarms; i++) ++ fman_rtc_set_timer_alarm(regs, i, 0xFFFFFFFFFFFFFFFFLL); ++ ++ /* Clear TMR_TEVENT */ ++ fman_rtc_ack_event(regs, FMAN_RTC_TMR_TEVENT_ALL); ++ ++ /* Initialize TMR_TEMASK */ ++ fman_rtc_set_interrupt_mask(regs, 0); ++ ++ /* Clear TMR_FIPER registers */ ++ for (i = 0; i < num_fipers; i++) ++ fman_rtc_set_timer_fiper(regs, i, 0xFFFFFFFF); ++ ++ /* Initialize TMR_PRSC */ ++ iowrite32be(output_clock_divisor, ®s->tmr_prsc); ++ ++ /* Clear TMR_OFF */ ++ fman_rtc_set_timer_offset(regs, 0); ++} ++ ++bool fman_rtc_is_enabled(struct rtc_regs *regs) ++{ ++ return (bool)(fman_rtc_get_timer_ctrl(regs) & FMAN_RTC_TMR_CTRL_TE); ++} ++ ++void fman_rtc_enable(struct rtc_regs *regs, bool reset_clock) ++{ ++ uint32_t tmr_ctrl = fman_rtc_get_timer_ctrl(regs); ++ ++ /* TODO check that no timestamping MACs are working in this stage. */ ++ if (reset_clock) { ++ fman_rtc_set_timer_ctrl(regs, (tmr_ctrl | FMAN_RTC_TMR_CTRL_TMSR)); ++ ++ udelay(10); ++ /* Clear TMR_OFF */ ++ fman_rtc_set_timer_offset(regs, 0); ++ } ++ ++ fman_rtc_set_timer_ctrl(regs, (tmr_ctrl | FMAN_RTC_TMR_CTRL_TE)); ++} ++ ++void fman_rtc_disable(struct rtc_regs *regs) ++{ ++ fman_rtc_set_timer_ctrl(regs, (fman_rtc_get_timer_ctrl(regs) ++ & ~(FMAN_RTC_TMR_CTRL_TE))); ++} ++ ++void fman_rtc_clear_periodic_pulse(struct rtc_regs *regs, int id) ++{ ++ uint32_t tmp_reg; ++ if (id == 0) ++ tmp_reg = FMAN_RTC_TMR_TEVENT_PP1; ++ else ++ tmp_reg = FMAN_RTC_TMR_TEVENT_PP2; ++ fman_rtc_disable_interupt(regs, tmp_reg); ++ ++ tmp_reg = fman_rtc_get_timer_ctrl(regs); ++ if (tmp_reg & FMAN_RTC_TMR_CTRL_FS) ++ fman_rtc_set_timer_ctrl(regs, tmp_reg & ~FMAN_RTC_TMR_CTRL_FS); ++ ++ fman_rtc_set_timer_fiper(regs, id, 0xFFFFFFFF); ++} ++ ++void fman_rtc_clear_external_trigger(struct rtc_regs *regs, int id) ++{ ++ uint32_t tmpReg, tmp_ctrl; ++ ++ if (id == 0) ++ tmpReg = FMAN_RTC_TMR_TEVENT_ETS1; ++ else ++ tmpReg = FMAN_RTC_TMR_TEVENT_ETS2; ++ fman_rtc_disable_interupt(regs, tmpReg); ++ ++ if (id == 0) ++ tmpReg = FMAN_RTC_TMR_CTRL_PP1L; ++ else ++ tmpReg = FMAN_RTC_TMR_CTRL_PP2L; ++ tmp_ctrl = fman_rtc_get_timer_ctrl(regs); ++ if (tmp_ctrl & tmpReg) ++ fman_rtc_set_timer_ctrl(regs, tmp_ctrl & ~tmpReg); ++} ++ ++void fman_rtc_set_alarm(struct rtc_regs *regs, int id, uint32_t val, bool enable) ++{ ++ uint32_t tmpReg; ++ fman_rtc_set_timer_alarm(regs, id, val); ++ if (enable) { ++ if (id == 0) ++ tmpReg = FMAN_RTC_TMR_TEVENT_ALM1; ++ else ++ tmpReg = FMAN_RTC_TMR_TEVENT_ALM2; ++ fman_rtc_enable_interupt(regs, tmpReg); ++ } ++} ++ ++void fman_rtc_set_periodic_pulse(struct rtc_regs *regs, int id, uint32_t val, ++ bool enable) ++{ ++ uint32_t tmpReg; ++ fman_rtc_set_timer_fiper(regs, id, val); ++ if (enable) { ++ if (id == 0) ++ tmpReg = FMAN_RTC_TMR_TEVENT_PP1; ++ else ++ tmpReg = FMAN_RTC_TMR_TEVENT_PP2; ++ fman_rtc_enable_interupt(regs, tmpReg); ++ } ++} ++ ++void fman_rtc_set_ext_trigger(struct rtc_regs *regs, int id, bool enable, ++ bool use_pulse_as_input) ++{ ++ uint32_t tmpReg; ++ if (enable) { ++ if (id == 0) ++ tmpReg = FMAN_RTC_TMR_TEVENT_ETS1; ++ else ++ tmpReg = FMAN_RTC_TMR_TEVENT_ETS2; ++ fman_rtc_enable_interupt(regs, tmpReg); ++ } ++ if (use_pulse_as_input) { ++ if (id == 0) ++ tmpReg = FMAN_RTC_TMR_CTRL_PP1L; ++ else ++ tmpReg = FMAN_RTC_TMR_CTRL_PP2L; ++ fman_rtc_set_timer_ctrl(regs, fman_rtc_get_timer_ctrl(regs) | tmpReg); ++ } ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/Makefile +new file mode 100644 +index 00000000..fae50ce4 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/Makefile +@@ -0,0 +1,15 @@ ++# ++# Makefile for the Freescale Ethernet controllers ++# ++ccflags-y += -DVERSION=\"\" ++# ++#Include netcomm SW specific definitions ++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk ++ ++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc ++ ++ccflags-y += -I$(NCSW_FM_INC) ++ ++obj-y += fsl-ncsw-sp.o ++ ++fsl-ncsw-sp-objs := fm_sp.o fman_sp.o +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.c +new file mode 100644 +index 00000000..0994f34d +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.c +@@ -0,0 +1,757 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_sp.c ++ ++ @Description FM PCD Storage profile ... ++*//***************************************************************************/ ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "string_ext.h" ++#include "debug_ext.h" ++#include "net_ext.h" ++ ++#include "fm_vsp_ext.h" ++#include "fm_sp.h" ++#include "fm_common.h" ++#include "fsl_fman_sp.h" ++ ++ ++#if (DPAA_VERSION >= 11) ++static t_Error CheckParamsGeneratedInternally(t_FmVspEntry *p_FmVspEntry) ++{ ++ t_Error err = E_OK; ++ ++ if ((err = FmSpCheckIntContextParams(&p_FmVspEntry->intContext))!= E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ if ((err = FmSpCheckBufMargins(&p_FmVspEntry->bufMargins)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ return err; ++ ++} ++ ++static t_Error CheckParams(t_FmVspEntry *p_FmVspEntry) ++{ ++ t_Error err = E_OK; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->h_Fm, E_INVALID_HANDLE); ++ ++ if ((err = FmSpCheckBufPoolsParams(&p_FmVspEntry->p_FmVspEntryDriverParams->extBufPools, ++ p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools, ++ p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion)) != E_OK) ++ ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ if (p_FmVspEntry->p_FmVspEntryDriverParams->liodnOffset & ~FM_LIODN_OFFSET_MASK) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1)); ++ ++ err = FmVSPCheckRelativeProfile(p_FmVspEntry->h_Fm, ++ p_FmVspEntry->portType, ++ p_FmVspEntry->portId, ++ p_FmVspEntry->relativeProfileId); ++ ++ return err; ++} ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ ++/*****************************************************************************/ ++/* Inter-module API routines */ ++/*****************************************************************************/ ++void FmSpSetBufPoolsInAscOrderOfBufSizes(t_FmExtPools *p_FmExtPools, ++ uint8_t *orderedArray, ++ uint16_t *sizesArray) ++{ ++ uint16_t bufSize = 0; ++ int i=0, j=0, k=0; ++ ++ /* First we copy the external buffers pools information to an ordered local array */ ++ for (i=0;inumOfPoolsUsed;i++) ++ { ++ /* get pool size */ ++ bufSize = p_FmExtPools->extBufPool[i].size; ++ ++ /* keep sizes in an array according to poolId for direct access */ ++ sizesArray[p_FmExtPools->extBufPool[i].id] = bufSize; ++ ++ /* save poolId in an ordered array according to size */ ++ for (j=0;j<=i;j++) ++ { ++ /* this is the next free place in the array */ ++ if (j==i) ++ orderedArray[i] = p_FmExtPools->extBufPool[i].id; ++ else ++ { ++ /* find the right place for this poolId */ ++ if (bufSize < sizesArray[orderedArray[j]]) ++ { ++ /* move the poolIds one place ahead to make room for this poolId */ ++ for (k=i;k>j;k--) ++ orderedArray[k] = orderedArray[k-1]; ++ ++ /* now k==j, this is the place for the new size */ ++ orderedArray[k] = p_FmExtPools->extBufPool[i].id; ++ break; ++ } ++ } ++ } ++ } ++} ++ ++t_Error FmSpCheckBufPoolsParams(t_FmExtPools *p_FmExtPools, ++ t_FmBackupBmPools *p_FmBackupBmPools, ++ t_FmBufPoolDepletion *p_FmBufPoolDepletion) ++{ ++ ++ int i = 0, j = 0; ++ bool found; ++ uint8_t count = 0; ++ ++ if (p_FmExtPools) ++ { ++ if (p_FmExtPools->numOfPoolsUsed > FM_PORT_MAX_NUM_OF_EXT_POOLS) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfPoolsUsed can't be larger than %d", FM_PORT_MAX_NUM_OF_EXT_POOLS)); ++ ++ for (i=0;inumOfPoolsUsed;i++) ++ { ++ if (p_FmExtPools->extBufPool[i].id >= BM_MAX_NUM_OF_POOLS) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("extBufPools.extBufPool[%d].id can't be larger than %d", i, BM_MAX_NUM_OF_POOLS)); ++ if (!p_FmExtPools->extBufPool[i].size) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("extBufPools.extBufPool[%d].size is 0", i)); ++ } ++ } ++ if (!p_FmExtPools && (p_FmBackupBmPools || p_FmBufPoolDepletion)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("backupBmPools ot bufPoolDepletion can not be defined without external pools")); ++ ++ /* backup BM pools indication is valid only for some chip derivatives ++ (limited by the config routine) */ ++ if (p_FmBackupBmPools) ++ { ++ if (p_FmBackupBmPools->numOfBackupPools >= p_FmExtPools->numOfPoolsUsed) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("p_BackupBmPools must be smaller than extBufPools.numOfPoolsUsed")); ++ found = FALSE; ++ for (i = 0;inumOfBackupPools;i++) ++ { ++ ++ for (j=0;jnumOfPoolsUsed;j++) ++ { ++ if (p_FmBackupBmPools->poolIds[i] == p_FmExtPools->extBufPool[j].id) ++ { ++ found = TRUE; ++ break; ++ } ++ } ++ if (!found) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("All p_BackupBmPools.poolIds must be included in extBufPools.extBufPool[n].id")); ++ else ++ found = FALSE; ++ } ++ } ++ ++ /* up to extBufPools.numOfPoolsUsed pools may be defined */ ++ if (p_FmBufPoolDepletion && p_FmBufPoolDepletion->poolsGrpModeEnable) ++ { ++ if ((p_FmBufPoolDepletion->numOfPools > p_FmExtPools->numOfPoolsUsed)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufPoolDepletion.numOfPools can't be larger than %d and can't be larger than numOfPoolsUsed", FM_PORT_MAX_NUM_OF_EXT_POOLS)); ++ ++ if (!p_FmBufPoolDepletion->numOfPools) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufPoolDepletion.numOfPoolsToConsider can not be 0 when poolsGrpModeEnable=TRUE")); ++ ++ found = FALSE; ++ count = 0; ++ /* for each pool that is in poolsToConsider, check if it is defined ++ in extBufPool */ ++ for (i=0;ipoolsToConsider[i]) ++ { ++ for (j=0;jnumOfPoolsUsed;j++) ++ { ++ if (i == p_FmExtPools->extBufPool[j].id) ++ { ++ found = TRUE; ++ count++; ++ break; ++ } ++ } ++ if (!found) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Pools selected for depletion are not used.")); ++ else ++ found = FALSE; ++ } ++ } ++ /* check that the number of pools that we have checked is equal to the number announced by the user */ ++ if (count != p_FmBufPoolDepletion->numOfPools) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufPoolDepletion.numOfPools is larger than the number of pools defined.")); ++ } ++ ++ if (p_FmBufPoolDepletion && p_FmBufPoolDepletion->singlePoolModeEnable) ++ { ++ /* calculate vector for number of pools depletion */ ++ found = FALSE; ++ count = 0; ++ for (i=0;ipoolsToConsiderForSingleMode[i]) ++ { ++ for (j=0;jnumOfPoolsUsed;j++) ++ { ++ if (i == p_FmExtPools->extBufPool[j].id) ++ { ++ found = TRUE; ++ count++; ++ break; ++ } ++ } ++ if (!found) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Pools selected for depletion are not used.")); ++ else ++ found = FALSE; ++ } ++ } ++ if (!count) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("No pools defined for single buffer mode pool depletion.")); ++ } ++ ++ return E_OK; ++} ++ ++t_Error FmSpCheckIntContextParams(t_FmSpIntContextDataCopy *p_FmSpIntContextDataCopy) ++{ ++ /* Check that divisible by 16 and not larger than 240 */ ++ if (p_FmSpIntContextDataCopy->intContextOffset >MAX_INT_OFFSET) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.intContextOffset can't be larger than %d", MAX_INT_OFFSET)); ++ if (p_FmSpIntContextDataCopy->intContextOffset % OFFSET_UNITS) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.intContextOffset has to be divisible by %d", OFFSET_UNITS)); ++ ++ /* check that ic size+ic internal offset, does not exceed ic block size */ ++ if (p_FmSpIntContextDataCopy->size + p_FmSpIntContextDataCopy->intContextOffset > MAX_IC_SIZE) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.size + intContext.intContextOffset has to be smaller than %d", MAX_IC_SIZE)); ++ /* Check that divisible by 16 and not larger than 256 */ ++ if (p_FmSpIntContextDataCopy->size % OFFSET_UNITS) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.size has to be divisible by %d", OFFSET_UNITS)); ++ ++ /* Check that divisible by 16 and not larger than 4K */ ++ if (p_FmSpIntContextDataCopy->extBufOffset > MAX_EXT_OFFSET) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.extBufOffset can't be larger than %d", MAX_EXT_OFFSET)); ++ if (p_FmSpIntContextDataCopy->extBufOffset % OFFSET_UNITS) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.extBufOffset has to be divisible by %d", OFFSET_UNITS)); ++ ++ return E_OK; ++} ++ ++t_Error FmSpCheckBufMargins(t_FmSpBufMargins *p_FmSpBufMargins) ++{ ++ /* Check the margin definition */ ++ if (p_FmSpBufMargins->startMargins > MAX_EXT_BUFFER_OFFSET) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufMargins.startMargins can't be larger than %d", MAX_EXT_BUFFER_OFFSET)); ++ if (p_FmSpBufMargins->endMargins > MAX_EXT_BUFFER_OFFSET) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufMargins.endMargins can't be larger than %d", MAX_EXT_BUFFER_OFFSET)); ++ ++ return E_OK; ++} ++ ++t_Error FmSpBuildBufferStructure(t_FmSpIntContextDataCopy *p_FmSpIntContextDataCopy, ++ t_FmBufferPrefixContent *p_BufferPrefixContent, ++ t_FmSpBufMargins *p_FmSpBufMargins, ++ t_FmSpBufferOffsets *p_FmSpBufferOffsets, ++ uint8_t *internalBufferOffset) ++{ ++ uint32_t tmp; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmSpIntContextDataCopy, E_INVALID_VALUE); ++ ASSERT_COND(p_FmSpIntContextDataCopy); ++ ASSERT_COND(p_BufferPrefixContent); ++ ASSERT_COND(p_FmSpBufMargins); ++ ASSERT_COND(p_FmSpBufferOffsets); ++ ++ /* Align start of internal context data to 16 byte */ ++ p_FmSpIntContextDataCopy->extBufOffset = ++ (uint16_t)((p_BufferPrefixContent->privDataSize & (OFFSET_UNITS-1)) ? ++ ((p_BufferPrefixContent->privDataSize + OFFSET_UNITS) & ~(uint16_t)(OFFSET_UNITS-1)) : ++ p_BufferPrefixContent->privDataSize); ++ ++ /* Translate margin and intContext params to FM parameters */ ++ /* Initialize with illegal value. Later we'll set legal values. */ ++ p_FmSpBufferOffsets->prsResultOffset = (uint32_t)ILLEGAL_BASE; ++ p_FmSpBufferOffsets->timeStampOffset = (uint32_t)ILLEGAL_BASE; ++ p_FmSpBufferOffsets->hashResultOffset= (uint32_t)ILLEGAL_BASE; ++ p_FmSpBufferOffsets->pcdInfoOffset = (uint32_t)ILLEGAL_BASE; ++ ++ /* Internally the driver supports 4 options ++ 1. prsResult/timestamp/hashResult selection (in fact 8 options, but for simplicity we'll ++ relate to it as 1). ++ 2. All IC context (from AD) not including debug.*/ ++ ++ /* This 'if' covers option 2. We copy from beginning of context. */ ++ if (p_BufferPrefixContent->passAllOtherPCDInfo) ++ { ++ p_FmSpIntContextDataCopy->size = 128; /* must be aligned to 16 */ ++ /* Start copying data after 16 bytes (FD) from the beginning of the internal context */ ++ p_FmSpIntContextDataCopy->intContextOffset = 16; ++ ++ if (p_BufferPrefixContent->passAllOtherPCDInfo) ++ p_FmSpBufferOffsets->pcdInfoOffset = p_FmSpIntContextDataCopy->extBufOffset; ++ if (p_BufferPrefixContent->passPrsResult) ++ p_FmSpBufferOffsets->prsResultOffset = ++ (uint32_t)(p_FmSpIntContextDataCopy->extBufOffset + 16); ++ if (p_BufferPrefixContent->passTimeStamp) ++ p_FmSpBufferOffsets->timeStampOffset = ++ (uint32_t)(p_FmSpIntContextDataCopy->extBufOffset + 48); ++ if (p_BufferPrefixContent->passHashResult) ++ p_FmSpBufferOffsets->hashResultOffset = ++ (uint32_t)(p_FmSpIntContextDataCopy->extBufOffset + 56); ++ } ++ else ++ { ++ /* This case covers the options under 1 */ ++ /* Copy size must be in 16-byte granularity. */ ++ p_FmSpIntContextDataCopy->size = ++ (uint16_t)((p_BufferPrefixContent->passPrsResult ? 32 : 0) + ++ ((p_BufferPrefixContent->passTimeStamp || ++ p_BufferPrefixContent->passHashResult) ? 16 : 0)); ++ ++ /* Align start of internal context data to 16 byte */ ++ p_FmSpIntContextDataCopy->intContextOffset = ++ (uint8_t)(p_BufferPrefixContent->passPrsResult ? 32 : ++ ((p_BufferPrefixContent->passTimeStamp || ++ p_BufferPrefixContent->passHashResult) ? 64 : 0)); ++ ++ if (p_BufferPrefixContent->passPrsResult) ++ p_FmSpBufferOffsets->prsResultOffset = p_FmSpIntContextDataCopy->extBufOffset; ++ if (p_BufferPrefixContent->passTimeStamp) ++ p_FmSpBufferOffsets->timeStampOffset = p_BufferPrefixContent->passPrsResult ? ++ (p_FmSpIntContextDataCopy->extBufOffset + sizeof(t_FmPrsResult)) : ++ p_FmSpIntContextDataCopy->extBufOffset; ++ if (p_BufferPrefixContent->passHashResult) ++ /* If PR is not requested, whether TS is requested or not, IC will be copied from TS */ ++ p_FmSpBufferOffsets->hashResultOffset = p_BufferPrefixContent->passPrsResult ? ++ (p_FmSpIntContextDataCopy->extBufOffset + sizeof(t_FmPrsResult) + 8) : ++ p_FmSpIntContextDataCopy->extBufOffset + 8; ++ } ++ ++ if (p_FmSpIntContextDataCopy->size) ++ p_FmSpBufMargins->startMargins = ++ (uint16_t)(p_FmSpIntContextDataCopy->extBufOffset + ++ p_FmSpIntContextDataCopy->size); ++ else ++ /* No Internal Context passing, STartMargin is immediately after privateInfo */ ++ p_FmSpBufMargins->startMargins = p_BufferPrefixContent->privDataSize; ++ ++ /* save extra space for manip in both external and internal buffers */ ++ if (p_BufferPrefixContent->manipExtraSpace) ++ { ++ uint8_t extraSpace; ++#ifdef FM_CAPWAP_SUPPORT ++ if ((p_BufferPrefixContent->manipExtraSpace + CAPWAP_FRAG_EXTRA_SPACE) >= 256) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("p_BufferPrefixContent->manipExtraSpace should be less than %d", ++ 256-CAPWAP_FRAG_EXTRA_SPACE)); ++ extraSpace = (uint8_t)(p_BufferPrefixContent->manipExtraSpace + CAPWAP_FRAG_EXTRA_SPACE); ++#else ++ extraSpace = p_BufferPrefixContent->manipExtraSpace; ++#endif /* FM_CAPWAP_SUPPORT */ ++ p_FmSpBufferOffsets->manipOffset = p_FmSpBufMargins->startMargins; ++ p_FmSpBufMargins->startMargins += extraSpace; ++ *internalBufferOffset = extraSpace; ++ } ++ ++ /* align data start */ ++ tmp = (uint32_t)(p_FmSpBufMargins->startMargins % p_BufferPrefixContent->dataAlign); ++ if (tmp) ++ p_FmSpBufMargins->startMargins += (p_BufferPrefixContent->dataAlign-tmp); ++ p_FmSpBufferOffsets->dataOffset = p_FmSpBufMargins->startMargins; ++ ++ return E_OK; ++} ++/*********************** End of inter-module routines ************************/ ++ ++ ++#if (DPAA_VERSION >= 11) ++/*****************************************************************************/ ++/* API routines */ ++/*****************************************************************************/ ++t_Handle FM_VSP_Config(t_FmVspParams *p_FmVspParams) ++{ ++ t_FmVspEntry *p_FmVspEntry = NULL; ++ struct fm_storage_profile_params fm_vsp_params; ++ ++ p_FmVspEntry = (t_FmVspEntry *)XX_Malloc(sizeof(t_FmVspEntry)); ++ if (!p_FmVspEntry) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_StorageProfile allocation failed")); ++ return NULL; ++ } ++ memset(p_FmVspEntry, 0, sizeof(t_FmVspEntry)); ++ ++ p_FmVspEntry->p_FmVspEntryDriverParams = (t_FmVspEntryDriverParams *)XX_Malloc(sizeof(t_FmVspEntryDriverParams)); ++ if (!p_FmVspEntry->p_FmVspEntryDriverParams) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_StorageProfile allocation failed")); ++ XX_Free(p_FmVspEntry); ++ return NULL; ++ } ++ memset(p_FmVspEntry->p_FmVspEntryDriverParams, 0, sizeof(t_FmVspEntryDriverParams)); ++ fman_vsp_defconfig(&fm_vsp_params); ++ p_FmVspEntry->p_FmVspEntryDriverParams->dmaHeaderCacheAttr = fm_vsp_params.header_cache_attr; ++ p_FmVspEntry->p_FmVspEntryDriverParams->dmaIntContextCacheAttr = fm_vsp_params.int_context_cache_attr; ++ p_FmVspEntry->p_FmVspEntryDriverParams->dmaScatterGatherCacheAttr = fm_vsp_params.scatter_gather_cache_attr; ++ p_FmVspEntry->p_FmVspEntryDriverParams->dmaSwapData = fm_vsp_params.dma_swap_data; ++ p_FmVspEntry->p_FmVspEntryDriverParams->dmaWriteOptimize = fm_vsp_params.dma_write_optimize; ++ p_FmVspEntry->p_FmVspEntryDriverParams->noScatherGather = fm_vsp_params.no_scather_gather; ++ p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.privDataSize = DEFAULT_FM_SP_bufferPrefixContent_privDataSize; ++ p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.passPrsResult= DEFAULT_FM_SP_bufferPrefixContent_passPrsResult; ++ p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.passTimeStamp= DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp; ++ p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.passAllOtherPCDInfo ++ = DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp; ++ p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.dataAlign = DEFAULT_FM_SP_bufferPrefixContent_dataAlign; ++ p_FmVspEntry->p_FmVspEntryDriverParams->liodnOffset = p_FmVspParams->liodnOffset; ++ ++ memcpy(&p_FmVspEntry->p_FmVspEntryDriverParams->extBufPools, &p_FmVspParams->extBufPools, sizeof(t_FmExtPools)); ++ p_FmVspEntry->h_Fm = p_FmVspParams->h_Fm; ++ p_FmVspEntry->portType = p_FmVspParams->portParams.portType; ++ p_FmVspEntry->portId = p_FmVspParams->portParams.portId; ++ ++ p_FmVspEntry->relativeProfileId = p_FmVspParams->relativeProfileId; ++ ++ return p_FmVspEntry; ++} ++ ++t_Error FM_VSP_Init(t_Handle h_FmVsp) ++{ ++ ++ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry *)h_FmVsp; ++ struct fm_storage_profile_params fm_vsp_params; ++ uint8_t orderedArray[FM_PORT_MAX_NUM_OF_EXT_POOLS]; ++ uint16_t sizesArray[BM_MAX_NUM_OF_POOLS]; ++ t_Error err; ++ uint16_t absoluteProfileId = 0; ++ int i = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams,E_INVALID_HANDLE); ++ ++ CHECK_INIT_PARAMETERS(p_FmVspEntry, CheckParams); ++ ++ memset(&orderedArray, 0, sizeof(uint8_t) * FM_PORT_MAX_NUM_OF_EXT_POOLS); ++ memset(&sizesArray, 0, sizeof(uint16_t) * BM_MAX_NUM_OF_POOLS); ++ ++ err = FmSpBuildBufferStructure(&p_FmVspEntry->intContext, ++ &p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent, ++ &p_FmVspEntry->bufMargins, ++ &p_FmVspEntry->bufferOffsets, ++ &p_FmVspEntry->internalBufferOffset); ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ ++ err = CheckParamsGeneratedInternally(p_FmVspEntry); ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ ++ p_FmVspEntry->p_FmSpRegsBase = ++ (struct fm_pcd_storage_profile_regs *)FmGetVSPBaseAddr(p_FmVspEntry->h_Fm); ++ if (!p_FmVspEntry->p_FmSpRegsBase) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("impossible to initialize SpRegsBase")); ++ ++ /* order external buffer pools in ascending order of buffer pools sizes */ ++ FmSpSetBufPoolsInAscOrderOfBufSizes(&(p_FmVspEntry->p_FmVspEntryDriverParams)->extBufPools, ++ orderedArray, ++ sizesArray); ++ ++ p_FmVspEntry->extBufPools.numOfPoolsUsed = ++ p_FmVspEntry->p_FmVspEntryDriverParams->extBufPools.numOfPoolsUsed; ++ for (i = 0; i < p_FmVspEntry->extBufPools.numOfPoolsUsed; i++) ++ { ++ p_FmVspEntry->extBufPools.extBufPool[i].id = orderedArray[i]; ++ p_FmVspEntry->extBufPools.extBufPool[i].size = sizesArray[orderedArray[i]]; ++ } ++ ++ /* on user responsibility to fill it according requirement */ ++ memset(&fm_vsp_params, 0, sizeof(struct fm_storage_profile_params)); ++ fm_vsp_params.dma_swap_data = p_FmVspEntry->p_FmVspEntryDriverParams->dmaSwapData; ++ fm_vsp_params.int_context_cache_attr = p_FmVspEntry->p_FmVspEntryDriverParams->dmaIntContextCacheAttr; ++ fm_vsp_params.header_cache_attr = p_FmVspEntry->p_FmVspEntryDriverParams->dmaHeaderCacheAttr; ++ fm_vsp_params.scatter_gather_cache_attr = p_FmVspEntry->p_FmVspEntryDriverParams->dmaScatterGatherCacheAttr; ++ fm_vsp_params.dma_write_optimize = p_FmVspEntry->p_FmVspEntryDriverParams->dmaWriteOptimize; ++ fm_vsp_params.liodn_offset = p_FmVspEntry->p_FmVspEntryDriverParams->liodnOffset; ++ fm_vsp_params.no_scather_gather = p_FmVspEntry->p_FmVspEntryDriverParams->noScatherGather; ++ ++ if (p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion) ++ { ++ fm_vsp_params.buf_pool_depletion.buf_pool_depletion_enabled = TRUE; ++ fm_vsp_params.buf_pool_depletion.pools_grp_mode_enable = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->poolsGrpModeEnable; ++ fm_vsp_params.buf_pool_depletion.num_pools = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->numOfPools; ++ fm_vsp_params.buf_pool_depletion.pools_to_consider = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->poolsToConsider; ++ fm_vsp_params.buf_pool_depletion.single_pool_mode_enable = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->singlePoolModeEnable; ++ fm_vsp_params.buf_pool_depletion.pools_to_consider_for_single_mode = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->poolsToConsiderForSingleMode; ++ fm_vsp_params.buf_pool_depletion.has_pfc_priorities = TRUE; ++ fm_vsp_params.buf_pool_depletion.pfc_priorities_en = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->pfcPrioritiesEn; ++ } ++ else ++ fm_vsp_params.buf_pool_depletion.buf_pool_depletion_enabled = FALSE; ++ ++ if (p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools) ++ { ++ fm_vsp_params.backup_pools.num_backup_pools = p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools->numOfBackupPools; ++ fm_vsp_params.backup_pools.pool_ids = p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools->poolIds; ++ } ++ else ++ fm_vsp_params.backup_pools.num_backup_pools = 0; ++ ++ fm_vsp_params.fm_ext_pools.num_pools_used = p_FmVspEntry->extBufPools.numOfPoolsUsed; ++ fm_vsp_params.fm_ext_pools.ext_buf_pool = (struct fman_ext_pool_params*)&p_FmVspEntry->extBufPools.extBufPool; ++ fm_vsp_params.buf_margins = (struct fman_sp_buf_margins*)&p_FmVspEntry->bufMargins; ++ fm_vsp_params.int_context = (struct fman_sp_int_context_data_copy*)&p_FmVspEntry->intContext; ++ ++ /* no check on err - it was checked earlier */ ++ FmVSPGetAbsoluteProfileId(p_FmVspEntry->h_Fm, ++ p_FmVspEntry->portType, ++ p_FmVspEntry->portId, ++ p_FmVspEntry->relativeProfileId, ++ &absoluteProfileId); ++ ++ ASSERT_COND(p_FmVspEntry->p_FmSpRegsBase); ++ ASSERT_COND(fm_vsp_params.int_context); ++ ASSERT_COND(fm_vsp_params.buf_margins); ++ ASSERT_COND((absoluteProfileId <= FM_VSP_MAX_NUM_OF_ENTRIES)); ++ ++ /* Set all registers related to VSP */ ++ fman_vsp_init(p_FmVspEntry->p_FmSpRegsBase, absoluteProfileId, &fm_vsp_params,FM_PORT_MAX_NUM_OF_EXT_POOLS, BM_MAX_NUM_OF_POOLS, FM_MAX_NUM_OF_PFC_PRIORITIES); ++ ++ p_FmVspEntry->absoluteSpId = absoluteProfileId; ++ ++ if (p_FmVspEntry->p_FmVspEntryDriverParams) ++ XX_Free(p_FmVspEntry->p_FmVspEntryDriverParams); ++ p_FmVspEntry->p_FmVspEntryDriverParams = NULL; ++ ++ return E_OK; ++} ++ ++t_Error FM_VSP_Free(t_Handle h_FmVsp) ++{ ++ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry *)h_FmVsp; ++ SANITY_CHECK_RETURN_ERROR(h_FmVsp, E_INVALID_HANDLE); ++ XX_Free(p_FmVspEntry); ++ return E_OK; ++} ++ ++t_Error FM_VSP_ConfigBufferPrefixContent(t_Handle h_FmVsp, t_FmBufferPrefixContent *p_FmBufferPrefixContent) ++{ ++ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); ++ ++ memcpy(&p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent, p_FmBufferPrefixContent, sizeof(t_FmBufferPrefixContent)); ++ /* if dataAlign was not initialized by user, we return to driver's default */ ++ if (!p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.dataAlign) ++ p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.dataAlign = DEFAULT_FM_SP_bufferPrefixContent_dataAlign; ++ ++ return E_OK; ++} ++ ++t_Error FM_VSP_ConfigDmaSwapData(t_Handle h_FmVsp, e_FmDmaSwapOption swapData) ++{ ++ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); ++ ++ p_FmVspEntry->p_FmVspEntryDriverParams->dmaSwapData = swapData; ++ ++ return E_OK; ++} ++ ++t_Error FM_VSP_ConfigDmaIcCacheAttr(t_Handle h_FmVsp, e_FmDmaCacheOption intContextCacheAttr) ++{ ++ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); ++ ++ p_FmVspEntry->p_FmVspEntryDriverParams->dmaIntContextCacheAttr = intContextCacheAttr; ++ ++ return E_OK; ++} ++ ++t_Error FM_VSP_ConfigDmaHdrAttr(t_Handle h_FmVsp, e_FmDmaCacheOption headerCacheAttr) ++{ ++ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); ++ ++ p_FmVspEntry->p_FmVspEntryDriverParams->dmaHeaderCacheAttr = headerCacheAttr; ++ ++ return E_OK; ++} ++ ++t_Error FM_VSP_ConfigDmaScatterGatherAttr(t_Handle h_FmVsp, e_FmDmaCacheOption scatterGatherCacheAttr) ++{ ++ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); ++ ++ p_FmVspEntry->p_FmVspEntryDriverParams->dmaScatterGatherCacheAttr = scatterGatherCacheAttr; ++ ++ return E_OK; ++} ++ ++t_Error FM_VSP_ConfigDmaWriteOptimize(t_Handle h_FmVsp, bool optimize) ++{ ++ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); ++ ++ ++ p_FmVspEntry->p_FmVspEntryDriverParams->dmaWriteOptimize = optimize; ++ ++ return E_OK; ++} ++ ++t_Error FM_VSP_ConfigNoScatherGather(t_Handle h_FmVsp, bool noScatherGather) ++{ ++ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; ++ ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); ++ ++ ++ p_FmVspEntry->p_FmVspEntryDriverParams->noScatherGather = noScatherGather; ++ ++ return E_OK; ++} ++ ++t_Error FM_VSP_ConfigPoolDepletion(t_Handle h_FmVsp, t_FmBufPoolDepletion *p_BufPoolDepletion) ++{ ++ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmVsp, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_BufPoolDepletion, E_INVALID_HANDLE); ++ ++ p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion = (t_FmBufPoolDepletion *)XX_Malloc(sizeof(t_FmBufPoolDepletion)); ++ if (!p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_BufPoolDepletion allocation failed")); ++ memcpy(p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion, p_BufPoolDepletion, sizeof(t_FmBufPoolDepletion)); ++ ++ return E_OK; ++} ++ ++t_Error FM_VSP_ConfigBackupPools(t_Handle h_FmVsp, t_FmBackupBmPools *p_BackupBmPools) ++{ ++ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmVsp, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_BackupBmPools, E_INVALID_HANDLE); ++ ++ p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools = (t_FmBackupBmPools *)XX_Malloc(sizeof(t_FmBackupBmPools)); ++ if (!p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_BackupBmPools allocation failed")); ++ memcpy(p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools, p_BackupBmPools, sizeof(t_FmBackupBmPools)); ++ ++ return E_OK; ++} ++ ++uint32_t FM_VSP_GetBufferDataOffset(t_Handle h_FmVsp) ++{ ++ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, 0); ++ SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, 0); ++ ++ return p_FmVspEntry->bufferOffsets.dataOffset; ++} ++ ++uint8_t * FM_VSP_GetBufferICInfo(t_Handle h_FmVsp, char *p_Data) ++{ ++ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, NULL); ++ ++ if (p_FmVspEntry->bufferOffsets.pcdInfoOffset == ILLEGAL_BASE) ++ return NULL; ++ ++ return (uint8_t *)PTR_MOVE(p_Data, p_FmVspEntry->bufferOffsets.pcdInfoOffset); ++} ++ ++t_FmPrsResult * FM_VSP_GetBufferPrsResult(t_Handle h_FmVsp, char *p_Data) ++{ ++ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, NULL); ++ ++ if (p_FmVspEntry->bufferOffsets.prsResultOffset == ILLEGAL_BASE) ++ return NULL; ++ ++ return (t_FmPrsResult *)PTR_MOVE(p_Data, p_FmVspEntry->bufferOffsets.prsResultOffset); ++} ++ ++uint64_t * FM_VSP_GetBufferTimeStamp(t_Handle h_FmVsp, char *p_Data) ++{ ++ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, NULL); ++ ++ if (p_FmVspEntry->bufferOffsets.timeStampOffset == ILLEGAL_BASE) ++ return NULL; ++ ++ return (uint64_t *)PTR_MOVE(p_Data, p_FmVspEntry->bufferOffsets.timeStampOffset); ++} ++ ++uint8_t * FM_VSP_GetBufferHashResult(t_Handle h_FmVsp, char *p_Data) ++{ ++ t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, NULL); ++ ++ if (p_FmVspEntry->bufferOffsets.hashResultOffset == ILLEGAL_BASE) ++ return NULL; ++ ++ return (uint8_t *)PTR_MOVE(p_Data, p_FmVspEntry->bufferOffsets.hashResultOffset); ++} ++ ++#endif /* (DPAA_VERSION >= 11) */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.h +new file mode 100644 +index 00000000..9c171d85 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.h +@@ -0,0 +1,85 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_sp.h ++ ++ @Description FM SP ... ++*//***************************************************************************/ ++#ifndef __FM_SP_H ++#define __FM_SP_H ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "list_ext.h" ++ ++#include "fm_sp_common.h" ++#include "fm_common.h" ++ ++ ++#define __ERR_MODULE__ MODULE_FM_SP ++ ++typedef struct { ++ t_FmBufferPrefixContent bufferPrefixContent; ++ e_FmDmaSwapOption dmaSwapData; ++ e_FmDmaCacheOption dmaIntContextCacheAttr; ++ e_FmDmaCacheOption dmaHeaderCacheAttr; ++ e_FmDmaCacheOption dmaScatterGatherCacheAttr; ++ bool dmaWriteOptimize; ++ uint16_t liodnOffset; ++ bool noScatherGather; ++ t_FmBufPoolDepletion *p_BufPoolDepletion; ++ t_FmBackupBmPools *p_BackupBmPools; ++ t_FmExtPools extBufPools; ++} t_FmVspEntryDriverParams; ++ ++typedef struct { ++ bool valid; ++ volatile bool lock; ++ uint8_t pointedOwners; ++ uint16_t absoluteSpId; ++ uint8_t internalBufferOffset; ++ t_FmSpBufMargins bufMargins; ++ t_FmSpIntContextDataCopy intContext; ++ t_FmSpBufferOffsets bufferOffsets; ++ t_Handle h_Fm; ++ e_FmPortType portType; /**< Port type */ ++ uint8_t portId; /**< Port Id - relative to type */ ++ uint8_t relativeProfileId; ++ struct fm_pcd_storage_profile_regs *p_FmSpRegsBase; ++ t_FmExtPools extBufPools; ++ t_FmVspEntryDriverParams *p_FmVspEntryDriverParams; ++} t_FmVspEntry; ++ ++ ++#endif /* __FM_SP_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fman_sp.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fman_sp.c +new file mode 100755 +index 00000000..0f772e91 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fman_sp.c +@@ -0,0 +1,197 @@ ++/* ++ * Copyright 2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "fsl_fman_sp.h" ++ ++ ++uint32_t fman_vsp_get_statistics(struct fm_pcd_storage_profile_regs *regs, ++ uint16_t index) ++{ ++ struct fm_pcd_storage_profile_regs *sp_regs; ++ sp_regs = ®s[index]; ++ return ioread32be(&sp_regs->fm_sp_acnt); ++} ++ ++void fman_vsp_set_statistics(struct fm_pcd_storage_profile_regs *regs, ++ uint16_t index, uint32_t value) ++{ ++ struct fm_pcd_storage_profile_regs *sp_regs; ++ sp_regs = ®s[index]; ++ iowrite32be(value, &sp_regs->fm_sp_acnt); ++} ++ ++void fman_vsp_defconfig(struct fm_storage_profile_params *cfg) ++{ ++ cfg->dma_swap_data = ++ DEFAULT_FMAN_SP_DMA_SWAP_DATA; ++ cfg->int_context_cache_attr = ++ DEFAULT_FMAN_SP_DMA_INT_CONTEXT_CACHE_ATTR; ++ cfg->header_cache_attr = ++ DEFAULT_FMAN_SP_DMA_HEADER_CACHE_ATTR; ++ cfg->scatter_gather_cache_attr = ++ DEFAULT_FMAN_SP_DMA_SCATTER_GATHER_CACHE_ATTR; ++ cfg->dma_write_optimize = ++ DEFAULT_FMAN_SP_DMA_WRITE_OPTIMIZE; ++ cfg->no_scather_gather = ++ DEFAULT_FMAN_SP_NO_SCATTER_GATHER; ++} ++ ++static inline uint32_t calc_vec_dep(int max_pools, bool *pools, ++ struct fman_ext_pools *ext_buf_pools, uint32_t mask) ++{ ++ int i, j; ++ uint32_t vector = 0; ++ for (i = 0; i < max_pools; i++) ++ if (pools[i]) ++ for (j = 0; j < ext_buf_pools->num_pools_used; j++) ++ if (i == ext_buf_pools->ext_buf_pool[j].id) { ++ vector |= mask >> j; ++ break; ++ } ++ return vector; ++} ++ ++void fman_vsp_init(struct fm_pcd_storage_profile_regs *regs, ++ uint16_t index, struct fm_storage_profile_params *fm_vsp_params, ++ int port_max_num_of_ext_pools, int bm_max_num_of_pools, ++ int max_num_of_pfc_priorities) ++{ ++ int i = 0, j = 0; ++ struct fm_pcd_storage_profile_regs *sp_regs; ++ uint32_t tmp_reg, vector; ++ struct fman_ext_pools *ext_buf_pools = &fm_vsp_params->fm_ext_pools; ++ struct fman_buf_pool_depletion *buf_pool_depletion = ++ &fm_vsp_params->buf_pool_depletion; ++ struct fman_backup_bm_pools *backup_pools = ++ &fm_vsp_params->backup_pools; ++ struct fman_sp_int_context_data_copy *int_context_data_copy = ++ fm_vsp_params->int_context; ++ struct fman_sp_buf_margins *external_buffer_margins = ++ fm_vsp_params->buf_margins; ++ bool no_scather_gather = fm_vsp_params->no_scather_gather; ++ uint16_t liodn_offset = fm_vsp_params->liodn_offset; ++ ++ sp_regs = ®s[index]; ++ ++ /* fill external buffers manager pool information register*/ ++ for (i = 0; i < ext_buf_pools->num_pools_used; i++) { ++ tmp_reg = FMAN_SP_EXT_BUF_POOL_VALID | ++ FMAN_SP_EXT_BUF_POOL_EN_COUNTER; ++ tmp_reg |= ((uint32_t)ext_buf_pools->ext_buf_pool[i].id << ++ FMAN_SP_EXT_BUF_POOL_ID_SHIFT); ++ tmp_reg |= ext_buf_pools->ext_buf_pool[i].size; ++ /* functionality available only for some deriviatives ++ (limited by config) */ ++ for (j = 0; j < backup_pools->num_backup_pools; j++) ++ if (ext_buf_pools->ext_buf_pool[i].id == ++ backup_pools->pool_ids[j]) { ++ tmp_reg |= FMAN_SP_EXT_BUF_POOL_BACKUP; ++ break; ++ } ++ iowrite32be(tmp_reg, &sp_regs->fm_sp_ebmpi[i]); ++ } ++ ++ /* clear unused pools */ ++ for (i = ext_buf_pools->num_pools_used; ++ i < port_max_num_of_ext_pools; i++) ++ iowrite32be(0, &sp_regs->fm_sp_ebmpi[i]); ++ ++ /* fill pool depletion register*/ ++ tmp_reg = 0; ++ if (buf_pool_depletion->buf_pool_depletion_enabled && buf_pool_depletion->pools_grp_mode_enable) { ++ /* calculate vector for number of pools depletion */ ++ vector = calc_vec_dep(bm_max_num_of_pools, buf_pool_depletion-> ++ pools_to_consider, ext_buf_pools, 0x80000000); ++ ++ /* configure num of pools and vector for number of pools mode */ ++ tmp_reg |= (((uint32_t)buf_pool_depletion->num_pools - 1) << ++ FMAN_SP_POOL_DEP_NUM_OF_POOLS_SHIFT); ++ tmp_reg |= vector; ++ } ++ ++ if (buf_pool_depletion->buf_pool_depletion_enabled && buf_pool_depletion->single_pool_mode_enable) { ++ /* calculate vector for number of pools depletion */ ++ vector = calc_vec_dep(bm_max_num_of_pools, buf_pool_depletion-> ++ pools_to_consider_for_single_mode, ++ ext_buf_pools, 0x00000080); ++ ++ /* configure num of pools and vector for number of pools mode */ ++ tmp_reg |= vector; ++ } ++ ++ /* fill QbbPEV */ ++ if (buf_pool_depletion->buf_pool_depletion_enabled) { ++ vector = 0; ++ for (i = 0; i < max_num_of_pfc_priorities; i++) ++ if (buf_pool_depletion->pfc_priorities_en[i] == TRUE) ++ vector |= 0x00000100 << i; ++ tmp_reg |= vector; ++ } ++ iowrite32be(tmp_reg, &sp_regs->fm_sp_mpd); ++ ++ /* fill dma attributes register */ ++ tmp_reg = 0; ++ tmp_reg |= (uint32_t)fm_vsp_params->dma_swap_data << ++ FMAN_SP_DMA_ATTR_SWP_SHIFT; ++ tmp_reg |= (uint32_t)fm_vsp_params->int_context_cache_attr << ++ FMAN_SP_DMA_ATTR_IC_CACHE_SHIFT; ++ tmp_reg |= (uint32_t)fm_vsp_params->header_cache_attr << ++ FMAN_SP_DMA_ATTR_HDR_CACHE_SHIFT; ++ tmp_reg |= (uint32_t)fm_vsp_params->scatter_gather_cache_attr << ++ FMAN_SP_DMA_ATTR_SG_CACHE_SHIFT; ++ if (fm_vsp_params->dma_write_optimize) ++ tmp_reg |= FMAN_SP_DMA_ATTR_WRITE_OPTIMIZE; ++ iowrite32be(tmp_reg, &sp_regs->fm_sp_da); ++ ++ /* IC parameters - fill internal context parameters register */ ++ tmp_reg = 0; ++ tmp_reg |= (((uint32_t)int_context_data_copy->ext_buf_offset/ ++ OFFSET_UNITS) << FMAN_SP_IC_TO_EXT_SHIFT); ++ tmp_reg |= (((uint32_t)int_context_data_copy->int_context_offset/ ++ OFFSET_UNITS) << FMAN_SP_IC_FROM_INT_SHIFT); ++ tmp_reg |= (((uint32_t)int_context_data_copy->size/OFFSET_UNITS) << ++ FMAN_SP_IC_SIZE_SHIFT); ++ iowrite32be(tmp_reg, &sp_regs->fm_sp_icp); ++ ++ /* buffer margins - fill external buffer margins register */ ++ tmp_reg = 0; ++ tmp_reg |= (((uint32_t)external_buffer_margins->start_margins) << ++ FMAN_SP_EXT_BUF_MARG_START_SHIFT); ++ tmp_reg |= (((uint32_t)external_buffer_margins->end_margins) << ++ FMAN_SP_EXT_BUF_MARG_END_SHIFT); ++ if (no_scather_gather) ++ tmp_reg |= FMAN_SP_SG_DISABLE; ++ iowrite32be(tmp_reg, &sp_regs->fm_sp_ebm); ++ ++ /* buffer margins - fill spliodn register */ ++ iowrite32be(liodn_offset, &sp_regs->fm_sp_spliodn); ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c +new file mode 100644 +index 00000000..a870b47e +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c +@@ -0,0 +1,5216 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm.c ++ ++ @Description FM driver routines implementation. ++*//***************************************************************************/ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "xx_ext.h" ++#include "string_ext.h" ++#include "sprint_ext.h" ++#include "debug_ext.h" ++#include "fm_muram_ext.h" ++#include ++ ++#include "fm_common.h" ++#include "fm_ipc.h" ++#include "fm.h" ++#ifndef CONFIG_FMAN_ARM ++#include ++#endif ++#include "fsl_fman.h" ++ ++ ++/****************************************/ ++/* static functions */ ++/****************************************/ ++ ++static volatile bool blockingFlag = FALSE; ++static void IpcMsgCompletionCB(t_Handle h_Fm, ++ uint8_t *p_Msg, ++ uint8_t *p_Reply, ++ uint32_t replyLength, ++ t_Error status) ++{ ++ UNUSED(h_Fm);UNUSED(p_Msg);UNUSED(p_Reply);UNUSED(replyLength);UNUSED(status); ++ blockingFlag = FALSE; ++} ++ ++static void FreeInitResources(t_Fm *p_Fm) ++{ ++ if (p_Fm->camBaseAddr) ++ FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->camBaseAddr)); ++ if (p_Fm->fifoBaseAddr) ++ FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->fifoBaseAddr)); ++ if (p_Fm->resAddr) ++ FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->resAddr)); ++} ++ ++static bool IsFmanCtrlCodeLoaded(t_Fm *p_Fm) ++{ ++ t_FMIramRegs *p_Iram; ++ ++ ASSERT_COND(p_Fm); ++ p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM); ++ ++ return (bool)!!(GET_UINT32(p_Iram->iready) & IRAM_READY); ++} ++ ++static t_Error CheckFmParameters(t_Fm *p_Fm) ++{ ++ if (IsFmanCtrlCodeLoaded(p_Fm) && !p_Fm->resetOnInit) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Old FMan CTRL code is loaded; FM must be reset!")); ++#if (DPAA_VERSION < 11) ++ if (!p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats || ++ (p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats > DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("axiDbgNumOfBeats has to be in the range 1 - %d", DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS)); ++#endif /* (DPAA_VERSION < 11) */ ++ if (p_Fm->p_FmDriverParam->dma_cam_num_of_entries % DMA_CAM_UNITS) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_cam_num_of_entries has to be divisble by %d", DMA_CAM_UNITS)); ++// if (!p_Fm->p_FmDriverParam->dma_cam_num_of_entries || (p_Fm->p_FmDriverParam->dma_cam_num_of_entries > DMA_MODE_MAX_CAM_NUM_OF_ENTRIES)) ++// RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_cam_num_of_entries has to be in the range 1 - %d", DMA_MODE_MAX_CAM_NUM_OF_ENTRIES)); ++ if (p_Fm->p_FmDriverParam->dma_comm_qtsh_asrt_emer > DMA_THRESH_MAX_COMMQ) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_comm_qtsh_asrt_emer can not be larger than %d", DMA_THRESH_MAX_COMMQ)); ++ if (p_Fm->p_FmDriverParam->dma_comm_qtsh_clr_emer > DMA_THRESH_MAX_COMMQ) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_comm_qtsh_clr_emer can not be larger than %d", DMA_THRESH_MAX_COMMQ)); ++ if (p_Fm->p_FmDriverParam->dma_comm_qtsh_clr_emer >= p_Fm->p_FmDriverParam->dma_comm_qtsh_asrt_emer) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_comm_qtsh_clr_emer must be smaller than dma_comm_qtsh_asrt_emer")); ++#if (DPAA_VERSION < 11) ++ if (p_Fm->p_FmDriverParam->dma_read_buf_tsh_asrt_emer > DMA_THRESH_MAX_BUF) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_read_buf_tsh_asrt_emer can not be larger than %d", DMA_THRESH_MAX_BUF)); ++ if (p_Fm->p_FmDriverParam->dma_read_buf_tsh_clr_emer > DMA_THRESH_MAX_BUF) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_read_buf_tsh_clr_emer can not be larger than %d", DMA_THRESH_MAX_BUF)); ++ if (p_Fm->p_FmDriverParam->dma_read_buf_tsh_clr_emer >= p_Fm->p_FmDriverParam->dma_read_buf_tsh_asrt_emer) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_read_buf_tsh_clr_emer must be smaller than dma_read_buf_tsh_asrt_emer")); ++ if (p_Fm->p_FmDriverParam->dma_write_buf_tsh_asrt_emer > DMA_THRESH_MAX_BUF) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_write_buf_tsh_asrt_emer can not be larger than %d", DMA_THRESH_MAX_BUF)); ++ if (p_Fm->p_FmDriverParam->dma_write_buf_tsh_clr_emer > DMA_THRESH_MAX_BUF) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_write_buf_tsh_clr_emer can not be larger than %d", DMA_THRESH_MAX_BUF)); ++ if (p_Fm->p_FmDriverParam->dma_write_buf_tsh_clr_emer >= p_Fm->p_FmDriverParam->dma_write_buf_tsh_asrt_emer) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_write_buf_tsh_clr_emer must be smaller than dma_write_buf_tsh_asrt_emer")); ++#else /* (DPAA_VERSION >= 11) */ ++ if ((p_Fm->p_FmDriverParam->dma_dbg_cnt_mode == E_FMAN_DMA_DBG_CNT_INT_READ_EM)|| ++ (p_Fm->p_FmDriverParam->dma_dbg_cnt_mode == E_FMAN_DMA_DBG_CNT_INT_WRITE_EM) || ++ (p_Fm->p_FmDriverParam->dma_dbg_cnt_mode == E_FMAN_DMA_DBG_CNT_RAW_WAR_PROT)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_dbg_cnt_mode value not supported by this integration.")); ++ if ((p_Fm->p_FmDriverParam->dma_emergency_bus_select == FM_DMA_MURAM_READ_EMERGENCY)|| ++ (p_Fm->p_FmDriverParam->dma_emergency_bus_select == FM_DMA_MURAM_WRITE_EMERGENCY)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("emergencyBusSelect value not supported by this integration.")); ++ if (p_Fm->p_FmDriverParam->dma_stop_on_bus_error) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_stop_on_bus_error not supported by this integration.")); ++#ifdef FM_AID_MODE_NO_TNUM_SW005 ++ if (p_Fm->p_FmDriverParam->dma_aid_mode != E_FMAN_DMA_AID_OUT_PORT_ID) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_aid_mode not supported by this integration.")); ++#endif /* FM_AID_MODE_NO_TNUM_SW005 */ ++ if (p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_axi_dbg_num_of_beats not supported by this integration.")); ++#endif /* (DPAA_VERSION < 11) */ ++ ++ if (!p_Fm->p_FmStateStruct->fmClkFreq) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fmClkFreq must be set.")); ++ if (USEC_TO_CLK(p_Fm->p_FmDriverParam->dma_watchdog, p_Fm->p_FmStateStruct->fmClkFreq) > DMA_MAX_WATCHDOG) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("dma_watchdog depends on FM clock. dma_watchdog(in microseconds) * clk (in Mhz), may not exceed 0x08x", DMA_MAX_WATCHDOG)); ++ ++#if (DPAA_VERSION >= 11) ++ if ((p_Fm->partVSPBase + p_Fm->partNumOfVSPs) > FM_VSP_MAX_NUM_OF_ENTRIES) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("partVSPBase+partNumOfVSPs out of range!!!")); ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ if (p_Fm->p_FmStateStruct->totalFifoSize % BMI_FIFO_UNITS) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("totalFifoSize number has to be divisible by %d", BMI_FIFO_UNITS)); ++ if (!p_Fm->p_FmStateStruct->totalFifoSize || ++ (p_Fm->p_FmStateStruct->totalFifoSize > BMI_MAX_FIFO_SIZE)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("totalFifoSize (currently defined as %d) has to be in the range of 256 to %d", ++ p_Fm->p_FmStateStruct->totalFifoSize, ++ BMI_MAX_FIFO_SIZE)); ++ if (!p_Fm->p_FmStateStruct->totalNumOfTasks || ++ (p_Fm->p_FmStateStruct->totalNumOfTasks > BMI_MAX_NUM_OF_TASKS)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("totalNumOfTasks number has to be in the range 1 - %d", BMI_MAX_NUM_OF_TASKS)); ++ ++#ifdef FM_HAS_TOTAL_DMAS ++ if (!p_Fm->p_FmStateStruct->maxNumOfOpenDmas || ++ (p_Fm->p_FmStateStruct->maxNumOfOpenDmas > BMI_MAX_NUM_OF_DMAS)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("maxNumOfOpenDmas number has to be in the range 1 - %d", BMI_MAX_NUM_OF_DMAS)); ++#endif /* FM_HAS_TOTAL_DMAS */ ++ ++ if (p_Fm->p_FmDriverParam->disp_limit_tsh > FPM_MAX_DISP_LIMIT) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("disp_limit_tsh can't be greater than %d", FPM_MAX_DISP_LIMIT)); ++ ++ if (!p_Fm->f_Exception) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided")); ++ if (!p_Fm->f_BusError) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided")); ++ ++#ifdef FM_NO_WATCHDOG ++ if ((p_Fm->p_FmStateStruct->revInfo.majorRev == 2) && ++ (p_Fm->p_FmDriverParam->dma_watchdog)) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("watchdog!")); ++#endif /* FM_NO_WATCHDOG */ ++ ++#ifdef FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008 ++ if ((p_Fm->p_FmStateStruct->revInfo.majorRev < 6) && ++ (p_Fm->p_FmDriverParam->halt_on_unrecov_ecc_err)) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("HaltOnEccError!")); ++#endif /* FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008 */ ++ ++#ifdef FM_NO_TNUM_AGING ++ if ((p_Fm->p_FmStateStruct->revInfo.majorRev != 4) && ++ (p_Fm->p_FmStateStruct->revInfo.majorRev < 6)) ++ if (p_Fm->p_FmDriverParam->tnum_aging_period) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Tnum aging!")); ++#endif /* FM_NO_TNUM_AGING */ ++ ++ /* check that user did not set revision-dependent exceptions */ ++#ifdef FM_NO_DISPATCH_RAM_ECC ++ if ((p_Fm->p_FmStateStruct->revInfo.majorRev != 4) && ++ (p_Fm->p_FmStateStruct->revInfo.majorRev < 6)) ++ if (p_Fm->userSetExceptions & FM_EX_BMI_DISPATCH_RAM_ECC) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("exception e_FM_EX_BMI_DISPATCH_RAM_ECC!")); ++#endif /* FM_NO_DISPATCH_RAM_ECC */ ++ ++#ifdef FM_QMI_NO_ECC_EXCEPTIONS ++ if (p_Fm->p_FmStateStruct->revInfo.majorRev == 4) ++ if (p_Fm->userSetExceptions & (FM_EX_QMI_SINGLE_ECC | FM_EX_QMI_DOUBLE_ECC)) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("exception e_FM_EX_QMI_SINGLE_ECC/e_FM_EX_QMI_DOUBLE_ECC!")); ++#endif /* FM_QMI_NO_ECC_EXCEPTIONS */ ++ ++#ifdef FM_QMI_NO_SINGLE_ECC_EXCEPTION ++ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) ++ if (p_Fm->userSetExceptions & FM_EX_QMI_SINGLE_ECC) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("exception e_FM_EX_QMI_SINGLE_ECC!")); ++#endif /* FM_QMI_NO_SINGLE_ECC_EXCEPTION */ ++ ++ return E_OK; ++} ++ ++ ++static void SendIpcIsr(t_Fm *p_Fm, uint32_t macEvent, uint32_t pendingReg) ++{ ++ ASSERT_COND(p_Fm->guestId == NCSW_MASTER_ID); ++ ++ if (p_Fm->intrMng[macEvent].guestId == NCSW_MASTER_ID) ++ p_Fm->intrMng[macEvent].f_Isr(p_Fm->intrMng[macEvent].h_SrcHandle); ++ ++ /* If the MAC is running on guest-partition and we have IPC session with it, ++ we inform him about the event through IPC; otherwise, we ignore the event. */ ++ else if (p_Fm->h_IpcSessions[p_Fm->intrMng[macEvent].guestId]) ++ { ++ t_Error err; ++ t_FmIpcIsr fmIpcIsr; ++ t_FmIpcMsg msg; ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.msgId = FM_GUEST_ISR; ++ fmIpcIsr.pendingReg = pendingReg; ++ fmIpcIsr.boolErr = FALSE; ++ memcpy(msg.msgBody, &fmIpcIsr, sizeof(fmIpcIsr)); ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[p_Fm->intrMng[macEvent].guestId], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) + sizeof(fmIpcIsr), ++ NULL, ++ NULL, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ REPORT_ERROR(MINOR, err, NO_MSG); ++ } ++ else ++ DBG(TRACE, ("FM Guest mode, without IPC - can't call ISR!")); ++} ++ ++static void BmiErrEvent(t_Fm *p_Fm) ++{ ++ uint32_t event; ++ struct fman_bmi_regs *bmi_rg = p_Fm->p_FmBmiRegs; ++ ++ ++ event = fman_get_bmi_err_event(bmi_rg); ++ ++ if (event & BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC) ++ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_STORAGE_PROFILE_ECC); ++ if (event & BMI_ERR_INTR_EN_LIST_RAM_ECC) ++ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_LIST_RAM_ECC); ++ if (event & BMI_ERR_INTR_EN_STATISTICS_RAM_ECC) ++ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_STATISTICS_RAM_ECC); ++ if (event & BMI_ERR_INTR_EN_DISPATCH_RAM_ECC) ++ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_DISPATCH_RAM_ECC); ++} ++ ++static void QmiErrEvent(t_Fm *p_Fm) ++{ ++ uint32_t event; ++ struct fman_qmi_regs *qmi_rg = p_Fm->p_FmQmiRegs; ++ ++ event = fman_get_qmi_err_event(qmi_rg); ++ ++ if (event & QMI_ERR_INTR_EN_DOUBLE_ECC) ++ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_QMI_DOUBLE_ECC); ++ if (event & QMI_ERR_INTR_EN_DEQ_FROM_DEF) ++ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID); ++} ++ ++static void DmaErrEvent(t_Fm *p_Fm) ++{ ++ uint32_t status, com_id; ++ uint8_t tnum; ++ uint8_t hardwarePortId; ++ uint8_t relativePortId; ++ uint16_t liodn; ++ struct fman_dma_regs *dma_rg = p_Fm->p_FmDmaRegs; ++ ++ status = fman_get_dma_err_event(dma_rg); ++ ++ if (status & DMA_STATUS_BUS_ERR) ++ { ++ com_id = fman_get_dma_com_id(dma_rg); ++ hardwarePortId = (uint8_t)(((com_id & DMA_TRANSFER_PORTID_MASK) >> DMA_TRANSFER_PORTID_SHIFT)); ++ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); ++ HW_PORT_ID_TO_SW_PORT_ID(relativePortId, hardwarePortId); ++ tnum = (uint8_t)((com_id & DMA_TRANSFER_TNUM_MASK) >> DMA_TRANSFER_TNUM_SHIFT); ++ liodn = (uint16_t)(com_id & DMA_TRANSFER_LIODN_MASK); ++ ASSERT_COND(p_Fm->p_FmStateStruct->portsTypes[hardwarePortId] != e_FM_PORT_TYPE_DUMMY); ++ p_Fm->f_BusError(p_Fm->h_App, ++ p_Fm->p_FmStateStruct->portsTypes[hardwarePortId], ++ relativePortId, ++ fman_get_dma_addr(dma_rg), ++ tnum, ++ liodn); ++ } ++ if (status & DMA_STATUS_FM_SPDAT_ECC) ++ p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_SINGLE_PORT_ECC); ++ if (status & DMA_STATUS_READ_ECC) ++ p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_READ_ECC); ++ if (status & DMA_STATUS_SYSTEM_WRITE_ECC) ++ p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_SYSTEM_WRITE_ECC); ++ if (status & DMA_STATUS_FM_WRITE_ECC) ++ p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_FM_WRITE_ECC); ++ } ++ ++static void FpmErrEvent(t_Fm *p_Fm) ++{ ++ uint32_t event; ++ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; ++ ++ event = fman_get_fpm_err_event(fpm_rg); ++ ++ if ((event & FPM_EV_MASK_DOUBLE_ECC) && (event & FPM_EV_MASK_DOUBLE_ECC_EN)) ++ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_FPM_DOUBLE_ECC); ++ if ((event & FPM_EV_MASK_STALL) && (event & FPM_EV_MASK_STALL_EN)) ++ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_FPM_STALL_ON_TASKS); ++ if ((event & FPM_EV_MASK_SINGLE_ECC) && (event & FPM_EV_MASK_SINGLE_ECC_EN)) ++ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_FPM_SINGLE_ECC); ++} ++ ++static void MuramErrIntr(t_Fm *p_Fm) ++{ ++ uint32_t event; ++ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; ++ ++ event = fman_get_muram_err_event(fpm_rg); ++ ++ if (event & FPM_RAM_MURAM_ECC) ++ p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_MURAM_ECC); ++} ++ ++static void IramErrIntr(t_Fm *p_Fm) ++{ ++ uint32_t event; ++ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; ++ ++ event = fman_get_iram_err_event(fpm_rg); ++ ++ if (event & FPM_RAM_IRAM_ECC) ++ p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_IRAM_ECC); ++} ++ ++static void QmiEvent(t_Fm *p_Fm) ++{ ++ uint32_t event; ++ struct fman_qmi_regs *qmi_rg = p_Fm->p_FmQmiRegs; ++ ++ event = fman_get_qmi_event(qmi_rg); ++ ++ if (event & QMI_INTR_EN_SINGLE_ECC) ++ p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_QMI_SINGLE_ECC); ++} ++ ++static void UnimplementedIsr(t_Handle h_Arg) ++{ ++ UNUSED(h_Arg); ++ ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unimplemented ISR!")); ++} ++ ++static void UnimplementedFmanCtrlIsr(t_Handle h_Arg, uint32_t event) ++{ ++ UNUSED(h_Arg); UNUSED(event); ++ ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unimplemented FmCtl ISR!")); ++} ++ ++static void EnableTimeStamp(t_Fm *p_Fm) ++{ ++ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; ++ ++ ASSERT_COND(p_Fm->p_FmStateStruct); ++ ASSERT_COND(p_Fm->p_FmStateStruct->count1MicroBit); ++ ++ fman_enable_time_stamp(fpm_rg, p_Fm->p_FmStateStruct->count1MicroBit, p_Fm->p_FmStateStruct->fmClkFreq); ++ ++ p_Fm->p_FmStateStruct->enabledTimeStamp = TRUE; ++} ++ ++static t_Error ClearIRam(t_Fm *p_Fm) ++{ ++ t_FMIramRegs *p_Iram; ++ int i; ++ int iram_size; ++ ++ ASSERT_COND(p_Fm); ++ p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM); ++ iram_size = FM_IRAM_SIZE(p_Fm->p_FmStateStruct->revInfo.majorRev,p_Fm->p_FmStateStruct->revInfo.minorRev); ++ ++ /* Enable the auto-increment */ ++ WRITE_UINT32(p_Iram->iadd, IRAM_IADD_AIE); ++ while (GET_UINT32(p_Iram->iadd) != IRAM_IADD_AIE) ; ++ ++ for (i=0; i < (iram_size/4); i++) ++ WRITE_UINT32(p_Iram->idata, 0xffffffff); ++ ++ WRITE_UINT32(p_Iram->iadd, iram_size - 4); ++ CORE_MemoryBarrier(); ++ while (GET_UINT32(p_Iram->idata) != 0xffffffff) ; ++ ++ return E_OK; ++} ++ ++static t_Error LoadFmanCtrlCode(t_Fm *p_Fm) ++{ ++ t_FMIramRegs *p_Iram; ++ int i; ++ uint32_t tmp; ++ uint8_t compTo16; ++ ++ ASSERT_COND(p_Fm); ++ p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM); ++ ++ /* Enable the auto-increment */ ++ WRITE_UINT32(p_Iram->iadd, IRAM_IADD_AIE); ++ while (GET_UINT32(p_Iram->iadd) != IRAM_IADD_AIE) ; ++ ++ for (i=0; i < (p_Fm->firmware.size / 4); i++) ++ WRITE_UINT32(p_Iram->idata, p_Fm->firmware.p_Code[i]); ++ ++ compTo16 = (uint8_t)(p_Fm->firmware.size % 16); ++ if (compTo16) ++ for (i=0; i < ((16-compTo16) / 4); i++) ++ WRITE_UINT32(p_Iram->idata, 0xffffffff); ++ ++ WRITE_UINT32(p_Iram->iadd,p_Fm->firmware.size-4); ++ while (GET_UINT32(p_Iram->iadd) != (p_Fm->firmware.size-4)) ; ++ ++ /* verify that writing has completed */ ++ while (GET_UINT32(p_Iram->idata) != p_Fm->firmware.p_Code[(p_Fm->firmware.size / 4)-1]) ; ++ ++ if (p_Fm->fwVerify) ++ { ++ WRITE_UINT32(p_Iram->iadd, IRAM_IADD_AIE); ++ while (GET_UINT32(p_Iram->iadd) != IRAM_IADD_AIE) ; ++ for (i=0; i < (p_Fm->firmware.size / 4); i++) ++ { ++ tmp = GET_UINT32(p_Iram->idata); ++ if (tmp != p_Fm->firmware.p_Code[i]) ++ RETURN_ERROR(MAJOR, E_WRITE_FAILED, ++ ("UCode write error : write 0x%x, read 0x%x", ++ p_Fm->firmware.p_Code[i],tmp)); ++ } ++ WRITE_UINT32(p_Iram->iadd, 0x0); ++ } ++ ++ /* Enable patch from IRAM */ ++ WRITE_UINT32(p_Iram->iready, IRAM_READY); ++ XX_UDelay(1000); ++ ++ DBG(INFO, ("FMan-Controller code (ver %d.%d.%d) loaded to IRAM.", ++ ((uint16_t *)p_Fm->firmware.p_Code)[2], ++ ((uint8_t *)p_Fm->firmware.p_Code)[6], ++ ((uint8_t *)p_Fm->firmware.p_Code)[7])); ++ ++ return E_OK; ++} ++ ++#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 ++static t_Error FwNotResetErratumBugzilla6173WA(t_Fm *p_Fm) ++{ ++ t_FMIramRegs *p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM); ++ uint32_t tmpReg; ++ uint32_t savedSpliodn[63]; ++ ++ /* write to IRAM first location the debug instruction */ ++ WRITE_UINT32(p_Iram->iadd, 0); ++ while (GET_UINT32(p_Iram->iadd) != 0) ; ++ WRITE_UINT32(p_Iram->idata, FM_FW_DEBUG_INSTRUCTION); ++ ++ WRITE_UINT32(p_Iram->iadd, 0); ++ while (GET_UINT32(p_Iram->iadd) != 0) ; ++ while (GET_UINT32(p_Iram->idata) != FM_FW_DEBUG_INSTRUCTION) ; ++ ++ /* Enable patch from IRAM */ ++ WRITE_UINT32(p_Iram->iready, IRAM_READY); ++ CORE_MemoryBarrier(); ++ XX_UDelay(100); ++ IO2MemCpy32((uint8_t *)savedSpliodn, ++ (uint8_t *)p_Fm->p_FmBmiRegs->fmbm_spliodn, ++ 63*sizeof(uint32_t)); ++ ++ /* reset FMAN */ ++ WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rstc, FPM_RSTC_FM_RESET); ++ CORE_MemoryBarrier(); ++ XX_UDelay(100); ++ ++ /* verify breakpoint debug status register */ ++ tmpReg = GET_UINT32(*(uint32_t *)UINT_TO_PTR(p_Fm->baseAddr + FM_DEBUG_STATUS_REGISTER_OFFSET)); ++ if (!tmpReg) ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Invalid debug status register value is '0'")); ++ ++ /*************************************/ ++ /* Load FMan-Controller code to IRAM */ ++ /*************************************/ ++ ClearIRam(p_Fm); ++ if (p_Fm->firmware.p_Code && ++ (LoadFmanCtrlCode(p_Fm) != E_OK)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ XX_UDelay(100); ++ ++ /* reset FMAN again to start the microcode */ ++ WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rstc, FPM_RSTC_FM_RESET); ++ CORE_MemoryBarrier(); ++ XX_UDelay(100); ++ Mem2IOCpy32((uint8_t *)p_Fm->p_FmBmiRegs->fmbm_spliodn, ++ (uint8_t *)savedSpliodn, ++ 63*sizeof(uint32_t)); ++ ++ if (fman_is_qmi_halt_not_busy_state(p_Fm->p_FmQmiRegs)) ++ { ++ fman_resume(p_Fm->p_FmFpmRegs); ++ CORE_MemoryBarrier(); ++ XX_UDelay(100); ++ } ++ ++ return E_OK; ++} ++#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */ ++ ++static void GuestErrorIsr(t_Fm *p_Fm, uint32_t pending) ++{ ++#define FM_G_CALL_1G_MAC_ERR_ISR(_id) \ ++do { \ ++ p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].h_SrcHandle);\ ++} while (0) ++#define FM_G_CALL_10G_MAC_ERR_ISR(_id) \ ++do { \ ++ p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].h_SrcHandle);\ ++} while (0) ++ ++ /* error interrupts */ ++ if (pending & ERR_INTR_EN_1G_MAC0) ++ FM_G_CALL_1G_MAC_ERR_ISR(0); ++ if (pending & ERR_INTR_EN_1G_MAC1) ++ FM_G_CALL_1G_MAC_ERR_ISR(1); ++ if (pending & ERR_INTR_EN_1G_MAC2) ++ FM_G_CALL_1G_MAC_ERR_ISR(2); ++ if (pending & ERR_INTR_EN_1G_MAC3) ++ FM_G_CALL_1G_MAC_ERR_ISR(3); ++ if (pending & ERR_INTR_EN_1G_MAC4) ++ FM_G_CALL_1G_MAC_ERR_ISR(4); ++ if (pending & ERR_INTR_EN_1G_MAC5) ++ FM_G_CALL_1G_MAC_ERR_ISR(5); ++ if (pending & ERR_INTR_EN_1G_MAC6) ++ FM_G_CALL_1G_MAC_ERR_ISR(6); ++ if (pending & ERR_INTR_EN_1G_MAC7) ++ FM_G_CALL_1G_MAC_ERR_ISR(7); ++ if (pending & ERR_INTR_EN_10G_MAC0) ++ FM_G_CALL_10G_MAC_ERR_ISR(0); ++ if (pending & ERR_INTR_EN_10G_MAC1) ++ FM_G_CALL_10G_MAC_ERR_ISR(1); ++} ++ ++static void GuestEventIsr(t_Fm *p_Fm, uint32_t pending) ++{ ++#define FM_G_CALL_1G_MAC_ISR(_id) \ ++do { \ ++ p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].h_SrcHandle);\ ++} while (0) ++#define FM_G_CALL_10G_MAC_ISR(_id) \ ++do { \ ++ p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].h_SrcHandle);\ ++} while (0) ++ ++ if (pending & INTR_EN_1G_MAC0) ++ FM_G_CALL_1G_MAC_ISR(0); ++ if (pending & INTR_EN_1G_MAC1) ++ FM_G_CALL_1G_MAC_ISR(1); ++ if (pending & INTR_EN_1G_MAC2) ++ FM_G_CALL_1G_MAC_ISR(2); ++ if (pending & INTR_EN_1G_MAC3) ++ FM_G_CALL_1G_MAC_ISR(3); ++ if (pending & INTR_EN_1G_MAC4) ++ FM_G_CALL_1G_MAC_ISR(4); ++ if (pending & INTR_EN_1G_MAC5) ++ FM_G_CALL_1G_MAC_ISR(5); ++ if (pending & INTR_EN_1G_MAC6) ++ FM_G_CALL_1G_MAC_ISR(6); ++ if (pending & INTR_EN_1G_MAC7) ++ FM_G_CALL_1G_MAC_ISR(7); ++ if (pending & INTR_EN_10G_MAC0) ++ FM_G_CALL_10G_MAC_ISR(0); ++ if (pending & INTR_EN_10G_MAC1) ++ FM_G_CALL_10G_MAC_ISR(1); ++ if (pending & INTR_EN_TMR) ++ p_Fm->intrMng[e_FM_EV_TMR].f_Isr(p_Fm->intrMng[e_FM_EV_TMR].h_SrcHandle); ++} ++ ++#if (DPAA_VERSION >= 11) ++static t_Error SetVSPWindow(t_Handle h_Fm, ++ uint8_t hardwarePortId, ++ uint8_t baseStorageProfile, ++ uint8_t log2NumOfProfiles) ++{ ++ t_Fm *p_Fm = (t_Fm *)h_Fm; ++ ++ ASSERT_COND(h_Fm); ++ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); ++ ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ !p_Fm->p_FmBmiRegs && ++ p_Fm->h_IpcSessions[0]) ++ { ++ t_FmIpcVspSetPortWindow fmIpcVspSetPortWindow; ++ t_FmIpcMsg msg; ++ t_Error err = E_OK; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&fmIpcVspSetPortWindow, 0, sizeof(t_FmIpcVspSetPortWindow)); ++ fmIpcVspSetPortWindow.hardwarePortId = hardwarePortId; ++ fmIpcVspSetPortWindow.baseStorageProfile = baseStorageProfile; ++ fmIpcVspSetPortWindow.log2NumOfProfiles = log2NumOfProfiles; ++ msg.msgId = FM_VSP_SET_PORT_WINDOW; ++ memcpy(msg.msgBody, &fmIpcVspSetPortWindow, sizeof(t_FmIpcVspSetPortWindow)); ++ ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId), ++ NULL, ++ NULL, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ return E_OK; ++ } ++ else if (!p_Fm->p_FmBmiRegs) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("Either IPC or 'baseAddress' is required!")); ++ ++ fman_set_vsp_window(p_Fm->p_FmBmiRegs, ++ hardwarePortId, ++ baseStorageProfile, ++ log2NumOfProfiles); ++ ++ return E_OK; ++} ++ ++static uint8_t AllocVSPsForPartition(t_Handle h_Fm, uint8_t base, uint8_t numOfProfiles, uint8_t guestId) ++{ ++ t_Fm *p_Fm = (t_Fm *)h_Fm; ++ uint8_t profilesFound = 0; ++ int i = 0; ++ uint32_t intFlags; ++ ++ if (!numOfProfiles) ++ return E_OK; ++ ++ if ((numOfProfiles > FM_VSP_MAX_NUM_OF_ENTRIES) || ++ (base + numOfProfiles > FM_VSP_MAX_NUM_OF_ENTRIES)) ++ return (uint8_t)ILLEGAL_BASE; ++ ++ if (p_Fm->h_IpcSessions[0]) ++ { ++ t_FmIpcResourceAllocParams ipcAllocParams; ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ t_Error err; ++ uint32_t replyLength; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams)); ++ ipcAllocParams.guestId = p_Fm->guestId; ++ ipcAllocParams.num = p_Fm->partNumOfVSPs; ++ ipcAllocParams.base = p_Fm->partVSPBase; ++ msg.msgId = FM_VSP_ALLOC; ++ memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams)); ++ replyLength = sizeof(uint32_t) + sizeof(uint8_t); ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL); ++ if ((err != E_OK) || ++ (replyLength != (sizeof(uint32_t) + sizeof(uint8_t)))) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ else ++ memcpy((uint8_t*)&p_Fm->partVSPBase, reply.replyBody, sizeof(uint8_t)); ++ if (p_Fm->partVSPBase == (uint8_t)(ILLEGAL_BASE)) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ if (p_Fm->guestId != NCSW_MASTER_ID) ++ { ++ DBG(WARNING, ("FM Guest mode, without IPC - can't validate VSP range!")); ++ return (uint8_t)ILLEGAL_BASE; ++ } ++ ++ intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock); ++ for (i = base; i < base + numOfProfiles; i++) ++ if (p_Fm->p_FmSp->profiles[i].profilesMng.ownerId == (uint8_t)ILLEGAL_BASE) ++ profilesFound++; ++ else ++ break; ++ ++ if (profilesFound == numOfProfiles) ++ for (i = base; ip_FmSp->profiles[i].profilesMng.ownerId = guestId; ++ else ++ { ++ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); ++ return (uint8_t)ILLEGAL_BASE; ++ } ++ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); ++ ++ return base; ++} ++ ++static void FreeVSPsForPartition(t_Handle h_Fm, uint8_t base, uint8_t numOfProfiles, uint8_t guestId) ++{ ++ t_Fm *p_Fm = (t_Fm *)h_Fm; ++ int i = 0; ++ ++ ASSERT_COND(p_Fm); ++ ++ if (p_Fm->h_IpcSessions[0]) ++ { ++ t_FmIpcResourceAllocParams ipcAllocParams; ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ uint32_t replyLength; ++ t_Error err; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams)); ++ ipcAllocParams.guestId = p_Fm->guestId; ++ ipcAllocParams.num = p_Fm->partNumOfVSPs; ++ ipcAllocParams.base = p_Fm->partVSPBase; ++ msg.msgId = FM_VSP_FREE; ++ memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams)); ++ replyLength = sizeof(uint32_t) + sizeof(uint8_t); ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ REPORT_ERROR(MAJOR, err, NO_MSG); ++ return; ++ } ++ if (p_Fm->guestId != NCSW_MASTER_ID) ++ { ++ DBG(WARNING, ("FM Guest mode, without IPC - can't validate VSP range!")); ++ return; ++ } ++ ++ ASSERT_COND(p_Fm->p_FmSp); ++ ++ for (i=base; ip_FmSp->profiles[i].profilesMng.ownerId == guestId) ++ p_Fm->p_FmSp->profiles[i].profilesMng.ownerId = (uint8_t)ILLEGAL_BASE; ++ else ++ DBG(WARNING, ("Request for freeing storage profile window which wasn't allocated to this partition")); ++ } ++} ++#endif /* (DPAA_VERSION >= 11) */ ++ ++static t_Error FmGuestHandleIpcMsgCB(t_Handle h_Fm, ++ uint8_t *p_Msg, ++ uint32_t msgLength, ++ uint8_t *p_Reply, ++ uint32_t *p_ReplyLength) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ t_FmIpcMsg *p_IpcMsg = (t_FmIpcMsg*)p_Msg; ++ ++ UNUSED(p_Reply); ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((msgLength > sizeof(uint32_t)), E_INVALID_VALUE); ++ ++#ifdef DISABLE_SANITY_CHECKS ++ UNUSED(msgLength); ++#endif /* DISABLE_SANITY_CHECKS */ ++ ++ ASSERT_COND(p_Msg); ++ ++ *p_ReplyLength = 0; ++ ++ switch (p_IpcMsg->msgId) ++ { ++ case (FM_GUEST_ISR): ++ { ++ t_FmIpcIsr ipcIsr; ++ ++ memcpy((uint8_t*)&ipcIsr, p_IpcMsg->msgBody, sizeof(t_FmIpcIsr)); ++ if (ipcIsr.boolErr) ++ GuestErrorIsr(p_Fm, ipcIsr.pendingReg); ++ else ++ GuestEventIsr(p_Fm, ipcIsr.pendingReg); ++ break; ++ } ++ default: ++ *p_ReplyLength = 0; ++ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("command not found!!!")); ++ } ++ return E_OK; ++} ++ ++static t_Error FmHandleIpcMsgCB(t_Handle h_Fm, ++ uint8_t *p_Msg, ++ uint32_t msgLength, ++ uint8_t *p_Reply, ++ uint32_t *p_ReplyLength) ++{ ++ t_Error err; ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ t_FmIpcMsg *p_IpcMsg = (t_FmIpcMsg*)p_Msg; ++ t_FmIpcReply *p_IpcReply = (t_FmIpcReply*)p_Reply; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((msgLength >= sizeof(uint32_t)), E_INVALID_VALUE); ++ ++#ifdef DISABLE_SANITY_CHECKS ++ UNUSED(msgLength); ++#endif /* DISABLE_SANITY_CHECKS */ ++ ++ ASSERT_COND(p_IpcMsg); ++ ++ memset(p_IpcReply, 0, (sizeof(uint8_t) * FM_IPC_MAX_REPLY_SIZE)); ++ *p_ReplyLength = 0; ++ ++ switch (p_IpcMsg->msgId) ++ { ++ case (FM_GET_SET_PORT_PARAMS): ++ { ++ t_FmIpcPortInInitParams ipcInitParams; ++ t_FmInterModulePortInitParams initParams; ++ t_FmIpcPortOutInitParams ipcOutInitParams; ++ ++ memcpy((uint8_t*)&ipcInitParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortInInitParams)); ++ initParams.hardwarePortId = ipcInitParams.hardwarePortId; ++ initParams.portType = (e_FmPortType)ipcInitParams.enumPortType; ++ initParams.independentMode = (bool)(ipcInitParams.boolIndependentMode); ++ initParams.liodnOffset = ipcInitParams.liodnOffset; ++ initParams.numOfTasks = ipcInitParams.numOfTasks; ++ initParams.numOfExtraTasks = ipcInitParams.numOfExtraTasks; ++ initParams.numOfOpenDmas = ipcInitParams.numOfOpenDmas; ++ initParams.numOfExtraOpenDmas = ipcInitParams.numOfExtraOpenDmas; ++ initParams.sizeOfFifo = ipcInitParams.sizeOfFifo; ++ initParams.extraSizeOfFifo = ipcInitParams.extraSizeOfFifo; ++ initParams.deqPipelineDepth = ipcInitParams.deqPipelineDepth; ++ initParams.maxFrameLength = ipcInitParams.maxFrameLength; ++ initParams.liodnBase = ipcInitParams.liodnBase; ++ ++ p_IpcReply->error = (uint32_t)FmGetSetPortParams(h_Fm, &initParams); ++ ++ ipcOutInitParams.ipcPhysAddr.high = initParams.fmMuramPhysBaseAddr.high; ++ ipcOutInitParams.ipcPhysAddr.low = initParams.fmMuramPhysBaseAddr.low; ++ ipcOutInitParams.sizeOfFifo = initParams.sizeOfFifo; ++ ipcOutInitParams.extraSizeOfFifo = initParams.extraSizeOfFifo; ++ ipcOutInitParams.numOfTasks = initParams.numOfTasks; ++ ipcOutInitParams.numOfExtraTasks = initParams.numOfExtraTasks; ++ ipcOutInitParams.numOfOpenDmas = initParams.numOfOpenDmas; ++ ipcOutInitParams.numOfExtraOpenDmas = initParams.numOfExtraOpenDmas; ++ memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcOutInitParams, sizeof(ipcOutInitParams)); ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcPortOutInitParams); ++ break; ++ } ++ case (FM_SET_SIZE_OF_FIFO): ++ { ++ t_FmIpcPortRsrcParams ipcPortRsrcParams; ++ ++ memcpy((uint8_t*)&ipcPortRsrcParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortRsrcParams)); ++ p_IpcReply->error = (uint32_t)FmSetSizeOfFifo(h_Fm, ++ ipcPortRsrcParams.hardwarePortId, ++ &ipcPortRsrcParams.val, ++ &ipcPortRsrcParams.extra, ++ (bool)ipcPortRsrcParams.boolInitialConfig); ++ *p_ReplyLength = sizeof(uint32_t); ++ break; ++ } ++ case (FM_SET_NUM_OF_TASKS): ++ { ++ t_FmIpcPortRsrcParams ipcPortRsrcParams; ++ ++ memcpy((uint8_t*)&ipcPortRsrcParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortRsrcParams)); ++ p_IpcReply->error = (uint32_t)FmSetNumOfTasks(h_Fm, ipcPortRsrcParams.hardwarePortId, ++ (uint8_t*)&ipcPortRsrcParams.val, ++ (uint8_t*)&ipcPortRsrcParams.extra, ++ (bool)ipcPortRsrcParams.boolInitialConfig); ++ *p_ReplyLength = sizeof(uint32_t); ++ break; ++ } ++ case (FM_SET_NUM_OF_OPEN_DMAS): ++ { ++ t_FmIpcPortRsrcParams ipcPortRsrcParams; ++ ++ memcpy((uint8_t*)&ipcPortRsrcParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortRsrcParams)); ++ p_IpcReply->error = (uint32_t)FmSetNumOfOpenDmas(h_Fm, ipcPortRsrcParams.hardwarePortId, ++ (uint8_t*)&ipcPortRsrcParams.val, ++ (uint8_t*)&ipcPortRsrcParams.extra, ++ (bool)ipcPortRsrcParams.boolInitialConfig); ++ *p_ReplyLength = sizeof(uint32_t); ++ break; ++ } ++ case (FM_RESUME_STALLED_PORT): ++ *p_ReplyLength = sizeof(uint32_t); ++ p_IpcReply->error = (uint32_t)FmResumeStalledPort(h_Fm, p_IpcMsg->msgBody[0]); ++ break; ++ case (FM_MASTER_IS_ALIVE): ++ { ++ uint8_t guestId = p_IpcMsg->msgBody[0]; ++ /* build the FM master partition IPC address */ ++ memset(p_Fm->fmIpcHandlerModuleName[guestId], 0, (sizeof(char)) * MODULE_NAME_SIZE); ++ if (Sprint (p_Fm->fmIpcHandlerModuleName[guestId], "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, guestId) != (guestId<10 ? 6:7)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); ++ p_Fm->h_IpcSessions[guestId] = XX_IpcInitSession(p_Fm->fmIpcHandlerModuleName[guestId], p_Fm->fmModuleName); ++ if (p_Fm->h_IpcSessions[guestId] == NULL) ++ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("FM Master IPC session for guest %d", guestId)); ++ *(uint8_t*)(p_IpcReply->replyBody) = 1; ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); ++ break; ++ } ++ case (FM_IS_PORT_STALLED): ++ { ++ bool tmp; ++ ++ p_IpcReply->error = (uint32_t)FmIsPortStalled(h_Fm, p_IpcMsg->msgBody[0], &tmp); ++ *(uint8_t*)(p_IpcReply->replyBody) = (uint8_t)tmp; ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); ++ break; ++ } ++ case (FM_RESET_MAC): ++ { ++ t_FmIpcMacParams ipcMacParams; ++ ++ memcpy((uint8_t*)&ipcMacParams, p_IpcMsg->msgBody, sizeof(t_FmIpcMacParams)); ++ p_IpcReply->error = (uint32_t)FmResetMac(p_Fm, ++ (e_FmMacType)(ipcMacParams.enumType), ++ ipcMacParams.id); ++ *p_ReplyLength = sizeof(uint32_t); ++ break; ++ } ++ case (FM_SET_MAC_MAX_FRAME): ++ { ++ t_FmIpcMacMaxFrameParams ipcMacMaxFrameParams; ++ ++ memcpy((uint8_t*)&ipcMacMaxFrameParams, p_IpcMsg->msgBody, sizeof(t_FmIpcMacMaxFrameParams)); ++ err = FmSetMacMaxFrame(p_Fm, ++ (e_FmMacType)(ipcMacMaxFrameParams.macParams.enumType), ++ ipcMacMaxFrameParams.macParams.id, ++ ipcMacMaxFrameParams.maxFrameLength); ++ if (err != E_OK) ++ REPORT_ERROR(MINOR, err, NO_MSG); ++ break; ++ } ++#if (DPAA_VERSION >= 11) ++ case (FM_VSP_ALLOC) : ++ { ++ t_FmIpcResourceAllocParams ipcAllocParams; ++ uint8_t vspBase; ++ memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams)); ++ vspBase = AllocVSPsForPartition(h_Fm, (uint8_t)ipcAllocParams.base, (uint8_t)ipcAllocParams.num, ipcAllocParams.guestId); ++ memcpy(p_IpcReply->replyBody, (uint8_t*)&vspBase, sizeof(uint8_t)); ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); ++ break; ++ } ++ case (FM_VSP_FREE) : ++ { ++ t_FmIpcResourceAllocParams ipcAllocParams; ++ memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams)); ++ FreeVSPsForPartition(h_Fm, (uint8_t)ipcAllocParams.base, (uint8_t)ipcAllocParams.num, ipcAllocParams.guestId); ++ break; ++ } ++ case (FM_VSP_SET_PORT_WINDOW) : ++ { ++ t_FmIpcVspSetPortWindow ipcVspSetPortWindow; ++ memcpy(&ipcVspSetPortWindow, p_IpcMsg->msgBody, sizeof(t_FmIpcVspSetPortWindow)); ++ err = SetVSPWindow(h_Fm, ++ ipcVspSetPortWindow.hardwarePortId, ++ ipcVspSetPortWindow.baseStorageProfile, ++ ipcVspSetPortWindow.log2NumOfProfiles); ++ return err; ++ } ++ case (FM_SET_CONG_GRP_PFC_PRIO) : ++ { ++ t_FmIpcSetCongestionGroupPfcPriority fmIpcSetCongestionGroupPfcPriority; ++ memcpy(&fmIpcSetCongestionGroupPfcPriority, p_IpcMsg->msgBody, sizeof(t_FmIpcSetCongestionGroupPfcPriority)); ++ err = FmSetCongestionGroupPFCpriority(h_Fm, ++ fmIpcSetCongestionGroupPfcPriority.congestionGroupId, ++ fmIpcSetCongestionGroupPfcPriority.priorityBitMap); ++ return err; ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ case (FM_FREE_PORT): ++ { ++ t_FmInterModulePortFreeParams portParams; ++ t_FmIpcPortFreeParams ipcPortParams; ++ ++ memcpy((uint8_t*)&ipcPortParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortFreeParams)); ++ portParams.hardwarePortId = ipcPortParams.hardwarePortId; ++ portParams.portType = (e_FmPortType)(ipcPortParams.enumPortType); ++ portParams.deqPipelineDepth = ipcPortParams.deqPipelineDepth; ++ FmFreePortParams(h_Fm, &portParams); ++ break; ++ } ++ case (FM_REGISTER_INTR): ++ { ++ t_FmIpcRegisterIntr ipcRegIntr; ++ ++ memcpy((uint8_t*)&ipcRegIntr, p_IpcMsg->msgBody, sizeof(ipcRegIntr)); ++ p_Fm->intrMng[ipcRegIntr.event].guestId = ipcRegIntr.guestId; ++ break; ++ } ++ case (FM_GET_PARAMS): ++ { ++ t_FmIpcParams ipcParams; ++ ++ /* Get clock frequency */ ++ ipcParams.fmClkFreq = p_Fm->p_FmStateStruct->fmClkFreq; ++ ipcParams.fmMacClkFreq = p_Fm->p_FmStateStruct->fmMacClkFreq; ++ ++ fman_get_revision(p_Fm->p_FmFpmRegs,&ipcParams.majorRev,&ipcParams.minorRev); ++ ++ memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcParams, sizeof(t_FmIpcParams)); ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcParams); ++ break; ++ } ++ case (FM_GET_FMAN_CTRL_CODE_REV): ++ { ++ t_FmCtrlCodeRevisionInfo fmanCtrlRevInfo; ++ t_FmIpcFmanCtrlCodeRevisionInfo ipcRevInfo; ++ ++ p_IpcReply->error = (uint32_t)FM_GetFmanCtrlCodeRevision(h_Fm, &fmanCtrlRevInfo); ++ ipcRevInfo.packageRev = fmanCtrlRevInfo.packageRev; ++ ipcRevInfo.majorRev = fmanCtrlRevInfo.majorRev; ++ ipcRevInfo.minorRev = fmanCtrlRevInfo.minorRev; ++ memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcRevInfo, sizeof(t_FmIpcFmanCtrlCodeRevisionInfo)); ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcFmanCtrlCodeRevisionInfo); ++ break; ++ } ++ ++ case (FM_DMA_STAT): ++ { ++ t_FmDmaStatus dmaStatus; ++ t_FmIpcDmaStatus ipcDmaStatus; ++ ++ FM_GetDmaStatus(h_Fm, &dmaStatus); ++ ipcDmaStatus.boolCmqNotEmpty = (uint8_t)dmaStatus.cmqNotEmpty; ++ ipcDmaStatus.boolBusError = (uint8_t)dmaStatus.busError; ++ ipcDmaStatus.boolReadBufEccError = (uint8_t)dmaStatus.readBufEccError; ++ ipcDmaStatus.boolWriteBufEccSysError = (uint8_t)dmaStatus.writeBufEccSysError; ++ ipcDmaStatus.boolWriteBufEccFmError = (uint8_t)dmaStatus.writeBufEccFmError; ++ ipcDmaStatus.boolSinglePortEccError = (uint8_t)dmaStatus.singlePortEccError; ++ memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcDmaStatus, sizeof(t_FmIpcDmaStatus)); ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcDmaStatus); ++ break; ++ } ++ case (FM_ALLOC_FMAN_CTRL_EVENT_REG): ++ p_IpcReply->error = (uint32_t)FmAllocFmanCtrlEventReg(h_Fm, (uint8_t*)p_IpcReply->replyBody); ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); ++ break; ++ case (FM_FREE_FMAN_CTRL_EVENT_REG): ++ FmFreeFmanCtrlEventReg(h_Fm, p_IpcMsg->msgBody[0]); ++ break; ++ case (FM_GET_TIMESTAMP_SCALE): ++ { ++ uint32_t timeStamp = FmGetTimeStampScale(h_Fm); ++ ++ memcpy(p_IpcReply->replyBody, (uint8_t*)&timeStamp, sizeof(uint32_t)); ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t); ++ break; ++ } ++ case (FM_GET_COUNTER): ++ { ++ e_FmCounters inCounter; ++ uint32_t outCounter; ++ ++ memcpy((uint8_t*)&inCounter, p_IpcMsg->msgBody, sizeof(uint32_t)); ++ outCounter = FM_GetCounter(h_Fm, inCounter); ++ memcpy(p_IpcReply->replyBody, (uint8_t*)&outCounter, sizeof(uint32_t)); ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t); ++ break; ++ } ++ case (FM_SET_FMAN_CTRL_EVENTS_ENABLE): ++ { ++ t_FmIpcFmanEvents ipcFmanEvents; ++ ++ memcpy((uint8_t*)&ipcFmanEvents, p_IpcMsg->msgBody, sizeof(t_FmIpcFmanEvents)); ++ FmSetFmanCtrlIntr(h_Fm, ++ ipcFmanEvents.eventRegId, ++ ipcFmanEvents.enableEvents); ++ break; ++ } ++ case (FM_GET_FMAN_CTRL_EVENTS_ENABLE): ++ { ++ uint32_t tmp = FmGetFmanCtrlIntr(h_Fm, p_IpcMsg->msgBody[0]); ++ ++ memcpy(p_IpcReply->replyBody, (uint8_t*)&tmp, sizeof(uint32_t)); ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t); ++ break; ++ } ++ case (FM_GET_PHYS_MURAM_BASE): ++ { ++ t_FmPhysAddr physAddr; ++ t_FmIpcPhysAddr ipcPhysAddr; ++ ++ FmGetPhysicalMuramBase(h_Fm, &physAddr); ++ ipcPhysAddr.high = physAddr.high; ++ ipcPhysAddr.low = physAddr.low; ++ memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcPhysAddr, sizeof(t_FmIpcPhysAddr)); ++ *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcPhysAddr); ++ break; ++ } ++ case (FM_ENABLE_RAM_ECC): ++ { ++ if (((err = FM_EnableRamsEcc(h_Fm)) != E_OK) || ++ ((err = FM_SetException(h_Fm, e_FM_EX_IRAM_ECC, TRUE)) != E_OK) || ++ ((err = FM_SetException(h_Fm, e_FM_EX_MURAM_ECC, TRUE)) != E_OK)) ++#if (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0)) ++ UNUSED(err); ++#else ++ REPORT_ERROR(MINOR, err, NO_MSG); ++#endif /* (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0)) */ ++ break; ++ } ++ case (FM_DISABLE_RAM_ECC): ++ { ++ ++ if (((err = FM_SetException(h_Fm, e_FM_EX_IRAM_ECC, FALSE)) != E_OK) || ++ ((err = FM_SetException(h_Fm, e_FM_EX_MURAM_ECC, FALSE)) != E_OK) || ++ ((err = FM_DisableRamsEcc(h_Fm)) != E_OK)) ++#if (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0)) ++ UNUSED(err); ++#else ++ REPORT_ERROR(MINOR, err, NO_MSG); ++#endif /* (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0)) */ ++ break; ++ } ++ case (FM_SET_NUM_OF_FMAN_CTRL): ++ { ++ t_FmIpcPortNumOfFmanCtrls ipcPortNumOfFmanCtrls; ++ ++ memcpy((uint8_t*)&ipcPortNumOfFmanCtrls, p_IpcMsg->msgBody, sizeof(t_FmIpcPortNumOfFmanCtrls)); ++ err = FmSetNumOfRiscsPerPort(h_Fm, ++ ipcPortNumOfFmanCtrls.hardwarePortId, ++ ipcPortNumOfFmanCtrls.numOfFmanCtrls, ++ ipcPortNumOfFmanCtrls.orFmanCtrl); ++ if (err != E_OK) ++ REPORT_ERROR(MINOR, err, NO_MSG); ++ break; ++ } ++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 ++ case (FM_10G_TX_ECC_WA): ++ p_IpcReply->error = (uint32_t)Fm10GTxEccWorkaround(h_Fm, p_IpcMsg->msgBody[0]); ++ *p_ReplyLength = sizeof(uint32_t); ++ break; ++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ ++ default: ++ *p_ReplyLength = 0; ++ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("command not found!!!")); ++ } ++ return E_OK; ++} ++ ++ ++/****************************************/ ++/* Inter-Module functions */ ++/****************************************/ ++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 ++t_Error Fm10GTxEccWorkaround(t_Handle h_Fm, uint8_t macId) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ t_Error err = E_OK; ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ uint32_t replyLength; ++ uint8_t rxHardwarePortId, txHardwarePortId; ++ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; ++ ++ if (p_Fm->guestId != NCSW_MASTER_ID) ++ { ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_10G_TX_ECC_WA; ++ msg.msgBody[0] = macId; ++ replyLength = sizeof(uint32_t); ++ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId)+sizeof(macId), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ if (replyLength != sizeof(uint32_t)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ return (t_Error)(reply.error); ++ } ++ ++ SANITY_CHECK_RETURN_ERROR((macId == 0), E_NOT_SUPPORTED); ++ SANITY_CHECK_RETURN_ERROR(IsFmanCtrlCodeLoaded(p_Fm), E_INVALID_STATE); ++ ++ rxHardwarePortId = SwPortIdToHwPortId(e_FM_PORT_TYPE_RX_10G, ++ macId, ++ p_Fm->p_FmStateStruct->revInfo.majorRev, ++ p_Fm->p_FmStateStruct->revInfo.minorRev); ++ txHardwarePortId = SwPortIdToHwPortId(e_FM_PORT_TYPE_TX_10G, ++ macId, ++ p_Fm->p_FmStateStruct->revInfo.majorRev, ++ p_Fm->p_FmStateStruct->revInfo.minorRev); ++ if ((p_Fm->p_FmStateStruct->portsTypes[rxHardwarePortId] != e_FM_PORT_TYPE_DUMMY) || ++ (p_Fm->p_FmStateStruct->portsTypes[txHardwarePortId] != e_FM_PORT_TYPE_DUMMY)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("MAC should be initialized prior to Rx and Tx ports!")); ++ ++ return fman_set_erratum_10gmac_a004_wa(fpm_rg); ++} ++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ ++ ++uint16_t FmGetTnumAgingPeriod(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm *)h_Fm; ++ ++ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0); ++ SANITY_CHECK_RETURN_VALUE(!p_Fm->p_FmDriverParam, E_INVALID_STATE, 0); ++ ++ return p_Fm->tnumAgingPeriod; ++} ++ ++t_Error FmSetPortPreFetchConfiguration(t_Handle h_Fm, ++ uint8_t portNum, ++ bool preFetchConfigured) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); ++ ++ p_Fm->portsPreFetchConfigured[portNum] = TRUE; ++ p_Fm->portsPreFetchValue[portNum] = preFetchConfigured; ++ ++ return E_OK; ++} ++ ++t_Error FmGetPortPreFetchConfiguration(t_Handle h_Fm, ++ uint8_t portNum, ++ bool *p_PortConfigured, ++ bool *p_PreFetchConfigured) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); ++ ++ /* If the prefetch wasn't configured yet (not enable or disabled) ++ we return the value TRUE as it was already configured */ ++ if (!p_Fm->portsPreFetchConfigured[portNum]) ++ { ++ *p_PortConfigured = FALSE; ++ *p_PreFetchConfigured = FALSE; ++ } ++ else ++ { ++ *p_PortConfigured = TRUE; ++ *p_PreFetchConfigured = (p_Fm->portsPreFetchConfigured[portNum]); ++ } ++ ++ return E_OK; ++} ++ ++t_Error FmSetCongestionGroupPFCpriority(t_Handle h_Fm, ++ uint32_t congestionGroupId, ++ uint8_t priorityBitMap) ++{ ++ t_Fm *p_Fm = (t_Fm *)h_Fm; ++ uint32_t regNum; ++ ++ ASSERT_COND(h_Fm); ++ ++ if (congestionGroupId > FM_PORT_NUM_OF_CONGESTION_GRPS) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("Congestion group ID bigger than %d", ++ FM_PORT_NUM_OF_CONGESTION_GRPS)); ++ ++ if (p_Fm->guestId == NCSW_MASTER_ID) ++ { ++ ASSERT_COND(p_Fm->baseAddr); ++ regNum = (FM_PORT_NUM_OF_CONGESTION_GRPS - 1 - congestionGroupId) / 4; ++ fman_set_congestion_group_pfc_priority((uint32_t *)((p_Fm->baseAddr+FM_MM_CGP)), ++ congestionGroupId, ++ priorityBitMap, ++ regNum); ++ } ++ else if (p_Fm->h_IpcSessions[0]) ++ { ++ t_Error err; ++ t_FmIpcMsg msg; ++ t_FmIpcSetCongestionGroupPfcPriority fmIpcSetCongestionGroupPfcPriority; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&fmIpcSetCongestionGroupPfcPriority, 0, sizeof(t_FmIpcSetCongestionGroupPfcPriority)); ++ fmIpcSetCongestionGroupPfcPriority.congestionGroupId = congestionGroupId; ++ fmIpcSetCongestionGroupPfcPriority.priorityBitMap = priorityBitMap; ++ ++ msg.msgId = FM_SET_CONG_GRP_PFC_PRIO; ++ memcpy(msg.msgBody, &fmIpcSetCongestionGroupPfcPriority, sizeof(t_FmIpcSetCongestionGroupPfcPriority)); ++ ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId), ++ NULL, ++ NULL, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("guest without IPC!")); ++ ++ return E_OK; ++} ++ ++uintptr_t FmGetPcdPrsBaseAddr(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0); ++ ++ if (!p_Fm->baseAddr) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ++ ("No base-addr; probably Guest with IPC!")); ++ return 0; ++ } ++ ++ return (p_Fm->baseAddr + FM_MM_PRS); ++} ++ ++uintptr_t FmGetPcdKgBaseAddr(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0); ++ ++ if (!p_Fm->baseAddr) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ++ ("No base-addr; probably Guest with IPC!")); ++ return 0; ++ } ++ ++ return (p_Fm->baseAddr + FM_MM_KG); ++} ++ ++uintptr_t FmGetPcdPlcrBaseAddr(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0); ++ ++ if (!p_Fm->baseAddr) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ++ ("No base-addr; probably Guest with IPC!")); ++ return 0; ++ } ++ ++ return (p_Fm->baseAddr + FM_MM_PLCR); ++} ++ ++#if (DPAA_VERSION >= 11) ++uintptr_t FmGetVSPBaseAddr(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0); ++ ++ return p_Fm->vspBaseAddr; ++} ++#endif /* (DPAA_VERSION >= 11) */ ++ ++t_Handle FmGetMuramHandle(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, NULL); ++ ++ return (p_Fm->h_FmMuram); ++} ++ ++void FmGetPhysicalMuramBase(t_Handle h_Fm, t_FmPhysAddr *p_FmPhysAddr) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ if (p_Fm->fmMuramPhysBaseAddr) ++ { ++ /* General FM driver initialization */ ++ p_FmPhysAddr->low = (uint32_t)p_Fm->fmMuramPhysBaseAddr; ++ p_FmPhysAddr->high = (uint8_t)((p_Fm->fmMuramPhysBaseAddr & 0x000000ff00000000LL) >> 32); ++ return; ++ } ++ ++ ASSERT_COND(p_Fm->guestId != NCSW_MASTER_ID); ++ ++ if (p_Fm->h_IpcSessions[0]) ++ { ++ t_Error err; ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ uint32_t replyLength; ++ t_FmIpcPhysAddr ipcPhysAddr; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_GET_PHYS_MURAM_BASE; ++ replyLength = sizeof(uint32_t) + sizeof(t_FmPhysAddr); ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ { ++ REPORT_ERROR(MINOR, err, NO_MSG); ++ return; ++ } ++ if (replyLength != (sizeof(uint32_t) + sizeof(t_FmPhysAddr))) ++ { ++ REPORT_ERROR(MINOR, E_INVALID_VALUE,("IPC reply length mismatch")); ++ return; ++ } ++ memcpy((uint8_t*)&ipcPhysAddr, reply.replyBody, sizeof(t_FmIpcPhysAddr)); ++ p_FmPhysAddr->high = ipcPhysAddr.high; ++ p_FmPhysAddr->low = ipcPhysAddr.low; ++ } ++ else ++ REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("running in guest-mode without neither IPC nor mapped register!")); ++} ++ ++#if (DPAA_VERSION >= 11) ++t_Error FmVSPAllocForPort (t_Handle h_Fm, ++ e_FmPortType portType, ++ uint8_t portId, ++ uint8_t numOfVSPs) ++{ ++ t_Fm *p_Fm = (t_Fm *)h_Fm; ++ t_Error err = E_OK; ++ uint32_t profilesFound, intFlags; ++ uint8_t first, i; ++ uint8_t log2Num; ++ uint8_t swPortIndex=0, hardwarePortId; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ ++ if (!numOfVSPs) ++ return E_OK; ++ ++ if (numOfVSPs > FM_VSP_MAX_NUM_OF_ENTRIES) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("numProfiles can not be bigger than %d.",FM_VSP_MAX_NUM_OF_ENTRIES)); ++ ++ if (!POWER_OF_2(numOfVSPs)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numProfiles must be a power of 2.")); ++ ++ LOG2((uint64_t)numOfVSPs, log2Num); ++ ++ if ((log2Num == 0) || (p_Fm->partVSPBase == 0)) ++ first = 0; ++ else ++ first = 1< (p_Fm->partVSPBase + p_Fm->partNumOfVSPs)) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("can not allocate storage profile port window")); ++ ++ if (first < p_Fm->partVSPBase) ++ while (first < p_Fm->partVSPBase) ++ first = first + numOfVSPs; ++ ++ if ((first + numOfVSPs) > (p_Fm->partVSPBase + p_Fm->partNumOfVSPs)) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("can not allocate storage profile port window")); ++ ++ intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock); ++ profilesFound = 0; ++ for (i=first; i < p_Fm->partVSPBase + p_Fm->partNumOfVSPs; ) ++ { ++ if (!p_Fm->p_FmSp->profiles[i].profilesMng.allocated) ++ { ++ profilesFound++; ++ i++; ++ if (profilesFound == numOfVSPs) ++ break; ++ } ++ else ++ { ++ profilesFound = 0; ++ /* advance i to the next aligned address */ ++ first = i = (uint8_t)(first + numOfVSPs); ++ } ++ } ++ if (profilesFound == numOfVSPs) ++ for (i = first; ip_FmSp->profiles[i].profilesMng.allocated = TRUE; ++ else ++ { ++ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); ++ RETURN_ERROR(MINOR, E_FULL, ("No profiles.")); ++ } ++ ++ hardwarePortId = SwPortIdToHwPortId(portType, ++ portId, ++ p_Fm->p_FmStateStruct->revInfo.majorRev, ++ p_Fm->p_FmStateStruct->revInfo.minorRev); ++ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); ++ ++ p_Fm->p_FmSp->portsMapping[swPortIndex].numOfProfiles = numOfVSPs; ++ p_Fm->p_FmSp->portsMapping[swPortIndex].profilesBase = first; ++ ++ if ((err = SetVSPWindow(h_Fm,hardwarePortId, first,log2Num)) != E_OK) ++ for (i = first; i < first + numOfVSPs; i++) ++ p_Fm->p_FmSp->profiles[i].profilesMng.allocated = FALSE; ++ ++ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); ++ ++ return err; ++} ++ ++t_Error FmVSPFreeForPort(t_Handle h_Fm, ++ e_FmPortType portType, ++ uint8_t portId) ++{ ++ t_Fm *p_Fm = (t_Fm *)h_Fm; ++ uint8_t swPortIndex=0, hardwarePortId, first, numOfVSPs, i; ++ uint32_t intFlags; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ ++ hardwarePortId = SwPortIdToHwPortId(portType, ++ portId, ++ p_Fm->p_FmStateStruct->revInfo.majorRev, ++ p_Fm->p_FmStateStruct->revInfo.minorRev); ++ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); ++ ++ numOfVSPs = (uint8_t)p_Fm->p_FmSp->portsMapping[swPortIndex].numOfProfiles; ++ first = (uint8_t)p_Fm->p_FmSp->portsMapping[swPortIndex].profilesBase; ++ ++ intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock); ++ for (i = first; i < first + numOfVSPs; i++) ++ p_Fm->p_FmSp->profiles[i].profilesMng.allocated = FALSE; ++ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); ++ ++ p_Fm->p_FmSp->portsMapping[swPortIndex].numOfProfiles = 0; ++ p_Fm->p_FmSp->portsMapping[swPortIndex].profilesBase = 0; ++ ++ return E_OK; ++} ++#endif /* (DPAA_VERSION >= 11) */ ++ ++t_Error FmAllocFmanCtrlEventReg(t_Handle h_Fm, uint8_t *p_EventId) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ uint8_t i; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ p_Fm->h_IpcSessions[0]) ++ { ++ t_Error err; ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ uint32_t replyLength; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_ALLOC_FMAN_CTRL_EVENT_REG; ++ replyLength = sizeof(uint32_t) + sizeof(uint8_t); ++ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ if (replyLength != (sizeof(uint32_t) + sizeof(uint8_t))) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ ++ *p_EventId = *(uint8_t*)(reply.replyBody); ++ ++ return (t_Error)(reply.error); ++ } ++ else if (p_Fm->guestId != NCSW_MASTER_ID) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("running in guest-mode without IPC!")); ++ ++ for (i=0;iusedEventRegs[i]) ++ { ++ p_Fm->usedEventRegs[i] = TRUE; ++ *p_EventId = i; ++ break; ++ } ++ ++ if (i==FM_NUM_OF_FMAN_CTRL_EVENT_REGS) ++ RETURN_ERROR(MAJOR, E_BUSY, ("No resource - FMan controller event register.")); ++ ++ return E_OK; ++} ++ ++void FmFreeFmanCtrlEventReg(t_Handle h_Fm, uint8_t eventId) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE); ++ ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ p_Fm->h_IpcSessions[0]) ++ { ++ t_Error err; ++ t_FmIpcMsg msg; ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.msgId = FM_FREE_FMAN_CTRL_EVENT_REG; ++ msg.msgBody[0] = eventId; ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId)+sizeof(eventId), ++ NULL, ++ NULL, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ REPORT_ERROR(MINOR, err, NO_MSG); ++ return; ++ } ++ else if (p_Fm->guestId != NCSW_MASTER_ID) ++ { ++ REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("running in guest-mode without IPC!")); ++ return; ++ } ++ ++ ((t_Fm*)h_Fm)->usedEventRegs[eventId] = FALSE; ++} ++ ++void FmSetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, uint32_t enableEvents) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; ++ ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ !p_Fm->p_FmFpmRegs && ++ p_Fm->h_IpcSessions[0]) ++ { ++ t_FmIpcFmanEvents fmanCtrl; ++ t_Error err; ++ t_FmIpcMsg msg; ++ ++ fmanCtrl.eventRegId = eventRegId; ++ fmanCtrl.enableEvents = enableEvents; ++ memset(&msg, 0, sizeof(msg)); ++ msg.msgId = FM_SET_FMAN_CTRL_EVENTS_ENABLE; ++ memcpy(msg.msgBody, &fmanCtrl, sizeof(fmanCtrl)); ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId)+sizeof(fmanCtrl), ++ NULL, ++ NULL, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ REPORT_ERROR(MINOR, err, NO_MSG); ++ return; ++ } ++ else if (!p_Fm->p_FmFpmRegs) ++ { ++ REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("Either IPC or 'baseAddress' is required!")); ++ return; ++ } ++ ++ ASSERT_COND(eventRegId < FM_NUM_OF_FMAN_CTRL_EVENT_REGS); ++ fman_set_ctrl_intr(fpm_rg, eventRegId, enableEvents); ++} ++ ++uint32_t FmGetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; ++ ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ !p_Fm->p_FmFpmRegs && ++ p_Fm->h_IpcSessions[0]) ++ { ++ t_Error err; ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ uint32_t replyLength, ctrlIntr; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_GET_FMAN_CTRL_EVENTS_ENABLE; ++ msg.msgBody[0] = eventRegId; ++ replyLength = sizeof(uint32_t) + sizeof(uint32_t); ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId)+sizeof(eventRegId), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ { ++ REPORT_ERROR(MINOR, err, NO_MSG); ++ return 0; ++ } ++ if (replyLength != (sizeof(uint32_t) + sizeof(uint32_t))) ++ { ++ REPORT_ERROR(MINOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ return 0; ++ } ++ memcpy((uint8_t*)&ctrlIntr, reply.replyBody, sizeof(uint32_t)); ++ return ctrlIntr; ++ } ++ else if (!p_Fm->p_FmFpmRegs) ++ { ++ REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("Either IPC or 'baseAddress' is required!")); ++ return 0; ++ } ++ ++ return fman_get_ctrl_intr(fpm_rg, eventRegId); ++} ++ ++void FmRegisterIntr(t_Handle h_Fm, ++ e_FmEventModules module, ++ uint8_t modId, ++ e_FmIntrType intrType, ++ void (*f_Isr) (t_Handle h_Arg), ++ t_Handle h_Arg) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ int event = 0; ++ ++ ASSERT_COND(h_Fm); ++ ++ GET_FM_MODULE_EVENT(module, modId, intrType, event); ++ ASSERT_COND(event < e_FM_EV_DUMMY_LAST); ++ ++ /* register in local FM structure */ ++ p_Fm->intrMng[event].f_Isr = f_Isr; ++ p_Fm->intrMng[event].h_SrcHandle = h_Arg; ++ ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ p_Fm->h_IpcSessions[0]) ++ { ++ t_FmIpcRegisterIntr fmIpcRegisterIntr; ++ t_Error err; ++ t_FmIpcMsg msg; ++ ++ /* register in Master FM structure */ ++ fmIpcRegisterIntr.event = (uint32_t)event; ++ fmIpcRegisterIntr.guestId = p_Fm->guestId; ++ memset(&msg, 0, sizeof(msg)); ++ msg.msgId = FM_REGISTER_INTR; ++ memcpy(msg.msgBody, &fmIpcRegisterIntr, sizeof(fmIpcRegisterIntr)); ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) + sizeof(fmIpcRegisterIntr), ++ NULL, ++ NULL, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ REPORT_ERROR(MINOR, err, NO_MSG); ++ } ++ else if (p_Fm->guestId != NCSW_MASTER_ID) ++ REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("running in guest-mode without IPC!")); ++} ++ ++void FmUnregisterIntr(t_Handle h_Fm, ++ e_FmEventModules module, ++ uint8_t modId, ++ e_FmIntrType intrType) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ int event = 0; ++ ++ ASSERT_COND(h_Fm); ++ ++ GET_FM_MODULE_EVENT(module, modId,intrType, event); ++ ASSERT_COND(event < e_FM_EV_DUMMY_LAST); ++ ++ p_Fm->intrMng[event].f_Isr = UnimplementedIsr; ++ p_Fm->intrMng[event].h_SrcHandle = NULL; ++} ++ ++void FmRegisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, void (*f_Isr) (t_Handle h_Arg, uint32_t event), t_Handle h_Arg) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ ASSERT_COND(eventRegIdguestId != NCSW_MASTER_ID) ++ { ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM in guest-mode")); ++ return; ++ } ++ ++ p_Fm->fmanCtrlIntr[eventRegId].f_Isr = f_Isr; ++ p_Fm->fmanCtrlIntr[eventRegId].h_SrcHandle = h_Arg; ++} ++ ++void FmUnregisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ ASSERT_COND(eventRegIdguestId != NCSW_MASTER_ID) ++ { ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM in guest-mode")); ++ return; ++ } ++ ++ p_Fm->fmanCtrlIntr[eventRegId].f_Isr = UnimplementedFmanCtrlIsr; ++ p_Fm->fmanCtrlIntr[eventRegId].h_SrcHandle = NULL; ++} ++ ++void FmRegisterPcd(t_Handle h_Fm, t_Handle h_FmPcd) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ if (p_Fm->h_Pcd) ++ REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("PCD already set")); ++ ++ p_Fm->h_Pcd = h_FmPcd; ++} ++ ++void FmUnregisterPcd(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ if (!p_Fm->h_Pcd) ++ REPORT_ERROR(MAJOR, E_NOT_FOUND, ("PCD handle!")); ++ ++ p_Fm->h_Pcd = NULL; ++} ++ ++t_Handle FmGetPcdHandle(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ return p_Fm->h_Pcd; ++} ++ ++uint8_t FmGetId(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0xff); ++ ++ return p_Fm->p_FmStateStruct->fmId; ++} ++ ++t_Error FmReset(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ ++ WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rstc, FPM_RSTC_FM_RESET); ++ CORE_MemoryBarrier(); ++ XX_UDelay(100); ++ ++ return E_OK; ++} ++ ++t_Error FmSetNumOfRiscsPerPort(t_Handle h_Fm, ++ uint8_t hardwarePortId, ++ uint8_t numOfFmanCtrls, ++ t_FmFmanCtrl orFmanCtrl) ++{ ++ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ struct fman_fpm_regs *fpm_rg; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(((numOfFmanCtrls > 0) && (numOfFmanCtrls < 3)) , E_INVALID_HANDLE); ++ ++ fpm_rg = p_Fm->p_FmFpmRegs; ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ !p_Fm->p_FmFpmRegs && ++ p_Fm->h_IpcSessions[0]) ++ { ++ t_Error err; ++ t_FmIpcPortNumOfFmanCtrls params; ++ t_FmIpcMsg msg; ++ ++ memset(&msg, 0, sizeof(msg)); ++ params.hardwarePortId = hardwarePortId; ++ params.numOfFmanCtrls = numOfFmanCtrls; ++ params.orFmanCtrl = orFmanCtrl; ++ msg.msgId = FM_SET_NUM_OF_FMAN_CTRL; ++ memcpy(msg.msgBody, ¶ms, sizeof(params)); ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) +sizeof(params), ++ NULL, ++ NULL, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ return E_OK; ++ } ++ else if (!p_Fm->p_FmFpmRegs) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("Either IPC or 'baseAddress' is required!")); ++ ++ fman_set_num_of_riscs_per_port(fpm_rg, hardwarePortId, numOfFmanCtrls, orFmanCtrl); ++ ++ return E_OK; ++} ++ ++t_Error FmGetSetPortParams(t_Handle h_Fm, t_FmInterModulePortInitParams *p_PortParams) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ t_Error err; ++ uint32_t intFlags; ++ uint8_t hardwarePortId = p_PortParams->hardwarePortId, macId; ++ struct fman_rg fman_rg; ++ ++ fman_rg.bmi_rg = p_Fm->p_FmBmiRegs; ++ fman_rg.qmi_rg = p_Fm->p_FmQmiRegs; ++ fman_rg.fpm_rg = p_Fm->p_FmFpmRegs; ++ fman_rg.dma_rg = p_Fm->p_FmDmaRegs; ++ ++ if (p_Fm->guestId != NCSW_MASTER_ID) ++ { ++ t_FmIpcPortInInitParams portInParams; ++ t_FmIpcPortOutInitParams portOutParams; ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ uint32_t replyLength; ++ ++ portInParams.hardwarePortId = p_PortParams->hardwarePortId; ++ portInParams.enumPortType = (uint32_t)p_PortParams->portType; ++ portInParams.boolIndependentMode= (uint8_t)p_PortParams->independentMode; ++ portInParams.liodnOffset = p_PortParams->liodnOffset; ++ portInParams.numOfTasks = p_PortParams->numOfTasks; ++ portInParams.numOfExtraTasks = p_PortParams->numOfExtraTasks; ++ portInParams.numOfOpenDmas = p_PortParams->numOfOpenDmas; ++ portInParams.numOfExtraOpenDmas = p_PortParams->numOfExtraOpenDmas; ++ portInParams.sizeOfFifo = p_PortParams->sizeOfFifo; ++ portInParams.extraSizeOfFifo = p_PortParams->extraSizeOfFifo; ++ portInParams.deqPipelineDepth = p_PortParams->deqPipelineDepth; ++ portInParams.maxFrameLength = p_PortParams->maxFrameLength; ++ portInParams.liodnBase = p_PortParams->liodnBase; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_GET_SET_PORT_PARAMS; ++ memcpy(msg.msgBody, &portInParams, sizeof(portInParams)); ++ replyLength = (sizeof(uint32_t) + sizeof(t_FmIpcPortOutInitParams)); ++ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) +sizeof(portInParams), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ if (replyLength != (sizeof(uint32_t) + sizeof(t_FmIpcPortOutInitParams))) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ memcpy((uint8_t*)&portOutParams, reply.replyBody, sizeof(t_FmIpcPortOutInitParams)); ++ ++ p_PortParams->fmMuramPhysBaseAddr.high = portOutParams.ipcPhysAddr.high; ++ p_PortParams->fmMuramPhysBaseAddr.low = portOutParams.ipcPhysAddr.low; ++ p_PortParams->numOfTasks = portOutParams.numOfTasks; ++ p_PortParams->numOfExtraTasks = portOutParams.numOfExtraTasks; ++ p_PortParams->numOfOpenDmas = portOutParams.numOfOpenDmas; ++ p_PortParams->numOfExtraOpenDmas = portOutParams.numOfExtraOpenDmas; ++ p_PortParams->sizeOfFifo = portOutParams.sizeOfFifo; ++ p_PortParams->extraSizeOfFifo = portOutParams.extraSizeOfFifo; ++ ++ return (t_Error)(reply.error); ++ } ++ ++ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); ++ ++ intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock); ++ if (p_PortParams->independentMode) ++ { ++ /* set port parameters */ ++ p_Fm->independentMode = p_PortParams->independentMode; ++ /* disable dispatch limit */ ++ fman_qmi_disable_dispatch_limit(fman_rg.fpm_rg); ++ } ++ ++ if (p_PortParams->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) ++ { ++ if (p_Fm->hcPortInitialized) ++ { ++ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Only one host command port is allowed.")); ++ } ++ else ++ p_Fm->hcPortInitialized = TRUE; ++ } ++ p_Fm->p_FmStateStruct->portsTypes[hardwarePortId] = p_PortParams->portType; ++ ++ err = FmSetNumOfTasks(p_Fm, hardwarePortId, &p_PortParams->numOfTasks, &p_PortParams->numOfExtraTasks, TRUE); ++ if (err) ++ { ++ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT ++ if (p_Fm->p_FmStateStruct->revInfo.majorRev != 4) ++#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ ++ if ((p_PortParams->portType != e_FM_PORT_TYPE_RX) && ++ (p_PortParams->portType != e_FM_PORT_TYPE_RX_10G)) ++ /* for transmit & O/H ports */ ++ { ++ uint8_t enqTh; ++ uint8_t deqTh; ++ ++ /* update qmi ENQ/DEQ threshold */ ++ p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums += p_PortParams->deqPipelineDepth; ++ enqTh = fman_get_qmi_enq_th(fman_rg.qmi_rg); ++ /* if enqTh is too big, we reduce it to the max value that is still OK */ ++ if (enqTh >= (QMI_MAX_NUM_OF_TNUMS - p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums)) ++ { ++ enqTh = (uint8_t)(QMI_MAX_NUM_OF_TNUMS - p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums - 1); ++ fman_set_qmi_enq_th(fman_rg.qmi_rg, enqTh); ++ } ++ ++ deqTh = fman_get_qmi_deq_th(fman_rg.qmi_rg); ++ /* if deqTh is too small, we enlarge it to the min value that is still OK. ++ deqTh may not be larger than 63 (QMI_MAX_NUM_OF_TNUMS-1). */ ++ if ((deqTh <= p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums) && (deqTh < QMI_MAX_NUM_OF_TNUMS-1)) ++ { ++ deqTh = (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums + 1); ++ fman_set_qmi_deq_th(fman_rg.qmi_rg, deqTh); ++ } ++ } ++ ++#ifdef FM_LOW_END_RESTRICTION ++ if ((hardwarePortId==0x1) || (hardwarePortId==0x29)) ++ { ++ if (p_Fm->p_FmStateStruct->lowEndRestriction) ++ { ++ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); ++ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("OP #0 cannot work with Tx Port #1.")); ++ } ++ else ++ p_Fm->p_FmStateStruct->lowEndRestriction = TRUE; ++ } ++#endif /* FM_LOW_END_RESTRICTION */ ++ ++ err = FmSetSizeOfFifo(p_Fm, ++ hardwarePortId, ++ &p_PortParams->sizeOfFifo, ++ &p_PortParams->extraSizeOfFifo, ++ TRUE); ++ if (err) ++ { ++ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ err = FmSetNumOfOpenDmas(p_Fm, ++ hardwarePortId, ++ &p_PortParams->numOfOpenDmas, ++ &p_PortParams->numOfExtraOpenDmas, ++ TRUE); ++ if (err) ++ { ++ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ fman_set_liodn_per_port(&fman_rg, ++ hardwarePortId, ++ p_PortParams->liodnBase, ++ p_PortParams->liodnOffset); ++ ++ if (p_Fm->p_FmStateStruct->revInfo.majorRev < 6) ++ fman_set_order_restoration_per_port(fman_rg.fpm_rg, ++ hardwarePortId, ++ p_PortParams->independentMode, ++ !!((p_PortParams->portType==e_FM_PORT_TYPE_RX) || (p_PortParams->portType==e_FM_PORT_TYPE_RX_10G))); ++ ++ HW_PORT_ID_TO_SW_PORT_ID(macId, hardwarePortId); ++ ++#if defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS) ++ if ((p_PortParams->portType == e_FM_PORT_TYPE_TX_10G) || ++ (p_PortParams->portType == e_FM_PORT_TYPE_RX_10G)) ++ { ++ ASSERT_COND(macId < FM_MAX_NUM_OF_10G_MACS); ++ if (p_PortParams->maxFrameLength >= p_Fm->p_FmStateStruct->macMaxFrameLengths10G[macId]) ++ p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId] = p_PortParams->maxFrameLength; ++ else ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("Port maxFrameLength is smaller than MAC current MTU")); ++ } ++ else ++#endif /* defined(FM_MAX_NUM_OF_10G_MACS) && ... */ ++ if ((p_PortParams->portType == e_FM_PORT_TYPE_TX) || ++ (p_PortParams->portType == e_FM_PORT_TYPE_RX)) ++ { ++ ASSERT_COND(macId < FM_MAX_NUM_OF_1G_MACS); ++ if (p_PortParams->maxFrameLength >= p_Fm->p_FmStateStruct->macMaxFrameLengths1G[macId]) ++ p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId] = p_PortParams->maxFrameLength; ++ else ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("Port maxFrameLength is smaller than MAC current MTU")); ++ } ++ ++ FmGetPhysicalMuramBase(p_Fm, &p_PortParams->fmMuramPhysBaseAddr); ++ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); ++ ++ return E_OK; ++} ++ ++void FmFreePortParams(t_Handle h_Fm,t_FmInterModulePortFreeParams *p_PortParams) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ uint32_t intFlags; ++ uint8_t hardwarePortId = p_PortParams->hardwarePortId; ++ uint8_t numOfTasks, numOfDmas, macId; ++ uint16_t sizeOfFifo; ++ t_Error err; ++ t_FmIpcPortFreeParams portParams; ++ t_FmIpcMsg msg; ++ struct fman_qmi_regs *qmi_rg = p_Fm->p_FmQmiRegs; ++ struct fman_bmi_regs *bmi_rg = p_Fm->p_FmBmiRegs; ++ ++ if (p_Fm->guestId != NCSW_MASTER_ID) ++ { ++ portParams.hardwarePortId = p_PortParams->hardwarePortId; ++ portParams.enumPortType = (uint32_t)p_PortParams->portType; ++ portParams.deqPipelineDepth = p_PortParams->deqPipelineDepth; ++ memset(&msg, 0, sizeof(msg)); ++ msg.msgId = FM_FREE_PORT; ++ memcpy(msg.msgBody, &portParams, sizeof(portParams)); ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId)+sizeof(portParams), ++ NULL, ++ NULL, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ REPORT_ERROR(MINOR, err, NO_MSG); ++ return; ++ } ++ ++ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); ++ ++ intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock); ++ ++ if (p_PortParams->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) ++ { ++ ASSERT_COND(p_Fm->hcPortInitialized); ++ p_Fm->hcPortInitialized = FALSE; ++ } ++ ++ p_Fm->p_FmStateStruct->portsTypes[hardwarePortId] = e_FM_PORT_TYPE_DUMMY; ++ ++ /* free numOfTasks */ ++ numOfTasks = fman_get_num_of_tasks(bmi_rg, hardwarePortId); ++ ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfTasks >= numOfTasks); ++ p_Fm->p_FmStateStruct->accumulatedNumOfTasks -= numOfTasks; ++ ++ /* free numOfOpenDmas */ ++ numOfDmas = fman_get_num_of_dmas(bmi_rg, hardwarePortId); ++ ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas >= numOfDmas); ++ p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas -= numOfDmas; ++ ++#ifdef FM_HAS_TOTAL_DMAS ++ if (p_Fm->p_FmStateStruct->revInfo.majorRev < 6) ++ { ++ /* update total num of DMA's with committed number of open DMAS, and max uncommitted pool. */ ++ fman_set_num_of_open_dmas(bmi_rg, ++ hardwarePortId, ++ 1, ++ 0, ++ (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas + p_Fm->p_FmStateStruct->extraOpenDmasPoolSize)); ++ } ++#endif /* FM_HAS_TOTAL_DMAS */ ++ ++ /* free sizeOfFifo */ ++ sizeOfFifo = fman_get_size_of_fifo(bmi_rg, hardwarePortId); ++ ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedFifoSize >= (sizeOfFifo * BMI_FIFO_UNITS)); ++ p_Fm->p_FmStateStruct->accumulatedFifoSize -= (sizeOfFifo * BMI_FIFO_UNITS); ++ ++#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT ++ if (p_Fm->p_FmStateStruct->revInfo.majorRev != 4) ++#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ ++ if ((p_PortParams->portType != e_FM_PORT_TYPE_RX) && ++ (p_PortParams->portType != e_FM_PORT_TYPE_RX_10G)) ++ /* for transmit & O/H ports */ ++ { ++ uint8_t enqTh; ++ uint8_t deqTh; ++ ++ /* update qmi ENQ/DEQ threshold */ ++ p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums -= p_PortParams->deqPipelineDepth; ++ ++ /* p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums is now smaller, ++ so we can enlarge enqTh */ ++ enqTh = (uint8_t)(QMI_MAX_NUM_OF_TNUMS - p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums - 1); ++ ++ /* p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums is now smaller, ++ so we can reduce deqTh */ ++ deqTh = (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums + 1); ++ ++ fman_set_qmi_enq_th(qmi_rg, enqTh); ++ fman_set_qmi_deq_th(qmi_rg, deqTh); ++ } ++ ++ HW_PORT_ID_TO_SW_PORT_ID(macId, hardwarePortId); ++ ++#if defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS) ++ if ((p_PortParams->portType == e_FM_PORT_TYPE_TX_10G) || ++ (p_PortParams->portType == e_FM_PORT_TYPE_RX_10G)) ++ { ++ ASSERT_COND(macId < FM_MAX_NUM_OF_10G_MACS); ++ p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId] = 0; ++ } ++ else ++#endif /* defined(FM_MAX_NUM_OF_10G_MACS) && ... */ ++ if ((p_PortParams->portType == e_FM_PORT_TYPE_TX) || ++ (p_PortParams->portType == e_FM_PORT_TYPE_RX)) ++ { ++ ASSERT_COND(macId < FM_MAX_NUM_OF_1G_MACS); ++ p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId] = 0; ++ } ++ ++#ifdef FM_LOW_END_RESTRICTION ++ if ((hardwarePortId==0x1) || (hardwarePortId==0x29)) ++ p_Fm->p_FmStateStruct->lowEndRestriction = FALSE; ++#endif /* FM_LOW_END_RESTRICTION */ ++ XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); ++} ++ ++t_Error FmIsPortStalled(t_Handle h_Fm, uint8_t hardwarePortId, bool *p_IsStalled) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ t_Error err; ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ uint32_t replyLength; ++ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; ++ ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ !p_Fm->baseAddr && ++ p_Fm->h_IpcSessions[0]) ++ { ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_IS_PORT_STALLED; ++ msg.msgBody[0] = hardwarePortId; ++ replyLength = sizeof(uint32_t) + sizeof(uint8_t); ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId)+sizeof(hardwarePortId), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ if (replyLength != (sizeof(uint32_t) + sizeof(uint8_t))) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ ++ *p_IsStalled = (bool)!!(*(uint8_t*)(reply.replyBody)); ++ ++ return (t_Error)(reply.error); ++ } ++ else if (!p_Fm->baseAddr) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("Either IPC or 'baseAddress' is required!")); ++ ++ *p_IsStalled = fman_is_port_stalled(fpm_rg, hardwarePortId); ++ ++ return E_OK; ++} ++ ++t_Error FmResumeStalledPort(t_Handle h_Fm, uint8_t hardwarePortId) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ t_Error err; ++ bool isStalled; ++ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; ++ ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ !p_Fm->baseAddr && ++ p_Fm->h_IpcSessions[0]) ++ { ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ uint32_t replyLength; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_RESUME_STALLED_PORT; ++ msg.msgBody[0] = hardwarePortId; ++ replyLength = sizeof(uint32_t); ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) + sizeof(hardwarePortId), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ if (replyLength != sizeof(uint32_t)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ return (t_Error)(reply.error); ++ } ++ else if (!p_Fm->baseAddr) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("Either IPC or 'baseAddress' is required!")); ++ ++ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) ++ RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Not available for this FM revision!")); ++ ++ /* Get port status */ ++ err = FmIsPortStalled(h_Fm, hardwarePortId, &isStalled); ++ if (err) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't get port status")); ++ if (!isStalled) ++ return E_OK; ++ ++ fman_resume_stalled_port(fpm_rg, hardwarePortId); ++ ++ return E_OK; ++} ++ ++t_Error FmResetMac(t_Handle h_Fm, e_FmMacType type, uint8_t macId) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ t_Error err; ++ struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; ++ ++#if (DPAA_VERSION >= 11) ++ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("FMan MAC reset!")); ++#endif /*(DPAA_VERSION >= 11)*/ ++ ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ !p_Fm->baseAddr && ++ p_Fm->h_IpcSessions[0]) ++ { ++ t_FmIpcMacParams macParams; ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ uint32_t replyLength; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ macParams.id = macId; ++ macParams.enumType = (uint32_t)type; ++ msg.msgId = FM_RESET_MAC; ++ memcpy(msg.msgBody, &macParams, sizeof(macParams)); ++ replyLength = sizeof(uint32_t); ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId)+sizeof(macParams), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ if (replyLength != sizeof(uint32_t)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ return (t_Error)(reply.error); ++ } ++ else if (!p_Fm->baseAddr) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("Either IPC or 'baseAddress' is required!")); ++ ++ err = (t_Error)fman_reset_mac(fpm_rg, macId, !!(type == e_FM_MAC_10G)); ++ ++ if (err == -EBUSY) ++ return ERROR_CODE(E_TIMEOUT); ++ else if (err) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal MAC ID")); ++ ++ return E_OK; ++} ++ ++t_Error FmSetMacMaxFrame(t_Handle h_Fm, e_FmMacType type, uint8_t macId, uint16_t mtu) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ p_Fm->h_IpcSessions[0]) ++ { ++ t_FmIpcMacMaxFrameParams macMaxFrameLengthParams; ++ t_Error err; ++ t_FmIpcMsg msg; ++ ++ memset(&msg, 0, sizeof(msg)); ++ macMaxFrameLengthParams.macParams.id = macId; ++ macMaxFrameLengthParams.macParams.enumType = (uint32_t)type; ++ macMaxFrameLengthParams.maxFrameLength = (uint16_t)mtu; ++ msg.msgId = FM_SET_MAC_MAX_FRAME; ++ memcpy(msg.msgBody, &macMaxFrameLengthParams, sizeof(macMaxFrameLengthParams)); ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId)+sizeof(macMaxFrameLengthParams), ++ NULL, ++ NULL, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ return E_OK; ++ } ++ else if (p_Fm->guestId != NCSW_MASTER_ID) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("running in guest-mode without IPC!")); ++ ++ /* if port is already initialized, check that MaxFrameLength is smaller ++ * or equal to the port's max */ ++#if (defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS)) ++ if (type == e_FM_MAC_10G) ++ { ++ if ((!p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId]) ++ || (p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId] && ++ (mtu <= p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId]))) ++ p_Fm->p_FmStateStruct->macMaxFrameLengths10G[macId] = mtu; ++ else ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("MAC maxFrameLength is larger than Port maxFrameLength")); ++ ++ } ++ else ++#else ++ UNUSED(type); ++#endif /* (defined(FM_MAX_NUM_OF_10G_MACS) && ... */ ++ if ((!p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId]) ++ || (p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId] && ++ (mtu <= p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId]))) ++ p_Fm->p_FmStateStruct->macMaxFrameLengths1G[macId] = mtu; ++ else ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, ("MAC maxFrameLength is larger than Port maxFrameLength")); ++ ++ return E_OK; ++} ++ ++uint16_t FmGetClockFreq(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ /* for multicore environment: this depends on the ++ * fact that fmClkFreq was properly initialized at "init". */ ++ return p_Fm->p_FmStateStruct->fmClkFreq; ++} ++ ++uint16_t FmGetMacClockFreq(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ return p_Fm->p_FmStateStruct->fmMacClkFreq; ++} ++ ++uint32_t FmGetTimeStampScale(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ !p_Fm->baseAddr && ++ p_Fm->h_IpcSessions[0]) ++ { ++ t_Error err; ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ uint32_t replyLength, timeStamp; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_GET_TIMESTAMP_SCALE; ++ replyLength = sizeof(uint32_t) + sizeof(uint32_t); ++ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL)) != E_OK) ++ { ++ REPORT_ERROR(MAJOR, err, NO_MSG); ++ return 0; ++ } ++ if (replyLength != (sizeof(uint32_t) + sizeof(uint32_t))) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ return 0; ++ } ++ ++ memcpy((uint8_t*)&timeStamp, reply.replyBody, sizeof(uint32_t)); ++ return timeStamp; ++ } ++ else if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ p_Fm->baseAddr) ++ { ++ if (!(GET_UINT32(p_Fm->p_FmFpmRegs->fmfp_tsc1) & FPM_TS_CTL_EN)) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("timestamp is not enabled!")); ++ return 0; ++ } ++ } ++ else if (p_Fm->guestId != NCSW_MASTER_ID) ++ DBG(WARNING, ("No IPC - can't validate FM if timestamp enabled.")); ++ ++ return p_Fm->p_FmStateStruct->count1MicroBit; ++} ++ ++t_Error FmEnableRamsEcc(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ ++ p_Fm->p_FmStateStruct->ramsEccOwners++; ++ p_Fm->p_FmStateStruct->internalCall = TRUE; ++ ++ return FM_EnableRamsEcc(p_Fm); ++} ++ ++t_Error FmDisableRamsEcc(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ ++ ASSERT_COND(p_Fm->p_FmStateStruct->ramsEccOwners); ++ p_Fm->p_FmStateStruct->ramsEccOwners--; ++ ++ if (p_Fm->p_FmStateStruct->ramsEccOwners==0) ++ { ++ p_Fm->p_FmStateStruct->internalCall = TRUE; ++ return FM_DisableRamsEcc(p_Fm); ++ } ++ ++ return E_OK; ++} ++ ++uint8_t FmGetGuestId(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ return p_Fm->guestId; ++} ++ ++bool FmIsMaster(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ return (p_Fm->guestId == NCSW_MASTER_ID); ++} ++ ++t_Error FmSetSizeOfFifo(t_Handle h_Fm, ++ uint8_t hardwarePortId, ++ uint32_t *p_SizeOfFifo, ++ uint32_t *p_ExtraSizeOfFifo, ++ bool initialConfig) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ t_FmIpcPortRsrcParams rsrcParams; ++ t_Error err; ++ struct fman_bmi_regs *bmi_rg = p_Fm->p_FmBmiRegs; ++ uint32_t sizeOfFifo = *p_SizeOfFifo, extraSizeOfFifo = *p_ExtraSizeOfFifo; ++ uint16_t currentVal = 0, currentExtraVal = 0; ++ ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ !p_Fm->baseAddr && ++ p_Fm->h_IpcSessions[0]) ++ { ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ uint32_t replyLength; ++ ++ rsrcParams.hardwarePortId = hardwarePortId; ++ rsrcParams.val = sizeOfFifo; ++ rsrcParams.extra = extraSizeOfFifo; ++ rsrcParams.boolInitialConfig = (uint8_t)initialConfig; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_SET_SIZE_OF_FIFO; ++ memcpy(msg.msgBody, &rsrcParams, sizeof(rsrcParams)); ++ replyLength = sizeof(uint32_t); ++ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) + sizeof(rsrcParams), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ if (replyLength != sizeof(uint32_t)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ return (t_Error)(reply.error); ++ } ++ else if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ p_Fm->baseAddr) ++ { ++ DBG(WARNING, ("No IPC - can't validate FM total-fifo size.")); ++ fman_set_size_of_fifo(bmi_rg, hardwarePortId, sizeOfFifo, extraSizeOfFifo); ++ } ++ else if (p_Fm->guestId != NCSW_MASTER_ID) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ++ ("running in guest-mode without neither IPC nor mapped register!")); ++ ++ if (!initialConfig) ++ { ++ /* !initialConfig - runtime change of existing value. ++ * - read the current FIFO and extra FIFO size */ ++ currentExtraVal = fman_get_size_of_extra_fifo(bmi_rg, hardwarePortId); ++ currentVal = fman_get_size_of_fifo(bmi_rg, hardwarePortId); ++ } ++ ++ if (extraSizeOfFifo > currentExtraVal) ++ { ++ if (extraSizeOfFifo && !p_Fm->p_FmStateStruct->extraFifoPoolSize) ++ /* if this is the first time a port requires extraFifoPoolSize, the total extraFifoPoolSize ++ * must be initialized to 1 buffer per port ++ */ ++ p_Fm->p_FmStateStruct->extraFifoPoolSize = FM_MAX_NUM_OF_RX_PORTS*BMI_FIFO_UNITS; ++ ++ p_Fm->p_FmStateStruct->extraFifoPoolSize = MAX(p_Fm->p_FmStateStruct->extraFifoPoolSize, extraSizeOfFifo); ++ } ++ ++ /* check that there are enough uncommitted fifo size */ ++ if ((p_Fm->p_FmStateStruct->accumulatedFifoSize - currentVal + sizeOfFifo) > ++ (p_Fm->p_FmStateStruct->totalFifoSize - p_Fm->p_FmStateStruct->extraFifoPoolSize)){ ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ++ ("Port request fifo size + accumulated size > total FIFO size:")); ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ++ ("port 0x%x requested %d bytes, extra size = %d, accumulated size = %d total size = %d", ++ hardwarePortId, sizeOfFifo, p_Fm->p_FmStateStruct->extraFifoPoolSize, ++ p_Fm->p_FmStateStruct->accumulatedFifoSize, ++ p_Fm->p_FmStateStruct->totalFifoSize)); ++ } ++ else ++ { ++ /* update accumulated */ ++ ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedFifoSize >= currentVal); ++ p_Fm->p_FmStateStruct->accumulatedFifoSize -= currentVal; ++ p_Fm->p_FmStateStruct->accumulatedFifoSize += sizeOfFifo; ++ fman_set_size_of_fifo(bmi_rg, hardwarePortId, sizeOfFifo, extraSizeOfFifo); ++ } ++ ++ return E_OK; ++} ++ ++t_Error FmSetNumOfTasks(t_Handle h_Fm, ++ uint8_t hardwarePortId, ++ uint8_t *p_NumOfTasks, ++ uint8_t *p_NumOfExtraTasks, ++ bool initialConfig) ++{ ++ t_Fm *p_Fm = (t_Fm *)h_Fm; ++ t_Error err; ++ struct fman_bmi_regs *bmi_rg = p_Fm->p_FmBmiRegs; ++ uint8_t currentVal = 0, currentExtraVal = 0, numOfTasks = *p_NumOfTasks, numOfExtraTasks = *p_NumOfExtraTasks; ++ ++ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); ++ ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ !p_Fm->baseAddr && ++ p_Fm->h_IpcSessions[0]) ++ { ++ t_FmIpcPortRsrcParams rsrcParams; ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ uint32_t replyLength; ++ ++ rsrcParams.hardwarePortId = hardwarePortId; ++ rsrcParams.val = numOfTasks; ++ rsrcParams.extra = numOfExtraTasks; ++ rsrcParams.boolInitialConfig = (uint8_t)initialConfig; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_SET_NUM_OF_TASKS; ++ memcpy(msg.msgBody, &rsrcParams, sizeof(rsrcParams)); ++ replyLength = sizeof(uint32_t); ++ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) + sizeof(rsrcParams), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ if (replyLength != sizeof(uint32_t)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ return (t_Error)(reply.error); ++ } ++ else if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ p_Fm->baseAddr) ++ { ++ DBG(WARNING, ("No IPC - can't validate FM total-num-of-tasks.")); ++ fman_set_num_of_tasks(bmi_rg, hardwarePortId, numOfTasks, numOfExtraTasks); ++ } ++ else if (p_Fm->guestId != NCSW_MASTER_ID) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ++ ("running in guest-mode without neither IPC nor mapped register!")); ++ ++ if (!initialConfig) ++ { ++ /* !initialConfig - runtime change of existing value. ++ * - read the current number of tasks */ ++ currentVal = fman_get_num_of_tasks(bmi_rg, hardwarePortId); ++ currentExtraVal = fman_get_num_extra_tasks(bmi_rg, hardwarePortId); ++ } ++ ++ if (numOfExtraTasks > currentExtraVal) ++ p_Fm->p_FmStateStruct->extraTasksPoolSize = ++ (uint8_t)MAX(p_Fm->p_FmStateStruct->extraTasksPoolSize, numOfExtraTasks); ++ ++ /* check that there are enough uncommitted tasks */ ++ if ((p_Fm->p_FmStateStruct->accumulatedNumOfTasks - currentVal + numOfTasks) > ++ (p_Fm->p_FmStateStruct->totalNumOfTasks - p_Fm->p_FmStateStruct->extraTasksPoolSize)) ++ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ++ ("Requested numOfTasks and extra tasks pool for fm%d exceed total numOfTasks.", ++ p_Fm->p_FmStateStruct->fmId)); ++ else ++ { ++ ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfTasks >= currentVal); ++ /* update accumulated */ ++ p_Fm->p_FmStateStruct->accumulatedNumOfTasks -= currentVal; ++ p_Fm->p_FmStateStruct->accumulatedNumOfTasks += numOfTasks; ++ fman_set_num_of_tasks(bmi_rg, hardwarePortId, numOfTasks, numOfExtraTasks); ++ } ++ ++ return E_OK; ++} ++ ++t_Error FmSetNumOfOpenDmas(t_Handle h_Fm, ++ uint8_t hardwarePortId, ++ uint8_t *p_NumOfOpenDmas, ++ uint8_t *p_NumOfExtraOpenDmas, ++ bool initialConfig) ++ ++{ ++ t_Fm *p_Fm = (t_Fm *)h_Fm; ++ t_Error err; ++ struct fman_bmi_regs *bmi_rg = p_Fm->p_FmBmiRegs; ++ uint8_t numOfOpenDmas = *p_NumOfOpenDmas, numOfExtraOpenDmas = *p_NumOfExtraOpenDmas; ++ uint8_t totalNumDmas = 0, currentVal = 0, currentExtraVal = 0; ++ ++ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); ++ ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ !p_Fm->baseAddr && ++ p_Fm->h_IpcSessions[0]) ++ { ++ t_FmIpcPortRsrcParams rsrcParams; ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ uint32_t replyLength; ++ ++ rsrcParams.hardwarePortId = hardwarePortId; ++ rsrcParams.val = numOfOpenDmas; ++ rsrcParams.extra = numOfExtraOpenDmas; ++ rsrcParams.boolInitialConfig = (uint8_t)initialConfig; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_SET_NUM_OF_OPEN_DMAS; ++ memcpy(msg.msgBody, &rsrcParams, sizeof(rsrcParams)); ++ replyLength = sizeof(uint32_t); ++ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) + sizeof(rsrcParams), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ if (replyLength != sizeof(uint32_t)) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ return (t_Error)(reply.error); ++ } ++#ifdef FM_HAS_TOTAL_DMAS ++ else if (p_Fm->guestId != NCSW_MASTER_ID) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("running in guest-mode without IPC!")); ++#else ++ else if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ p_Fm->baseAddr && ++ (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)) ++ { ++ /*DBG(WARNING, ("No IPC - can't validate FM total-num-of-dmas."));*/ ++ ++ if (!numOfOpenDmas) ++ { ++ /* first config without explic it value: Do Nothing - reset value shouldn't be ++ changed, read register for port save */ ++ *p_NumOfOpenDmas = fman_get_num_of_dmas(bmi_rg, hardwarePortId); ++ *p_NumOfExtraOpenDmas = fman_get_num_extra_dmas(bmi_rg, hardwarePortId); ++ } ++ else ++ /* whether it is the first time with explicit value, or runtime "set" - write register */ ++ fman_set_num_of_open_dmas(bmi_rg, ++ hardwarePortId, ++ numOfOpenDmas, ++ numOfExtraOpenDmas, ++ p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas + p_Fm->p_FmStateStruct->extraOpenDmasPoolSize); ++ } ++ else if (p_Fm->guestId != NCSW_MASTER_ID) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ++ ("running in guest-mode without neither IPC nor mapped register!")); ++#endif /* FM_HAS_TOTAL_DMAS */ ++ ++ if (!initialConfig) ++ { ++ /* !initialConfig - runtime change of existing value. ++ * - read the current number of open Dma's */ ++ currentExtraVal = fman_get_num_extra_dmas(bmi_rg, hardwarePortId); ++ currentVal = fman_get_num_of_dmas(bmi_rg, hardwarePortId); ++ } ++ ++#ifdef FM_NO_GUARANTEED_RESET_VALUES ++ /* it's illegal to be in a state where this is not the first set and no value is specified */ ++ ASSERT_COND(initialConfig || numOfOpenDmas); ++ if (!numOfOpenDmas) ++ { ++ /* !numOfOpenDmas - first configuration according to values in regs. ++ * - read the current number of open Dma's */ ++ currentExtraVal = fman_get_num_extra_dmas(bmi_rg, hardwarePortId); ++ currentVal = fman_get_num_of_dmas(bmi_rg, hardwarePortId); ++ /* This is the first configuration and user did not specify value (!numOfOpenDmas), ++ * reset values will be used and we just save these values for resource management */ ++ p_Fm->p_FmStateStruct->extraOpenDmasPoolSize = ++ (uint8_t)MAX(p_Fm->p_FmStateStruct->extraOpenDmasPoolSize, currentExtraVal); ++ p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas += currentVal; ++ *p_NumOfOpenDmas = currentVal; ++ *p_NumOfExtraOpenDmas = currentExtraVal; ++ return E_OK; ++ } ++#endif /* FM_NO_GUARANTEED_RESET_VALUES */ ++ ++ if (numOfExtraOpenDmas > currentExtraVal) ++ p_Fm->p_FmStateStruct->extraOpenDmasPoolSize = ++ (uint8_t)MAX(p_Fm->p_FmStateStruct->extraOpenDmasPoolSize, numOfExtraOpenDmas); ++ ++#ifdef FM_HAS_TOTAL_DMAS ++ if ((p_Fm->p_FmStateStruct->revInfo.majorRev < 6) && ++ (p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas - currentVal + numOfOpenDmas > ++ p_Fm->p_FmStateStruct->maxNumOfOpenDmas)) ++ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ++ ("Requested numOfOpenDmas for fm%d exceeds total numOfOpenDmas.", ++ p_Fm->p_FmStateStruct->fmId)); ++#else ++ if ((p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) && ++#ifdef FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 ++ !((p_Fm->p_FmStateStruct->revInfo.majorRev == 6) && ++ (p_Fm->p_FmStateStruct->revInfo.minorRev == 0)) && ++#endif /* FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 */ ++ (p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas - currentVal + numOfOpenDmas > DMA_THRESH_MAX_COMMQ + 1)) ++ RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ++ ("Requested numOfOpenDmas for fm%d exceeds DMA Command queue (%d)", ++ p_Fm->p_FmStateStruct->fmId, DMA_THRESH_MAX_COMMQ+1)); ++#endif /* FM_HAS_TOTAL_DMAS */ ++ else ++ { ++ ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas >= currentVal); ++ /* update acummulated */ ++ p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas -= currentVal; ++ p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas += numOfOpenDmas; ++ ++#ifdef FM_HAS_TOTAL_DMAS ++ if (p_Fm->p_FmStateStruct->revInfo.majorRev < 6) ++ totalNumDmas = (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas + p_Fm->p_FmStateStruct->extraOpenDmasPoolSize); ++#endif /* FM_HAS_TOTAL_DMAS */ ++ fman_set_num_of_open_dmas(bmi_rg, ++ hardwarePortId, ++ numOfOpenDmas, ++ numOfExtraOpenDmas, ++ totalNumDmas); ++ } ++ ++ return E_OK; ++} ++ ++#if (DPAA_VERSION >= 11) ++t_Error FmVSPCheckRelativeProfile(t_Handle h_Fm, ++ e_FmPortType portType, ++ uint8_t portId, ++ uint16_t relativeProfile) ++{ ++ t_Fm *p_Fm; ++ t_FmSp *p_FmPcdSp; ++ uint8_t swPortIndex=0, hardwarePortId; ++ ++ ASSERT_COND(h_Fm); ++ p_Fm = (t_Fm*)h_Fm; ++ ++ hardwarePortId = SwPortIdToHwPortId(portType, ++ portId, ++ p_Fm->p_FmStateStruct->revInfo.majorRev, ++ p_Fm->p_FmStateStruct->revInfo.minorRev); ++ ASSERT_COND(hardwarePortId); ++ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); ++ ++ p_FmPcdSp = p_Fm->p_FmSp; ++ ASSERT_COND(p_FmPcdSp); ++ ++ if (!p_FmPcdSp->portsMapping[swPortIndex].numOfProfiles) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE , ("Port has no allocated profiles")); ++ if (relativeProfile >= p_FmPcdSp->portsMapping[swPortIndex].numOfProfiles) ++ RETURN_ERROR(MAJOR, E_NOT_IN_RANGE , ("Profile id is out of range")); ++ ++ return E_OK; ++} ++ ++t_Error FmVSPGetAbsoluteProfileId(t_Handle h_Fm, ++ e_FmPortType portType, ++ uint8_t portId, ++ uint16_t relativeProfile, ++ uint16_t *p_AbsoluteId) ++{ ++ t_Fm *p_Fm; ++ t_FmSp *p_FmPcdSp; ++ uint8_t swPortIndex=0, hardwarePortId; ++ t_Error err; ++ ++ ASSERT_COND(h_Fm); ++ p_Fm = (t_Fm*)h_Fm; ++ ++ err = FmVSPCheckRelativeProfile(h_Fm, portType, portId, relativeProfile); ++ if (err != E_OK) ++ return err; ++ ++ hardwarePortId = SwPortIdToHwPortId(portType, ++ portId, ++ p_Fm->p_FmStateStruct->revInfo.majorRev, ++ p_Fm->p_FmStateStruct->revInfo.minorRev); ++ ASSERT_COND(hardwarePortId); ++ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); ++ ++ p_FmPcdSp = p_Fm->p_FmSp; ++ ASSERT_COND(p_FmPcdSp); ++ ++ *p_AbsoluteId = (uint16_t)(p_FmPcdSp->portsMapping[swPortIndex].profilesBase + relativeProfile); ++ ++ return E_OK; ++} ++#endif /* (DPAA_VERSION >= 11) */ ++ ++static t_Error InitFmDma(t_Fm *p_Fm) ++{ ++ t_Error err; ++ ++ err = (t_Error)fman_dma_init(p_Fm->p_FmDmaRegs, p_Fm->p_FmDriverParam); ++ if (err != E_OK) ++ return err; ++ ++ /* Allocate MURAM for CAM */ ++ p_Fm->camBaseAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram, ++ (uint32_t)(p_Fm->p_FmDriverParam->dma_cam_num_of_entries*DMA_CAM_SIZEOF_ENTRY), ++ DMA_CAM_ALIGN)); ++ if (!p_Fm->camBaseAddr) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for DMA CAM failed")); ++ ++ WRITE_BLOCK(UINT_TO_PTR(p_Fm->camBaseAddr), ++ 0, ++ (uint32_t)(p_Fm->p_FmDriverParam->dma_cam_num_of_entries*DMA_CAM_SIZEOF_ENTRY)); ++ ++ if (p_Fm->p_FmStateStruct->revInfo.majorRev == 2) ++ { ++ FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->camBaseAddr)); ++ ++ p_Fm->camBaseAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram, ++ (uint32_t)(p_Fm->p_FmDriverParam->dma_cam_num_of_entries*72 + 128), ++ 64)); ++ if (!p_Fm->camBaseAddr) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for DMA CAM failed")); ++ ++ WRITE_BLOCK(UINT_TO_PTR(p_Fm->camBaseAddr), ++ 0, ++ (uint32_t)(p_Fm->p_FmDriverParam->dma_cam_num_of_entries*72 + 128)); ++ ++ switch(p_Fm->p_FmDriverParam->dma_cam_num_of_entries) ++ { ++ case (8): ++ WRITE_UINT32(*(uint32_t*)p_Fm->camBaseAddr, 0xff000000); ++ break; ++ case (16): ++ WRITE_UINT32(*(uint32_t*)p_Fm->camBaseAddr, 0xffff0000); ++ break; ++ case (24): ++ WRITE_UINT32(*(uint32_t*)p_Fm->camBaseAddr, 0xffffff00); ++ break; ++ case (32): ++ WRITE_UINT32(*(uint32_t*)p_Fm->camBaseAddr, 0xffffffff); ++ break; ++ default: ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("wrong dma_cam_num_of_entries")); ++ } ++ } ++ ++ p_Fm->p_FmDriverParam->cam_base_addr = ++ (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->camBaseAddr)) - p_Fm->fmMuramPhysBaseAddr); ++ ++ return E_OK; ++} ++ ++static t_Error InitFmFpm(t_Fm *p_Fm) ++{ ++ return (t_Error)fman_fpm_init(p_Fm->p_FmFpmRegs, p_Fm->p_FmDriverParam); ++} ++ ++static t_Error InitFmBmi(t_Fm *p_Fm) ++{ ++ return (t_Error)fman_bmi_init(p_Fm->p_FmBmiRegs, p_Fm->p_FmDriverParam); ++} ++ ++static t_Error InitFmQmi(t_Fm *p_Fm) ++{ ++ return (t_Error)fman_qmi_init(p_Fm->p_FmQmiRegs, p_Fm->p_FmDriverParam); ++} ++ ++static t_Error InitGuestMode(t_Fm *p_Fm) ++{ ++ t_Error err = E_OK; ++ int i; ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ uint32_t replyLength; ++ ++ ASSERT_COND(p_Fm); ++ ASSERT_COND(p_Fm->guestId != NCSW_MASTER_ID); ++ ++ /* build the FM guest partition IPC address */ ++ if (Sprint (p_Fm->fmModuleName, "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, p_Fm->guestId) != (p_Fm->guestId<10 ? 6:7)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); ++ ++ /* build the FM master partition IPC address */ ++ memset(p_Fm->fmIpcHandlerModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE); ++ if (Sprint (p_Fm->fmIpcHandlerModuleName[0], "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, NCSW_MASTER_ID) != 6) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); ++ ++ for (i=0;iintrMng[i].f_Isr = UnimplementedIsr; ++ ++ p_Fm->h_IpcSessions[0] = XX_IpcInitSession(p_Fm->fmIpcHandlerModuleName[0], p_Fm->fmModuleName); ++ if (p_Fm->h_IpcSessions[0]) ++ { ++ uint8_t isMasterAlive; ++ t_FmIpcParams ipcParams; ++ ++ err = XX_IpcRegisterMsgHandler(p_Fm->fmModuleName, FmGuestHandleIpcMsgCB, p_Fm, FM_IPC_MAX_REPLY_SIZE); ++ if (err) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_MASTER_IS_ALIVE; ++ msg.msgBody[0] = p_Fm->guestId; ++ replyLength = sizeof(uint32_t) + sizeof(uint8_t); ++ do ++ { ++ blockingFlag = TRUE; ++ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId)+sizeof(p_Fm->guestId), ++ (uint8_t*)&reply, ++ &replyLength, ++ IpcMsgCompletionCB, ++ p_Fm)) != E_OK) ++ REPORT_ERROR(MINOR, err, NO_MSG); ++ while (blockingFlag) ; ++ if (replyLength != (sizeof(uint32_t) + sizeof(uint8_t))) ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ isMasterAlive = *(uint8_t*)(reply.replyBody); ++ } while (!isMasterAlive); ++ ++ /* read FM parameters and save */ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_GET_PARAMS; ++ replyLength = sizeof(uint32_t) + sizeof(t_FmIpcParams); ++ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ if (replyLength != (sizeof(uint32_t) + sizeof(t_FmIpcParams))) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ memcpy((uint8_t*)&ipcParams, reply.replyBody, sizeof(t_FmIpcParams)); ++ ++ p_Fm->p_FmStateStruct->fmClkFreq = ipcParams.fmClkFreq; ++ p_Fm->p_FmStateStruct->fmMacClkFreq = ipcParams.fmMacClkFreq; ++ p_Fm->p_FmStateStruct->revInfo.majorRev = ipcParams.majorRev; ++ p_Fm->p_FmStateStruct->revInfo.minorRev = ipcParams.minorRev; ++ } ++ else ++ { ++ DBG(WARNING, ("FM Guest mode - without IPC")); ++ if (!p_Fm->p_FmStateStruct->fmClkFreq) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("No fmClkFreq configured for guest without IPC")); ++ if (p_Fm->baseAddr) ++ { ++ fman_get_revision(p_Fm->p_FmFpmRegs, ++ &p_Fm->p_FmStateStruct->revInfo.majorRev, ++ &p_Fm->p_FmStateStruct->revInfo.minorRev); ++ ++ } ++ } ++ ++#if (DPAA_VERSION >= 11) ++ p_Fm->partVSPBase = AllocVSPsForPartition(p_Fm, p_Fm->partVSPBase, p_Fm->partNumOfVSPs, p_Fm->guestId); ++ if (p_Fm->partVSPBase == (uint8_t)(ILLEGAL_BASE)) ++ DBG(WARNING, ("partition VSPs allocation is FAILED")); ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ /* General FM driver initialization */ ++ if (p_Fm->baseAddr) ++ p_Fm->fmMuramPhysBaseAddr = ++ (uint64_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->baseAddr + FM_MM_MURAM))); ++ ++ XX_Free(p_Fm->p_FmDriverParam); ++ p_Fm->p_FmDriverParam = NULL; ++ ++ if ((p_Fm->guestId == NCSW_MASTER_ID) || ++ (p_Fm->h_IpcSessions[0])) ++ { ++ FM_DisableRamsEcc(p_Fm); ++ FmMuramClear(p_Fm->h_FmMuram); ++ FM_EnableRamsEcc(p_Fm); ++ } ++ ++ return E_OK; ++} ++ ++static __inline__ enum fman_exceptions FmanExceptionTrans(e_FmExceptions exception) ++{ ++ switch (exception) { ++ case e_FM_EX_DMA_BUS_ERROR: ++ return E_FMAN_EX_DMA_BUS_ERROR; ++ case e_FM_EX_DMA_READ_ECC: ++ return E_FMAN_EX_DMA_READ_ECC; ++ case e_FM_EX_DMA_SYSTEM_WRITE_ECC: ++ return E_FMAN_EX_DMA_SYSTEM_WRITE_ECC; ++ case e_FM_EX_DMA_FM_WRITE_ECC: ++ return E_FMAN_EX_DMA_FM_WRITE_ECC; ++ case e_FM_EX_FPM_STALL_ON_TASKS: ++ return E_FMAN_EX_FPM_STALL_ON_TASKS; ++ case e_FM_EX_FPM_SINGLE_ECC: ++ return E_FMAN_EX_FPM_SINGLE_ECC; ++ case e_FM_EX_FPM_DOUBLE_ECC: ++ return E_FMAN_EX_FPM_DOUBLE_ECC; ++ case e_FM_EX_QMI_SINGLE_ECC: ++ return E_FMAN_EX_QMI_SINGLE_ECC; ++ case e_FM_EX_QMI_DOUBLE_ECC: ++ return E_FMAN_EX_QMI_DOUBLE_ECC; ++ case e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID: ++ return E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID; ++ case e_FM_EX_BMI_LIST_RAM_ECC: ++ return E_FMAN_EX_BMI_LIST_RAM_ECC; ++ case e_FM_EX_BMI_STORAGE_PROFILE_ECC: ++ return E_FMAN_EX_BMI_STORAGE_PROFILE_ECC; ++ case e_FM_EX_BMI_STATISTICS_RAM_ECC: ++ return E_FMAN_EX_BMI_STATISTICS_RAM_ECC; ++ case e_FM_EX_BMI_DISPATCH_RAM_ECC: ++ return E_FMAN_EX_BMI_DISPATCH_RAM_ECC; ++ case e_FM_EX_IRAM_ECC: ++ return E_FMAN_EX_IRAM_ECC; ++ case e_FM_EX_MURAM_ECC: ++ return E_FMAN_EX_MURAM_ECC; ++ default: ++ return E_FMAN_EX_DMA_BUS_ERROR; ++ } ++} ++ ++uint8_t SwPortIdToHwPortId(e_FmPortType type, uint8_t relativePortId, uint8_t majorRev, uint8_t minorRev) ++{ ++ switch (type) ++ { ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ case (e_FM_PORT_TYPE_OH_HOST_COMMAND): ++ CHECK_PORT_ID_OH_PORTS(relativePortId); ++ return (uint8_t)(BASE_OH_PORTID + (relativePortId)); ++ case (e_FM_PORT_TYPE_RX): ++ CHECK_PORT_ID_1G_RX_PORTS(relativePortId); ++ return (uint8_t)(BASE_1G_RX_PORTID + (relativePortId)); ++ case (e_FM_PORT_TYPE_RX_10G): ++ /* The 10G port in T1024 (FMan Version 6.4) is the first port. ++ * This is the reason why the 1G port offset is used. ++ */ ++ if (majorRev == 6 && minorRev == 4) ++ { ++ CHECK_PORT_ID_1G_RX_PORTS(relativePortId); ++ return (uint8_t)(BASE_1G_RX_PORTID + (relativePortId)); ++ } ++ else ++ { ++ CHECK_PORT_ID_10G_RX_PORTS(relativePortId); ++ return (uint8_t)(BASE_10G_RX_PORTID + (relativePortId)); ++ } ++ case (e_FM_PORT_TYPE_TX): ++ CHECK_PORT_ID_1G_TX_PORTS(relativePortId); ++ return (uint8_t)(BASE_1G_TX_PORTID + (relativePortId)); ++ case (e_FM_PORT_TYPE_TX_10G): ++ /* The 10G port in T1024 (FMan Version 6.4) is the first port. ++ * This is the reason why the 1G port offset is used. ++ */ ++ if (majorRev == 6 && minorRev == 4) ++ { ++ CHECK_PORT_ID_1G_TX_PORTS(relativePortId); ++ return (uint8_t)(BASE_1G_TX_PORTID + (relativePortId)); ++ } ++ else ++ { ++ CHECK_PORT_ID_10G_TX_PORTS(relativePortId); ++ return (uint8_t)(BASE_10G_TX_PORTID + (relativePortId)); ++ } ++ default: ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal port type")); ++ return 0; ++ } ++} ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++t_Error FmDumpPortRegs (t_Handle h_Fm, uint8_t hardwarePortId) ++{ ++ t_Fm *p_Fm = (t_Fm *)h_Fm; ++ ++ DECLARE_DUMP; ++ ++ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(((p_Fm->guestId == NCSW_MASTER_ID) || ++ p_Fm->baseAddr), E_INVALID_OPERATION); ++ ++ DUMP_TITLE(&p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1], ("fmbm_pp for port %u", (hardwarePortId))); ++ DUMP_MEMORY(&p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1], sizeof(uint32_t)); ++ ++ DUMP_TITLE(&p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId-1], ("fmbm_pfs for port %u", (hardwarePortId ))); ++ DUMP_MEMORY(&p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId-1], sizeof(uint32_t)); ++ ++ DUMP_TITLE(&p_Fm->p_FmBmiRegs->fmbm_spliodn[hardwarePortId-1], ("fmbm_spliodn for port %u", (hardwarePortId))); ++ DUMP_MEMORY(&p_Fm->p_FmBmiRegs->fmbm_spliodn[hardwarePortId-1], sizeof(uint32_t)); ++ ++ DUMP_TITLE(&p_Fm->p_FmFpmRegs->fmfp_ps[hardwarePortId], ("fmfp_ps for port %u", (hardwarePortId))); ++ DUMP_MEMORY(&p_Fm->p_FmFpmRegs->fmfp_ps[hardwarePortId], sizeof(uint32_t)); ++ ++ DUMP_TITLE(&p_Fm->p_FmDmaRegs->fmdmplr[hardwarePortId/2], ("fmdmplr for port %u", (hardwarePortId))); ++ DUMP_MEMORY(&p_Fm->p_FmDmaRegs->fmdmplr[hardwarePortId/2], sizeof(uint32_t)); ++ ++ return E_OK; ++} ++#endif /* (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) */ ++ ++ ++/*****************************************************************************/ ++/* API Init unit functions */ ++/*****************************************************************************/ ++t_Handle FM_Config(t_FmParams *p_FmParam) ++{ ++ t_Fm *p_Fm; ++ uint8_t i; ++ uintptr_t baseAddr; ++ ++ SANITY_CHECK_RETURN_VALUE(p_FmParam, E_NULL_POINTER, NULL); ++ SANITY_CHECK_RETURN_VALUE(((p_FmParam->firmware.p_Code && p_FmParam->firmware.size) || ++ (!p_FmParam->firmware.p_Code && !p_FmParam->firmware.size)), ++ E_INVALID_VALUE, NULL); ++ ++ baseAddr = p_FmParam->baseAddr; ++ ++ /* Allocate FM structure */ ++ p_Fm = (t_Fm *) XX_Malloc(sizeof(t_Fm)); ++ if (!p_Fm) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM driver structure")); ++ return NULL; ++ } ++ memset(p_Fm, 0, sizeof(t_Fm)); ++ ++ p_Fm->p_FmStateStruct = (t_FmStateStruct *) XX_Malloc(sizeof(t_FmStateStruct)); ++ if (!p_Fm->p_FmStateStruct) ++ { ++ XX_Free(p_Fm); ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Status structure")); ++ return NULL; ++ } ++ memset(p_Fm->p_FmStateStruct, 0, sizeof(t_FmStateStruct)); ++ ++ /* Initialize FM parameters which will be kept by the driver */ ++ p_Fm->p_FmStateStruct->fmId = p_FmParam->fmId; ++ p_Fm->guestId = p_FmParam->guestId; ++ ++ for (i=0; ip_FmStateStruct->portsTypes[i] = e_FM_PORT_TYPE_DUMMY; ++ ++ /* Allocate the FM driver's parameters structure */ ++ p_Fm->p_FmDriverParam = (struct fman_cfg *)XX_Malloc(sizeof(struct fman_cfg)); ++ if (!p_Fm->p_FmDriverParam) ++ { ++ XX_Free(p_Fm->p_FmStateStruct); ++ XX_Free(p_Fm); ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM driver parameters")); ++ return NULL; ++ } ++ memset(p_Fm->p_FmDriverParam, 0, sizeof(struct fman_cfg)); ++ ++#if (DPAA_VERSION >= 11) ++ p_Fm->p_FmSp = (t_FmSp *)XX_Malloc(sizeof(t_FmSp)); ++ if (!p_Fm->p_FmSp) ++ { ++ XX_Free(p_Fm->p_FmDriverParam); ++ XX_Free(p_Fm->p_FmStateStruct); ++ XX_Free(p_Fm); ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("allocation for internal data structure failed")); ++ return NULL; ++ } ++ memset(p_Fm->p_FmSp, 0, sizeof(t_FmSp)); ++ ++ for (i=0; ip_FmSp->profiles[i].profilesMng.ownerId = (uint8_t)ILLEGAL_BASE; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ /* Initialize FM parameters which will be kept by the driver */ ++ p_Fm->p_FmStateStruct->fmId = p_FmParam->fmId; ++ p_Fm->h_FmMuram = p_FmParam->h_FmMuram; ++ p_Fm->h_App = p_FmParam->h_App; ++ p_Fm->p_FmStateStruct->fmClkFreq = p_FmParam->fmClkFreq; ++ p_Fm->p_FmStateStruct->fmMacClkFreq = p_FmParam->fmClkFreq / ((!p_FmParam->fmMacClkRatio)? 2: p_FmParam->fmMacClkRatio); ++ p_Fm->f_Exception = p_FmParam->f_Exception; ++ p_Fm->f_BusError = p_FmParam->f_BusError; ++ p_Fm->p_FmFpmRegs = (struct fman_fpm_regs *)UINT_TO_PTR(baseAddr + FM_MM_FPM); ++ p_Fm->p_FmBmiRegs = (struct fman_bmi_regs *)UINT_TO_PTR(baseAddr + FM_MM_BMI); ++ p_Fm->p_FmQmiRegs = (struct fman_qmi_regs *)UINT_TO_PTR(baseAddr + FM_MM_QMI); ++ p_Fm->p_FmDmaRegs = (struct fman_dma_regs *)UINT_TO_PTR(baseAddr + FM_MM_DMA); ++ p_Fm->p_FmRegs = (struct fman_regs *)UINT_TO_PTR(baseAddr + FM_MM_BMI); ++ p_Fm->baseAddr = baseAddr; ++ p_Fm->p_FmStateStruct->irq = p_FmParam->irq; ++ p_Fm->p_FmStateStruct->errIrq = p_FmParam->errIrq; ++ p_Fm->hcPortInitialized = FALSE; ++ p_Fm->independentMode = FALSE; ++ ++ p_Fm->h_Spinlock = XX_InitSpinlock(); ++ if (!p_Fm->h_Spinlock) ++ { ++ XX_Free(p_Fm->p_FmDriverParam); ++ XX_Free(p_Fm->p_FmStateStruct); ++ XX_Free(p_Fm); ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("can't allocate spinlock!")); ++ return NULL; ++ } ++ ++#if (DPAA_VERSION >= 11) ++ p_Fm->partVSPBase = p_FmParam->partVSPBase; ++ p_Fm->partNumOfVSPs = p_FmParam->partNumOfVSPs; ++ p_Fm->vspBaseAddr = p_FmParam->vspBaseAddr; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ fman_defconfig(p_Fm->p_FmDriverParam, ++ !!(p_Fm->guestId == NCSW_MASTER_ID)); ++/* overide macros dependent parameters */ ++#ifdef FM_PEDANTIC_DMA ++ p_Fm->p_FmDriverParam->pedantic_dma = TRUE; ++ p_Fm->p_FmDriverParam->dma_aid_override = TRUE; ++#endif /* FM_PEDANTIC_DMA */ ++#ifndef FM_QMI_NO_DEQ_OPTIONS_SUPPORT ++ p_Fm->p_FmDriverParam->qmi_deq_option_support = TRUE; ++#endif /* !FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ ++ ++ p_Fm->p_FmStateStruct->ramsEccEnable = FALSE; ++ p_Fm->p_FmStateStruct->extraFifoPoolSize = 0; ++ p_Fm->p_FmStateStruct->exceptions = DEFAULT_exceptions; ++ p_Fm->resetOnInit = DEFAULT_resetOnInit; ++ p_Fm->f_ResetOnInitOverride = DEFAULT_resetOnInitOverrideCallback; ++ p_Fm->fwVerify = DEFAULT_VerifyUcode; ++ p_Fm->firmware.size = p_FmParam->firmware.size; ++ if (p_Fm->firmware.size) ++ { ++ p_Fm->firmware.p_Code = (uint32_t *)XX_Malloc(p_Fm->firmware.size); ++ if (!p_Fm->firmware.p_Code) ++ { ++ XX_FreeSpinlock(p_Fm->h_Spinlock); ++ XX_Free(p_Fm->p_FmStateStruct); ++ XX_Free(p_Fm->p_FmDriverParam); ++ XX_Free(p_Fm); ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM firmware code")); ++ return NULL; ++ } ++ memcpy(p_Fm->firmware.p_Code, p_FmParam->firmware.p_Code ,p_Fm->firmware.size); ++ } ++ ++ if (p_Fm->guestId != NCSW_MASTER_ID) ++ return p_Fm; ++ ++ /* read revision */ ++ /* Chip dependent, will be configured in Init */ ++ fman_get_revision(p_Fm->p_FmFpmRegs, ++ &p_Fm->p_FmStateStruct->revInfo.majorRev, ++ &p_Fm->p_FmStateStruct->revInfo.minorRev); ++ ++#ifdef FM_AID_MODE_NO_TNUM_SW005 ++ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) ++ p_Fm->p_FmDriverParam->dma_aid_mode = e_FM_DMA_AID_OUT_PORT_ID; ++#endif /* FM_AID_MODE_NO_TNUM_SW005 */ ++#ifndef FM_QMI_NO_DEQ_OPTIONS_SUPPORT ++ if (p_Fm->p_FmStateStruct->revInfo.majorRev != 4) ++ p_Fm->p_FmDriverParam->qmi_def_tnums_thresh = QMI_DEF_TNUMS_THRESH; ++#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ ++ ++ p_Fm->p_FmStateStruct->totalFifoSize = 0; ++ p_Fm->p_FmStateStruct->totalNumOfTasks = ++ DEFAULT_totalNumOfTasks(p_Fm->p_FmStateStruct->revInfo.majorRev, ++ p_Fm->p_FmStateStruct->revInfo.minorRev); ++ ++#ifdef FM_HAS_TOTAL_DMAS ++ p_Fm->p_FmStateStruct->maxNumOfOpenDmas = BMI_MAX_NUM_OF_DMAS; ++#endif /* FM_HAS_TOTAL_DMAS */ ++#if (DPAA_VERSION < 11) ++ p_Fm->p_FmDriverParam->dma_comm_qtsh_clr_emer = DEFAULT_dmaCommQLow; ++ p_Fm->p_FmDriverParam->dma_comm_qtsh_asrt_emer = DEFAULT_dmaCommQHigh; ++ p_Fm->p_FmDriverParam->dma_cam_num_of_entries = DEFAULT_dmaCamNumOfEntries; ++ p_Fm->p_FmDriverParam->dma_read_buf_tsh_clr_emer = DEFAULT_dmaReadIntBufLow; ++ p_Fm->p_FmDriverParam->dma_read_buf_tsh_asrt_emer = DEFAULT_dmaReadIntBufHigh; ++ p_Fm->p_FmDriverParam->dma_write_buf_tsh_clr_emer = DEFAULT_dmaWriteIntBufLow; ++ p_Fm->p_FmDriverParam->dma_write_buf_tsh_asrt_emer = DEFAULT_dmaWriteIntBufHigh; ++ p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats = DEFAULT_axiDbgNumOfBeats; ++#endif /* (DPAA_VERSION < 11) */ ++#ifdef FM_NO_TNUM_AGING ++ p_Fm->p_FmDriverParam->tnum_aging_period = 0; ++#endif ++ p_Fm->tnumAgingPeriod = p_Fm->p_FmDriverParam->tnum_aging_period; ++ ++ return p_Fm; ++} ++ ++/**************************************************************************//** ++ @Function FM_Init ++ ++ @Description Initializes the FM module ++ ++ @Param[in] h_Fm - FM module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_Init(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ struct fman_cfg *p_FmDriverParam = NULL; ++ t_Error err = E_OK; ++ int i; ++ t_FmRevisionInfo revInfo; ++ struct fman_rg fman_rg; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ ++ fman_rg.bmi_rg = p_Fm->p_FmBmiRegs; ++ fman_rg.qmi_rg = p_Fm->p_FmQmiRegs; ++ fman_rg.fpm_rg = p_Fm->p_FmFpmRegs; ++ fman_rg.dma_rg = p_Fm->p_FmDmaRegs; ++ ++ p_Fm->p_FmStateStruct->count1MicroBit = FM_TIMESTAMP_1_USEC_BIT; ++ p_Fm->p_FmDriverParam->num_of_fman_ctrl_evnt_regs = FM_NUM_OF_FMAN_CTRL_EVENT_REGS; ++ ++ if (p_Fm->guestId != NCSW_MASTER_ID) ++ return InitGuestMode(p_Fm); ++ ++ /* if user didn't configured totalFifoSize - (totalFifoSize=0) we configure default ++ * according to chip. otherwise, we use user's configuration. ++ */ ++ if (p_Fm->p_FmStateStruct->totalFifoSize == 0) ++ p_Fm->p_FmStateStruct->totalFifoSize = DEFAULT_totalFifoSize(p_Fm->p_FmStateStruct->revInfo.majorRev, ++ p_Fm->p_FmStateStruct->revInfo.minorRev); ++ ++ CHECK_INIT_PARAMETERS(p_Fm, CheckFmParameters); ++ ++ p_FmDriverParam = p_Fm->p_FmDriverParam; ++ ++ FM_GetRevision(p_Fm, &revInfo); ++ ++ /* clear revision-dependent non existing exception */ ++#ifdef FM_NO_DISPATCH_RAM_ECC ++ if ((revInfo.majorRev != 4) && ++ (revInfo.majorRev < 6)) ++ p_Fm->p_FmStateStruct->exceptions &= ~FM_EX_BMI_DISPATCH_RAM_ECC; ++#endif /* FM_NO_DISPATCH_RAM_ECC */ ++ ++#ifdef FM_QMI_NO_ECC_EXCEPTIONS ++ if (revInfo.majorRev == 4) ++ p_Fm->p_FmStateStruct->exceptions &= ~(FM_EX_QMI_SINGLE_ECC | FM_EX_QMI_DOUBLE_ECC); ++#endif /* FM_QMI_NO_ECC_EXCEPTIONS */ ++ ++#ifdef FM_QMI_NO_SINGLE_ECC_EXCEPTION ++ if (revInfo.majorRev >= 6) ++ p_Fm->p_FmStateStruct->exceptions &= ~FM_EX_QMI_SINGLE_ECC; ++#endif /* FM_QMI_NO_SINGLE_ECC_EXCEPTION */ ++ ++ FmMuramClear(p_Fm->h_FmMuram); ++ ++ /* clear CPG */ ++ IOMemSet32(UINT_TO_PTR(p_Fm->baseAddr + FM_MM_CGP), 0, FM_PORT_NUM_OF_CONGESTION_GRPS); ++ ++ /* add to the default exceptions the user's definitions */ ++ p_Fm->p_FmStateStruct->exceptions |= p_Fm->userSetExceptions; ++ ++ /* Reset the FM if required */ ++ if (p_Fm->resetOnInit) ++ { ++#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 ++ if ((err = FwNotResetErratumBugzilla6173WA(p_Fm)) != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++#else /* not FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */ ++ ++ if (p_Fm->f_ResetOnInitOverride) ++ { ++ /* Perform user specific FMan reset */ ++ p_Fm->f_ResetOnInitOverride(h_Fm); ++ } ++ else ++ { ++ /* Perform FMan reset */ ++ FmReset(h_Fm); ++ } ++ ++ if (fman_is_qmi_halt_not_busy_state(p_Fm->p_FmQmiRegs)) ++ { ++ fman_resume(p_Fm->p_FmFpmRegs); ++ XX_UDelay(100); ++ } ++#endif /* not FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */ ++ } ++ ++#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 ++ if (!p_Fm->resetOnInit) /* Skip operations done in errata workaround */ ++ { ++#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */ ++ /* Load FMan-Controller code to IRAM */ ++ ++ ClearIRam(p_Fm); ++ ++ if (p_Fm->firmware.p_Code && (LoadFmanCtrlCode(p_Fm) != E_OK)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 ++ } ++#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */ ++ ++#ifdef FM_CAPWAP_SUPPORT ++ /* save first 256 byte in MURAM */ ++ p_Fm->resAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram, 256, 0)); ++ if (!p_Fm->resAddr) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for reserved Area failed")); ++ ++ WRITE_BLOCK(UINT_TO_PTR(p_Fm->resAddr), 0, 256); ++#endif /* FM_CAPWAP_SUPPORT */ ++ ++#if (DPAA_VERSION >= 11) ++ p_Fm->partVSPBase = AllocVSPsForPartition(h_Fm, p_Fm->partVSPBase, p_Fm->partNumOfVSPs, p_Fm->guestId); ++ if (p_Fm->partVSPBase == (uint8_t)(ILLEGAL_BASE)) ++ DBG(WARNING, ("partition VSPs allocation is FAILED")); ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ /* General FM driver initialization */ ++ p_Fm->fmMuramPhysBaseAddr = ++ (uint64_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->baseAddr + FM_MM_MURAM))); ++ ++ for (i=0;iintrMng[i].f_Isr = UnimplementedIsr; ++ for (i=0;ifmanCtrlIntr[i].f_Isr = UnimplementedFmanCtrlIsr; ++ ++ p_FmDriverParam->exceptions = p_Fm->p_FmStateStruct->exceptions; ++ ++ /**********************/ ++ /* Init DMA Registers */ ++ /**********************/ ++ err = InitFmDma(p_Fm); ++ if (err != E_OK) ++ { ++ FreeInitResources(p_Fm); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ /**********************/ ++ /* Init FPM Registers */ ++ /**********************/ ++ err = InitFmFpm(p_Fm); ++ if (err != E_OK) ++ { ++ FreeInitResources(p_Fm); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ /* define common resources */ ++ /* allocate MURAM for FIFO according to total size */ ++ p_Fm->fifoBaseAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram, ++ p_Fm->p_FmStateStruct->totalFifoSize, ++ BMI_FIFO_ALIGN)); ++ if (!p_Fm->fifoBaseAddr) ++ { ++ FreeInitResources(p_Fm); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for BMI FIFO failed")); ++ } ++ ++ p_FmDriverParam->fifo_base_addr = (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->fifoBaseAddr)) - p_Fm->fmMuramPhysBaseAddr); ++ p_FmDriverParam->total_fifo_size = p_Fm->p_FmStateStruct->totalFifoSize; ++ p_FmDriverParam->total_num_of_tasks = p_Fm->p_FmStateStruct->totalNumOfTasks; ++ p_FmDriverParam->clk_freq = p_Fm->p_FmStateStruct->fmClkFreq; ++ ++ /**********************/ ++ /* Init BMI Registers */ ++ /**********************/ ++ err = InitFmBmi(p_Fm); ++ if (err != E_OK) ++ { ++ FreeInitResources(p_Fm); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ /**********************/ ++ /* Init QMI Registers */ ++ /**********************/ ++ err = InitFmQmi(p_Fm); ++ if (err != E_OK) ++ { ++ FreeInitResources(p_Fm); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ /* build the FM master partition IPC address */ ++ if (Sprint (p_Fm->fmModuleName, "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, NCSW_MASTER_ID) != 6) ++ { ++ FreeInitResources(p_Fm); ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); ++ } ++ ++ err = XX_IpcRegisterMsgHandler(p_Fm->fmModuleName, FmHandleIpcMsgCB, p_Fm, FM_IPC_MAX_REPLY_SIZE); ++ if (err) ++ { ++ FreeInitResources(p_Fm); ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ } ++ ++ /* Register the FM interrupts handlers */ ++ if (p_Fm->p_FmStateStruct->irq != NO_IRQ) ++ { ++ XX_SetIntr(p_Fm->p_FmStateStruct->irq, FM_EventIsr, p_Fm); ++ XX_EnableIntr(p_Fm->p_FmStateStruct->irq); ++ } ++ ++ if (p_Fm->p_FmStateStruct->errIrq != NO_IRQ) ++ { ++ XX_SetIntr(p_Fm->p_FmStateStruct->errIrq, (void (*) (t_Handle))FM_ErrorIsr, p_Fm); ++ XX_EnableIntr(p_Fm->p_FmStateStruct->errIrq); ++ } ++ ++ err = (t_Error)fman_enable(&fman_rg , p_FmDriverParam); ++ if (err != E_OK) ++ return err; /* FIXME */ ++ ++ EnableTimeStamp(p_Fm); ++ ++ if (p_Fm->firmware.p_Code) ++ { ++ XX_Free(p_Fm->firmware.p_Code); ++ p_Fm->firmware.p_Code = NULL; ++ } ++ ++ XX_Free(p_Fm->p_FmDriverParam); ++ p_Fm->p_FmDriverParam = NULL; ++ ++ return E_OK; ++} ++ ++/**************************************************************************//** ++ @Function FM_Free ++ ++ @Description Frees all resources that were assigned to FM module. ++ ++ Calling this routine invalidates the descriptor. ++ ++ @Param[in] h_Fm - FM module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_Free(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ struct fman_rg fman_rg; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ ++ fman_rg.bmi_rg = p_Fm->p_FmBmiRegs; ++ fman_rg.qmi_rg = p_Fm->p_FmQmiRegs; ++ fman_rg.fpm_rg = p_Fm->p_FmFpmRegs; ++ fman_rg.dma_rg = p_Fm->p_FmDmaRegs; ++ ++ if (p_Fm->guestId != NCSW_MASTER_ID) ++ { ++#if (DPAA_VERSION >= 11) ++ FreeVSPsForPartition(h_Fm, p_Fm->partVSPBase, p_Fm->partNumOfVSPs, p_Fm->guestId); ++ ++ if (p_Fm->p_FmSp) ++ { ++ XX_Free(p_Fm->p_FmSp); ++ p_Fm->p_FmSp = NULL; ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ if (p_Fm->fmModuleName[0] != 0) ++ XX_IpcUnregisterMsgHandler(p_Fm->fmModuleName); ++ ++ if (!p_Fm->recoveryMode) ++ XX_Free(p_Fm->p_FmStateStruct); ++ ++ XX_Free(p_Fm); ++ ++ return E_OK; ++ } ++ ++ fman_free_resources(&fman_rg); ++ ++ if ((p_Fm->guestId == NCSW_MASTER_ID) && (p_Fm->fmModuleName[0] != 0)) ++ XX_IpcUnregisterMsgHandler(p_Fm->fmModuleName); ++ ++ if (p_Fm->p_FmStateStruct) ++ { ++ if (p_Fm->p_FmStateStruct->irq != NO_IRQ) ++ { ++ XX_DisableIntr(p_Fm->p_FmStateStruct->irq); ++ XX_FreeIntr(p_Fm->p_FmStateStruct->irq); ++ } ++ if (p_Fm->p_FmStateStruct->errIrq != NO_IRQ) ++ { ++ XX_DisableIntr(p_Fm->p_FmStateStruct->errIrq); ++ XX_FreeIntr(p_Fm->p_FmStateStruct->errIrq); ++ } ++ } ++ ++#if (DPAA_VERSION >= 11) ++ FreeVSPsForPartition(h_Fm, p_Fm->partVSPBase, p_Fm->partNumOfVSPs, p_Fm->guestId); ++ ++ if (p_Fm->p_FmSp) ++ { ++ XX_Free(p_Fm->p_FmSp); ++ p_Fm->p_FmSp = NULL; ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ if (p_Fm->h_Spinlock) ++ XX_FreeSpinlock(p_Fm->h_Spinlock); ++ ++ if (p_Fm->p_FmDriverParam) ++ { ++ if (p_Fm->firmware.p_Code) ++ XX_Free(p_Fm->firmware.p_Code); ++ XX_Free(p_Fm->p_FmDriverParam); ++ p_Fm->p_FmDriverParam = NULL; ++ } ++ ++ FreeInitResources(p_Fm); ++ ++ if (!p_Fm->recoveryMode && p_Fm->p_FmStateStruct) ++ XX_Free(p_Fm->p_FmStateStruct); ++ ++ XX_Free(p_Fm); ++ ++ return E_OK; ++} ++ ++/*************************************************/ ++/* API Advanced Init unit functions */ ++/*************************************************/ ++ ++t_Error FM_ConfigResetOnInit(t_Handle h_Fm, bool enable) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ p_Fm->resetOnInit = enable; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigResetOnInitOverrideCallback(t_Handle h_Fm, t_FmResetOnInitOverrideCallback *f_ResetOnInitOverride) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ p_Fm->f_ResetOnInitOverride = f_ResetOnInitOverride; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigTotalFifoSize(t_Handle h_Fm, uint32_t totalFifoSize) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ p_Fm->p_FmStateStruct->totalFifoSize = totalFifoSize; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigDmaCacheOverride(t_Handle h_Fm, e_FmDmaCacheOverride cacheOverride) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ enum fman_dma_cache_override fsl_cache_override; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ FMAN_CACHE_OVERRIDE_TRANS(fsl_cache_override, cacheOverride) ++ p_Fm->p_FmDriverParam->dma_cache_override = fsl_cache_override; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigDmaAidOverride(t_Handle h_Fm, bool aidOverride) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ p_Fm->p_FmDriverParam->dma_aid_override = aidOverride; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigDmaAidMode(t_Handle h_Fm, e_FmDmaAidMode aidMode) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ enum fman_dma_aid_mode fsl_aid_mode; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ FMAN_AID_MODE_TRANS(fsl_aid_mode, aidMode); ++ p_Fm->p_FmDriverParam->dma_aid_mode = fsl_aid_mode; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigDmaAxiDbgNumOfBeats(t_Handle h_Fm, uint8_t axiDbgNumOfBeats) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++#if (DPAA_VERSION >= 11) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!")); ++#else ++ p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats = axiDbgNumOfBeats; ++ ++ return E_OK; ++#endif /* (DPAA_VERSION >= 11) */ ++} ++ ++t_Error FM_ConfigDmaCamNumOfEntries(t_Handle h_Fm, uint8_t numOfEntries) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ p_Fm->p_FmDriverParam->dma_cam_num_of_entries = numOfEntries; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigDmaDbgCounter(t_Handle h_Fm, e_FmDmaDbgCntMode fmDmaDbgCntMode) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ enum fman_dma_dbg_cnt_mode fsl_dma_dbg_cnt; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ FMAN_DMA_DBG_CNT_TRANS(fsl_dma_dbg_cnt, fmDmaDbgCntMode); ++ p_Fm->p_FmDriverParam->dma_dbg_cnt_mode = fsl_dma_dbg_cnt; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigDmaStopOnBusErr(t_Handle h_Fm, bool stop) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ p_Fm->p_FmDriverParam->dma_stop_on_bus_error = stop; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigDmaEmergency(t_Handle h_Fm, t_FmDmaEmergency *p_Emergency) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ enum fman_dma_emergency_level fsl_dma_emer; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ FMAN_DMA_EMER_TRANS(fsl_dma_emer, p_Emergency->emergencyLevel); ++ p_Fm->p_FmDriverParam->dma_en_emergency = TRUE; ++ p_Fm->p_FmDriverParam->dma_emergency_bus_select = (uint32_t)p_Emergency->emergencyBusSelect; ++ p_Fm->p_FmDriverParam->dma_emergency_level = fsl_dma_emer; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigDmaEmergencySmoother(t_Handle h_Fm, uint32_t emergencyCnt) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ p_Fm->p_FmDriverParam->dma_en_emergency_smoother = TRUE; ++ p_Fm->p_FmDriverParam->dma_emergency_switch_counter = emergencyCnt; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigDmaErr(t_Handle h_Fm, e_FmDmaErr dmaErr) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ enum fman_dma_err fsl_dma_err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ FMAN_DMA_ERR_TRANS(fsl_dma_err, dmaErr); ++ p_Fm->p_FmDriverParam->dma_err = fsl_dma_err; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigCatastrophicErr(t_Handle h_Fm, e_FmCatastrophicErr catastrophicErr) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ enum fman_catastrophic_err fsl_catastrophic_err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ FMAN_CATASTROPHIC_ERR_TRANS(fsl_catastrophic_err, catastrophicErr); ++ p_Fm->p_FmDriverParam->catastrophic_err = fsl_catastrophic_err; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigEnableMuramTestMode(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!")); ++ ++ p_Fm->p_FmDriverParam->en_muram_test_mode = TRUE; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigEnableIramTestMode(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE ); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!")); ++ ++ p_Fm->p_FmDriverParam->en_iram_test_mode = TRUE; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigHaltOnExternalActivation(t_Handle h_Fm, bool enable) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ p_Fm->p_FmDriverParam->halt_on_external_activ = enable; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigHaltOnUnrecoverableEccError(t_Handle h_Fm, bool enable) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!")); ++ ++ p_Fm->p_FmDriverParam->halt_on_unrecov_ecc_err = enable; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigException(t_Handle h_Fm, e_FmExceptions exception, bool enable) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ uint32_t bitMask = 0; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ GET_EXCEPTION_FLAG(bitMask, exception); ++ if (bitMask) ++ { ++ if (enable) ++ p_Fm->userSetExceptions |= bitMask; ++ else ++ p_Fm->p_FmStateStruct->exceptions &= ~bitMask; ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigExternalEccRamsEnable(t_Handle h_Fm, bool enable) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ p_Fm->p_FmDriverParam->external_ecc_rams_enable = enable; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigTnumAgingPeriod(t_Handle h_Fm, uint16_t tnumAgingPeriod) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ p_Fm->p_FmDriverParam->tnum_aging_period = tnumAgingPeriod; ++ p_Fm->tnumAgingPeriod = p_Fm->p_FmDriverParam->tnum_aging_period; ++ ++ return E_OK; ++} ++ ++/****************************************************/ ++/* Hidden-DEBUG Only API */ ++/****************************************************/ ++ ++t_Error FM_ConfigThresholds(t_Handle h_Fm, t_FmThresholds *p_FmThresholds) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ p_Fm->p_FmDriverParam->disp_limit_tsh = p_FmThresholds->dispLimit; ++ p_Fm->p_FmDriverParam->prs_disp_tsh = p_FmThresholds->prsDispTh; ++ p_Fm->p_FmDriverParam->plcr_disp_tsh = p_FmThresholds->plcrDispTh; ++ p_Fm->p_FmDriverParam->kg_disp_tsh = p_FmThresholds->kgDispTh; ++ p_Fm->p_FmDriverParam->bmi_disp_tsh = p_FmThresholds->bmiDispTh; ++ p_Fm->p_FmDriverParam->qmi_enq_disp_tsh = p_FmThresholds->qmiEnqDispTh; ++ p_Fm->p_FmDriverParam->qmi_deq_disp_tsh = p_FmThresholds->qmiDeqDispTh; ++ p_Fm->p_FmDriverParam->fm_ctl1_disp_tsh = p_FmThresholds->fmCtl1DispTh; ++ p_Fm->p_FmDriverParam->fm_ctl2_disp_tsh = p_FmThresholds->fmCtl2DispTh; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigDmaSosEmergencyThreshold(t_Handle h_Fm, uint32_t dmaSosEmergency) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ p_Fm->p_FmDriverParam->dma_sos_emergency = dmaSosEmergency; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigDmaWriteBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds) ++ ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++#if (DPAA_VERSION >= 11) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!")); ++#else ++ p_Fm->p_FmDriverParam->dma_write_buf_tsh_asrt_emer = p_FmDmaThresholds->assertEmergency; ++ p_Fm->p_FmDriverParam->dma_write_buf_tsh_clr_emer = p_FmDmaThresholds->clearEmergency; ++ ++ return E_OK; ++#endif ++} ++ ++t_Error FM_ConfigDmaCommQThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ p_Fm->p_FmDriverParam->dma_comm_qtsh_asrt_emer = p_FmDmaThresholds->assertEmergency; ++ p_Fm->p_FmDriverParam->dma_comm_qtsh_clr_emer = p_FmDmaThresholds->clearEmergency; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigDmaReadBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++#if (DPAA_VERSION >= 11) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!")); ++#else ++ p_Fm->p_FmDriverParam->dma_read_buf_tsh_clr_emer = p_FmDmaThresholds->clearEmergency; ++ p_Fm->p_FmDriverParam->dma_read_buf_tsh_asrt_emer = p_FmDmaThresholds->assertEmergency; ++ ++ return E_OK; ++#endif ++} ++ ++t_Error FM_ConfigDmaWatchdog(t_Handle h_Fm, uint32_t watchdogValue) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ p_Fm->p_FmDriverParam->dma_watchdog = watchdogValue; ++ ++ return E_OK; ++} ++ ++t_Error FM_ConfigEnableCounters(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++UNUSED(p_Fm); ++ ++ return E_OK; ++} ++ ++t_Error FmGetSetParams(t_Handle h_Fm, t_FmGetSetParams *p_Params) ++{ ++ t_Fm* p_Fm = (t_Fm*)h_Fm; ++ if (p_Params->setParams.type & UPDATE_FM_CLD) ++ { ++ WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_cld, GET_UINT32( ++ p_Fm->p_FmFpmRegs->fm_cld) | 0x00000800); ++ } ++ if (p_Params->setParams.type & CLEAR_IRAM_READY) ++ { ++ t_FMIramRegs *p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM); ++ WRITE_UINT32(p_Iram->iready,GET_UINT32(p_Iram->iready) & ~IRAM_READY); ++ } ++ if (p_Params->setParams.type & UPDATE_FPM_EXTC) ++ WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_extc,0x80000000); ++ if (p_Params->setParams.type & UPDATE_FPM_EXTC_CLEAR) ++ WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_extc,0x00800000); ++ if (p_Params->setParams.type & UPDATE_FPM_BRKC_SLP) ++ { ++ if (p_Params->setParams.sleep) ++ WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc, GET_UINT32( ++ p_Fm->p_FmFpmRegs->fmfp_brkc) | FPM_BRKC_SLP); ++ else ++ WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc, GET_UINT32( ++ p_Fm->p_FmFpmRegs->fmfp_brkc) & ~FPM_BRKC_SLP); ++ } ++ if (p_Params->getParams.type & GET_FM_CLD) ++ p_Params->getParams.fm_cld = GET_UINT32(p_Fm->p_FmFpmRegs->fm_cld); ++ if (p_Params->getParams.type & GET_FMQM_GS) ++ p_Params->getParams.fmqm_gs = GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_gs); ++ if (p_Params->getParams.type & GET_FM_NPI) ++ p_Params->getParams.fm_npi = GET_UINT32(p_Fm->p_FmFpmRegs->fm_npi); ++ if (p_Params->getParams.type & GET_FMFP_EXTC) ++ p_Params->getParams.fmfp_extc = GET_UINT32(p_Fm->p_FmFpmRegs->fmfp_extc); ++ return E_OK; ++} ++ ++ ++/****************************************************/ ++/* API Run-time Control uint functions */ ++/****************************************************/ ++void FM_EventIsr(t_Handle h_Fm) ++{ ++#define FM_M_CALL_1G_MAC_ISR(_id) \ ++ { \ ++ if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].guestId) \ ++ SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id), pending); \ ++ else \ ++ p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].h_SrcHandle);\ ++ } ++#define FM_M_CALL_10G_MAC_ISR(_id) \ ++ { \ ++ if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].guestId) \ ++ SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id), pending); \ ++ else \ ++ p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].h_SrcHandle);\ ++ } ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ uint32_t pending, event; ++ struct fman_fpm_regs *fpm_rg; ++ ++ SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ fpm_rg = p_Fm->p_FmFpmRegs; ++ ++ /* normal interrupts */ ++ pending = fman_get_normal_pending(fpm_rg); ++ if (!pending) ++ return; ++ if (pending & INTR_EN_WAKEUP) // this is a wake up from sleep interrupt ++ { ++ t_FmGetSetParams fmGetSetParams; ++ memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); ++ fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP; ++ fmGetSetParams.setParams.sleep = 0; ++ FmGetSetParams(h_Fm, &fmGetSetParams); ++ } ++ if (pending & INTR_EN_QMI) ++ QmiEvent(p_Fm); ++ if (pending & INTR_EN_PRS) ++ p_Fm->intrMng[e_FM_EV_PRS].f_Isr(p_Fm->intrMng[e_FM_EV_PRS].h_SrcHandle); ++ if (pending & INTR_EN_PLCR) ++ p_Fm->intrMng[e_FM_EV_PLCR].f_Isr(p_Fm->intrMng[e_FM_EV_PLCR].h_SrcHandle); ++ if (pending & INTR_EN_TMR) ++ p_Fm->intrMng[e_FM_EV_TMR].f_Isr(p_Fm->intrMng[e_FM_EV_TMR].h_SrcHandle); ++ ++ /* MAC events may belong to different partitions */ ++ if (pending & INTR_EN_1G_MAC0) ++ FM_M_CALL_1G_MAC_ISR(0); ++ if (pending & INTR_EN_1G_MAC1) ++ FM_M_CALL_1G_MAC_ISR(1); ++ if (pending & INTR_EN_1G_MAC2) ++ FM_M_CALL_1G_MAC_ISR(2); ++ if (pending & INTR_EN_1G_MAC3) ++ FM_M_CALL_1G_MAC_ISR(3); ++ if (pending & INTR_EN_1G_MAC4) ++ FM_M_CALL_1G_MAC_ISR(4); ++ if (pending & INTR_EN_1G_MAC5) ++ FM_M_CALL_1G_MAC_ISR(5); ++ if (pending & INTR_EN_1G_MAC6) ++ FM_M_CALL_1G_MAC_ISR(6); ++ if (pending & INTR_EN_1G_MAC7) ++ FM_M_CALL_1G_MAC_ISR(7); ++ if (pending & INTR_EN_10G_MAC0) ++ FM_M_CALL_10G_MAC_ISR(0); ++ if (pending & INTR_EN_10G_MAC1) ++ FM_M_CALL_10G_MAC_ISR(1); ++ ++ /* IM port events may belong to different partitions */ ++ if (pending & INTR_EN_REV0) ++ { ++ event = fman_get_controller_event(fpm_rg, 0); ++ if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_0].guestId) ++ /*TODO IPC ISR For Fman Ctrl */ ++ ASSERT_COND(0); ++ /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_0, pending); */ ++ else ++ p_Fm->fmanCtrlIntr[0].f_Isr(p_Fm->fmanCtrlIntr[0].h_SrcHandle, event); ++ ++ } ++ if (pending & INTR_EN_REV1) ++ { ++ event = fman_get_controller_event(fpm_rg, 1); ++ if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_1].guestId) ++ /*TODO IPC ISR For Fman Ctrl */ ++ ASSERT_COND(0); ++ /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_1, pending); */ ++ else ++ p_Fm->fmanCtrlIntr[1].f_Isr(p_Fm->fmanCtrlIntr[1].h_SrcHandle, event); ++ } ++ if (pending & INTR_EN_REV2) ++ { ++ event = fman_get_controller_event(fpm_rg, 2); ++ if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_2].guestId) ++ /*TODO IPC ISR For Fman Ctrl */ ++ ASSERT_COND(0); ++ /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_2, pending); */ ++ else ++ p_Fm->fmanCtrlIntr[2].f_Isr(p_Fm->fmanCtrlIntr[2].h_SrcHandle, event); ++ } ++ if (pending & INTR_EN_REV3) ++ { ++ event = fman_get_controller_event(fpm_rg, 3); ++ if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_3].guestId) ++ /*TODO IPC ISR For Fman Ctrl */ ++ ASSERT_COND(0); ++ /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_2, pendin3); */ ++ else ++ p_Fm->fmanCtrlIntr[3].f_Isr(p_Fm->fmanCtrlIntr[3].h_SrcHandle, event); ++ } ++#ifdef FM_MACSEC_SUPPORT ++ if (pending & INTR_EN_MACSEC_MAC0) ++ { ++ if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_MACSEC_MAC0].guestId) ++ SendIpcIsr(p_Fm, e_FM_EV_MACSEC_MAC0, pending); ++ else ++ p_Fm->intrMng[e_FM_EV_MACSEC_MAC0].f_Isr(p_Fm->intrMng[e_FM_EV_MACSEC_MAC0].h_SrcHandle); ++ } ++#endif /* FM_MACSEC_SUPPORT */ ++} ++ ++t_Error FM_ErrorIsr(t_Handle h_Fm) ++{ ++#define FM_M_CALL_1G_MAC_ERR_ISR(_id) \ ++ { \ ++ if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].guestId) \ ++ SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id), pending); \ ++ else \ ++ p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].h_SrcHandle);\ ++ } ++#define FM_M_CALL_10G_MAC_ERR_ISR(_id) \ ++ { \ ++ if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].guestId) \ ++ SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id), pending); \ ++ else \ ++ p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].h_SrcHandle);\ ++ } ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ uint32_t pending; ++ struct fman_fpm_regs *fpm_rg; ++ ++ SANITY_CHECK_RETURN_ERROR(h_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ fpm_rg = p_Fm->p_FmFpmRegs; ++ ++ /* error interrupts */ ++ pending = fman_get_fpm_error_interrupts(fpm_rg); ++ if (!pending) ++ return ERROR_CODE(E_EMPTY); ++ ++ if (pending & ERR_INTR_EN_BMI) ++ BmiErrEvent(p_Fm); ++ if (pending & ERR_INTR_EN_QMI) ++ QmiErrEvent(p_Fm); ++ if (pending & ERR_INTR_EN_FPM) ++ FpmErrEvent(p_Fm); ++ if (pending & ERR_INTR_EN_DMA) ++ DmaErrEvent(p_Fm); ++ if (pending & ERR_INTR_EN_IRAM) ++ IramErrIntr(p_Fm); ++ if (pending & ERR_INTR_EN_MURAM) ++ MuramErrIntr(p_Fm); ++ if (pending & ERR_INTR_EN_PRS) ++ p_Fm->intrMng[e_FM_EV_ERR_PRS].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_PRS].h_SrcHandle); ++ if (pending & ERR_INTR_EN_PLCR) ++ p_Fm->intrMng[e_FM_EV_ERR_PLCR].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_PLCR].h_SrcHandle); ++ if (pending & ERR_INTR_EN_KG) ++ p_Fm->intrMng[e_FM_EV_ERR_KG].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_KG].h_SrcHandle); ++ ++ /* MAC events may belong to different partitions */ ++ if (pending & ERR_INTR_EN_1G_MAC0) ++ FM_M_CALL_1G_MAC_ERR_ISR(0); ++ if (pending & ERR_INTR_EN_1G_MAC1) ++ FM_M_CALL_1G_MAC_ERR_ISR(1); ++ if (pending & ERR_INTR_EN_1G_MAC2) ++ FM_M_CALL_1G_MAC_ERR_ISR(2); ++ if (pending & ERR_INTR_EN_1G_MAC3) ++ FM_M_CALL_1G_MAC_ERR_ISR(3); ++ if (pending & ERR_INTR_EN_1G_MAC4) ++ FM_M_CALL_1G_MAC_ERR_ISR(4); ++ if (pending & ERR_INTR_EN_1G_MAC5) ++ FM_M_CALL_1G_MAC_ERR_ISR(5); ++ if (pending & ERR_INTR_EN_1G_MAC6) ++ FM_M_CALL_1G_MAC_ERR_ISR(6); ++ if (pending & ERR_INTR_EN_1G_MAC7) ++ FM_M_CALL_1G_MAC_ERR_ISR(7); ++ if (pending & ERR_INTR_EN_10G_MAC0) ++ FM_M_CALL_10G_MAC_ERR_ISR(0); ++ if (pending & ERR_INTR_EN_10G_MAC1) ++ FM_M_CALL_10G_MAC_ERR_ISR(1); ++ ++#ifdef FM_MACSEC_SUPPORT ++ if (pending & ERR_INTR_EN_MACSEC_MAC0) ++ { ++ if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_ERR_MACSEC_MAC0].guestId) ++ SendIpcIsr(p_Fm, e_FM_EV_ERR_MACSEC_MAC0, pending); ++ else ++ p_Fm->intrMng[e_FM_EV_ERR_MACSEC_MAC0].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_MACSEC_MAC0].h_SrcHandle); ++ } ++#endif /* FM_MACSEC_SUPPORT */ ++ ++ return E_OK; ++} ++ ++t_Error FM_SetPortsBandwidth(t_Handle h_Fm, t_FmPortsBandwidthParams *p_PortsBandwidth) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ int i; ++ uint8_t sum; ++ uint8_t hardwarePortId; ++ uint8_t weights[64]; ++ uint8_t weight, maxPercent = 0; ++ struct fman_bmi_regs *bmi_rg; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ bmi_rg = p_Fm->p_FmBmiRegs; ++ ++ memset(weights, 0, (sizeof(uint8_t) * 64)); ++ ++ /* check that all ports add up to 100% */ ++ sum = 0; ++ for (i=0; i < p_PortsBandwidth->numOfPorts; i++) ++ sum +=p_PortsBandwidth->portsBandwidths[i].bandwidth; ++ if (sum != 100) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Sum of ports bandwidth differ from 100%")); ++ ++ /* find highest percent */ ++ for (i=0; i < p_PortsBandwidth->numOfPorts; i++) ++ { ++ if (p_PortsBandwidth->portsBandwidths[i].bandwidth > maxPercent) ++ maxPercent = p_PortsBandwidth->portsBandwidths[i].bandwidth; ++ } ++ ++ ASSERT_COND(maxPercent > 0); /* guaranteed by sum = 100 */ ++ ++ /* calculate weight for each port */ ++ for (i=0; i < p_PortsBandwidth->numOfPorts; i++) ++ { ++ weight = (uint8_t)((p_PortsBandwidth->portsBandwidths[i].bandwidth * PORT_MAX_WEIGHT ) / maxPercent); ++ /* we want even division between 1-to-PORT_MAX_WEIGHT. so if exact division ++ is not reached, we round up so that: ++ 0 until maxPercent/PORT_MAX_WEIGHT get "1" ++ maxPercent/PORT_MAX_WEIGHT+1 until (maxPercent/PORT_MAX_WEIGHT)*2 get "2" ++ ... ++ maxPercent - maxPercent/PORT_MAX_WEIGHT until maxPercent get "PORT_MAX_WEIGHT: */ ++ if ((uint8_t)((p_PortsBandwidth->portsBandwidths[i].bandwidth * PORT_MAX_WEIGHT ) % maxPercent)) ++ weight++; ++ ++ /* find the location of this port within the register */ ++ hardwarePortId = ++ SwPortIdToHwPortId(p_PortsBandwidth->portsBandwidths[i].type, ++ p_PortsBandwidth->portsBandwidths[i].relativePortId, ++ p_Fm->p_FmStateStruct->revInfo.majorRev, ++ p_Fm->p_FmStateStruct->revInfo.minorRev); ++ ++ ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); ++ weights[hardwarePortId] = weight; ++ } ++ ++ fman_set_ports_bandwidth(bmi_rg, weights); ++ ++ return E_OK; ++} ++ ++t_Error FM_EnableRamsEcc(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ struct fman_fpm_regs *fpm_rg; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ ++ fpm_rg = p_Fm->p_FmFpmRegs; ++ ++ if (p_Fm->guestId != NCSW_MASTER_ID) ++ { ++ t_FmIpcMsg msg; ++ t_Error err; ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.msgId = FM_ENABLE_RAM_ECC; ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId), ++ NULL, ++ NULL, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ return E_OK; ++ } ++ ++ if (!p_Fm->p_FmStateStruct->internalCall) ++ p_Fm->p_FmStateStruct->explicitEnable = TRUE; ++ p_Fm->p_FmStateStruct->internalCall = FALSE; ++ ++ if (p_Fm->p_FmStateStruct->ramsEccEnable) ++ return E_OK; ++ else ++ { ++ fman_enable_rams_ecc(fpm_rg); ++ p_Fm->p_FmStateStruct->ramsEccEnable = TRUE; ++ } ++ ++ return E_OK; ++} ++ ++t_Error FM_DisableRamsEcc(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ bool explicitDisable = FALSE; ++ struct fman_fpm_regs *fpm_rg; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_HANDLE); ++ ++ fpm_rg = p_Fm->p_FmFpmRegs; ++ ++ if (p_Fm->guestId != NCSW_MASTER_ID) ++ { ++ t_Error err; ++ t_FmIpcMsg msg; ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.msgId = FM_DISABLE_RAM_ECC; ++ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId), ++ NULL, ++ NULL, ++ NULL, ++ NULL)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ return E_OK; ++ } ++ ++ if (!p_Fm->p_FmStateStruct->internalCall) ++ explicitDisable = TRUE; ++ p_Fm->p_FmStateStruct->internalCall = FALSE; ++ ++ /* if rams are already disabled, or if rams were explicitly enabled and are ++ currently called indirectly (not explicitly), ignore this call. */ ++ if (!p_Fm->p_FmStateStruct->ramsEccEnable || ++ (p_Fm->p_FmStateStruct->explicitEnable && !explicitDisable)) ++ return E_OK; ++ else ++ { ++ if (p_Fm->p_FmStateStruct->explicitEnable) ++ /* This is the case were both explicit are TRUE. ++ Turn off this flag for cases were following ramsEnable ++ routines are called */ ++ p_Fm->p_FmStateStruct->explicitEnable = FALSE; ++ ++ fman_enable_rams_ecc(fpm_rg); ++ p_Fm->p_FmStateStruct->ramsEccEnable = FALSE; ++ } ++ ++ return E_OK; ++} ++ ++t_Error FM_SetException(t_Handle h_Fm, e_FmExceptions exception, bool enable) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ uint32_t bitMask = 0; ++ enum fman_exceptions fslException; ++ struct fman_rg fman_rg; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); ++ ++ fman_rg.bmi_rg = p_Fm->p_FmBmiRegs; ++ fman_rg.qmi_rg = p_Fm->p_FmQmiRegs; ++ fman_rg.fpm_rg = p_Fm->p_FmFpmRegs; ++ fman_rg.dma_rg = p_Fm->p_FmDmaRegs; ++ ++ GET_EXCEPTION_FLAG(bitMask, exception); ++ if (bitMask) ++ { ++ if (enable) ++ p_Fm->p_FmStateStruct->exceptions |= bitMask; ++ else ++ p_Fm->p_FmStateStruct->exceptions &= ~bitMask; ++ ++ fslException = FmanExceptionTrans(exception); ++ ++ return (t_Error)fman_set_exception(&fman_rg, ++ fslException, ++ enable); ++ } ++ else ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); ++ ++ return E_OK; ++} ++ ++t_Error FM_GetRevision(t_Handle h_Fm, t_FmRevisionInfo *p_FmRevisionInfo) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ p_FmRevisionInfo->majorRev = p_Fm->p_FmStateStruct->revInfo.majorRev; ++ p_FmRevisionInfo->minorRev = p_Fm->p_FmStateStruct->revInfo.minorRev; ++ ++ return E_OK; ++} ++ ++t_Error FM_GetFmanCtrlCodeRevision(t_Handle h_Fm, t_FmCtrlCodeRevisionInfo *p_RevisionInfo) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ t_FMIramRegs *p_Iram; ++ uint32_t revInfo; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_RevisionInfo, E_NULL_POINTER); ++ ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ p_Fm->h_IpcSessions[0]) ++ { ++ t_Error err; ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ uint32_t replyLength; ++ t_FmIpcFmanCtrlCodeRevisionInfo ipcRevInfo; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_GET_FMAN_CTRL_CODE_REV; ++ replyLength = sizeof(uint32_t) + sizeof(t_FmCtrlCodeRevisionInfo); ++ if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ if (replyLength != (sizeof(uint32_t) + sizeof(t_FmCtrlCodeRevisionInfo))) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ memcpy((uint8_t*)&ipcRevInfo, reply.replyBody, sizeof(t_FmCtrlCodeRevisionInfo)); ++ p_RevisionInfo->packageRev = ipcRevInfo.packageRev; ++ p_RevisionInfo->majorRev = ipcRevInfo.majorRev; ++ p_RevisionInfo->minorRev = ipcRevInfo.minorRev; ++ return (t_Error)(reply.error); ++ } ++ else if (p_Fm->guestId != NCSW_MASTER_ID) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("running in guest-mode without IPC!")); ++ ++ p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM); ++ WRITE_UINT32(p_Iram->iadd, 0x4); ++ while (GET_UINT32(p_Iram->iadd) != 0x4) ; ++ revInfo = GET_UINT32(p_Iram->idata); ++ p_RevisionInfo->packageRev = (uint16_t)((revInfo & 0xFFFF0000) >> 16); ++ p_RevisionInfo->majorRev = (uint8_t)((revInfo & 0x0000FF00) >> 8); ++ p_RevisionInfo->minorRev = (uint8_t)(revInfo & 0x000000FF); ++ ++ return E_OK; ++} ++ ++uint32_t FM_GetCounter(t_Handle h_Fm, e_FmCounters counter) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ t_Error err; ++ uint32_t counterValue; ++ struct fman_rg fman_rg; ++ enum fman_counters fsl_counter; ++ ++ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0); ++ SANITY_CHECK_RETURN_VALUE(!p_Fm->p_FmDriverParam, E_INVALID_STATE, 0); ++ ++ fman_rg.bmi_rg = p_Fm->p_FmBmiRegs; ++ fman_rg.qmi_rg = p_Fm->p_FmQmiRegs; ++ fman_rg.fpm_rg = p_Fm->p_FmFpmRegs; ++ fman_rg.dma_rg = p_Fm->p_FmDmaRegs; ++ ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ !p_Fm->baseAddr && ++ p_Fm->h_IpcSessions[0]) ++ { ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ uint32_t replyLength, outCounter; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_GET_COUNTER; ++ memcpy(msg.msgBody, (uint8_t *)&counter, sizeof(uint32_t)); ++ replyLength = sizeof(uint32_t) + sizeof(uint32_t); ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId) +sizeof(counterValue), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ { ++ REPORT_ERROR(MAJOR, err, NO_MSG); ++ return 0; ++ } ++ if (replyLength != (sizeof(uint32_t) + sizeof(uint32_t))) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ return 0; ++ } ++ ++ memcpy((uint8_t*)&outCounter, reply.replyBody, sizeof(uint32_t)); ++ return outCounter; ++ } ++ else if (!p_Fm->baseAddr) ++ { ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Either IPC or 'baseAddress' is required!")); ++ return 0; ++ } ++ ++ /* When applicable (when there is an 'enable counters' bit, ++ check that counters are enabled */ ++ switch (counter) ++ { ++ case (e_FM_COUNTERS_DEQ_1): ++ case (e_FM_COUNTERS_DEQ_2): ++ case (e_FM_COUNTERS_DEQ_3): ++ if ((p_Fm->p_FmStateStruct->revInfo.majorRev == 4) || ++ (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)) ++ { ++ REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Requested counter not supported")); ++ return 0; ++ } ++ case (e_FM_COUNTERS_ENQ_TOTAL_FRAME): ++ case (e_FM_COUNTERS_DEQ_TOTAL_FRAME): ++ case (e_FM_COUNTERS_DEQ_0): ++ case (e_FM_COUNTERS_DEQ_FROM_DEFAULT): ++ case (e_FM_COUNTERS_DEQ_FROM_CONTEXT): ++ case (e_FM_COUNTERS_DEQ_FROM_FD): ++ case (e_FM_COUNTERS_DEQ_CONFIRM): ++ if (!(GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_gc) & QMI_CFG_EN_COUNTERS)) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Requested counter was not enabled")); ++ return 0; ++ } ++ break; ++ default: ++ break; ++ } ++ ++ FMAN_COUNTERS_TRANS(fsl_counter, counter); ++ return fman_get_counter(&fman_rg, fsl_counter); ++} ++ ++t_Error FM_ModifyCounter(t_Handle h_Fm, e_FmCounters counter, uint32_t val) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ struct fman_rg fman_rg; ++ enum fman_counters fsl_counter; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); ++ ++ fman_rg.bmi_rg = p_Fm->p_FmBmiRegs; ++ fman_rg.qmi_rg = p_Fm->p_FmQmiRegs; ++ fman_rg.fpm_rg = p_Fm->p_FmFpmRegs; ++ fman_rg.dma_rg = p_Fm->p_FmDmaRegs; ++ ++ FMAN_COUNTERS_TRANS(fsl_counter, counter); ++ return (t_Error)fman_modify_counter(&fman_rg, fsl_counter, val); ++} ++ ++void FM_SetDmaEmergency(t_Handle h_Fm, e_FmDmaMuramPort muramPort, bool enable) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ struct fman_dma_regs *dma_rg; ++ ++ SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE); ++ ++ dma_rg = p_Fm->p_FmDmaRegs; ++ ++ fman_set_dma_emergency(dma_rg, !!(muramPort==e_FM_DMA_MURAM_PORT_WRITE), enable); ++} ++ ++void FM_SetDmaExtBusPri(t_Handle h_Fm, e_FmDmaExtBusPri pri) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ struct fman_dma_regs *dma_rg; ++ ++ SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE); ++ ++ dma_rg = p_Fm->p_FmDmaRegs; ++ ++ fman_set_dma_ext_bus_pri(dma_rg, pri); ++} ++ ++void FM_GetDmaStatus(t_Handle h_Fm, t_FmDmaStatus *p_FmDmaStatus) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ uint32_t dmaStatus; ++ struct fman_dma_regs *dma_rg; ++ ++ SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE); ++ ++ dma_rg = p_Fm->p_FmDmaRegs; ++ ++ if ((p_Fm->guestId != NCSW_MASTER_ID) && ++ !p_Fm->baseAddr && ++ p_Fm->h_IpcSessions[0]) ++ { ++ t_FmIpcDmaStatus ipcDmaStatus; ++ t_FmIpcMsg msg; ++ t_FmIpcReply reply; ++ t_Error err; ++ uint32_t replyLength; ++ ++ memset(&msg, 0, sizeof(msg)); ++ memset(&reply, 0, sizeof(reply)); ++ msg.msgId = FM_DMA_STAT; ++ replyLength = sizeof(uint32_t) + sizeof(t_FmIpcDmaStatus); ++ err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], ++ (uint8_t*)&msg, ++ sizeof(msg.msgId), ++ (uint8_t*)&reply, ++ &replyLength, ++ NULL, ++ NULL); ++ if (err != E_OK) ++ { ++ REPORT_ERROR(MINOR, err, NO_MSG); ++ return; ++ } ++ if (replyLength != (sizeof(uint32_t) + sizeof(t_FmIpcDmaStatus))) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); ++ return; ++ } ++ memcpy((uint8_t*)&ipcDmaStatus, reply.replyBody, sizeof(t_FmIpcDmaStatus)); ++ ++ p_FmDmaStatus->cmqNotEmpty = (bool)ipcDmaStatus.boolCmqNotEmpty; /**< Command queue is not empty */ ++ p_FmDmaStatus->busError = (bool)ipcDmaStatus.boolBusError; /**< Bus error occurred */ ++ p_FmDmaStatus->readBufEccError = (bool)ipcDmaStatus.boolReadBufEccError; /**< Double ECC error on buffer Read */ ++ p_FmDmaStatus->writeBufEccSysError =(bool)ipcDmaStatus.boolWriteBufEccSysError; /**< Double ECC error on buffer write from system side */ ++ p_FmDmaStatus->writeBufEccFmError = (bool)ipcDmaStatus.boolWriteBufEccFmError; /**< Double ECC error on buffer write from FM side */ ++ p_FmDmaStatus->singlePortEccError = (bool)ipcDmaStatus.boolSinglePortEccError; /**< Double ECC error on buffer write from FM side */ ++ return; ++ } ++ else if (!p_Fm->baseAddr) ++ { ++ REPORT_ERROR(MINOR, E_NOT_SUPPORTED, ++ ("Either IPC or 'baseAddress' is required!")); ++ return; ++ } ++ ++ dmaStatus = fman_get_dma_status(dma_rg); ++ ++ p_FmDmaStatus->cmqNotEmpty = (bool)(dmaStatus & DMA_STATUS_CMD_QUEUE_NOT_EMPTY); ++ p_FmDmaStatus->busError = (bool)(dmaStatus & DMA_STATUS_BUS_ERR); ++ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) ++ p_FmDmaStatus->singlePortEccError = (bool)(dmaStatus & DMA_STATUS_FM_SPDAT_ECC); ++ else ++ { ++ p_FmDmaStatus->readBufEccError = (bool)(dmaStatus & DMA_STATUS_READ_ECC); ++ p_FmDmaStatus->writeBufEccSysError = (bool)(dmaStatus & DMA_STATUS_SYSTEM_WRITE_ECC); ++ p_FmDmaStatus->writeBufEccFmError = (bool)(dmaStatus & DMA_STATUS_FM_WRITE_ECC); ++ } ++} ++ ++void FM_Resume(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ struct fman_fpm_regs *fpm_rg; ++ ++ SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ fpm_rg = p_Fm->p_FmFpmRegs; ++ ++ fman_resume(fpm_rg); ++} ++ ++t_Error FM_GetSpecialOperationCoding(t_Handle h_Fm, ++ fmSpecialOperations_t spOper, ++ uint8_t *p_SpOperCoding) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ t_FmCtrlCodeRevisionInfo revInfo; ++ t_Error err; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR(p_SpOperCoding, E_NULL_POINTER); ++ ++ if (!spOper) ++ { ++ *p_SpOperCoding = 0; ++ return E_OK; ++ } ++ ++ if ((err = FM_GetFmanCtrlCodeRevision(p_Fm, &revInfo)) != E_OK) ++ { ++ DBG(WARNING, ("FM in guest-mode without IPC, can't validate firmware revision.")); ++ revInfo.packageRev = IP_OFFLOAD_PACKAGE_NUMBER; ++ } ++ else if (!IS_OFFLOAD_PACKAGE(revInfo.packageRev)) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Fman ctrl code package")); ++ ++ switch (spOper) ++ { ++ case (FM_SP_OP_CAPWAP_DTLS_DEC): ++ *p_SpOperCoding = 9; ++ break; ++ case (FM_SP_OP_CAPWAP_DTLS_ENC): ++ *p_SpOperCoding = 10; ++ break; ++ case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN|FM_SP_OP_IPSEC_MANIP): ++ case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN|FM_SP_OP_IPSEC_MANIP|FM_SP_OP_RPD): ++ *p_SpOperCoding = 5; ++ break; ++ case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_MANIP): ++ case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_MANIP|FM_SP_OP_RPD): ++ *p_SpOperCoding = 6; ++ break; ++ case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN|FM_SP_OP_RPD): ++ *p_SpOperCoding = 3; ++ break; ++ case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN): ++ *p_SpOperCoding = 1; ++ break; ++ case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN|FM_SP_OP_IPSEC_NO_ETH_HDR): ++ *p_SpOperCoding = 12; ++ break; ++ case (FM_SP_OP_IPSEC|FM_SP_OP_RPD): ++ *p_SpOperCoding = 4; ++ break; ++ case (FM_SP_OP_IPSEC): ++ *p_SpOperCoding = 2; ++ break; ++ case (FM_SP_OP_DCL4C): ++ *p_SpOperCoding = 7; ++ break; ++ case (FM_SP_OP_CLEAR_RPD): ++ *p_SpOperCoding = 8; ++ break; ++ default: ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); ++ } ++ ++ return E_OK; ++} ++ ++t_Error FM_CtrlMonStart(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm *)h_Fm; ++ t_FmTrbRegs *p_MonRegs; ++ uint8_t i; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc, ++ GET_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc) | FPM_BRKC_RDBG); ++ ++ for (i = 0; i < FM_NUM_OF_CTRL; i++) ++ { ++ p_MonRegs = (t_FmTrbRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_TRB(i)); ++ ++ /* Reset control registers */ ++ WRITE_UINT32(p_MonRegs->tcrh, TRB_TCRH_RESET); ++ WRITE_UINT32(p_MonRegs->tcrl, TRB_TCRL_RESET); ++ ++ /* Configure: counter #1 counts all stalls in risc - ldsched stall ++ counter #2 counts all stalls in risc - other stall*/ ++ WRITE_UINT32(p_MonRegs->tcrl, TRB_TCRL_RESET | TRB_TCRL_UTIL); ++ ++ /* Enable monitoring */ ++ WRITE_UINT32(p_MonRegs->tcrh, TRB_TCRH_ENABLE_COUNTERS); ++ } ++ ++ return E_OK; ++} ++ ++t_Error FM_CtrlMonStop(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm *)h_Fm; ++ t_FmTrbRegs *p_MonRegs; ++ uint8_t i; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ ++ for (i = 0; i < FM_NUM_OF_CTRL; i++) ++ { ++ p_MonRegs = (t_FmTrbRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_TRB(i)); ++ WRITE_UINT32(p_MonRegs->tcrh, TRB_TCRH_DISABLE_COUNTERS); ++ } ++ ++ WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc, ++ GET_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc) & ~FPM_BRKC_RDBG); ++ ++ return E_OK; ++} ++ ++t_Error FM_CtrlMonGetCounters(t_Handle h_Fm, uint8_t fmCtrlIndex, t_FmCtrlMon *p_Mon) ++{ ++ t_Fm *p_Fm = (t_Fm *)h_Fm; ++ t_FmTrbRegs *p_MonRegs; ++ uint64_t clkCnt, utilValue, effValue; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); ++ SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); ++ SANITY_CHECK_RETURN_ERROR(p_Mon, E_NULL_POINTER); ++ ++ if (fmCtrlIndex >= FM_NUM_OF_CTRL) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("FM Controller index")); ++ ++ p_MonRegs = (t_FmTrbRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_TRB(fmCtrlIndex)); ++ ++ clkCnt = (uint64_t) ++ ((uint64_t)GET_UINT32(p_MonRegs->tpcch) << 32 | GET_UINT32(p_MonRegs->tpccl)); ++ ++ utilValue = (uint64_t) ++ ((uint64_t)GET_UINT32(p_MonRegs->tpc1h) << 32 | GET_UINT32(p_MonRegs->tpc1l)); ++ ++ effValue = (uint64_t) ++ ((uint64_t)GET_UINT32(p_MonRegs->tpc2h) << 32 | GET_UINT32(p_MonRegs->tpc2l)); ++ ++ p_Mon->percentCnt[0] = (uint8_t)div64_u64((clkCnt - utilValue) * 100, clkCnt); ++ if (clkCnt != utilValue) ++ p_Mon->percentCnt[1] = (uint8_t)div64_u64(((clkCnt - utilValue) - effValue) * 100, clkCnt - utilValue); ++ else ++ p_Mon->percentCnt[1] = 0; ++ ++ return E_OK; ++} ++ ++t_Handle FM_GetMuramHandle(t_Handle h_Fm) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ ++ SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, NULL); ++ ++ return (p_Fm->h_FmMuram); ++} ++ ++/****************************************************/ ++/* Hidden-DEBUG Only API */ ++/****************************************************/ ++t_Error FM_ForceIntr (t_Handle h_Fm, e_FmExceptions exception) ++{ ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ enum fman_exceptions fslException; ++ struct fman_rg fman_rg; ++ ++ SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); ++ ++ fman_rg.bmi_rg = p_Fm->p_FmBmiRegs; ++ fman_rg.qmi_rg = p_Fm->p_FmQmiRegs; ++ fman_rg.fpm_rg = p_Fm->p_FmFpmRegs; ++ fman_rg.dma_rg = p_Fm->p_FmDmaRegs; ++ ++ switch (exception) ++ { ++ case e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID: ++ if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID)) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); ++ break; ++ case e_FM_EX_QMI_SINGLE_ECC: ++ if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) ++ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("e_FM_EX_QMI_SINGLE_ECC not supported on this integration.")); ++ ++ if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_SINGLE_ECC)) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); ++ break; ++ case e_FM_EX_QMI_DOUBLE_ECC: ++ if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_DOUBLE_ECC)) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); ++ break; ++ case e_FM_EX_BMI_LIST_RAM_ECC: ++ if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_LIST_RAM_ECC)) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); ++ break; ++ case e_FM_EX_BMI_STORAGE_PROFILE_ECC: ++ if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_STORAGE_PROFILE_ECC)) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); ++ break; ++ case e_FM_EX_BMI_STATISTICS_RAM_ECC: ++ if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_STATISTICS_RAM_ECC)) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); ++ break; ++ case e_FM_EX_BMI_DISPATCH_RAM_ECC: ++ if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_DISPATCH_RAM_ECC)) ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); ++ break; ++ default: ++ RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception may not be forced")); ++ } ++ ++ fslException = FmanExceptionTrans(exception); ++ fman_force_intr (&fman_rg, fslException); ++ ++ return E_OK; ++} ++ ++t_Handle FmGetPcd(t_Handle h_Fm) ++{ ++ return ((t_Fm*)h_Fm)->h_Pcd; ++} ++#if (DPAA_VERSION >= 11) ++extern void *g_MemacRegs; ++void fm_clk_down(void); ++uint32_t fman_memac_get_event(void *regs, uint32_t ev_mask); ++void FM_ChangeClock(t_Handle h_Fm, int hardwarePortId) ++{ ++ int macId; ++ uint32_t event, rcr; ++ t_Fm *p_Fm = (t_Fm*)h_Fm; ++ rcr = GET_UINT32(p_Fm->p_FmFpmRegs->fm_rcr); ++ rcr |= 0x04000000; ++ WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rcr, rcr); ++ ++ HW_PORT_ID_TO_SW_PORT_ID(macId, hardwarePortId); ++ do ++ { ++ event = fman_memac_get_event(g_MemacRegs, 0xFFFFFFFF); ++ } while ((event & 0x00000020) == 0); ++ fm_clk_down(); ++ rcr = GET_UINT32(p_Fm->p_FmFpmRegs->fm_rcr); ++ rcr &= ~0x04000000; ++ WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rcr, rcr); ++} ++#endif +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.h +new file mode 100644 +index 00000000..0bded75d +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.h +@@ -0,0 +1,648 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm.h ++ ++ @Description FM internal structures and definitions. ++*//***************************************************************************/ ++#ifndef __FM_H ++#define __FM_H ++ ++#include "error_ext.h" ++#include "std_ext.h" ++#include "fm_ext.h" ++#include "fm_ipc.h" ++ ++#include "fsl_fman.h" ++ ++#define __ERR_MODULE__ MODULE_FM ++ ++#define FM_MAX_NUM_OF_HW_PORT_IDS 64 ++#define FM_MAX_NUM_OF_GUESTS 100 ++ ++/**************************************************************************//** ++ @Description Exceptions ++*//***************************************************************************/ ++#define FM_EX_DMA_BUS_ERROR 0x80000000 /**< DMA bus error. */ ++#define FM_EX_DMA_READ_ECC 0x40000000 ++#define FM_EX_DMA_SYSTEM_WRITE_ECC 0x20000000 ++#define FM_EX_DMA_FM_WRITE_ECC 0x10000000 ++#define FM_EX_FPM_STALL_ON_TASKS 0x08000000 /**< Stall of tasks on FPM */ ++#define FM_EX_FPM_SINGLE_ECC 0x04000000 /**< Single ECC on FPM */ ++#define FM_EX_FPM_DOUBLE_ECC 0x02000000 ++#define FM_EX_QMI_SINGLE_ECC 0x01000000 /**< Single ECC on FPM */ ++#define FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID 0x00800000 /**< Dequeu from default queue id */ ++#define FM_EX_QMI_DOUBLE_ECC 0x00400000 ++#define FM_EX_BMI_LIST_RAM_ECC 0x00200000 ++#define FM_EX_BMI_STORAGE_PROFILE_ECC 0x00100000 ++#define FM_EX_BMI_STATISTICS_RAM_ECC 0x00080000 ++#define FM_EX_IRAM_ECC 0x00040000 ++#define FM_EX_MURAM_ECC 0x00020000 ++#define FM_EX_BMI_DISPATCH_RAM_ECC 0x00010000 ++#define FM_EX_DMA_SINGLE_PORT_ECC 0x00008000 ++ ++#define DMA_EMSR_EMSTR_MASK 0x0000FFFF ++ ++#define DMA_THRESH_COMMQ_MASK 0xFF000000 ++#define DMA_THRESH_READ_INT_BUF_MASK 0x007F0000 ++#define DMA_THRESH_WRITE_INT_BUF_MASK 0x0000007F ++ ++#define GET_EXCEPTION_FLAG(bitMask, exception) \ ++switch (exception){ \ ++ case e_FM_EX_DMA_BUS_ERROR: \ ++ bitMask = FM_EX_DMA_BUS_ERROR; break; \ ++ case e_FM_EX_DMA_SINGLE_PORT_ECC: \ ++ bitMask = FM_EX_DMA_SINGLE_PORT_ECC; break; \ ++ case e_FM_EX_DMA_READ_ECC: \ ++ bitMask = FM_EX_DMA_READ_ECC; break; \ ++ case e_FM_EX_DMA_SYSTEM_WRITE_ECC: \ ++ bitMask = FM_EX_DMA_SYSTEM_WRITE_ECC; break; \ ++ case e_FM_EX_DMA_FM_WRITE_ECC: \ ++ bitMask = FM_EX_DMA_FM_WRITE_ECC; break; \ ++ case e_FM_EX_FPM_STALL_ON_TASKS: \ ++ bitMask = FM_EX_FPM_STALL_ON_TASKS; break; \ ++ case e_FM_EX_FPM_SINGLE_ECC: \ ++ bitMask = FM_EX_FPM_SINGLE_ECC; break; \ ++ case e_FM_EX_FPM_DOUBLE_ECC: \ ++ bitMask = FM_EX_FPM_DOUBLE_ECC; break; \ ++ case e_FM_EX_QMI_SINGLE_ECC: \ ++ bitMask = FM_EX_QMI_SINGLE_ECC; break; \ ++ case e_FM_EX_QMI_DOUBLE_ECC: \ ++ bitMask = FM_EX_QMI_DOUBLE_ECC; break; \ ++ case e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID: \ ++ bitMask = FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID; break; \ ++ case e_FM_EX_BMI_LIST_RAM_ECC: \ ++ bitMask = FM_EX_BMI_LIST_RAM_ECC; break; \ ++ case e_FM_EX_BMI_STORAGE_PROFILE_ECC: \ ++ bitMask = FM_EX_BMI_STORAGE_PROFILE_ECC; break; \ ++ case e_FM_EX_BMI_STATISTICS_RAM_ECC: \ ++ bitMask = FM_EX_BMI_STATISTICS_RAM_ECC; break; \ ++ case e_FM_EX_BMI_DISPATCH_RAM_ECC: \ ++ bitMask = FM_EX_BMI_DISPATCH_RAM_ECC; break; \ ++ case e_FM_EX_IRAM_ECC: \ ++ bitMask = FM_EX_IRAM_ECC; break; \ ++ case e_FM_EX_MURAM_ECC: \ ++ bitMask = FM_EX_MURAM_ECC; break; \ ++ default: bitMask = 0;break; \ ++} ++ ++#define GET_FM_MODULE_EVENT(_mod, _id, _intrType, _event) \ ++ switch (_mod) { \ ++ case e_FM_MOD_PRS: \ ++ if (_id) _event = e_FM_EV_DUMMY_LAST; \ ++ else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_PRS : e_FM_EV_PRS; \ ++ break; \ ++ case e_FM_MOD_KG: \ ++ if (_id) _event = e_FM_EV_DUMMY_LAST; \ ++ else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_KG : e_FM_EV_DUMMY_LAST; \ ++ break; \ ++ case e_FM_MOD_PLCR: \ ++ if (_id) _event = e_FM_EV_DUMMY_LAST; \ ++ else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_PLCR : e_FM_EV_PLCR; \ ++ break; \ ++ case e_FM_MOD_TMR: \ ++ if (_id) _event = e_FM_EV_DUMMY_LAST; \ ++ else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_DUMMY_LAST : e_FM_EV_TMR; \ ++ break; \ ++ case e_FM_MOD_10G_MAC: \ ++ if (_id >= FM_MAX_NUM_OF_10G_MACS) _event = e_FM_EV_DUMMY_LAST; \ ++ else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? (e_FM_EV_ERR_10G_MAC0 + _id) : (e_FM_EV_10G_MAC0 + _id); \ ++ break; \ ++ case e_FM_MOD_1G_MAC: \ ++ if (_id >= FM_MAX_NUM_OF_1G_MACS) _event = e_FM_EV_DUMMY_LAST; \ ++ else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? (e_FM_EV_ERR_1G_MAC0 + _id) : (e_FM_EV_1G_MAC0 + _id); \ ++ break; \ ++ case e_FM_MOD_MACSEC: \ ++ switch (_id){ \ ++ case (0): _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_MACSEC_MAC0:e_FM_EV_MACSEC_MAC0; \ ++ break; \ ++ } \ ++ break; \ ++ case e_FM_MOD_FMAN_CTRL: \ ++ if (_intrType == e_FM_INTR_TYPE_ERR) _event = e_FM_EV_DUMMY_LAST; \ ++ else _event = (e_FM_EV_FMAN_CTRL_0 + _id); \ ++ break; \ ++ default: _event = e_FM_EV_DUMMY_LAST; \ ++ break; \ ++ } ++ ++#define FMAN_CACHE_OVERRIDE_TRANS(fsl_cache_override, _cache_override) \ ++ switch (_cache_override){ \ ++ case e_FM_DMA_NO_CACHE_OR: \ ++ fsl_cache_override = E_FMAN_DMA_NO_CACHE_OR; break; \ ++ case e_FM_DMA_NO_STASH_DATA: \ ++ fsl_cache_override = E_FMAN_DMA_NO_STASH_DATA; break; \ ++ case e_FM_DMA_MAY_STASH_DATA: \ ++ fsl_cache_override = E_FMAN_DMA_MAY_STASH_DATA; break; \ ++ case e_FM_DMA_STASH_DATA: \ ++ fsl_cache_override = E_FMAN_DMA_STASH_DATA; break; \ ++ default: \ ++ fsl_cache_override = E_FMAN_DMA_NO_CACHE_OR; break; \ ++ } ++ ++#define FMAN_AID_MODE_TRANS(fsl_aid_mode, _aid_mode) \ ++ switch (_aid_mode){ \ ++ case e_FM_DMA_AID_OUT_PORT_ID: \ ++ fsl_aid_mode = E_FMAN_DMA_AID_OUT_PORT_ID; break; \ ++ case e_FM_DMA_AID_OUT_TNUM: \ ++ fsl_aid_mode = E_FMAN_DMA_AID_OUT_TNUM; break; \ ++ default: \ ++ fsl_aid_mode = E_FMAN_DMA_AID_OUT_PORT_ID; break; \ ++ } ++ ++#define FMAN_DMA_DBG_CNT_TRANS(fsl_dma_dbg_cnt, _dma_dbg_cnt) \ ++ switch (_dma_dbg_cnt){ \ ++ case e_FM_DMA_DBG_NO_CNT: \ ++ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_NO_CNT; break; \ ++ case e_FM_DMA_DBG_CNT_DONE: \ ++ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_DONE; break; \ ++ case e_FM_DMA_DBG_CNT_COMM_Q_EM: \ ++ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_COMM_Q_EM; break; \ ++ case e_FM_DMA_DBG_CNT_INT_READ_EM: \ ++ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_INT_READ_EM; break; \ ++ case e_FM_DMA_DBG_CNT_INT_WRITE_EM: \ ++ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_INT_WRITE_EM ; break; \ ++ case e_FM_DMA_DBG_CNT_FPM_WAIT: \ ++ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_FPM_WAIT ; break; \ ++ case e_FM_DMA_DBG_CNT_SIGLE_BIT_ECC: \ ++ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_SIGLE_BIT_ECC ; break; \ ++ case e_FM_DMA_DBG_CNT_RAW_WAR_PROT: \ ++ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_RAW_WAR_PROT ; break; \ ++ default: \ ++ fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_NO_CNT; break; \ ++ } ++ ++#define FMAN_DMA_EMER_TRANS(fsl_dma_emer, _dma_emer) \ ++ switch (_dma_emer){ \ ++ case e_FM_DMA_EM_EBS: \ ++ fsl_dma_emer = E_FMAN_DMA_EM_EBS; break; \ ++ case e_FM_DMA_EM_SOS: \ ++ fsl_dma_emer = E_FMAN_DMA_EM_SOS; break; \ ++ default: \ ++ fsl_dma_emer = E_FMAN_DMA_EM_EBS; break; \ ++ } ++ ++#define FMAN_DMA_ERR_TRANS(fsl_dma_err, _dma_err) \ ++ switch (_dma_err){ \ ++ case e_FM_DMA_ERR_CATASTROPHIC: \ ++ fsl_dma_err = E_FMAN_DMA_ERR_CATASTROPHIC; break; \ ++ case e_FM_DMA_ERR_REPORT: \ ++ fsl_dma_err = E_FMAN_DMA_ERR_REPORT; break; \ ++ default: \ ++ fsl_dma_err = E_FMAN_DMA_ERR_CATASTROPHIC; break; \ ++ } ++ ++#define FMAN_CATASTROPHIC_ERR_TRANS(fsl_catastrophic_err, _catastrophic_err) \ ++ switch (_catastrophic_err){ \ ++ case e_FM_CATASTROPHIC_ERR_STALL_PORT: \ ++ fsl_catastrophic_err = E_FMAN_CATAST_ERR_STALL_PORT; break; \ ++ case e_FM_CATASTROPHIC_ERR_STALL_TASK: \ ++ fsl_catastrophic_err = E_FMAN_CATAST_ERR_STALL_TASK; break; \ ++ default: \ ++ fsl_catastrophic_err = E_FMAN_CATAST_ERR_STALL_PORT; break; \ ++ } ++ ++#define FMAN_COUNTERS_TRANS(fsl_counters, _counters) \ ++ switch (_counters){ \ ++ case e_FM_COUNTERS_ENQ_TOTAL_FRAME: \ ++ fsl_counters = E_FMAN_COUNTERS_ENQ_TOTAL_FRAME; break; \ ++ case e_FM_COUNTERS_DEQ_TOTAL_FRAME: \ ++ fsl_counters = E_FMAN_COUNTERS_DEQ_TOTAL_FRAME; break; \ ++ case e_FM_COUNTERS_DEQ_0: \ ++ fsl_counters = E_FMAN_COUNTERS_DEQ_0; break; \ ++ case e_FM_COUNTERS_DEQ_1: \ ++ fsl_counters = E_FMAN_COUNTERS_DEQ_1; break; \ ++ case e_FM_COUNTERS_DEQ_2: \ ++ fsl_counters = E_FMAN_COUNTERS_DEQ_2; break; \ ++ case e_FM_COUNTERS_DEQ_3: \ ++ fsl_counters = E_FMAN_COUNTERS_DEQ_3; break; \ ++ case e_FM_COUNTERS_DEQ_FROM_DEFAULT: \ ++ fsl_counters = E_FMAN_COUNTERS_DEQ_FROM_DEFAULT; break; \ ++ case e_FM_COUNTERS_DEQ_FROM_CONTEXT: \ ++ fsl_counters = E_FMAN_COUNTERS_DEQ_FROM_CONTEXT; break; \ ++ case e_FM_COUNTERS_DEQ_FROM_FD: \ ++ fsl_counters = E_FMAN_COUNTERS_DEQ_FROM_FD; break; \ ++ case e_FM_COUNTERS_DEQ_CONFIRM: \ ++ fsl_counters = E_FMAN_COUNTERS_DEQ_CONFIRM; break; \ ++ default: \ ++ fsl_counters = E_FMAN_COUNTERS_ENQ_TOTAL_FRAME; break; \ ++ } ++ ++/**************************************************************************//** ++ @Description defaults ++*//***************************************************************************/ ++#define DEFAULT_exceptions (FM_EX_DMA_BUS_ERROR |\ ++ FM_EX_DMA_READ_ECC |\ ++ FM_EX_DMA_SYSTEM_WRITE_ECC |\ ++ FM_EX_DMA_FM_WRITE_ECC |\ ++ FM_EX_FPM_STALL_ON_TASKS |\ ++ FM_EX_FPM_SINGLE_ECC |\ ++ FM_EX_FPM_DOUBLE_ECC |\ ++ FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID|\ ++ FM_EX_BMI_LIST_RAM_ECC |\ ++ FM_EX_BMI_STORAGE_PROFILE_ECC |\ ++ FM_EX_BMI_STATISTICS_RAM_ECC |\ ++ FM_EX_IRAM_ECC |\ ++ FM_EX_MURAM_ECC |\ ++ FM_EX_BMI_DISPATCH_RAM_ECC |\ ++ FM_EX_QMI_DOUBLE_ECC |\ ++ FM_EX_QMI_SINGLE_ECC) ++ ++#define DEFAULT_eccEnable FALSE ++#ifdef FM_PEDANTIC_DMA ++#define DEFAULT_aidOverride TRUE ++#else ++#define DEFAULT_aidOverride FALSE ++#endif /* FM_PEDANTIC_DMA */ ++#define DEFAULT_aidMode e_FM_DMA_AID_OUT_TNUM ++#define DEFAULT_dmaStopOnBusError FALSE ++#define DEFAULT_stopAtBusError FALSE ++#define DEFAULT_axiDbgNumOfBeats 1 ++#define DEFAULT_dmaReadIntBufLow ((DMA_THRESH_MAX_BUF+1)/2) ++#define DEFAULT_dmaReadIntBufHigh ((DMA_THRESH_MAX_BUF+1)*3/4) ++#define DEFAULT_dmaWriteIntBufLow ((DMA_THRESH_MAX_BUF+1)/2) ++#define DEFAULT_dmaWriteIntBufHigh ((DMA_THRESH_MAX_BUF+1)*3/4) ++#define DEFAULT_catastrophicErr e_FM_CATASTROPHIC_ERR_STALL_PORT ++#define DEFAULT_dmaErr e_FM_DMA_ERR_CATASTROPHIC ++#define DEFAULT_resetOnInit FALSE ++#define DEFAULT_resetOnInitOverrideCallback NULL ++#define DEFAULT_haltOnExternalActivation FALSE /* do not change! if changed, must be disabled for rev1 ! */ ++#define DEFAULT_haltOnUnrecoverableEccError FALSE /* do not change! if changed, must be disabled for rev1 ! */ ++#define DEFAULT_externalEccRamsEnable FALSE ++#define DEFAULT_VerifyUcode FALSE ++ ++#if (DPAA_VERSION < 11) ++#define DEFAULT_totalFifoSize(major, minor) \ ++ (((major == 2) || (major == 5)) ? \ ++ (100*KILOBYTE) : ((major == 4) ? \ ++ (49*KILOBYTE) : (122*KILOBYTE))) ++#define DEFAULT_totalNumOfTasks(major, minor) \ ++ BMI_MAX_NUM_OF_TASKS ++ ++#define DEFAULT_dmaCommQLow ((DMA_THRESH_MAX_COMMQ+1)/2) ++#define DEFAULT_dmaCommQHigh ((DMA_THRESH_MAX_COMMQ+1)*3/4) ++#define DEFAULT_cacheOverride e_FM_DMA_NO_CACHE_OR ++#define DEFAULT_dmaCamNumOfEntries 32 ++#define DEFAULT_dmaDbgCntMode e_FM_DMA_DBG_NO_CNT ++#define DEFAULT_dmaEnEmergency FALSE ++#define DEFAULT_dmaSosEmergency 0 ++#define DEFAULT_dmaWatchdog 0 /* disabled */ ++#define DEFAULT_dmaEnEmergencySmoother FALSE ++#define DEFAULT_dmaEmergencySwitchCounter 0 ++ ++#define DEFAULT_dispLimit 0 ++#define DEFAULT_prsDispTh 16 ++#define DEFAULT_plcrDispTh 16 ++#define DEFAULT_kgDispTh 16 ++#define DEFAULT_bmiDispTh 16 ++#define DEFAULT_qmiEnqDispTh 16 ++#define DEFAULT_qmiDeqDispTh 16 ++#define DEFAULT_fmCtl1DispTh 16 ++#define DEFAULT_fmCtl2DispTh 16 ++ ++#else /* (DPAA_VERSION < 11) */ ++/* Defaults are registers' reset values */ ++#define DEFAULT_totalFifoSize(major, minor) \ ++ (((major == 6) && ((minor == 1) || (minor == 4))) ? \ ++ (156*KILOBYTE) : (295*KILOBYTE)) ++ ++/* According to the default value of FMBM_CFG2[TNTSKS] */ ++#define DEFAULT_totalNumOfTasks(major, minor) \ ++ (((major == 6) && ((minor == 1) || (minor == 4))) ? 59 : 124) ++ ++#define DEFAULT_dmaCommQLow 0x2A ++#define DEFAULT_dmaCommQHigh 0x3F ++#define DEFAULT_cacheOverride e_FM_DMA_NO_CACHE_OR ++#define DEFAULT_dmaCamNumOfEntries 64 ++#define DEFAULT_dmaDbgCntMode e_FM_DMA_DBG_NO_CNT ++#define DEFAULT_dmaEnEmergency FALSE ++#define DEFAULT_dmaSosEmergency 0 ++#define DEFAULT_dmaWatchdog 0 /* disabled */ ++#define DEFAULT_dmaEnEmergencySmoother FALSE ++#define DEFAULT_dmaEmergencySwitchCounter 0 ++ ++#define DEFAULT_dispLimit 0 ++#define DEFAULT_prsDispTh 16 ++#define DEFAULT_plcrDispTh 16 ++#define DEFAULT_kgDispTh 16 ++#define DEFAULT_bmiDispTh 16 ++#define DEFAULT_qmiEnqDispTh 16 ++#define DEFAULT_qmiDeqDispTh 16 ++#define DEFAULT_fmCtl1DispTh 16 ++#define DEFAULT_fmCtl2DispTh 16 ++#endif /* (DPAA_VERSION < 11) */ ++ ++#define FM_TIMESTAMP_1_USEC_BIT 8 ++ ++/**************************************************************************//** ++ @Collection Defines used for enabling/disabling FM interrupts ++ @{ ++*//***************************************************************************/ ++#define ERR_INTR_EN_DMA 0x00010000 ++#define ERR_INTR_EN_FPM 0x80000000 ++#define ERR_INTR_EN_BMI 0x00800000 ++#define ERR_INTR_EN_QMI 0x00400000 ++#define ERR_INTR_EN_PRS 0x00200000 ++#define ERR_INTR_EN_KG 0x00100000 ++#define ERR_INTR_EN_PLCR 0x00080000 ++#define ERR_INTR_EN_MURAM 0x00040000 ++#define ERR_INTR_EN_IRAM 0x00020000 ++#define ERR_INTR_EN_10G_MAC0 0x00008000 ++#define ERR_INTR_EN_10G_MAC1 0x00000040 ++#define ERR_INTR_EN_1G_MAC0 0x00004000 ++#define ERR_INTR_EN_1G_MAC1 0x00002000 ++#define ERR_INTR_EN_1G_MAC2 0x00001000 ++#define ERR_INTR_EN_1G_MAC3 0x00000800 ++#define ERR_INTR_EN_1G_MAC4 0x00000400 ++#define ERR_INTR_EN_1G_MAC5 0x00000200 ++#define ERR_INTR_EN_1G_MAC6 0x00000100 ++#define ERR_INTR_EN_1G_MAC7 0x00000080 ++#define ERR_INTR_EN_MACSEC_MAC0 0x00000001 ++ ++#define INTR_EN_QMI 0x40000000 ++#define INTR_EN_PRS 0x20000000 ++#define INTR_EN_WAKEUP 0x10000000 ++#define INTR_EN_PLCR 0x08000000 ++#define INTR_EN_1G_MAC0 0x00080000 ++#define INTR_EN_1G_MAC1 0x00040000 ++#define INTR_EN_1G_MAC2 0x00020000 ++#define INTR_EN_1G_MAC3 0x00010000 ++#define INTR_EN_1G_MAC4 0x00000040 ++#define INTR_EN_1G_MAC5 0x00000020 ++#define INTR_EN_1G_MAC6 0x00000008 ++#define INTR_EN_1G_MAC7 0x00000002 ++#define INTR_EN_10G_MAC0 0x00200000 ++#define INTR_EN_10G_MAC1 0x00100000 ++#define INTR_EN_REV0 0x00008000 ++#define INTR_EN_REV1 0x00004000 ++#define INTR_EN_REV2 0x00002000 ++#define INTR_EN_REV3 0x00001000 ++#define INTR_EN_BRK 0x00000080 ++#define INTR_EN_TMR 0x01000000 ++#define INTR_EN_MACSEC_MAC0 0x00000001 ++/* @} */ ++ ++/**************************************************************************//** ++ @Description Memory Mapped Registers ++*//***************************************************************************/ ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(push,1) ++#endif /* defined(__MWERKS__) && ... */ ++ ++typedef struct ++{ ++ volatile uint32_t iadd; /**< FM IRAM instruction address register */ ++ volatile uint32_t idata; /**< FM IRAM instruction data register */ ++ volatile uint32_t itcfg; /**< FM IRAM timing config register */ ++ volatile uint32_t iready; /**< FM IRAM ready register */ ++ volatile uint32_t res[0x1FFFC]; ++} t_FMIramRegs; ++ ++/* Trace buffer registers - ++ each FM Controller has its own trace buffer residing at FM_MM_TRB(fmCtrlIndex) offset */ ++typedef struct t_FmTrbRegs ++{ ++ volatile uint32_t tcrh; ++ volatile uint32_t tcrl; ++ volatile uint32_t tesr; ++ volatile uint32_t tecr0h; ++ volatile uint32_t tecr0l; ++ volatile uint32_t terf0h; ++ volatile uint32_t terf0l; ++ volatile uint32_t tecr1h; ++ volatile uint32_t tecr1l; ++ volatile uint32_t terf1h; ++ volatile uint32_t terf1l; ++ volatile uint32_t tpcch; ++ volatile uint32_t tpccl; ++ volatile uint32_t tpc1h; ++ volatile uint32_t tpc1l; ++ volatile uint32_t tpc2h; ++ volatile uint32_t tpc2l; ++ volatile uint32_t twdimr; ++ volatile uint32_t twicvr; ++ volatile uint32_t tar; ++ volatile uint32_t tdr; ++ volatile uint32_t tsnum1; ++ volatile uint32_t tsnum2; ++ volatile uint32_t tsnum3; ++ volatile uint32_t tsnum4; ++} t_FmTrbRegs; ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(pop) ++#endif /* defined(__MWERKS__) && ... */ ++ ++/**************************************************************************//** ++ @Description General defines ++*//***************************************************************************/ ++#define FM_DEBUG_STATUS_REGISTER_OFFSET 0x000d1084UL ++#define FM_FW_DEBUG_INSTRUCTION 0x6ffff805UL ++ ++/**************************************************************************//** ++ @Description FPM defines ++*//***************************************************************************/ ++/* masks */ ++#define FPM_BRKC_RDBG 0x00000200 ++#define FPM_BRKC_SLP 0x00000800 ++/**************************************************************************//** ++ @Description BMI defines ++*//***************************************************************************/ ++/* masks */ ++#define BMI_INIT_START 0x80000000 ++#define BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC 0x80000000 ++#define BMI_ERR_INTR_EN_LIST_RAM_ECC 0x40000000 ++#define BMI_ERR_INTR_EN_STATISTICS_RAM_ECC 0x20000000 ++#define BMI_ERR_INTR_EN_DISPATCH_RAM_ECC 0x10000000 ++/**************************************************************************//** ++ @Description QMI defines ++*//***************************************************************************/ ++/* masks */ ++#define QMI_ERR_INTR_EN_DOUBLE_ECC 0x80000000 ++#define QMI_ERR_INTR_EN_DEQ_FROM_DEF 0x40000000 ++#define QMI_INTR_EN_SINGLE_ECC 0x80000000 ++ ++/**************************************************************************//** ++ @Description IRAM defines ++*//***************************************************************************/ ++/* masks */ ++#define IRAM_IADD_AIE 0x80000000 ++#define IRAM_READY 0x80000000 ++ ++/**************************************************************************//** ++ @Description TRB defines ++*//***************************************************************************/ ++/* masks */ ++#define TRB_TCRH_RESET 0x04000000 ++#define TRB_TCRH_ENABLE_COUNTERS 0x84008000 ++#define TRB_TCRH_DISABLE_COUNTERS 0x8400C000 ++#define TRB_TCRL_RESET 0x20000000 ++#define TRB_TCRL_UTIL 0x00000460 ++typedef struct { ++ void (*f_Isr) (t_Handle h_Arg, uint32_t event); ++ t_Handle h_SrcHandle; ++} t_FmanCtrlIntrSrc; ++ ++ ++typedef void (t_FmanCtrlIsr)( t_Handle h_Fm, uint32_t event); ++ ++typedef struct ++{ ++/***************************/ ++/* Master/Guest parameters */ ++/***************************/ ++ uint8_t fmId; ++ e_FmPortType portsTypes[FM_MAX_NUM_OF_HW_PORT_IDS]; ++ uint16_t fmClkFreq; ++ uint16_t fmMacClkFreq; ++ t_FmRevisionInfo revInfo; ++/**************************/ ++/* Master Only parameters */ ++/**************************/ ++ bool enabledTimeStamp; ++ uint8_t count1MicroBit; ++ uint8_t totalNumOfTasks; ++ uint32_t totalFifoSize; ++ uint8_t maxNumOfOpenDmas; ++ uint8_t accumulatedNumOfTasks; ++ uint32_t accumulatedFifoSize; ++ uint8_t accumulatedNumOfOpenDmas; ++ uint8_t accumulatedNumOfDeqTnums; ++#ifdef FM_LOW_END_RESTRICTION ++ bool lowEndRestriction; ++#endif /* FM_LOW_END_RESTRICTION */ ++ uint32_t exceptions; ++ int irq; ++ int errIrq; ++ bool ramsEccEnable; ++ bool explicitEnable; ++ bool internalCall; ++ uint8_t ramsEccOwners; ++ uint32_t extraFifoPoolSize; ++ uint8_t extraTasksPoolSize; ++ uint8_t extraOpenDmasPoolSize; ++#if defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS) ++ uint16_t portMaxFrameLengths10G[FM_MAX_NUM_OF_10G_MACS]; ++ uint16_t macMaxFrameLengths10G[FM_MAX_NUM_OF_10G_MACS]; ++#endif /* defined(FM_MAX_NUM_OF_10G_MACS) && ... */ ++ uint16_t portMaxFrameLengths1G[FM_MAX_NUM_OF_1G_MACS]; ++ uint16_t macMaxFrameLengths1G[FM_MAX_NUM_OF_1G_MACS]; ++} t_FmStateStruct; ++ ++#if (DPAA_VERSION >= 11) ++typedef struct t_FmMapParam { ++ uint16_t profilesBase; ++ uint16_t numOfProfiles; ++ t_Handle h_FmPort; ++} t_FmMapParam; ++ ++typedef struct t_FmAllocMng { ++ bool allocated; ++ uint8_t ownerId; /* guestId for KG in multi-partition only, ++ portId for PLCR in any environment */ ++} t_FmAllocMng; ++ ++typedef struct t_FmPcdSpEntry { ++ bool valid; ++ t_FmAllocMng profilesMng; ++} t_FmPcdSpEntry; ++ ++typedef struct t_FmSp { ++ void *p_FmPcdStoragePrflRegs; ++ t_FmPcdSpEntry profiles[FM_VSP_MAX_NUM_OF_ENTRIES]; ++ t_FmMapParam portsMapping[FM_MAX_NUM_OF_PORTS]; ++} t_FmSp; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++typedef struct t_Fm ++{ ++/***************************/ ++/* Master/Guest parameters */ ++/***************************/ ++/* locals for recovery */ ++ uintptr_t baseAddr; ++ ++/* un-needed for recovery */ ++ t_Handle h_Pcd; ++ char fmModuleName[MODULE_NAME_SIZE]; ++ char fmIpcHandlerModuleName[FM_MAX_NUM_OF_GUESTS][MODULE_NAME_SIZE]; ++ t_Handle h_IpcSessions[FM_MAX_NUM_OF_GUESTS]; ++ t_FmIntrSrc intrMng[e_FM_EV_DUMMY_LAST]; /* FM exceptions user callback */ ++ uint8_t guestId; ++/**************************/ ++/* Master Only parameters */ ++/**************************/ ++/* locals for recovery */ ++ struct fman_fpm_regs *p_FmFpmRegs; ++ struct fman_bmi_regs *p_FmBmiRegs; ++ struct fman_qmi_regs *p_FmQmiRegs; ++ struct fman_dma_regs *p_FmDmaRegs; ++ struct fman_regs *p_FmRegs; ++ t_FmExceptionsCallback *f_Exception; ++ t_FmBusErrorCallback *f_BusError; ++ t_Handle h_App; /* Application handle */ ++ t_Handle h_Spinlock; ++ bool recoveryMode; ++ t_FmStateStruct *p_FmStateStruct; ++ uint16_t tnumAgingPeriod; ++#if (DPAA_VERSION >= 11) ++ t_FmSp *p_FmSp; ++ uint8_t partNumOfVSPs; ++ uint8_t partVSPBase; ++ uintptr_t vspBaseAddr; ++#endif /* (DPAA_VERSION >= 11) */ ++ bool portsPreFetchConfigured[FM_MAX_NUM_OF_HW_PORT_IDS]; /* Prefetch configration per Tx-port */ ++ bool portsPreFetchValue[FM_MAX_NUM_OF_HW_PORT_IDS]; /* Prefetch configration per Tx-port */ ++ ++/* un-needed for recovery */ ++ struct fman_cfg *p_FmDriverParam; ++ t_Handle h_FmMuram; ++ uint64_t fmMuramPhysBaseAddr; ++ bool independentMode; ++ bool hcPortInitialized; ++ uintptr_t camBaseAddr; /* save for freeing */ ++ uintptr_t resAddr; ++ uintptr_t fifoBaseAddr; /* save for freeing */ ++ t_FmanCtrlIntrSrc fmanCtrlIntr[FM_NUM_OF_FMAN_CTRL_EVENT_REGS]; /* FM exceptions user callback */ ++ bool usedEventRegs[FM_NUM_OF_FMAN_CTRL_EVENT_REGS]; ++ t_FmFirmwareParams firmware; ++ bool fwVerify; ++ bool resetOnInit; ++ t_FmResetOnInitOverrideCallback *f_ResetOnInitOverride; ++ uint32_t userSetExceptions; ++} t_Fm; ++ ++ ++#endif /* __FM_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_ipc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_ipc.h +new file mode 100644 +index 00000000..7ce36a76 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_ipc.h +@@ -0,0 +1,465 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File fm_ipc.h ++ ++ @Description FM Inter-Partition prototypes, structures and definitions. ++*//***************************************************************************/ ++#ifndef __FM_IPC_H ++#define __FM_IPC_H ++ ++#include "error_ext.h" ++#include "std_ext.h" ++ ++ ++/**************************************************************************//** ++ @Group FM_grp Frame Manager API ++ ++ @Description FM API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group FM_IPC_grp FM Inter-Partition messaging Unit ++ ++ @Description FM Inter-Partition messaging unit API definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(push,1) ++#endif /* defined(__MWERKS__) && ... */ ++ ++/**************************************************************************//** ++ @Description enum for defining MAC types ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description A structure of parameters for specifying a MAC. ++*//***************************************************************************/ ++typedef _Packed struct ++{ ++ uint8_t id; ++ uint32_t enumType; ++} _PackedType t_FmIpcMacParams; ++ ++/**************************************************************************//** ++ @Description A structure of parameters for specifying a MAC. ++*//***************************************************************************/ ++typedef _Packed struct ++{ ++ t_FmIpcMacParams macParams; ++ uint16_t maxFrameLength; ++} _PackedType t_FmIpcMacMaxFrameParams; ++ ++/**************************************************************************//** ++ @Description FM physical Address ++*//***************************************************************************/ ++typedef _Packed struct t_FmIpcPhysAddr ++{ ++ volatile uint8_t high; ++ volatile uint32_t low; ++} _PackedType t_FmIpcPhysAddr; ++ ++ ++typedef _Packed struct t_FmIpcPortOutInitParams { ++ uint8_t numOfTasks; /**< OUT */ ++ uint8_t numOfExtraTasks; /**< OUT */ ++ uint8_t numOfOpenDmas; /**< OUT */ ++ uint8_t numOfExtraOpenDmas; /**< OUT */ ++ uint32_t sizeOfFifo; /**< OUT */ ++ uint32_t extraSizeOfFifo; /**< OUT */ ++ t_FmIpcPhysAddr ipcPhysAddr; /**< OUT */ ++} _PackedType t_FmIpcPortOutInitParams; ++ ++/**************************************************************************//** ++ @Description Structure for IPC communication during FM_PORT_Init. ++*//***************************************************************************/ ++typedef _Packed struct t_FmIpcPortInInitParams { ++ uint8_t hardwarePortId; /**< IN. port Id */ ++ uint32_t enumPortType; /**< IN. Port type */ ++ uint8_t boolIndependentMode;/**< IN. TRUE if FM Port operates in independent mode */ ++ uint16_t liodnOffset; /**< IN. Port's requested resource */ ++ uint8_t numOfTasks; /**< IN. Port's requested resource */ ++ uint8_t numOfExtraTasks; /**< IN. Port's requested resource */ ++ uint8_t numOfOpenDmas; /**< IN. Port's requested resource */ ++ uint8_t numOfExtraOpenDmas; /**< IN. Port's requested resource */ ++ uint32_t sizeOfFifo; /**< IN. Port's requested resource */ ++ uint32_t extraSizeOfFifo; /**< IN. Port's requested resource */ ++ uint8_t deqPipelineDepth; /**< IN. Port's requested resource */ ++ uint16_t maxFrameLength; /**< IN. Port's max frame length. */ ++ uint16_t liodnBase; /**< IN. Irrelevant for P4080 rev 1. ++ LIODN base for this port, to be ++ used together with LIODN offset. */ ++} _PackedType t_FmIpcPortInInitParams; ++ ++ ++/**************************************************************************//** ++ @Description Structure for IPC communication between port and FM ++ regarding tasks and open DMA resources management. ++*//***************************************************************************/ ++typedef _Packed struct t_FmIpcPortRsrcParams { ++ uint8_t hardwarePortId; /**< IN. port Id */ ++ uint32_t val; /**< IN. Port's requested resource */ ++ uint32_t extra; /**< IN. Port's requested resource */ ++ uint8_t boolInitialConfig; ++} _PackedType t_FmIpcPortRsrcParams; ++ ++ ++/**************************************************************************//** ++ @Description Structure for IPC communication between port and FM ++ regarding tasks and open DMA resources management. ++*//***************************************************************************/ ++typedef _Packed struct t_FmIpcPortFifoParams { ++ t_FmIpcPortRsrcParams rsrcParams; ++ uint32_t enumPortType; ++ uint8_t boolIndependentMode; ++ uint8_t deqPipelineDepth; ++ uint8_t numOfPools; ++ uint16_t secondLargestBufSize; ++ uint16_t largestBufSize; ++ uint8_t boolInitialConfig; ++} _PackedType t_FmIpcPortFifoParams; ++ ++/**************************************************************************//** ++ @Description Structure for port-FM communication during FM_PORT_Free. ++*//***************************************************************************/ ++typedef _Packed struct t_FmIpcPortFreeParams { ++ uint8_t hardwarePortId; /**< IN. port Id */ ++ uint32_t enumPortType; /**< IN. Port type */ ++ uint8_t deqPipelineDepth; /**< IN. Port's requested resource */ ++} _PackedType t_FmIpcPortFreeParams; ++ ++/**************************************************************************//** ++ @Description Structure for defining DMA status ++*//***************************************************************************/ ++typedef _Packed struct t_FmIpcDmaStatus { ++ uint8_t boolCmqNotEmpty; /**< Command queue is not empty */ ++ uint8_t boolBusError; /**< Bus error occurred */ ++ uint8_t boolReadBufEccError; /**< Double ECC error on buffer Read */ ++ uint8_t boolWriteBufEccSysError; /**< Double ECC error on buffer write from system side */ ++ uint8_t boolWriteBufEccFmError; /**< Double ECC error on buffer write from FM side */ ++ uint8_t boolSinglePortEccError; /**< Single port ECC error from FM side */ ++} _PackedType t_FmIpcDmaStatus; ++ ++typedef _Packed struct t_FmIpcRegisterIntr ++{ ++ uint8_t guestId; /* IN */ ++ uint32_t event; /* IN */ ++} _PackedType t_FmIpcRegisterIntr; ++ ++typedef _Packed struct t_FmIpcIsr ++{ ++ uint8_t boolErr; /* IN */ ++ uint32_t pendingReg; /* IN */ ++} _PackedType t_FmIpcIsr; ++ ++/**************************************************************************//** ++ @Description structure for returning FM parameters ++*//***************************************************************************/ ++typedef _Packed struct t_FmIpcParams { ++ uint16_t fmClkFreq; /**< OUT: FM Clock frequency */ ++ uint16_t fmMacClkFreq; /**< OUT: FM MAC clock frequence */ ++ uint8_t majorRev; /**< OUT: FM Major revision */ ++ uint8_t minorRev; /**< OUT: FM Minor revision */ ++} _PackedType t_FmIpcParams; ++ ++ ++/**************************************************************************//** ++ @Description structure for returning Fman Ctrl Code revision information ++*//***************************************************************************/ ++typedef _Packed struct t_FmIpcFmanCtrlCodeRevisionInfo { ++ uint16_t packageRev; /**< OUT: Package revision */ ++ uint8_t majorRev; /**< OUT: Major revision */ ++ uint8_t minorRev; /**< OUT: Minor revision */ ++} _PackedType t_FmIpcFmanCtrlCodeRevisionInfo; ++ ++/**************************************************************************//** ++ @Description Structure for defining Fm number of Fman controlers ++*//***************************************************************************/ ++typedef _Packed struct t_FmIpcPortNumOfFmanCtrls { ++ uint8_t hardwarePortId; /**< IN. port Id */ ++ uint8_t numOfFmanCtrls; /**< IN. Port type */ ++ t_FmFmanCtrl orFmanCtrl; /**< IN. fman controller for order restoration*/ ++} t_FmIpcPortNumOfFmanCtrls; ++ ++/**************************************************************************//** ++ @Description structure for setting Fman contriller events ++*//***************************************************************************/ ++typedef _Packed struct t_FmIpcFmanEvents { ++ uint8_t eventRegId; /**< IN: Fman controller event register id */ ++ uint32_t enableEvents; /**< IN/OUT: required enabled events mask */ ++} _PackedType t_FmIpcFmanEvents; ++ ++typedef _Packed struct t_FmIpcResourceAllocParams { ++ uint8_t guestId; ++ uint16_t base; ++ uint16_t num; ++}_PackedType t_FmIpcResourceAllocParams; ++ ++typedef _Packed struct t_FmIpcVspSetPortWindow { ++ uint8_t hardwarePortId; ++ uint8_t baseStorageProfile; ++ uint8_t log2NumOfProfiles; ++}_PackedType t_FmIpcVspSetPortWindow; ++ ++typedef _Packed struct t_FmIpcSetCongestionGroupPfcPriority { ++ uint32_t congestionGroupId; ++ uint8_t priorityBitMap; ++}_PackedType t_FmIpcSetCongestionGroupPfcPriority; ++ ++#define FM_IPC_MAX_REPLY_BODY_SIZE 20 ++#define FM_IPC_MAX_REPLY_SIZE (FM_IPC_MAX_REPLY_BODY_SIZE + sizeof(uint32_t)) ++#define FM_IPC_MAX_MSG_SIZE 30 ++ ++typedef _Packed struct t_FmIpcMsg ++{ ++ uint32_t msgId; ++ uint8_t msgBody[FM_IPC_MAX_MSG_SIZE]; ++} _PackedType t_FmIpcMsg; ++ ++typedef _Packed struct t_FmIpcReply ++{ ++ uint32_t error; ++ uint8_t replyBody[FM_IPC_MAX_REPLY_BODY_SIZE]; ++} _PackedType t_FmIpcReply; ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(pop) ++#endif /* defined(__MWERKS__) && ... */ ++ ++ ++/***************************************************************************/ ++/************************ FRONT-END-TO-BACK-END*****************************/ ++/***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function FM_GET_TIMESTAMP_SCALE ++ ++ @Description Used by FM front-end. ++ ++ @Param[out] uint32_t Pointer ++*//***************************************************************************/ ++#define FM_GET_TIMESTAMP_SCALE 1 ++ ++/**************************************************************************//** ++ @Function FM_GET_COUNTER ++ ++ @Description Used by FM front-end. ++ ++ @Param[in/out] t_FmIpcGetCounter Pointer ++*//***************************************************************************/ ++#define FM_GET_COUNTER 2 ++ ++/**************************************************************************//** ++ @Function FM_GET_SET_PORT_PARAMS ++ ++ @Description Used by FM front-end for the PORT module in order to set and get ++ parameters in/from master FM module on FM PORT initialization time. ++ ++ @Param[in/out] t_FmIcPortInitParams Pointer ++*//***************************************************************************/ ++#define FM_GET_SET_PORT_PARAMS 4 ++ ++/**************************************************************************//** ++ @Function FM_FREE_PORT ++ ++ @Description Used by FM front-end for the PORT module when a port is freed ++ to free all FM PORT resources. ++ ++ @Param[in] uint8_t Pointer ++*//***************************************************************************/ ++#define FM_FREE_PORT 5 ++ ++/**************************************************************************//** ++ @Function FM_RESET_MAC ++ ++ @Description Used by front-end for the MAC module to reset the MAC registers ++ ++ @Param[in] t_FmIpcMacParams Pointer . ++*//***************************************************************************/ ++#define FM_RESET_MAC 6 ++ ++/**************************************************************************//** ++ @Function FM_RESUME_STALLED_PORT ++ ++ @Description Used by FM front-end for the PORT module in order to ++ release a stalled FM Port. ++ ++ @Param[in] uint8_t Pointer ++*//***************************************************************************/ ++#define FM_RESUME_STALLED_PORT 7 ++ ++/**************************************************************************//** ++ @Function FM_IS_PORT_STALLED ++ ++ @Description Used by FM front-end for the PORT module in order to check whether ++ an FM port is stalled. ++ ++ @Param[in/out] t_FmIcPortIsStalled Pointer ++*//***************************************************************************/ ++#define FM_IS_PORT_STALLED 8 ++ ++/**************************************************************************//** ++ @Function FM_GET_PARAMS ++ ++ @Description Used by FM front-end for the PORT module in order to dump ++ return FM parameters. ++ ++ @Param[in] uint8_t Pointer ++*//***************************************************************************/ ++#define FM_GET_PARAMS 10 ++ ++/**************************************************************************//** ++ @Function FM_REGISTER_INTR ++ ++ @Description Used by FM front-end to register an interrupt handler to ++ be called upon interrupt for guest. ++ ++ @Param[out] t_FmIpcRegisterIntr Pointer ++*//***************************************************************************/ ++#define FM_REGISTER_INTR 11 ++ ++/**************************************************************************//** ++ @Function FM_DMA_STAT ++ ++ @Description Used by FM front-end to read the FM DMA status. ++ ++ @Param[out] t_FmIpcDmaStatus Pointer ++*//***************************************************************************/ ++#define FM_DMA_STAT 13 ++ ++/**************************************************************************//** ++ @Function FM_ALLOC_FMAN_CTRL_EVENT_REG ++ ++ @Description Used by FM front-end to allocate event register. ++ ++ @Param[out] Event register id Pointer ++*//***************************************************************************/ ++#define FM_ALLOC_FMAN_CTRL_EVENT_REG 14 ++ ++/**************************************************************************//** ++ @Function FM_FREE_FMAN_CTRL_EVENT_REG ++ ++ @Description Used by FM front-end to free locate event register. ++ ++ @Param[in] uint8_t Pointer - Event register id ++*//***************************************************************************/ ++#define FM_FREE_FMAN_CTRL_EVENT_REG 15 ++ ++/**************************************************************************//** ++ @Function FM_SET_FMAN_CTRL_EVENTS_ENABLE ++ ++ @Description Used by FM front-end to enable events in the FPM ++ Fman controller event register. ++ ++ @Param[in] t_FmIpcFmanEvents Pointer ++*//***************************************************************************/ ++#define FM_SET_FMAN_CTRL_EVENTS_ENABLE 16 ++ ++/**************************************************************************//** ++ @Function FM_SET_FMAN_CTRL_EVENTS_ENABLE ++ ++ @Description Used by FM front-end to enable events in the FPM ++ Fman controller event register. ++ ++ @Param[in/out] t_FmIpcFmanEvents Pointer ++*//***************************************************************************/ ++#define FM_GET_FMAN_CTRL_EVENTS_ENABLE 17 ++ ++/**************************************************************************//** ++ @Function FM_SET_MAC_MAX_FRAME ++ ++ @Description Used by FM front-end to set MAC's MTU/RTU's in ++ back-end. ++ ++ @Param[in/out] t_FmIpcMacMaxFrameParams Pointer ++*//***************************************************************************/ ++#define FM_SET_MAC_MAX_FRAME 18 ++ ++/**************************************************************************//** ++ @Function FM_GET_PHYS_MURAM_BASE ++ ++ @Description Used by FM front-end in order to get MURAM base address ++ ++ @Param[in/out] t_FmIpcPhysAddr Pointer ++*//***************************************************************************/ ++#define FM_GET_PHYS_MURAM_BASE 19 ++ ++/**************************************************************************//** ++ @Function FM_MASTER_IS_ALIVE ++ ++ @Description Used by FM front-end in order to verify Master is up ++ ++ @Param[in/out] bool ++*//***************************************************************************/ ++#define FM_MASTER_IS_ALIVE 20 ++ ++#define FM_ENABLE_RAM_ECC 21 ++#define FM_DISABLE_RAM_ECC 22 ++#define FM_SET_NUM_OF_FMAN_CTRL 23 ++#define FM_SET_SIZE_OF_FIFO 24 ++#define FM_SET_NUM_OF_TASKS 25 ++#define FM_SET_NUM_OF_OPEN_DMAS 26 ++#define FM_VSP_ALLOC 27 ++#define FM_VSP_FREE 28 ++#define FM_VSP_SET_PORT_WINDOW 29 ++#define FM_GET_FMAN_CTRL_CODE_REV 30 ++#define FM_SET_CONG_GRP_PFC_PRIO 31 ++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 ++#define FM_10G_TX_ECC_WA 100 ++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ ++ ++/***************************************************************************/ ++/************************ BACK-END-TO-FRONT-END*****************************/ ++/***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function FM_GUEST_ISR ++ ++ @Description Used by FM back-end to report an interrupt to the front-end. ++ ++ @Param[out] t_FmIpcIsr Pointer ++*//***************************************************************************/ ++#define FM_GUEST_ISR 1 ++ ++ ++ ++/** @} */ /* end of FM_IPC_grp group */ ++/** @} */ /* end of FM_grp group */ ++ ++ ++#endif /* __FM_IPC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_muram.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_muram.c +new file mode 100644 +index 00000000..0bc67cb7 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_muram.c +@@ -0,0 +1,174 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File FM_muram.c ++ ++ @Description FM MURAM ... ++*//***************************************************************************/ ++#include "error_ext.h" ++#include "std_ext.h" ++#include "mm_ext.h" ++#include "string_ext.h" ++#include "sprint_ext.h" ++#include "fm_muram_ext.h" ++#include "fm_common.h" ++ ++#define __ERR_MODULE__ MODULE_FM_MURAM ++ ++ ++typedef struct ++{ ++ t_Handle h_Mem; ++ uintptr_t baseAddr; ++ uint32_t size; ++} t_FmMuram; ++ ++ ++void FmMuramClear(t_Handle h_FmMuram) ++{ ++ t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram; ++ ++ SANITY_CHECK_RETURN(h_FmMuram, E_INVALID_HANDLE); ++ IOMemSet32(UINT_TO_PTR(p_FmMuram->baseAddr), 0, p_FmMuram->size); ++} ++ ++ ++t_Handle FM_MURAM_ConfigAndInit(uintptr_t baseAddress, uint32_t size) ++{ ++ t_Handle h_Mem; ++ t_FmMuram *p_FmMuram; ++ ++ if (!baseAddress) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("baseAddress 0 is not supported")); ++ return NULL; ++ } ++ ++ if (baseAddress%4) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("baseAddress not 4 bytes aligned!")); ++ return NULL; ++ } ++ ++ /* Allocate FM MURAM structure */ ++ p_FmMuram = (t_FmMuram *) XX_Malloc(sizeof(t_FmMuram)); ++ if (!p_FmMuram) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MURAM driver structure")); ++ return NULL; ++ } ++ memset(p_FmMuram, 0, sizeof(t_FmMuram)); ++ ++ ++ if ((MM_Init(&h_Mem, baseAddress, size) != E_OK) || (!h_Mem)) ++ { ++ XX_Free(p_FmMuram); ++ REPORT_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-MURAM partition!!!")); ++ return NULL; ++ } ++ ++ /* Initialize FM MURAM parameters which will be kept by the driver */ ++ p_FmMuram->baseAddr = baseAddress; ++ p_FmMuram->size = size; ++ p_FmMuram->h_Mem = h_Mem; ++ ++ return p_FmMuram; ++} ++ ++t_Error FM_MURAM_Free(t_Handle h_FmMuram) ++{ ++ t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram; ++ ++ if (p_FmMuram->h_Mem) ++ MM_Free(p_FmMuram->h_Mem); ++ ++ XX_Free(h_FmMuram); ++ ++ return E_OK; ++} ++ ++void * FM_MURAM_AllocMem(t_Handle h_FmMuram, uint32_t size, uint32_t align) ++{ ++ t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram; ++ uintptr_t addr; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmMuram, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(p_FmMuram->h_Mem, E_INVALID_HANDLE, NULL); ++ ++ addr = (uintptr_t)MM_Get(p_FmMuram->h_Mem, size, align ,"FM MURAM"); ++ ++ if (addr == ILLEGAL_BASE) ++ return NULL; ++ ++ return UINT_TO_PTR(addr); ++} ++ ++void * FM_MURAM_AllocMemForce(t_Handle h_FmMuram, uint64_t base, uint32_t size) ++{ ++ t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram; ++ uintptr_t addr; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmMuram, E_INVALID_HANDLE, NULL); ++ SANITY_CHECK_RETURN_VALUE(p_FmMuram->h_Mem, E_INVALID_HANDLE, NULL); ++ ++ addr = (uintptr_t)MM_GetForce(p_FmMuram->h_Mem, base, size, "FM MURAM"); ++ ++ if (addr == ILLEGAL_BASE) ++ return NULL; ++ ++ return UINT_TO_PTR(addr); ++} ++ ++t_Error FM_MURAM_FreeMem(t_Handle h_FmMuram, void *ptr) ++{ ++ t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram; ++ ++ SANITY_CHECK_RETURN_ERROR(h_FmMuram, E_INVALID_HANDLE); ++ SANITY_CHECK_RETURN_ERROR(p_FmMuram->h_Mem, E_INVALID_HANDLE); ++ ++ if (MM_Put(p_FmMuram->h_Mem, PTR_TO_UINT(ptr)) == 0) ++ RETURN_ERROR(MINOR, E_INVALID_ADDRESS, ("memory pointer!!!")); ++ ++ return E_OK; ++} ++ ++uint64_t FM_MURAM_GetFreeMemSize(t_Handle h_FmMuram) ++{ ++ t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram; ++ ++ SANITY_CHECK_RETURN_VALUE(h_FmMuram, E_INVALID_HANDLE, 0); ++ SANITY_CHECK_RETURN_VALUE(p_FmMuram->h_Mem, E_INVALID_HANDLE, 0); ++ ++ return MM_GetFreeMemSize(p_FmMuram->h_Mem); ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c +new file mode 100755 +index 00000000..a41ecd04 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c +@@ -0,0 +1,1398 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#include ++#include "fsl_fman.h" ++#include "dpaa_integration_ext.h" ++ ++uint32_t fman_get_bmi_err_event(struct fman_bmi_regs *bmi_rg) ++{ ++ uint32_t event, mask, force; ++ ++ event = ioread32be(&bmi_rg->fmbm_ievr); ++ mask = ioread32be(&bmi_rg->fmbm_ier); ++ event &= mask; ++ /* clear the forced events */ ++ force = ioread32be(&bmi_rg->fmbm_ifr); ++ if (force & event) ++ iowrite32be(force & ~event, &bmi_rg->fmbm_ifr); ++ /* clear the acknowledged events */ ++ iowrite32be(event, &bmi_rg->fmbm_ievr); ++ return event; ++} ++ ++uint32_t fman_get_qmi_err_event(struct fman_qmi_regs *qmi_rg) ++{ ++ uint32_t event, mask, force; ++ ++ event = ioread32be(&qmi_rg->fmqm_eie); ++ mask = ioread32be(&qmi_rg->fmqm_eien); ++ event &= mask; ++ ++ /* clear the forced events */ ++ force = ioread32be(&qmi_rg->fmqm_eif); ++ if (force & event) ++ iowrite32be(force & ~event, &qmi_rg->fmqm_eif); ++ /* clear the acknowledged events */ ++ iowrite32be(event, &qmi_rg->fmqm_eie); ++ return event; ++} ++ ++uint32_t fman_get_dma_com_id(struct fman_dma_regs *dma_rg) ++{ ++ return ioread32be(&dma_rg->fmdmtcid); ++} ++ ++uint64_t fman_get_dma_addr(struct fman_dma_regs *dma_rg) ++{ ++ uint64_t addr; ++ ++ addr = (uint64_t)ioread32be(&dma_rg->fmdmtal); ++ addr |= ((uint64_t)(ioread32be(&dma_rg->fmdmtah)) << 32); ++ ++ return addr; ++} ++ ++uint32_t fman_get_dma_err_event(struct fman_dma_regs *dma_rg) ++{ ++ uint32_t status, mask; ++ ++ status = ioread32be(&dma_rg->fmdmsr); ++ mask = ioread32be(&dma_rg->fmdmmr); ++ ++ /* clear DMA_STATUS_BUS_ERR if mask has no DMA_MODE_BER */ ++ if ((mask & DMA_MODE_BER) != DMA_MODE_BER) ++ status &= ~DMA_STATUS_BUS_ERR; ++ ++ /* clear relevant bits if mask has no DMA_MODE_ECC */ ++ if ((mask & DMA_MODE_ECC) != DMA_MODE_ECC) ++ status &= ~(DMA_STATUS_FM_SPDAT_ECC | ++ DMA_STATUS_READ_ECC | ++ DMA_STATUS_SYSTEM_WRITE_ECC | ++ DMA_STATUS_FM_WRITE_ECC); ++ ++ /* clear set events */ ++ iowrite32be(status, &dma_rg->fmdmsr); ++ ++ return status; ++} ++ ++uint32_t fman_get_fpm_err_event(struct fman_fpm_regs *fpm_rg) ++{ ++ uint32_t event; ++ ++ event = ioread32be(&fpm_rg->fmfp_ee); ++ /* clear the all occurred events */ ++ iowrite32be(event, &fpm_rg->fmfp_ee); ++ return event; ++} ++ ++uint32_t fman_get_muram_err_event(struct fman_fpm_regs *fpm_rg) ++{ ++ uint32_t event, mask; ++ ++ event = ioread32be(&fpm_rg->fm_rcr); ++ mask = ioread32be(&fpm_rg->fm_rie); ++ ++ /* clear MURAM event bit (do not clear IRAM event) */ ++ iowrite32be(event & ~FPM_RAM_IRAM_ECC, &fpm_rg->fm_rcr); ++ ++ if ((mask & FPM_MURAM_ECC_ERR_EX_EN)) ++ return event; ++ else ++ return 0; ++} ++ ++uint32_t fman_get_iram_err_event(struct fman_fpm_regs *fpm_rg) ++{ ++ uint32_t event, mask; ++ ++ event = ioread32be(&fpm_rg->fm_rcr) ; ++ mask = ioread32be(&fpm_rg->fm_rie); ++ /* clear IRAM event bit (do not clear MURAM event) */ ++ iowrite32be(event & ~FPM_RAM_MURAM_ECC, ++ &fpm_rg->fm_rcr); ++ ++ if ((mask & FPM_IRAM_ECC_ERR_EX_EN)) ++ return event; ++ else ++ return 0; ++} ++ ++uint32_t fman_get_qmi_event(struct fman_qmi_regs *qmi_rg) ++{ ++ uint32_t event, mask, force; ++ ++ event = ioread32be(&qmi_rg->fmqm_ie); ++ mask = ioread32be(&qmi_rg->fmqm_ien); ++ event &= mask; ++ /* clear the forced events */ ++ force = ioread32be(&qmi_rg->fmqm_if); ++ if (force & event) ++ iowrite32be(force & ~event, &qmi_rg->fmqm_if); ++ /* clear the acknowledged events */ ++ iowrite32be(event, &qmi_rg->fmqm_ie); ++ return event; ++} ++ ++void fman_enable_time_stamp(struct fman_fpm_regs *fpm_rg, ++ uint8_t count1ubit, ++ uint16_t fm_clk_freq) ++{ ++ uint32_t tmp; ++ uint64_t frac; ++ uint32_t intgr; ++ uint32_t ts_freq = (uint32_t)(1 << count1ubit); /* in Mhz */ ++ ++ /* configure timestamp so that bit 8 will count 1 microsecond ++ * Find effective count rate at TIMESTAMP least significant bits: ++ * Effective_Count_Rate = 1MHz x 2^8 = 256MHz ++ * Find frequency ratio between effective count rate and the clock: ++ * Effective_Count_Rate / CLK e.g. for 600 MHz clock: ++ * 256/600 = 0.4266666... */ ++ ++ intgr = ts_freq / fm_clk_freq; ++ /* we multiply by 2^16 to keep the fraction of the division ++ * we do not div back, since we write this value as a fraction ++ * see spec */ ++ ++ frac = ((uint64_t)ts_freq << 16) - ((uint64_t)intgr << 16) * fm_clk_freq; ++ /* we check remainder of the division in order to round up if not int */ ++ if (do_div(frac, fm_clk_freq)) ++ frac++; ++ ++ tmp = (intgr << FPM_TS_INT_SHIFT) | (uint16_t)frac; ++ iowrite32be(tmp, &fpm_rg->fmfp_tsc2); ++ ++ /* enable timestamp with original clock */ ++ iowrite32be(FPM_TS_CTL_EN, &fpm_rg->fmfp_tsc1); ++} ++ ++uint32_t fman_get_fpm_error_interrupts(struct fman_fpm_regs *fpm_rg) ++{ ++ return ioread32be(&fpm_rg->fm_epi); ++} ++ ++ ++int fman_set_erratum_10gmac_a004_wa(struct fman_fpm_regs *fpm_rg) ++{ ++ int timeout = 100; ++ ++ iowrite32be(0x40000000, &fpm_rg->fmfp_extc); ++ ++ while ((ioread32be(&fpm_rg->fmfp_extc) & 0x40000000) && --timeout) ++ udelay(10); ++ ++ if (!timeout) ++ return -EBUSY; ++ return 0; ++} ++ ++void fman_set_ctrl_intr(struct fman_fpm_regs *fpm_rg, ++ uint8_t event_reg_id, ++ uint32_t enable_events) ++{ ++ iowrite32be(enable_events, &fpm_rg->fmfp_cee[event_reg_id]); ++} ++ ++uint32_t fman_get_ctrl_intr(struct fman_fpm_regs *fpm_rg, uint8_t event_reg_id) ++{ ++ return ioread32be(&fpm_rg->fmfp_cee[event_reg_id]); ++} ++ ++void fman_set_num_of_riscs_per_port(struct fman_fpm_regs *fpm_rg, ++ uint8_t port_id, ++ uint8_t num_fman_ctrls, ++ uint32_t or_fman_ctrl) ++{ ++ uint32_t tmp = 0; ++ ++ tmp = (uint32_t)(port_id << FPM_PORT_FM_CTL_PORTID_SHIFT); ++ /*TODO - maybe to put CTL# according to another criteria*/ ++ if (num_fman_ctrls == 2) ++ tmp = FPM_PRT_FM_CTL2 | FPM_PRT_FM_CTL1; ++ /* order restoration */ ++ tmp |= (or_fman_ctrl << FPM_PRC_ORA_FM_CTL_SEL_SHIFT) | or_fman_ctrl; ++ ++ iowrite32be(tmp, &fpm_rg->fmfp_prc); ++} ++ ++void fman_set_order_restoration_per_port(struct fman_fpm_regs *fpm_rg, ++ uint8_t port_id, ++ bool independent_mode, ++ bool is_rx_port) ++{ ++ uint32_t tmp = 0; ++ ++ tmp = (uint32_t)(port_id << FPM_PORT_FM_CTL_PORTID_SHIFT); ++ if (independent_mode) { ++ if (is_rx_port) ++ tmp |= (FPM_PRT_FM_CTL1 << ++ FPM_PRC_ORA_FM_CTL_SEL_SHIFT) | FPM_PRT_FM_CTL1; ++ else ++ tmp |= (FPM_PRT_FM_CTL2 << ++ FPM_PRC_ORA_FM_CTL_SEL_SHIFT) | FPM_PRT_FM_CTL2; ++ } else { ++ tmp |= (FPM_PRT_FM_CTL2|FPM_PRT_FM_CTL1); ++ ++ /* order restoration */ ++ if (port_id % 2) ++ tmp |= (FPM_PRT_FM_CTL1 << ++ FPM_PRC_ORA_FM_CTL_SEL_SHIFT); ++ else ++ tmp |= (FPM_PRT_FM_CTL2 << ++ FPM_PRC_ORA_FM_CTL_SEL_SHIFT); ++ } ++ iowrite32be(tmp, &fpm_rg->fmfp_prc); ++} ++ ++uint8_t fman_get_qmi_deq_th(struct fman_qmi_regs *qmi_rg) ++{ ++ return (uint8_t)ioread32be(&qmi_rg->fmqm_gc); ++} ++ ++uint8_t fman_get_qmi_enq_th(struct fman_qmi_regs *qmi_rg) ++{ ++ return (uint8_t)(ioread32be(&qmi_rg->fmqm_gc) >> 8); ++} ++ ++void fman_set_qmi_enq_th(struct fman_qmi_regs *qmi_rg, uint8_t val) ++{ ++ uint32_t tmp_reg; ++ ++ tmp_reg = ioread32be(&qmi_rg->fmqm_gc); ++ tmp_reg &= ~QMI_CFG_ENQ_MASK; ++ tmp_reg |= ((uint32_t)val << 8); ++ iowrite32be(tmp_reg, &qmi_rg->fmqm_gc); ++} ++ ++void fman_set_qmi_deq_th(struct fman_qmi_regs *qmi_rg, uint8_t val) ++{ ++ uint32_t tmp_reg; ++ ++ tmp_reg = ioread32be(&qmi_rg->fmqm_gc); ++ tmp_reg &= ~QMI_CFG_DEQ_MASK; ++ tmp_reg |= (uint32_t)val; ++ iowrite32be(tmp_reg, &qmi_rg->fmqm_gc); ++} ++ ++void fman_qmi_disable_dispatch_limit(struct fman_fpm_regs *fpm_rg) ++{ ++ iowrite32be(0, &fpm_rg->fmfp_mxd); ++} ++ ++void fman_set_liodn_per_port(struct fman_rg *fman_rg, uint8_t port_id, ++ uint16_t liodn_base, ++ uint16_t liodn_ofst) ++{ ++ uint32_t tmp; ++ ++ if ((port_id > 63) || (port_id < 1)) ++ return; ++ ++ /* set LIODN base for this port */ ++ tmp = ioread32be(&fman_rg->dma_rg->fmdmplr[port_id / 2]); ++ if (port_id % 2) { ++ tmp &= ~FM_LIODN_BASE_MASK; ++ tmp |= (uint32_t)liodn_base; ++ } else { ++ tmp &= ~(FM_LIODN_BASE_MASK << DMA_LIODN_SHIFT); ++ tmp |= (uint32_t)liodn_base << DMA_LIODN_SHIFT; ++ } ++ iowrite32be(tmp, &fman_rg->dma_rg->fmdmplr[port_id / 2]); ++ iowrite32be((uint32_t)liodn_ofst, ++ &fman_rg->bmi_rg->fmbm_spliodn[port_id - 1]); ++} ++ ++bool fman_is_port_stalled(struct fman_fpm_regs *fpm_rg, uint8_t port_id) ++{ ++ return (bool)!!(ioread32be(&fpm_rg->fmfp_ps[port_id]) & FPM_PS_STALLED); ++} ++ ++void fman_resume_stalled_port(struct fman_fpm_regs *fpm_rg, uint8_t port_id) ++{ ++ uint32_t tmp; ++ ++ tmp = (uint32_t)((port_id << FPM_PORT_FM_CTL_PORTID_SHIFT) | ++ FPM_PRC_REALSE_STALLED); ++ iowrite32be(tmp, &fpm_rg->fmfp_prc); ++} ++ ++int fman_reset_mac(struct fman_fpm_regs *fpm_rg, uint8_t mac_id, bool is_10g) ++{ ++ uint32_t msk, timeout = 100; ++ ++ /* Get the relevant bit mask */ ++ if (is_10g) { ++ switch (mac_id) { ++ case(0): ++ msk = FPM_RSTC_10G0_RESET; ++ break; ++ case(1): ++ msk = FPM_RSTC_10G1_RESET; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } else { ++ switch (mac_id) { ++ case(0): ++ msk = FPM_RSTC_1G0_RESET; ++ break; ++ case(1): ++ msk = FPM_RSTC_1G1_RESET; ++ break; ++ case(2): ++ msk = FPM_RSTC_1G2_RESET; ++ break; ++ case(3): ++ msk = FPM_RSTC_1G3_RESET; ++ break; ++ case(4): ++ msk = FPM_RSTC_1G4_RESET; ++ break; ++ case (5): ++ msk = FPM_RSTC_1G5_RESET; ++ break; ++ case (6): ++ msk = FPM_RSTC_1G6_RESET; ++ break; ++ case (7): ++ msk = FPM_RSTC_1G7_RESET; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ /* reset */ ++ iowrite32be(msk, &fpm_rg->fm_rstc); ++ while ((ioread32be(&fpm_rg->fm_rstc) & msk) && --timeout) ++ udelay(10); ++ ++ if (!timeout) ++ return -EBUSY; ++ return 0; ++} ++ ++uint16_t fman_get_size_of_fifo(struct fman_bmi_regs *bmi_rg, uint8_t port_id) ++{ ++ uint32_t tmp_reg; ++ ++ if ((port_id > 63) || (port_id < 1)) ++ return 0; ++ ++ tmp_reg = ioread32be(&bmi_rg->fmbm_pfs[port_id - 1]); ++ return (uint16_t)((tmp_reg & BMI_FIFO_SIZE_MASK) + 1); ++} ++ ++uint32_t fman_get_total_fifo_size(struct fman_bmi_regs *bmi_rg) ++{ ++ uint32_t reg, res; ++ ++ reg = ioread32be(&bmi_rg->fmbm_cfg1); ++ res = (reg >> BMI_CFG1_FIFO_SIZE_SHIFT) & 0x3ff; ++ return res * FMAN_BMI_FIFO_UNITS; ++} ++ ++uint16_t fman_get_size_of_extra_fifo(struct fman_bmi_regs *bmi_rg, ++ uint8_t port_id) ++{ ++ uint32_t tmp_reg; ++ ++ if ((port_id > 63) || (port_id < 1)) ++ return 0; ++ ++ tmp_reg = ioread32be(&bmi_rg->fmbm_pfs[port_id-1]); ++ return (uint16_t)((tmp_reg & BMI_EXTRA_FIFO_SIZE_MASK) >> ++ BMI_EXTRA_FIFO_SIZE_SHIFT); ++} ++ ++void fman_set_size_of_fifo(struct fman_bmi_regs *bmi_rg, ++ uint8_t port_id, ++ uint32_t sz_fifo, ++ uint32_t extra_sz_fifo) ++{ ++ uint32_t tmp; ++ ++ if ((port_id > 63) || (port_id < 1)) ++ return; ++ ++ /* calculate reg */ ++ tmp = (uint32_t)((sz_fifo / FMAN_BMI_FIFO_UNITS - 1) | ++ ((extra_sz_fifo / FMAN_BMI_FIFO_UNITS) << ++ BMI_EXTRA_FIFO_SIZE_SHIFT)); ++ iowrite32be(tmp, &bmi_rg->fmbm_pfs[port_id - 1]); ++} ++ ++uint8_t fman_get_num_of_tasks(struct fman_bmi_regs *bmi_rg, uint8_t port_id) ++{ ++ uint32_t tmp; ++ ++ if ((port_id > 63) || (port_id < 1)) ++ return 0; ++ ++ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]); ++ return (uint8_t)(((tmp & BMI_NUM_OF_TASKS_MASK) >> ++ BMI_NUM_OF_TASKS_SHIFT) + 1); ++} ++ ++uint8_t fman_get_num_extra_tasks(struct fman_bmi_regs *bmi_rg, uint8_t port_id) ++{ ++ uint32_t tmp; ++ ++ if ((port_id > 63) || (port_id < 1)) ++ return 0; ++ ++ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]); ++ return (uint8_t)((tmp & BMI_NUM_OF_EXTRA_TASKS_MASK) >> ++ BMI_EXTRA_NUM_OF_TASKS_SHIFT); ++} ++ ++void fman_set_num_of_tasks(struct fman_bmi_regs *bmi_rg, ++ uint8_t port_id, ++ uint8_t num_tasks, ++ uint8_t num_extra_tasks) ++{ ++ uint32_t tmp; ++ ++ if ((port_id > 63) || (port_id < 1)) ++ return; ++ ++ /* calculate reg */ ++ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]) & ++ ~(BMI_NUM_OF_TASKS_MASK | BMI_NUM_OF_EXTRA_TASKS_MASK); ++ tmp |= (uint32_t)(((num_tasks - 1) << BMI_NUM_OF_TASKS_SHIFT) | ++ (num_extra_tasks << BMI_EXTRA_NUM_OF_TASKS_SHIFT)); ++ iowrite32be(tmp, &bmi_rg->fmbm_pp[port_id - 1]); ++} ++ ++uint8_t fman_get_num_of_dmas(struct fman_bmi_regs *bmi_rg, uint8_t port_id) ++{ ++ uint32_t tmp; ++ ++ if ((port_id > 63) || (port_id < 1)) ++ return 0; ++ ++ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]); ++ return (uint8_t)(((tmp & BMI_NUM_OF_DMAS_MASK) >> ++ BMI_NUM_OF_DMAS_SHIFT) + 1); ++} ++ ++uint8_t fman_get_num_extra_dmas(struct fman_bmi_regs *bmi_rg, uint8_t port_id) ++{ ++ uint32_t tmp; ++ ++ if ((port_id > 63) || (port_id < 1)) ++ return 0; ++ ++ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]); ++ return (uint8_t)((tmp & BMI_NUM_OF_EXTRA_DMAS_MASK) >> ++ BMI_EXTRA_NUM_OF_DMAS_SHIFT); ++} ++ ++void fman_set_num_of_open_dmas(struct fman_bmi_regs *bmi_rg, ++ uint8_t port_id, ++ uint8_t num_open_dmas, ++ uint8_t num_extra_open_dmas, ++ uint8_t total_num_dmas) ++{ ++ uint32_t tmp = 0; ++ ++ if ((port_id > 63) || (port_id < 1)) ++ return; ++ ++ /* calculate reg */ ++ tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]) & ++ ~(BMI_NUM_OF_DMAS_MASK | BMI_NUM_OF_EXTRA_DMAS_MASK); ++ tmp |= (uint32_t)(((num_open_dmas-1) << BMI_NUM_OF_DMAS_SHIFT) | ++ (num_extra_open_dmas << BMI_EXTRA_NUM_OF_DMAS_SHIFT)); ++ iowrite32be(tmp, &bmi_rg->fmbm_pp[port_id - 1]); ++ ++ /* update total num of DMA's with committed number of open DMAS, ++ * and max uncommitted pool. */ ++ if (total_num_dmas) ++ { ++ tmp = ioread32be(&bmi_rg->fmbm_cfg2) & ~BMI_CFG2_DMAS_MASK; ++ tmp |= (uint32_t)(total_num_dmas - 1) << BMI_CFG2_DMAS_SHIFT; ++ iowrite32be(tmp, &bmi_rg->fmbm_cfg2); ++ } ++} ++ ++void fman_set_vsp_window(struct fman_bmi_regs *bmi_rg, ++ uint8_t port_id, ++ uint8_t base_storage_profile, ++ uint8_t log2_num_of_profiles) ++{ ++ uint32_t tmp = 0; ++ if ((port_id > 63) || (port_id < 1)) ++ return; ++ ++ tmp = ioread32be(&bmi_rg->fmbm_spliodn[port_id-1]); ++ tmp |= (uint32_t)((uint32_t)base_storage_profile & 0x3f) << 16; ++ tmp |= (uint32_t)log2_num_of_profiles << 28; ++ iowrite32be(tmp, &bmi_rg->fmbm_spliodn[port_id-1]); ++} ++ ++void fman_set_congestion_group_pfc_priority(uint32_t *cpg_rg, ++ uint32_t congestion_group_id, ++ uint8_t priority_bit_map, ++ uint32_t reg_num) ++{ ++ uint32_t offset, tmp = 0; ++ ++ offset = (congestion_group_id%4)*8; ++ ++ tmp = ioread32be(&cpg_rg[reg_num]); ++ tmp &= ~(0xFF<catastrophic_err = DEFAULT_CATASTROPHIC_ERR; ++ cfg->dma_err = DEFAULT_DMA_ERR; ++ cfg->halt_on_external_activ = DEFAULT_HALT_ON_EXTERNAL_ACTIVATION; ++ cfg->halt_on_unrecov_ecc_err = DEFAULT_HALT_ON_UNRECOVERABLE_ECC_ERROR; ++ cfg->en_iram_test_mode = FALSE; ++ cfg->en_muram_test_mode = FALSE; ++ cfg->external_ecc_rams_enable = DEFAULT_EXTERNAL_ECC_RAMS_ENABLE; ++ ++ if (!is_master) ++ return; ++ ++ cfg->dma_aid_override = DEFAULT_AID_OVERRIDE; ++ cfg->dma_aid_mode = DEFAULT_AID_MODE; ++ cfg->dma_comm_qtsh_clr_emer = DEFAULT_DMA_COMM_Q_LOW; ++ cfg->dma_comm_qtsh_asrt_emer = DEFAULT_DMA_COMM_Q_HIGH; ++ cfg->dma_cache_override = DEFAULT_CACHE_OVERRIDE; ++ cfg->dma_cam_num_of_entries = DEFAULT_DMA_CAM_NUM_OF_ENTRIES; ++ cfg->dma_dbg_cnt_mode = DEFAULT_DMA_DBG_CNT_MODE; ++ cfg->dma_en_emergency = DEFAULT_DMA_EN_EMERGENCY; ++ cfg->dma_sos_emergency = DEFAULT_DMA_SOS_EMERGENCY; ++ cfg->dma_watchdog = DEFAULT_DMA_WATCHDOG; ++ cfg->dma_en_emergency_smoother = DEFAULT_DMA_EN_EMERGENCY_SMOOTHER; ++ cfg->dma_emergency_switch_counter = DEFAULT_DMA_EMERGENCY_SWITCH_COUNTER; ++ cfg->disp_limit_tsh = DEFAULT_DISP_LIMIT; ++ cfg->prs_disp_tsh = DEFAULT_PRS_DISP_TH; ++ cfg->plcr_disp_tsh = DEFAULT_PLCR_DISP_TH; ++ cfg->kg_disp_tsh = DEFAULT_KG_DISP_TH; ++ cfg->bmi_disp_tsh = DEFAULT_BMI_DISP_TH; ++ cfg->qmi_enq_disp_tsh = DEFAULT_QMI_ENQ_DISP_TH; ++ cfg->qmi_deq_disp_tsh = DEFAULT_QMI_DEQ_DISP_TH; ++ cfg->fm_ctl1_disp_tsh = DEFAULT_FM_CTL1_DISP_TH; ++ cfg->fm_ctl2_disp_tsh = DEFAULT_FM_CTL2_DISP_TH; ++ ++ cfg->pedantic_dma = FALSE; ++ cfg->tnum_aging_period = DEFAULT_TNUM_AGING_PERIOD; ++ cfg->dma_stop_on_bus_error = FALSE; ++ cfg->qmi_deq_option_support = FALSE; ++} ++ ++void fman_regconfig(struct fman_rg *fman_rg, struct fman_cfg *cfg) ++{ ++ uint32_t tmp_reg; ++ ++ /* read the values from the registers as they are initialized by the HW with ++ * the required values. ++ */ ++ tmp_reg = ioread32be(&fman_rg->bmi_rg->fmbm_cfg1); ++ cfg->total_fifo_size = ++ (((tmp_reg & BMI_TOTAL_FIFO_SIZE_MASK) >> BMI_CFG1_FIFO_SIZE_SHIFT) + 1) * FMAN_BMI_FIFO_UNITS; ++ ++ tmp_reg = ioread32be(&fman_rg->bmi_rg->fmbm_cfg2); ++ cfg->total_num_of_tasks = ++ (uint8_t)(((tmp_reg & BMI_TOTAL_NUM_OF_TASKS_MASK) >> BMI_CFG2_TASKS_SHIFT) + 1); ++ ++ tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmtr); ++ cfg->dma_comm_qtsh_asrt_emer = (uint8_t)(tmp_reg >> DMA_THRESH_COMMQ_SHIFT); ++ ++ tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmhy); ++ cfg->dma_comm_qtsh_clr_emer = (uint8_t)(tmp_reg >> DMA_THRESH_COMMQ_SHIFT); ++ ++ tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmmr); ++ cfg->dma_cache_override = (enum fman_dma_cache_override)((tmp_reg & DMA_MODE_CACHE_OR_MASK) >> DMA_MODE_CACHE_OR_SHIFT); ++ cfg->dma_cam_num_of_entries = (uint8_t)((((tmp_reg & DMA_MODE_CEN_MASK) >> DMA_MODE_CEN_SHIFT) +1)*DMA_CAM_UNITS); ++ cfg->dma_aid_override = (bool)((tmp_reg & DMA_MODE_AID_OR)? TRUE:FALSE); ++ cfg->dma_dbg_cnt_mode = (enum fman_dma_dbg_cnt_mode)((tmp_reg & DMA_MODE_DBG_MASK) >> DMA_MODE_DBG_SHIFT); ++ cfg->dma_en_emergency = (bool)((tmp_reg & DMA_MODE_EB)? TRUE : FALSE); ++ ++ tmp_reg = ioread32be(&fman_rg->fpm_rg->fmfp_mxd); ++ cfg->disp_limit_tsh = (uint8_t)((tmp_reg & FPM_DISP_LIMIT_MASK) >> FPM_DISP_LIMIT_SHIFT); ++ ++ tmp_reg = ioread32be(&fman_rg->fpm_rg->fmfp_dist1); ++ cfg->prs_disp_tsh = (uint8_t)((tmp_reg & FPM_THR1_PRS_MASK ) >> FPM_THR1_PRS_SHIFT); ++ cfg->plcr_disp_tsh = (uint8_t)((tmp_reg & FPM_THR1_KG_MASK ) >> FPM_THR1_KG_SHIFT); ++ cfg->kg_disp_tsh = (uint8_t)((tmp_reg & FPM_THR1_PLCR_MASK ) >> FPM_THR1_PLCR_SHIFT); ++ cfg->bmi_disp_tsh = (uint8_t)((tmp_reg & FPM_THR1_BMI_MASK ) >> FPM_THR1_BMI_SHIFT); ++ ++ tmp_reg = ioread32be(&fman_rg->fpm_rg->fmfp_dist2); ++ cfg->qmi_enq_disp_tsh = (uint8_t)((tmp_reg & FPM_THR2_QMI_ENQ_MASK ) >> FPM_THR2_QMI_ENQ_SHIFT); ++ cfg->qmi_deq_disp_tsh = (uint8_t)((tmp_reg & FPM_THR2_QMI_DEQ_MASK ) >> FPM_THR2_QMI_DEQ_SHIFT); ++ cfg->fm_ctl1_disp_tsh = (uint8_t)((tmp_reg & FPM_THR2_FM_CTL1_MASK ) >> FPM_THR2_FM_CTL1_SHIFT); ++ cfg->fm_ctl2_disp_tsh = (uint8_t)((tmp_reg & FPM_THR2_FM_CTL2_MASK ) >> FPM_THR2_FM_CTL2_SHIFT); ++ ++ tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmsetr); ++ cfg->dma_sos_emergency = tmp_reg; ++ ++ tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmwcr); ++ cfg->dma_watchdog = tmp_reg/cfg->clk_freq; ++ ++ tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmemsr); ++ cfg->dma_en_emergency_smoother = (bool)((tmp_reg & DMA_EMSR_EMSTR_MASK)? TRUE : FALSE); ++ cfg->dma_emergency_switch_counter = (tmp_reg & DMA_EMSR_EMSTR_MASK); ++} ++ ++void fman_reset(struct fman_fpm_regs *fpm_rg) ++{ ++ iowrite32be(FPM_RSTC_FM_RESET, &fpm_rg->fm_rstc); ++} ++ ++/**************************************************************************//** ++ @Function FM_Init ++ ++ @Description Initializes the FM module ++ ++ @Param[in] h_Fm - FM module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++int fman_dma_init(struct fman_dma_regs *dma_rg, struct fman_cfg *cfg) ++{ ++ uint32_t tmp_reg; ++ ++ /**********************/ ++ /* Init DMA Registers */ ++ /**********************/ ++ /* clear status reg events */ ++ /* oren - check!!! */ ++ tmp_reg = (DMA_STATUS_BUS_ERR | DMA_STATUS_READ_ECC | ++ DMA_STATUS_SYSTEM_WRITE_ECC | DMA_STATUS_FM_WRITE_ECC); ++ iowrite32be(ioread32be(&dma_rg->fmdmsr) | tmp_reg, ++ &dma_rg->fmdmsr); ++ ++ /* configure mode register */ ++ tmp_reg = 0; ++ tmp_reg |= cfg->dma_cache_override << DMA_MODE_CACHE_OR_SHIFT; ++ if (cfg->dma_aid_override) ++ tmp_reg |= DMA_MODE_AID_OR; ++ if (cfg->exceptions & FMAN_EX_DMA_BUS_ERROR) ++ tmp_reg |= DMA_MODE_BER; ++ if ((cfg->exceptions & FMAN_EX_DMA_SYSTEM_WRITE_ECC) | ++ (cfg->exceptions & FMAN_EX_DMA_READ_ECC) | ++ (cfg->exceptions & FMAN_EX_DMA_FM_WRITE_ECC)) ++ tmp_reg |= DMA_MODE_ECC; ++ if (cfg->dma_stop_on_bus_error) ++ tmp_reg |= DMA_MODE_SBER; ++ if(cfg->dma_axi_dbg_num_of_beats) ++ tmp_reg |= (uint32_t)(DMA_MODE_AXI_DBG_MASK & ++ ((cfg->dma_axi_dbg_num_of_beats - 1) << DMA_MODE_AXI_DBG_SHIFT)); ++ ++ if (cfg->dma_en_emergency) { ++ tmp_reg |= cfg->dma_emergency_bus_select; ++ tmp_reg |= cfg->dma_emergency_level << DMA_MODE_EMER_LVL_SHIFT; ++ if (cfg->dma_en_emergency_smoother) ++ iowrite32be(cfg->dma_emergency_switch_counter, ++ &dma_rg->fmdmemsr); ++ } ++ tmp_reg |= ((cfg->dma_cam_num_of_entries / DMA_CAM_UNITS) - 1) << ++ DMA_MODE_CEN_SHIFT; ++ tmp_reg |= DMA_MODE_SECURE_PROT; ++ tmp_reg |= cfg->dma_dbg_cnt_mode << DMA_MODE_DBG_SHIFT; ++ tmp_reg |= cfg->dma_aid_mode << DMA_MODE_AID_MODE_SHIFT; ++ ++ if (cfg->pedantic_dma) ++ tmp_reg |= DMA_MODE_EMER_READ; ++ ++ iowrite32be(tmp_reg, &dma_rg->fmdmmr); ++ ++ /* configure thresholds register */ ++ tmp_reg = ((uint32_t)cfg->dma_comm_qtsh_asrt_emer << ++ DMA_THRESH_COMMQ_SHIFT) | ++ ((uint32_t)cfg->dma_read_buf_tsh_asrt_emer << ++ DMA_THRESH_READ_INT_BUF_SHIFT) | ++ ((uint32_t)cfg->dma_write_buf_tsh_asrt_emer); ++ ++ iowrite32be(tmp_reg, &dma_rg->fmdmtr); ++ ++ /* configure hysteresis register */ ++ tmp_reg = ((uint32_t)cfg->dma_comm_qtsh_clr_emer << ++ DMA_THRESH_COMMQ_SHIFT) | ++ ((uint32_t)cfg->dma_read_buf_tsh_clr_emer << ++ DMA_THRESH_READ_INT_BUF_SHIFT) | ++ ((uint32_t)cfg->dma_write_buf_tsh_clr_emer); ++ ++ iowrite32be(tmp_reg, &dma_rg->fmdmhy); ++ ++ /* configure emergency threshold */ ++ iowrite32be(cfg->dma_sos_emergency, &dma_rg->fmdmsetr); ++ ++ /* configure Watchdog */ ++ iowrite32be((cfg->dma_watchdog * cfg->clk_freq), ++ &dma_rg->fmdmwcr); ++ ++ iowrite32be(cfg->cam_base_addr, &dma_rg->fmdmebcr); ++ ++ return 0; ++} ++ ++int fman_fpm_init(struct fman_fpm_regs *fpm_rg, struct fman_cfg *cfg) ++{ ++ uint32_t tmp_reg; ++ int i; ++ ++ /**********************/ ++ /* Init FPM Registers */ ++ /**********************/ ++ tmp_reg = (uint32_t)(cfg->disp_limit_tsh << FPM_DISP_LIMIT_SHIFT); ++ iowrite32be(tmp_reg, &fpm_rg->fmfp_mxd); ++ ++ tmp_reg = (((uint32_t)cfg->prs_disp_tsh << FPM_THR1_PRS_SHIFT) | ++ ((uint32_t)cfg->kg_disp_tsh << FPM_THR1_KG_SHIFT) | ++ ((uint32_t)cfg->plcr_disp_tsh << FPM_THR1_PLCR_SHIFT) | ++ ((uint32_t)cfg->bmi_disp_tsh << FPM_THR1_BMI_SHIFT)); ++ iowrite32be(tmp_reg, &fpm_rg->fmfp_dist1); ++ ++ tmp_reg = (((uint32_t)cfg->qmi_enq_disp_tsh << FPM_THR2_QMI_ENQ_SHIFT) | ++ ((uint32_t)cfg->qmi_deq_disp_tsh << FPM_THR2_QMI_DEQ_SHIFT) | ++ ((uint32_t)cfg->fm_ctl1_disp_tsh << FPM_THR2_FM_CTL1_SHIFT) | ++ ((uint32_t)cfg->fm_ctl2_disp_tsh << FPM_THR2_FM_CTL2_SHIFT)); ++ iowrite32be(tmp_reg, &fpm_rg->fmfp_dist2); ++ ++ /* define exceptions and error behavior */ ++ tmp_reg = 0; ++ /* Clear events */ ++ tmp_reg |= (FPM_EV_MASK_STALL | FPM_EV_MASK_DOUBLE_ECC | ++ FPM_EV_MASK_SINGLE_ECC); ++ /* enable interrupts */ ++ if (cfg->exceptions & FMAN_EX_FPM_STALL_ON_TASKS) ++ tmp_reg |= FPM_EV_MASK_STALL_EN; ++ if (cfg->exceptions & FMAN_EX_FPM_SINGLE_ECC) ++ tmp_reg |= FPM_EV_MASK_SINGLE_ECC_EN; ++ if (cfg->exceptions & FMAN_EX_FPM_DOUBLE_ECC) ++ tmp_reg |= FPM_EV_MASK_DOUBLE_ECC_EN; ++ tmp_reg |= (cfg->catastrophic_err << FPM_EV_MASK_CAT_ERR_SHIFT); ++ tmp_reg |= (cfg->dma_err << FPM_EV_MASK_DMA_ERR_SHIFT); ++ if (!cfg->halt_on_external_activ) ++ tmp_reg |= FPM_EV_MASK_EXTERNAL_HALT; ++ if (!cfg->halt_on_unrecov_ecc_err) ++ tmp_reg |= FPM_EV_MASK_ECC_ERR_HALT; ++ iowrite32be(tmp_reg, &fpm_rg->fmfp_ee); ++ ++ /* clear all fmCtls event registers */ ++ for (i = 0; i < cfg->num_of_fman_ctrl_evnt_regs; i++) ++ iowrite32be(0xFFFFFFFF, &fpm_rg->fmfp_cev[i]); ++ ++ /* RAM ECC - enable and clear events*/ ++ /* first we need to clear all parser memory, ++ * as it is uninitialized and may cause ECC errors */ ++ /* event bits */ ++ tmp_reg = (FPM_RAM_MURAM_ECC | FPM_RAM_IRAM_ECC); ++ /* Rams enable not effected by RCR bit, but by a COP configuration */ ++ if (cfg->external_ecc_rams_enable) ++ tmp_reg |= FPM_RAM_RAMS_ECC_EN_SRC_SEL; ++ ++ /* enable test mode */ ++ if (cfg->en_muram_test_mode) ++ tmp_reg |= FPM_RAM_MURAM_TEST_ECC; ++ if (cfg->en_iram_test_mode) ++ tmp_reg |= FPM_RAM_IRAM_TEST_ECC; ++ iowrite32be(tmp_reg, &fpm_rg->fm_rcr); ++ ++ tmp_reg = 0; ++ if (cfg->exceptions & FMAN_EX_IRAM_ECC) { ++ tmp_reg |= FPM_IRAM_ECC_ERR_EX_EN; ++ fman_enable_rams_ecc(fpm_rg); ++ } ++ if (cfg->exceptions & FMAN_EX_NURAM_ECC) { ++ tmp_reg |= FPM_MURAM_ECC_ERR_EX_EN; ++ fman_enable_rams_ecc(fpm_rg); ++ } ++ iowrite32be(tmp_reg, &fpm_rg->fm_rie); ++ ++ return 0; ++} ++ ++int fman_bmi_init(struct fman_bmi_regs *bmi_rg, struct fman_cfg *cfg) ++{ ++ uint32_t tmp_reg; ++ ++ /**********************/ ++ /* Init BMI Registers */ ++ /**********************/ ++ ++ /* define common resources */ ++ tmp_reg = cfg->fifo_base_addr; ++ tmp_reg = tmp_reg / BMI_FIFO_ALIGN; ++ ++ tmp_reg |= ((cfg->total_fifo_size / FMAN_BMI_FIFO_UNITS - 1) << ++ BMI_CFG1_FIFO_SIZE_SHIFT); ++ iowrite32be(tmp_reg, &bmi_rg->fmbm_cfg1); ++ ++ tmp_reg = ((uint32_t)(cfg->total_num_of_tasks - 1) << ++ BMI_CFG2_TASKS_SHIFT); ++ /* num of DMA's will be dynamically updated when each port is set */ ++ iowrite32be(tmp_reg, &bmi_rg->fmbm_cfg2); ++ ++ /* define unmaskable exceptions, enable and clear events */ ++ tmp_reg = 0; ++ iowrite32be(BMI_ERR_INTR_EN_LIST_RAM_ECC | ++ BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC | ++ BMI_ERR_INTR_EN_STATISTICS_RAM_ECC | ++ BMI_ERR_INTR_EN_DISPATCH_RAM_ECC, ++ &bmi_rg->fmbm_ievr); ++ ++ if (cfg->exceptions & FMAN_EX_BMI_LIST_RAM_ECC) ++ tmp_reg |= BMI_ERR_INTR_EN_LIST_RAM_ECC; ++ if (cfg->exceptions & FMAN_EX_BMI_PIPELINE_ECC) ++ tmp_reg |= BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC; ++ if (cfg->exceptions & FMAN_EX_BMI_STATISTICS_RAM_ECC) ++ tmp_reg |= BMI_ERR_INTR_EN_STATISTICS_RAM_ECC; ++ if (cfg->exceptions & FMAN_EX_BMI_DISPATCH_RAM_ECC) ++ tmp_reg |= BMI_ERR_INTR_EN_DISPATCH_RAM_ECC; ++ iowrite32be(tmp_reg, &bmi_rg->fmbm_ier); ++ ++ return 0; ++} ++ ++int fman_qmi_init(struct fman_qmi_regs *qmi_rg, struct fman_cfg *cfg) ++{ ++ uint32_t tmp_reg; ++ uint16_t period_in_fm_clocks; ++ uint8_t remainder; ++ /**********************/ ++ /* Init QMI Registers */ ++ /**********************/ ++ /* Clear error interrupt events */ ++ ++ iowrite32be(QMI_ERR_INTR_EN_DOUBLE_ECC | QMI_ERR_INTR_EN_DEQ_FROM_DEF, ++ &qmi_rg->fmqm_eie); ++ tmp_reg = 0; ++ if (cfg->exceptions & FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID) ++ tmp_reg |= QMI_ERR_INTR_EN_DEQ_FROM_DEF; ++ if (cfg->exceptions & FMAN_EX_QMI_DOUBLE_ECC) ++ tmp_reg |= QMI_ERR_INTR_EN_DOUBLE_ECC; ++ /* enable events */ ++ iowrite32be(tmp_reg, &qmi_rg->fmqm_eien); ++ ++ if (cfg->tnum_aging_period) { ++ /* tnum_aging_period is in units of usec, p_FmClockFreq in Mhz */ ++ period_in_fm_clocks = (uint16_t) ++ (cfg->tnum_aging_period * cfg->clk_freq); ++ /* period_in_fm_clocks must be a 64 multiply */ ++ remainder = (uint8_t)(period_in_fm_clocks % 64); ++ if (remainder) ++ tmp_reg = (uint32_t)((period_in_fm_clocks / 64) + 1); ++ else{ ++ tmp_reg = (uint32_t)(period_in_fm_clocks / 64); ++ if (!tmp_reg) ++ tmp_reg = 1; ++ } ++ tmp_reg <<= QMI_TAPC_TAP; ++ iowrite32be(tmp_reg, &qmi_rg->fmqm_tapc); ++ } ++ tmp_reg = 0; ++ /* Clear interrupt events */ ++ iowrite32be(QMI_INTR_EN_SINGLE_ECC, &qmi_rg->fmqm_ie); ++ if (cfg->exceptions & FMAN_EX_QMI_SINGLE_ECC) ++ tmp_reg |= QMI_INTR_EN_SINGLE_ECC; ++ /* enable events */ ++ iowrite32be(tmp_reg, &qmi_rg->fmqm_ien); ++ ++ return 0; ++} ++ ++int fman_enable(struct fman_rg *fman_rg, struct fman_cfg *cfg) ++{ ++ uint32_t cfg_reg = 0; ++ ++ /**********************/ ++ /* Enable all modules */ ++ /**********************/ ++ /* clear & enable global counters - calculate reg and save for later, ++ because it's the same reg for QMI enable */ ++ cfg_reg = QMI_CFG_EN_COUNTERS; ++ if (cfg->qmi_deq_option_support) ++ cfg_reg |= (uint32_t)(((cfg->qmi_def_tnums_thresh) << 8) | ++ (uint32_t)cfg->qmi_def_tnums_thresh); ++ ++ iowrite32be(BMI_INIT_START, &fman_rg->bmi_rg->fmbm_init); ++ iowrite32be(cfg_reg | QMI_CFG_ENQ_EN | QMI_CFG_DEQ_EN, ++ &fman_rg->qmi_rg->fmqm_gc); ++ ++ return 0; ++} ++ ++void fman_free_resources(struct fman_rg *fman_rg) ++{ ++ /* disable BMI and QMI */ ++ iowrite32be(0, &fman_rg->bmi_rg->fmbm_init); ++ iowrite32be(0, &fman_rg->qmi_rg->fmqm_gc); ++ ++ /* release BMI resources */ ++ iowrite32be(0, &fman_rg->bmi_rg->fmbm_cfg2); ++ iowrite32be(0, &fman_rg->bmi_rg->fmbm_cfg1); ++ ++ /* disable ECC */ ++ iowrite32be(0, &fman_rg->fpm_rg->fm_rcr); ++} ++ ++/****************************************************/ ++/* API Run-time Control uint functions */ ++/****************************************************/ ++uint32_t fman_get_normal_pending(struct fman_fpm_regs *fpm_rg) ++{ ++ return ioread32be(&fpm_rg->fm_npi); ++} ++ ++uint32_t fman_get_controller_event(struct fman_fpm_regs *fpm_rg, uint8_t reg_id) ++{ ++ uint32_t event; ++ ++ event = ioread32be(&fpm_rg->fmfp_fcev[reg_id]) & ++ ioread32be(&fpm_rg->fmfp_cee[reg_id]); ++ iowrite32be(event, &fpm_rg->fmfp_cev[reg_id]); ++ ++ return event; ++} ++ ++uint32_t fman_get_error_pending(struct fman_fpm_regs *fpm_rg) ++{ ++ return ioread32be(&fpm_rg->fm_epi); ++} ++ ++void fman_set_ports_bandwidth(struct fman_bmi_regs *bmi_rg, uint8_t *weights) ++{ ++ int i; ++ uint8_t shift; ++ uint32_t tmp = 0; ++ ++ for (i = 0; i < 64; i++) { ++ if (weights[i] > 1) { /* no need to write 1 since it is 0 */ ++ /* Add this port to tmp_reg */ ++ /* (each 8 ports result in one register)*/ ++ shift = (uint8_t)(32 - 4 * ((i % 8) + 1)); ++ tmp |= ((weights[i] - 1) << shift); ++ } ++ if (i % 8 == 7) { /* last in this set */ ++ iowrite32be(tmp, &bmi_rg->fmbm_arb[i / 8]); ++ tmp = 0; ++ } ++ } ++} ++ ++void fman_enable_rams_ecc(struct fman_fpm_regs *fpm_rg) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(&fpm_rg->fm_rcr); ++ if (tmp & FPM_RAM_RAMS_ECC_EN_SRC_SEL) ++ iowrite32be(tmp | FPM_RAM_IRAM_ECC_EN, ++ &fpm_rg->fm_rcr); ++ else ++ iowrite32be(tmp | FPM_RAM_RAMS_ECC_EN | ++ FPM_RAM_IRAM_ECC_EN, ++ &fpm_rg->fm_rcr); ++} ++ ++void fman_disable_rams_ecc(struct fman_fpm_regs *fpm_rg) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(&fpm_rg->fm_rcr); ++ if (tmp & FPM_RAM_RAMS_ECC_EN_SRC_SEL) ++ iowrite32be(tmp & ~FPM_RAM_IRAM_ECC_EN, ++ &fpm_rg->fm_rcr); ++ else ++ iowrite32be(tmp & ~(FPM_RAM_RAMS_ECC_EN | FPM_RAM_IRAM_ECC_EN), ++ &fpm_rg->fm_rcr); ++} ++ ++int fman_set_exception(struct fman_rg *fman_rg, ++ enum fman_exceptions exception, ++ bool enable) ++{ ++ uint32_t tmp; ++ ++ switch (exception) { ++ case(E_FMAN_EX_DMA_BUS_ERROR): ++ tmp = ioread32be(&fman_rg->dma_rg->fmdmmr); ++ if (enable) ++ tmp |= DMA_MODE_BER; ++ else ++ tmp &= ~DMA_MODE_BER; ++ /* disable bus error */ ++ iowrite32be(tmp, &fman_rg->dma_rg->fmdmmr); ++ break; ++ case(E_FMAN_EX_DMA_READ_ECC): ++ case(E_FMAN_EX_DMA_SYSTEM_WRITE_ECC): ++ case(E_FMAN_EX_DMA_FM_WRITE_ECC): ++ tmp = ioread32be(&fman_rg->dma_rg->fmdmmr); ++ if (enable) ++ tmp |= DMA_MODE_ECC; ++ else ++ tmp &= ~DMA_MODE_ECC; ++ iowrite32be(tmp, &fman_rg->dma_rg->fmdmmr); ++ break; ++ case(E_FMAN_EX_FPM_STALL_ON_TASKS): ++ tmp = ioread32be(&fman_rg->fpm_rg->fmfp_ee); ++ if (enable) ++ tmp |= FPM_EV_MASK_STALL_EN; ++ else ++ tmp &= ~FPM_EV_MASK_STALL_EN; ++ iowrite32be(tmp, &fman_rg->fpm_rg->fmfp_ee); ++ break; ++ case(E_FMAN_EX_FPM_SINGLE_ECC): ++ tmp = ioread32be(&fman_rg->fpm_rg->fmfp_ee); ++ if (enable) ++ tmp |= FPM_EV_MASK_SINGLE_ECC_EN; ++ else ++ tmp &= ~FPM_EV_MASK_SINGLE_ECC_EN; ++ iowrite32be(tmp, &fman_rg->fpm_rg->fmfp_ee); ++ break; ++ case(E_FMAN_EX_FPM_DOUBLE_ECC): ++ tmp = ioread32be(&fman_rg->fpm_rg->fmfp_ee); ++ if (enable) ++ tmp |= FPM_EV_MASK_DOUBLE_ECC_EN; ++ else ++ tmp &= ~FPM_EV_MASK_DOUBLE_ECC_EN; ++ iowrite32be(tmp, &fman_rg->fpm_rg->fmfp_ee); ++ break; ++ case(E_FMAN_EX_QMI_SINGLE_ECC): ++ tmp = ioread32be(&fman_rg->qmi_rg->fmqm_ien); ++ if (enable) ++ tmp |= QMI_INTR_EN_SINGLE_ECC; ++ else ++ tmp &= ~QMI_INTR_EN_SINGLE_ECC; ++ iowrite32be(tmp, &fman_rg->qmi_rg->fmqm_ien); ++ break; ++ case(E_FMAN_EX_QMI_DOUBLE_ECC): ++ tmp = ioread32be(&fman_rg->qmi_rg->fmqm_eien); ++ if (enable) ++ tmp |= QMI_ERR_INTR_EN_DOUBLE_ECC; ++ else ++ tmp &= ~QMI_ERR_INTR_EN_DOUBLE_ECC; ++ iowrite32be(tmp, &fman_rg->qmi_rg->fmqm_eien); ++ break; ++ case(E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID): ++ tmp = ioread32be(&fman_rg->qmi_rg->fmqm_eien); ++ if (enable) ++ tmp |= QMI_ERR_INTR_EN_DEQ_FROM_DEF; ++ else ++ tmp &= ~QMI_ERR_INTR_EN_DEQ_FROM_DEF; ++ iowrite32be(tmp, &fman_rg->qmi_rg->fmqm_eien); ++ break; ++ case(E_FMAN_EX_BMI_LIST_RAM_ECC): ++ tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier); ++ if (enable) ++ tmp |= BMI_ERR_INTR_EN_LIST_RAM_ECC; ++ else ++ tmp &= ~BMI_ERR_INTR_EN_LIST_RAM_ECC; ++ iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier); ++ break; ++ case(E_FMAN_EX_BMI_STORAGE_PROFILE_ECC): ++ tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier); ++ if (enable) ++ tmp |= BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC; ++ else ++ tmp &= ~BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC; ++ iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier); ++ break; ++ case(E_FMAN_EX_BMI_STATISTICS_RAM_ECC): ++ tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier); ++ if (enable) ++ tmp |= BMI_ERR_INTR_EN_STATISTICS_RAM_ECC; ++ else ++ tmp &= ~BMI_ERR_INTR_EN_STATISTICS_RAM_ECC; ++ iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier); ++ break; ++ case(E_FMAN_EX_BMI_DISPATCH_RAM_ECC): ++ tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier); ++ if (enable) ++ tmp |= BMI_ERR_INTR_EN_DISPATCH_RAM_ECC; ++ else ++ tmp &= ~BMI_ERR_INTR_EN_DISPATCH_RAM_ECC; ++ iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier); ++ break; ++ case(E_FMAN_EX_IRAM_ECC): ++ tmp = ioread32be(&fman_rg->fpm_rg->fm_rie); ++ if (enable) { ++ /* enable ECC if not enabled */ ++ fman_enable_rams_ecc(fman_rg->fpm_rg); ++ /* enable ECC interrupts */ ++ tmp |= FPM_IRAM_ECC_ERR_EX_EN; ++ } else { ++ /* ECC mechanism may be disabled, ++ * depending on driver status */ ++ fman_disable_rams_ecc(fman_rg->fpm_rg); ++ tmp &= ~FPM_IRAM_ECC_ERR_EX_EN; ++ } ++ iowrite32be(tmp, &fman_rg->fpm_rg->fm_rie); ++ break; ++ case(E_FMAN_EX_MURAM_ECC): ++ tmp = ioread32be(&fman_rg->fpm_rg->fm_rie); ++ if (enable) { ++ /* enable ECC if not enabled */ ++ fman_enable_rams_ecc(fman_rg->fpm_rg); ++ /* enable ECC interrupts */ ++ tmp |= FPM_MURAM_ECC_ERR_EX_EN; ++ } else { ++ /* ECC mechanism may be disabled, ++ * depending on driver status */ ++ fman_disable_rams_ecc(fman_rg->fpm_rg); ++ tmp &= ~FPM_MURAM_ECC_ERR_EX_EN; ++ } ++ iowrite32be(tmp, &fman_rg->fpm_rg->fm_rie); ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++void fman_get_revision(struct fman_fpm_regs *fpm_rg, ++ uint8_t *major, ++ uint8_t *minor) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(&fpm_rg->fm_ip_rev_1); ++ *major = (uint8_t)((tmp & FPM_REV1_MAJOR_MASK) >> FPM_REV1_MAJOR_SHIFT); ++ *minor = (uint8_t)((tmp & FPM_REV1_MINOR_MASK) >> FPM_REV1_MINOR_SHIFT); ++ ++} ++ ++uint32_t fman_get_counter(struct fman_rg *fman_rg, ++ enum fman_counters reg_name) ++{ ++ uint32_t ret_val; ++ ++ switch (reg_name) { ++ case(E_FMAN_COUNTERS_ENQ_TOTAL_FRAME): ++ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_etfc); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_TOTAL_FRAME): ++ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dtfc); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_0): ++ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dc0); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_1): ++ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dc1); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_2): ++ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dc2); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_3): ++ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dc3); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_FROM_DEFAULT): ++ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dfdc); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_FROM_CONTEXT): ++ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dfcc); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_FROM_FD): ++ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dffc); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_CONFIRM): ++ ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dcc); ++ break; ++ default: ++ ret_val = 0; ++ } ++ return ret_val; ++} ++ ++int fman_modify_counter(struct fman_rg *fman_rg, ++ enum fman_counters reg_name, ++ uint32_t val) ++{ ++ /* When applicable (when there is an 'enable counters' bit, ++ * check that counters are enabled */ ++ switch (reg_name) { ++ case(E_FMAN_COUNTERS_ENQ_TOTAL_FRAME): ++ case(E_FMAN_COUNTERS_DEQ_TOTAL_FRAME): ++ case(E_FMAN_COUNTERS_DEQ_0): ++ case(E_FMAN_COUNTERS_DEQ_1): ++ case(E_FMAN_COUNTERS_DEQ_2): ++ case(E_FMAN_COUNTERS_DEQ_3): ++ case(E_FMAN_COUNTERS_DEQ_FROM_DEFAULT): ++ case(E_FMAN_COUNTERS_DEQ_FROM_CONTEXT): ++ case(E_FMAN_COUNTERS_DEQ_FROM_FD): ++ case(E_FMAN_COUNTERS_DEQ_CONFIRM): ++ if (!(ioread32be(&fman_rg->qmi_rg->fmqm_gc) & ++ QMI_CFG_EN_COUNTERS)) ++ return -EINVAL; ++ break; ++ default: ++ break; ++ } ++ /* Set counter */ ++ switch (reg_name) { ++ case(E_FMAN_COUNTERS_ENQ_TOTAL_FRAME): ++ iowrite32be(val, &fman_rg->qmi_rg->fmqm_etfc); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_TOTAL_FRAME): ++ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dtfc); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_0): ++ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dc0); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_1): ++ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dc1); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_2): ++ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dc2); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_3): ++ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dc3); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_FROM_DEFAULT): ++ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dfdc); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_FROM_CONTEXT): ++ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dfcc); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_FROM_FD): ++ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dffc); ++ break; ++ case(E_FMAN_COUNTERS_DEQ_CONFIRM): ++ iowrite32be(val, &fman_rg->qmi_rg->fmqm_dcc); ++ break; ++ case(E_FMAN_COUNTERS_SEMAPHOR_ENTRY_FULL_REJECT): ++ iowrite32be(val, &fman_rg->dma_rg->fmdmsefrc); ++ break; ++ case(E_FMAN_COUNTERS_SEMAPHOR_QUEUE_FULL_REJECT): ++ iowrite32be(val, &fman_rg->dma_rg->fmdmsqfrc); ++ break; ++ case(E_FMAN_COUNTERS_SEMAPHOR_SYNC_REJECT): ++ iowrite32be(val, &fman_rg->dma_rg->fmdmssrc); ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++void fman_set_dma_emergency(struct fman_dma_regs *dma_rg, ++ bool is_write, ++ bool enable) ++{ ++ uint32_t msk; ++ ++ msk = (uint32_t)(is_write ? DMA_MODE_EMER_WRITE : DMA_MODE_EMER_READ); ++ ++ if (enable) ++ iowrite32be(ioread32be(&dma_rg->fmdmmr) | msk, ++ &dma_rg->fmdmmr); ++ else /* disable */ ++ iowrite32be(ioread32be(&dma_rg->fmdmmr) & ~msk, ++ &dma_rg->fmdmmr); ++} ++ ++void fman_set_dma_ext_bus_pri(struct fman_dma_regs *dma_rg, uint32_t pri) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(&dma_rg->fmdmmr) | ++ (pri << DMA_MODE_BUS_PRI_SHIFT); ++ ++ iowrite32be(tmp, &dma_rg->fmdmmr); ++} ++ ++uint32_t fman_get_dma_status(struct fman_dma_regs *dma_rg) ++{ ++ return ioread32be(&dma_rg->fmdmsr); ++} ++ ++void fman_force_intr(struct fman_rg *fman_rg, ++ enum fman_exceptions exception) ++{ ++ switch (exception) { ++ case E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID: ++ iowrite32be(QMI_ERR_INTR_EN_DEQ_FROM_DEF, ++ &fman_rg->qmi_rg->fmqm_eif); ++ break; ++ case E_FMAN_EX_QMI_SINGLE_ECC: ++ iowrite32be(QMI_INTR_EN_SINGLE_ECC, ++ &fman_rg->qmi_rg->fmqm_if); ++ break; ++ case E_FMAN_EX_QMI_DOUBLE_ECC: ++ iowrite32be(QMI_ERR_INTR_EN_DOUBLE_ECC, ++ &fman_rg->qmi_rg->fmqm_eif); ++ break; ++ case E_FMAN_EX_BMI_LIST_RAM_ECC: ++ iowrite32be(BMI_ERR_INTR_EN_LIST_RAM_ECC, ++ &fman_rg->bmi_rg->fmbm_ifr); ++ break; ++ case E_FMAN_EX_BMI_STORAGE_PROFILE_ECC: ++ iowrite32be(BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC, ++ &fman_rg->bmi_rg->fmbm_ifr); ++ break; ++ case E_FMAN_EX_BMI_STATISTICS_RAM_ECC: ++ iowrite32be(BMI_ERR_INTR_EN_STATISTICS_RAM_ECC, ++ &fman_rg->bmi_rg->fmbm_ifr); ++ break; ++ case E_FMAN_EX_BMI_DISPATCH_RAM_ECC: ++ iowrite32be(BMI_ERR_INTR_EN_DISPATCH_RAM_ECC, ++ &fman_rg->bmi_rg->fmbm_ifr); ++ break; ++ default: ++ break; ++ } ++} ++ ++bool fman_is_qmi_halt_not_busy_state(struct fman_qmi_regs *qmi_rg) ++{ ++ return (bool)!!(ioread32be(&qmi_rg->fmqm_gs) & QMI_GS_HALT_NOT_BUSY); ++} ++void fman_resume(struct fman_fpm_regs *fpm_rg) ++{ ++ uint32_t tmp; ++ ++ tmp = ioread32be(&fpm_rg->fmfp_ee); ++ /* clear tmp_reg event bits in order not to clear standing events */ ++ tmp &= ~(FPM_EV_MASK_DOUBLE_ECC | ++ FPM_EV_MASK_STALL | ++ FPM_EV_MASK_SINGLE_ECC); ++ tmp |= FPM_EV_MASK_RELEASE_FM; ++ ++ iowrite32be(tmp, &fpm_rg->fmfp_ee); ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_common.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_common.h +new file mode 100644 +index 00000000..204840c9 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_common.h +@@ -0,0 +1,1214 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_common.h ++ ++ @Description FM internal structures and definitions. ++*//***************************************************************************/ ++#ifndef __FM_COMMON_H ++#define __FM_COMMON_H ++ ++#include "error_ext.h" ++#include "std_ext.h" ++#include "fm_pcd_ext.h" ++#include "fm_ext.h" ++#include "fm_port_ext.h" ++ ++ ++#define e_FM_PORT_TYPE_OH_HOST_COMMAND e_FM_PORT_TYPE_DUMMY ++ ++#define CLS_PLAN_NUM_PER_GRP 8 ++ ++#define IP_OFFLOAD_PACKAGE_NUMBER 106 ++#define CAPWAP_OFFLOAD_PACKAGE_NUMBER 108 ++#define IS_OFFLOAD_PACKAGE(num) ((num == IP_OFFLOAD_PACKAGE_NUMBER) || (num == CAPWAP_OFFLOAD_PACKAGE_NUMBER)) ++ ++ ++ ++/**************************************************************************//** ++ @Description Modules registers offsets ++*//***************************************************************************/ ++#define FM_MM_MURAM 0x00000000 ++#define FM_MM_BMI 0x00080000 ++#define FM_MM_QMI 0x00080400 ++#define FM_MM_PRS 0x000c7000 ++#define FM_MM_KG 0x000C1000 ++#define FM_MM_DMA 0x000C2000 ++#define FM_MM_FPM 0x000C3000 ++#define FM_MM_PLCR 0x000C0000 ++#define FM_MM_IMEM 0x000C4000 ++#define FM_MM_CGP 0x000DB000 ++#define FM_MM_TRB(i) (0x000D0200 + 0x400 * (i)) ++#if (DPAA_VERSION >= 11) ++#define FM_MM_SP 0x000dc000 ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ ++/**************************************************************************//** ++ @Description Enum for inter-module interrupts registration ++*//***************************************************************************/ ++typedef enum e_FmEventModules{ ++ e_FM_MOD_PRS, /**< Parser event */ ++ e_FM_MOD_KG, /**< Keygen event */ ++ e_FM_MOD_PLCR, /**< Policer event */ ++ e_FM_MOD_10G_MAC, /**< 10G MAC event */ ++ e_FM_MOD_1G_MAC, /**< 1G MAC event */ ++ e_FM_MOD_TMR, /**< Timer event */ ++ e_FM_MOD_FMAN_CTRL, /**< FMAN Controller Timer event */ ++ e_FM_MOD_MACSEC, ++ e_FM_MOD_DUMMY_LAST ++} e_FmEventModules; ++ ++/**************************************************************************//** ++ @Description Enum for interrupts types ++*//***************************************************************************/ ++typedef enum e_FmIntrType { ++ e_FM_INTR_TYPE_ERR, ++ e_FM_INTR_TYPE_NORMAL ++} e_FmIntrType; ++ ++/**************************************************************************//** ++ @Description Enum for inter-module interrupts registration ++*//***************************************************************************/ ++typedef enum e_FmInterModuleEvent ++{ ++ e_FM_EV_PRS = 0, /**< Parser event */ ++ e_FM_EV_ERR_PRS, /**< Parser error event */ ++ e_FM_EV_KG, /**< Keygen event */ ++ e_FM_EV_ERR_KG, /**< Keygen error event */ ++ e_FM_EV_PLCR, /**< Policer event */ ++ e_FM_EV_ERR_PLCR, /**< Policer error event */ ++ e_FM_EV_ERR_10G_MAC0, /**< 10G MAC 0 error event */ ++ e_FM_EV_ERR_10G_MAC1, /**< 10G MAC 1 error event */ ++ e_FM_EV_ERR_1G_MAC0, /**< 1G MAC 0 error event */ ++ e_FM_EV_ERR_1G_MAC1, /**< 1G MAC 1 error event */ ++ e_FM_EV_ERR_1G_MAC2, /**< 1G MAC 2 error event */ ++ e_FM_EV_ERR_1G_MAC3, /**< 1G MAC 3 error event */ ++ e_FM_EV_ERR_1G_MAC4, /**< 1G MAC 4 error event */ ++ e_FM_EV_ERR_1G_MAC5, /**< 1G MAC 5 error event */ ++ e_FM_EV_ERR_1G_MAC6, /**< 1G MAC 6 error event */ ++ e_FM_EV_ERR_1G_MAC7, /**< 1G MAC 7 error event */ ++ e_FM_EV_ERR_MACSEC_MAC0, ++ e_FM_EV_TMR, /**< Timer event */ ++ e_FM_EV_10G_MAC0, /**< 10G MAC 0 event (Magic packet detection)*/ ++ e_FM_EV_10G_MAC1, /**< 10G MAC 1 event (Magic packet detection)*/ ++ e_FM_EV_1G_MAC0, /**< 1G MAC 0 event (Magic packet detection)*/ ++ e_FM_EV_1G_MAC1, /**< 1G MAC 1 event (Magic packet detection)*/ ++ e_FM_EV_1G_MAC2, /**< 1G MAC 2 (Magic packet detection)*/ ++ e_FM_EV_1G_MAC3, /**< 1G MAC 3 (Magic packet detection)*/ ++ e_FM_EV_1G_MAC4, /**< 1G MAC 4 (Magic packet detection)*/ ++ e_FM_EV_1G_MAC5, /**< 1G MAC 5 (Magic packet detection)*/ ++ e_FM_EV_1G_MAC6, /**< 1G MAC 6 (Magic packet detection)*/ ++ e_FM_EV_1G_MAC7, /**< 1G MAC 7 (Magic packet detection)*/ ++ e_FM_EV_MACSEC_MAC0, /**< MACSEC MAC 0 event */ ++ e_FM_EV_FMAN_CTRL_0, /**< Fman controller event 0 */ ++ e_FM_EV_FMAN_CTRL_1, /**< Fman controller event 1 */ ++ e_FM_EV_FMAN_CTRL_2, /**< Fman controller event 2 */ ++ e_FM_EV_FMAN_CTRL_3, /**< Fman controller event 3 */ ++ e_FM_EV_DUMMY_LAST ++} e_FmInterModuleEvent; ++ ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(push,1) ++#endif /* defined(__MWERKS__) && ... */ ++ ++/**************************************************************************//** ++ @Description PCD KG scheme registers ++*//***************************************************************************/ ++typedef _Packed struct t_FmPcdPlcrProfileRegs { ++ volatile uint32_t fmpl_pemode; /* 0x090 FMPL_PEMODE - FM Policer Profile Entry Mode*/ ++ volatile uint32_t fmpl_pegnia; /* 0x094 FMPL_PEGNIA - FM Policer Profile Entry GREEN Next Invoked Action*/ ++ volatile uint32_t fmpl_peynia; /* 0x098 FMPL_PEYNIA - FM Policer Profile Entry YELLOW Next Invoked Action*/ ++ volatile uint32_t fmpl_pernia; /* 0x09C FMPL_PERNIA - FM Policer Profile Entry RED Next Invoked Action*/ ++ volatile uint32_t fmpl_pecir; /* 0x0A0 FMPL_PECIR - FM Policer Profile Entry Committed Information Rate*/ ++ volatile uint32_t fmpl_pecbs; /* 0x0A4 FMPL_PECBS - FM Policer Profile Entry Committed Burst Size*/ ++ volatile uint32_t fmpl_pepepir_eir; /* 0x0A8 FMPL_PEPIR_EIR - FM Policer Profile Entry Peak/Excess Information Rate*/ ++ volatile uint32_t fmpl_pepbs_ebs; /* 0x0AC FMPL_PEPBS_EBS - FM Policer Profile Entry Peak/Excess Information Rate*/ ++ volatile uint32_t fmpl_pelts; /* 0x0B0 FMPL_PELTS - FM Policer Profile Entry Last TimeStamp*/ ++ volatile uint32_t fmpl_pects; /* 0x0B4 FMPL_PECTS - FM Policer Profile Entry Committed Token Status*/ ++ volatile uint32_t fmpl_pepts_ets; /* 0x0B8 FMPL_PEPTS_ETS - FM Policer Profile Entry Peak/Excess Token Status*/ ++ volatile uint32_t fmpl_pegpc; /* 0x0BC FMPL_PEGPC - FM Policer Profile Entry GREEN Packet Counter*/ ++ volatile uint32_t fmpl_peypc; /* 0x0C0 FMPL_PEYPC - FM Policer Profile Entry YELLOW Packet Counter*/ ++ volatile uint32_t fmpl_perpc; /* 0x0C4 FMPL_PERPC - FM Policer Profile Entry RED Packet Counter */ ++ volatile uint32_t fmpl_perypc; /* 0x0C8 FMPL_PERYPC - FM Policer Profile Entry Recolored YELLOW Packet Counter*/ ++ volatile uint32_t fmpl_perrpc; /* 0x0CC FMPL_PERRPC - FM Policer Profile Entry Recolored RED Packet Counter*/ ++ volatile uint32_t fmpl_res1[12]; /* 0x0D0-0x0FF Reserved */ ++} _PackedType t_FmPcdPlcrProfileRegs; ++ ++ ++typedef _Packed struct t_FmPcdCcCapwapReassmTimeoutParams { ++ volatile uint32_t portIdAndCapwapReassmTbl; ++ volatile uint32_t fqidForTimeOutFrames; ++ volatile uint32_t timeoutRequestTime; ++}_PackedType t_FmPcdCcCapwapReassmTimeoutParams; ++ ++/**************************************************************************//** ++ @Description PCD CTRL Parameters Page ++*//***************************************************************************/ ++typedef _Packed struct t_FmPcdCtrlParamsPage { ++ volatile uint8_t reserved0[16]; ++ volatile uint32_t iprIpv4Nia; ++ volatile uint32_t iprIpv6Nia; ++ volatile uint8_t reserved1[24]; ++ volatile uint32_t ipfOptionsCounter; ++ volatile uint8_t reserved2[12]; ++ volatile uint32_t misc; ++ volatile uint32_t errorsDiscardMask; ++ volatile uint32_t discardMask; ++ volatile uint8_t reserved3[4]; ++ volatile uint32_t postBmiFetchNia; ++ volatile uint8_t reserved4[172]; ++} _PackedType t_FmPcdCtrlParamsPage; ++ ++ ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(pop) ++#endif /* defined(__MWERKS__) && ... */ ++ ++ ++/*for UNDER_CONSTRUCTION_FM_RMU_USE_SEC its defined in fm_ext.h*/ ++typedef uint32_t t_FmFmanCtrl; ++ ++#define FPM_PORT_FM_CTL1 0x00000001 ++#define FPM_PORT_FM_CTL2 0x00000002 ++ ++ ++ ++typedef struct t_FmPcdCcFragScratchPoolCmdParams { ++ uint32_t numOfBuffers; ++ uint8_t bufferPoolId; ++} t_FmPcdCcFragScratchPoolCmdParams; ++ ++typedef struct t_FmPcdCcReassmTimeoutParams { ++ bool activate; ++ uint8_t tsbs; ++ uint32_t iprcpt; ++} t_FmPcdCcReassmTimeoutParams; ++ ++typedef struct { ++ uint8_t baseEntry; ++ uint16_t numOfClsPlanEntries; ++ uint32_t vectors[FM_PCD_MAX_NUM_OF_CLS_PLANS]; ++} t_FmPcdKgInterModuleClsPlanSet; ++ ++/**************************************************************************//** ++ @Description Structure for binding a port to keygen schemes. ++*//***************************************************************************/ ++typedef struct t_FmPcdKgInterModuleBindPortToSchemes { ++ uint8_t hardwarePortId; ++ uint8_t netEnvId; ++ bool useClsPlan; /**< TRUE if this port uses the clsPlan mechanism */ ++ uint8_t numOfSchemes; ++ uint8_t schemesIds[FM_PCD_KG_NUM_OF_SCHEMES]; ++} t_FmPcdKgInterModuleBindPortToSchemes; ++ ++typedef struct { ++ uint32_t nextCcNodeInfo; ++ t_List node; ++} t_CcNodeInfo; ++ ++typedef struct ++{ ++ t_Handle h_CcNode; ++ uint16_t index; ++ t_List node; ++}t_CcNodeInformation; ++#define CC_NODE_F_OBJECT(ptr) LIST_OBJECT(ptr, t_CcNodeInformation, node) ++ ++typedef enum e_ModifyState ++{ ++ e_MODIFY_STATE_ADD = 0, ++ e_MODIFY_STATE_REMOVE, ++ e_MODIFY_STATE_CHANGE ++} e_ModifyState; ++ ++typedef struct ++{ ++ t_Handle h_Manip; ++ t_List node; ++}t_ManipInfo; ++#define CC_NEXT_NODE_F_OBJECT(ptr) LIST_OBJECT(ptr, t_CcNodeInfo, node) ++ ++typedef struct { ++ uint32_t type; ++ uint8_t prOffset; ++ uint16_t dataOffset; ++ uint8_t internalBufferOffset; ++ uint8_t numOfTasks; ++ uint8_t numOfExtraTasks; ++ uint8_t hardwarePortId; ++ t_FmRevisionInfo revInfo; ++ uint32_t nia; ++ uint32_t discardMask; ++} t_GetCcParams; ++ ++typedef struct { ++ uint32_t type; ++ int psoSize; ++ uint32_t nia; ++ t_FmFmanCtrl orFmanCtrl; ++ bool overwrite; ++ uint8_t ofpDpde; ++} t_SetCcParams; ++ ++typedef struct { ++ t_GetCcParams getCcParams; ++ t_SetCcParams setCcParams; ++} t_FmPortGetSetCcParams; ++ ++typedef struct { ++ uint32_t type; ++ bool sleep; ++} t_FmSetParams; ++ ++typedef struct { ++ uint32_t type; ++ uint32_t fmqm_gs; ++ uint32_t fm_npi; ++ uint32_t fm_cld; ++ uint32_t fmfp_extc; ++} t_FmGetParams; ++ ++typedef struct { ++ t_FmSetParams setParams; ++ t_FmGetParams getParams; ++} t_FmGetSetParams; ++ ++t_Error FmGetSetParams(t_Handle h_Fm, t_FmGetSetParams *p_Params); ++ ++static __inline__ bool TRY_LOCK(t_Handle h_Spinlock, volatile bool *p_Flag) ++{ ++ uint32_t intFlags; ++ if (h_Spinlock) ++ intFlags = XX_LockIntrSpinlock(h_Spinlock); ++ else ++ intFlags = XX_DisableAllIntr(); ++ ++ if (*p_Flag) ++ { ++ if (h_Spinlock) ++ XX_UnlockIntrSpinlock(h_Spinlock, intFlags); ++ else ++ XX_RestoreAllIntr(intFlags); ++ return FALSE; ++ } ++ *p_Flag = TRUE; ++ ++ if (h_Spinlock) ++ XX_UnlockIntrSpinlock(h_Spinlock, intFlags); ++ else ++ XX_RestoreAllIntr(intFlags); ++ ++ return TRUE; ++} ++ ++#define RELEASE_LOCK(_flag) _flag = FALSE; ++ ++/**************************************************************************//** ++ @Collection Defines used for manipulation CC and BMI ++ @{ ++*//***************************************************************************/ ++#define INTERNAL_CONTEXT_OFFSET 0x80000000 ++#define OFFSET_OF_PR 0x40000000 ++#define MANIP_EXTRA_SPACE 0x20000000 ++#define NUM_OF_TASKS 0x10000000 ++#define OFFSET_OF_DATA 0x08000000 ++#define HW_PORT_ID 0x04000000 ++#define FM_REV 0x02000000 ++#define GET_NIA_FPNE 0x01000000 ++#define GET_NIA_PNDN 0x00800000 ++#define NUM_OF_EXTRA_TASKS 0x00400000 ++#define DISCARD_MASK 0x00200000 ++ ++#define UPDATE_NIA_PNEN 0x80000000 ++#define UPDATE_PSO 0x40000000 ++#define UPDATE_NIA_PNDN 0x20000000 ++#define UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY 0x10000000 ++#define UPDATE_OFP_DPTE 0x08000000 ++#define UPDATE_NIA_FENE 0x04000000 ++#define UPDATE_NIA_CMNE 0x02000000 ++#define UPDATE_NIA_FPNE 0x01000000 ++/* @} */ ++ ++/**************************************************************************//** ++ @Collection Defines used for manipulation CC and CC ++ @{ ++*//***************************************************************************/ ++#define UPDATE_NIA_ENQ_WITHOUT_DMA 0x80000000 ++#define UPDATE_CC_WITH_TREE 0x40000000 ++#define UPDATE_CC_WITH_DELETE_TREE 0x20000000 ++#define UPDATE_KG_NIA_CC_WA 0x10000000 ++#define UPDATE_KG_OPT_MODE 0x08000000 ++#define UPDATE_KG_NIA 0x04000000 ++#define UPDATE_CC_SHADOW_CLEAR 0x02000000 ++/* @} */ ++ ++#define UPDATE_FPM_BRKC_SLP 0x80000000 ++#define UPDATE_FPM_EXTC 0x40000000 ++#define UPDATE_FPM_EXTC_CLEAR 0x20000000 ++#define GET_FMQM_GS 0x10000000 ++#define GET_FM_NPI 0x08000000 ++#define GET_FMFP_EXTC 0x04000000 ++#define CLEAR_IRAM_READY 0x02000000 ++#define UPDATE_FM_CLD 0x01000000 ++#define GET_FM_CLD 0x00800000 ++#define FM_MAX_NUM_OF_PORTS (FM_MAX_NUM_OF_OH_PORTS + \ ++ FM_MAX_NUM_OF_1G_RX_PORTS + \ ++ FM_MAX_NUM_OF_10G_RX_PORTS + \ ++ FM_MAX_NUM_OF_1G_TX_PORTS + \ ++ FM_MAX_NUM_OF_10G_TX_PORTS) ++ ++#define MODULE_NAME_SIZE 30 ++#define DUMMY_PORT_ID 0 ++ ++#define FM_LIODN_OFFSET_MASK 0x3FF ++ ++/**************************************************************************//** ++ @Description NIA Description ++*//***************************************************************************/ ++#define NIA_ENG_MASK 0x007C0000 ++#define NIA_AC_MASK 0x0003ffff ++ ++#define NIA_ORDER_RESTOR 0x00800000 ++#define NIA_ENG_FM_CTL 0x00000000 ++#define NIA_ENG_PRS 0x00440000 ++#define NIA_ENG_KG 0x00480000 ++#define NIA_ENG_PLCR 0x004C0000 ++#define NIA_ENG_BMI 0x00500000 ++#define NIA_ENG_QMI_ENQ 0x00540000 ++#define NIA_ENG_QMI_DEQ 0x00580000 ++ ++#define NIA_FM_CTL_AC_CC 0x00000006 ++#define NIA_FM_CTL_AC_HC 0x0000000C ++#define NIA_FM_CTL_AC_IND_MODE_TX 0x00000008 ++#define NIA_FM_CTL_AC_IND_MODE_RX 0x0000000A ++#define NIA_FM_CTL_AC_POP_TO_N_STEP 0x0000000e ++#define NIA_FM_CTL_AC_PRE_BMI_FETCH_HEADER 0x00000010 ++#define NIA_FM_CTL_AC_PRE_BMI_FETCH_FULL_FRAME 0x00000018 ++#define NIA_FM_CTL_AC_POST_BMI_FETCH 0x00000012 ++#define NIA_FM_CTL_AC_PRE_BMI_ENQ_FRAME 0x0000001A ++#define NIA_FM_CTL_AC_PRE_BMI_DISCARD_FRAME 0x0000001E ++#define NIA_FM_CTL_AC_POST_BMI_ENQ_ORR 0x00000014 ++#define NIA_FM_CTL_AC_POST_BMI_ENQ 0x00000022 ++#define NIA_FM_CTL_AC_PRE_CC 0x00000020 ++#define NIA_FM_CTL_AC_POST_TX 0x00000024 ++/* V3 only */ ++#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME 0x00000028 ++#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_DISCARD_FRAME 0x0000002A ++#define NIA_FM_CTL_AC_NO_IPACC_POP_TO_N_STEP 0x0000002C ++ ++#define NIA_BMI_AC_ENQ_FRAME 0x00000002 ++#define NIA_BMI_AC_TX_RELEASE 0x000002C0 ++#define NIA_BMI_AC_RELEASE 0x000000C0 ++#define NIA_BMI_AC_DISCARD 0x000000C1 ++#define NIA_BMI_AC_TX 0x00000274 ++#define NIA_BMI_AC_FETCH 0x00000208 ++#define NIA_BMI_AC_MASK 0x000003FF ++ ++#define NIA_KG_DIRECT 0x00000100 ++#define NIA_KG_CC_EN 0x00000200 ++#define NIA_PLCR_ABSOLUTE 0x00008000 ++ ++#define NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA 0x00000202 ++ ++#if defined(FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675) || defined(FM_ERROR_VSP_NO_MATCH_SW006) ++#define GET_NIA_BMI_AC_ENQ_FRAME(h_FmPcd) \ ++ (uint32_t)((FmPcdIsAdvancedOffloadSupported(h_FmPcd)) ? \ ++ (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_PRE_BMI_ENQ_FRAME) : \ ++ (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME)) ++#define GET_NIA_BMI_AC_DISCARD_FRAME(h_FmPcd) \ ++ (uint32_t)((FmPcdIsAdvancedOffloadSupported(h_FmPcd)) ? \ ++ (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_PRE_BMI_DISCARD_FRAME) : \ ++ (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_DISCARD_FRAME)) ++#define GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME() \ ++ (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME) ++#else ++#define GET_NIA_BMI_AC_ENQ_FRAME(h_FmPcd) \ ++ (uint32_t)((FmPcdIsAdvancedOffloadSupported(h_FmPcd)) ? \ ++ (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_PRE_BMI_ENQ_FRAME) : \ ++ (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)) ++#define GET_NIA_BMI_AC_DISCARD_FRAME(h_FmPcd) \ ++ (uint32_t)((FmPcdIsAdvancedOffloadSupported(h_FmPcd)) ? \ ++ (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_PRE_BMI_DISCARD_FRAME) : \ ++ (NIA_ENG_BMI | NIA_BMI_AC_DISCARD)) ++#define GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME() \ ++ (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME) ++#endif /* defined(FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675) || ... */ ++ ++/**************************************************************************//** ++ @Description CTRL Parameters Page defines ++*//***************************************************************************/ ++#define FM_CTL_PARAMS_PAGE_OP_FIX_EN 0x80000000 ++#define FM_CTL_PARAMS_PAGE_OFFLOAD_SUPPORT_EN 0x40000000 ++#define FM_CTL_PARAMS_PAGE_ALWAYS_ON 0x00000100 ++ ++#define FM_CTL_PARAMS_PAGE_ERROR_VSP_MASK 0x0000003f ++ ++/**************************************************************************//** ++ @Description Port Id defines ++*//***************************************************************************/ ++#if (DPAA_VERSION == 10) ++#define BASE_OH_PORTID 1 ++#else ++#define BASE_OH_PORTID 2 ++#endif /* (DPAA_VERSION == 10) */ ++#define BASE_1G_RX_PORTID 8 ++#define BASE_10G_RX_PORTID 0x10 ++#define BASE_1G_TX_PORTID 0x28 ++#define BASE_10G_TX_PORTID 0x30 ++ ++#define FM_PCD_PORT_OH_BASE_INDX 0 ++#define FM_PCD_PORT_1G_RX_BASE_INDX (FM_PCD_PORT_OH_BASE_INDX+FM_MAX_NUM_OF_OH_PORTS) ++#define FM_PCD_PORT_10G_RX_BASE_INDX (FM_PCD_PORT_1G_RX_BASE_INDX+FM_MAX_NUM_OF_1G_RX_PORTS) ++#define FM_PCD_PORT_1G_TX_BASE_INDX (FM_PCD_PORT_10G_RX_BASE_INDX+FM_MAX_NUM_OF_10G_RX_PORTS) ++#define FM_PCD_PORT_10G_TX_BASE_INDX (FM_PCD_PORT_1G_TX_BASE_INDX+FM_MAX_NUM_OF_1G_TX_PORTS) ++ ++#if (FM_MAX_NUM_OF_OH_PORTS > 0) ++#define CHECK_PORT_ID_OH_PORTS(_relativePortId) \ ++ if ((_relativePortId) >= FM_MAX_NUM_OF_OH_PORTS) \ ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal OH_PORT port id")) ++#else ++#define CHECK_PORT_ID_OH_PORTS(_relativePortId) \ ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal OH_PORT port id")) ++#endif ++#if (FM_MAX_NUM_OF_1G_RX_PORTS > 0) ++#define CHECK_PORT_ID_1G_RX_PORTS(_relativePortId) \ ++ if ((_relativePortId) >= FM_MAX_NUM_OF_1G_RX_PORTS) \ ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_RX_PORT port id")) ++#else ++#define CHECK_PORT_ID_1G_RX_PORTS(_relativePortId) \ ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_RX_PORT port id")) ++#endif ++#if (FM_MAX_NUM_OF_10G_RX_PORTS > 0) ++#define CHECK_PORT_ID_10G_RX_PORTS(_relativePortId) \ ++ if ((_relativePortId) >= FM_MAX_NUM_OF_10G_RX_PORTS) \ ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_RX_PORT port id")) ++#else ++#define CHECK_PORT_ID_10G_RX_PORTS(_relativePortId) \ ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_RX_PORT port id")) ++#endif ++#if (FM_MAX_NUM_OF_1G_TX_PORTS > 0) ++#define CHECK_PORT_ID_1G_TX_PORTS(_relativePortId) \ ++ if ((_relativePortId) >= FM_MAX_NUM_OF_1G_TX_PORTS) \ ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_TX_PORT port id")) ++#else ++#define CHECK_PORT_ID_1G_TX_PORTS(_relativePortId) \ ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_TX_PORT port id")) ++#endif ++#if (FM_MAX_NUM_OF_10G_TX_PORTS > 0) ++#define CHECK_PORT_ID_10G_TX_PORTS(_relativePortId) \ ++ if ((_relativePortId) >= FM_MAX_NUM_OF_10G_TX_PORTS) \ ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_TX_PORT port id")) ++#else ++#define CHECK_PORT_ID_10G_TX_PORTS(_relativePortId) \ ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_TX_PORT port id")) ++#endif ++ ++uint8_t SwPortIdToHwPortId(e_FmPortType type, uint8_t relativePortId, uint8_t majorRev, uint8_t minorRev); ++ ++#define HW_PORT_ID_TO_SW_PORT_ID(_relativePortId, hardwarePortId) \ ++{ if (((hardwarePortId) >= BASE_OH_PORTID) && \ ++ ((hardwarePortId) < BASE_OH_PORTID+FM_MAX_NUM_OF_OH_PORTS)) \ ++ _relativePortId = (uint8_t)((hardwarePortId)-BASE_OH_PORTID); \ ++ else if (((hardwarePortId) >= BASE_10G_TX_PORTID) && \ ++ ((hardwarePortId) < BASE_10G_TX_PORTID+FM_MAX_NUM_OF_10G_TX_PORTS)) \ ++ _relativePortId = (uint8_t)((hardwarePortId)-BASE_10G_TX_PORTID); \ ++ else if (((hardwarePortId) >= BASE_1G_TX_PORTID) && \ ++ ((hardwarePortId) < BASE_1G_TX_PORTID+FM_MAX_NUM_OF_1G_TX_PORTS)) \ ++ _relativePortId = (uint8_t)((hardwarePortId)-BASE_1G_TX_PORTID); \ ++ else if (((hardwarePortId) >= BASE_10G_RX_PORTID) && \ ++ ((hardwarePortId) < BASE_10G_RX_PORTID+FM_MAX_NUM_OF_10G_RX_PORTS)) \ ++ _relativePortId = (uint8_t)((hardwarePortId)-BASE_10G_RX_PORTID); \ ++ else if (((hardwarePortId) >= BASE_1G_RX_PORTID) && \ ++ ((hardwarePortId) < BASE_1G_RX_PORTID+FM_MAX_NUM_OF_1G_RX_PORTS)) \ ++ _relativePortId = (uint8_t)((hardwarePortId)-BASE_1G_RX_PORTID); \ ++ else { \ ++ _relativePortId = (uint8_t)DUMMY_PORT_ID; \ ++ ASSERT_COND(TRUE); \ ++ } \ ++} ++ ++#define HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId) \ ++do { \ ++ if (((hardwarePortId) >= BASE_OH_PORTID) && ((hardwarePortId) < BASE_OH_PORTID+FM_MAX_NUM_OF_OH_PORTS)) \ ++ swPortIndex = (uint8_t)((hardwarePortId)-BASE_OH_PORTID+FM_PCD_PORT_OH_BASE_INDX); \ ++ else if (((hardwarePortId) >= BASE_1G_RX_PORTID) && \ ++ ((hardwarePortId) < BASE_1G_RX_PORTID+FM_MAX_NUM_OF_1G_RX_PORTS)) \ ++ swPortIndex = (uint8_t)((hardwarePortId)-BASE_1G_RX_PORTID+FM_PCD_PORT_1G_RX_BASE_INDX); \ ++ else if (((hardwarePortId) >= BASE_10G_RX_PORTID) && \ ++ ((hardwarePortId) < BASE_10G_RX_PORTID+FM_MAX_NUM_OF_10G_RX_PORTS)) \ ++ swPortIndex = (uint8_t)((hardwarePortId)-BASE_10G_RX_PORTID+FM_PCD_PORT_10G_RX_BASE_INDX); \ ++ else if (((hardwarePortId) >= BASE_1G_TX_PORTID) && \ ++ ((hardwarePortId) < BASE_1G_TX_PORTID+FM_MAX_NUM_OF_1G_TX_PORTS)) \ ++ swPortIndex = (uint8_t)((hardwarePortId)-BASE_1G_TX_PORTID+FM_PCD_PORT_1G_TX_BASE_INDX); \ ++ else if (((hardwarePortId) >= BASE_10G_TX_PORTID) && \ ++ ((hardwarePortId) < BASE_10G_TX_PORTID+FM_MAX_NUM_OF_10G_TX_PORTS)) \ ++ swPortIndex = (uint8_t)((hardwarePortId)-BASE_10G_TX_PORTID+FM_PCD_PORT_10G_TX_BASE_INDX); \ ++ else ASSERT_COND(FALSE); \ ++} while (0) ++ ++#define SW_PORT_INDX_TO_HW_PORT_ID(hardwarePortId, swPortIndex) \ ++do { \ ++ if (((swPortIndex) >= FM_PCD_PORT_OH_BASE_INDX) && ((swPortIndex) < FM_PCD_PORT_1G_RX_BASE_INDX)) \ ++ hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_OH_BASE_INDX+BASE_OH_PORTID); \ ++ else if (((swPortIndex) >= FM_PCD_PORT_1G_RX_BASE_INDX) && ((swPortIndex) < FM_PCD_PORT_10G_RX_BASE_INDX)) \ ++ hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_1G_RX_BASE_INDX+BASE_1G_RX_PORTID); \ ++ else if (((swPortIndex) >= FM_PCD_PORT_10G_RX_BASE_INDX) && ((swPortIndex) < FM_MAX_NUM_OF_PORTS)) \ ++ hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_10G_RX_BASE_INDX+BASE_10G_RX_PORTID); \ ++ else if (((swPortIndex) >= FM_PCD_PORT_1G_TX_BASE_INDX) && ((swPortIndex) < FM_PCD_PORT_10G_TX_BASE_INDX)) \ ++ hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_1G_TX_BASE_INDX+BASE_1G_TX_PORTID); \ ++ else if (((swPortIndex) >= FM_PCD_PORT_10G_TX_BASE_INDX) && ((swPortIndex) < FM_MAX_NUM_OF_PORTS)) \ ++ hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_10G_TX_BASE_INDX+BASE_10G_TX_PORTID); \ ++ else ASSERT_COND(FALSE); \ ++} while (0) ++ ++#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE) ++#define BMI_FIFO_UNITS 0x100 ++ ++typedef struct { ++ void (*f_Isr) (t_Handle h_Arg); ++ t_Handle h_SrcHandle; ++ uint8_t guestId; ++} t_FmIntrSrc; ++ ++#define ILLEGAL_HDR_NUM 0xFF ++#define NO_HDR_NUM FM_PCD_PRS_NUM_OF_HDRS ++ ++#define IS_PRIVATE_HEADER(hdr) (((hdr) == HEADER_TYPE_USER_DEFINED_SHIM1) || \ ++ ((hdr) == HEADER_TYPE_USER_DEFINED_SHIM2)) ++#define IS_SPECIAL_HEADER(hdr) ((hdr) == HEADER_TYPE_MACSEC) ++ ++static __inline__ uint8_t GetPrsHdrNum(e_NetHeaderType hdr) ++{ ++ switch (hdr) ++ { case (HEADER_TYPE_ETH): return 0; ++ case (HEADER_TYPE_LLC_SNAP): return 1; ++ case (HEADER_TYPE_VLAN): return 2; ++ case (HEADER_TYPE_PPPoE): return 3; ++ case (HEADER_TYPE_PPP): return 3; ++ case (HEADER_TYPE_MPLS): return 4; ++ case (HEADER_TYPE_IPv4): return 5; ++ case (HEADER_TYPE_IPv6): return 6; ++ case (HEADER_TYPE_GRE): return 7; ++ case (HEADER_TYPE_MINENCAP): return 8; ++ case (HEADER_TYPE_USER_DEFINED_L3): return 9; ++ case (HEADER_TYPE_TCP): return 10; ++ case (HEADER_TYPE_UDP): return 11; ++ case (HEADER_TYPE_IPSEC_AH): ++ case (HEADER_TYPE_IPSEC_ESP): return 12; ++ case (HEADER_TYPE_SCTP): return 13; ++ case (HEADER_TYPE_DCCP): return 14; ++ case (HEADER_TYPE_USER_DEFINED_L4): return 15; ++ case (HEADER_TYPE_USER_DEFINED_SHIM1): ++ case (HEADER_TYPE_USER_DEFINED_SHIM2): ++ case (HEADER_TYPE_MACSEC): return NO_HDR_NUM; ++ default: ++ return ILLEGAL_HDR_NUM; ++ } ++} ++ ++#define FM_PCD_MAX_NUM_OF_OPTIONS(clsPlanEntries) ((clsPlanEntries==256)? 8:((clsPlanEntries==128)? 7: ((clsPlanEntries==64)? 6: ((clsPlanEntries==32)? 5:0)))) ++ ++ ++/**************************************************************************//** ++ @Description A structure for initializing a keygen classification plan group ++*//***************************************************************************/ ++typedef struct t_FmPcdKgInterModuleClsPlanGrpParams { ++ uint8_t netEnvId; /* IN */ ++ bool grpExists; /* OUT (unused in FmPcdKgBuildClsPlanGrp)*/ ++ uint8_t clsPlanGrpId; /* OUT */ ++ bool emptyClsPlanGrp; /* OUT */ ++ uint8_t numOfOptions; /* OUT in FmPcdGetSetClsPlanGrpParams IN in FmPcdKgBuildClsPlanGrp*/ ++ protocolOpt_t options[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)]; ++ /* OUT in FmPcdGetSetClsPlanGrpParams IN in FmPcdKgBuildClsPlanGrp*/ ++ uint32_t optVectors[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)]; ++ /* OUT in FmPcdGetSetClsPlanGrpParams IN in FmPcdKgBuildClsPlanGrp*/ ++} t_FmPcdKgInterModuleClsPlanGrpParams; ++ ++typedef struct t_FmPcdLock { ++ t_Handle h_Spinlock; ++ volatile bool flag; ++ t_List node; ++} t_FmPcdLock; ++#define FM_PCD_LOCK_OBJ(ptr) LIST_OBJECT(ptr, t_FmPcdLock, node) ++ ++ ++typedef t_Error (t_FmPortGetSetCcParamsCallback) (t_Handle h_FmPort, ++ t_FmPortGetSetCcParams *p_FmPortGetSetCcParams); ++ ++ ++/***********************************************************************/ ++/* Common API for FM-PCD module */ ++/***********************************************************************/ ++t_Handle FmPcdGetHcHandle(t_Handle h_FmPcd); ++uint32_t FmPcdGetSwPrsOffset(t_Handle h_FmPcd, e_NetHeaderType hdr, uint8_t indexPerHdr); ++uint32_t FmPcdGetLcv(t_Handle h_FmPcd, uint32_t netEnvId, uint8_t hdrNum); ++uint32_t FmPcdGetMacsecLcv(t_Handle h_FmPcd, uint32_t netEnvId); ++void FmPcdIncNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId); ++void FmPcdDecNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId); ++uint8_t FmPcdGetNetEnvId(t_Handle h_NetEnv); ++void FmPcdPortRegister(t_Handle h_FmPcd, t_Handle h_FmPort, uint8_t hardwarePortId); ++uint32_t FmPcdLock(t_Handle h_FmPcd); ++void FmPcdUnlock(t_Handle h_FmPcd, uint32_t intFlags); ++bool FmPcdNetEnvIsHdrExist(t_Handle h_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr); ++t_Error FmPcdFragHcScratchPoolInit(t_Handle h_FmPcd, uint8_t scratchBpid); ++t_Error FmPcdRegisterReassmPort(t_Handle h_FmPcd, t_Handle h_IpReasmCommonPramTbl); ++t_Error FmPcdUnregisterReassmPort(t_Handle h_FmPcd, t_Handle h_IpReasmCommonPramTbl); ++bool FmPcdIsAdvancedOffloadSupported(t_Handle h_FmPcd); ++bool FmPcdLockTryLockAll(t_Handle h_FmPcd); ++void FmPcdLockUnlockAll(t_Handle h_FmPcd); ++t_Error FmPcdHcSync(t_Handle h_FmPcd); ++t_Handle FmGetPcd(t_Handle h_Fm); ++/***********************************************************************/ ++/* Common API for FM-PCD KG module */ ++/***********************************************************************/ ++uint8_t FmPcdKgGetClsPlanGrpBase(t_Handle h_FmPcd, uint8_t clsPlanGrp); ++uint16_t FmPcdKgGetClsPlanGrpSize(t_Handle h_FmPcd, uint8_t clsPlanGrp); ++t_Error FmPcdKgBuildClsPlanGrp(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_Grp, t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet); ++ ++uint8_t FmPcdKgGetSchemeId(t_Handle h_Scheme); ++#if (DPAA_VERSION >= 11) ++bool FmPcdKgGetVspe(t_Handle h_Scheme); ++#endif /* (DPAA_VERSION >= 11) */ ++uint8_t FmPcdKgGetRelativeSchemeId(t_Handle h_FmPcd, uint8_t schemeId); ++void FmPcdKgDestroyClsPlanGrp(t_Handle h_FmPcd, uint8_t grpId); ++t_Error FmPcdKgCheckInvalidateSchemeSw(t_Handle h_Scheme); ++t_Error FmPcdKgBuildBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_BindPortToSchemes, uint32_t *p_SpReg, bool add); ++bool FmPcdKgHwSchemeIsValid(uint32_t schemeModeReg); ++uint32_t FmPcdKgBuildWriteSchemeActionReg(uint8_t schemeId, bool updateCounter); ++uint32_t FmPcdKgBuildReadSchemeActionReg(uint8_t schemeId); ++uint32_t FmPcdKgBuildWriteClsPlanBlockActionReg(uint8_t grpId); ++uint32_t FmPcdKgBuildWritePortSchemeBindActionReg(uint8_t hardwarePortId); ++uint32_t FmPcdKgBuildReadPortSchemeBindActionReg(uint8_t hardwarePortId); ++uint32_t FmPcdKgBuildWritePortClsPlanBindActionReg(uint8_t hardwarePortId); ++bool FmPcdKgIsSchemeValidSw(t_Handle h_Scheme); ++ ++t_Error FmPcdKgBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind); ++t_Error FmPcdKgUnbindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind); ++uint32_t FmPcdKgGetRequiredAction(t_Handle h_FmPcd, uint8_t schemeId); ++uint32_t FmPcdKgGetRequiredActionFlag(t_Handle h_FmPcd, uint8_t schemeId); ++e_FmPcdDoneAction FmPcdKgGetDoneAction(t_Handle h_FmPcd, uint8_t schemeId); ++e_FmPcdEngine FmPcdKgGetNextEngine(t_Handle h_FmPcd, uint8_t schemeId); ++void FmPcdKgUpdateRequiredAction(t_Handle h_Scheme, uint32_t requiredAction); ++bool FmPcdKgIsDirectPlcr(t_Handle h_FmPcd, uint8_t schemeId); ++bool FmPcdKgIsDistrOnPlcrProfile(t_Handle h_FmPcd, uint8_t schemeId); ++uint16_t FmPcdKgGetRelativeProfileId(t_Handle h_FmPcd, uint8_t schemeId); ++t_Handle FmPcdKgGetSchemeHandle(t_Handle h_FmPcd, uint8_t relativeSchemeId); ++bool FmPcdKgIsSchemeHasOwners(t_Handle h_Scheme); ++t_Error FmPcdKgCcGetSetParams(t_Handle h_FmPcd, t_Handle h_Scheme, uint32_t requiredAction, uint32_t value); ++t_Error FmPcdKgSetOrBindToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t netEnvId, protocolOpt_t *p_OptArray, uint8_t *p_ClsPlanGrpId, bool *p_IsEmptyClsPlanGrp); ++t_Error FmPcdKgDeleteOrUnbindPortToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId); ++ ++/***********************************************************************/ ++/* Common API for FM-PCD parser module */ ++/***********************************************************************/ ++t_Error FmPcdPrsIncludePortInStatistics(t_Handle p_FmPcd, uint8_t hardwarePortId, bool include); ++ ++/***********************************************************************/ ++/* Common API for FM-PCD policer module */ ++/***********************************************************************/ ++t_Error FmPcdPlcrAllocProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId, uint16_t numOfProfiles); ++t_Error FmPcdPlcrFreeProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId); ++bool FmPcdPlcrIsProfileValid(t_Handle h_FmPcd, uint16_t absoluteProfileId); ++uint16_t FmPcdPlcrGetPortProfilesBase(t_Handle h_FmPcd, uint8_t hardwarePortId); ++uint16_t FmPcdPlcrGetPortNumOfProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId); ++uint32_t FmPcdPlcrBuildWritePlcrActionRegs(uint16_t absoluteProfileId); ++uint32_t FmPcdPlcrBuildCounterProfileReg(e_FmPcdPlcrProfileCounters counter); ++uint32_t FmPcdPlcrBuildWritePlcrActionReg(uint16_t absoluteProfileId); ++uint32_t FmPcdPlcrBuildReadPlcrActionReg(uint16_t absoluteProfileId); ++uint16_t FmPcdPlcrProfileGetAbsoluteId(t_Handle h_Profile); ++t_Error FmPcdPlcrGetAbsoluteIdByProfileParams(t_Handle h_FmPcd, ++ e_FmPcdProfileTypeSelection profileType, ++ t_Handle h_FmPort, ++ uint16_t relativeProfile, ++ uint16_t *p_AbsoluteId); ++void FmPcdPlcrInvalidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId); ++void FmPcdPlcrValidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId); ++bool FmPcdPlcrHwProfileIsValid(uint32_t profileModeReg); ++uint32_t FmPcdPlcrGetRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId); ++uint32_t FmPcdPlcrGetRequiredActionFlag(t_Handle h_FmPcd, uint16_t absoluteProfileId); ++uint32_t FmPcdPlcrBuildNiaProfileReg(bool green, bool yellow, bool red); ++void FmPcdPlcrUpdateRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId, uint32_t requiredAction); ++t_Error FmPcdPlcrCcGetSetParams(t_Handle h_FmPcd, uint16_t profileIndx,uint32_t requiredAction); ++ ++/***********************************************************************/ ++/* Common API for FM-PCD CC module */ ++/***********************************************************************/ ++uint8_t FmPcdCcGetParseCode(t_Handle h_CcNode); ++uint8_t FmPcdCcGetOffset(t_Handle h_CcNode); ++t_Error FmPcdCcRemoveKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint16_t keyIndex); ++t_Error FmPcdCcAddKey(t_Handle h_FmPcd, t_Handle h_CcNode, uint16_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_FmPCdCcKeyParams); ++t_Error FmPcdCcModifyKey(t_Handle h_FmPcd, t_Handle h_CcNode, uint16_t keyIndex, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask); ++t_Error FmPcdCcModifyKeyAndNextEngine(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint16_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_FmPcdCcKeyParams); ++t_Error FmPcdCcModifyMissNextEngineParamNode(t_Handle h_FmPcd,t_Handle h_FmPcdCcNode, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); ++t_Error FmPcdCcModifyNextEngineParamTree(t_Handle h_FmPcd, t_Handle h_FmPcdCcTree, uint8_t grpId, uint8_t index, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); ++uint32_t FmPcdCcGetNodeAddrOffsetFromNodeInfo(t_Handle h_FmPcd, t_Handle h_Pointer); ++t_Handle FmPcdCcTreeGetSavedManipParams(t_Handle h_FmTree); ++void FmPcdCcTreeSetSavedManipParams(t_Handle h_FmTree, t_Handle h_SavedManipParams); ++t_Error FmPcdCcTreeAddIPR(t_Handle h_FmPcd, t_Handle h_FmTree, t_Handle h_NetEnv, t_Handle h_ReassemblyManip, bool schemes); ++t_Error FmPcdCcTreeAddCPR(t_Handle h_FmPcd, t_Handle h_FmTree, t_Handle h_NetEnv, t_Handle h_ReassemblyManip, bool schemes); ++t_Error FmPcdCcBindTree(t_Handle h_FmPcd, t_Handle h_PcdParams, t_Handle h_CcTree, uint32_t *p_Offset,t_Handle h_FmPort); ++t_Error FmPcdCcUnbindTree(t_Handle h_FmPcd, t_Handle h_CcTree); ++ ++/***********************************************************************/ ++/* Common API for FM-PCD Manip module */ ++/***********************************************************************/ ++t_Error FmPcdManipUpdate(t_Handle h_FmPcd, t_Handle h_PcdParams, t_Handle h_FmPort, t_Handle h_Manip, t_Handle h_Ad, bool validate, int level, t_Handle h_FmTree, bool modify); ++ ++/***********************************************************************/ ++/* Common API for FM-Port module */ ++/***********************************************************************/ ++#if (DPAA_VERSION >= 11) ++typedef enum e_FmPortGprFuncType ++{ ++ e_FM_PORT_GPR_EMPTY = 0, ++ e_FM_PORT_GPR_MURAM_PAGE ++} e_FmPortGprFuncType; ++ ++t_Error FmPortSetGprFunc(t_Handle h_FmPort, e_FmPortGprFuncType gprFunc, void **p_Value); ++#endif /* DPAA_VERSION >= 11) */ ++t_Error FmGetSetParams(t_Handle h_Fm, t_FmGetSetParams *p_FmGetSetParams); ++t_Error FmPortGetSetCcParams(t_Handle h_FmPort, t_FmPortGetSetCcParams *p_FmPortGetSetCcParams); ++uint8_t FmPortGetNetEnvId(t_Handle h_FmPort); ++uint8_t FmPortGetHardwarePortId(t_Handle h_FmPort); ++uint32_t FmPortGetPcdEngines(t_Handle h_FmPort); ++void FmPortPcdKgSwUnbindClsPlanGrp (t_Handle h_FmPort); ++ ++ ++#if (DPAA_VERSION >= 11) ++t_Error FmPcdFrmReplicUpdate(t_Handle h_FmPcd, t_Handle h_FmPort, t_Handle h_FrmReplic); ++#endif /* (DPAA_VERSION >= 11) */ ++ ++/**************************************************************************//** ++ @Function FmRegisterIntr ++ ++ @Description Used to register an inter-module event handler to be processed by FM ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] mod The module that causes the event ++ @Param[in] modId Module id - if more than 1 instansiation of this ++ mode exists,0 otherwise. ++ @Param[in] intrType Interrupt type (error/normal) selection. ++ @Param[in] f_Isr The interrupt service routine. ++ @Param[in] h_Arg Argument to be passed to f_Isr. ++ ++ @Return None. ++*//***************************************************************************/ ++void FmRegisterIntr(t_Handle h_Fm, ++ e_FmEventModules mod, ++ uint8_t modId, ++ e_FmIntrType intrType, ++ void (*f_Isr) (t_Handle h_Arg), ++ t_Handle h_Arg); ++ ++/**************************************************************************//** ++ @Function FmUnregisterIntr ++ ++ @Description Used to un-register an inter-module event handler that was processed by FM ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] mod The module that causes the event ++ @Param[in] modId Module id - if more than 1 instansiation of this ++ mode exists,0 otherwise. ++ @Param[in] intrType Interrupt type (error/normal) selection. ++ ++ @Return None. ++*//***************************************************************************/ ++void FmUnregisterIntr(t_Handle h_Fm, ++ e_FmEventModules mod, ++ uint8_t modId, ++ e_FmIntrType intrType); ++ ++/**************************************************************************//** ++ @Function FmRegisterFmCtlIntr ++ ++ @Description Used to register to one of the fmCtl events in the FM module ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] eventRegId FmCtl event id (0-7). ++ @Param[in] f_Isr The interrupt service routine. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++void FmRegisterFmCtlIntr(t_Handle h_Fm, uint8_t eventRegId, void (*f_Isr) (t_Handle h_Fm, uint32_t event)); ++ ++ ++/**************************************************************************//** ++ @Description enum for defining MAC types ++*//***************************************************************************/ ++typedef enum e_FmMacType { ++ e_FM_MAC_10G = 0, /**< 10G MAC */ ++ e_FM_MAC_1G /**< 1G MAC */ ++} e_FmMacType; ++ ++/**************************************************************************//** ++ @Description Structure for port-FM communication during FM_PORT_Init. ++ Fields commented 'IN' are passed by the port module to be used ++ by the FM module. ++ Fields commented 'OUT' will be filled by FM before returning to port. ++ Some fields are optional (depending on configuration) and ++ will be analized by the port and FM modules accordingly. ++*//***************************************************************************/ ++typedef struct t_FmInterModulePortInitParams { ++ uint8_t hardwarePortId; /**< IN. port Id */ ++ e_FmPortType portType; /**< IN. Port type */ ++ bool independentMode; /**< IN. TRUE if FM Port operates in independent mode */ ++ uint16_t liodnOffset; /**< IN. Port's requested resource */ ++ uint8_t numOfTasks; /**< IN. Port's requested resource */ ++ uint8_t numOfExtraTasks; /**< IN. Port's requested resource */ ++ uint8_t numOfOpenDmas; /**< IN. Port's requested resource */ ++ uint8_t numOfExtraOpenDmas; /**< IN. Port's requested resource */ ++ uint32_t sizeOfFifo; /**< IN. Port's requested resource */ ++ uint32_t extraSizeOfFifo; /**< IN. Port's requested resource */ ++ uint8_t deqPipelineDepth; /**< IN. Port's requested resource */ ++ uint16_t maxFrameLength; /**< IN. Port's max frame length. */ ++ uint16_t liodnBase; /**< IN. Irrelevant for P4080 rev 1. ++ LIODN base for this port, to be ++ used together with LIODN offset. */ ++ t_FmPhysAddr fmMuramPhysBaseAddr;/**< OUT. FM-MURAM physical address*/ ++} t_FmInterModulePortInitParams; ++ ++/**************************************************************************//** ++ @Description Structure for port-FM communication during FM_PORT_Free. ++*//***************************************************************************/ ++typedef struct t_FmInterModulePortFreeParams { ++ uint8_t hardwarePortId; /**< IN. port Id */ ++ e_FmPortType portType; /**< IN. Port type */ ++ uint8_t deqPipelineDepth; /**< IN. Port's requested resource */ ++} t_FmInterModulePortFreeParams; ++ ++/**************************************************************************//** ++ @Function FmGetPcdPrsBaseAddr ++ ++ @Description Get the base address of the Parser from the FM module ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return Base address. ++*//***************************************************************************/ ++uintptr_t FmGetPcdPrsBaseAddr(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FmGetPcdKgBaseAddr ++ ++ @Description Get the base address of the Keygen from the FM module ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return Base address. ++*//***************************************************************************/ ++uintptr_t FmGetPcdKgBaseAddr(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FmGetPcdPlcrBaseAddr ++ ++ @Description Get the base address of the Policer from the FM module ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return Base address. ++*//***************************************************************************/ ++uintptr_t FmGetPcdPlcrBaseAddr(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FmGetMuramHandle ++ ++ @Description Get the handle of the MURAM from the FM module ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return MURAM module handle. ++*//***************************************************************************/ ++t_Handle FmGetMuramHandle(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FmGetPhysicalMuramBase ++ ++ @Description Get the physical base address of the MURAM from the FM module ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] fmPhysAddr Physical MURAM base ++ ++ @Return Physical base address. ++*//***************************************************************************/ ++void FmGetPhysicalMuramBase(t_Handle h_Fm, t_FmPhysAddr *fmPhysAddr); ++ ++/**************************************************************************//** ++ @Function FmGetTimeStampScale ++ ++ @Description Used internally by other modules in order to get the timeStamp ++ period as requested by the application. ++ ++ This function returns bit number that is incremented every 1 usec. ++ To calculate timestamp period in nsec, use ++ 1000 / (1 << FmGetTimeStampScale()). ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return Bit that counts 1 usec. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++uint32_t FmGetTimeStampScale(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FmResumeStalledPort ++ ++ @Description Used internally by FM port to release a stalled port. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] hardwarePortId HW port id. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++t_Error FmResumeStalledPort(t_Handle h_Fm, uint8_t hardwarePortId); ++ ++/**************************************************************************//** ++ @Function FmIsPortStalled ++ ++ @Description Used internally by FM port to read the port's status. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] hardwarePortId HW port id. ++ @Param[in] p_IsStalled A pointer to the boolean port stalled state ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++t_Error FmIsPortStalled(t_Handle h_Fm, uint8_t hardwarePortId, bool *p_IsStalled); ++ ++/**************************************************************************//** ++ @Function FmResetMac ++ ++ @Description Used by MAC driver to reset the MAC registers ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] type MAC type. ++ @Param[in] macId MAC id - according to type. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++t_Error FmResetMac(t_Handle h_Fm, e_FmMacType type, uint8_t macId); ++ ++/**************************************************************************//** ++ @Function FmGetClockFreq ++ ++ @Description Used by MAC driver to get the FM clock frequency ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return clock-freq on success; 0 otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++uint16_t FmGetClockFreq(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FmGetMacClockFreq ++ ++ @Description Used by MAC driver to get the MAC clock frequency ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return clock-freq on success; 0 otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++uint16_t FmGetMacClockFreq(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FmGetId ++ ++ @Description Used by PCD driver to read rhe FM id ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++uint8_t FmGetId(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FmReset ++ ++ @Description Used to reset the FM ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FmReset(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FmGetSetPortParams ++ ++ @Description Used by FM-PORT driver to pass and receive parameters between ++ PORT and FM modules. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in,out] p_PortParams A structure of FM Port parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++t_Error FmGetSetPortParams(t_Handle h_Fm,t_FmInterModulePortInitParams *p_PortParams); ++ ++/**************************************************************************//** ++ @Function FmFreePortParams ++ ++ @Description Used by FM-PORT driver to free port's resources within the FM. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in,out] p_PortParams A structure of FM Port parameters. ++ ++ @Return None. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++void FmFreePortParams(t_Handle h_Fm,t_FmInterModulePortFreeParams *p_PortParams); ++ ++/**************************************************************************//** ++ @Function FmSetNumOfRiscsPerPort ++ ++ @Description Used by FM-PORT driver to pass parameter between ++ PORT and FM modules for working with number of RISC.. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] hardwarePortId hardware port Id. ++ @Param[in] numOfFmanCtrls number of Fman Controllers. ++ @Param[in] orFmanCtrl Fman Controller for order restoration. ++ ++ @Return None. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++t_Error FmSetNumOfRiscsPerPort(t_Handle h_Fm, uint8_t hardwarePortId, uint8_t numOfFmanCtrls, t_FmFmanCtrl orFmanCtrl); ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++/**************************************************************************//* ++ @Function FmDumpPortRegs ++ ++ @Description Dumps FM port registers which are part of FM common registers ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] hardwarePortId HW port id. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only FM_Init(). ++*//***************************************************************************/ ++t_Error FmDumpPortRegs(t_Handle h_Fm,uint8_t hardwarePortId); ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++void FmRegisterPcd(t_Handle h_Fm, t_Handle h_FmPcd); ++void FmUnregisterPcd(t_Handle h_Fm); ++t_Handle FmGetPcdHandle(t_Handle h_Fm); ++t_Error FmEnableRamsEcc(t_Handle h_Fm); ++t_Error FmDisableRamsEcc(t_Handle h_Fm); ++void FmGetRevision(t_Handle h_Fm, t_FmRevisionInfo *p_FmRevisionInfo); ++t_Error FmAllocFmanCtrlEventReg(t_Handle h_Fm, uint8_t *p_EventId); ++void FmFreeFmanCtrlEventReg(t_Handle h_Fm, uint8_t eventId); ++void FmSetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, uint32_t enableEvents); ++uint32_t FmGetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId); ++void FmRegisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, void (*f_Isr) (t_Handle h_Fm, uint32_t event), t_Handle h_Arg); ++void FmUnregisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId); ++t_Error FmSetMacMaxFrame(t_Handle h_Fm, e_FmMacType type, uint8_t macId, uint16_t mtu); ++bool FmIsMaster(t_Handle h_Fm); ++uint8_t FmGetGuestId(t_Handle h_Fm); ++uint16_t FmGetTnumAgingPeriod(t_Handle h_Fm); ++t_Error FmSetPortPreFetchConfiguration(t_Handle h_Fm, uint8_t portNum, bool preFetchConfigured); ++t_Error FmGetPortPreFetchConfiguration(t_Handle h_Fm, uint8_t portNum, bool *p_PortConfigured, bool *p_PreFetchConfigured); ++ ++ ++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 ++t_Error Fm10GTxEccWorkaround(t_Handle h_Fm, uint8_t macId); ++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ ++ ++void FmMuramClear(t_Handle h_FmMuram); ++t_Error FmSetNumOfOpenDmas(t_Handle h_Fm, ++ uint8_t hardwarePortId, ++ uint8_t *p_NumOfOpenDmas, ++ uint8_t *p_NumOfExtraOpenDmas, ++ bool initialConfig); ++t_Error FmSetNumOfTasks(t_Handle h_Fm, ++ uint8_t hardwarePortId, ++ uint8_t *p_NumOfTasks, ++ uint8_t *p_NumOfExtraTasks, ++ bool initialConfig); ++t_Error FmSetSizeOfFifo(t_Handle h_Fm, ++ uint8_t hardwarePortId, ++ uint32_t *p_SizeOfFifo, ++ uint32_t *p_ExtraSizeOfFifo, ++ bool initialConfig); ++ ++t_Error FmSetCongestionGroupPFCpriority(t_Handle h_Fm, ++ uint32_t congestionGroupId, ++ uint8_t priorityBitMap); ++ ++#if (DPAA_VERSION >= 11) ++t_Error FmVSPAllocForPort(t_Handle h_Fm, ++ e_FmPortType portType, ++ uint8_t portId, ++ uint8_t numOfStorageProfiles); ++ ++t_Error FmVSPFreeForPort(t_Handle h_Fm, ++ e_FmPortType portType, ++ uint8_t portId); ++ ++t_Error FmVSPGetAbsoluteProfileId(t_Handle h_Fm, ++ e_FmPortType portType, ++ uint8_t portId, ++ uint16_t relativeProfile, ++ uint16_t *p_AbsoluteId); ++t_Error FmVSPCheckRelativeProfile(t_Handle h_Fm, ++ e_FmPortType portType, ++ uint8_t portId, ++ uint16_t relativeProfile); ++ ++uintptr_t FmGetVSPBaseAddr(t_Handle h_Fm); ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ ++#endif /* __FM_COMMON_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_hc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_hc.h +new file mode 100644 +index 00000000..492aa8a3 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_hc.h +@@ -0,0 +1,93 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#ifndef __FM_HC_H ++#define __FM_HC_H ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "fsl_fman_kg.h" ++ ++#define __ERR_MODULE__ MODULE_FM_PCD ++ ++ ++typedef struct t_FmHcParams { ++ t_Handle h_Fm; ++ t_Handle h_FmPcd; ++ t_FmPcdHcParams params; ++} t_FmHcParams; ++ ++ ++t_Handle FmHcConfigAndInit(t_FmHcParams *p_FmHcParams); ++void FmHcFree(t_Handle h_FmHc); ++t_Error FmHcSetFramesDataMemory(t_Handle h_FmHc, ++ uint8_t memId); ++t_Error FmHcDumpRegs(t_Handle h_FmHc); ++ ++void FmHcTxConf(t_Handle h_FmHc, t_DpaaFD *p_Fd); ++ ++t_Error FmHcPcdKgSetScheme(t_Handle h_FmHc, ++ t_Handle h_Scheme, ++ struct fman_kg_scheme_regs *p_SchemeRegs, ++ bool updateCounter); ++t_Error FmHcPcdKgDeleteScheme(t_Handle h_FmHc, t_Handle h_Scheme); ++t_Error FmHcPcdCcCapwapTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcCapwapReassmTimeoutParams *p_CcCapwapReassmTimeoutParams ); ++t_Error FmHcPcdCcIpFragScratchPollCmd(t_Handle h_FmHc, bool fill, t_FmPcdCcFragScratchPoolCmdParams *p_FmPcdCcFragScratchPoolCmdParams); ++t_Error FmHcPcdCcTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcReassmTimeoutParams *p_CcReassmTimeoutParams, uint8_t *p_Result); ++t_Error FmHcPcdKgSetClsPlan(t_Handle h_FmHc, t_FmPcdKgInterModuleClsPlanSet *p_Set); ++t_Error FmHcPcdKgDeleteClsPlan(t_Handle h_FmHc, uint8_t clsPlanGrpId); ++ ++t_Error FmHcPcdKgSetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t value); ++uint32_t FmHcPcdKgGetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme); ++ ++t_Error FmHcPcdCcDoDynamicChange(t_Handle h_FmHc, uint32_t oldAdAddrOffset, uint32_t newAdAddrOffset); ++ ++t_Error FmHcPcdPlcrSetProfile(t_Handle h_FmHc, t_Handle h_Profile, t_FmPcdPlcrProfileRegs *p_PlcrRegs); ++t_Error FmHcPcdPlcrDeleteProfile(t_Handle h_FmHc, t_Handle h_Profile); ++ ++t_Error FmHcPcdPlcrSetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter, uint32_t value); ++uint32_t FmHcPcdPlcrGetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter); ++ ++t_Error FmHcKgWriteSp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t spReg, bool add); ++t_Error FmHcKgWriteCpp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t cppReg); ++ ++t_Error FmHcPcdKgCcGetSetParams(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t requiredAction, uint32_t value); ++t_Error FmHcPcdPlcrCcGetSetParams(t_Handle h_FmHc,uint16_t absoluteProfileId, uint32_t requiredAction); ++ ++t_Error FmHcPcdSync(t_Handle h_FmHc); ++t_Handle FmHcGetPort(t_Handle h_FmHc); ++ ++ ++ ++ ++#endif /* __FM_HC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_sp_common.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_sp_common.h +new file mode 100644 +index 00000000..f9dd384b +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_sp_common.h +@@ -0,0 +1,117 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_sp_common.h ++ ++ @Description FM SP ... ++*//***************************************************************************/ ++#ifndef __FM_SP_COMMON_H ++#define __FM_SP_COMMON_H ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "list_ext.h" ++ ++#include "fm_ext.h" ++#include "fm_pcd_ext.h" ++#include "fsl_fman.h" ++ ++/**************************************************************************//** ++ @Description defaults ++*//***************************************************************************/ ++#define DEFAULT_FM_SP_bufferPrefixContent_privDataSize 0 ++#define DEFAULT_FM_SP_bufferPrefixContent_passPrsResult FALSE ++#define DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp FALSE ++#define DEFAULT_FM_SP_bufferPrefixContent_allOtherPCDInfo FALSE ++#define DEFAULT_FM_SP_bufferPrefixContent_dataAlign 64 ++ ++/**************************************************************************//** ++ @Description structure for defining internal context copying ++*//***************************************************************************/ ++typedef struct ++{ ++ uint16_t extBufOffset; /**< Offset in External buffer to which internal ++ context is copied to (Rx) or taken from (Tx, Op). */ ++ uint8_t intContextOffset; /**< Offset within internal context to copy from ++ (Rx) or to copy to (Tx, Op). */ ++ uint16_t size; /**< Internal offset size to be copied */ ++} t_FmSpIntContextDataCopy; ++ ++/**************************************************************************//** ++ @Description struct for defining external buffer margins ++*//***************************************************************************/ ++typedef struct { ++ uint16_t startMargins; /**< Number of bytes to be left at the beginning ++ of the external buffer (must be divisible by 16) */ ++ uint16_t endMargins; /**< number of bytes to be left at the end ++ of the external buffer(must be divisible by 16) */ ++} t_FmSpBufMargins; ++ ++typedef struct { ++ uint32_t dataOffset; ++ uint32_t prsResultOffset; ++ uint32_t timeStampOffset; ++ uint32_t hashResultOffset; ++ uint32_t pcdInfoOffset; ++ uint32_t manipOffset; ++} t_FmSpBufferOffsets; ++ ++ ++t_Error FmSpBuildBufferStructure(t_FmSpIntContextDataCopy *p_FmPortIntContextDataCopy, ++ t_FmBufferPrefixContent *p_BufferPrefixContent, ++ t_FmSpBufMargins *p_FmPortBufMargins, ++ t_FmSpBufferOffsets *p_FmPortBufferOffsets, ++ uint8_t *internalBufferOffset); ++ ++t_Error FmSpCheckIntContextParams(t_FmSpIntContextDataCopy *p_FmSpIntContextDataCopy); ++t_Error FmSpCheckBufPoolsParams(t_FmExtPools *p_FmExtPools, ++ t_FmBackupBmPools *p_FmBackupBmPools, ++ t_FmBufPoolDepletion *p_FmBufPoolDepletion); ++t_Error FmSpCheckBufMargins(t_FmSpBufMargins *p_FmSpBufMargins); ++void FmSpSetBufPoolsInAscOrderOfBufSizes(t_FmExtPools *p_FmExtPools, uint8_t *orderedArray, uint16_t *sizesArray); ++ ++t_Error FmPcdSpAllocProfiles(t_Handle h_FmPcd, ++ uint8_t hardwarePortId, ++ uint16_t numOfStorageProfiles, ++ uint16_t *base, ++ uint8_t *log2Num); ++t_Error FmPcdSpGetAbsoluteProfileId(t_Handle h_FmPcd, ++ t_Handle h_FmPort, ++ uint16_t relativeProfile, ++ uint16_t *p_AbsoluteId); ++void SpInvalidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId); ++void SpValidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId); ++ ++ ++#endif /* __FM_SP_COMMON_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/etc/Makefile b/drivers/net/ethernet/freescale/sdk_fman/etc/Makefile +new file mode 100644 +index 00000000..d03a519c +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/etc/Makefile +@@ -0,0 +1,12 @@ ++# ++# Makefile for the Freescale Ethernet controllers ++# ++ccflags-y += -DVERSION=\"\" ++# ++#Include netcomm SW specific definitions ++ ++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk ++ ++obj-y += fsl-ncsw-etc.o ++ ++fsl-ncsw-etc-objs := mm.o memcpy.o sprint.o list.o error.o +diff --git a/drivers/net/ethernet/freescale/sdk_fman/etc/error.c b/drivers/net/ethernet/freescale/sdk_fman/etc/error.c +new file mode 100644 +index 00000000..fead7f50 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/etc/error.c +@@ -0,0 +1,95 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/* ++ ++ @File error.c ++ ++ @Description General errors and events reporting utilities. ++*//***************************************************************************/ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++#include "error_ext.h" ++ ++ ++const char *dbgLevelStrings[] = ++{ ++ "CRITICAL" ++ ,"MAJOR" ++ ,"MINOR" ++ ,"WARNING" ++ ,"INFO" ++ ,"TRACE" ++}; ++ ++ ++char * ErrTypeStrings (e_ErrorType err) ++{ ++ switch (err) ++ { ++ case (E_OK): return "OK"; ++ case (E_WRITE_FAILED): return "Write Access Failed"; ++ case (E_NO_DEVICE): return "No Device"; ++ case (E_NOT_AVAILABLE): return "Resource Is Unavailable"; ++ case (E_NO_MEMORY): return "Memory Allocation Failed"; ++ case (E_INVALID_ADDRESS): return "Invalid Address"; ++ case (E_BUSY): return "Resource Is Busy"; ++ case (E_ALREADY_EXISTS): return "Resource Already Exists"; ++ case (E_INVALID_OPERATION): return "Invalid Operation"; ++ case (E_INVALID_VALUE): return "Invalid Value"; ++ case (E_NOT_IN_RANGE): return "Value Out Of Range"; ++ case (E_NOT_SUPPORTED): return "Unsupported Operation"; ++ case (E_INVALID_STATE): return "Invalid State"; ++ case (E_INVALID_HANDLE): return "Invalid Handle"; ++ case (E_INVALID_ID): return "Invalid ID"; ++ case (E_NULL_POINTER): return "Unexpected NULL Pointer"; ++ case (E_INVALID_SELECTION): return "Invalid Selection"; ++ case (E_INVALID_COMM_MODE): return "Invalid Communication Mode"; ++ case (E_INVALID_MEMORY_TYPE): return "Invalid Memory Type"; ++ case (E_INVALID_CLOCK): return "Invalid Clock"; ++ case (E_CONFLICT): return "Conflict In Settings"; ++ case (E_NOT_ALIGNED): return "Incorrect Alignment"; ++ case (E_NOT_FOUND): return "Resource Not Found"; ++ case (E_FULL): return "Resource Is Full"; ++ case (E_EMPTY): return "Resource Is Empty"; ++ case (E_ALREADY_FREE): return "Resource Already Free"; ++ case (E_READ_FAILED): return "Read Access Failed"; ++ case (E_INVALID_FRAME): return "Invalid Frame"; ++ case (E_SEND_FAILED): return "Send Operation Failed"; ++ case (E_RECEIVE_FAILED): return "Receive Operation Failed"; ++ case (E_TIMEOUT): return "Operation Timed Out"; ++ default: ++ break; ++ } ++ return NULL; ++} ++#endif /* (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/etc/list.c b/drivers/net/ethernet/freescale/sdk_fman/etc/list.c +new file mode 100644 +index 00000000..2d044be2 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/etc/list.c +@@ -0,0 +1,71 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ ++ @File list.c ++ ++ @Description Implementation of list. ++*//***************************************************************************/ ++#include "std_ext.h" ++#include "list_ext.h" ++ ++ ++void LIST_Append(t_List *p_NewList, t_List *p_Head) ++{ ++ t_List *p_First = LIST_FIRST(p_NewList); ++ ++ if (p_First != p_NewList) ++ { ++ t_List *p_Last = LIST_LAST(p_NewList); ++ t_List *p_Cur = LIST_NEXT(p_Head); ++ ++ LIST_PREV(p_First) = p_Head; ++ LIST_FIRST(p_Head) = p_First; ++ LIST_NEXT(p_Last) = p_Cur; ++ LIST_LAST(p_Cur) = p_Last; ++ } ++} ++ ++ ++int LIST_NumOfObjs(t_List *p_List) ++{ ++ t_List *p_Tmp; ++ int numOfObjs = 0; ++ ++ if (!LIST_IsEmpty(p_List)) ++ LIST_FOR_EACH(p_Tmp, p_List) ++ numOfObjs++; ++ ++ return numOfObjs; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/etc/memcpy.c b/drivers/net/ethernet/freescale/sdk_fman/etc/memcpy.c +new file mode 100644 +index 00000000..fa203ec7 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/etc/memcpy.c +@@ -0,0 +1,620 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++ ++#include "std_ext.h" ++#include "xx_ext.h" ++#include "memcpy_ext.h" ++ ++void * MemCpy8(void* pDst, void* pSrc, uint32_t size) ++{ ++ int i; ++ ++ for(i = 0; i < size; ++i) ++ *(((uint8_t*)(pDst)) + i) = *(((uint8_t*)(pSrc)) + i); ++ ++ return pDst; ++} ++ ++void * MemSet8(void* pDst, int c, uint32_t size) ++{ ++ int i; ++ ++ for(i = 0; i < size; ++i) ++ *(((uint8_t*)(pDst)) + i) = (uint8_t)(c); ++ ++ return pDst; ++} ++ ++void * MemCpy32(void* pDst,void* pSrc, uint32_t size) ++{ ++ uint32_t leftAlign; ++ uint32_t rightAlign; ++ uint32_t lastWord; ++ uint32_t currWord; ++ uint32_t *p_Src32; ++ uint32_t *p_Dst32; ++ uint8_t *p_Src8; ++ uint8_t *p_Dst8; ++ ++ p_Src8 = (uint8_t*)(pSrc); ++ p_Dst8 = (uint8_t*)(pDst); ++ /* first copy byte by byte till the source first alignment ++ * this step is necessary to ensure we do not even try to access ++ * data which is before the source buffer, hence it is not ours. ++ */ ++ while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */ ++ { ++ *p_Dst8++ = *p_Src8++; ++ size--; ++ } ++ ++ /* align destination (possibly disaligning source)*/ ++ while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ ++ { ++ *p_Dst8++ = *p_Src8++; ++ size--; ++ } ++ ++ /* dest is aligned and source is not necessarily aligned */ ++ leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */ ++ rightAlign = 32 - leftAlign; ++ ++ ++ if (leftAlign == 0) ++ { ++ /* source is also aligned */ ++ p_Src32 = (uint32_t*)(p_Src8); ++ p_Dst32 = (uint32_t*)(p_Dst8); ++ while (size >> 2) /* size >= 4 */ ++ { ++ *p_Dst32++ = *p_Src32++; ++ size -= 4; ++ } ++ p_Src8 = (uint8_t*)(p_Src32); ++ p_Dst8 = (uint8_t*)(p_Dst32); ++ } ++ else ++ { ++ /* source is not aligned (destination is aligned)*/ ++ p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3)); ++ p_Dst32 = (uint32_t*)(p_Dst8); ++ lastWord = *p_Src32++; ++ while(size >> 3) /* size >= 8 */ ++ { ++ currWord = *p_Src32; ++ *p_Dst32 = (lastWord << leftAlign) | (currWord >> rightAlign); ++ lastWord = currWord; ++ p_Src32++; ++ p_Dst32++; ++ size -= 4; ++ } ++ p_Dst8 = (uint8_t*)(p_Dst32); ++ p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3); ++ } ++ ++ /* complete the left overs */ ++ while (size--) ++ *p_Dst8++ = *p_Src8++; ++ ++ return pDst; ++} ++ ++void * IO2IOCpy32(void* pDst,void* pSrc, uint32_t size) ++{ ++ uint32_t leftAlign; ++ uint32_t rightAlign; ++ uint32_t lastWord; ++ uint32_t currWord; ++ uint32_t *p_Src32; ++ uint32_t *p_Dst32; ++ uint8_t *p_Src8; ++ uint8_t *p_Dst8; ++ ++ p_Src8 = (uint8_t*)(pSrc); ++ p_Dst8 = (uint8_t*)(pDst); ++ /* first copy byte by byte till the source first alignment ++ * this step is necessary to ensure we do not even try to access ++ * data which is before the source buffer, hence it is not ours. ++ */ ++ while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */ ++ { ++ WRITE_UINT8(*p_Dst8, GET_UINT8(*p_Src8)); ++ p_Dst8++;p_Src8++; ++ size--; ++ } ++ ++ /* align destination (possibly disaligning source)*/ ++ while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ ++ { ++ WRITE_UINT8(*p_Dst8, GET_UINT8(*p_Src8)); ++ p_Dst8++;p_Src8++; ++ size--; ++ } ++ ++ /* dest is aligned and source is not necessarily aligned */ ++ leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */ ++ rightAlign = 32 - leftAlign; ++ ++ if (leftAlign == 0) ++ { ++ /* source is also aligned */ ++ p_Src32 = (uint32_t*)(p_Src8); ++ p_Dst32 = (uint32_t*)(p_Dst8); ++ while (size >> 2) /* size >= 4 */ ++ { ++ WRITE_UINT32(*p_Dst32, GET_UINT32(*p_Src32)); ++ p_Dst32++;p_Src32++; ++ size -= 4; ++ } ++ p_Src8 = (uint8_t*)(p_Src32); ++ p_Dst8 = (uint8_t*)(p_Dst32); ++ } ++ else ++ { ++ /* source is not aligned (destination is aligned)*/ ++ p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3)); ++ p_Dst32 = (uint32_t*)(p_Dst8); ++ lastWord = GET_UINT32(*p_Src32); ++ p_Src32++; ++ while(size >> 3) /* size >= 8 */ ++ { ++ currWord = GET_UINT32(*p_Src32); ++ WRITE_UINT32(*p_Dst32, (lastWord << leftAlign) | (currWord >> rightAlign)); ++ lastWord = currWord; ++ p_Src32++;p_Dst32++; ++ size -= 4; ++ } ++ p_Dst8 = (uint8_t*)(p_Dst32); ++ p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3); ++ } ++ ++ /* complete the left overs */ ++ while (size--) ++ { ++ WRITE_UINT8(*p_Dst8, GET_UINT8(*p_Src8)); ++ p_Dst8++;p_Src8++; ++ } ++ ++ return pDst; ++} ++ ++void * Mem2IOCpy32(void* pDst,void* pSrc, uint32_t size) ++{ ++ uint32_t leftAlign; ++ uint32_t rightAlign; ++ uint32_t lastWord; ++ uint32_t currWord; ++ uint32_t *p_Src32; ++ uint32_t *p_Dst32; ++ uint8_t *p_Src8; ++ uint8_t *p_Dst8; ++ ++ p_Src8 = (uint8_t*)(pSrc); ++ p_Dst8 = (uint8_t*)(pDst); ++ /* first copy byte by byte till the source first alignment ++ * this step is necessary to ensure we do not even try to access ++ * data which is before the source buffer, hence it is not ours. ++ */ ++ while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */ ++ { ++ WRITE_UINT8(*p_Dst8, *p_Src8); ++ p_Dst8++;p_Src8++; ++ size--; ++ } ++ ++ /* align destination (possibly disaligning source)*/ ++ while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ ++ { ++ WRITE_UINT8(*p_Dst8, *p_Src8); ++ p_Dst8++;p_Src8++; ++ size--; ++ } ++ ++ /* dest is aligned and source is not necessarily aligned */ ++ leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */ ++ rightAlign = 32 - leftAlign; ++ ++ if (leftAlign == 0) ++ { ++ /* source is also aligned */ ++ p_Src32 = (uint32_t*)(p_Src8); ++ p_Dst32 = (uint32_t*)(p_Dst8); ++ while (size >> 2) /* size >= 4 */ ++ { ++ WRITE_UINT32(*p_Dst32, *p_Src32); ++ p_Dst32++;p_Src32++; ++ size -= 4; ++ } ++ p_Src8 = (uint8_t*)(p_Src32); ++ p_Dst8 = (uint8_t*)(p_Dst32); ++ } ++ else ++ { ++ /* source is not aligned (destination is aligned)*/ ++ p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3)); ++ p_Dst32 = (uint32_t*)(p_Dst8); ++ lastWord = *p_Src32++; ++ while(size >> 3) /* size >= 8 */ ++ { ++ currWord = *p_Src32; ++ WRITE_UINT32(*p_Dst32, (lastWord << leftAlign) | (currWord >> rightAlign)); ++ lastWord = currWord; ++ p_Src32++;p_Dst32++; ++ size -= 4; ++ } ++ p_Dst8 = (uint8_t*)(p_Dst32); ++ p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3); ++ } ++ ++ /* complete the left overs */ ++ while (size--) ++ { ++ WRITE_UINT8(*p_Dst8, *p_Src8); ++ p_Dst8++;p_Src8++; ++ } ++ ++ return pDst; ++} ++ ++void * IO2MemCpy32(void* pDst,void* pSrc, uint32_t size) ++{ ++ uint32_t leftAlign; ++ uint32_t rightAlign; ++ uint32_t lastWord; ++ uint32_t currWord; ++ uint32_t *p_Src32; ++ uint32_t *p_Dst32; ++ uint8_t *p_Src8; ++ uint8_t *p_Dst8; ++ ++ p_Src8 = (uint8_t*)(pSrc); ++ p_Dst8 = (uint8_t*)(pDst); ++ /* first copy byte by byte till the source first alignment ++ * this step is necessary to ensure we do not even try to access ++ * data which is before the source buffer, hence it is not ours. ++ */ ++ while((PTR_TO_UINT(p_Src8) & 3) && size) /* (pSrc mod 4) > 0 and size > 0 */ ++ { ++ *p_Dst8 = GET_UINT8(*p_Src8); ++ p_Dst8++;p_Src8++; ++ size--; ++ } ++ ++ /* align destination (possibly disaligning source)*/ ++ while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ ++ { ++ *p_Dst8 = GET_UINT8(*p_Src8); ++ p_Dst8++;p_Src8++; ++ size--; ++ } ++ ++ /* dest is aligned and source is not necessarily aligned */ ++ leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 3) << 3); /* leftAlign = (pSrc mod 4)*8 */ ++ rightAlign = 32 - leftAlign; ++ ++ if (leftAlign == 0) ++ { ++ /* source is also aligned */ ++ p_Src32 = (uint32_t*)(p_Src8); ++ p_Dst32 = (uint32_t*)(p_Dst8); ++ while (size >> 2) /* size >= 4 */ ++ { ++ *p_Dst32 = GET_UINT32(*p_Src32); ++ p_Dst32++;p_Src32++; ++ size -= 4; ++ } ++ p_Src8 = (uint8_t*)(p_Src32); ++ p_Dst8 = (uint8_t*)(p_Dst32); ++ } ++ else ++ { ++ /* source is not aligned (destination is aligned)*/ ++ p_Src32 = (uint32_t*)(p_Src8 - (leftAlign >> 3)); ++ p_Dst32 = (uint32_t*)(p_Dst8); ++ lastWord = GET_UINT32(*p_Src32); ++ p_Src32++; ++ while(size >> 3) /* size >= 8 */ ++ { ++ currWord = GET_UINT32(*p_Src32); ++ *p_Dst32 = (lastWord << leftAlign) | (currWord >> rightAlign); ++ lastWord = currWord; ++ p_Src32++;p_Dst32++; ++ size -= 4; ++ } ++ p_Dst8 = (uint8_t*)(p_Dst32); ++ p_Src8 = (uint8_t*)(p_Src32) - 4 + (leftAlign >> 3); ++ } ++ ++ /* complete the left overs */ ++ while (size--) ++ { ++ *p_Dst8 = GET_UINT8(*p_Src8); ++ p_Dst8++;p_Src8++; ++ } ++ ++ return pDst; ++} ++ ++void * MemCpy64(void* pDst,void* pSrc, uint32_t size) ++{ ++ uint32_t leftAlign; ++ uint32_t rightAlign; ++ uint64_t lastWord; ++ uint64_t currWord; ++ uint64_t *pSrc64; ++ uint64_t *pDst64; ++ uint8_t *p_Src8; ++ uint8_t *p_Dst8; ++ ++ p_Src8 = (uint8_t*)(pSrc); ++ p_Dst8 = (uint8_t*)(pDst); ++ /* first copy byte by byte till the source first alignment ++ * this step is necessarily to ensure we do not even try to access ++ * data which is before the source buffer, hence it is not ours. ++ */ ++ while((PTR_TO_UINT(p_Src8) & 7) && size) /* (pSrc mod 8) > 0 and size > 0 */ ++ { ++ *p_Dst8++ = *p_Src8++; ++ size--; ++ } ++ ++ /* align destination (possibly disaligning source)*/ ++ while((PTR_TO_UINT(p_Dst8) & 7) && size) /* (pDst mod 8) > 0 and size > 0 */ ++ { ++ *p_Dst8++ = *p_Src8++; ++ size--; ++ } ++ ++ /* dest is aligned and source is not necessarily aligned */ ++ leftAlign = (uint32_t)((PTR_TO_UINT(p_Src8) & 7) << 3); /* leftAlign = (pSrc mod 8)*8 */ ++ rightAlign = 64 - leftAlign; ++ ++ ++ if (leftAlign == 0) ++ { ++ /* source is also aligned */ ++ pSrc64 = (uint64_t*)(p_Src8); ++ pDst64 = (uint64_t*)(p_Dst8); ++ while (size >> 3) /* size >= 8 */ ++ { ++ *pDst64++ = *pSrc64++; ++ size -= 8; ++ } ++ p_Src8 = (uint8_t*)(pSrc64); ++ p_Dst8 = (uint8_t*)(pDst64); ++ } ++ else ++ { ++ /* source is not aligned (destination is aligned)*/ ++ pSrc64 = (uint64_t*)(p_Src8 - (leftAlign >> 3)); ++ pDst64 = (uint64_t*)(p_Dst8); ++ lastWord = *pSrc64++; ++ while(size >> 4) /* size >= 16 */ ++ { ++ currWord = *pSrc64; ++ *pDst64 = (lastWord << leftAlign) | (currWord >> rightAlign); ++ lastWord = currWord; ++ pSrc64++; ++ pDst64++; ++ size -= 8; ++ } ++ p_Dst8 = (uint8_t*)(pDst64); ++ p_Src8 = (uint8_t*)(pSrc64) - 8 + (leftAlign >> 3); ++ } ++ ++ /* complete the left overs */ ++ while (size--) ++ *p_Dst8++ = *p_Src8++; ++ ++ return pDst; ++} ++ ++void * MemSet32(void* pDst, uint8_t val, uint32_t size) ++{ ++ uint32_t val32; ++ uint32_t *p_Dst32; ++ uint8_t *p_Dst8; ++ ++ p_Dst8 = (uint8_t*)(pDst); ++ ++ /* generate four 8-bit val's in 32-bit container */ ++ val32 = (uint32_t) val; ++ val32 |= (val32 << 8); ++ val32 |= (val32 << 16); ++ ++ /* align destination to 32 */ ++ while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ ++ { ++ *p_Dst8++ = val; ++ size--; ++ } ++ ++ /* 32-bit chunks */ ++ p_Dst32 = (uint32_t*)(p_Dst8); ++ while (size >> 2) /* size >= 4 */ ++ { ++ *p_Dst32++ = val32; ++ size -= 4; ++ } ++ ++ /* complete the leftovers */ ++ p_Dst8 = (uint8_t*)(p_Dst32); ++ while (size--) ++ *p_Dst8++ = val; ++ ++ return pDst; ++} ++ ++void * IOMemSet32(void* pDst, uint8_t val, uint32_t size) ++{ ++ uint32_t val32; ++ uint32_t *p_Dst32; ++ uint8_t *p_Dst8; ++ ++ p_Dst8 = (uint8_t*)(pDst); ++ ++ /* generate four 8-bit val's in 32-bit container */ ++ val32 = (uint32_t) val; ++ val32 |= (val32 << 8); ++ val32 |= (val32 << 16); ++ ++ /* align destination to 32 */ ++ while((PTR_TO_UINT(p_Dst8) & 3) && size) /* (pDst mod 4) > 0 and size > 0 */ ++ { ++ WRITE_UINT8(*p_Dst8, val); ++ p_Dst8++; ++ size--; ++ } ++ ++ /* 32-bit chunks */ ++ p_Dst32 = (uint32_t*)(p_Dst8); ++ while (size >> 2) /* size >= 4 */ ++ { ++ WRITE_UINT32(*p_Dst32, val32); ++ p_Dst32++; ++ size -= 4; ++ } ++ ++ /* complete the leftovers */ ++ p_Dst8 = (uint8_t*)(p_Dst32); ++ while (size--) ++ { ++ WRITE_UINT8(*p_Dst8, val); ++ p_Dst8++; ++ } ++ ++ return pDst; ++} ++ ++void * MemSet64(void* pDst, uint8_t val, uint32_t size) ++{ ++ uint64_t val64; ++ uint64_t *pDst64; ++ uint8_t *p_Dst8; ++ ++ p_Dst8 = (uint8_t*)(pDst); ++ ++ /* generate four 8-bit val's in 32-bit container */ ++ val64 = (uint64_t) val; ++ val64 |= (val64 << 8); ++ val64 |= (val64 << 16); ++ val64 |= (val64 << 24); ++ val64 |= (val64 << 32); ++ ++ /* align destination to 64 */ ++ while((PTR_TO_UINT(p_Dst8) & 7) && size) /* (pDst mod 8) > 0 and size > 0 */ ++ { ++ *p_Dst8++ = val; ++ size--; ++ } ++ ++ /* 64-bit chunks */ ++ pDst64 = (uint64_t*)(p_Dst8); ++ while (size >> 4) /* size >= 8 */ ++ { ++ *pDst64++ = val64; ++ size -= 8; ++ } ++ ++ /* complete the leftovers */ ++ p_Dst8 = (uint8_t*)(pDst64); ++ while (size--) ++ *p_Dst8++ = val; ++ ++ return pDst; ++} ++ ++void MemDisp(uint8_t *p, int size) ++{ ++ uint32_t space = (uint32_t)(PTR_TO_UINT(p) & 0x3); ++ uint8_t *p_Limit; ++ ++ if (space) ++ { ++ p_Limit = (p - space + 4); ++ ++ XX_Print("0x%08X: ", (p - space)); ++ ++ while (space--) ++ { ++ XX_Print("--"); ++ } ++ while (size && (p < p_Limit)) ++ { ++ XX_Print("%02x", *(uint8_t*)p); ++ size--; ++ p++; ++ } ++ ++ XX_Print(" "); ++ p_Limit += 12; ++ ++ while ((size > 3) && (p < p_Limit)) ++ { ++ XX_Print("%08x ", *(uint32_t*)p); ++ size -= 4; ++ p += 4; ++ } ++ XX_Print("\r\n"); ++ } ++ ++ while (size > 15) ++ { ++ XX_Print("0x%08X: %08x %08x %08x %08x\r\n", ++ p, *(uint32_t *)p, *(uint32_t *)(p + 4), ++ *(uint32_t *)(p + 8), *(uint32_t *)(p + 12)); ++ size -= 16; ++ p += 16; ++ } ++ ++ if (size) ++ { ++ XX_Print("0x%08X: ", p); ++ ++ while (size > 3) ++ { ++ XX_Print("%08x ", *(uint32_t *)p); ++ size -= 4; ++ p += 4; ++ } ++ while (size) ++ { ++ XX_Print("%02x", *(uint8_t *)p); ++ size--; ++ p++; ++ } ++ ++ XX_Print("\r\n"); ++ } ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/etc/mm.c b/drivers/net/ethernet/freescale/sdk_fman/etc/mm.c +new file mode 100644 +index 00000000..9fcc46e0 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/etc/mm.c +@@ -0,0 +1,1155 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#include "string_ext.h" ++#include "error_ext.h" ++#include "std_ext.h" ++#include "part_ext.h" ++#include "xx_ext.h" ++ ++#include "mm.h" ++ ++ ++ ++ ++/********************************************************************** ++ * MM internal routines set * ++ **********************************************************************/ ++ ++/**************************************************************** ++ * Routine: CreateBusyBlock ++ * ++ * Description: ++ * Initializes a new busy block of "size" bytes and started ++ * rom "base" address. Each busy block has a name that ++ * specified the purpose of the memory allocation. ++ * ++ * Arguments: ++ * base - base address of the busy block ++ * size - size of the busy block ++ * name - name that specified the busy block ++ * ++ * Return value: ++ * A pointer to new created structure returned on success; ++ * Otherwise, NULL. ++ ****************************************************************/ ++static t_BusyBlock * CreateBusyBlock(uint64_t base, uint64_t size, char *name) ++{ ++ t_BusyBlock *p_BusyBlock; ++ uint32_t n; ++ ++ p_BusyBlock = (t_BusyBlock *)XX_Malloc(sizeof(t_BusyBlock)); ++ if ( !p_BusyBlock ) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); ++ return NULL; ++ } ++ ++ p_BusyBlock->base = base; ++ p_BusyBlock->end = base + size; ++ ++ n = strlen(name); ++ if (n >= MM_MAX_NAME_LEN) ++ n = MM_MAX_NAME_LEN - 1; ++ strncpy(p_BusyBlock->name, name, MM_MAX_NAME_LEN-1); ++ p_BusyBlock->name[n] = '\0'; ++ p_BusyBlock->p_Next = 0; ++ ++ return p_BusyBlock; ++} ++ ++/**************************************************************** ++ * Routine: CreateNewBlock ++ * ++ * Description: ++ * Initializes a new memory block of "size" bytes and started ++ * from "base" address. ++ * ++ * Arguments: ++ * base - base address of the memory block ++ * size - size of the memory block ++ * ++ * Return value: ++ * A pointer to new created structure returned on success; ++ * Otherwise, NULL. ++ ****************************************************************/ ++static t_MemBlock * CreateNewBlock(uint64_t base, uint64_t size) ++{ ++ t_MemBlock *p_MemBlock; ++ ++ p_MemBlock = (t_MemBlock *)XX_Malloc(sizeof(t_MemBlock)); ++ if ( !p_MemBlock ) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); ++ return NULL; ++ } ++ ++ p_MemBlock->base = base; ++ p_MemBlock->end = base+size; ++ p_MemBlock->p_Next = 0; ++ ++ return p_MemBlock; ++} ++ ++/**************************************************************** ++ * Routine: CreateFreeBlock ++ * ++ * Description: ++ * Initializes a new free block of of "size" bytes and ++ * started from "base" address. ++ * ++ * Arguments: ++ * base - base address of the free block ++ * size - size of the free block ++ * ++ * Return value: ++ * A pointer to new created structure returned on success; ++ * Otherwise, NULL. ++ ****************************************************************/ ++static t_FreeBlock * CreateFreeBlock(uint64_t base, uint64_t size) ++{ ++ t_FreeBlock *p_FreeBlock; ++ ++ p_FreeBlock = (t_FreeBlock *)XX_Malloc(sizeof(t_FreeBlock)); ++ if ( !p_FreeBlock ) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); ++ return NULL; ++ } ++ ++ p_FreeBlock->base = base; ++ p_FreeBlock->end = base + size; ++ p_FreeBlock->p_Next = 0; ++ ++ return p_FreeBlock; ++} ++ ++/**************************************************************** ++ * Routine: AddFree ++ * ++ * Description: ++ * Adds a new free block to the free lists. It updates each ++ * free list to include a new free block. ++ * Note, that all free block in each free list are ordered ++ * by their base address. ++ * ++ * Arguments: ++ * p_MM - pointer to the MM object ++ * base - base address of a given free block ++ * end - end address of a given free block ++ * ++ * Return value: ++ * ++ * ++ ****************************************************************/ ++static t_Error AddFree(t_MM *p_MM, uint64_t base, uint64_t end) ++{ ++ t_FreeBlock *p_PrevB, *p_CurrB, *p_NewB; ++ uint64_t alignment; ++ uint64_t alignBase; ++ int i; ++ ++ /* Updates free lists to include a just released block */ ++ for (i=0; i <= MM_MAX_ALIGNMENT; i++) ++ { ++ p_PrevB = p_NewB = 0; ++ p_CurrB = p_MM->freeBlocks[i]; ++ ++ alignment = (uint64_t)(0x1 << i); ++ alignBase = MAKE_ALIGNED(base, alignment); ++ ++ /* Goes to the next free list if there is no block to free */ ++ if (alignBase >= end) ++ continue; ++ ++ /* Looks for a free block that should be updated */ ++ while ( p_CurrB ) ++ { ++ if ( alignBase <= p_CurrB->end ) ++ { ++ if ( end > p_CurrB->end ) ++ { ++ t_FreeBlock *p_NextB; ++ while ( p_CurrB->p_Next && end > p_CurrB->p_Next->end ) ++ { ++ p_NextB = p_CurrB->p_Next; ++ p_CurrB->p_Next = p_CurrB->p_Next->p_Next; ++ XX_Free(p_NextB); ++ } ++ ++ p_NextB = p_CurrB->p_Next; ++ if ( !p_NextB || (p_NextB && end < p_NextB->base) ) ++ { ++ p_CurrB->end = end; ++ } ++ else ++ { ++ p_CurrB->end = p_NextB->end; ++ p_CurrB->p_Next = p_NextB->p_Next; ++ XX_Free(p_NextB); ++ } ++ } ++ else if ( (end < p_CurrB->base) && ((end-alignBase) >= alignment) ) ++ { ++ if ((p_NewB = CreateFreeBlock(alignBase, end-alignBase)) == NULL) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); ++ ++ p_NewB->p_Next = p_CurrB; ++ if (p_PrevB) ++ p_PrevB->p_Next = p_NewB; ++ else ++ p_MM->freeBlocks[i] = p_NewB; ++ break; ++ } ++ ++ if ((alignBase < p_CurrB->base) && (end >= p_CurrB->base)) ++ { ++ p_CurrB->base = alignBase; ++ } ++ ++ /* if size of the free block is less then alignment ++ * deletes that free block from the free list. */ ++ if ( (p_CurrB->end - p_CurrB->base) < alignment) ++ { ++ if ( p_PrevB ) ++ p_PrevB->p_Next = p_CurrB->p_Next; ++ else ++ p_MM->freeBlocks[i] = p_CurrB->p_Next; ++ XX_Free(p_CurrB); ++ p_CurrB = NULL; ++ } ++ break; ++ } ++ else ++ { ++ p_PrevB = p_CurrB; ++ p_CurrB = p_CurrB->p_Next; ++ } ++ } ++ ++ /* If no free block found to be updated, insert a new free block ++ * to the end of the free list. ++ */ ++ if ( !p_CurrB && ((((uint64_t)(end-base)) & ((uint64_t)(alignment-1))) == 0) ) ++ { ++ if ((p_NewB = CreateFreeBlock(alignBase, end-base)) == NULL) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); ++ ++ if (p_PrevB) ++ p_PrevB->p_Next = p_NewB; ++ else ++ p_MM->freeBlocks[i] = p_NewB; ++ } ++ ++ /* Update boundaries of the new free block */ ++ if ((alignment == 1) && !p_NewB) ++ { ++ if ( p_CurrB && base > p_CurrB->base ) ++ base = p_CurrB->base; ++ if ( p_CurrB && end < p_CurrB->end ) ++ end = p_CurrB->end; ++ } ++ } ++ ++ return (E_OK); ++} ++ ++/**************************************************************** ++ * Routine: CutFree ++ * ++ * Description: ++ * Cuts a free block from holdBase to holdEnd from the free lists. ++ * That is, it updates all free lists of the MM object do ++ * not include a block of memory from holdBase to holdEnd. ++ * For each free lists it seek for a free block that holds ++ * either holdBase or holdEnd. If such block is found it updates it. ++ * ++ * Arguments: ++ * p_MM - pointer to the MM object ++ * holdBase - base address of the allocated block ++ * holdEnd - end address of the allocated block ++ * ++ * Return value: ++ * E_OK is returned on success, ++ * otherwise returns an error code. ++ * ++ ****************************************************************/ ++static t_Error CutFree(t_MM *p_MM, uint64_t holdBase, uint64_t holdEnd) ++{ ++ t_FreeBlock *p_PrevB, *p_CurrB, *p_NewB; ++ uint64_t alignBase, base, end; ++ uint64_t alignment; ++ int i; ++ ++ for (i=0; i <= MM_MAX_ALIGNMENT; i++) ++ { ++ p_PrevB = p_NewB = 0; ++ p_CurrB = p_MM->freeBlocks[i]; ++ ++ alignment = (uint64_t)(0x1 << i); ++ alignBase = MAKE_ALIGNED(holdEnd, alignment); ++ ++ while ( p_CurrB ) ++ { ++ base = p_CurrB->base; ++ end = p_CurrB->end; ++ ++ if ( (holdBase <= base) && (holdEnd <= end) && (holdEnd > base) ) ++ { ++ if ( alignBase >= end || ++ (alignBase < end && ((end-alignBase) < alignment)) ) ++ { ++ if (p_PrevB) ++ p_PrevB->p_Next = p_CurrB->p_Next; ++ else ++ p_MM->freeBlocks[i] = p_CurrB->p_Next; ++ XX_Free(p_CurrB); ++ } ++ else ++ { ++ p_CurrB->base = alignBase; ++ } ++ break; ++ } ++ else if ( (holdBase > base) && (holdEnd <= end) ) ++ { ++ if ( (holdBase-base) >= alignment ) ++ { ++ if ( (alignBase < end) && ((end-alignBase) >= alignment) ) ++ { ++ if ((p_NewB = CreateFreeBlock(alignBase, end-alignBase)) == NULL) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); ++ p_NewB->p_Next = p_CurrB->p_Next; ++ p_CurrB->p_Next = p_NewB; ++ } ++ p_CurrB->end = holdBase; ++ } ++ else if ( (alignBase < end) && ((end-alignBase) >= alignment) ) ++ { ++ p_CurrB->base = alignBase; ++ } ++ else ++ { ++ if (p_PrevB) ++ p_PrevB->p_Next = p_CurrB->p_Next; ++ else ++ p_MM->freeBlocks[i] = p_CurrB->p_Next; ++ XX_Free(p_CurrB); ++ } ++ break; ++ } ++ else ++ { ++ p_PrevB = p_CurrB; ++ p_CurrB = p_CurrB->p_Next; ++ } ++ } ++ } ++ ++ return (E_OK); ++} ++ ++/**************************************************************** ++ * Routine: AddBusy ++ * ++ * Description: ++ * Adds a new busy block to the list of busy blocks. Note, ++ * that all busy blocks are ordered by their base address in ++ * the busy list. ++ * ++ * Arguments: ++ * MM - handler to the MM object ++ * p_NewBusyB - pointer to the a busy block ++ * ++ * Return value: ++ * None. ++ * ++ ****************************************************************/ ++static void AddBusy(t_MM *p_MM, t_BusyBlock *p_NewBusyB) ++{ ++ t_BusyBlock *p_CurrBusyB, *p_PrevBusyB; ++ ++ /* finds a place of a new busy block in the list of busy blocks */ ++ p_PrevBusyB = 0; ++ p_CurrBusyB = p_MM->busyBlocks; ++ ++ while ( p_CurrBusyB && p_NewBusyB->base > p_CurrBusyB->base ) ++ { ++ p_PrevBusyB = p_CurrBusyB; ++ p_CurrBusyB = p_CurrBusyB->p_Next; ++ } ++ ++ /* insert the new busy block into the list of busy blocks */ ++ if ( p_CurrBusyB ) ++ p_NewBusyB->p_Next = p_CurrBusyB; ++ if ( p_PrevBusyB ) ++ p_PrevBusyB->p_Next = p_NewBusyB; ++ else ++ p_MM->busyBlocks = p_NewBusyB; ++} ++ ++/**************************************************************** ++ * Routine: CutBusy ++ * ++ * Description: ++ * Cuts a block from base to end from the list of busy blocks. ++ * This is done by updating the list of busy blocks do not ++ * include a given block, that block is going to be free. If a ++ * given block is a part of some other busy block, so that ++ * busy block is updated. If there are number of busy blocks ++ * included in the given block, so all that blocks are removed ++ * from the busy list and the end blocks are updated. ++ * If the given block devides some block into two parts, a new ++ * busy block is added to the busy list. ++ * ++ * Arguments: ++ * p_MM - pointer to the MM object ++ * base - base address of a given busy block ++ * end - end address of a given busy block ++ * ++ * Return value: ++ * E_OK on success, E_NOMEMORY otherwise. ++ * ++ ****************************************************************/ ++static t_Error CutBusy(t_MM *p_MM, uint64_t base, uint64_t end) ++{ ++ t_BusyBlock *p_CurrB, *p_PrevB, *p_NewB; ++ ++ p_CurrB = p_MM->busyBlocks; ++ p_PrevB = p_NewB = 0; ++ ++ while ( p_CurrB ) ++ { ++ if ( base < p_CurrB->end ) ++ { ++ if ( end > p_CurrB->end ) ++ { ++ t_BusyBlock *p_NextB; ++ while ( p_CurrB->p_Next && end >= p_CurrB->p_Next->end ) ++ { ++ p_NextB = p_CurrB->p_Next; ++ p_CurrB->p_Next = p_CurrB->p_Next->p_Next; ++ XX_Free(p_NextB); ++ } ++ ++ p_NextB = p_CurrB->p_Next; ++ if ( p_NextB && end > p_NextB->base ) ++ { ++ p_NextB->base = end; ++ } ++ } ++ ++ if ( base <= p_CurrB->base ) ++ { ++ if ( end < p_CurrB->end && end > p_CurrB->base ) ++ { ++ p_CurrB->base = end; ++ } ++ else if ( end >= p_CurrB->end ) ++ { ++ if ( p_PrevB ) ++ p_PrevB->p_Next = p_CurrB->p_Next; ++ else ++ p_MM->busyBlocks = p_CurrB->p_Next; ++ XX_Free(p_CurrB); ++ } ++ } ++ else ++ { ++ if ( end < p_CurrB->end && end > p_CurrB->base ) ++ { ++ if ((p_NewB = CreateBusyBlock(end, ++ p_CurrB->end-end, ++ p_CurrB->name)) == NULL) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); ++ p_NewB->p_Next = p_CurrB->p_Next; ++ p_CurrB->p_Next = p_NewB; ++ } ++ p_CurrB->end = base; ++ } ++ break; ++ } ++ else ++ { ++ p_PrevB = p_CurrB; ++ p_CurrB = p_CurrB->p_Next; ++ } ++ } ++ ++ return (E_OK); ++} ++ ++/**************************************************************** ++ * Routine: MmGetGreaterAlignment ++ * ++ * Description: ++ * Allocates a block of memory according to the given size ++ * and the alignment. That routine is called from the MM_Get ++ * routine if the required alignment is greater then MM_MAX_ALIGNMENT. ++ * In that case, it goes over free blocks of 64 byte align list ++ * and checks if it has the required size of bytes of the required ++ * alignment. If no blocks found returns ILLEGAL_BASE. ++ * After the block is found and data is allocated, it calls ++ * the internal CutFree routine to update all free lists ++ * do not include a just allocated block. Of course, each ++ * free list contains a free blocks with the same alignment. ++ * It is also creates a busy block that holds ++ * information about an allocated block. ++ * ++ * Arguments: ++ * MM - handle to the MM object ++ * size - size of the MM ++ * alignment - index as a power of two defines ++ * a required alignment that is greater then 64. ++ * name - the name that specifies an allocated block. ++ * ++ * Return value: ++ * base address of an allocated block. ++ * ILLEGAL_BASE if can't allocate a block ++ * ++ ****************************************************************/ ++static uint64_t MmGetGreaterAlignment(t_MM *p_MM, uint64_t size, uint64_t alignment, char* name) ++{ ++ t_FreeBlock *p_FreeB; ++ t_BusyBlock *p_NewBusyB; ++ uint64_t holdBase, holdEnd, alignBase = 0; ++ ++ /* goes over free blocks of the 64 byte alignment list ++ and look for a block of the suitable size and ++ base address according to the alignment. */ ++ p_FreeB = p_MM->freeBlocks[MM_MAX_ALIGNMENT]; ++ ++ while ( p_FreeB ) ++ { ++ alignBase = MAKE_ALIGNED(p_FreeB->base, alignment); ++ ++ /* the block is found if the aligned base inside the block ++ * and has the anough size. */ ++ if ( alignBase >= p_FreeB->base && ++ alignBase < p_FreeB->end && ++ size <= (p_FreeB->end - alignBase) ) ++ break; ++ else ++ p_FreeB = p_FreeB->p_Next; ++ } ++ ++ /* If such block isn't found */ ++ if ( !p_FreeB ) ++ return (uint64_t)(ILLEGAL_BASE); ++ ++ holdBase = alignBase; ++ holdEnd = alignBase + size; ++ ++ /* init a new busy block */ ++ if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL) ++ return (uint64_t)(ILLEGAL_BASE); ++ ++ /* calls Update routine to update a lists of free blocks */ ++ if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK ) ++ { ++ XX_Free(p_NewBusyB); ++ return (uint64_t)(ILLEGAL_BASE); ++ } ++ ++ /* insert the new busy block into the list of busy blocks */ ++ AddBusy ( p_MM, p_NewBusyB ); ++ ++ return (holdBase); ++} ++ ++ ++/********************************************************************** ++ * MM API routines set * ++ **********************************************************************/ ++ ++/*****************************************************************************/ ++t_Error MM_Init(t_Handle *h_MM, uint64_t base, uint64_t size) ++{ ++ t_MM *p_MM; ++ uint64_t newBase, newSize; ++ int i; ++ ++ if (!size) ++ { ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Size (should be positive)")); ++ } ++ ++ /* Initializes a new MM object */ ++ p_MM = (t_MM *)XX_Malloc(sizeof(t_MM)); ++ if (!p_MM) ++ { ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); ++ } ++ ++ p_MM->h_Spinlock = XX_InitSpinlock(); ++ if (!p_MM->h_Spinlock) ++ { ++ XX_Free(p_MM); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MM spinlock!")); ++ } ++ ++ /* Initializes counter of free memory to total size */ ++ p_MM->freeMemSize = size; ++ ++ /* A busy list is empty */ ++ p_MM->busyBlocks = 0; ++ ++ /* Initializes a new memory block */ ++ if ((p_MM->memBlocks = CreateNewBlock(base, size)) == NULL) ++ { ++ MM_Free(p_MM); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); ++ } ++ ++ /* Initializes a new free block for each free list*/ ++ for (i=0; i <= MM_MAX_ALIGNMENT; i++) ++ { ++ newBase = MAKE_ALIGNED( base, (0x1 << i) ); ++ newSize = size - (newBase - base); ++ ++ if ((p_MM->freeBlocks[i] = CreateFreeBlock(newBase, newSize)) == NULL) ++ { ++ MM_Free(p_MM); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); ++ } ++ } ++ ++ *h_MM = p_MM; ++ ++ return (E_OK); ++} ++ ++/*****************************************************************************/ ++void MM_Free(t_Handle h_MM) ++{ ++ t_MM *p_MM = (t_MM *)h_MM; ++ t_MemBlock *p_MemBlock; ++ t_BusyBlock *p_BusyBlock; ++ t_FreeBlock *p_FreeBlock; ++ void *p_Block; ++ int i; ++ ++ ASSERT_COND(p_MM); ++ ++ /* release memory allocated for busy blocks */ ++ p_BusyBlock = p_MM->busyBlocks; ++ while ( p_BusyBlock ) ++ { ++ p_Block = p_BusyBlock; ++ p_BusyBlock = p_BusyBlock->p_Next; ++ XX_Free(p_Block); ++ } ++ ++ /* release memory allocated for free blocks */ ++ for (i=0; i <= MM_MAX_ALIGNMENT; i++) ++ { ++ p_FreeBlock = p_MM->freeBlocks[i]; ++ while ( p_FreeBlock ) ++ { ++ p_Block = p_FreeBlock; ++ p_FreeBlock = p_FreeBlock->p_Next; ++ XX_Free(p_Block); ++ } ++ } ++ ++ /* release memory allocated for memory blocks */ ++ p_MemBlock = p_MM->memBlocks; ++ while ( p_MemBlock ) ++ { ++ p_Block = p_MemBlock; ++ p_MemBlock = p_MemBlock->p_Next; ++ XX_Free(p_Block); ++ } ++ ++ if (p_MM->h_Spinlock) ++ XX_FreeSpinlock(p_MM->h_Spinlock); ++ ++ /* release memory allocated for MM object itself */ ++ XX_Free(p_MM); ++} ++ ++/*****************************************************************************/ ++uint64_t MM_Get(t_Handle h_MM, uint64_t size, uint64_t alignment, char* name) ++{ ++ t_MM *p_MM = (t_MM *)h_MM; ++ t_FreeBlock *p_FreeB; ++ t_BusyBlock *p_NewBusyB; ++ uint64_t holdBase, holdEnd, j, i = 0; ++ uint32_t intFlags; ++ ++ SANITY_CHECK_RETURN_VALUE(p_MM, E_INVALID_HANDLE, (uint64_t)ILLEGAL_BASE); ++ ++ /* checks that alignment value is greater then zero */ ++ if (alignment == 0) ++ { ++ alignment = 1; ++ } ++ ++ j = alignment; ++ ++ /* checks if alignment is a power of two, if it correct and if the ++ required size is multiple of the given alignment. */ ++ while ((j & 0x1) == 0) ++ { ++ i++; ++ j = j >> 1; ++ } ++ ++ /* if the given alignment isn't power of two, returns an error */ ++ if (j != 1) ++ { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("alignment (should be power of 2)")); ++ return (uint64_t)ILLEGAL_BASE; ++ } ++ ++ if (i > MM_MAX_ALIGNMENT) ++ { ++ return (MmGetGreaterAlignment(p_MM, size, alignment, name)); ++ } ++ ++ intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); ++ /* look for a block of the size greater or equal to the required size. */ ++ p_FreeB = p_MM->freeBlocks[i]; ++ while ( p_FreeB && (p_FreeB->end - p_FreeB->base) < size ) ++ p_FreeB = p_FreeB->p_Next; ++ ++ /* If such block is found */ ++ if ( !p_FreeB ) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ return (uint64_t)(ILLEGAL_BASE); ++ } ++ ++ holdBase = p_FreeB->base; ++ holdEnd = holdBase + size; ++ ++ /* init a new busy block */ ++ if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ return (uint64_t)(ILLEGAL_BASE); ++ } ++ ++ /* calls Update routine to update a lists of free blocks */ ++ if ( CutFree ( p_MM, holdBase, holdEnd ) != E_OK ) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ XX_Free(p_NewBusyB); ++ return (uint64_t)(ILLEGAL_BASE); ++ } ++ ++ /* Decreasing the allocated memory size from free memory size */ ++ p_MM->freeMemSize -= size; ++ ++ /* insert the new busy block into the list of busy blocks */ ++ AddBusy ( p_MM, p_NewBusyB ); ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ ++ return (holdBase); ++} ++ ++/*****************************************************************************/ ++uint64_t MM_GetForce(t_Handle h_MM, uint64_t base, uint64_t size, char* name) ++{ ++ t_MM *p_MM = (t_MM *)h_MM; ++ t_FreeBlock *p_FreeB; ++ t_BusyBlock *p_NewBusyB; ++ uint32_t intFlags; ++ bool blockIsFree = FALSE; ++ ++ ASSERT_COND(p_MM); ++ ++ intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); ++ p_FreeB = p_MM->freeBlocks[0]; /* The biggest free blocks are in the ++ free list with alignment 1 */ ++ ++ while ( p_FreeB ) ++ { ++ if ( base >= p_FreeB->base && (base+size) <= p_FreeB->end ) ++ { ++ blockIsFree = TRUE; ++ break; ++ } ++ else ++ p_FreeB = p_FreeB->p_Next; ++ } ++ ++ if ( !blockIsFree ) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ return (uint64_t)(ILLEGAL_BASE); ++ } ++ ++ /* init a new busy block */ ++ if ((p_NewBusyB = CreateBusyBlock(base, size, name)) == NULL) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ return (uint64_t)(ILLEGAL_BASE); ++ } ++ ++ /* calls Update routine to update a lists of free blocks */ ++ if ( CutFree ( p_MM, base, base+size ) != E_OK ) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ XX_Free(p_NewBusyB); ++ return (uint64_t)(ILLEGAL_BASE); ++ } ++ ++ /* Decreasing the allocated memory size from free memory size */ ++ p_MM->freeMemSize -= size; ++ ++ /* insert the new busy block into the list of busy blocks */ ++ AddBusy ( p_MM, p_NewBusyB ); ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ ++ return (base); ++} ++ ++/*****************************************************************************/ ++uint64_t MM_GetForceMin(t_Handle h_MM, uint64_t size, uint64_t alignment, uint64_t min, char* name) ++{ ++ t_MM *p_MM = (t_MM *)h_MM; ++ t_FreeBlock *p_FreeB; ++ t_BusyBlock *p_NewBusyB; ++ uint64_t holdBase, holdEnd, j = alignment, i=0; ++ uint32_t intFlags; ++ ++ ASSERT_COND(p_MM); ++ ++ /* checks if alignment is a power of two, if it correct and if the ++ required size is multiple of the given alignment. */ ++ while ((j & 0x1) == 0) ++ { ++ i++; ++ j = j >> 1; ++ } ++ ++ if ( (j != 1) || (i > MM_MAX_ALIGNMENT) ) ++ { ++ return (uint64_t)(ILLEGAL_BASE); ++ } ++ ++ intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); ++ p_FreeB = p_MM->freeBlocks[i]; ++ ++ /* look for the first block that contains the minimum ++ base address. If the whole required size may be fit ++ into it, use that block, otherwise look for the next ++ block of size greater or equal to the required size. */ ++ while ( p_FreeB && (min >= p_FreeB->end)) ++ p_FreeB = p_FreeB->p_Next; ++ ++ /* If such block is found */ ++ if ( !p_FreeB ) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ return (uint64_t)(ILLEGAL_BASE); ++ } ++ ++ /* if this block is large enough, use this block */ ++ holdBase = ( min <= p_FreeB->base ) ? p_FreeB->base : min; ++ if ((holdBase + size) <= p_FreeB->end ) ++ { ++ holdEnd = holdBase + size; ++ } ++ else ++ { ++ p_FreeB = p_FreeB->p_Next; ++ while ( p_FreeB && ((p_FreeB->end - p_FreeB->base) < size) ) ++ p_FreeB = p_FreeB->p_Next; ++ ++ /* If such block is found */ ++ if ( !p_FreeB ) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ return (uint64_t)(ILLEGAL_BASE); ++ } ++ ++ holdBase = p_FreeB->base; ++ holdEnd = holdBase + size; ++ } ++ ++ /* init a new busy block */ ++ if ((p_NewBusyB = CreateBusyBlock(holdBase, size, name)) == NULL) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ return (uint64_t)(ILLEGAL_BASE); ++ } ++ ++ /* calls Update routine to update a lists of free blocks */ ++ if ( CutFree( p_MM, holdBase, holdEnd ) != E_OK ) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ XX_Free(p_NewBusyB); ++ return (uint64_t)(ILLEGAL_BASE); ++ } ++ ++ /* Decreasing the allocated memory size from free memory size */ ++ p_MM->freeMemSize -= size; ++ ++ /* insert the new busy block into the list of busy blocks */ ++ AddBusy( p_MM, p_NewBusyB ); ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ ++ return (holdBase); ++} ++ ++/*****************************************************************************/ ++uint64_t MM_Put(t_Handle h_MM, uint64_t base) ++{ ++ t_MM *p_MM = (t_MM *)h_MM; ++ t_BusyBlock *p_BusyB, *p_PrevBusyB; ++ uint64_t size; ++ uint32_t intFlags; ++ ++ ASSERT_COND(p_MM); ++ ++ /* Look for a busy block that have the given base value. ++ * That block will be returned back to the memory. ++ */ ++ p_PrevBusyB = 0; ++ ++ intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); ++ p_BusyB = p_MM->busyBlocks; ++ while ( p_BusyB && base != p_BusyB->base ) ++ { ++ p_PrevBusyB = p_BusyB; ++ p_BusyB = p_BusyB->p_Next; ++ } ++ ++ if ( !p_BusyB ) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ return (uint64_t)(0); ++ } ++ ++ if ( AddFree( p_MM, p_BusyB->base, p_BusyB->end ) != E_OK ) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ return (uint64_t)(0); ++ } ++ ++ /* removes a busy block form the list of busy blocks */ ++ if ( p_PrevBusyB ) ++ p_PrevBusyB->p_Next = p_BusyB->p_Next; ++ else ++ p_MM->busyBlocks = p_BusyB->p_Next; ++ ++ size = p_BusyB->end - p_BusyB->base; ++ ++ /* Adding the deallocated memory size to free memory size */ ++ p_MM->freeMemSize += size; ++ ++ XX_Free(p_BusyB); ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ ++ return (size); ++} ++ ++/*****************************************************************************/ ++uint64_t MM_PutForce(t_Handle h_MM, uint64_t base, uint64_t size) ++{ ++ t_MM *p_MM = (t_MM *)h_MM; ++ uint64_t end = base + size; ++ uint32_t intFlags; ++ ++ ASSERT_COND(p_MM); ++ ++ intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); ++ ++ if ( CutBusy( p_MM, base, end ) != E_OK ) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ return (uint64_t)(0); ++ } ++ ++ if ( AddFree ( p_MM, base, end ) != E_OK ) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ return (uint64_t)(0); ++ } ++ ++ /* Adding the deallocated memory size to free memory size */ ++ p_MM->freeMemSize += size; ++ ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ ++ return (size); ++} ++ ++/*****************************************************************************/ ++t_Error MM_Add(t_Handle h_MM, uint64_t base, uint64_t size) ++{ ++ t_MM *p_MM = (t_MM *)h_MM; ++ t_MemBlock *p_MemB, *p_NewMemB; ++ t_Error errCode; ++ uint32_t intFlags; ++ ++ ASSERT_COND(p_MM); ++ ++ /* find a last block in the list of memory blocks to insert a new ++ * memory block ++ */ ++ intFlags = XX_LockIntrSpinlock(p_MM->h_Spinlock); ++ ++ p_MemB = p_MM->memBlocks; ++ while ( p_MemB->p_Next ) ++ { ++ if ( base >= p_MemB->base && base < p_MemB->end ) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG); ++ } ++ p_MemB = p_MemB->p_Next; ++ } ++ /* check for a last memory block */ ++ if ( base >= p_MemB->base && base < p_MemB->end ) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG); ++ } ++ ++ /* create a new memory block */ ++ if ((p_NewMemB = CreateNewBlock(base, size)) == NULL) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); ++ } ++ ++ /* append a new memory block to the end of the list of memory blocks */ ++ p_MemB->p_Next = p_NewMemB; ++ ++ /* add a new free block to the free lists */ ++ errCode = AddFree(p_MM, base, base+size); ++ if (errCode) ++ { ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ p_MemB->p_Next = 0; ++ XX_Free(p_NewMemB); ++ return ((t_Error)errCode); ++ } ++ ++ /* Adding the new block size to free memory size */ ++ p_MM->freeMemSize += size; ++ ++ XX_UnlockIntrSpinlock(p_MM->h_Spinlock, intFlags); ++ ++ return (E_OK); ++} ++ ++/*****************************************************************************/ ++uint64_t MM_GetMemBlock(t_Handle h_MM, int index) ++{ ++ t_MM *p_MM = (t_MM*)h_MM; ++ t_MemBlock *p_MemBlock; ++ int i; ++ ++ ASSERT_COND(p_MM); ++ ++ p_MemBlock = p_MM->memBlocks; ++ for (i=0; i < index; i++) ++ p_MemBlock = p_MemBlock->p_Next; ++ ++ if ( p_MemBlock ) ++ return (p_MemBlock->base); ++ else ++ return (uint64_t)ILLEGAL_BASE; ++} ++ ++/*****************************************************************************/ ++uint64_t MM_GetBase(t_Handle h_MM) ++{ ++ t_MM *p_MM = (t_MM*)h_MM; ++ t_MemBlock *p_MemBlock; ++ ++ ASSERT_COND(p_MM); ++ ++ p_MemBlock = p_MM->memBlocks; ++ return p_MemBlock->base; ++} ++ ++/*****************************************************************************/ ++bool MM_InRange(t_Handle h_MM, uint64_t addr) ++{ ++ t_MM *p_MM = (t_MM*)h_MM; ++ t_MemBlock *p_MemBlock; ++ ++ ASSERT_COND(p_MM); ++ ++ p_MemBlock = p_MM->memBlocks; ++ ++ if ((addr >= p_MemBlock->base) && (addr < p_MemBlock->end)) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++/*****************************************************************************/ ++uint64_t MM_GetFreeMemSize(t_Handle h_MM) ++{ ++ t_MM *p_MM = (t_MM*)h_MM; ++ ++ ASSERT_COND(p_MM); ++ ++ return p_MM->freeMemSize; ++} ++ ++/*****************************************************************************/ ++void MM_Dump(t_Handle h_MM) ++{ ++ t_MM *p_MM = (t_MM *)h_MM; ++ t_FreeBlock *p_FreeB; ++ t_BusyBlock *p_BusyB; ++ int i; ++ ++ p_BusyB = p_MM->busyBlocks; ++ XX_Print("List of busy blocks:\n"); ++ while (p_BusyB) ++ { ++ XX_Print("\t0x%p: (%s: b=0x%llx, e=0x%llx)\n", p_BusyB, p_BusyB->name, p_BusyB->base, p_BusyB->end ); ++ p_BusyB = p_BusyB->p_Next; ++ } ++ ++ XX_Print("\nLists of free blocks according to alignment:\n"); ++ for (i=0; i <= MM_MAX_ALIGNMENT; i++) ++ { ++ XX_Print("%d alignment:\n", (0x1 << i)); ++ p_FreeB = p_MM->freeBlocks[i]; ++ while (p_FreeB) ++ { ++ XX_Print("\t0x%p: (b=0x%llx, e=0x%llx)\n", p_FreeB, p_FreeB->base, p_FreeB->end); ++ p_FreeB = p_FreeB->p_Next; ++ } ++ XX_Print("\n"); ++ } ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/etc/mm.h b/drivers/net/ethernet/freescale/sdk_fman/etc/mm.h +new file mode 100644 +index 00000000..43b2298f +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/etc/mm.h +@@ -0,0 +1,105 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************** ++ * ++ * File: mm.h ++ * ++ * ++ * Description: ++ * MM (Memory Management) object definitions. ++ * It also includes definitions of the Free Block, Busy Block ++ * and Memory Block structures used by the MM object. ++ * ++ ****************************************************************/ ++ ++#ifndef __MM_H ++#define __MM_H ++ ++ ++#include "mm_ext.h" ++ ++#define __ERR_MODULE__ MODULE_MM ++ ++ ++#define MAKE_ALIGNED(addr, align) \ ++ (((uint64_t)(addr) + ((align) - 1)) & (~(((uint64_t)align) - 1))) ++ ++ ++/* t_MemBlock data structure defines parameters of the Memory Block */ ++typedef struct t_MemBlock ++{ ++ struct t_MemBlock *p_Next; /* Pointer to the next memory block */ ++ ++ uint64_t base; /* Base address of the memory block */ ++ uint64_t end; /* End address of the memory block */ ++} t_MemBlock; ++ ++ ++/* t_FreeBlock data structure defines parameters of the Free Block */ ++typedef struct t_FreeBlock ++{ ++ struct t_FreeBlock *p_Next; /* Pointer to the next free block */ ++ ++ uint64_t base; /* Base address of the block */ ++ uint64_t end; /* End address of the block */ ++} t_FreeBlock; ++ ++ ++/* t_BusyBlock data structure defines parameters of the Busy Block */ ++typedef struct t_BusyBlock ++{ ++ struct t_BusyBlock *p_Next; /* Pointer to the next free block */ ++ ++ uint64_t base; /* Base address of the block */ ++ uint64_t end; /* End address of the block */ ++ char name[MM_MAX_NAME_LEN]; /* That block of memory was allocated for ++ something specified by the Name */ ++} t_BusyBlock; ++ ++ ++/* t_MM data structure defines parameters of the MM object */ ++typedef struct t_MM ++{ ++ t_Handle h_Spinlock; ++ ++ t_MemBlock *memBlocks; /* List of memory blocks (Memory list) */ ++ t_BusyBlock *busyBlocks; /* List of busy blocks (Busy list) */ ++ t_FreeBlock *freeBlocks[MM_MAX_ALIGNMENT + 1]; ++ /* Alignment lists of free blocks (Free lists) */ ++ ++ uint64_t freeMemSize; /* Total size of free memory (in bytes) */ ++} t_MM; ++ ++ ++#endif /* __MM_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/etc/sprint.c b/drivers/net/ethernet/freescale/sdk_fman/etc/sprint.c +new file mode 100644 +index 00000000..46d2956a +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/etc/sprint.c +@@ -0,0 +1,81 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/*------------------------------------------------------*/ ++/* File: sprint.c */ ++/* */ ++/* Description: */ ++/* Debug routines (externals) */ ++/*------------------------------------------------------*/ ++#include "string_ext.h" ++#include "stdlib_ext.h" ++#include "stdarg_ext.h" ++#include "sprint_ext.h" ++#include "std_ext.h" ++#include "xx_ext.h" ++ ++ ++int Sprint(char * buf, const char *fmt, ...) ++{ ++ va_list args; ++ int i; ++ ++ va_start(args, fmt); ++ i=vsprintf(buf,fmt,args); ++ va_end(args); ++ return i; ++} ++ ++int Snprint(char * buf, uint32_t size, const char *fmt, ...) ++{ ++ va_list args; ++ int i; ++ ++ va_start(args, fmt); ++ i=vsnprintf(buf,size,fmt,args); ++ va_end(args); ++ return i; ++} ++ ++#ifndef NCSW_VXWORKS ++int Sscan(const char * buf, const char * fmt, ...) ++{ ++ va_list args; ++ int i; ++ ++ va_start(args,fmt); ++ i = vsscanf(buf,fmt,args); ++ va_end(args); ++ return i; ++} ++#endif /* NCSW_VXWORKS */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/fmanv3h_dflags.h b/drivers/net/ethernet/freescale/sdk_fman/fmanv3h_dflags.h +new file mode 100644 +index 00000000..435b0d2b +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/fmanv3h_dflags.h +@@ -0,0 +1,57 @@ ++/* ++ * Copyright 2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __dflags_h ++#define __dflags_h ++ ++ ++#define NCSW_LINUX ++ ++#define T4240 ++#define NCSW_PPC_CORE ++ ++#define DEBUG_ERRORS 1 ++ ++#if defined(DEBUG) ++#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_INFO ++ ++#define DEBUG_XX_MALLOC ++#define DEBUG_MEM_LEAKS ++ ++#else ++#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_WARNING ++#endif /* (DEBUG) */ ++ ++#define REPORT_EVENTS 1 ++#define EVENT_GLOBAL_LEVEL REPORT_LEVEL_MINOR ++ ++#endif /* __dflags_h */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/fmanv3l_dflags.h b/drivers/net/ethernet/freescale/sdk_fman/fmanv3l_dflags.h +new file mode 100644 +index 00000000..789eb879 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/fmanv3l_dflags.h +@@ -0,0 +1,56 @@ ++/* ++ * Copyright 2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __dflags_h ++#define __dflags_h ++ ++ ++#define NCSW_LINUX ++ ++#define NCSW_PPC_CORE ++ ++#define DEBUG_ERRORS 1 ++ ++#if defined(DEBUG) ++#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_INFO ++ ++#define DEBUG_XX_MALLOC ++#define DEBUG_MEM_LEAKS ++ ++#else ++#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_WARNING ++#endif /* (DEBUG) */ ++ ++#define REPORT_EVENTS 1 ++#define EVENT_GLOBAL_LEVEL REPORT_LEVEL_MINOR ++ ++#endif /* __dflags_h */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/crc_mac_addr_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/crc_mac_addr_ext.h +new file mode 100644 +index 00000000..a84d5631 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/crc_mac_addr_ext.h +@@ -0,0 +1,364 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/*------------------------------------------------------*/ ++/* */ ++/* File: crc_mac_addr_ext.h */ ++/* */ ++/* Description: */ ++/* Define a macro that calculate the crc value of */ ++/* an Ethernet MAC address (48 bitd address */ ++/*------------------------------------------------------*/ ++ ++#ifndef __crc_mac_addr_ext_h ++#define __crc_mac_addr_ext_h ++ ++#include "std_ext.h" ++ ++ ++static uint32_t crc_table[256] = ++{ ++ 0x00000000, ++ 0x77073096, ++ 0xee0e612c, ++ 0x990951ba, ++ 0x076dc419, ++ 0x706af48f, ++ 0xe963a535, ++ 0x9e6495a3, ++ 0x0edb8832, ++ 0x79dcb8a4, ++ 0xe0d5e91e, ++ 0x97d2d988, ++ 0x09b64c2b, ++ 0x7eb17cbd, ++ 0xe7b82d07, ++ 0x90bf1d91, ++ 0x1db71064, ++ 0x6ab020f2, ++ 0xf3b97148, ++ 0x84be41de, ++ 0x1adad47d, ++ 0x6ddde4eb, ++ 0xf4d4b551, ++ 0x83d385c7, ++ 0x136c9856, ++ 0x646ba8c0, ++ 0xfd62f97a, ++ 0x8a65c9ec, ++ 0x14015c4f, ++ 0x63066cd9, ++ 0xfa0f3d63, ++ 0x8d080df5, ++ 0x3b6e20c8, ++ 0x4c69105e, ++ 0xd56041e4, ++ 0xa2677172, ++ 0x3c03e4d1, ++ 0x4b04d447, ++ 0xd20d85fd, ++ 0xa50ab56b, ++ 0x35b5a8fa, ++ 0x42b2986c, ++ 0xdbbbc9d6, ++ 0xacbcf940, ++ 0x32d86ce3, ++ 0x45df5c75, ++ 0xdcd60dcf, ++ 0xabd13d59, ++ 0x26d930ac, ++ 0x51de003a, ++ 0xc8d75180, ++ 0xbfd06116, ++ 0x21b4f4b5, ++ 0x56b3c423, ++ 0xcfba9599, ++ 0xb8bda50f, ++ 0x2802b89e, ++ 0x5f058808, ++ 0xc60cd9b2, ++ 0xb10be924, ++ 0x2f6f7c87, ++ 0x58684c11, ++ 0xc1611dab, ++ 0xb6662d3d, ++ 0x76dc4190, ++ 0x01db7106, ++ 0x98d220bc, ++ 0xefd5102a, ++ 0x71b18589, ++ 0x06b6b51f, ++ 0x9fbfe4a5, ++ 0xe8b8d433, ++ 0x7807c9a2, ++ 0x0f00f934, ++ 0x9609a88e, ++ 0xe10e9818, ++ 0x7f6a0dbb, ++ 0x086d3d2d, ++ 0x91646c97, ++ 0xe6635c01, ++ 0x6b6b51f4, ++ 0x1c6c6162, ++ 0x856530d8, ++ 0xf262004e, ++ 0x6c0695ed, ++ 0x1b01a57b, ++ 0x8208f4c1, ++ 0xf50fc457, ++ 0x65b0d9c6, ++ 0x12b7e950, ++ 0x8bbeb8ea, ++ 0xfcb9887c, ++ 0x62dd1ddf, ++ 0x15da2d49, ++ 0x8cd37cf3, ++ 0xfbd44c65, ++ 0x4db26158, ++ 0x3ab551ce, ++ 0xa3bc0074, ++ 0xd4bb30e2, ++ 0x4adfa541, ++ 0x3dd895d7, ++ 0xa4d1c46d, ++ 0xd3d6f4fb, ++ 0x4369e96a, ++ 0x346ed9fc, ++ 0xad678846, ++ 0xda60b8d0, ++ 0x44042d73, ++ 0x33031de5, ++ 0xaa0a4c5f, ++ 0xdd0d7cc9, ++ 0x5005713c, ++ 0x270241aa, ++ 0xbe0b1010, ++ 0xc90c2086, ++ 0x5768b525, ++ 0x206f85b3, ++ 0xb966d409, ++ 0xce61e49f, ++ 0x5edef90e, ++ 0x29d9c998, ++ 0xb0d09822, ++ 0xc7d7a8b4, ++ 0x59b33d17, ++ 0x2eb40d81, ++ 0xb7bd5c3b, ++ 0xc0ba6cad, ++ 0xedb88320, ++ 0x9abfb3b6, ++ 0x03b6e20c, ++ 0x74b1d29a, ++ 0xead54739, ++ 0x9dd277af, ++ 0x04db2615, ++ 0x73dc1683, ++ 0xe3630b12, ++ 0x94643b84, ++ 0x0d6d6a3e, ++ 0x7a6a5aa8, ++ 0xe40ecf0b, ++ 0x9309ff9d, ++ 0x0a00ae27, ++ 0x7d079eb1, ++ 0xf00f9344, ++ 0x8708a3d2, ++ 0x1e01f268, ++ 0x6906c2fe, ++ 0xf762575d, ++ 0x806567cb, ++ 0x196c3671, ++ 0x6e6b06e7, ++ 0xfed41b76, ++ 0x89d32be0, ++ 0x10da7a5a, ++ 0x67dd4acc, ++ 0xf9b9df6f, ++ 0x8ebeeff9, ++ 0x17b7be43, ++ 0x60b08ed5, ++ 0xd6d6a3e8, ++ 0xa1d1937e, ++ 0x38d8c2c4, ++ 0x4fdff252, ++ 0xd1bb67f1, ++ 0xa6bc5767, ++ 0x3fb506dd, ++ 0x48b2364b, ++ 0xd80d2bda, ++ 0xaf0a1b4c, ++ 0x36034af6, ++ 0x41047a60, ++ 0xdf60efc3, ++ 0xa867df55, ++ 0x316e8eef, ++ 0x4669be79, ++ 0xcb61b38c, ++ 0xbc66831a, ++ 0x256fd2a0, ++ 0x5268e236, ++ 0xcc0c7795, ++ 0xbb0b4703, ++ 0x220216b9, ++ 0x5505262f, ++ 0xc5ba3bbe, ++ 0xb2bd0b28, ++ 0x2bb45a92, ++ 0x5cb36a04, ++ 0xc2d7ffa7, ++ 0xb5d0cf31, ++ 0x2cd99e8b, ++ 0x5bdeae1d, ++ 0x9b64c2b0, ++ 0xec63f226, ++ 0x756aa39c, ++ 0x026d930a, ++ 0x9c0906a9, ++ 0xeb0e363f, ++ 0x72076785, ++ 0x05005713, ++ 0x95bf4a82, ++ 0xe2b87a14, ++ 0x7bb12bae, ++ 0x0cb61b38, ++ 0x92d28e9b, ++ 0xe5d5be0d, ++ 0x7cdcefb7, ++ 0x0bdbdf21, ++ 0x86d3d2d4, ++ 0xf1d4e242, ++ 0x68ddb3f8, ++ 0x1fda836e, ++ 0x81be16cd, ++ 0xf6b9265b, ++ 0x6fb077e1, ++ 0x18b74777, ++ 0x88085ae6, ++ 0xff0f6a70, ++ 0x66063bca, ++ 0x11010b5c, ++ 0x8f659eff, ++ 0xf862ae69, ++ 0x616bffd3, ++ 0x166ccf45, ++ 0xa00ae278, ++ 0xd70dd2ee, ++ 0x4e048354, ++ 0x3903b3c2, ++ 0xa7672661, ++ 0xd06016f7, ++ 0x4969474d, ++ 0x3e6e77db, ++ 0xaed16a4a, ++ 0xd9d65adc, ++ 0x40df0b66, ++ 0x37d83bf0, ++ 0xa9bcae53, ++ 0xdebb9ec5, ++ 0x47b2cf7f, ++ 0x30b5ffe9, ++ 0xbdbdf21c, ++ 0xcabac28a, ++ 0x53b39330, ++ 0x24b4a3a6, ++ 0xbad03605, ++ 0xcdd70693, ++ 0x54de5729, ++ 0x23d967bf, ++ 0xb3667a2e, ++ 0xc4614ab8, ++ 0x5d681b02, ++ 0x2a6f2b94, ++ 0xb40bbe37, ++ 0xc30c8ea1, ++ 0x5a05df1b, ++ 0x2d02ef8d ++}; ++ ++ ++#define GET_MAC_ADDR_CRC(addr, crc) \ ++{ \ ++ uint32_t i; \ ++ uint8_t data; \ ++ \ ++ /* CRC calculation */ \ ++ crc = 0xffffffff; \ ++ for (i=0; i < 6; i++) \ ++ { \ ++ data = (uint8_t)(addr >> ((5-i)*8)); \ ++ crc = crc^data; \ ++ crc = crc_table[crc&0xff] ^ (crc>>8); \ ++ } \ ++} \ ++ ++/* Define a macro for getting the mirrored value of */ ++/* a byte size number. (0x11010011 --> 0x11001011) */ ++/* Sometimes the mirrored value of the CRC is required */ ++static __inline__ uint8_t GetMirror(uint8_t n) ++{ ++ uint8_t mirror[16] = ++ { ++ 0x00, ++ 0x08, ++ 0x04, ++ 0x0c, ++ 0x02, ++ 0x0a, ++ 0x06, ++ 0x0e, ++ 0x01, ++ 0x09, ++ 0x05, ++ 0x0d, ++ 0x03, ++ 0x0b, ++ 0x07, ++ 0x0f ++ }; ++ return ((uint8_t)(((mirror[n & 0x0f] << 4) | (mirror[n >> 4])))); ++} ++ ++static __inline__ uint32_t GetMirror32(uint32_t n) ++{ ++ return (((uint32_t)GetMirror((uint8_t)(n))<<24) | ++ ((uint32_t)GetMirror((uint8_t)(n>>8))<<16) | ++ ((uint32_t)GetMirror((uint8_t)(n>>16))<<8) | ++ ((uint32_t)GetMirror((uint8_t)(n>>24)))); ++} ++ ++#define MIRROR GetMirror ++#define MIRROR_32 GetMirror32 ++ ++ ++#endif /* __crc_mac_addr_ext_h */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/dpaa_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/dpaa_ext.h +new file mode 100644 +index 00000000..e6d9e932 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/dpaa_ext.h +@@ -0,0 +1,210 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File dpaa_ext.h ++ ++ @Description DPAA Application Programming Interface. ++*//***************************************************************************/ ++#ifndef __DPAA_EXT_H ++#define __DPAA_EXT_H ++ ++#include "std_ext.h" ++#include "error_ext.h" ++ ++ ++/**************************************************************************//** ++ @Group DPAA_grp Data Path Acceleration Architecture API ++ ++ @Description DPAA API functions, definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(push,1) ++#endif /* defined(__MWERKS__) && ... */ ++ ++/**************************************************************************//** ++ @Description Frame descriptor ++*//***************************************************************************/ ++typedef _Packed struct t_DpaaFD { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ volatile uint8_t liodn; ++ volatile uint8_t bpid; ++ volatile uint8_t elion; ++ volatile uint8_t addrh; ++ volatile uint32_t addrl; ++#else ++ volatile uint32_t addrl; ++ volatile uint8_t addrh; ++ volatile uint8_t elion; ++ volatile uint8_t bpid; ++ volatile uint8_t liodn; ++ #endif ++ volatile uint32_t length; /**< Frame length */ ++ volatile uint32_t status; /**< FD status */ ++} _PackedType t_DpaaFD; ++ ++/**************************************************************************//** ++ @Description enum for defining frame format ++*//***************************************************************************/ ++typedef enum e_DpaaFDFormatType { ++ e_DPAA_FD_FORMAT_TYPE_SHORT_SBSF = 0x0, /**< Simple frame Single buffer; Offset and ++ small length (9b OFFSET, 20b LENGTH) */ ++ e_DPAA_FD_FORMAT_TYPE_LONG_SBSF = 0x2, /**< Simple frame, single buffer; big length ++ (29b LENGTH ,No OFFSET) */ ++ e_DPAA_FD_FORMAT_TYPE_SHORT_MBSF = 0x4, /**< Simple frame, Scatter Gather table; Offset ++ and small length (9b OFFSET, 20b LENGTH) */ ++ e_DPAA_FD_FORMAT_TYPE_LONG_MBSF = 0x6, /**< Simple frame, Scatter Gather table; ++ big length (29b LENGTH ,No OFFSET) */ ++ e_DPAA_FD_FORMAT_TYPE_COMPOUND = 0x1, /**< Compound Frame (29b CONGESTION-WEIGHT ++ No LENGTH or OFFSET) */ ++ e_DPAA_FD_FORMAT_TYPE_DUMMY ++} e_DpaaFDFormatType; ++ ++/**************************************************************************//** ++ @Collection Frame descriptor macros ++*//***************************************************************************/ ++#define DPAA_FD_DD_MASK 0xc0000000 /**< FD DD field mask */ ++#define DPAA_FD_PID_MASK 0x3f000000 /**< FD PID field mask */ ++#define DPAA_FD_ELIODN_MASK 0x0000f000 /**< FD ELIODN field mask */ ++#define DPAA_FD_BPID_MASK 0x00ff0000 /**< FD BPID field mask */ ++#define DPAA_FD_ADDRH_MASK 0x000000ff /**< FD ADDRH field mask */ ++#define DPAA_FD_ADDRL_MASK 0xffffffff /**< FD ADDRL field mask */ ++#define DPAA_FD_FORMAT_MASK 0xe0000000 /**< FD FORMAT field mask */ ++#define DPAA_FD_OFFSET_MASK 0x1ff00000 /**< FD OFFSET field mask */ ++#define DPAA_FD_LENGTH_MASK 0x000fffff /**< FD LENGTH field mask */ ++ ++#define DPAA_FD_GET_ADDRH(fd) ((t_DpaaFD *)fd)->addrh /**< Macro to get FD ADDRH field */ ++#define DPAA_FD_GET_ADDRL(fd) ((t_DpaaFD *)fd)->addrl /**< Macro to get FD ADDRL field */ ++#define DPAA_FD_GET_PHYS_ADDR(fd) ((physAddress_t)(((uint64_t)DPAA_FD_GET_ADDRH(fd) << 32) | (uint64_t)DPAA_FD_GET_ADDRL(fd))) /**< Macro to get FD ADDR field */ ++#define DPAA_FD_GET_FORMAT(fd) ((((t_DpaaFD *)fd)->length & DPAA_FD_FORMAT_MASK) >> (31-2)) /**< Macro to get FD FORMAT field */ ++#define DPAA_FD_GET_OFFSET(fd) ((((t_DpaaFD *)fd)->length & DPAA_FD_OFFSET_MASK) >> (31-11)) /**< Macro to get FD OFFSET field */ ++#define DPAA_FD_GET_LENGTH(fd) (((t_DpaaFD *)fd)->length & DPAA_FD_LENGTH_MASK) /**< Macro to get FD LENGTH field */ ++#define DPAA_FD_GET_STATUS(fd) ((t_DpaaFD *)fd)->status /**< Macro to get FD STATUS field */ ++#define DPAA_FD_GET_ADDR(fd) XX_PhysToVirt(DPAA_FD_GET_PHYS_ADDR(fd)) /**< Macro to get FD ADDR (virtual) */ ++ ++#define DPAA_FD_SET_ADDRH(fd,val) ((t_DpaaFD *)fd)->addrh = (val) /**< Macro to set FD ADDRH field */ ++#define DPAA_FD_SET_ADDRL(fd,val) ((t_DpaaFD *)fd)->addrl = (val) /**< Macro to set FD ADDRL field */ ++#define DPAA_FD_SET_ADDR(fd,val) \ ++do { \ ++ uint64_t physAddr = (uint64_t)(XX_VirtToPhys(val)); \ ++ DPAA_FD_SET_ADDRH(fd, ((uint32_t)(physAddr >> 32))); \ ++ DPAA_FD_SET_ADDRL(fd, (uint32_t)physAddr); \ ++} while (0) /**< Macro to set FD ADDR field */ ++#define DPAA_FD_SET_FORMAT(fd,val) (((t_DpaaFD *)fd)->length = ((((t_DpaaFD *)fd)->length & ~DPAA_FD_FORMAT_MASK) | (((val) << (31-2))& DPAA_FD_FORMAT_MASK))) /**< Macro to set FD FORMAT field */ ++#define DPAA_FD_SET_OFFSET(fd,val) (((t_DpaaFD *)fd)->length = ((((t_DpaaFD *)fd)->length & ~DPAA_FD_OFFSET_MASK) | (((val) << (31-11))& DPAA_FD_OFFSET_MASK) )) /**< Macro to set FD OFFSET field */ ++#define DPAA_FD_SET_LENGTH(fd,val) (((t_DpaaFD *)fd)->length = (((t_DpaaFD *)fd)->length & ~DPAA_FD_LENGTH_MASK) | ((val) & DPAA_FD_LENGTH_MASK)) /**< Macro to set FD LENGTH field */ ++#define DPAA_FD_SET_STATUS(fd,val) ((t_DpaaFD *)fd)->status = (val) /**< Macro to set FD STATUS field */ ++/* @} */ ++ ++/**************************************************************************//** ++ @Description Frame Scatter/Gather Table Entry ++*//***************************************************************************/ ++typedef _Packed struct t_DpaaSGTE { ++ volatile uint32_t addrh; /**< Buffer Address high */ ++ volatile uint32_t addrl; /**< Buffer Address low */ ++ volatile uint32_t length; /**< Buffer length */ ++ volatile uint32_t offset; /**< SGTE offset */ ++} _PackedType t_DpaaSGTE; ++ ++#define DPAA_NUM_OF_SG_TABLE_ENTRY 16 ++ ++/**************************************************************************//** ++ @Description Frame Scatter/Gather Table ++*//***************************************************************************/ ++typedef _Packed struct t_DpaaSGT { ++ t_DpaaSGTE tableEntry[DPAA_NUM_OF_SG_TABLE_ENTRY]; ++ /**< Structure that holds information about ++ a single S/G entry. */ ++} _PackedType t_DpaaSGT; ++ ++/**************************************************************************//** ++ @Description Compound Frame Table ++*//***************************************************************************/ ++typedef _Packed struct t_DpaaCompTbl { ++ t_DpaaSGTE outputBuffInfo; /**< Structure that holds information about ++ the compound-frame output buffer; ++ NOTE: this may point to a S/G table */ ++ t_DpaaSGTE inputBuffInfo; /**< Structure that holds information about ++ the compound-frame input buffer; ++ NOTE: this may point to a S/G table */ ++} _PackedType t_DpaaCompTbl; ++ ++/**************************************************************************//** ++ @Collection Frame Scatter/Gather Table Entry macros ++*//***************************************************************************/ ++#define DPAA_SGTE_ADDRH_MASK 0x000000ff /**< SGTE ADDRH field mask */ ++#define DPAA_SGTE_ADDRL_MASK 0xffffffff /**< SGTE ADDRL field mask */ ++#define DPAA_SGTE_E_MASK 0x80000000 /**< SGTE Extension field mask */ ++#define DPAA_SGTE_F_MASK 0x40000000 /**< SGTE Final field mask */ ++#define DPAA_SGTE_LENGTH_MASK 0x3fffffff /**< SGTE LENGTH field mask */ ++#define DPAA_SGTE_BPID_MASK 0x00ff0000 /**< SGTE BPID field mask */ ++#define DPAA_SGTE_OFFSET_MASK 0x00001fff /**< SGTE OFFSET field mask */ ++ ++#define DPAA_SGTE_GET_ADDRH(sgte) (((t_DpaaSGTE *)sgte)->addrh & DPAA_SGTE_ADDRH_MASK) /**< Macro to get SGTE ADDRH field */ ++#define DPAA_SGTE_GET_ADDRL(sgte) ((t_DpaaSGTE *)sgte)->addrl /**< Macro to get SGTE ADDRL field */ ++#define DPAA_SGTE_GET_PHYS_ADDR(sgte) ((physAddress_t)(((uint64_t)DPAA_SGTE_GET_ADDRH(sgte) << 32) | (uint64_t)DPAA_SGTE_GET_ADDRL(sgte))) /**< Macro to get FD ADDR field */ ++#define DPAA_SGTE_GET_EXTENSION(sgte) ((((t_DpaaSGTE *)sgte)->length & DPAA_SGTE_E_MASK) >> (31-0)) /**< Macro to get SGTE EXTENSION field */ ++#define DPAA_SGTE_GET_FINAL(sgte) ((((t_DpaaSGTE *)sgte)->length & DPAA_SGTE_F_MASK) >> (31-1)) /**< Macro to get SGTE FINAL field */ ++#define DPAA_SGTE_GET_LENGTH(sgte) (((t_DpaaSGTE *)sgte)->length & DPAA_SGTE_LENGTH_MASK) /**< Macro to get SGTE LENGTH field */ ++#define DPAA_SGTE_GET_BPID(sgte) ((((t_DpaaSGTE *)sgte)->offset & DPAA_SGTE_BPID_MASK) >> (31-15)) /**< Macro to get SGTE BPID field */ ++#define DPAA_SGTE_GET_OFFSET(sgte) (((t_DpaaSGTE *)sgte)->offset & DPAA_SGTE_OFFSET_MASK) /**< Macro to get SGTE OFFSET field */ ++#define DPAA_SGTE_GET_ADDR(sgte) XX_PhysToVirt(DPAA_SGTE_GET_PHYS_ADDR(sgte)) ++ ++#define DPAA_SGTE_SET_ADDRH(sgte,val) (((t_DpaaSGTE *)sgte)->addrh = ((((t_DpaaSGTE *)sgte)->addrh & ~DPAA_SGTE_ADDRH_MASK) | ((val) & DPAA_SGTE_ADDRH_MASK))) /**< Macro to set SGTE ADDRH field */ ++#define DPAA_SGTE_SET_ADDRL(sgte,val) ((t_DpaaSGTE *)sgte)->addrl = (val) /**< Macro to set SGTE ADDRL field */ ++#define DPAA_SGTE_SET_ADDR(sgte,val) \ ++do { \ ++ uint64_t physAddr = (uint64_t)(XX_VirtToPhys(val)); \ ++ DPAA_SGTE_SET_ADDRH(sgte, ((uint32_t)(physAddr >> 32))); \ ++ DPAA_SGTE_SET_ADDRL(sgte, (uint32_t)physAddr); \ ++} while (0) /**< Macro to set SGTE ADDR field */ ++#define DPAA_SGTE_SET_EXTENSION(sgte,val) (((t_DpaaSGTE *)sgte)->length = ((((t_DpaaSGTE *)sgte)->length & ~DPAA_SGTE_E_MASK) | (((val) << (31-0))& DPAA_SGTE_E_MASK))) /**< Macro to set SGTE EXTENSION field */ ++#define DPAA_SGTE_SET_FINAL(sgte,val) (((t_DpaaSGTE *)sgte)->length = ((((t_DpaaSGTE *)sgte)->length & ~DPAA_SGTE_F_MASK) | (((val) << (31-1))& DPAA_SGTE_F_MASK))) /**< Macro to set SGTE FINAL field */ ++#define DPAA_SGTE_SET_LENGTH(sgte,val) (((t_DpaaSGTE *)sgte)->length = (((t_DpaaSGTE *)sgte)->length & ~DPAA_SGTE_LENGTH_MASK) | ((val) & DPAA_SGTE_LENGTH_MASK)) /**< Macro to set SGTE LENGTH field */ ++#define DPAA_SGTE_SET_BPID(sgte,val) (((t_DpaaSGTE *)sgte)->offset = ((((t_DpaaSGTE *)sgte)->offset & ~DPAA_SGTE_BPID_MASK) | (((val) << (31-15))& DPAA_SGTE_BPID_MASK))) /**< Macro to set SGTE BPID field */ ++#define DPAA_SGTE_SET_OFFSET(sgte,val) (((t_DpaaSGTE *)sgte)->offset = ((((t_DpaaSGTE *)sgte)->offset & ~DPAA_SGTE_OFFSET_MASK) | (((val) << (31-31))& DPAA_SGTE_OFFSET_MASK) )) /**< Macro to set SGTE OFFSET field */ ++/* @} */ ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(pop) ++#endif /* defined(__MWERKS__) && ... */ ++ ++#define DPAA_LIODN_DONT_OVERRIDE (-1) ++ ++/** @} */ /* end of DPAA_grp group */ ++ ++ ++#endif /* __DPAA_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_ext.h +new file mode 100644 +index 00000000..a8a64386 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_ext.h +@@ -0,0 +1,1731 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File fm_ext.h ++ ++ @Description FM Application Programming Interface. ++*//***************************************************************************/ ++#ifndef __FM_EXT ++#define __FM_EXT ++ ++#include "error_ext.h" ++#include "std_ext.h" ++#include "dpaa_ext.h" ++#include "fsl_fman_sp.h" ++ ++/**************************************************************************//** ++ @Group FM_grp Frame Manager API ++ ++ @Description FM API functions, definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group FM_lib_grp FM library ++ ++ @Description FM API functions, definitions and enums. ++ ++ The FM module is the main driver module and is a mandatory module ++ for FM driver users. This module must be initialized first prior ++ to any other drivers modules. ++ The FM is a "singleton" module. It is responsible of the common ++ HW modules: FPM, DMA, common QMI and common BMI initializations and ++ run-time control routines. This module must be initialized always ++ when working with any of the FM modules. ++ NOTE - We assume that the FM library will be initialized only by core No. 0! ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description Enum for defining port types ++*//***************************************************************************/ ++typedef enum e_FmPortType { ++ e_FM_PORT_TYPE_OH_OFFLINE_PARSING = 0, /**< Offline parsing port */ ++ e_FM_PORT_TYPE_RX, /**< 1G Rx port */ ++ e_FM_PORT_TYPE_RX_10G, /**< 10G Rx port */ ++ e_FM_PORT_TYPE_TX, /**< 1G Tx port */ ++ e_FM_PORT_TYPE_TX_10G, /**< 10G Tx port */ ++ e_FM_PORT_TYPE_DUMMY ++} e_FmPortType; ++ ++/**************************************************************************//** ++ @Collection General FM defines ++*//***************************************************************************/ ++#define FM_MAX_NUM_OF_PARTITIONS 64 /**< Maximum number of partitions */ ++#define FM_PHYS_ADDRESS_SIZE 6 /**< FM Physical address size */ ++/* @} */ ++ ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(push,1) ++#endif /* defined(__MWERKS__) && ... */ ++ ++/**************************************************************************//** ++ @Description FM physical Address ++*//***************************************************************************/ ++typedef _Packed struct t_FmPhysAddr { ++ volatile uint8_t high; /**< High part of the physical address */ ++ volatile uint32_t low; /**< Low part of the physical address */ ++} _PackedType t_FmPhysAddr; ++ ++/**************************************************************************//** ++ @Description Parse results memory layout ++*//***************************************************************************/ ++typedef _Packed struct t_FmPrsResult { ++ volatile uint8_t lpid; /**< Logical port id */ ++ volatile uint8_t shimr; /**< Shim header result */ ++ volatile uint16_t l2r; /**< Layer 2 result */ ++ volatile uint16_t l3r; /**< Layer 3 result */ ++ volatile uint8_t l4r; /**< Layer 4 result */ ++ volatile uint8_t cplan; /**< Classification plan id */ ++ volatile uint16_t nxthdr; /**< Next Header */ ++ volatile uint16_t cksum; /**< Running-sum */ ++ volatile uint16_t flags_frag_off; /**< Flags & fragment-offset field of the last IP-header */ ++ volatile uint8_t route_type; /**< Routing type field of a IPv6 routing extension header */ ++ volatile uint8_t rhp_ip_valid; /**< Routing Extension Header Present; last bit is IP valid */ ++ volatile uint8_t shim_off[2]; /**< Shim offset */ ++ volatile uint8_t ip_pid_off; /**< IP PID (last IP-proto) offset */ ++ volatile uint8_t eth_off; /**< ETH offset */ ++ volatile uint8_t llc_snap_off; /**< LLC_SNAP offset */ ++ volatile uint8_t vlan_off[2]; /**< VLAN offset */ ++ volatile uint8_t etype_off; /**< ETYPE offset */ ++ volatile uint8_t pppoe_off; /**< PPP offset */ ++ volatile uint8_t mpls_off[2]; /**< MPLS offset */ ++ volatile uint8_t ip_off[2]; /**< IP offset */ ++ volatile uint8_t gre_off; /**< GRE offset */ ++ volatile uint8_t l4_off; /**< Layer 4 offset */ ++ volatile uint8_t nxthdr_off; /**< Parser end point */ ++} _PackedType t_FmPrsResult; ++ ++/**************************************************************************//** ++ @Collection FM Parser results ++*//***************************************************************************/ ++#define FM_PR_L2_VLAN_STACK 0x00000100 /**< Parse Result: VLAN stack */ ++#define FM_PR_L2_ETHERNET 0x00008000 /**< Parse Result: Ethernet*/ ++#define FM_PR_L2_VLAN 0x00004000 /**< Parse Result: VLAN */ ++#define FM_PR_L2_LLC_SNAP 0x00002000 /**< Parse Result: LLC_SNAP */ ++#define FM_PR_L2_MPLS 0x00001000 /**< Parse Result: MPLS */ ++#define FM_PR_L2_PPPoE 0x00000800 /**< Parse Result: PPPoE */ ++/* @} */ ++ ++/**************************************************************************//** ++ @Collection FM Frame descriptor macros ++*//***************************************************************************/ ++#define FM_FD_CMD_FCO 0x80000000 /**< Frame queue Context Override */ ++#define FM_FD_CMD_RPD 0x40000000 /**< Read Prepended Data */ ++#define FM_FD_CMD_UPD 0x20000000 /**< Update Prepended Data */ ++#define FM_FD_CMD_DTC 0x10000000 /**< Do L4 Checksum */ ++#define FM_FD_CMD_DCL4C 0x10000000 /**< Didn't calculate L4 Checksum */ ++#define FM_FD_CMD_CFQ 0x00ffffff /**< Confirmation Frame Queue */ ++ ++#define FM_FD_ERR_UNSUPPORTED_FORMAT 0x04000000 /**< Not for Rx-Port! Unsupported Format */ ++#define FM_FD_ERR_LENGTH 0x02000000 /**< Not for Rx-Port! Length Error */ ++#define FM_FD_ERR_DMA 0x01000000 /**< DMA Data error */ ++ ++#define FM_FD_IPR 0x00000001 /**< IPR frame (not error) */ ++ ++#define FM_FD_ERR_IPR_NCSP (0x00100000 | FM_FD_IPR) /**< IPR non-consistent-sp */ ++#define FM_FD_ERR_IPR (0x00200000 | FM_FD_IPR) /**< IPR error */ ++#define FM_FD_ERR_IPR_TO (0x00300000 | FM_FD_IPR) /**< IPR timeout */ ++ ++#ifdef FM_CAPWAP_SUPPORT ++#define FM_FD_ERR_CRE 0x00200000 ++#define FM_FD_ERR_CHE 0x00100000 ++#endif /* FM_CAPWAP_SUPPORT */ ++ ++#define FM_FD_ERR_PHYSICAL 0x00080000 /**< Rx FIFO overflow, FCS error, code error, running disparity ++ error (SGMII and TBI modes), FIFO parity error. PHY ++ Sequence error, PHY error control character detected. */ ++#define FM_FD_ERR_SIZE 0x00040000 /**< Frame too long OR Frame size exceeds max_length_frame */ ++#define FM_FD_ERR_CLS_DISCARD 0x00020000 /**< classification discard */ ++#define FM_FD_ERR_EXTRACTION 0x00008000 /**< Extract Out of Frame */ ++#define FM_FD_ERR_NO_SCHEME 0x00004000 /**< No Scheme Selected */ ++#define FM_FD_ERR_KEYSIZE_OVERFLOW 0x00002000 /**< Keysize Overflow */ ++#define FM_FD_ERR_COLOR_RED 0x00000800 /**< Frame color is red */ ++#define FM_FD_ERR_COLOR_YELLOW 0x00000400 /**< Frame color is yellow */ ++#define FM_FD_ERR_ILL_PLCR 0x00000200 /**< Illegal Policer Profile selected */ ++#define FM_FD_ERR_PLCR_FRAME_LEN 0x00000100 /**< Policer frame length error */ ++#define FM_FD_ERR_PRS_TIMEOUT 0x00000080 /**< Parser Time out Exceed */ ++#define FM_FD_ERR_PRS_ILL_INSTRUCT 0x00000040 /**< Invalid Soft Parser instruction */ ++#define FM_FD_ERR_PRS_HDR_ERR 0x00000020 /**< Header error was identified during parsing */ ++#define FM_FD_ERR_BLOCK_LIMIT_EXCEEDED 0x00000008 /**< Frame parsed beyind 256 first bytes */ ++ ++#define FM_FD_TX_STATUS_ERR_MASK (FM_FD_ERR_UNSUPPORTED_FORMAT | \ ++ FM_FD_ERR_LENGTH | \ ++ FM_FD_ERR_DMA) /**< TX Error FD bits */ ++ ++#define FM_FD_RX_STATUS_ERR_MASK (FM_FD_ERR_UNSUPPORTED_FORMAT | \ ++ FM_FD_ERR_LENGTH | \ ++ FM_FD_ERR_DMA | \ ++ FM_FD_ERR_IPR | \ ++ FM_FD_ERR_IPR_TO | \ ++ FM_FD_ERR_IPR_NCSP | \ ++ FM_FD_ERR_PHYSICAL | \ ++ FM_FD_ERR_SIZE | \ ++ FM_FD_ERR_CLS_DISCARD | \ ++ FM_FD_ERR_COLOR_RED | \ ++ FM_FD_ERR_COLOR_YELLOW | \ ++ FM_FD_ERR_ILL_PLCR | \ ++ FM_FD_ERR_PLCR_FRAME_LEN | \ ++ FM_FD_ERR_EXTRACTION | \ ++ FM_FD_ERR_NO_SCHEME | \ ++ FM_FD_ERR_KEYSIZE_OVERFLOW | \ ++ FM_FD_ERR_PRS_TIMEOUT | \ ++ FM_FD_ERR_PRS_ILL_INSTRUCT | \ ++ FM_FD_ERR_PRS_HDR_ERR | \ ++ FM_FD_ERR_BLOCK_LIMIT_EXCEEDED) /**< RX Error FD bits */ ++ ++#define FM_FD_RX_STATUS_ERR_NON_FM 0x00400000 /**< non Frame-Manager error */ ++/* @} */ ++ ++/**************************************************************************//** ++ @Description Context A ++*//***************************************************************************/ ++typedef _Packed struct t_FmContextA { ++ volatile uint32_t command; /**< ContextA Command */ ++ volatile uint8_t res0[4]; /**< ContextA Reserved bits */ ++} _PackedType t_FmContextA; ++ ++/**************************************************************************//** ++ @Description Context B ++*//***************************************************************************/ ++typedef uint32_t t_FmContextB; ++ ++/**************************************************************************//** ++ @Collection Special Operation options ++*//***************************************************************************/ ++typedef uint32_t fmSpecialOperations_t; /**< typedef for defining Special Operation options */ ++ ++#define FM_SP_OP_IPSEC 0x80000000 /**< activate features that related to IPSec (e.g fix Eth-type) */ ++#define FM_SP_OP_IPSEC_UPDATE_UDP_LEN 0x40000000 /**< update the UDP-Len after Encryption */ ++#define FM_SP_OP_IPSEC_MANIP 0x20000000 /**< handle the IPSec-manip options */ ++#define FM_SP_OP_RPD 0x10000000 /**< Set the RPD bit */ ++#define FM_SP_OP_DCL4C 0x08000000 /**< Set the DCL4C bit */ ++#define FM_SP_OP_CHECK_SEC_ERRORS 0x04000000 /**< Check SEC errors */ ++#define FM_SP_OP_CLEAR_RPD 0x02000000 /**< Clear the RPD bit */ ++#define FM_SP_OP_CAPWAP_DTLS_ENC 0x01000000 /**< activate features that related to CAPWAP-DTLS post Encryption */ ++#define FM_SP_OP_CAPWAP_DTLS_DEC 0x00800000 /**< activate features that related to CAPWAP-DTLS post Decryption */ ++#define FM_SP_OP_IPSEC_NO_ETH_HDR 0x00400000 /**< activate features that related to IPSec without Eth hdr */ ++/* @} */ ++ ++/**************************************************************************//** ++ @Collection Context A macros ++*//***************************************************************************/ ++#define FM_CONTEXTA_OVERRIDE_MASK 0x80000000 ++#define FM_CONTEXTA_ICMD_MASK 0x40000000 ++#define FM_CONTEXTA_A1_VALID_MASK 0x20000000 ++#define FM_CONTEXTA_MACCMD_MASK 0x00ff0000 ++#define FM_CONTEXTA_MACCMD_VALID_MASK 0x00800000 ++#define FM_CONTEXTA_MACCMD_SECURED_MASK 0x00100000 ++#define FM_CONTEXTA_MACCMD_SC_MASK 0x000f0000 ++#define FM_CONTEXTA_A1_MASK 0x0000ffff ++ ++#define FM_CONTEXTA_GET_OVERRIDE(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_OVERRIDE_MASK) >> (31-0)) ++#define FM_CONTEXTA_GET_ICMD(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_ICMD_MASK) >> (31-1)) ++#define FM_CONTEXTA_GET_A1_VALID(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_A1_VALID_MASK) >> (31-2)) ++#define FM_CONTEXTA_GET_A1(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_A1_MASK) >> (31-31)) ++#define FM_CONTEXTA_GET_MACCMD(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_MACCMD_MASK) >> (31-15)) ++#define FM_CONTEXTA_GET_MACCMD_VALID(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_MACCMD_VALID_MASK) >> (31-8)) ++#define FM_CONTEXTA_GET_MACCMD_SECURED(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_MACCMD_SECURED_MASK) >> (31-11)) ++#define FM_CONTEXTA_GET_MACCMD_SECURE_CHANNEL(contextA) ((((t_FmContextA *)contextA)->command & FM_CONTEXTA_MACCMD_SC_MASK) >> (31-15)) ++ ++#define FM_CONTEXTA_SET_OVERRIDE(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_OVERRIDE_MASK) | (((uint32_t)(val) << (31-0)) & FM_CONTEXTA_OVERRIDE_MASK) )) ++#define FM_CONTEXTA_SET_ICMD(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_ICMD_MASK) | (((val) << (31-1)) & FM_CONTEXTA_ICMD_MASK) )) ++#define FM_CONTEXTA_SET_A1_VALID(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_A1_VALID_MASK) | (((val) << (31-2)) & FM_CONTEXTA_A1_VALID_MASK) )) ++#define FM_CONTEXTA_SET_A1(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_A1_MASK) | (((val) << (31-31)) & FM_CONTEXTA_A1_MASK) )) ++#define FM_CONTEXTA_SET_MACCMD(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_MACCMD_MASK) | (((val) << (31-15)) & FM_CONTEXTA_MACCMD_MASK) )) ++#define FM_CONTEXTA_SET_MACCMD_VALID(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_MACCMD_VALID_MASK) | (((val) << (31-8)) & FM_CONTEXTA_MACCMD_VALID_MASK) )) ++#define FM_CONTEXTA_SET_MACCMD_SECURED(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_MACCMD_SECURED_MASK) | (((val) << (31-11)) & FM_CONTEXTA_MACCMD_SECURED_MASK) )) ++#define FM_CONTEXTA_SET_MACCMD_SECURE_CHANNEL(contextA,val) (((t_FmContextA *)contextA)->command = (uint32_t)((((t_FmContextA *)contextA)->command & ~FM_CONTEXTA_MACCMD_SC_MASK) | (((val) << (31-15)) & FM_CONTEXTA_MACCMD_SC_MASK) )) ++/* @} */ ++ ++/**************************************************************************//** ++ @Collection Context B macros ++*//***************************************************************************/ ++#define FM_CONTEXTB_FQID_MASK 0x00ffffff ++ ++#define FM_CONTEXTB_GET_FQID(contextB) (*((t_FmContextB *)contextB) & FM_CONTEXTB_FQID_MASK) ++#define FM_CONTEXTB_SET_FQID(contextB,val) (*((t_FmContextB *)contextB) = ((*((t_FmContextB *)contextB) & ~FM_CONTEXTB_FQID_MASK) | ((val) & FM_CONTEXTB_FQID_MASK))) ++/* @} */ ++ ++#if defined(__MWERKS__) && !defined(__GNUC__) ++#pragma pack(pop) ++#endif /* defined(__MWERKS__) && ... */ ++ ++ ++/**************************************************************************//** ++ @Description FM Exceptions ++*//***************************************************************************/ ++typedef enum e_FmExceptions { ++ e_FM_EX_DMA_BUS_ERROR = 0, /**< DMA bus error. */ ++ e_FM_EX_DMA_READ_ECC, /**< Read Buffer ECC error (Valid for FM rev < 6)*/ ++ e_FM_EX_DMA_SYSTEM_WRITE_ECC, /**< Write Buffer ECC error on system side (Valid for FM rev < 6)*/ ++ e_FM_EX_DMA_FM_WRITE_ECC, /**< Write Buffer ECC error on FM side (Valid for FM rev < 6)*/ ++ e_FM_EX_DMA_SINGLE_PORT_ECC, /**< Single Port ECC error on FM side (Valid for FM rev > 6)*/ ++ e_FM_EX_FPM_STALL_ON_TASKS, /**< Stall of tasks on FPM */ ++ e_FM_EX_FPM_SINGLE_ECC, /**< Single ECC on FPM. */ ++ e_FM_EX_FPM_DOUBLE_ECC, /**< Double ECC error on FPM ram access */ ++ e_FM_EX_QMI_SINGLE_ECC, /**< Single ECC on QMI. */ ++ e_FM_EX_QMI_DOUBLE_ECC, /**< Double bit ECC occurred on QMI */ ++ e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,/**< Dequeue from unknown port id */ ++ e_FM_EX_BMI_LIST_RAM_ECC, /**< Linked List RAM ECC error */ ++ e_FM_EX_BMI_STORAGE_PROFILE_ECC, /**< Storage Profile ECC Error */ ++ e_FM_EX_BMI_STATISTICS_RAM_ECC, /**< Statistics Count RAM ECC Error Enable */ ++ e_FM_EX_BMI_DISPATCH_RAM_ECC, /**< Dispatch RAM ECC Error Enable */ ++ e_FM_EX_IRAM_ECC, /**< Double bit ECC occurred on IRAM*/ ++ e_FM_EX_MURAM_ECC /**< Double bit ECC occurred on MURAM*/ ++} e_FmExceptions; ++ ++/**************************************************************************//** ++ @Description Enum for defining port DMA swap mode ++*//***************************************************************************/ ++typedef enum e_FmDmaSwapOption { ++ e_FM_DMA_NO_SWP = FMAN_DMA_NO_SWP, /**< No swap, transfer data as is.*/ ++ e_FM_DMA_SWP_PPC_LE = FMAN_DMA_SWP_PPC_LE, /**< The transferred data should be swapped ++ in PowerPc Little Endian mode. */ ++ e_FM_DMA_SWP_BE = FMAN_DMA_SWP_BE /**< The transferred data should be swapped ++ in Big Endian mode */ ++} e_FmDmaSwapOption; ++ ++/**************************************************************************//** ++ @Description Enum for defining port DMA cache attributes ++*//***************************************************************************/ ++typedef enum e_FmDmaCacheOption { ++ e_FM_DMA_NO_STASH = FMAN_DMA_NO_STASH, /**< Cacheable, no Allocate (No Stashing) */ ++ e_FM_DMA_STASH = FMAN_DMA_STASH /**< Cacheable and Allocate (Stashing on) */ ++} e_FmDmaCacheOption; ++ ++ ++/**************************************************************************//** ++ @Group FM_init_grp FM Initialization Unit ++ ++ @Description FM Initialization Unit ++ ++ Initialization Flow ++ Initialization of the FM Module will be carried out by the application ++ according to the following sequence: ++ - Calling the configuration routine with basic parameters. ++ - Calling the advance initialization routines to change driver's defaults. ++ - Calling the initialization routine. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function t_FmExceptionsCallback ++ ++ @Description Exceptions user callback routine, will be called upon an ++ exception passing the exception identification. ++ ++ @Param[in] h_App - User's application descriptor. ++ @Param[in] exception - The exception. ++*//***************************************************************************/ ++typedef void (t_FmExceptionsCallback)(t_Handle h_App, ++ e_FmExceptions exception); ++ ++ ++/**************************************************************************//** ++ @Function t_FmBusErrorCallback ++ ++ @Description Bus error user callback routine, will be called upon a ++ bus error, passing parameters describing the errors and the owner. ++ ++ @Param[in] h_App - User's application descriptor. ++ @Param[in] portType - Port type (e_FmPortType) ++ @Param[in] portId - Port id - relative to type. ++ @Param[in] addr - Address that caused the error ++ @Param[in] tnum - Owner of error ++ @Param[in] liodn - Logical IO device number ++*//***************************************************************************/ ++typedef void (t_FmBusErrorCallback) (t_Handle h_App, ++ e_FmPortType portType, ++ uint8_t portId, ++ uint64_t addr, ++ uint8_t tnum, ++ uint16_t liodn); ++ ++/**************************************************************************//** ++ @Description A structure for defining buffer prefix area content. ++*//***************************************************************************/ ++typedef struct t_FmBufferPrefixContent { ++ uint16_t privDataSize; /**< Number of bytes to be left at the beginning ++ of the external buffer; Note that the private-area will ++ start from the base of the buffer address. */ ++ bool passPrsResult; /**< TRUE to pass the parse result to/from the FM; ++ User may use FM_PORT_GetBufferPrsResult() in order to ++ get the parser-result from a buffer. */ ++ bool passTimeStamp; /**< TRUE to pass the timeStamp to/from the FM ++ User may use FM_PORT_GetBufferTimeStamp() in order to ++ get the parser-result from a buffer. */ ++ bool passHashResult; /**< TRUE to pass the KG hash result to/from the FM ++ User may use FM_PORT_GetBufferHashResult() in order to ++ get the parser-result from a buffer. */ ++ bool passAllOtherPCDInfo;/**< Add all other Internal-Context information: ++ AD, hash-result, key, etc. */ ++ uint16_t dataAlign; /**< 0 to use driver's default alignment [DEFAULT_FM_SP_bufferPrefixContent_dataAlign], ++ other value for selecting a data alignment (must be a power of 2); ++ if write optimization is used, must be >= 16. */ ++ uint8_t manipExtraSpace; /**< Maximum extra size needed (insertion-size minus removal-size); ++ Note that this field impacts the size of the buffer-prefix ++ (i.e. it pushes the data offset); ++ This field is irrelevant if DPAA_VERSION==10 */ ++} t_FmBufferPrefixContent; ++ ++/**************************************************************************//** ++ @Description A structure of information about each of the external ++ buffer pools used by a port or storage-profile. ++*//***************************************************************************/ ++typedef struct t_FmExtPoolParams { ++ uint8_t id; /**< External buffer pool id */ ++ uint16_t size; /**< External buffer pool buffer size */ ++} t_FmExtPoolParams; ++ ++/**************************************************************************//** ++ @Description A structure for informing the driver about the external ++ buffer pools allocated in the BM and used by a port or a ++ storage-profile. ++*//***************************************************************************/ ++typedef struct t_FmExtPools { ++ uint8_t numOfPoolsUsed; /**< Number of pools use by this port */ ++ t_FmExtPoolParams extBufPool[FM_PORT_MAX_NUM_OF_EXT_POOLS]; ++ /**< Parameters for each port */ ++} t_FmExtPools; ++ ++/**************************************************************************//** ++ @Description A structure for defining backup BM Pools. ++*//***************************************************************************/ ++typedef struct t_FmBackupBmPools { ++ uint8_t numOfBackupPools; /**< Number of BM backup pools - ++ must be smaller than the total number of ++ pools defined for the specified port.*/ ++ uint8_t poolIds[FM_PORT_MAX_NUM_OF_EXT_POOLS]; ++ /**< numOfBackupPools pool id's, specifying which ++ pools should be used only as backup. Pool ++ id's specified here must be a subset of the ++ pools used by the specified port.*/ ++} t_FmBackupBmPools; ++ ++/**************************************************************************//** ++ @Description A structure for defining BM pool depletion criteria ++*//***************************************************************************/ ++typedef struct t_FmBufPoolDepletion { ++ bool poolsGrpModeEnable; /**< select mode in which pause frames will be sent after ++ a number of pools (all together!) are depleted */ ++ uint8_t numOfPools; /**< the number of depleted pools that will invoke ++ pause frames transmission. */ ++ bool poolsToConsider[BM_MAX_NUM_OF_POOLS]; ++ /**< For each pool, TRUE if it should be considered for ++ depletion (Note - this pool must be used by this port!). */ ++ bool singlePoolModeEnable; /**< select mode in which pause frames will be sent after ++ a single-pool is depleted; */ ++ bool poolsToConsiderForSingleMode[BM_MAX_NUM_OF_POOLS]; ++ /**< For each pool, TRUE if it should be considered for ++ depletion (Note - this pool must be used by this port!) */ ++#if (DPAA_VERSION >= 11) ++ bool pfcPrioritiesEn[FM_MAX_NUM_OF_PFC_PRIORITIES]; ++ /**< This field is used by the MAC as the Priority Enable Vector in the PFC frame which is transmitted */ ++#endif /* (DPAA_VERSION >= 11) */ ++} t_FmBufPoolDepletion; ++ ++/**************************************************************************//** ++ @Description A Structure for defining Ucode patch for loading. ++*//***************************************************************************/ ++typedef struct t_FmFirmwareParams { ++ uint32_t size; /**< Size of uCode */ ++ uint32_t *p_Code; /**< A pointer to the uCode */ ++} t_FmFirmwareParams; ++ ++/**************************************************************************//** ++ @Description A Structure for defining FM initialization parameters ++*//***************************************************************************/ ++typedef struct t_FmParams { ++ uint8_t fmId; /**< Index of the FM */ ++ uint8_t guestId; /**< FM Partition Id */ ++ uintptr_t baseAddr; /**< A pointer to base of memory mapped FM registers (virtual); ++ this field is optional when the FM runs in "guest-mode" ++ (i.e. guestId != NCSW_MASTER_ID); in that case, the driver will ++ use the memory-map instead of calling the IPC where possible; ++ NOTE that this should include ALL common registers of the FM including ++ the PCD registers area (i.e. until the VSP pages - 880KB). */ ++ t_Handle h_FmMuram; /**< A handle of an initialized MURAM object, ++ to be used by the FM. */ ++ uint16_t fmClkFreq; /**< In Mhz; ++ Relevant when FM not runs in "guest-mode". */ ++ uint16_t fmMacClkRatio; /**< FM MAC Clock ratio, for backward comparability: ++ when fmMacClkRatio = 0, ratio is 2:1 ++ when fmMacClkRatio = 1, ratio is 1:1 */ ++ t_FmExceptionsCallback *f_Exception; /**< An application callback routine to handle exceptions; ++ Relevant when FM not runs in "guest-mode". */ ++ t_FmBusErrorCallback *f_BusError; /**< An application callback routine to handle exceptions; ++ Relevant when FM not runs in "guest-mode". */ ++ t_Handle h_App; /**< A handle to an application layer object; This handle will ++ be passed by the driver upon calling the above callbacks; ++ Relevant when FM not runs in "guest-mode". */ ++ int irq; /**< FM interrupt source for normal events; ++ Relevant when FM not runs in "guest-mode". */ ++ int errIrq; /**< FM interrupt source for errors; ++ Relevant when FM not runs in "guest-mode". */ ++ t_FmFirmwareParams firmware; /**< The firmware parameters structure; ++ Relevant when FM not runs in "guest-mode". */ ++ ++#if (DPAA_VERSION >= 11) ++ uintptr_t vspBaseAddr; /**< A pointer to base of memory mapped FM VSP registers (virtual); ++ i.e. up to 24KB, depending on the specific chip. */ ++ uint8_t partVSPBase; /**< The first Virtual-Storage-Profile-id dedicated to this partition. ++ NOTE: this parameter relevant only when working with multiple partitions. */ ++ uint8_t partNumOfVSPs; /**< Number of VSPs dedicated to this partition. ++ NOTE: this parameter relevant only when working with multiple partitions. */ ++#endif /* (DPAA_VERSION >= 11) */ ++} t_FmParams; ++ ++ ++/**************************************************************************//** ++ @Function FM_Config ++ ++ @Description Creates the FM module and returns its handle (descriptor). ++ This descriptor must be passed as first parameter to all other ++ FM function calls. ++ ++ No actual initialization or configuration of FM hardware is ++ done by this routine. All FM parameters get default values that ++ may be changed by calling one or more of the advance config routines. ++ ++ @Param[in] p_FmParams - A pointer to a data structure of mandatory FM parameters ++ ++ @Return A handle to the FM object, or NULL for Failure. ++*//***************************************************************************/ ++t_Handle FM_Config(t_FmParams *p_FmParams); ++ ++/**************************************************************************//** ++ @Function FM_Init ++ ++ @Description Initializes the FM module by defining the software structure ++ and configuring the hardware registers. ++ ++ @Param[in] h_Fm - FM module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_Init(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FM_Free ++ ++ @Description Frees all resources that were assigned to FM module. ++ ++ Calling this routine invalidates the descriptor. ++ ++ @Param[in] h_Fm - FM module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_Free(t_Handle h_Fm); ++ ++ ++/**************************************************************************//** ++ @Group FM_advanced_init_grp FM Advanced Configuration Unit ++ ++ @Description Advanced configuration routines are optional routines that may ++ be called in order to change the default driver settings. ++ ++ Note: Advanced configuration routines are not available for guest partition. ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description Enum for selecting DMA debug mode ++*//***************************************************************************/ ++typedef enum e_FmDmaDbgCntMode { ++ e_FM_DMA_DBG_NO_CNT = 0, /**< No counting */ ++ e_FM_DMA_DBG_CNT_DONE, /**< Count DONE commands */ ++ e_FM_DMA_DBG_CNT_COMM_Q_EM, /**< count command queue emergency signals */ ++ e_FM_DMA_DBG_CNT_INT_READ_EM, /**< Count Internal Read buffer emergency signal */ ++ e_FM_DMA_DBG_CNT_INT_WRITE_EM, /**< Count Internal Write buffer emergency signal */ ++ e_FM_DMA_DBG_CNT_FPM_WAIT, /**< Count FPM WAIT signal */ ++ e_FM_DMA_DBG_CNT_SIGLE_BIT_ECC, /**< Single bit ECC errors. */ ++ e_FM_DMA_DBG_CNT_RAW_WAR_PROT /**< Number of times there was a need for RAW & WAR protection. */ ++} e_FmDmaDbgCntMode; ++ ++/**************************************************************************//** ++ @Description Enum for selecting DMA Cache Override ++*//***************************************************************************/ ++typedef enum e_FmDmaCacheOverride { ++ e_FM_DMA_NO_CACHE_OR = 0, /**< No override of the Cache field */ ++ e_FM_DMA_NO_STASH_DATA, /**< Data should not be stashed in system level cache */ ++ e_FM_DMA_MAY_STASH_DATA, /**< Data may be stashed in system level cache */ ++ e_FM_DMA_STASH_DATA /**< Data should be stashed in system level cache */ ++} e_FmDmaCacheOverride; ++ ++/**************************************************************************//** ++ @Description Enum for selecting DMA External Bus Priority ++*//***************************************************************************/ ++typedef enum e_FmDmaExtBusPri { ++ e_FM_DMA_EXT_BUS_NORMAL = 0, /**< Normal priority */ ++ e_FM_DMA_EXT_BUS_EBS, /**< AXI extended bus service priority */ ++ e_FM_DMA_EXT_BUS_SOS, /**< AXI sos priority */ ++ e_FM_DMA_EXT_BUS_EBS_AND_SOS /**< AXI ebs + sos priority */ ++} e_FmDmaExtBusPri; ++ ++/**************************************************************************//** ++ @Description Enum for choosing the field that will be output on AID ++*//***************************************************************************/ ++typedef enum e_FmDmaAidMode { ++ e_FM_DMA_AID_OUT_PORT_ID = 0, /**< 4 LSB of PORT_ID */ ++ e_FM_DMA_AID_OUT_TNUM /**< 4 LSB of TNUM */ ++} e_FmDmaAidMode; ++ ++/**************************************************************************//** ++ @Description Enum for selecting FPM Catastrophic error behavior ++*//***************************************************************************/ ++typedef enum e_FmCatastrophicErr { ++ e_FM_CATASTROPHIC_ERR_STALL_PORT = 0, /**< Port_ID is stalled (only reset can release it) */ ++ e_FM_CATASTROPHIC_ERR_STALL_TASK /**< Only erroneous task is stalled */ ++} e_FmCatastrophicErr; ++ ++/**************************************************************************//** ++ @Description Enum for selecting FPM DMA Error behavior ++*//***************************************************************************/ ++typedef enum e_FmDmaErr { ++ e_FM_DMA_ERR_CATASTROPHIC = 0, /**< Dma error is treated as a catastrophic ++ error (e_FmCatastrophicErr)*/ ++ e_FM_DMA_ERR_REPORT /**< Dma error is just reported */ ++} e_FmDmaErr; ++ ++/**************************************************************************//** ++ @Description Enum for selecting DMA Emergency level by BMI emergency signal ++*//***************************************************************************/ ++typedef enum e_FmDmaEmergencyLevel { ++ e_FM_DMA_EM_EBS = 0, /**< EBS emergency */ ++ e_FM_DMA_EM_SOS /**< SOS emergency */ ++} e_FmDmaEmergencyLevel; ++ ++/**************************************************************************//** ++ @Collection Enum for selecting DMA Emergency options ++*//***************************************************************************/ ++typedef uint32_t fmEmergencyBus_t; /**< DMA emergency options */ ++ ++#define FM_DMA_MURAM_READ_EMERGENCY 0x00800000 /**< Enable emergency for MURAM1 */ ++#define FM_DMA_MURAM_WRITE_EMERGENCY 0x00400000 /**< Enable emergency for MURAM2 */ ++#define FM_DMA_EXT_BUS_EMERGENCY 0x00100000 /**< Enable emergency for external bus */ ++/* @} */ ++ ++/**************************************************************************//** ++ @Description A structure for defining DMA emergency level ++*//***************************************************************************/ ++typedef struct t_FmDmaEmergency { ++ fmEmergencyBus_t emergencyBusSelect; /**< An OR of the busses where emergency ++ should be enabled */ ++ e_FmDmaEmergencyLevel emergencyLevel; /**< EBS/SOS */ ++} t_FmDmaEmergency; ++ ++/**************************************************************************//* ++ @Description structure for defining FM threshold ++*//***************************************************************************/ ++typedef struct t_FmThresholds { ++ uint8_t dispLimit; /**< The number of times a frames may ++ be passed in the FM before assumed to ++ be looping. */ ++ uint8_t prsDispTh; /**< This is the number pf packets that may be ++ queued in the parser dispatch queue*/ ++ uint8_t plcrDispTh; /**< This is the number pf packets that may be ++ queued in the policer dispatch queue*/ ++ uint8_t kgDispTh; /**< This is the number pf packets that may be ++ queued in the keygen dispatch queue*/ ++ uint8_t bmiDispTh; /**< This is the number pf packets that may be ++ queued in the BMI dispatch queue*/ ++ uint8_t qmiEnqDispTh; /**< This is the number pf packets that may be ++ queued in the QMI enqueue dispatch queue*/ ++ uint8_t qmiDeqDispTh; /**< This is the number pf packets that may be ++ queued in the QMI dequeue dispatch queue*/ ++ uint8_t fmCtl1DispTh; /**< This is the number pf packets that may be ++ queued in fmCtl1 dispatch queue*/ ++ uint8_t fmCtl2DispTh; /**< This is the number pf packets that may be ++ queued in fmCtl2 dispatch queue*/ ++} t_FmThresholds; ++ ++/**************************************************************************//* ++ @Description structure for defining DMA thresholds ++*//***************************************************************************/ ++typedef struct t_FmDmaThresholds { ++ uint8_t assertEmergency; /**< When this value is reached, ++ assert emergency (Threshold)*/ ++ uint8_t clearEmergency; /**< After emergency is asserted, it is held ++ until this value is reached (Hystheresis) */ ++} t_FmDmaThresholds; ++ ++/**************************************************************************//** ++ @Function t_FmResetOnInitOverrideCallback ++ ++ @Description FMan specific reset on init user callback routine, ++ will be used to override the standard FMan reset on init procedure ++ ++ @Param[in] h_Fm - FMan handler ++*//***************************************************************************/ ++typedef void (t_FmResetOnInitOverrideCallback)(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FM_ConfigResetOnInit ++ ++ @Description Define whether to reset the FM before initialization. ++ Change the default configuration [DEFAULT_resetOnInit]. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] enable When TRUE, FM will be reset before any initialization. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigResetOnInit(t_Handle h_Fm, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_ConfigResetOnInitOverrideCallback ++ ++ @Description Define a special reset of FM before initialization. ++ Change the default configuration [DEFAULT_resetOnInitOverrideCallback]. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] f_ResetOnInitOverride FM specific reset on init user callback routine. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigResetOnInitOverrideCallback(t_Handle h_Fm, t_FmResetOnInitOverrideCallback *f_ResetOnInitOverride); ++ ++/**************************************************************************//** ++ @Function FM_ConfigTotalFifoSize ++ ++ @Description Define Total FIFO size for the whole FM. ++ Calling this routine changes the total Fifo size in the internal driver ++ data base from its default configuration [DEFAULT_totalFifoSize] ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] totalFifoSize The selected new value. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigTotalFifoSize(t_Handle h_Fm, uint32_t totalFifoSize); ++ ++ /**************************************************************************//** ++ @Function FM_ConfigDmaCacheOverride ++ ++ @Description Define cache override mode. ++ Calling this routine changes the cache override mode ++ in the internal driver data base from its default configuration [DEFAULT_cacheOverride] ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] cacheOverride The selected new value. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigDmaCacheOverride(t_Handle h_Fm, e_FmDmaCacheOverride cacheOverride); ++ ++/**************************************************************************//** ++ @Function FM_ConfigDmaAidOverride ++ ++ @Description Define DMA AID override mode. ++ Calling this routine changes the AID override mode ++ in the internal driver data base from its default configuration [DEFAULT_aidOverride] ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] aidOverride The selected new value. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigDmaAidOverride(t_Handle h_Fm, bool aidOverride); ++ ++/**************************************************************************//** ++ @Function FM_ConfigDmaAidMode ++ ++ @Description Define DMA AID mode. ++ Calling this routine changes the AID mode in the internal ++ driver data base from its default configuration [DEFAULT_aidMode] ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] aidMode The selected new value. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigDmaAidMode(t_Handle h_Fm, e_FmDmaAidMode aidMode); ++ ++/**************************************************************************//** ++ @Function FM_ConfigDmaAxiDbgNumOfBeats ++ ++ @Description Define DMA AXI number of beats. ++ Calling this routine changes the AXI number of beats in the internal ++ driver data base from its default configuration [DEFAULT_axiDbgNumOfBeats] ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] axiDbgNumOfBeats The selected new value. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigDmaAxiDbgNumOfBeats(t_Handle h_Fm, uint8_t axiDbgNumOfBeats); ++ ++/**************************************************************************//** ++ @Function FM_ConfigDmaCamNumOfEntries ++ ++ @Description Define number of CAM entries. ++ Calling this routine changes the number of CAM entries in the internal ++ driver data base from its default configuration [DEFAULT_dmaCamNumOfEntries]. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] numOfEntries The selected new value. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigDmaCamNumOfEntries(t_Handle h_Fm, uint8_t numOfEntries); ++ ++/**************************************************************************//** ++ @Function FM_ConfigEnableCounters ++ ++ @Description Obsolete, always return E_OK. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_ConfigEnableCounters(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FM_ConfigDmaDbgCounter ++ ++ @Description Define DMA debug counter. ++ Calling this routine changes the number of the DMA debug counter in the internal ++ driver data base from its default configuration [DEFAULT_dmaDbgCntMode]. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] fmDmaDbgCntMode An enum selecting the debug counter mode. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigDmaDbgCounter(t_Handle h_Fm, e_FmDmaDbgCntMode fmDmaDbgCntMode); ++ ++/**************************************************************************//** ++ @Function FM_ConfigDmaStopOnBusErr ++ ++ @Description Define bus error behavior. ++ Calling this routine changes the bus error behavior definition ++ in the internal driver data base from its default ++ configuration [DEFAULT_dmaStopOnBusError]. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] stop TRUE to stop on bus error, FALSE to continue. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ Only if bus error is enabled. ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigDmaStopOnBusErr(t_Handle h_Fm, bool stop); ++ ++/**************************************************************************//** ++ @Function FM_ConfigDmaEmergency ++ ++ @Description Define DMA emergency. ++ Calling this routine changes the DMA emergency definition ++ in the internal driver data base from its default ++ configuration where's it's disabled. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] p_Emergency An OR mask of all required options. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigDmaEmergency(t_Handle h_Fm, t_FmDmaEmergency *p_Emergency); ++ ++/**************************************************************************//** ++ @Function FM_ConfigDmaErr ++ ++ @Description DMA error treatment. ++ Calling this routine changes the DMA error treatment ++ in the internal driver data base from its default ++ configuration [DEFAULT_dmaErr]. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] dmaErr The selected new choice. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigDmaErr(t_Handle h_Fm, e_FmDmaErr dmaErr); ++ ++/**************************************************************************//** ++ @Function FM_ConfigCatastrophicErr ++ ++ @Description Define FM behavior on catastrophic error. ++ Calling this routine changes the FM behavior on catastrophic ++ error in the internal driver data base from its default ++ [DEFAULT_catastrophicErr]. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] catastrophicErr The selected new choice. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigCatastrophicErr(t_Handle h_Fm, e_FmCatastrophicErr catastrophicErr); ++ ++/**************************************************************************//** ++ @Function FM_ConfigEnableMuramTestMode ++ ++ @Description Enable MURAM test mode. ++ Calling this routine changes the internal driver data base ++ from its default selection of test mode where it's disabled. ++ This routine is only avaiable on old FM revisions (FMan v2). ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigEnableMuramTestMode(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FM_ConfigEnableIramTestMode ++ ++ @Description Enable IRAM test mode. ++ Calling this routine changes the internal driver data base ++ from its default selection of test mode where it's disabled. ++ This routine is only avaiable on old FM revisions (FMan v2). ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigEnableIramTestMode(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FM_ConfigHaltOnExternalActivation ++ ++ @Description Define FM behavior on external halt activation. ++ Calling this routine changes the FM behavior on external halt ++ activation in the internal driver data base from its default ++ [DEFAULT_haltOnExternalActivation]. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] enable TRUE to enable halt on external halt ++ activation. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigHaltOnExternalActivation(t_Handle h_Fm, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_ConfigHaltOnUnrecoverableEccError ++ ++ @Description Define FM behavior on external halt activation. ++ Calling this routine changes the FM behavior on unrecoverable ++ ECC error in the internal driver data base from its default ++ [DEFAULT_haltOnUnrecoverableEccError]. ++ This routine is only avaiable on old FM revisions (FMan v2). ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] enable TRUE to enable halt on unrecoverable Ecc error ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigHaltOnUnrecoverableEccError(t_Handle h_Fm, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_ConfigException ++ ++ @Description Define FM exceptions. ++ Calling this routine changes the exceptions defaults in the ++ internal driver data base where all exceptions are enabled. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] exception The exception to be selected. ++ @Param[in] enable TRUE to enable interrupt, FALSE to mask it. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigException(t_Handle h_Fm, e_FmExceptions exception, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_ConfigExternalEccRamsEnable ++ ++ @Description Select external ECC enabling. ++ Calling this routine changes the ECC enabling control in the internal ++ driver data base from its default [DEFAULT_externalEccRamsEnable]. ++ When this option is enabled Rams ECC enabling is not effected ++ by FM_EnableRamsEcc/FM_DisableRamsEcc, but by a JTAG. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] enable TRUE to enable this option. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigExternalEccRamsEnable(t_Handle h_Fm, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_ConfigTnumAgingPeriod ++ ++ @Description Define Tnum aging period. ++ Calling this routine changes the Tnum aging of dequeue TNUMs ++ in the QMI in the internal driver data base from its default ++ [DEFAULT_tnumAgingPeriod]. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] tnumAgingPeriod Tnum Aging Period in microseconds. ++ Note that period is recalculated in units of ++ 64 FM clocks. Driver will pick the closest ++ possible period. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++ NOTE that if some MAC is configured for PFC, '0' value is NOT ++ allowed. ++*//***************************************************************************/ ++t_Error FM_ConfigTnumAgingPeriod(t_Handle h_Fm, uint16_t tnumAgingPeriod); ++ ++/**************************************************************************//* ++ @Function FM_ConfigDmaEmergencySmoother ++ ++ @Description Define DMA emergency smoother. ++ Calling this routine changes the definition of the minimum ++ amount of DATA beats transferred on the AXI READ and WRITE ++ ports before lowering the emergency level. ++ By default smoother is disabled. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] emergencyCnt emergency switching counter. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigDmaEmergencySmoother(t_Handle h_Fm, uint32_t emergencyCnt); ++ ++/**************************************************************************//* ++ @Function FM_ConfigThresholds ++ ++ @Description Calling this routine changes the internal driver data base ++ from its default FM threshold configuration: ++ dispLimit: [DEFAULT_dispLimit] ++ prsDispTh: [DEFAULT_prsDispTh] ++ plcrDispTh: [DEFAULT_plcrDispTh] ++ kgDispTh: [DEFAULT_kgDispTh] ++ bmiDispTh: [DEFAULT_bmiDispTh] ++ qmiEnqDispTh: [DEFAULT_qmiEnqDispTh] ++ qmiDeqDispTh: [DEFAULT_qmiDeqDispTh] ++ fmCtl1DispTh: [DEFAULT_fmCtl1DispTh] ++ fmCtl2DispTh: [DEFAULT_fmCtl2DispTh] ++ ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] p_FmThresholds A structure of threshold parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigThresholds(t_Handle h_Fm, t_FmThresholds *p_FmThresholds); ++ ++/**************************************************************************//* ++ @Function FM_ConfigDmaSosEmergencyThreshold ++ ++ @Description Calling this routine changes the internal driver data base ++ from its default dma SOS emergency configuration [DEFAULT_dmaSosEmergency] ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] dmaSosEmergency The selected new value. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigDmaSosEmergencyThreshold(t_Handle h_Fm, uint32_t dmaSosEmergency); ++ ++/**************************************************************************//* ++ @Function FM_ConfigDmaWriteBufThresholds ++ ++ @Description Calling this routine changes the internal driver data base ++ from its default configuration of DMA write buffer threshold ++ assertEmergency: [DEFAULT_dmaWriteIntBufLow] ++ clearEmergency: [DEFAULT_dmaWriteIntBufHigh] ++ This routine is only avaiable on old FM revisions (FMan v2). ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] p_FmDmaThresholds A structure of thresholds to define emergency behavior - ++ When 'assertEmergency' value is reached, emergency is asserted, ++ then it is held until 'clearEmergency' value is reached. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigDmaWriteBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds); ++ ++ /**************************************************************************//* ++ @Function FM_ConfigDmaCommQThresholds ++ ++ @Description Calling this routine changes the internal driver data base ++ from its default configuration of DMA command queue threshold ++ assertEmergency: [DEFAULT_dmaCommQLow] ++ clearEmergency: [DEFAULT_dmaCommQHigh] ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] p_FmDmaThresholds A structure of thresholds to define emergency behavior - ++ When 'assertEmergency' value is reached, emergency is asserted, ++ then it is held until 'clearEmergency' value is reached.. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigDmaCommQThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds); ++ ++/**************************************************************************//* ++ @Function FM_ConfigDmaReadBufThresholds ++ ++ @Description Calling this routine changes the internal driver data base ++ from its default configuration of DMA read buffer threshold ++ assertEmergency: [DEFAULT_dmaReadIntBufLow] ++ clearEmergency: [DEFAULT_dmaReadIntBufHigh] ++ This routine is only avaiable on old FM revisions (FMan v2). ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] p_FmDmaThresholds A structure of thresholds to define emergency behavior - ++ When 'assertEmergency' value is reached, emergency is asserted, ++ then it is held until 'clearEmergency' value is reached.. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigDmaReadBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds); ++ ++/**************************************************************************//* ++ @Function FM_ConfigDmaWatchdog ++ ++ @Description Calling this routine changes the internal driver data base ++ from its default watchdog configuration, which is disabled ++ [DEFAULT_dmaWatchdog]. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] watchDogValue The selected new value - in microseconds. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ConfigDmaWatchdog(t_Handle h_Fm, uint32_t watchDogValue); ++ ++/** @} */ /* end of FM_advanced_init_grp group */ ++/** @} */ /* end of FM_init_grp group */ ++ ++ ++/**************************************************************************//** ++ @Group FM_runtime_control_grp FM Runtime Control Unit ++ ++ @Description FM Runtime control unit API functions, definitions and enums. ++ The FM driver provides a set of control routines. ++ These routines may only be called after the module was fully ++ initialized (both configuration and initialization routines were ++ called). They are typically used to get information from hardware ++ (status, counters/statistics, revision etc.), to modify a current ++ state or to force/enable a required action. Run-time control may ++ be called whenever necessary and as many times as needed. ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Collection General FM defines. ++*//***************************************************************************/ ++#define FM_MAX_NUM_OF_VALID_PORTS (FM_MAX_NUM_OF_OH_PORTS + \ ++ FM_MAX_NUM_OF_1G_RX_PORTS + \ ++ FM_MAX_NUM_OF_10G_RX_PORTS + \ ++ FM_MAX_NUM_OF_1G_TX_PORTS + \ ++ FM_MAX_NUM_OF_10G_TX_PORTS) /**< Number of available FM ports */ ++/* @} */ ++ ++/**************************************************************************//* ++ @Description A Structure for Port bandwidth requirement. Port is identified ++ by type and relative id. ++*//***************************************************************************/ ++typedef struct t_FmPortBandwidth { ++ e_FmPortType type; /**< FM port type */ ++ uint8_t relativePortId; /**< Type relative port id */ ++ uint8_t bandwidth; /**< bandwidth - (in term of percents) */ ++} t_FmPortBandwidth; ++ ++/**************************************************************************//* ++ @Description A Structure containing an array of Port bandwidth requirements. ++ The user should state the ports requiring bandwidth in terms of ++ percentage - i.e. all port's bandwidths in the array must add ++ up to 100. ++*//***************************************************************************/ ++typedef struct t_FmPortsBandwidthParams { ++ uint8_t numOfPorts; /**< The number of relevant ports, which is the ++ number of valid entries in the array below */ ++ t_FmPortBandwidth portsBandwidths[FM_MAX_NUM_OF_VALID_PORTS]; ++ /**< for each port, it's bandwidth (all port's ++ bandwidths must add up to 100.*/ ++} t_FmPortsBandwidthParams; ++ ++/**************************************************************************//** ++ @Description DMA Emergency control on MURAM ++*//***************************************************************************/ ++typedef enum e_FmDmaMuramPort { ++ e_FM_DMA_MURAM_PORT_WRITE, /**< MURAM write port */ ++ e_FM_DMA_MURAM_PORT_READ /**< MURAM read port */ ++} e_FmDmaMuramPort; ++ ++/**************************************************************************//** ++ @Description Enum for defining FM counters ++*//***************************************************************************/ ++typedef enum e_FmCounters { ++ e_FM_COUNTERS_ENQ_TOTAL_FRAME = 0, /**< QMI total enqueued frames counter */ ++ e_FM_COUNTERS_DEQ_TOTAL_FRAME, /**< QMI total dequeued frames counter */ ++ e_FM_COUNTERS_DEQ_0, /**< QMI 0 frames from QMan counter */ ++ e_FM_COUNTERS_DEQ_1, /**< QMI 1 frames from QMan counter */ ++ e_FM_COUNTERS_DEQ_2, /**< QMI 2 frames from QMan counter */ ++ e_FM_COUNTERS_DEQ_3, /**< QMI 3 frames from QMan counter */ ++ e_FM_COUNTERS_DEQ_FROM_DEFAULT, /**< QMI dequeue from default queue counter */ ++ e_FM_COUNTERS_DEQ_FROM_CONTEXT, /**< QMI dequeue from FQ context counter */ ++ e_FM_COUNTERS_DEQ_FROM_FD, /**< QMI dequeue from FD command field counter */ ++ e_FM_COUNTERS_DEQ_CONFIRM /**< QMI dequeue confirm counter */ ++} e_FmCounters; ++ ++/**************************************************************************//** ++ @Description A Structure for returning FM revision information ++*//***************************************************************************/ ++typedef struct t_FmRevisionInfo { ++ uint8_t majorRev; /**< Major revision */ ++ uint8_t minorRev; /**< Minor revision */ ++} t_FmRevisionInfo; ++ ++/**************************************************************************//** ++ @Description A Structure for returning FM ctrl code revision information ++*//***************************************************************************/ ++typedef struct t_FmCtrlCodeRevisionInfo { ++ uint16_t packageRev; /**< Package revision */ ++ uint8_t majorRev; /**< Major revision */ ++ uint8_t minorRev; /**< Minor revision */ ++} t_FmCtrlCodeRevisionInfo; ++ ++/**************************************************************************//** ++ @Description A Structure for defining DMA status ++*//***************************************************************************/ ++typedef struct t_FmDmaStatus { ++ bool cmqNotEmpty; /**< Command queue is not empty */ ++ bool busError; /**< Bus error occurred */ ++ bool readBufEccError; /**< Double ECC error on buffer Read (Valid for FM rev < 6)*/ ++ bool writeBufEccSysError; /**< Double ECC error on buffer write from system side (Valid for FM rev < 6)*/ ++ bool writeBufEccFmError; /**< Double ECC error on buffer write from FM side (Valid for FM rev < 6) */ ++ bool singlePortEccError; /**< Single Port ECC error from FM side (Valid for FM rev >= 6)*/ ++} t_FmDmaStatus; ++ ++/**************************************************************************//** ++ @Description A Structure for obtaining FM controller monitor values ++*//***************************************************************************/ ++typedef struct t_FmCtrlMon { ++ uint8_t percentCnt[2]; /**< Percentage value */ ++} t_FmCtrlMon; ++ ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++/**************************************************************************//** ++ @Function FM_DumpRegs ++ ++ @Description Dumps all FM registers ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return E_OK on success; ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++t_Error FM_DumpRegs(t_Handle h_Fm); ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++/**************************************************************************//** ++ @Function FM_SetException ++ ++ @Description Calling this routine enables/disables the specified exception. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] exception The exception to be selected. ++ @Param[in] enable TRUE to enable interrupt, FALSE to mask it. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_SetException(t_Handle h_Fm, e_FmExceptions exception, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_EnableRamsEcc ++ ++ @Description Enables ECC mechanism for all the different FM RAM's; E.g. IRAM, ++ MURAM, Parser, Keygen, Policer, etc. ++ Note: ++ If FM_ConfigExternalEccRamsEnable was called to enable external ++ setting of ECC, this routine effects IRAM ECC only. ++ This routine is also called by the driver if an ECC exception is ++ enabled. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_EnableRamsEcc(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FM_DisableRamsEcc ++ ++ @Description Disables ECC mechanism for all the different FM RAM's; E.g. IRAM, ++ MURAM, Parser, Keygen, Policer, etc. ++ Note: ++ If FM_ConfigExternalEccRamsEnable was called to enable external ++ setting of ECC, this routine effects IRAM ECC only. ++ In opposed to FM_EnableRamsEcc, this routine must be called ++ explicitly to disable all Rams ECC. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Config() and before FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_DisableRamsEcc(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FM_GetRevision ++ ++ @Description Returns the FM revision ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[out] p_FmRevisionInfo A structure of revision information parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++t_Error FM_GetRevision(t_Handle h_Fm, t_FmRevisionInfo *p_FmRevisionInfo); ++ ++/**************************************************************************//** ++ @Function FM_GetFmanCtrlCodeRevision ++ ++ @Description Returns the Fman controller code revision ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[out] p_RevisionInfo A structure of revision information parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++t_Error FM_GetFmanCtrlCodeRevision(t_Handle h_Fm, t_FmCtrlCodeRevisionInfo *p_RevisionInfo); ++ ++/**************************************************************************//** ++ @Function FM_GetCounter ++ ++ @Description Reads one of the FM counters. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] counter The requested counter. ++ ++ @Return Counter's current value. ++ ++ @Cautions Allowed only following FM_Init(). ++ Note that it is user's responsibility to call this routine only ++ for enabled counters, and there will be no indication if a ++ disabled counter is accessed. ++*//***************************************************************************/ ++uint32_t FM_GetCounter(t_Handle h_Fm, e_FmCounters counter); ++ ++/**************************************************************************//** ++ @Function FM_ModifyCounter ++ ++ @Description Sets a value to an enabled counter. Use "0" to reset the counter. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] counter The requested counter. ++ @Param[in] val The requested value to be written into the counter. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ModifyCounter(t_Handle h_Fm, e_FmCounters counter, uint32_t val); ++ ++/**************************************************************************//** ++ @Function FM_Resume ++ ++ @Description Release FM after halt FM command or after unrecoverable ECC error. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++void FM_Resume(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FM_SetDmaEmergency ++ ++ @Description Manual emergency set ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] muramPort MURAM direction select. ++ @Param[in] enable TRUE to manually enable emergency, FALSE to disable. ++ ++ @Return None. ++ ++ @Cautions Allowed only following FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++void FM_SetDmaEmergency(t_Handle h_Fm, e_FmDmaMuramPort muramPort, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_SetDmaExtBusPri ++ ++ @Description Set the DMA external bus priority ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] pri External bus priority select ++ ++ @Return None. ++ ++ @Cautions Allowed only following FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++void FM_SetDmaExtBusPri(t_Handle h_Fm, e_FmDmaExtBusPri pri); ++ ++/**************************************************************************//** ++ @Function FM_GetDmaStatus ++ ++ @Description Reads the DMA current status ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[out] p_FmDmaStatus A structure of DMA status parameters. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++void FM_GetDmaStatus(t_Handle h_Fm, t_FmDmaStatus *p_FmDmaStatus); ++ ++/**************************************************************************//** ++ @Function FM_ErrorIsr ++ ++ @Description FM interrupt-service-routine for errors. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return E_OK on success; E_EMPTY if no errors found in register, other ++ error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ErrorIsr(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FM_EventIsr ++ ++ @Description FM interrupt-service-routine for normal events. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Cautions Allowed only following FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++void FM_EventIsr(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FM_GetSpecialOperationCoding ++ ++ @Description Return a specific coding according to the input mask. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] spOper special operation mask. ++ @Param[out] p_SpOperCoding special operation code. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++t_Error FM_GetSpecialOperationCoding(t_Handle h_Fm, ++ fmSpecialOperations_t spOper, ++ uint8_t *p_SpOperCoding); ++ ++/**************************************************************************//** ++ @Function FM_CtrlMonStart ++ ++ @Description Start monitoring utilization of all available FM controllers. ++ ++ In order to obtain FM controllers utilization the following sequence ++ should be used: ++ -# FM_CtrlMonStart() ++ -# FM_CtrlMonStop() ++ -# FM_CtrlMonGetCounters() - issued for each FM controller ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID). ++*//***************************************************************************/ ++t_Error FM_CtrlMonStart(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FM_CtrlMonStop ++ ++ @Description Stop monitoring utilization of all available FM controllers. ++ ++ In order to obtain FM controllers utilization the following sequence ++ should be used: ++ -# FM_CtrlMonStart() ++ -# FM_CtrlMonStop() ++ -# FM_CtrlMonGetCounters() - issued for each FM controller ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID). ++*//***************************************************************************/ ++t_Error FM_CtrlMonStop(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FM_CtrlMonGetCounters ++ ++ @Description Obtain FM controller utilization parameters. ++ ++ In order to obtain FM controllers utilization the following sequence ++ should be used: ++ -# FM_CtrlMonStart() ++ -# FM_CtrlMonStop() ++ -# FM_CtrlMonGetCounters() - issued for each FM controller ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] fmCtrlIndex FM Controller index for that utilization results ++ are requested. ++ @Param[in] p_Mon Pointer to utilization results structure. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID). ++*//***************************************************************************/ ++t_Error FM_CtrlMonGetCounters(t_Handle h_Fm, uint8_t fmCtrlIndex, t_FmCtrlMon *p_Mon); ++ ++ ++/**************************************************************************//* ++ @Function FM_ForceIntr ++ ++ @Description Causes an interrupt event on the requested source. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] exception An exception to be forced. ++ ++ @Return E_OK on success; Error code if the exception is not enabled, ++ or is not able to create interrupt. ++ ++ @Cautions Allowed only following FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_ForceIntr (t_Handle h_Fm, e_FmExceptions exception); ++ ++/**************************************************************************//* ++ @Function FM_SetPortsBandwidth ++ ++ @Description Sets relative weights between ports when accessing common resources. ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ @Param[in] p_PortsBandwidth A structure of ports bandwidths in percentage, i.e. ++ total must equal 100. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_SetPortsBandwidth(t_Handle h_Fm, t_FmPortsBandwidthParams *p_PortsBandwidth); ++ ++/**************************************************************************//* ++ @Function FM_GetMuramHandle ++ ++ @Description Gets the corresponding MURAM handle ++ ++ @Param[in] h_Fm A handle to an FM Module. ++ ++ @Return MURAM handle; NULL otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Handle FM_GetMuramHandle(t_Handle h_Fm); ++ ++/** @} */ /* end of FM_runtime_control_grp group */ ++/** @} */ /* end of FM_lib_grp group */ ++/** @} */ /* end of FM_grp group */ ++ ++ ++#ifdef NCSW_BACKWARD_COMPATIBLE_API ++typedef t_FmFirmwareParams t_FmPcdFirmwareParams; ++typedef t_FmBufferPrefixContent t_FmPortBufferPrefixContent; ++typedef t_FmExtPoolParams t_FmPortExtPoolParams; ++typedef t_FmExtPools t_FmPortExtPools; ++typedef t_FmBackupBmPools t_FmPortBackupBmPools; ++typedef t_FmBufPoolDepletion t_FmPortBufPoolDepletion; ++typedef e_FmDmaSwapOption e_FmPortDmaSwapOption; ++typedef e_FmDmaCacheOption e_FmPortDmaCacheOption; ++ ++#define FM_CONTEXTA_GET_OVVERIDE FM_CONTEXTA_GET_OVERRIDE ++#define FM_CONTEXTA_SET_OVVERIDE FM_CONTEXTA_SET_OVERRIDE ++ ++#define e_FM_EX_BMI_PIPELINE_ECC e_FM_EX_BMI_STORAGE_PROFILE_ECC ++#define e_FM_PORT_DMA_NO_SWP e_FM_DMA_NO_SWP ++#define e_FM_PORT_DMA_SWP_PPC_LE e_FM_DMA_SWP_PPC_LE ++#define e_FM_PORT_DMA_SWP_BE e_FM_DMA_SWP_BE ++#define e_FM_PORT_DMA_NO_STASH e_FM_DMA_NO_STASH ++#define e_FM_PORT_DMA_STASH e_FM_DMA_STASH ++#endif /* NCSW_BACKWARD_COMPATIBLE_API */ ++ ++ ++#endif /* __FM_EXT */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_mac_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_mac_ext.h +new file mode 100644 +index 00000000..da7e0463 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_mac_ext.h +@@ -0,0 +1,859 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File fm_mac_ext.h ++ ++ @Description FM MAC ... ++*//***************************************************************************/ ++#ifndef __FM_MAC_EXT_H ++#define __FM_MAC_EXT_H ++ ++#include "std_ext.h" ++#include "enet_ext.h" ++ ++ ++/**************************************************************************//** ++ ++ @Group FM_grp Frame Manager API ++ ++ @Description FM API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group FM_mac_grp FM MAC ++ ++ @Description FM MAC API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++#define FM_MAC_NO_PFC 0xff ++ ++ ++/**************************************************************************//** ++ @Description FM MAC Exceptions ++*//***************************************************************************/ ++typedef enum e_FmMacExceptions { ++ e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO = 0 /**< 10GEC MDIO scan event interrupt */ ++ ,e_FM_MAC_EX_10G_MDIO_CMD_CMPL /**< 10GEC MDIO command completion interrupt */ ++ ,e_FM_MAC_EX_10G_REM_FAULT /**< 10GEC, mEMAC Remote fault interrupt */ ++ ,e_FM_MAC_EX_10G_LOC_FAULT /**< 10GEC, mEMAC Local fault interrupt */ ++ ,e_FM_MAC_EX_10G_1TX_ECC_ER /**< 10GEC, mEMAC Transmit frame ECC error interrupt */ ++ ,e_FM_MAC_EX_10G_TX_FIFO_UNFL /**< 10GEC, mEMAC Transmit FIFO underflow interrupt */ ++ ,e_FM_MAC_EX_10G_TX_FIFO_OVFL /**< 10GEC, mEMAC Transmit FIFO overflow interrupt */ ++ ,e_FM_MAC_EX_10G_TX_ER /**< 10GEC Transmit frame error interrupt */ ++ ,e_FM_MAC_EX_10G_RX_FIFO_OVFL /**< 10GEC, mEMAC Receive FIFO overflow interrupt */ ++ ,e_FM_MAC_EX_10G_RX_ECC_ER /**< 10GEC, mEMAC Receive frame ECC error interrupt */ ++ ,e_FM_MAC_EX_10G_RX_JAB_FRM /**< 10GEC Receive jabber frame interrupt */ ++ ,e_FM_MAC_EX_10G_RX_OVRSZ_FRM /**< 10GEC Receive oversized frame interrupt */ ++ ,e_FM_MAC_EX_10G_RX_RUNT_FRM /**< 10GEC Receive runt frame interrupt */ ++ ,e_FM_MAC_EX_10G_RX_FRAG_FRM /**< 10GEC Receive fragment frame interrupt */ ++ ,e_FM_MAC_EX_10G_RX_LEN_ER /**< 10GEC Receive payload length error interrupt */ ++ ,e_FM_MAC_EX_10G_RX_CRC_ER /**< 10GEC Receive CRC error interrupt */ ++ ,e_FM_MAC_EX_10G_RX_ALIGN_ER /**< 10GEC Receive alignment error interrupt */ ++ ,e_FM_MAC_EX_1G_BAB_RX /**< dTSEC Babbling receive error */ ++ ,e_FM_MAC_EX_1G_RX_CTL /**< dTSEC Receive control (pause frame) interrupt */ ++ ,e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET /**< dTSEC Graceful transmit stop complete */ ++ ,e_FM_MAC_EX_1G_BAB_TX /**< dTSEC Babbling transmit error */ ++ ,e_FM_MAC_EX_1G_TX_CTL /**< dTSEC Transmit control (pause frame) interrupt */ ++ ,e_FM_MAC_EX_1G_TX_ERR /**< dTSEC Transmit error */ ++ ,e_FM_MAC_EX_1G_LATE_COL /**< dTSEC Late collision */ ++ ,e_FM_MAC_EX_1G_COL_RET_LMT /**< dTSEC Collision retry limit */ ++ ,e_FM_MAC_EX_1G_TX_FIFO_UNDRN /**< dTSEC Transmit FIFO underrun */ ++ ,e_FM_MAC_EX_1G_MAG_PCKT /**< dTSEC Magic Packet detection */ ++ ,e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET /**< dTSEC MII management read completion */ ++ ,e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET /**< dTSEC MII management write completion */ ++ ,e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET /**< dTSEC Graceful receive stop complete */ ++ ,e_FM_MAC_EX_1G_TX_DATA_ERR /**< dTSEC Internal data error on transmit */ ++ ,e_FM_MAC_EX_1G_RX_DATA_ERR /**< dTSEC Internal data error on receive */ ++ ,e_FM_MAC_EX_1G_1588_TS_RX_ERR /**< dTSEC Time-Stamp Receive Error */ ++ ,e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL /**< dTSEC MIB counter overflow */ ++ ,e_FM_MAC_EX_TS_FIFO_ECC_ERR /**< mEMAC Time-stamp FIFO ECC error interrupt; ++ not supported on T4240/B4860 rev1 chips */ ++ ,e_FM_MAC_EX_MAGIC_PACKET_INDICATION = e_FM_MAC_EX_1G_MAG_PCKT ++ /**< mEMAC Magic Packet Indication Interrupt */ ++} e_FmMacExceptions; ++ ++/**************************************************************************//** ++ @Description TM MAC statistics level ++*//***************************************************************************/ ++typedef enum e_FmMacStatisticsLevel { ++ e_FM_MAC_NONE_STATISTICS = 0, /**< No statistics */ ++ e_FM_MAC_PARTIAL_STATISTICS, /**< Only error counters are available; Optimized for performance */ ++ e_FM_MAC_FULL_STATISTICS /**< All counters available; Not optimized for performance */ ++} e_FmMacStatisticsLevel; ++ ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Description Priority Flow Control Parameters ++*//***************************************************************************/ ++typedef struct t_FmMacPfcParams { ++ bool pfcEnable; /**< Enable/Disable PFC */ ++ ++ uint16_t pauseQuanta[FM_MAX_NUM_OF_PFC_PRIORITIES]; /**< Pause Quanta per priority to be sent in a pause frame. Each quanta represents a 512 bit-times*/ ++ ++ uint16_t pauseThresholdQuanta[FM_MAX_NUM_OF_PFC_PRIORITIES];/**< Pause threshold per priority, when timer passes this threshold time a PFC frames is sent again if the port is still congested or BM pool in depletion*/ ++ ++ ++} t_FmMacPfcParams; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++/**************************************************************************//** ++ @Function t_FmMacExceptionCallback ++ ++ @Description Fm Mac Exception Callback from FM MAC to the user ++ ++ @Param[in] h_App - Handle to the upper layer handler ++ ++ @Param[in] exceptions - The exception that occurred ++ ++ @Return void. ++*//***************************************************************************/ ++typedef void (t_FmMacExceptionCallback)(t_Handle h_App, e_FmMacExceptions exceptions); ++ ++ ++/**************************************************************************//** ++ @Description TM MAC statistics rfc3635 ++*//***************************************************************************/ ++typedef struct t_FmMacStatistics { ++/* RMON */ ++ uint64_t eStatPkts64; /**< r-10G tr-DT 64 byte frame counter */ ++ uint64_t eStatPkts65to127; /**< r-10G 65 to 127 byte frame counter */ ++ uint64_t eStatPkts128to255; /**< r-10G 128 to 255 byte frame counter */ ++ uint64_t eStatPkts256to511; /**< r-10G 256 to 511 byte frame counter */ ++ uint64_t eStatPkts512to1023; /**< r-10G 512 to 1023 byte frame counter */ ++ uint64_t eStatPkts1024to1518; /**< r-10G 1024 to 1518 byte frame counter */ ++ uint64_t eStatPkts1519to1522; /**< r-10G 1519 to 1522 byte good frame count */ ++/* */ ++ uint64_t eStatFragments; /**< Total number of packets that were less than 64 octets long with a wrong CRC.*/ ++ uint64_t eStatJabbers; /**< Total number of packets longer than valid maximum length octets */ ++ uint64_t eStatsDropEvents; /**< number of dropped packets due to internal errors of the MAC Client (during receive). */ ++ uint64_t eStatCRCAlignErrors; /**< Incremented when frames of correct length but with CRC error are received.*/ ++ uint64_t eStatUndersizePkts; /**< Incremented for frames under 64 bytes with a valid FCS and otherwise well formed; ++ This count does not include range length errors */ ++ uint64_t eStatOversizePkts; /**< Incremented for frames which exceed 1518 (non VLAN) or 1522 (VLAN) and contains ++ a valid FCS and otherwise well formed */ ++/* Pause */ ++ uint64_t teStatPause; /**< Pause MAC Control received */ ++ uint64_t reStatPause; /**< Pause MAC Control sent */ ++/* MIB II */ ++ uint64_t ifInOctets; /**< Total number of byte received. */ ++ uint64_t ifInPkts; /**< Total number of packets received.*/ ++ uint64_t ifInUcastPkts; /**< Total number of unicast frame received; ++ NOTE: this counter is not supported on dTSEC MAC */ ++ uint64_t ifInMcastPkts; /**< Total number of multicast frame received*/ ++ uint64_t ifInBcastPkts; /**< Total number of broadcast frame received */ ++ uint64_t ifInDiscards; /**< Frames received, but discarded due to problems within the MAC RX. */ ++ uint64_t ifInErrors; /**< Number of frames received with error: ++ - FIFO Overflow Error ++ - CRC Error ++ - Frame Too Long Error ++ - Alignment Error ++ - The dedicated Error Code (0xfe, not a code error) was received */ ++ uint64_t ifOutOctets; /**< Total number of byte sent. */ ++ uint64_t ifOutPkts; /**< Total number of packets sent .*/ ++ uint64_t ifOutUcastPkts; /**< Total number of unicast frame sent; ++ NOTE: this counter is not supported on dTSEC MAC */ ++ uint64_t ifOutMcastPkts; /**< Total number of multicast frame sent */ ++ uint64_t ifOutBcastPkts; /**< Total number of multicast frame sent */ ++ uint64_t ifOutDiscards; /**< Frames received, but discarded due to problems within the MAC TX N/A!.*/ ++ uint64_t ifOutErrors; /**< Number of frames transmitted with error: ++ - FIFO Overflow Error ++ - FIFO Underflow Error ++ - Other */ ++} t_FmMacStatistics; ++ ++ ++/**************************************************************************//** ++ @Group FM_mac_init_grp FM MAC Initialization Unit ++ ++ @Description FM MAC Initialization Unit ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description FM MAC config input ++*//***************************************************************************/ ++typedef struct t_FmMacParams { ++ uintptr_t baseAddr; /**< Base of memory mapped FM MAC registers */ ++ t_EnetAddr addr; /**< MAC address of device; First octet is sent first */ ++ uint8_t macId; /**< MAC ID; ++ numbering of dTSEC and 1G-mEMAC: ++ 0 - FM_MAX_NUM_OF_1G_MACS; ++ numbering of 10G-MAC (TGEC) and 10G-mEMAC: ++ 0 - FM_MAX_NUM_OF_10G_MACS */ ++ e_EnetMode enetMode; /**< Ethernet operation mode (MAC-PHY interface and speed); ++ Note that the speed should indicate the maximum rate that ++ this MAC should support rather than the actual speed; ++ i.e. user should use the FM_MAC_AdjustLink() routine to ++ provide accurate speed; ++ In case of mEMAC RGMII mode, the MAC is configured to RGMII ++ automatic mode, where actual speed/duplex mode information ++ is provided by PHY automatically in-band; FM_MAC_AdjustLink() ++ function should be used to switch to manual RGMII speed/duplex mode ++ configuration if RGMII PHY doesn't support in-band status signaling; ++ In addition, in mEMAC, in case where user is using the higher MACs ++ (i.e. the MACs that should support 10G), user should pass here ++ speed=10000 even if the interface is not allowing that (e.g. SGMII). */ ++ t_Handle h_Fm; /**< A handle to the FM object this port related to */ ++ int mdioIrq; /**< MDIO exceptions interrupt source - not valid for all ++ MACs; MUST be set to 'NO_IRQ' for MACs that don't have ++ mdio-irq, or for polling */ ++ t_FmMacExceptionCallback *f_Event; /**< MDIO Events Callback Routine */ ++ t_FmMacExceptionCallback *f_Exception; /**< Exception Callback Routine */ ++ t_Handle h_App; /**< A handle to an application layer object; This handle will ++ be passed by the driver upon calling the above callbacks */ ++} t_FmMacParams; ++ ++ ++/**************************************************************************//** ++ @Function FM_MAC_Config ++ ++ @Description Creates descriptor for the FM MAC module. ++ ++ The routine returns a handle (descriptor) to the FM MAC object. ++ This descriptor must be passed as first parameter to all other ++ FM MAC function calls. ++ ++ No actual initialization or configuration of FM MAC hardware is ++ done by this routine. ++ ++ @Param[in] p_FmMacParam - Pointer to data structure of parameters ++ ++ @Retval Handle to FM MAC object, or NULL for Failure. ++*//***************************************************************************/ ++t_Handle FM_MAC_Config(t_FmMacParams *p_FmMacParam); ++ ++/**************************************************************************//** ++ @Function FM_MAC_Init ++ ++ @Description Initializes the FM MAC module ++ ++ @Param[in] h_FmMac - FM module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_MAC_Init(t_Handle h_FmMac); ++ ++/**************************************************************************//** ++ @Function FM_Free ++ ++ @Description Frees all resources that were assigned to FM MAC module. ++ ++ Calling this routine invalidates the descriptor. ++ ++ @Param[in] h_FmMac - FM module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_MAC_Free(t_Handle h_FmMac); ++ ++ ++/**************************************************************************//** ++ @Group FM_mac_advanced_init_grp FM MAC Advanced Configuration Unit ++ ++ @Description Configuration functions used to change default values. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function FM_MAC_ConfigResetOnInit ++ ++ @Description Tell the driver whether to reset the FM MAC before initialization or ++ not. It changes the default configuration [DEFAULT_resetOnInit]. ++ ++ @Param[in] h_FmMac A handle to a FM MAC Module. ++ @Param[in] enable When TRUE, FM will be reset before any initialization. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_ConfigResetOnInit(t_Handle h_FmMac, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_MAC_ConfigLoopback ++ ++ @Description Enable/Disable internal loopback mode ++ ++ @Param[in] h_FmMac A handle to a FM MAC Module. ++ @Param[in] enable TRUE to enable or FALSE to disable. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_ConfigLoopback(t_Handle h_FmMac, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_MAC_ConfigMaxFrameLength ++ ++ @Description Setup maximum Rx Frame Length (in 1G MAC, effects also Tx) ++ ++ @Param[in] h_FmMac A handle to a FM MAC Module. ++ @Param[in] newVal MAX Frame length ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_ConfigMaxFrameLength(t_Handle h_FmMac, uint16_t newVal); ++ ++/**************************************************************************//** ++ @Function FM_MAC_ConfigWan ++ ++ @Description ENABLE WAN mode in 10G-MAC ++ ++ @Param[in] h_FmMac A handle to a FM MAC Module. ++ @Param[in] enable TRUE to enable or FALSE to disable. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_ConfigWan(t_Handle h_FmMac, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_MAC_ConfigPadAndCrc ++ ++ @Description Config PAD and CRC mode ++ ++ @Param[in] h_FmMac A handle to a FM MAC Module. ++ @Param[in] enable TRUE to enable or FALSE to disable. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init(). ++ Not supported on 10G-MAC (i.e. CRC & PAD are added automatically ++ by HW); on mEMAC, this routine supports only PAD (i.e. CRC is ++ added automatically by HW). ++*//***************************************************************************/ ++t_Error FM_MAC_ConfigPadAndCrc(t_Handle h_FmMac, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_MAC_ConfigHalfDuplex ++ ++ @Description Config Half Duplex Mode ++ ++ @Param[in] h_FmMac A handle to a FM MAC Module. ++ @Param[in] enable TRUE to enable or FALSE to disable. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_ConfigHalfDuplex(t_Handle h_FmMac, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_MAC_ConfigTbiPhyAddr ++ ++ @Description Configures the address of internal TBI PHY. ++ ++ @Param[in] h_FmMac A handle to a FM MAC Module. ++ @Param[in] newVal TBI PHY address (1-31). ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_ConfigTbiPhyAddr(t_Handle h_FmMac, uint8_t newVal); ++ ++/**************************************************************************//** ++ @Function FM_MAC_ConfigLengthCheck ++ ++ @Description Configure the frame length checking. ++ ++ @Param[in] h_FmMac A handle to a FM MAC Module. ++ @Param[in] enable TRUE to enable or FALSE to disable. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_ConfigLengthCheck(t_Handle h_FmMac, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_MAC_ConfigException ++ ++ @Description Change Exception selection from default ++ ++ @Param[in] h_FmMac A handle to a FM MAC Module. ++ @Param[in] ex Type of the desired exceptions ++ @Param[in] enable TRUE to enable the specified exception, FALSE to disable it. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Config() and before FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_ConfigException(t_Handle h_FmMac, e_FmMacExceptions ex, bool enable); ++ ++#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 ++t_Error FM_MAC_ConfigSkipFman11Workaround (t_Handle h_FmMac); ++#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ ++/** @} */ /* end of FM_mac_advanced_init_grp group */ ++/** @} */ /* end of FM_mac_init_grp group */ ++ ++ ++/**************************************************************************//** ++ @Group FM_mac_runtime_control_grp FM MAC Runtime Control Unit ++ ++ @Description FM MAC Runtime control unit API functions, definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function FM_MAC_Enable ++ ++ @Description Enable the MAC ++ ++ @Param[in] h_FmMac A handle to a FM MAC Module. ++ @Param[in] mode Mode of operation (RX, TX, Both) ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_Enable(t_Handle h_FmMac, e_CommMode mode); ++ ++/**************************************************************************//** ++ @Function FM_MAC_Disable ++ ++ @Description DISABLE the MAC ++ ++ @Param[in] h_FmMac A handle to a FM MAC Module. ++ @Param[in] mode Define what part to Disable (RX, TX or BOTH) ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_Disable(t_Handle h_FmMac, e_CommMode mode); ++ ++/**************************************************************************//** ++ @Function FM_MAC_Resume ++ ++ @Description Re-init the MAC after suspend ++ ++ @Param[in] h_FmMac A handle to a FM MAC Module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_Resume(t_Handle h_FmMac); ++ ++/**************************************************************************//** ++ @Function FM_MAC_Enable1588TimeStamp ++ ++ @Description Enables the TSU operation. ++ ++ @Param[in] h_Fm - Handle to the PTP as returned from the FM_MAC_PtpConfig. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_Enable1588TimeStamp(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FM_MAC_Disable1588TimeStamp ++ ++ @Description Disables the TSU operation. ++ ++ @Param[in] h_Fm - Handle to the PTP as returned from the FM_MAC_PtpConfig. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_Disable1588TimeStamp(t_Handle h_Fm); ++ ++/**************************************************************************//** ++ @Function FM_MAC_SetTxAutoPauseFrames ++ ++ @Description Enable/Disable transmission of Pause-Frames. ++ The routine changes the default configuration [DEFAULT_TX_PAUSE_TIME]. ++ ++ @Param[in] h_FmMac - A handle to a FM MAC Module. ++ @Param[in] pauseTime - Pause quanta value used with transmitted pause frames. ++ Each quanta represents a 512 bit-times; Note that '0' ++ as an input here will be used as disabling the ++ transmission of the pause-frames. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_SetTxAutoPauseFrames(t_Handle h_FmMac, ++ uint16_t pauseTime); ++ ++ /**************************************************************************//** ++ @Function FM_MAC_SetTxPauseFrames ++ ++ @Description Enable/Disable transmission of Pause-Frames. ++ The routine changes the default configuration: ++ pause-time - [DEFAULT_TX_PAUSE_TIME] ++ threshold-time - [0] ++ ++ @Param[in] h_FmMac - A handle to a FM MAC Module. ++ @Param[in] priority - the PFC class of service; use 'FM_MAC_NO_PFC' ++ to indicate legacy pause support (i.e. no PFC). ++ @Param[in] pauseTime - Pause quanta value used with transmitted pause frames. ++ Each quanta represents a 512 bit-times; ++ Note that '0' as an input here will be used as disabling the ++ transmission of the pause-frames. ++ @Param[in] threshTime - Pause Threshold equanta value used by the MAC to retransmit pause frame. ++ if the situation causing a pause frame to be sent didn't finish when the timer ++ reached the threshold quanta, the MAC will retransmit the pause frame. ++ Each quanta represents a 512 bit-times. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Init(). ++ In order for PFC to work properly the user must configure ++ TNUM-aging in the tx-port it is recommended that pre-fetch and ++ rate limit in the tx port should be disabled; ++ PFC is supported only on new mEMAC; i.e. in MACs that don't have ++ PFC support (10G-MAC and dTSEC), user should use 'FM_MAC_NO_PFC' ++ in the 'priority' field. ++*//***************************************************************************/ ++t_Error FM_MAC_SetTxPauseFrames(t_Handle h_FmMac, ++ uint8_t priority, ++ uint16_t pauseTime, ++ uint16_t threshTime); ++ ++/**************************************************************************//** ++ @Function FM_MAC_SetRxIgnorePauseFrames ++ ++ @Description Enable/Disable ignoring of Pause-Frames. ++ ++ @Param[in] h_FmMac - A handle to a FM MAC Module. ++ @Param[in] en - boolean indicates whether to ignore the incoming pause ++ frames or not. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_SetRxIgnorePauseFrames(t_Handle h_FmMac, bool en); ++ ++/**************************************************************************//** ++ @Function FM_MAC_SetWakeOnLan ++ ++ @Description Enable/Disable Wake On Lan support ++ ++ @Param[in] h_FmMac - A handle to a FM MAC Module. ++ @Param[in] en - boolean indicates whether to enable Wake On Lan ++ support or not. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_SetWakeOnLan(t_Handle h_FmMac, bool en); ++ ++/**************************************************************************//** ++ @Function FM_MAC_ResetCounters ++ ++ @Description reset all statistics counters ++ ++ @Param[in] h_FmMac - A handle to a FM MAC Module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_ResetCounters(t_Handle h_FmMac); ++ ++/**************************************************************************//** ++ @Function FM_MAC_SetException ++ ++ @Description Enable/Disable a specific Exception ++ ++ @Param[in] h_FmMac - A handle to a FM MAC Module. ++ @Param[in] ex - Type of the desired exceptions ++ @Param[in] enable - TRUE to enable the specified exception, FALSE to disable it. ++ ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_SetException(t_Handle h_FmMac, e_FmMacExceptions ex, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_MAC_SetStatistics ++ ++ @Description Define Statistics level. ++ Where applicable, the routine also enables the MIB counters ++ overflow interrupt in order to keep counters accurate ++ and account for overflows. ++ This routine is relevant only for dTSEC. ++ ++ @Param[in] h_FmMac - A handle to a FM MAC Module. ++ @Param[in] statisticsLevel - Full statistics level provides all standard counters but may ++ reduce performance. Partial statistics provides only special ++ event counters (errors etc.). If selected, regular counters (such as ++ byte/packet) will be invalid and will return -1. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_SetStatistics(t_Handle h_FmMac, e_FmMacStatisticsLevel statisticsLevel); ++ ++/**************************************************************************//** ++ @Function FM_MAC_GetStatistics ++ ++ @Description get all statistics counters ++ ++ @Param[in] h_FmMac - A handle to a FM MAC Module. ++ @Param[in] p_Statistics - Structure with statistics ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_GetStatistics(t_Handle h_FmMac, t_FmMacStatistics *p_Statistics); ++ ++/**************************************************************************//** ++ @Function FM_MAC_ModifyMacAddr ++ ++ @Description Replace the main MAC Address ++ ++ @Param[in] h_FmMac - A handle to a FM Module. ++ @Param[in] p_EnetAddr - Ethernet Mac address ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only after FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_ModifyMacAddr(t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); ++ ++/**************************************************************************//** ++ @Function FM_MAC_AddHashMacAddr ++ ++ @Description Add an Address to the hash table. This is for filter purpose only. ++ ++ @Param[in] h_FmMac - A handle to a FM Module. ++ @Param[in] p_EnetAddr - Ethernet Mac address ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Init(). It is a filter only address. ++ @Cautions Some address need to be filterd out in upper FM blocks. ++*//***************************************************************************/ ++t_Error FM_MAC_AddHashMacAddr(t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); ++ ++/**************************************************************************//** ++ @Function FM_MAC_RemoveHashMacAddr ++ ++ @Description Delete an Address to the hash table. This is for filter purpose only. ++ ++ @Param[in] h_FmMac - A handle to a FM Module. ++ @Param[in] p_EnetAddr - Ethernet Mac address ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_RemoveHashMacAddr(t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); ++ ++/**************************************************************************//** ++ @Function FM_MAC_AddExactMatchMacAddr ++ ++ @Description Add a unicast or multicast mac address for exact-match filtering ++ (8 on dTSEC, 2 for 10G-MAC) ++ ++ @Param[in] h_FmMac - A handle to a FM Module. ++ @Param[in] p_EnetAddr - MAC Address to ADD ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only after FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_AddExactMatchMacAddr(t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); ++ ++/**************************************************************************//** ++ @Function FM_MAC_RemovelExactMatchMacAddr ++ ++ @Description Remove a uni cast or multi cast mac address. ++ ++ @Param[in] h_FmMac - A handle to a FM Module. ++ @Param[in] p_EnetAddr - MAC Address to remove ++ ++ @Return E_OK on success; Error code otherwise.. ++ ++ @Cautions Allowed only after FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_RemovelExactMatchMacAddr(t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); ++ ++/**************************************************************************//** ++ @Function FM_MAC_SetPromiscuous ++ ++ @Description Enable/Disable MAC Promiscuous mode for ALL mac addresses. ++ ++ @Param[in] h_FmMac - A handle to a FM MAC Module. ++ @Param[in] enable - TRUE to enable or FALSE to disable. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only after FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_SetPromiscuous(t_Handle h_FmMac, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_MAC_AdjustLink ++ ++ @Description Adjusts the Ethernet link with new speed/duplex setup. ++ This routine is relevant for dTSEC and mEMAC. ++ In case of mEMAC, this routine is also used for manual ++ re-configuration of RGMII speed and duplex mode for ++ RGMII PHYs not supporting in-band status information ++ to MAC. ++ ++ @Param[in] h_FmMac - A handle to a FM Module. ++ @Param[in] speed - Ethernet speed. ++ @Param[in] fullDuplex - TRUE for full-duplex mode; ++ FALSE for half-duplex mode. ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_MAC_AdjustLink(t_Handle h_FmMac, e_EnetSpeed speed, bool fullDuplex); ++ ++/**************************************************************************//** ++ @Function FM_MAC_RestartAutoneg ++ ++ @Description Restarts the auto-negotiation process. ++ When auto-negotiation process is invoked under traffic the ++ auto-negotiation process between the internal SGMII PHY and the ++ external PHY does not always complete successfully. Calling this ++ function will restart the auto-negotiation process that will end ++ successfully. It is recommended to call this function after issuing ++ auto-negotiation restart command to the Eth Phy. ++ This routine is relevant only for dTSEC. ++ ++ @Param[in] h_FmMac - A handle to a FM Module. ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_MAC_RestartAutoneg(t_Handle h_FmMac); ++ ++/**************************************************************************//** ++ @Function FM_MAC_GetId ++ ++ @Description Return the MAC ID ++ ++ @Param[in] h_FmMac - A handle to a FM Module. ++ @Param[out] p_MacId - MAC ID of device ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only after FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_GetId(t_Handle h_FmMac, uint32_t *p_MacId); ++ ++/**************************************************************************//** ++ @Function FM_MAC_GetVesrion ++ ++ @Description Return Mac HW chip version ++ ++ @Param[in] h_FmMac - A handle to a FM Module. ++ @Param[out] p_MacVresion - Mac version as defined by the chip ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only after FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_GetVesrion(t_Handle h_FmMac, uint32_t *p_MacVresion); ++ ++/**************************************************************************//** ++ @Function FM_MAC_MII_WritePhyReg ++ ++ @Description Write data into Phy Register ++ ++ @Param[in] h_FmMac - A handle to a FM Module. ++ @Param[in] phyAddr - Phy Address on the MII bus ++ @Param[in] reg - Register Number. ++ @Param[in] data - Data to write. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only after FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_MII_WritePhyReg(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t data); ++ ++/**************************************************************************//** ++ @Function FM_MAC_MII_ReadPhyReg ++ ++ @Description Read data from Phy Register ++ ++ @Param[in] h_FmMac - A handle to a FM Module. ++ @Param[in] phyAddr - Phy Address on the MII bus ++ @Param[in] reg - Register Number. ++ @Param[out] p_Data - Data from PHY. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only after FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_MII_ReadPhyReg(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data); ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++/**************************************************************************//** ++ @Function FM_MAC_DumpRegs ++ ++ @Description Dump internal registers ++ ++ @Param[in] h_FmMac - A handle to a FM Module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only after FM_MAC_Init(). ++*//***************************************************************************/ ++t_Error FM_MAC_DumpRegs(t_Handle h_FmMac); ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++/** @} */ /* end of FM_mac_runtime_control_grp group */ ++/** @} */ /* end of FM_mac_grp group */ ++/** @} */ /* end of FM_grp group */ ++ ++ ++#endif /* __FM_MAC_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_macsec_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_macsec_ext.h +new file mode 100644 +index 00000000..57925f10 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_macsec_ext.h +@@ -0,0 +1,1271 @@ ++/* ++ * Copyright 2008-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/**************************************************************************//** ++ @File fm_macsec_ext.h ++ ++ @Description FM MACSEC ... ++*//***************************************************************************/ ++#ifndef __FM_MACSEC_EXT_H ++#define __FM_MACSEC_EXT_H ++ ++#include "std_ext.h" ++ ++ ++/**************************************************************************//** ++ @Group FM_grp Frame Manager API ++ ++ @Description FM API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group FM_MACSEC_grp FM MACSEC ++ ++ @Description FM MACSEC API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description MACSEC Exceptions ++*//***************************************************************************/ ++typedef enum e_FmMacsecExceptions { ++ e_FM_MACSEC_EX_SINGLE_BIT_ECC, /**< Single bit ECC error */ ++ e_FM_MACSEC_EX_MULTI_BIT_ECC /**< Multi bit ECC error */ ++} e_FmMacsecExceptions; ++ ++ ++/**************************************************************************//** ++ @Group FM_MACSEC_init_grp FM-MACSEC Initialization Unit ++ ++ @Description FM MACSEC Initialization Unit ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function t_FmMacsecExceptionsCallback ++ ++ @Description Exceptions user callback routine, will be called upon an ++ exception passing the exception identification. ++ ++ @Param[in] h_App A handle to an application layer object; This handle ++ will be passed by the driver upon calling this callback. ++ @Param[in] exception The exception. ++*//***************************************************************************/ ++typedef void (t_FmMacsecExceptionsCallback) ( t_Handle h_App, ++ e_FmMacsecExceptions exception); ++ ++ ++/**************************************************************************//** ++ @Description FM MACSEC config input ++*//***************************************************************************/ ++typedef struct t_FmMacsecParams { ++ t_Handle h_Fm; /**< A handle to the FM object related to */ ++ bool guestMode; /**< Partition-id */ ++ union { ++ struct { ++ uint8_t fmMacId; /**< FM MAC id */ ++ } guestParams; ++ ++ struct { ++ uintptr_t baseAddr; /**< Base of memory mapped FM MACSEC registers */ ++ t_Handle h_FmMac; /**< A handle to the FM MAC object related to */ ++ t_FmMacsecExceptionsCallback *f_Exception; /**< Exception Callback Routine */ ++ t_Handle h_App; /**< A handle to an application layer object; This handle will ++ be passed by the driver upon calling the above callbacks */ ++ } nonGuestParams; ++ }; ++} t_FmMacsecParams; ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_Config ++ ++ @Description Creates descriptor for the FM MACSEC module; ++ ++ The routine returns a handle (descriptor) to the FM MACSEC object; ++ This descriptor must be passed as first parameter to all other ++ FM MACSEC function calls; ++ ++ No actual initialization or configuration of FM MACSEC hardware is ++ done by this routine. ++ ++ @Param[in] p_FmMacsecParam Pointer to data structure of parameters. ++ ++ @Retval Handle to FM MACSEC object, or NULL for Failure. ++*//***************************************************************************/ ++t_Handle FM_MACSEC_Config(t_FmMacsecParams *p_FmMacsecParam); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_Init ++ ++ @Description Initializes the FM MACSEC module. ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_MACSEC_Init(t_Handle h_FmMacsec); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_Free ++ ++ @Description Frees all resources that were assigned to FM MACSEC module; ++ ++ Calling this routine invalidates the descriptor. ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_MACSEC_Free(t_Handle h_FmMacsec); ++ ++ ++/**************************************************************************//** ++ @Group FM_MACSEC_advanced_init_grp FM-MACSEC Advanced Configuration Unit ++ ++ @Description Configuration functions used to change default values. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description enum for unknown sci frame treatment ++*//***************************************************************************/ ++typedef enum e_FmMacsecUnknownSciFrameTreatment { ++ e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DISCARD_BOTH = 0, /**< Controlled port - Strict mode */ ++ e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DISCARD_UNCONTROLLED_DELIVER_OR_DISCARD_CONTROLLED, /**< If C bit clear deliver on controlled port, else discard ++ Controlled port - Check or Disable mode */ ++ e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DELIVER_UNCONTROLLED_DISCARD_CONTROLLED, /**< Controlled port - Strict mode */ ++ e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DELIVER_OR_DISCARD_UNCONTROLLED_DELIVER_OR_DISCARD_CONTROLLED /**< If C bit set deliver on uncontrolled port and discard on controlled port, ++ else discard on uncontrolled port and deliver on controlled port ++ Controlled port - Check or Disable mode */ ++} e_FmMacsecUnknownSciFrameTreatment; ++ ++/**************************************************************************//** ++ @Description enum for untag frame treatment ++*//***************************************************************************/ ++typedef enum e_FmMacsecUntagFrameTreatment { ++ e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DELIVER_UNCONTROLLED_DISCARD_CONTROLLED = 0, /**< Controlled port - Strict mode */ ++ e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DISCARD_BOTH, /**< Controlled port - Strict mode */ ++ e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DISCARD_UNCONTROLLED_DELIVER_CONTROLLED_UNMODIFIED /**< Controlled port - Strict mode */ ++} e_FmMacsecUntagFrameTreatment; ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_ConfigUnknownSciFrameTreatment ++ ++ @Description Change the treatment for received frames with unknown sci from its default ++ configuration [DEFAULT_unknownSciFrameTreatment]. ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ @Param[in] treatMode The selected mode. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_ConfigUnknownSciFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUnknownSciFrameTreatment treatMode); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_ConfigInvalidTagsFrameTreatment ++ ++ @Description Change the treatment for received frames with invalid tags or ++ a zero value PN or an invalid ICV from its default configuration ++ [DEFAULT_invalidTagsFrameTreatment]. ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ @Param[in] deliverUncontrolled If True deliver on the uncontrolled port, else discard; ++ In both cases discard on the controlled port; ++ this provide Strict, Check or Disable mode. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_ConfigInvalidTagsFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment ++ ++ @Description Change the treatment for received frames with the Encryption bit ++ set and the Changed Text bit clear from its default configuration ++ [DEFAULT_encryptWithNoChangedTextFrameTreatment]. ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ @Param[in] discardUncontrolled If True discard on the uncontrolled port, else deliver; ++ In both cases discard on the controlled port; ++ this provide Strict, Check or Disable mode. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment(t_Handle h_FmMacsec, bool discardUncontrolled); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_ConfigChangedTextWithNoEncryptFrameTreatment ++ ++ @Description Change the treatment for received frames with the Encryption bit ++ clear and the Changed Text bit set from its default configuration ++ [DEFAULT_changedTextWithNoEncryptFrameTreatment]. ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ @Param[in] deliverUncontrolled If True deliver on the uncontrolled port, else discard; ++ In both cases discard on the controlled port; ++ this provide Strict, Check or Disable mode. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_ConfigChangedTextWithNoEncryptFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_ConfigUntagFrameTreatment ++ ++ @Description Change the treatment for received frames without the MAC security tag (SecTAG) ++ from its default configuration [DEFAULT_untagFrameTreatment]. ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ @Param[in] treatMode The selected mode. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_ConfigUntagFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUntagFrameTreatment treatMode); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_ConfigOnlyScbIsSetFrameTreatment ++ ++ @Description Change the treatment for received frames with only SCB bit set ++ from its default configuration [DEFAULT_onlyScbIsSetFrameTreatment]. ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ @Param[in] deliverUncontrolled If True deliver on the uncontrolled port, else discard; ++ In both cases discard on the controlled port; ++ this provide Strict, Check or Disable mode. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_ConfigOnlyScbIsSetFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_ConfigPnExhaustionThreshold ++ ++ @Description It's provide the ability to configure a PN exhaustion threshold; ++ When the NextPn crosses this value an interrupt event ++ is asserted to warn that the active SA should re-key. ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ @Param[in] pnExhThr If the threshold is reached, an interrupt event ++ is asserted to re-key. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_ConfigPnExhaustionThreshold(t_Handle h_FmMacsec, uint32_t pnExhThr); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_ConfigKeysUnreadable ++ ++ @Description Turn on privacy mode; All the keys and their hash values can't be read any more; ++ Can not be cleared unless hard reset. ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_ConfigKeysUnreadable(t_Handle h_FmMacsec); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_ConfigSectagWithoutSCI ++ ++ @Description Promise that all generated Sectag will be without SCI included. ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_ConfigSectagWithoutSCI(t_Handle h_FmMacsec); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_ConfigException ++ ++ @Description Calling this routine changes the internal driver data base ++ from its default selection of exceptions enablement; ++ By default all exceptions are enabled. ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ @Param[in] exception The exception to be selected. ++ @Param[in] enable TRUE to enable interrupt, FALSE to mask it. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_Config() and before FM_MACSEC_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_ConfigException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable); ++ ++/** @} */ /* end of FM_MACSEC_advanced_init_grp group */ ++/** @} */ /* end of FM_MACSEC_init_grp group */ ++ ++ ++/**************************************************************************//** ++ @Group FM_MACSEC_runtime_control_grp FM-MACSEC Runtime Control Data Unit ++ ++ @Description FM MACSEC runtime control data unit API functions, definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_GetRevision ++ ++ @Description Return MACSEC HW chip revision ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ @Param[out] p_MacsecRevision MACSEC revision as defined by the chip. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only after FM_MACSEC_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_GetRevision(t_Handle h_FmMacsec, uint32_t *p_MacsecRevision); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_Enable ++ ++ @Description This routine should be called after MACSEC is initialized for enabling all ++ MACSEC engines according to their existing configuration. ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_Init() and when MACSEC is disabled. ++*//***************************************************************************/ ++t_Error FM_MACSEC_Enable(t_Handle h_FmMacsec); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_Disable ++ ++ @Description This routine may be called when MACSEC is enabled in order to ++ disable all MACSEC engines; The MACSEC is working in bypass mode. ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_Init() and when MACSEC is enabled. ++*//***************************************************************************/ ++t_Error FM_MACSEC_Disable(t_Handle h_FmMacsec); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SetException ++ ++ @Description Calling this routine enables/disables the specified exception. ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ @Param[in] exception The exception to be selected. ++ @Param[in] enable TRUE to enable interrupt, FALSE to mask it. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SetException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable); ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++/**************************************************************************//** ++ @Function FM_MACSEC_DumpRegs ++ ++ @Description Dump internal registers. ++ ++ @Param[in] h_FmMacsec - FM MACSEC module descriptor. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only after FM_MACSEC_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_DumpRegs(t_Handle h_FmMacsec); ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++#ifdef VERIFICATION_SUPPORT ++/********************* VERIFICATION ONLY ********************************/ ++/**************************************************************************//** ++ @Function FM_MACSEC_BackdoorSet ++ ++ @Description Set register of the MACSEC memory map ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ @Param[out] offset Register offset. ++ @Param[out] value Value to write. ++ ++ ++ @Return None ++ ++ @Cautions Allowed only following FM_MACSEC_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_BackdoorSet(t_Handle h_FmMacsec, uint32_t offset, uint32_t value); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_BackdoorGet ++ ++ @Description Read from register of the MACSEC memory map. ++ ++ @Param[in] h_FmMacsec FM MACSEC module descriptor. ++ @Param[out] offset Register offset. ++ ++ @Return Value read ++ ++ @Cautions Allowed only following FM_MACSEC_Init(). ++*//***************************************************************************/ ++uint32_t FM_MACSEC_BackdoorGet(t_Handle h_FmMacsec, uint32_t offset); ++#endif /* VERIFICATION_SUPPORT */ ++ ++/** @} */ /* end of FM_MACSEC_runtime_control_grp group */ ++ ++ ++/**************************************************************************//** ++ @Group FM_MACSEC_SECY_grp FM-MACSEC SecY ++ ++ @Description FM-MACSEC SecY API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++typedef uint8_t macsecSAKey_t[32]; ++typedef uint64_t macsecSCI_t; ++typedef uint8_t macsecAN_t; ++ ++/**************************************************************************//** ++@Description MACSEC SECY Cipher Suite ++*//***************************************************************************/ ++typedef enum e_FmMacsecSecYCipherSuite { ++ e_FM_MACSEC_SECY_GCM_AES_128 = 0, /**< GCM-AES-128 */ ++#if (DPAA_VERSION >= 11) ++ e_FM_MACSEC_SECY_GCM_AES_256 /**< GCM-AES-256 */ ++#endif /* (DPAA_VERSION >= 11) */ ++} e_FmMacsecSecYCipherSuite; ++ ++/**************************************************************************//** ++ @Description MACSEC SECY Exceptions ++*//***************************************************************************/ ++typedef enum e_FmMacsecSecYExceptions { ++ e_FM_MACSEC_SECY_EX_FRAME_DISCARDED /**< Frame Discarded */ ++} e_FmMacsecSecYExceptions; ++ ++/**************************************************************************//** ++ @Description MACSEC SECY Events ++*//***************************************************************************/ ++typedef enum e_FmMacsecSecYEvents { ++ e_FM_MACSEC_SECY_EV_NEXT_PN /**< Next Packet Number exhaustion threshold reached */ ++} e_FmMacsecSecYEvents; ++ ++/**************************************************************************//** ++ @Collection MACSEC SECY Frame Discarded Descriptor error ++*//***************************************************************************/ ++typedef uint8_t macsecTxScFrameDiscardedErrSelect_t; /**< typedef for defining Frame Discarded Descriptor errors */ ++ ++#define FM_MACSEC_SECY_TX_SC_FRM_DISCAR_ERR_NEXT_PN_ZERO 0x8000 /**< NextPn == 0 */ ++#define FM_MACSEC_SECY_TX_SC_FRM_DISCAR_ERR_SC_DISBALE 0x4000 /**< SC is disable */ ++/* @} */ ++ ++/**************************************************************************//** ++ @Function t_FmMacsecSecYExceptionsCallback ++ ++ @Description Exceptions user callback routine, will be called upon an ++ exception passing the exception identification. ++ ++ @Param[in] h_App A handle to an application layer object; This handle ++ will be passed by the driver upon calling this callback. ++ @Param[in] exception The exception. ++*//***************************************************************************/ ++typedef void (t_FmMacsecSecYExceptionsCallback) ( t_Handle h_App, ++ e_FmMacsecSecYExceptions exception); ++ ++/**************************************************************************//** ++ @Function t_FmMacsecSecYEventsCallback ++ ++ @Description Events user callback routine, will be called upon an ++ event passing the event identification. ++ ++ @Param[in] h_App A handle to an application layer object; This handle ++ will be passed by the driver upon calling this callback. ++ @Param[in] event The event. ++*//***************************************************************************/ ++typedef void (t_FmMacsecSecYEventsCallback) ( t_Handle h_App, ++ e_FmMacsecSecYEvents event); ++ ++/**************************************************************************//** ++ @Description RFC2863 MIB ++*//***************************************************************************/ ++typedef struct t_MIBStatistics { ++ uint64_t ifInOctets; /**< Total number of byte received */ ++ uint64_t ifInPkts; /**< Total number of packets received */ ++ uint64_t ifInMcastPkts; /**< Total number of multicast frame received */ ++ uint64_t ifInBcastPkts; /**< Total number of broadcast frame received */ ++ uint64_t ifInDiscards; /**< Frames received, but discarded due to problems within the MAC RX : ++ - InPktsNoTag, ++ - InPktsLate, ++ - InPktsOverrun */ ++ uint64_t ifInErrors; /**< Number of frames received with error: ++ - InPktsBadTag, ++ - InPktsNoSCI, ++ - InPktsNotUsingSA ++ - InPktsNotValid */ ++ uint64_t ifOutOctets; /**< Total number of byte sent */ ++ uint64_t ifOutPkts; /**< Total number of packets sent */ ++ uint64_t ifOutMcastPkts; /**< Total number of multicast frame sent */ ++ uint64_t ifOutBcastPkts; /**< Total number of multicast frame sent */ ++ uint64_t ifOutDiscards; /**< Frames received, but discarded due to problems within the MAC TX N/A! */ ++ uint64_t ifOutErrors; /**< Number of frames transmitted with error: ++ - FIFO Overflow Error ++ - FIFO Underflow Error ++ - Other */ ++} t_MIBStatistics; ++ ++/**************************************************************************//** ++ @Description MACSEC SecY Rx SA Statistics ++*//***************************************************************************/ ++typedef struct t_FmMacsecSecYRxSaStatistics { ++ uint32_t inPktsOK; /**< The number of frames with resolved SCI, have passed all ++ frame validation frame validation with the validateFrame not set to disable */ ++ uint32_t inPktsInvalid; /**< The number of frames with resolved SCI, that have failed frame ++ validation with the validateFrame set to check */ ++ uint32_t inPktsNotValid; /**< The number of frames with resolved SCI, discarded on the controlled port, ++ that have failed frame validation with the validateFrame set to strict or the c bit is set */ ++ uint32_t inPktsNotUsingSA; /**< The number of frames received with resolved SCI and discarded on disabled or ++ not provisioned SA with validateFrame in the strict mode or the C bit is set */ ++ uint32_t inPktsUnusedSA; /**< The number of frames received with resolved SCI on disabled or not provisioned SA ++ with validateFrame not in the strict mode and the C bit is cleared */ ++} t_FmMacsecSecYRxSaStatistics; ++ ++/**************************************************************************//** ++ @Description MACSEC SecY Tx SA Statistics ++*//***************************************************************************/ ++typedef struct t_FmMacsecSecYTxSaStatistics { ++ uint64_t outPktsProtected; /**< The number of frames, that the user of the controlled port requested to ++ be transmitted, which were integrity protected */ ++ uint64_t outPktsEncrypted; /**< The number of frames, that the user of the controlled port requested to ++ be transmitted, which were confidentiality protected */ ++} t_FmMacsecSecYTxSaStatistics; ++ ++/**************************************************************************//** ++ @Description MACSEC SecY Rx SC Statistics ++*//***************************************************************************/ ++typedef struct t_FmMacsecSecYRxScStatistics { ++ uint64_t inPktsUnchecked; /**< The number of frames with resolved SCI, delivered to the user of a controlled port, ++ that are not validated with the validateFrame set to disable */ ++ uint64_t inPktsDelayed; /**< The number of frames with resolved SCI, delivered to the user of a controlled port, ++ that have their PN smaller than the lowest_PN with the validateFrame set to ++ disable or replayProtect disabled */ ++ uint64_t inPktsLate; /**< The number of frames with resolved SCI, discarded on the controlled port, ++ that have their PN smaller than the lowest_PN with the validateFrame set to ++ Check or Strict and replayProtect enabled */ ++ uint64_t inPktsOK; /**< The number of frames with resolved SCI, have passed all ++ frame validation frame validation with the validateFrame not set to disable */ ++ uint64_t inPktsInvalid; /**< The number of frames with resolved SCI, that have failed frame ++ validation with the validateFrame set to check */ ++ uint64_t inPktsNotValid; /**< The number of frames with resolved SCI, discarded on the controlled port, ++ that have failed frame validation with the validateFrame set to strict or the c bit is set */ ++ uint64_t inPktsNotUsingSA; /**< The number of frames received with resolved SCI and discarded on disabled or ++ not provisioned SA with validateFrame in the strict mode or the C bit is set */ ++ uint64_t inPktsUnusedSA; /**< The number of frames received with resolved SCI on disabled or not provisioned SA ++ with validateFrame not in the strict mode and the C bit is cleared */ ++} t_FmMacsecSecYRxScStatistics; ++ ++/**************************************************************************//** ++ @Description MACSEC SecY Tx SC Statistics ++*//***************************************************************************/ ++typedef struct t_FmMacsecSecYTxScStatistics { ++ uint64_t outPktsProtected; /**< The number of frames, that the user of the controlled port requested to ++ be transmitted, which were integrity protected */ ++ uint64_t outPktsEncrypted; /**< The number of frames, that the user of the controlled port requested to ++ be transmitted, which were confidentiality protected */ ++} t_FmMacsecSecYTxScStatistics; ++ ++/**************************************************************************//** ++ @Description MACSEC SecY Statistics ++*//***************************************************************************/ ++typedef struct t_FmMacsecSecYStatistics { ++ t_MIBStatistics mibCtrlStatistics; /**< Controlled port MIB statistics */ ++ t_MIBStatistics mibNonCtrlStatistics; /**< Uncontrolled port MIB statistics */ ++/* Frame verification statistics */ ++ uint64_t inPktsUntagged; /**< The number of received packets without the MAC security tag ++ (SecTAG) with validateFrames which is not in the strict mode */ ++ uint64_t inPktsNoTag; /**< The number of received packets discarded without the ++ MAC security tag (SecTAG) with validateFrames which is in the strict mode */ ++ uint64_t inPktsBadTag; /**< The number of received packets discarded with an invalid ++ SecTAG or a zero value PN or an invalid ICV */ ++ uint64_t inPktsUnknownSCI; /**< The number of received packets with unknown SCI with the ++ condition : validateFrames is not in the strict mode and the ++ C bit in the SecTAG is not set */ ++ uint64_t inPktsNoSCI; /**< The number of received packets discarded with unknown SCI ++ information with the condition : validateFrames is in the strict mode ++ or the C bit in the SecTAG is set */ ++ uint64_t inPktsOverrun; /**< The number of packets discarded because the number of ++ received packets exceeded the cryptographic performance capabilities */ ++/* Frame validation statistics */ ++ uint64_t inOctetsValidated; /**< The number of octets of plaintext recovered from received frames with ++ resolved SCI that were integrity protected but not encrypted */ ++ uint64_t inOctetsDecrypted; /**< The number of octets of plaintext recovered from received frames with ++ resolved SCI that were integrity protected and encrypted */ ++/* Frame generation statistics */ ++ uint64_t outPktsUntagged; /**< The number of frames, that the user of the controlled port requested to ++ be transmitted, with protectFrame false */ ++ uint64_t outPktsTooLong; /**< The number of frames, that the user of the controlled port requested to ++ be transmitted, discarded due to length being larger than Maximum Frame Length (MACSEC_MFL) */ ++/* Frame protection statistics */ ++ uint64_t outOctetsProtected; /**< The number of octets of User Data in transmitted frames that were ++ integrity protected but not encrypted */ ++ uint64_t outOctetsEncrypted; /**< The number of octets of User Data in transmitted frames that were ++ both integrity protected and encrypted */ ++} t_FmMacsecSecYStatistics; ++ ++ ++/**************************************************************************//** ++ @Description MACSEC SecY SC Params ++*//***************************************************************************/ ++typedef struct t_FmMacsecSecYSCParams { ++ macsecSCI_t sci; /**< The secure channel identification of the SC */ ++ e_FmMacsecSecYCipherSuite cipherSuite; /**< Cipher suite to be used for the SC */ ++} t_FmMacsecSecYSCParams; ++ ++/**************************************************************************//** ++ @Group FM_MACSEC_SECY_init_grp FM-MACSEC SecY Initialization Unit ++ ++ @Description FM-MACSEC SecY Initialization Unit ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description enum for validate frames ++*//***************************************************************************/ ++typedef enum e_FmMacsecValidFrameBehavior { ++ e_FM_MACSEC_VALID_FRAME_BEHAVIOR_DISABLE = 0, /**< disable the validation function */ ++ e_FM_MACSEC_VALID_FRAME_BEHAVIOR_CHECK, /**< enable the validation function but only for checking ++ without filtering out invalid frames */ ++ e_FM_MACSEC_VALID_FRAME_BEHAVIOR_STRICT /**< enable the validation function and also strictly filter ++ out those invalid frames */ ++} e_FmMacsecValidFrameBehavior; ++ ++/**************************************************************************//** ++ @Description enum for sci insertion ++*//***************************************************************************/ ++typedef enum e_FmMacsecSciInsertionMode { ++ e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_SECTAG = 0, /**< explicit sci in the sectag */ ++ e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_MAC_SA, /**< mac sa is overwritten with the sci*/ ++ e_FM_MACSEC_SCI_INSERTION_MODE_IMPLICT_PTP /**< implicit point-to-point sci (pre-shared) */ ++} e_FmMacsecSciInsertionMode; ++ ++/**************************************************************************//** ++ @Description FM MACSEC SecY config input ++*//***************************************************************************/ ++typedef struct t_FmMacsecSecYParams { ++ t_Handle h_FmMacsec; /**< A handle to the FM MACSEC object */ ++ t_FmMacsecSecYSCParams txScParams; /**< Tx SC Params */ ++ uint32_t numReceiveChannels; /**< Number of receive channels dedicated to this SecY */ ++ t_FmMacsecSecYExceptionsCallback *f_Exception; /**< Callback routine to be called by the driver upon SecY exception */ ++ t_FmMacsecSecYEventsCallback *f_Event; /**< Callback routine to be called by the driver upon SecY event */ ++ t_Handle h_App; /**< A handle to an application layer object; This handle will ++ be passed by the driver upon calling the above callbacks */ ++} t_FmMacsecSecYParams; ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_Config ++ ++ @Description Creates descriptor for the FM MACSEC SECY module; ++ ++ The routine returns a handle (descriptor) to the FM MACSEC SECY object; ++ This descriptor must be passed as first parameter to all other ++ FM MACSEC SECY function calls; ++ No actual initialization or configuration of FM MACSEC SecY hardware is ++ done by this routine. ++ ++ @Param[in] p_FmMacsecSecYParam Pointer to data structure of parameters. ++ ++ @Return Handle to FM MACSEC SECY object, or NULL for Failure. ++*//***************************************************************************/ ++t_Handle FM_MACSEC_SECY_Config(t_FmMacsecSecYParams *p_FmMacsecSecYParam); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_Init ++ ++ @Description Initializes the FM MACSEC SECY module. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_Init(t_Handle h_FmMacsecSecY); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_Free ++ ++ @Description Frees all resources that were assigned to FM MACSEC SECY module. ++ ++ Calling this routine invalidates the descriptor. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_Free(t_Handle h_FmMacsecSecY); ++ ++/**************************************************************************//** ++ @Group FM_MACSEC_SECY_advanced_init_grp FM-MACSEC SecY Advanced Configuration Unit ++ ++ @Description Configuration functions used to change default values. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_ConfigSciInsertionMode ++ ++ @Description Calling this routine changes the SCI-insertion-mode in the ++ internal driver data base from its default configuration ++ [DEFAULT_sciInsertionMode] ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] sciInsertionMode Sci insertion mode ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init(); ++ ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_ConfigSciInsertionMode(t_Handle h_FmMacsecSecY, e_FmMacsecSciInsertionMode sciInsertionMode); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_ConfigProtectFrames ++ ++ @Description Calling this routine changes the protect-frame mode in the ++ internal driver data base from its default configuration ++ [DEFAULT_protectFrames] ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] protectFrames If FALSE, frames are transmitted without modification ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init(); ++ ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_ConfigProtectFrames(t_Handle h_FmMacsecSecY, bool protectFrames); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_ConfigReplayWindow ++ ++ @Description Calling this routine changes the replay-window settings in the ++ internal driver data base from its default configuration ++ [DEFAULT_replayEnable], [DEFAULT_replayWindow] ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] replayProtect; Replay protection function mode ++ @Param[in] replayWindow; The size of the replay window ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init(); ++ ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_ConfigReplayWindow(t_Handle h_FmMacsecSecY, bool replayProtect, uint32_t replayWindow); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_ConfigValidationMode ++ ++ @Description Calling this routine changes the frame-validation-behavior mode ++ in the internal driver data base from its default configuration ++ [DEFAULT_validateFrames] ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] validateFrames Validation function mode ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init(); ++ ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_ConfigValidationMode(t_Handle h_FmMacsecSecY, e_FmMacsecValidFrameBehavior validateFrames); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_ConfigConfidentiality ++ ++ @Description Calling this routine changes the confidentiality settings in the ++ internal driver data base from its default configuration ++ [DEFAULT_confidentialityEnable], [DEFAULT_confidentialityOffset] ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] confidentialityEnable TRUE - confidentiality protection and integrity protection ++ FALSE - no confidentiality protection, only integrity protection ++ @Param[in] confidentialityOffset The number of initial octets of each MSDU without confidentiality protection ++ common values are 0, 30, and 50 ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init(); ++ ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_ConfigConfidentiality(t_Handle h_FmMacsecSecY, bool confidentialityEnable, uint16_t confidentialityOffset); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_ConfigPointToPoint ++ ++ @Description configure this SecY to work in point-to-point mode, means that ++ it will have only one rx sc; ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init(); ++ Can be called only once in a system; only the first secY that will call this ++ routine will be able to operate in Point-To-Point mode. ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_ConfigPointToPoint(t_Handle h_FmMacsecSecY); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_ConfigException ++ ++ @Description Calling this routine changes the internal driver data base ++ from its default selection of exceptions enablement; ++ By default all exceptions are enabled. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] exception The exception to be selected. ++ @Param[in] enable TRUE to enable interrupt, FALSE to mask it. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_ConfigException(t_Handle h_FmMacsecSecY, e_FmMacsecSecYExceptions exception, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_ConfigEvent ++ ++ @Description Calling this routine changes the internal driver data base ++ from its default selection of events enablement; ++ By default all events are enabled. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] event The event to be selected. ++ @Param[in] enable TRUE to enable interrupt, FALSE to mask it. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_ConfigEvent(t_Handle h_FmMacsecSecY, e_FmMacsecSecYEvents event, bool enable); ++ ++/** @} */ /* end of FM_MACSEC_SECY_advanced_init_grp group */ ++/** @} */ /* end of FM_MACSEC_SECY_init_grp group */ ++ ++ ++/**************************************************************************//** ++ @Group FM_MACSEC_SECY_runtime_control_grp FM-MACSEC SecY Runtime Control Unit ++ ++ @Description FM MACSEC SECY Runtime control unit API functions, definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_CreateRxSc ++ ++ @Description Create a receive secure channel. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] scParams secure channel params. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Init(). ++*//***************************************************************************/ ++t_Handle FM_MACSEC_SECY_CreateRxSc(t_Handle h_FmMacsecSecY, t_FmMacsecSecYSCParams *p_ScParams); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_DeleteRxSc ++ ++ @Description Deleting an initialized secure channel. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_CreateRxSc(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_DeleteRxSc(t_Handle h_FmMacsecSecY, t_Handle h_Sc); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_CreateRxSa ++ ++ @Description Create a receive secure association for the secure channel; ++ the SA cannot be used to receive frames until FM_MACSEC_SECY_RxSaEnableReceive is called. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc. ++ @Param[in] an association number represent the SA. ++ @Param[in] lowestPn the lowest acceptable PN value for a received frame. ++ @Param[in] key the desired key for this SA. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_CreateRxSc(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_CreateRxSa(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t lowestPn, macsecSAKey_t key); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_DeleteRxSa ++ ++ @Description Deleting an initialized secure association. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc. ++ @Param[in] an association number represent the SA. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_DeleteRxSa(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_RxSaEnableReceive ++ ++ @Description Enabling the SA to receive frames. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc. ++ @Param[in] an association number represent the SA. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_CreateRxSa(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_RxSaEnableReceive(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_RxSaDisableReceive ++ ++ @Description Disabling the SA from receive frames. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc. ++ @Param[in] an association number represent the SA. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_CreateRxSa(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_RxSaDisableReceive(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_RxSaUpdateNextPn ++ ++ @Description Update the next packet number expected on RX; ++ The value of nextPN shall be set to the greater of its existing value and the ++ supplied of updtNextPN (802.1AE-2006 10.7.15). ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc. ++ @Param[in] an association number represent the SA. ++ @Param[in] updtNextPN the next PN value for a received frame. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_CreateRxSa(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_RxSaUpdateNextPn(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t updtNextPN); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_RxSaUpdateLowestPn ++ ++ @Description Update the lowest packet number expected on RX; ++ The value of lowestPN shall be set to the greater of its existing value and the ++ supplied of updtLowestPN (802.1AE-2006 10.7.15). ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc. ++ @Param[in] an association number represent the SA. ++ @Param[in] updtLowestPN the lowest PN acceptable value for a received frame. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_CreateRxSa(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_RxSaUpdateLowestPn(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t updtLowestPN); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_RxSaModifyKey ++ ++ @Description Modify the current key of the SA with a new one. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc. ++ @Param[in] an association number represent the SA. ++ @Param[in] key new key to replace the current key. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_CreateRxSa(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_RxSaModifyKey(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, macsecSAKey_t key); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_CreateTxSa ++ ++ @Description Create a transmit secure association for the secure channel; ++ the SA cannot be used to transmit frames until FM_MACSEC_SECY_TxSaSetActivate is called; ++ Only one SA can be active at a time. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] an association number represent the SA. ++ @Param[in] key the desired key for this SA. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_CreateTxSa(t_Handle h_FmMacsecSecY, macsecAN_t an, macsecSAKey_t key); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_DeleteTxSa ++ ++ @Description Deleting an initialized secure association. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] an association number represent the SA. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_DeleteTxSa(t_Handle h_FmMacsecSecY, macsecAN_t an); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_TxSaModifyKey ++ ++ @Description Modify the key of the inactive SA with a new one. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] nextActiveAn association number represent the next SA to be activated. ++ @Param[in] key new key to replace the current key. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_TxSaModifyKey(t_Handle h_FmMacsecSecY, macsecAN_t nextActiveAn, macsecSAKey_t key); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_TxSaSetActive ++ ++ @Description Set this SA to the active SA to be used on TX for SC; ++ only one SA can be active at a time. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] an association number represent the SA. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_TxSaSetActive(t_Handle h_FmMacsecSecY, macsecAN_t an); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_TxSaGetActive ++ ++ @Description Get the active SA that being used for TX. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[out] p_An the active an. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_TxSaGetActive(t_Handle h_FmMacsecSecY, macsecAN_t *p_An); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_GetStatistics ++ ++ @Description get all statistics counters. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] p_Statistics Structure with statistics. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_GetStatistics(t_Handle h_FmMacsecSecY, t_FmMacsecSecYStatistics *p_Statistics); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_RxScGetStatistics ++ ++ @Description get all statistics counters. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] h_Sc Rx Sc handle. ++ @Param[in] p_Statistics Structure with statistics. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_RxScGetStatistics(t_Handle h_FmMacsecSecY, t_Handle h_Sc, t_FmMacsecSecYRxScStatistics *p_Statistics); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_RxSaGetStatistics ++ ++ @Description get all statistics counters ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] h_Sc Rx Sc handle. ++ @Param[in] an association number represent the SA. ++ @Param[in] p_Statistics Structure with statistics. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_RxSaGetStatistics(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, t_FmMacsecSecYRxSaStatistics *p_Statistics); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_TxScGetStatistics ++ ++ @Description get all statistics counters. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] p_Statistics Structure with statistics. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_TxScGetStatistics(t_Handle h_FmMacsecSecY, t_FmMacsecSecYTxScStatistics *p_Statistics); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_TxSaGetStatistics ++ ++ @Description get all statistics counters. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] an association number represent the SA. ++ @Param[in] p_Statistics Structure with statistics. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_TxSaGetStatistics(t_Handle h_FmMacsecSecY, macsecAN_t an, t_FmMacsecSecYTxSaStatistics *p_Statistics); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_SetException ++ ++ @Description Calling this routine enables/disables the specified exception. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] exception The exception to be selected. ++ @Param[in] enable TRUE to enable interrupt, FALSE to mask it. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_SetException(t_Handle h_FmMacsecSecY, e_FmMacsecExceptions exception, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_SetEvent ++ ++ @Description Calling this routine enables/disables the specified event. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] event The event to be selected. ++ @Param[in] enable TRUE to enable interrupt, FALSE to mask it. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Config() and before FM_MACSEC_SECY_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_SetEvent(t_Handle h_FmMacsecSecY, e_FmMacsecSecYEvents event, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_GetRxScPhysId ++ ++ @Description return the physical id of the Secure Channel. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[in] h_Sc SC handle as returned by FM_MACSEC_SECY_CreateRxSc. ++ @Param[out] p_ScPhysId the SC physical id. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_CreateRxSc(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_GetRxScPhysId(t_Handle h_FmMacsecSecY, t_Handle h_Sc, uint32_t *p_ScPhysId); ++ ++/**************************************************************************//** ++ @Function FM_MACSEC_SECY_GetTxScPhysId ++ ++ @Description return the physical id of the Secure Channel. ++ ++ @Param[in] h_FmMacsecSecY FM MACSEC SECY module descriptor. ++ @Param[out] p_ScPhysId the SC physical id. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MACSEC_SECY_Init(). ++*//***************************************************************************/ ++t_Error FM_MACSEC_SECY_GetTxScPhysId(t_Handle h_FmMacsecSecY, uint32_t *p_ScPhysId); ++ ++/** @} */ /* end of FM_MACSEC_SECY_runtime_control_grp group */ ++/** @} */ /* end of FM_MACSEC_SECY_grp group */ ++/** @} */ /* end of FM_MACSEC_grp group */ ++/** @} */ /* end of FM_grp group */ ++ ++ ++#endif /* __FM_MACSEC_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_muram_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_muram_ext.h +new file mode 100644 +index 00000000..ef62c8ef +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_muram_ext.h +@@ -0,0 +1,170 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File fm_muram_ext.h ++ ++ @Description FM MURAM Application Programming Interface. ++*//***************************************************************************/ ++#ifndef __FM_MURAM_EXT ++#define __FM_MURAM_EXT ++ ++#include "error_ext.h" ++#include "std_ext.h" ++ ++ ++/**************************************************************************//** ++ ++ @Group FM_grp Frame Manager API ++ ++ @Description FM API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group FM_muram_grp FM MURAM ++ ++ @Description FM MURAM API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group FM_muram_init_grp FM MURAM Initialization Unit ++ ++ @Description FM MURAM initialization API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function FM_MURAM_ConfigAndInit ++ ++ @Description Creates partition in the MURAM. ++ ++ The routine returns a handle (descriptor) to the MURAM partition. ++ This descriptor must be passed as first parameter to all other ++ FM-MURAM function calls. ++ ++ No actual initialization or configuration of FM_MURAM hardware is ++ done by this routine. ++ ++ @Param[in] baseAddress - Pointer to base of memory mapped FM-MURAM. ++ @Param[in] size - Size of the FM-MURAM partition. ++ ++ @Return Handle to FM-MURAM object, or NULL for Failure. ++*//***************************************************************************/ ++t_Handle FM_MURAM_ConfigAndInit(uintptr_t baseAddress, uint32_t size); ++ ++/**************************************************************************//** ++ @Function FM_MURAM_Free ++ ++ @Description Frees all resources that were assigned to FM-MURAM module. ++ ++ Calling this routine invalidates the descriptor. ++ ++ @Param[in] h_FmMuram - FM-MURAM module descriptor. ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_MURAM_Free(t_Handle h_FmMuram); ++ ++/** @} */ /* end of FM_muram_init_grp group */ ++ ++ ++/**************************************************************************//** ++ @Group FM_muram_ctrl_grp FM MURAM Control Unit ++ ++ @Description FM MURAM control API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function FM_MURAM_AllocMem ++ ++ @Description Allocate some memory from FM-MURAM partition. ++ ++ @Param[in] h_FmMuram - FM-MURAM module descriptor. ++ @Param[in] size - size of the memory to be allocated. ++ @Param[in] align - Alignment of the memory. ++ ++ @Return address of the allocated memory; NULL otherwise. ++*//***************************************************************************/ ++void * FM_MURAM_AllocMem(t_Handle h_FmMuram, uint32_t size, uint32_t align); ++ ++/**************************************************************************//** ++ @Function FM_MURAM_AllocMemForce ++ ++ @Description Allocate some specific memory from FM-MURAM partition (according ++ to base). ++ ++ @Param[in] h_FmMuram - FM-MURAM module descriptor. ++ @Param[in] base - the desired base-address to be allocated. ++ @Param[in] size - size of the memory to be allocated. ++ ++ @Return address of the allocated memory; NULL otherwise. ++*//***************************************************************************/ ++void * FM_MURAM_AllocMemForce(t_Handle h_FmMuram, uint64_t base, uint32_t size); ++ ++/**************************************************************************//** ++ @Function FM_MURAM_FreeMem ++ ++ @Description Free an allocated memory from FM-MURAM partition. ++ ++ @Param[in] h_FmMuram - FM-MURAM module descriptor. ++ @Param[in] ptr - A pointer to an allocated memory. ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_MURAM_FreeMem(t_Handle h_FmMuram, void *ptr); ++ ++/**************************************************************************//** ++ @Function FM_MURAM_GetFreeMemSize ++ ++ @Description Returns the size (in bytes) of free MURAM memory. ++ ++ @Param[in] h_FmMuram - FM-MURAM module descriptor. ++ ++ @Return Free MURAM memory size in bytes. ++*//***************************************************************************/ ++uint64_t FM_MURAM_GetFreeMemSize(t_Handle h_FmMuram); ++ ++/** @} */ /* end of FM_muram_ctrl_grp group */ ++/** @} */ /* end of FM_muram_grp group */ ++/** @} */ /* end of FM_grp group */ ++ ++ ++ ++#endif /* __FM_MURAM_EXT */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_pcd_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_pcd_ext.h +new file mode 100644 +index 00000000..8d1c3d88 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_pcd_ext.h +@@ -0,0 +1,3974 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File fm_pcd_ext.h ++ ++ @Description FM PCD API definitions ++*//***************************************************************************/ ++#ifndef __FM_PCD_EXT ++#define __FM_PCD_EXT ++ ++#include "std_ext.h" ++#include "net_ext.h" ++#include "list_ext.h" ++#include "fm_ext.h" ++#include "fsl_fman_kg.h" ++ ++ ++/**************************************************************************//** ++ @Group FM_grp Frame Manager API ++ ++ @Description Frame Manager Application Programming Interface ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group FM_PCD_grp FM PCD ++ ++ @Description Frame Manager PCD (Parse-Classify-Distribute) API. ++ ++ The FM PCD module is responsible for the initialization of all ++ global classifying FM modules. This includes the parser general and ++ common registers, the key generator global and common registers, ++ and the policer global and common registers. ++ In addition, the FM PCD SW module will initialize all required ++ key generator schemes, coarse classification flows, and policer ++ profiles. When FM module is configured to work with one of these ++ entities, it will register to it using the FM PORT API. The PCD ++ module will manage the PCD resources - i.e. resource management of ++ KeyGen schemes, etc. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Collection General PCD defines ++*//***************************************************************************/ ++#define FM_PCD_MAX_NUM_OF_PRIVATE_HDRS 2 /**< Number of units/headers saved for user */ ++ ++#define FM_PCD_PRS_NUM_OF_HDRS 16 /**< Number of headers supported by HW parser */ ++#define FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS (32 - FM_PCD_MAX_NUM_OF_PRIVATE_HDRS) ++ /**< Number of distinction units is limited by ++ register size (32 bits) minus reserved bits ++ for private headers. */ ++#define FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS 4 /**< Maximum number of interchangeable headers ++ in a distinction unit */ ++#define FM_PCD_KG_NUM_OF_GENERIC_REGS FM_KG_NUM_OF_GENERIC_REGS /**< Total number of generic KeyGen registers */ ++#define FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY 35 /**< Max number allowed on any configuration; ++ For HW implementation reasons, in most ++ cases less than this will be allowed; The ++ driver will return an initialization error ++ if resource is unavailable. */ ++#define FM_PCD_KG_NUM_OF_EXTRACT_MASKS 4 /**< Total number of masks allowed on KeyGen extractions. */ ++#define FM_PCD_KG_NUM_OF_DEFAULT_GROUPS 16 /**< Number of default value logical groups */ ++ ++#define FM_PCD_PRS_NUM_OF_LABELS 32 /**< Maximum number of SW parser labels */ ++#define FM_SW_PRS_MAX_IMAGE_SIZE (FM_PCD_SW_PRS_SIZE /*- FM_PCD_PRS_SW_OFFSET -FM_PCD_PRS_SW_TAIL_SIZE*/-FM_PCD_PRS_SW_PATCHES_SIZE) ++ /**< Maximum size of SW parser code */ ++ ++#define FM_PCD_MAX_MANIP_INSRT_TEMPLATE_SIZE 128 /**< Maximum size of insertion template for ++ insert manipulation */ ++ ++#if (DPAA_VERSION >= 11) ++#define FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES 64 /**< Maximum possible entries for frame replicator group */ ++#endif /* (DPAA_VERSION >= 11) */ ++/* @} */ ++ ++ ++/**************************************************************************//** ++ @Group FM_PCD_init_grp FM PCD Initialization Unit ++ ++ @Description Frame Manager PCD Initialization Unit API ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description PCD counters ++*//***************************************************************************/ ++typedef enum e_FmPcdCounters { ++ e_FM_PCD_KG_COUNTERS_TOTAL, /**< KeyGen counter */ ++ e_FM_PCD_PLCR_COUNTERS_RED, /**< Policer counter - counts the total number of RED packets that exit the Policer. */ ++ e_FM_PCD_PLCR_COUNTERS_YELLOW, /**< Policer counter - counts the total number of YELLOW packets that exit the Policer. */ ++ e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED, /**< Policer counter - counts the number of packets that changed color to RED by the Policer; ++ This is a subset of e_FM_PCD_PLCR_COUNTERS_RED packet count, indicating active color changes. */ ++ e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW, /**< Policer counter - counts the number of packets that changed color to YELLOW by the Policer; ++ This is a subset of e_FM_PCD_PLCR_COUNTERS_YELLOW packet count, indicating active color changes. */ ++ e_FM_PCD_PLCR_COUNTERS_TOTAL, /**< Policer counter - counts the total number of packets passed in the Policer. */ ++ e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH, /**< Policer counter - counts the number of packets with length mismatch. */ ++ e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH, /**< Parser counter - counts the number of times the parser block is dispatched. */ ++ e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED, /**< Parser counter - counts the number of times L2 parse result is returned (including errors). */ ++ e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED, /**< Parser counter - counts the number of times L3 parse result is returned (including errors). */ ++ e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED, /**< Parser counter - counts the number of times L4 parse result is returned (including errors). */ ++ e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED, /**< Parser counter - counts the number of times SHIM parse result is returned (including errors). */ ++ e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter - counts the number of times L2 parse result is returned with errors. */ ++ e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter - counts the number of times L3 parse result is returned with errors. */ ++ e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter - counts the number of times L4 parse result is returned with errors. */ ++ e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter - counts the number of times SHIM parse result is returned with errors. */ ++ e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES, /**< Parser counter - counts the number of cycles spent executing soft parser instruction (including stall cycles). */ ++ e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES, /**< Parser counter - counts the number of cycles stalled waiting for parser internal memory reads while executing soft parser instruction. */ ++ e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES, /**< Parser counter - counts the number of cycles spent executing hard parser (including stall cycles). */ ++ e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES, /**< MURAM counter - counts the number of cycles while performing FMan Memory read. */ ++ e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES, /**< MURAM counter - counts the number of cycles stalled while performing FMan Memory read. */ ++ e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES, /**< MURAM counter - counts the number of cycles while performing FMan Memory write. */ ++ e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES, /**< MURAM counter - counts the number of cycles stalled while performing FMan Memory write. */ ++ e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES /**< FPM counter - counts the number of cycles stalled while performing a FPM Command. */ ++} e_FmPcdCounters; ++ ++/**************************************************************************//** ++ @Description PCD interrupts ++*//***************************************************************************/ ++typedef enum e_FmPcdExceptions { ++ e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC, /**< KeyGen double-bit ECC error is detected on internal memory read access. */ ++ e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW, /**< KeyGen scheme configuration error indicating a key size larger than 56 bytes. */ ++ e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC, /**< Policer double-bit ECC error has been detected on PRAM read access. */ ++ e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR, /**< Policer access to a non-initialized profile has been detected. */ ++ e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE, /**< Policer RAM self-initialization complete */ ++ e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE, /**< Policer atomic action complete */ ++ e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC, /**< Parser double-bit ECC error */ ++ e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC /**< Parser single-bit ECC error */ ++} e_FmPcdExceptions; ++ ++ ++/**************************************************************************//** ++ @Description Exceptions user callback routine, will be called upon an ++ exception passing the exception identification. ++ ++ @Param[in] h_App - User's application descriptor. ++ @Param[in] exception - The exception. ++ *//***************************************************************************/ ++typedef void (t_FmPcdExceptionCallback) (t_Handle h_App, e_FmPcdExceptions exception); ++ ++/**************************************************************************//** ++ @Description Exceptions user callback routine, will be called upon an exception ++ passing the exception identification. ++ ++ @Param[in] h_App - User's application descriptor. ++ @Param[in] exception - The exception. ++ @Param[in] index - id of the relevant source (may be scheme or profile id). ++ *//***************************************************************************/ ++typedef void (t_FmPcdIdExceptionCallback) ( t_Handle h_App, ++ e_FmPcdExceptions exception, ++ uint16_t index); ++ ++/**************************************************************************//** ++ @Description A callback for enqueuing frame onto a QM queue. ++ ++ @Param[in] h_QmArg - Application's handle passed to QM module on enqueue. ++ @Param[in] p_Fd - Frame descriptor for the frame. ++ ++ @Return E_OK on success; Error code otherwise. ++ *//***************************************************************************/ ++typedef t_Error (t_FmPcdQmEnqueueCallback) (t_Handle h_QmArg, void *p_Fd); ++ ++/**************************************************************************//** ++ @Description Host-Command parameters structure. ++ ++ When using Host command for PCD functionalities, a dedicated port ++ must be used. If this routine is called for a PCD in a single partition ++ environment, or it is the Master partition in a Multi-partition ++ environment, The port will be initialized by the PCD driver ++ initialization routine. ++ *//***************************************************************************/ ++typedef struct t_FmPcdHcParams { ++ uintptr_t portBaseAddr; /**< Virtual Address of Host-Command Port memory mapped registers.*/ ++ uint8_t portId; /**< Port Id (0-6 relative to Host-Command/Offline-Parsing ports); ++ NOTE: When configuring Host Command port for ++ FMANv3 devices (DPAA_VERSION 11 and higher), ++ portId=0 MUST be used. */ ++ uint16_t liodnBase; /**< LIODN base for this port, to be used together with LIODN offset ++ (irrelevant for P4080 revision 1.0) */ ++ uint32_t errFqid; /**< Host-Command Port error queue Id. */ ++ uint32_t confFqid; /**< Host-Command Port confirmation queue Id. */ ++ uint32_t qmChannel; /**< QM channel dedicated to this Host-Command port; ++ will be used by the FM for dequeue. */ ++ t_FmPcdQmEnqueueCallback *f_QmEnqueue; /**< Callback routine for enqueuing a frame to the QM */ ++ t_Handle h_QmArg; /**< Application's handle passed to QM module on enqueue */ ++} t_FmPcdHcParams; ++ ++/**************************************************************************//** ++ @Description The main structure for PCD initialization ++ *//***************************************************************************/ ++typedef struct t_FmPcdParams { ++ bool prsSupport; /**< TRUE if Parser will be used for any of the FM ports. */ ++ bool ccSupport; /**< TRUE if Coarse Classification will be used for any ++ of the FM ports. */ ++ bool kgSupport; /**< TRUE if KeyGen will be used for any of the FM ports. */ ++ bool plcrSupport; /**< TRUE if Policer will be used for any of the FM ports. */ ++ t_Handle h_Fm; /**< A handle to the FM module. */ ++ uint8_t numOfSchemes; /**< Number of schemes dedicated to this partition. ++ this parameter is relevant if 'kgSupport'=TRUE. */ ++ bool useHostCommand; /**< Optional for single partition, Mandatory for Multi partition */ ++ t_FmPcdHcParams hc; /**< Host Command parameters, relevant only if 'useHostCommand'=TRUE; ++ Relevant when FM not runs in "guest-mode". */ ++ ++ t_FmPcdExceptionCallback *f_Exception; /**< Callback routine for general PCD exceptions; ++ Relevant when FM not runs in "guest-mode". */ ++ t_FmPcdIdExceptionCallback *f_ExceptionId; /**< Callback routine for specific KeyGen scheme or ++ Policer profile exceptions; ++ Relevant when FM not runs in "guest-mode". */ ++ t_Handle h_App; /**< A handle to an application layer object; This handle will ++ be passed by the driver upon calling the above callbacks; ++ Relevant when FM not runs in "guest-mode". */ ++ uint8_t partPlcrProfilesBase; /**< The first policer-profile-id dedicated to this partition. ++ this parameter is relevant if 'plcrSupport'=TRUE. ++ NOTE: this parameter relevant only when working with multiple partitions. */ ++ uint16_t partNumOfPlcrProfiles; /**< Number of policer-profiles dedicated to this partition. ++ this parameter is relevant if 'plcrSupport'=TRUE. ++ NOTE: this parameter relevant only when working with multiple partitions. */ ++} t_FmPcdParams; ++ ++ ++/**************************************************************************//** ++ @Function FM_PCD_Config ++ ++ @Description Basic configuration of the PCD module. ++ Creates descriptor for the FM PCD module. ++ ++ @Param[in] p_FmPcdParams A structure of parameters for the initialization of PCD. ++ ++ @Return A handle to the initialized module. ++*//***************************************************************************/ ++t_Handle FM_PCD_Config(t_FmPcdParams *p_FmPcdParams); ++ ++/**************************************************************************//** ++ @Function FM_PCD_Init ++ ++ @Description Initialization of the PCD module. ++ ++ @Param[in] h_FmPcd - FM PCD module descriptor. ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_PCD_Init(t_Handle h_FmPcd); ++ ++/**************************************************************************//** ++ @Function FM_PCD_Free ++ ++ @Description Frees all resources that were assigned to FM module. ++ ++ Calling this routine invalidates the descriptor. ++ ++ @Param[in] h_FmPcd - FM PCD module descriptor. ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_PCD_Free(t_Handle h_FmPcd); ++ ++/**************************************************************************//** ++ @Group FM_PCD_advanced_cfg_grp FM PCD Advanced Configuration Unit ++ ++ @Description Frame Manager PCD Advanced Configuration API. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function FM_PCD_ConfigException ++ ++ @Description Calling this routine changes the internal driver data base ++ from its default selection of exceptions enabling. ++ [DEFAULT_numOfSharedPlcrProfiles]. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] exception The exception to be selected. ++ @Param[in] enable TRUE to enable interrupt, FALSE to mask it. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_PCD_ConfigException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_PCD_ConfigHcFramesDataMemory ++ ++ @Description Configures memory-partition-id for FMan-Controller Host-Command ++ frames. Calling this routine changes the internal driver data ++ base from its default configuration [0]. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] memId Memory partition ID. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions This routine may be called only if 'useHostCommand' was TRUE ++ when FM_PCD_Config() routine was called. ++*//***************************************************************************/ ++t_Error FM_PCD_ConfigHcFramesDataMemory(t_Handle h_FmPcd, uint8_t memId); ++ ++/**************************************************************************//** ++ @Function FM_PCD_ConfigPlcrNumOfSharedProfiles ++ ++ @Description Calling this routine changes the internal driver data base ++ from its default selection of exceptions enablement. ++ [DEFAULT_numOfSharedPlcrProfiles]. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] numOfSharedPlcrProfiles Number of profiles to ++ be shared between ports on this partition ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_PCD_ConfigPlcrNumOfSharedProfiles(t_Handle h_FmPcd, uint16_t numOfSharedPlcrProfiles); ++ ++/**************************************************************************//** ++ @Function FM_PCD_ConfigPlcrAutoRefreshMode ++ ++ @Description Calling this routine changes the internal driver data base ++ from its default selection of exceptions enablement. ++ By default auto-refresh is [DEFAULT_plcrAutoRefresh]. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] enable TRUE to enable, FALSE to disable ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_PCD_ConfigPlcrAutoRefreshMode(t_Handle h_FmPcd, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_PCD_ConfigPrsMaxCycleLimit ++ ++ @Description Calling this routine changes the internal data structure for ++ the maximum parsing time from its default value ++ [DEFAULT_MAX_PRS_CYC_LIM]. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] value 0 to disable the mechanism, or new ++ maximum parsing time. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_PCD_ConfigPrsMaxCycleLimit(t_Handle h_FmPcd,uint16_t value); ++ ++/** @} */ /* end of FM_PCD_advanced_cfg_grp group */ ++/** @} */ /* end of FM_PCD_init_grp group */ ++ ++ ++/**************************************************************************//** ++ @Group FM_PCD_Runtime_grp FM PCD Runtime Unit ++ ++ @Description Frame Manager PCD Runtime Unit API ++ ++ The runtime control allows creation of PCD infrastructure modules ++ such as Network Environment Characteristics, Classification Plan ++ Groups and Coarse Classification Trees. ++ It also allows on-the-fly initialization, modification and removal ++ of PCD modules such as KeyGen schemes, coarse classification nodes ++ and Policer profiles. ++ ++ In order to explain the programming model of the PCD driver interface ++ a few terms should be explained, and will be used below. ++ - Distinction Header - One of the 16 protocols supported by the FM parser, ++ or one of the SHIM headers (1 or 2). May be a header with a special ++ option (see below). ++ - Interchangeable Headers Group - This is a group of Headers recognized ++ by either one of them. For example, if in a specific context the user ++ chooses to treat IPv4 and IPV6 in the same way, they may create an ++ interchangeable Headers Unit consisting of these 2 headers. ++ - A Distinction Unit - a Distinction Header or an Interchangeable Headers ++ Group. ++ - Header with special option - applies to Ethernet, MPLS, VLAN, IPv4 and ++ IPv6, includes multicast, broadcast and other protocol specific options. ++ In terms of hardware it relates to the options available in the classification ++ plan. ++ - Network Environment Characteristics - a set of Distinction Units that define ++ the total recognizable header selection for a certain environment. This is ++ NOT the list of all headers that will ever appear in a flow, but rather ++ everything that needs distinction in a flow, where distinction is made by KeyGen ++ schemes and coarse classification action descriptors. ++ ++ The PCD runtime modules initialization is done in stages. The first stage after ++ initializing the PCD module itself is to establish a Network Flows Environment ++ Definition. The application may choose to establish one or more such environments. ++ Later, when needed, the application will have to state, for some of its modules, ++ to which single environment it belongs. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description A structure for SW parser labels ++ *//***************************************************************************/ ++typedef struct t_FmPcdPrsLabelParams { ++ uint32_t instructionOffset; /**< SW parser label instruction offset (2 bytes ++ resolution), relative to Parser RAM. */ ++ e_NetHeaderType hdr; /**< The existence of this header will invoke ++ the SW parser code; Use HEADER_TYPE_NONE ++ to indicate that sw parser is to run ++ independent of the existence of any protocol ++ (run before HW parser). */ ++ uint8_t indexPerHdr; /**< Normally 0, if more than one SW parser ++ attachments for the same header, use this ++ index to distinguish between them. */ ++} t_FmPcdPrsLabelParams; ++ ++/**************************************************************************//** ++ @Description A structure for SW parser ++ *//***************************************************************************/ ++typedef struct t_FmPcdPrsSwParams { ++ bool override; /**< FALSE to invoke a check that nothing else ++ was loaded to this address, including ++ internal patches. ++ TRUE to override any existing code.*/ ++ uint32_t size; /**< SW parser code size */ ++ uint16_t base; /**< SW parser base (in instruction counts! ++ must be larger than 0x20)*/ ++ uint8_t *p_Code; /**< SW parser code */ ++ uint32_t swPrsDataParams[FM_PCD_PRS_NUM_OF_HDRS]; ++ /**< SW parser data (parameters) */ ++ uint8_t numOfLabels; /**< Number of labels for SW parser. */ ++ t_FmPcdPrsLabelParams labelsTable[FM_PCD_PRS_NUM_OF_LABELS]; ++ /**< SW parser labels table, containing ++ numOfLabels entries */ ++} t_FmPcdPrsSwParams; ++ ++ ++/**************************************************************************//** ++ @Function FM_PCD_Enable ++ ++ @Description This routine should be called after PCD is initialized for enabling all ++ PCD engines according to their existing configuration. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init() and when PCD is disabled. ++*//***************************************************************************/ ++t_Error FM_PCD_Enable(t_Handle h_FmPcd); ++ ++/**************************************************************************//** ++ @Function FM_PCD_Disable ++ ++ @Description This routine may be called when PCD is enabled in order to ++ disable all PCD engines. It may be called ++ only when none of the ports in the system are using the PCD. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init() and when PCD is enabled. ++*//***************************************************************************/ ++t_Error FM_PCD_Disable(t_Handle h_FmPcd); ++ ++/**************************************************************************//** ++ @Function FM_PCD_GetCounter ++ ++ @Description Reads one of the FM PCD counters. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] counter The requested counter. ++ ++ @Return Counter's current value. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++ Note that it is user's responsibility to call this routine only ++ for enabled counters, and there will be no indication if a ++ disabled counter is accessed. ++*//***************************************************************************/ ++uint32_t FM_PCD_GetCounter(t_Handle h_FmPcd, e_FmPcdCounters counter); ++ ++/**************************************************************************//** ++@Function FM_PCD_PrsLoadSw ++ ++@Description This routine may be called in order to load software parsing code. ++ ++ ++@Param[in] h_FmPcd FM PCD module descriptor. ++@Param[in] p_SwPrs A pointer to a structure of software ++ parser parameters, including the software ++ parser image. ++ ++@Return E_OK on success; Error code otherwise. ++ ++@Cautions Allowed only following FM_PCD_Init() and when PCD is disabled. ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_PCD_PrsLoadSw(t_Handle h_FmPcd, t_FmPcdPrsSwParams *p_SwPrs); ++ ++/**************************************************************************//** ++@Function FM_PCD_SetAdvancedOffloadSupport ++ ++@Description This routine must be called in order to support the following features: ++ IP-fragmentation, IP-reassembly, IPsec, Header-manipulation, frame-replicator. ++ ++@Param[in] h_FmPcd FM PCD module descriptor. ++ ++@Return E_OK on success; Error code otherwise. ++ ++@Cautions Allowed only following FM_PCD_Init() and when PCD is disabled. ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_PCD_SetAdvancedOffloadSupport(t_Handle h_FmPcd); ++ ++/**************************************************************************//** ++ @Function FM_PCD_KgSetDfltValue ++ ++ @Description Calling this routine sets a global default value to be used ++ by the KeyGen when parser does not recognize a required ++ field/header. ++ By default default values are 0. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] valueId 0,1 - one of 2 global default values. ++ @Param[in] value The requested default value. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init() and when PCD is disabled. ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_PCD_KgSetDfltValue(t_Handle h_FmPcd, uint8_t valueId, uint32_t value); ++ ++/**************************************************************************//** ++ @Function FM_PCD_KgSetAdditionalDataAfterParsing ++ ++ @Description Calling this routine allows the KeyGen to access data past ++ the parser finishing point. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] payloadOffset the number of bytes beyond the parser location. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init() and when PCD is disabled. ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_PCD_KgSetAdditionalDataAfterParsing(t_Handle h_FmPcd, uint8_t payloadOffset); ++ ++/**************************************************************************//** ++ @Function FM_PCD_SetException ++ ++ @Description Calling this routine enables/disables PCD interrupts. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] exception The exception to be selected. ++ @Param[in] enable TRUE to enable interrupt, FALSE to mask it. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_PCD_SetException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_PCD_ModifyCounter ++ ++ @Description Sets a value to an enabled counter. Use "0" to reset the counter. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] counter The requested counter. ++ @Param[in] value The requested value to be written into the counter. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_PCD_ModifyCounter(t_Handle h_FmPcd, e_FmPcdCounters counter, uint32_t value); ++ ++/**************************************************************************//** ++ @Function FM_PCD_SetPlcrStatistics ++ ++ @Description This routine may be used to enable/disable policer statistics ++ counter. By default the statistics is enabled. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor ++ @Param[in] enable TRUE to enable, FALSE to disable. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_PCD_SetPlcrStatistics(t_Handle h_FmPcd, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_PCD_SetPrsStatistics ++ ++ @Description Defines whether to gather parser statistics including all ports. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] enable TRUE to enable, FALSE to disable. ++ ++ @Return None ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++void FM_PCD_SetPrsStatistics(t_Handle h_FmPcd, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_PCD_HcTxConf ++ ++ @Description This routine should be called to confirm frames that were ++ received on the HC confirmation queue. ++ ++ @Param[in] h_FmPcd A handle to an FM PCD Module. ++ @Param[in] p_Fd Frame descriptor of the received frame. ++ ++ @Cautions Allowed only following FM_PCD_Init(). Allowed only if 'useHostCommand' ++ option was selected in the initialization. ++*//***************************************************************************/ ++void FM_PCD_HcTxConf(t_Handle h_FmPcd, t_DpaaFD *p_Fd); ++ ++/**************************************************************************//* ++ @Function FM_PCD_ForceIntr ++ ++ @Description Causes an interrupt event on the requested source. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] exception An exception to be forced. ++ ++ @Return E_OK on success; Error code if the exception is not enabled, ++ or is not able to create interrupt. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_PCD_ForceIntr (t_Handle h_FmPcd, e_FmPcdExceptions exception); ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++/**************************************************************************//** ++ @Function FM_PCD_DumpRegs ++ ++ @Description Dumps all PCD registers ++ ++ @Param[in] h_FmPcd A handle to an FM PCD Module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++ NOTE: this routine may be called only for FM in master mode ++ (i.e. 'guestId'=NCSW_MASTER_ID) or in a case that the registers ++ are mapped. ++*//***************************************************************************/ ++t_Error FM_PCD_DumpRegs(t_Handle h_FmPcd); ++ ++/**************************************************************************//** ++ @Function FM_PCD_KgDumpRegs ++ ++ @Description Dumps all PCD KG registers ++ ++ @Param[in] h_FmPcd A handle to an FM PCD Module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++ NOTE: this routine may be called only for FM in master mode ++ (i.e. 'guestId'=NCSW_MASTER_ID) or in a case that the registers ++ are mapped. ++*//***************************************************************************/ ++t_Error FM_PCD_KgDumpRegs(t_Handle h_FmPcd); ++ ++/**************************************************************************//** ++ @Function FM_PCD_PlcrDumpRegs ++ ++ @Description Dumps all PCD Policer registers ++ ++ @Param[in] h_FmPcd A handle to an FM PCD Module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++ NOTE: this routine may be called only for FM in master mode ++ (i.e. 'guestId'=NCSW_MASTER_ID) or in a case that the registers ++ are mapped. ++*//***************************************************************************/ ++t_Error FM_PCD_PlcrDumpRegs(t_Handle h_FmPcd); ++ ++/**************************************************************************//** ++ @Function FM_PCD_PlcrProfileDumpRegs ++ ++ @Description Dumps all PCD Policer profile registers ++ ++ @Param[in] h_Profile A handle to a Policer profile. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++ NOTE: this routine may be called only for FM in master mode ++ (i.e. 'guestId'=NCSW_MASTER_ID) or in a case that the registers ++ are mapped. ++*//***************************************************************************/ ++t_Error FM_PCD_PlcrProfileDumpRegs(t_Handle h_Profile); ++ ++/**************************************************************************//** ++ @Function FM_PCD_PrsDumpRegs ++ ++ @Description Dumps all PCD Parser registers ++ ++ @Param[in] h_FmPcd A handle to an FM PCD Module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++ NOTE: this routine may be called only for FM in master mode ++ (i.e. 'guestId'=NCSW_MASTER_ID) or in a case that the registers ++ are mapped. ++*//***************************************************************************/ ++t_Error FM_PCD_PrsDumpRegs(t_Handle h_FmPcd); ++ ++/**************************************************************************//** ++ @Function FM_PCD_HcDumpRegs ++ ++ @Description Dumps HC Port registers ++ ++ @Param[in] h_FmPcd A handle to an FM PCD Module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++ NOTE: this routine may be called only for FM in master mode ++ (i.e. 'guestId'=NCSW_MASTER_ID). ++*//***************************************************************************/ ++t_Error FM_PCD_HcDumpRegs(t_Handle h_FmPcd); ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++ ++ ++/**************************************************************************//** ++ KeyGen FM_PCD_Runtime_build_grp FM PCD Runtime Building Unit ++ ++ @Description Frame Manager PCD Runtime Building API ++ ++ This group contains routines for setting, deleting and modifying ++ PCD resources, for defining the total PCD tree. ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Collection Definitions of coarse classification ++ parameters as required by KeyGen (when coarse classification ++ is the next engine after this scheme). ++*//***************************************************************************/ ++#define FM_PCD_MAX_NUM_OF_CC_TREES 8 ++#define FM_PCD_MAX_NUM_OF_CC_GROUPS 16 ++#define FM_PCD_MAX_NUM_OF_CC_UNITS 4 ++#define FM_PCD_MAX_NUM_OF_KEYS 256 ++#define FM_PCD_MAX_NUM_OF_FLOWS (4*KILOBYTE) ++#define FM_PCD_MAX_SIZE_OF_KEY 56 ++#define FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP 16 ++#define FM_PCD_LAST_KEY_INDEX 0xffff ++ ++#define FM_PCD_MAX_NUM_OF_CC_NODES 255 /* Obsolete, not used - will be removed in the future */ ++/* @} */ ++ ++/**************************************************************************//** ++ @Collection A set of definitions to allow protocol ++ special option description. ++*//***************************************************************************/ ++typedef uint32_t protocolOpt_t; /**< A general type to define a protocol option. */ ++ ++typedef protocolOpt_t ethProtocolOpt_t; /**< Ethernet protocol options. */ ++#define ETH_BROADCAST 0x80000000 /**< Ethernet Broadcast. */ ++#define ETH_MULTICAST 0x40000000 /**< Ethernet Multicast. */ ++ ++typedef protocolOpt_t vlanProtocolOpt_t; /**< VLAN protocol options. */ ++#define VLAN_STACKED 0x20000000 /**< Stacked VLAN. */ ++ ++typedef protocolOpt_t mplsProtocolOpt_t; /**< MPLS protocol options. */ ++#define MPLS_STACKED 0x10000000 /**< Stacked MPLS. */ ++ ++typedef protocolOpt_t ipv4ProtocolOpt_t; /**< IPv4 protocol options. */ ++#define IPV4_BROADCAST_1 0x08000000 /**< IPv4 Broadcast. */ ++#define IPV4_MULTICAST_1 0x04000000 /**< IPv4 Multicast. */ ++#define IPV4_UNICAST_2 0x02000000 /**< Tunneled IPv4 - Unicast. */ ++#define IPV4_MULTICAST_BROADCAST_2 0x01000000 /**< Tunneled IPv4 - Broadcast/Multicast. */ ++ ++#define IPV4_FRAG_1 0x00000008 /**< IPV4 reassembly option. ++ IPV4 Reassembly manipulation requires network ++ environment with IPV4 header and IPV4_FRAG_1 option */ ++ ++typedef protocolOpt_t ipv6ProtocolOpt_t; /**< IPv6 protocol options. */ ++#define IPV6_MULTICAST_1 0x00800000 /**< IPv6 Multicast. */ ++#define IPV6_UNICAST_2 0x00400000 /**< Tunneled IPv6 - Unicast. */ ++#define IPV6_MULTICAST_2 0x00200000 /**< Tunneled IPv6 - Multicast. */ ++ ++#define IPV6_FRAG_1 0x00000004 /**< IPV6 reassembly option. ++ IPV6 Reassembly manipulation requires network ++ environment with IPV6 header and IPV6_FRAG_1 option; ++ in case where fragment found, the fragment-extension offset ++ may be found at 'shim2' (in parser-result). */ ++#if (DPAA_VERSION >= 11) ++typedef protocolOpt_t capwapProtocolOpt_t; /**< CAPWAP protocol options. */ ++#define CAPWAP_FRAG_1 0x00000008 /**< CAPWAP reassembly option. ++ CAPWAP Reassembly manipulation requires network ++ environment with CAPWAP header and CAPWAP_FRAG_1 option; ++ in case where fragment found, the fragment-extension offset ++ may be found at 'shim2' (in parser-result). */ ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ ++/* @} */ ++ ++#define FM_PCD_MANIP_MAX_HDR_SIZE 256 ++#define FM_PCD_MANIP_DSCP_TO_VLAN_TRANS 64 ++ ++/**************************************************************************//** ++ @Collection A set of definitions to support Header Manipulation selection. ++*//***************************************************************************/ ++typedef uint32_t hdrManipFlags_t; /**< A general type to define a HMan update command flags. */ ++ ++typedef hdrManipFlags_t ipv4HdrManipUpdateFlags_t; /**< IPv4 protocol HMan update command flags. */ ++ ++#define HDR_MANIP_IPV4_TOS 0x80000000 /**< update TOS with the given value ('tos' field ++ of t_FmPcdManipHdrFieldUpdateIpv4) */ ++#define HDR_MANIP_IPV4_ID 0x40000000 /**< update IP ID with the given value ('id' field ++ of t_FmPcdManipHdrFieldUpdateIpv4) */ ++#define HDR_MANIP_IPV4_TTL 0x20000000 /**< Decrement TTL by 1 */ ++#define HDR_MANIP_IPV4_SRC 0x10000000 /**< update IP source address with the given value ++ ('src' field of t_FmPcdManipHdrFieldUpdateIpv4) */ ++#define HDR_MANIP_IPV4_DST 0x08000000 /**< update IP destination address with the given value ++ ('dst' field of t_FmPcdManipHdrFieldUpdateIpv4) */ ++ ++typedef hdrManipFlags_t ipv6HdrManipUpdateFlags_t; /**< IPv6 protocol HMan update command flags. */ ++ ++#define HDR_MANIP_IPV6_TC 0x80000000 /**< update Traffic Class address with the given value ++ ('trafficClass' field of t_FmPcdManipHdrFieldUpdateIpv6) */ ++#define HDR_MANIP_IPV6_HL 0x40000000 /**< Decrement Hop Limit by 1 */ ++#define HDR_MANIP_IPV6_SRC 0x20000000 /**< update IP source address with the given value ++ ('src' field of t_FmPcdManipHdrFieldUpdateIpv6) */ ++#define HDR_MANIP_IPV6_DST 0x10000000 /**< update IP destination address with the given value ++ ('dst' field of t_FmPcdManipHdrFieldUpdateIpv6) */ ++ ++typedef hdrManipFlags_t tcpUdpHdrManipUpdateFlags_t;/**< TCP/UDP protocol HMan update command flags. */ ++ ++#define HDR_MANIP_TCP_UDP_SRC 0x80000000 /**< update TCP/UDP source address with the given value ++ ('src' field of t_FmPcdManipHdrFieldUpdateTcpUdp) */ ++#define HDR_MANIP_TCP_UDP_DST 0x40000000 /**< update TCP/UDP destination address with the given value ++ ('dst' field of t_FmPcdManipHdrFieldUpdateTcpUdp) */ ++#define HDR_MANIP_TCP_UDP_CHECKSUM 0x20000000 /**< update TCP/UDP checksum */ ++ ++/* @} */ ++ ++/**************************************************************************//** ++ @Description A type used for returning the order of the key extraction. ++ each value in this array represents the index of the extraction ++ command as defined by the user in the initialization extraction array. ++ The valid size of this array is the user define number of extractions ++ required (also marked by the second '0' in this array). ++*//***************************************************************************/ ++typedef uint8_t t_FmPcdKgKeyOrder [FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY]; ++ ++/**************************************************************************//** ++ @Description All PCD engines ++*//***************************************************************************/ ++typedef enum e_FmPcdEngine { ++ e_FM_PCD_INVALID = 0, /**< Invalid PCD engine */ ++ e_FM_PCD_DONE, /**< No PCD Engine indicated */ ++ e_FM_PCD_KG, /**< KeyGen */ ++ e_FM_PCD_CC, /**< Coarse classifier */ ++ e_FM_PCD_PLCR, /**< Policer */ ++ e_FM_PCD_PRS, /**< Parser */ ++#if (DPAA_VERSION >= 11) ++ e_FM_PCD_FR, /**< Frame-Replicator */ ++#endif /* (DPAA_VERSION >= 11) */ ++ e_FM_PCD_HASH /**< Hash table */ ++} e_FmPcdEngine; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting extraction by header types ++*//***************************************************************************/ ++typedef enum e_FmPcdExtractByHdrType { ++ e_FM_PCD_EXTRACT_FROM_HDR, /**< Extract bytes from header */ ++ e_FM_PCD_EXTRACT_FROM_FIELD, /**< Extract bytes from header field */ ++ e_FM_PCD_EXTRACT_FULL_FIELD /**< Extract a full field */ ++} e_FmPcdExtractByHdrType; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting extraction source ++ (when it is not the header) ++*//***************************************************************************/ ++typedef enum e_FmPcdExtractFrom { ++ e_FM_PCD_EXTRACT_FROM_FRAME_START, /**< KG & CC: Extract from beginning of frame */ ++ e_FM_PCD_EXTRACT_FROM_DFLT_VALUE, /**< KG only: Extract from a default value */ ++ e_FM_PCD_EXTRACT_FROM_CURR_END_OF_PARSE, /**< KG & CC: Extract from the point where parsing had finished */ ++ e_FM_PCD_EXTRACT_FROM_KEY, /**< CC only: Field where saved KEY */ ++ e_FM_PCD_EXTRACT_FROM_HASH, /**< CC only: Field where saved HASH */ ++ e_FM_PCD_EXTRACT_FROM_PARSE_RESULT, /**< KG only: Extract from the parser result */ ++ e_FM_PCD_EXTRACT_FROM_ENQ_FQID, /**< KG & CC: Extract from enqueue FQID */ ++ e_FM_PCD_EXTRACT_FROM_FLOW_ID /**< CC only: Field where saved Dequeue FQID */ ++} e_FmPcdExtractFrom; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting extraction type ++*//***************************************************************************/ ++typedef enum e_FmPcdExtractType { ++ e_FM_PCD_EXTRACT_BY_HDR, /**< Extract according to header */ ++ e_FM_PCD_EXTRACT_NON_HDR, /**< Extract from data that is not the header */ ++ e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO /**< Extract private info as specified by user */ ++} e_FmPcdExtractType; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting default extraction value ++*//***************************************************************************/ ++typedef enum e_FmPcdKgExtractDfltSelect { ++ e_FM_PCD_KG_DFLT_GBL_0, /**< Default selection is KG register 0 */ ++ e_FM_PCD_KG_DFLT_GBL_1, /**< Default selection is KG register 1 */ ++ e_FM_PCD_KG_DFLT_PRIVATE_0, /**< Default selection is a per scheme register 0 */ ++ e_FM_PCD_KG_DFLT_PRIVATE_1, /**< Default selection is a per scheme register 1 */ ++ e_FM_PCD_KG_DFLT_ILLEGAL /**< Illegal selection */ ++} e_FmPcdKgExtractDfltSelect; ++ ++/**************************************************************************//** ++ @Description Enumeration type defining all default groups - each group shares ++ a default value, one of four user-initialized values. ++*//***************************************************************************/ ++typedef enum e_FmPcdKgKnownFieldsDfltTypes { ++ e_FM_PCD_KG_MAC_ADDR, /**< MAC Address */ ++ e_FM_PCD_KG_TCI, /**< TCI field */ ++ e_FM_PCD_KG_ENET_TYPE, /**< ENET Type */ ++ e_FM_PCD_KG_PPP_SESSION_ID, /**< PPP Session id */ ++ e_FM_PCD_KG_PPP_PROTOCOL_ID, /**< PPP Protocol id */ ++ e_FM_PCD_KG_MPLS_LABEL, /**< MPLS label */ ++ e_FM_PCD_KG_IP_ADDR, /**< IP address */ ++ e_FM_PCD_KG_PROTOCOL_TYPE, /**< Protocol type */ ++ e_FM_PCD_KG_IP_TOS_TC, /**< TOS or TC */ ++ e_FM_PCD_KG_IPV6_FLOW_LABEL, /**< IPV6 flow label */ ++ e_FM_PCD_KG_IPSEC_SPI, /**< IPSEC SPI */ ++ e_FM_PCD_KG_L4_PORT, /**< L4 Port */ ++ e_FM_PCD_KG_TCP_FLAG, /**< TCP Flag */ ++ e_FM_PCD_KG_GENERIC_FROM_DATA, /**< grouping implemented by SW, ++ any data extraction that is not the full ++ field described above */ ++ e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V, /**< grouping implemented by SW, ++ any data extraction without validation */ ++ e_FM_PCD_KG_GENERIC_NOT_FROM_DATA /**< grouping implemented by SW, ++ extraction from parser result or ++ direct use of default value */ ++} e_FmPcdKgKnownFieldsDfltTypes; ++ ++/**************************************************************************//** ++ @Description Enumeration type for defining header index for scenarios with ++ multiple (tunneled) headers ++*//***************************************************************************/ ++typedef enum e_FmPcdHdrIndex { ++ e_FM_PCD_HDR_INDEX_NONE = 0, /**< used when multiple headers not used, also ++ to specify regular IP (not tunneled). */ ++ e_FM_PCD_HDR_INDEX_1, /**< may be used for VLAN, MPLS, tunneled IP */ ++ e_FM_PCD_HDR_INDEX_2, /**< may be used for MPLS, tunneled IP */ ++ e_FM_PCD_HDR_INDEX_3, /**< may be used for MPLS */ ++ e_FM_PCD_HDR_INDEX_LAST = 0xFF /**< may be used for VLAN, MPLS */ ++} e_FmPcdHdrIndex; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting the policer profile functional type ++*//***************************************************************************/ ++typedef enum e_FmPcdProfileTypeSelection { ++ e_FM_PCD_PLCR_PORT_PRIVATE, /**< Port dedicated profile */ ++ e_FM_PCD_PLCR_SHARED /**< Shared profile (shared within partition) */ ++} e_FmPcdProfileTypeSelection; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting the policer profile algorithm ++*//***************************************************************************/ ++typedef enum e_FmPcdPlcrAlgorithmSelection { ++ e_FM_PCD_PLCR_PASS_THROUGH, /**< Policer pass through */ ++ e_FM_PCD_PLCR_RFC_2698, /**< Policer algorithm RFC 2698 */ ++ e_FM_PCD_PLCR_RFC_4115 /**< Policer algorithm RFC 4115 */ ++} e_FmPcdPlcrAlgorithmSelection; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting a policer profile color mode ++*//***************************************************************************/ ++typedef enum e_FmPcdPlcrColorMode { ++ e_FM_PCD_PLCR_COLOR_BLIND, /**< Color blind */ ++ e_FM_PCD_PLCR_COLOR_AWARE /**< Color aware */ ++} e_FmPcdPlcrColorMode; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting a policer profile color ++*//***************************************************************************/ ++typedef enum e_FmPcdPlcrColor { ++ e_FM_PCD_PLCR_GREEN, /**< Green color code */ ++ e_FM_PCD_PLCR_YELLOW, /**< Yellow color code */ ++ e_FM_PCD_PLCR_RED, /**< Red color code */ ++ e_FM_PCD_PLCR_OVERRIDE /**< Color override code */ ++} e_FmPcdPlcrColor; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting the policer profile packet frame length selector ++*//***************************************************************************/ ++typedef enum e_FmPcdPlcrFrameLengthSelect { ++ e_FM_PCD_PLCR_L2_FRM_LEN, /**< L2 frame length */ ++ e_FM_PCD_PLCR_L3_FRM_LEN, /**< L3 frame length */ ++ e_FM_PCD_PLCR_L4_FRM_LEN, /**< L4 frame length */ ++ e_FM_PCD_PLCR_FULL_FRM_LEN /**< Full frame length */ ++} e_FmPcdPlcrFrameLengthSelect; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting roll-back frame ++*//***************************************************************************/ ++typedef enum e_FmPcdPlcrRollBackFrameSelect { ++ e_FM_PCD_PLCR_ROLLBACK_L2_FRM_LEN, /**< Roll-back L2 frame length */ ++ e_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN /**< Roll-back Full frame length */ ++} e_FmPcdPlcrRollBackFrameSelect; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting the policer profile packet or byte mode ++*//***************************************************************************/ ++typedef enum e_FmPcdPlcrRateMode { ++ e_FM_PCD_PLCR_BYTE_MODE, /**< Byte mode */ ++ e_FM_PCD_PLCR_PACKET_MODE /**< Packet mode */ ++} e_FmPcdPlcrRateMode; ++ ++/**************************************************************************//** ++ @Description Enumeration type for defining action of frame ++*//***************************************************************************/ ++typedef enum e_FmPcdDoneAction { ++ e_FM_PCD_ENQ_FRAME = 0, /**< Enqueue frame */ ++ e_FM_PCD_DROP_FRAME /**< Mark this frame as error frame and continue ++ to error flow; 'FM_PORT_FRM_ERR_CLS_DISCARD' ++ flag will be set for this frame. */ ++} e_FmPcdDoneAction; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting the policer counter ++*//***************************************************************************/ ++typedef enum e_FmPcdPlcrProfileCounters { ++ e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER, /**< Green packets counter */ ++ e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER, /**< Yellow packets counter */ ++ e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER, /**< Red packets counter */ ++ e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER, /**< Recolored yellow packets counter */ ++ e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER /**< Recolored red packets counter */ ++} e_FmPcdPlcrProfileCounters; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting the PCD action after extraction ++*//***************************************************************************/ ++typedef enum e_FmPcdAction { ++ e_FM_PCD_ACTION_NONE, /**< NONE */ ++ e_FM_PCD_ACTION_EXACT_MATCH, /**< Exact match on the selected extraction */ ++ e_FM_PCD_ACTION_INDEXED_LOOKUP /**< Indexed lookup on the selected extraction */ ++} e_FmPcdAction; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of insert manipulation ++*//***************************************************************************/ ++typedef enum e_FmPcdManipHdrInsrtType { ++ e_FM_PCD_MANIP_INSRT_GENERIC, /**< Insert according to offset & size */ ++ e_FM_PCD_MANIP_INSRT_BY_HDR, /**< Insert according to protocol */ ++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) ++ e_FM_PCD_MANIP_INSRT_BY_TEMPLATE /**< Insert template to start of frame */ ++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ ++} e_FmPcdManipHdrInsrtType; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of remove manipulation ++*//***************************************************************************/ ++typedef enum e_FmPcdManipHdrRmvType { ++ e_FM_PCD_MANIP_RMV_GENERIC, /**< Remove according to offset & size */ ++ e_FM_PCD_MANIP_RMV_BY_HDR /**< Remove according to offset & size */ ++} e_FmPcdManipHdrRmvType; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting specific L2 fields removal ++*//***************************************************************************/ ++typedef enum e_FmPcdManipHdrRmvSpecificL2 { ++ e_FM_PCD_MANIP_HDR_RMV_ETHERNET, /**< Ethernet/802.3 MAC */ ++ e_FM_PCD_MANIP_HDR_RMV_STACKED_QTAGS, /**< stacked QTags */ ++ e_FM_PCD_MANIP_HDR_RMV_ETHERNET_AND_MPLS, /**< MPLS and Ethernet/802.3 MAC header until ++ the header which follows the MPLS header */ ++ e_FM_PCD_MANIP_HDR_RMV_MPLS, /**< Remove MPLS header (Unlimited MPLS labels) */ ++ e_FM_PCD_MANIP_HDR_RMV_PPPOE /**< Remove the PPPoE header and PPP protocol field. */ ++} e_FmPcdManipHdrRmvSpecificL2; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting specific fields updates ++*//***************************************************************************/ ++typedef enum e_FmPcdManipHdrFieldUpdateType { ++ e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN, /**< VLAN updates */ ++ e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4, /**< IPV4 updates */ ++ e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6, /**< IPV6 updates */ ++ e_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP, /**< TCP_UDP updates */ ++} e_FmPcdManipHdrFieldUpdateType; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting VLAN updates ++*//***************************************************************************/ ++typedef enum e_FmPcdManipHdrFieldUpdateVlan { ++ e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_VPRI, /**< Replace VPri of outer most VLAN tag. */ ++ e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN /**< DSCP to VLAN priority bits translation */ ++} e_FmPcdManipHdrFieldUpdateVlan; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting specific L2 header insertion ++*//***************************************************************************/ ++typedef enum e_FmPcdManipHdrInsrtSpecificL2 { ++ e_FM_PCD_MANIP_HDR_INSRT_MPLS, /**< Insert MPLS header (Unlimited MPLS labels) */ ++ e_FM_PCD_MANIP_HDR_INSRT_PPPOE /**< Insert PPPOE */ ++} e_FmPcdManipHdrInsrtSpecificL2; ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Description Enumeration type for selecting QoS mapping mode ++ ++ Note: In all cases except 'e_FM_PCD_MANIP_HDR_QOS_MAPPING_NONE' ++ User should instruct the port to read the hash-result ++*//***************************************************************************/ ++typedef enum e_FmPcdManipHdrQosMappingMode { ++ e_FM_PCD_MANIP_HDR_QOS_MAPPING_NONE = 0, /**< No mapping, QoS field will not be changed */ ++ e_FM_PCD_MANIP_HDR_QOS_MAPPING_AS_IS, /**< QoS field will be overwritten by the last byte in the hash-result. */ ++} e_FmPcdManipHdrQosMappingMode; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting QoS source ++ ++ Note: In all cases except 'e_FM_PCD_MANIP_HDR_QOS_SRC_NONE' ++ User should left room for the hash-result on input/output buffer ++ and instruct the port to read/write the hash-result to the buffer (RPD should be set) ++*//***************************************************************************/ ++typedef enum e_FmPcdManipHdrQosSrc { ++ e_FM_PCD_MANIP_HDR_QOS_SRC_NONE = 0, /**< TODO */ ++ e_FM_PCD_MANIP_HDR_QOS_SRC_USER_DEFINED, /**< QoS will be taken from the last byte in the hash-result. */ ++} e_FmPcdManipHdrQosSrc; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of header insertion ++*//***************************************************************************/ ++typedef enum e_FmPcdManipHdrInsrtByHdrType { ++ e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2, /**< Specific L2 fields insertion */ ++#if (DPAA_VERSION >= 11) ++ e_FM_PCD_MANIP_INSRT_BY_HDR_IP, /**< IP insertion */ ++ e_FM_PCD_MANIP_INSRT_BY_HDR_UDP, /**< UDP insertion */ ++ e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE, /**< UDP lite insertion */ ++ e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP /**< CAPWAP insertion */ ++#endif /* (DPAA_VERSION >= 11) */ ++} e_FmPcdManipHdrInsrtByHdrType; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting specific customCommand ++*//***************************************************************************/ ++typedef enum e_FmPcdManipHdrCustomType { ++ e_FM_PCD_MANIP_HDR_CUSTOM_IP_REPLACE, /**< Replace IPv4/IPv6 */ ++ e_FM_PCD_MANIP_HDR_CUSTOM_GEN_FIELD_REPLACE, /**< Replace IPv4/IPv6 */ ++} e_FmPcdManipHdrCustomType; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting specific customCommand ++*//***************************************************************************/ ++typedef enum e_FmPcdManipHdrCustomIpReplace { ++ e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV4_BY_IPV6, /**< Replace IPv4 by IPv6 */ ++ e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4 /**< Replace IPv6 by IPv4 */ ++} e_FmPcdManipHdrCustomIpReplace; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of header removal ++*//***************************************************************************/ ++typedef enum e_FmPcdManipHdrRmvByHdrType { ++ e_FM_PCD_MANIP_RMV_BY_HDR_SPECIFIC_L2 = 0, /**< Specific L2 fields removal */ ++#if (DPAA_VERSION >= 11) ++ e_FM_PCD_MANIP_RMV_BY_HDR_CAPWAP, /**< CAPWAP removal */ ++#endif /* (DPAA_VERSION >= 11) */ ++#if (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) ++ e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START, /**< Locate from data that is not the header */ ++#endif /* (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ ++} e_FmPcdManipHdrRmvByHdrType; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of timeout mode ++*//***************************************************************************/ ++typedef enum e_FmPcdManipReassemTimeOutMode { ++ e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAMES, /**< Limits the time of the reassembly process ++ from the first fragment to the last */ ++ e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAG /**< Limits the time of receiving the fragment */ ++} e_FmPcdManipReassemTimeOutMode; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of WaysNumber mode ++*//***************************************************************************/ ++typedef enum e_FmPcdManipReassemWaysNumber { ++ e_FM_PCD_MANIP_ONE_WAY_HASH = 1, /**< One way hash */ ++ e_FM_PCD_MANIP_TWO_WAYS_HASH, /**< Two ways hash */ ++ e_FM_PCD_MANIP_THREE_WAYS_HASH, /**< Three ways hash */ ++ e_FM_PCD_MANIP_FOUR_WAYS_HASH, /**< Four ways hash */ ++ e_FM_PCD_MANIP_FIVE_WAYS_HASH, /**< Five ways hash */ ++ e_FM_PCD_MANIP_SIX_WAYS_HASH, /**< Six ways hash */ ++ e_FM_PCD_MANIP_SEVEN_WAYS_HASH, /**< Seven ways hash */ ++ e_FM_PCD_MANIP_EIGHT_WAYS_HASH /**< Eight ways hash */ ++} e_FmPcdManipReassemWaysNumber; ++ ++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of statistics mode ++*//***************************************************************************/ ++typedef enum e_FmPcdStatsType { ++ e_FM_PCD_STATS_PER_FLOWID = 0 /**< Flow ID is used as index for getting statistics */ ++} e_FmPcdStatsType; ++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting manipulation type ++*//***************************************************************************/ ++typedef enum e_FmPcdManipType { ++ e_FM_PCD_MANIP_HDR = 0, /**< Header manipulation */ ++ e_FM_PCD_MANIP_REASSEM, /**< Reassembly */ ++ e_FM_PCD_MANIP_FRAG, /**< Fragmentation */ ++ e_FM_PCD_MANIP_SPECIAL_OFFLOAD /**< Special Offloading */ ++} e_FmPcdManipType; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of statistics mode ++*//***************************************************************************/ ++typedef enum e_FmPcdCcStatsMode { ++ e_FM_PCD_CC_STATS_MODE_NONE = 0, /**< No statistics support */ ++ e_FM_PCD_CC_STATS_MODE_FRAME, /**< Frame count statistics */ ++ e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME, /**< Byte and frame count statistics */ ++#if (DPAA_VERSION >= 11) ++ e_FM_PCD_CC_STATS_MODE_RMON, /**< Byte and frame length range count statistics; ++ This mode is supported only on B4860 device */ ++#endif /* (DPAA_VERSION >= 11) */ ++} e_FmPcdCcStatsMode; ++ ++/**************************************************************************//** ++ @Description Enumeration type for determining the action in case an IP packet ++ is larger than MTU but its DF (Don't Fragment) bit is set. ++*//***************************************************************************/ ++typedef enum e_FmPcdManipDontFragAction { ++ e_FM_PCD_MANIP_DISCARD_PACKET = 0, /**< Discard packet */ ++ e_FM_PCD_MANIP_ENQ_TO_ERR_Q_OR_DISCARD_PACKET = e_FM_PCD_MANIP_DISCARD_PACKET, ++ /**< Obsolete, cannot enqueue to error queue; ++ In practice, selects to discard packets; ++ Will be removed in the future */ ++ e_FM_PCD_MANIP_FRAGMENT_PACKET, /**< Fragment packet and continue normal processing */ ++ e_FM_PCD_MANIP_CONTINUE_WITHOUT_FRAG /**< Continue normal processing without fragmenting the packet */ ++} e_FmPcdManipDontFragAction; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of special offload manipulation ++*//***************************************************************************/ ++typedef enum e_FmPcdManipSpecialOffloadType { ++ e_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC, /**< IPSec offload manipulation */ ++#if (DPAA_VERSION >= 11) ++ e_FM_PCD_MANIP_SPECIAL_OFFLOAD_CAPWAP /**< CAPWAP offload manipulation */ ++#endif /* (DPAA_VERSION >= 11) */ ++} e_FmPcdManipSpecialOffloadType; ++ ++ ++/**************************************************************************//** ++ @Description A Union of protocol dependent special options ++*//***************************************************************************/ ++typedef union u_FmPcdHdrProtocolOpt { ++ ethProtocolOpt_t ethOpt; /**< Ethernet options */ ++ vlanProtocolOpt_t vlanOpt; /**< VLAN options */ ++ mplsProtocolOpt_t mplsOpt; /**< MPLS options */ ++ ipv4ProtocolOpt_t ipv4Opt; /**< IPv4 options */ ++ ipv6ProtocolOpt_t ipv6Opt; /**< IPv6 options */ ++#if (DPAA_VERSION >= 11) ++ capwapProtocolOpt_t capwapOpt; /**< CAPWAP options */ ++#endif /* (DPAA_VERSION >= 11) */ ++} u_FmPcdHdrProtocolOpt; ++ ++/**************************************************************************//** ++ @Description A union holding protocol fields ++ ++ ++ Fields supported as "full fields": ++ HEADER_TYPE_ETH: ++ NET_HEADER_FIELD_ETH_DA ++ NET_HEADER_FIELD_ETH_SA ++ NET_HEADER_FIELD_ETH_TYPE ++ ++ HEADER_TYPE_LLC_SNAP: ++ NET_HEADER_FIELD_LLC_SNAP_TYPE ++ ++ HEADER_TYPE_VLAN: ++ NET_HEADER_FIELD_VLAN_TCI ++ (index may apply: ++ e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1, ++ e_FM_PCD_HDR_INDEX_LAST) ++ ++ HEADER_TYPE_MPLS: ++ NET_HEADER_FIELD_MPLS_LABEL_STACK ++ (index may apply: ++ e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1, ++ e_FM_PCD_HDR_INDEX_2, ++ e_FM_PCD_HDR_INDEX_LAST) ++ ++ HEADER_TYPE_IPv4: ++ NET_HEADER_FIELD_IPv4_SRC_IP ++ NET_HEADER_FIELD_IPv4_DST_IP ++ NET_HEADER_FIELD_IPv4_PROTO ++ NET_HEADER_FIELD_IPv4_TOS ++ (index may apply: ++ e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1, ++ e_FM_PCD_HDR_INDEX_2/e_FM_PCD_HDR_INDEX_LAST) ++ ++ HEADER_TYPE_IPv6: ++ NET_HEADER_FIELD_IPv6_SRC_IP ++ NET_HEADER_FIELD_IPv6_DST_IP ++ NET_HEADER_FIELD_IPv6_NEXT_HDR ++ NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL | NET_HEADER_FIELD_IPv6_TC (must come together!) ++ (index may apply: ++ e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1, ++ e_FM_PCD_HDR_INDEX_2/e_FM_PCD_HDR_INDEX_LAST) ++ ++ (Note that starting from DPAA 1-1, NET_HEADER_FIELD_IPv6_NEXT_HDR applies to ++ the last next header indication, meaning the next L4, which may be ++ present at the Ipv6 last extension. On earlier revisions this field ++ applies to the Next-Header field of the main IPv6 header) ++ ++ HEADER_TYPE_IP: ++ NET_HEADER_FIELD_IP_PROTO ++ (index may apply: ++ e_FM_PCD_HDR_INDEX_LAST) ++ NET_HEADER_FIELD_IP_DSCP ++ (index may apply: ++ e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1) ++ HEADER_TYPE_GRE: ++ NET_HEADER_FIELD_GRE_TYPE ++ ++ HEADER_TYPE_MINENCAP ++ NET_HEADER_FIELD_MINENCAP_SRC_IP ++ NET_HEADER_FIELD_MINENCAP_DST_IP ++ NET_HEADER_FIELD_MINENCAP_TYPE ++ ++ HEADER_TYPE_TCP: ++ NET_HEADER_FIELD_TCP_PORT_SRC ++ NET_HEADER_FIELD_TCP_PORT_DST ++ NET_HEADER_FIELD_TCP_FLAGS ++ ++ HEADER_TYPE_UDP: ++ NET_HEADER_FIELD_UDP_PORT_SRC ++ NET_HEADER_FIELD_UDP_PORT_DST ++ ++ HEADER_TYPE_UDP_LITE: ++ NET_HEADER_FIELD_UDP_LITE_PORT_SRC ++ NET_HEADER_FIELD_UDP_LITE_PORT_DST ++ ++ HEADER_TYPE_IPSEC_AH: ++ NET_HEADER_FIELD_IPSEC_AH_SPI ++ NET_HEADER_FIELD_IPSEC_AH_NH ++ ++ HEADER_TYPE_IPSEC_ESP: ++ NET_HEADER_FIELD_IPSEC_ESP_SPI ++ ++ HEADER_TYPE_SCTP: ++ NET_HEADER_FIELD_SCTP_PORT_SRC ++ NET_HEADER_FIELD_SCTP_PORT_DST ++ ++ HEADER_TYPE_DCCP: ++ NET_HEADER_FIELD_DCCP_PORT_SRC ++ NET_HEADER_FIELD_DCCP_PORT_DST ++ ++ HEADER_TYPE_PPPoE: ++ NET_HEADER_FIELD_PPPoE_PID ++ NET_HEADER_FIELD_PPPoE_SID ++ ++ ***************************************************************** ++ Fields supported as "from fields": ++ HEADER_TYPE_ETH (with or without validation): ++ NET_HEADER_FIELD_ETH_TYPE ++ ++ HEADER_TYPE_VLAN (with or without validation): ++ NET_HEADER_FIELD_VLAN_TCI ++ (index may apply: ++ e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1, ++ e_FM_PCD_HDR_INDEX_LAST) ++ ++ HEADER_TYPE_IPv4 (without validation): ++ NET_HEADER_FIELD_IPv4_PROTO ++ (index may apply: ++ e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1, ++ e_FM_PCD_HDR_INDEX_2/e_FM_PCD_HDR_INDEX_LAST) ++ ++ HEADER_TYPE_IPv6 (without validation): ++ NET_HEADER_FIELD_IPv6_NEXT_HDR ++ (index may apply: ++ e_FM_PCD_HDR_INDEX_NONE/e_FM_PCD_HDR_INDEX_1, ++ e_FM_PCD_HDR_INDEX_2/e_FM_PCD_HDR_INDEX_LAST) ++ ++*//***************************************************************************/ ++typedef union t_FmPcdFields { ++ headerFieldEth_t eth; /**< Ethernet */ ++ headerFieldVlan_t vlan; /**< VLAN */ ++ headerFieldLlcSnap_t llcSnap; /**< LLC SNAP */ ++ headerFieldPppoe_t pppoe; /**< PPPoE */ ++ headerFieldMpls_t mpls; /**< MPLS */ ++ headerFieldIp_t ip; /**< IP */ ++ headerFieldIpv4_t ipv4; /**< IPv4 */ ++ headerFieldIpv6_t ipv6; /**< IPv6 */ ++ headerFieldUdp_t udp; /**< UDP */ ++ headerFieldUdpLite_t udpLite; /**< UDP Lite */ ++ headerFieldTcp_t tcp; /**< TCP */ ++ headerFieldSctp_t sctp; /**< SCTP */ ++ headerFieldDccp_t dccp; /**< DCCP */ ++ headerFieldGre_t gre; /**< GRE */ ++ headerFieldMinencap_t minencap; /**< Minimal Encapsulation */ ++ headerFieldIpsecAh_t ipsecAh; /**< IPSec AH */ ++ headerFieldIpsecEsp_t ipsecEsp; /**< IPSec ESP */ ++ headerFieldUdpEncapEsp_t udpEncapEsp; /**< UDP Encapsulation ESP */ ++} t_FmPcdFields; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header extraction for key generation ++*//***************************************************************************/ ++typedef struct t_FmPcdFromHdr { ++ uint8_t size; /**< Size in byte */ ++ uint8_t offset; /**< Byte offset */ ++} t_FmPcdFromHdr; ++ ++/**************************************************************************//** ++ @Description Parameters for defining field extraction for key generation ++*//***************************************************************************/ ++typedef struct t_FmPcdFromField { ++ t_FmPcdFields field; /**< Field selection */ ++ uint8_t size; /**< Size in byte */ ++ uint8_t offset; /**< Byte offset */ ++} t_FmPcdFromField; ++ ++/**************************************************************************//** ++ @Description Parameters for defining a single network environment unit ++ ++ A distinction unit should be defined if it will later be used ++ by one or more PCD engines to distinguish between flows. ++*//***************************************************************************/ ++typedef struct t_FmPcdDistinctionUnit { ++ struct { ++ e_NetHeaderType hdr; /**< One of the headers supported by the FM */ ++ u_FmPcdHdrProtocolOpt opt; /**< Select only one option ! */ ++ } hdrs[FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS]; ++} t_FmPcdDistinctionUnit; ++ ++/**************************************************************************//** ++ @Description Parameters for defining all different distinction units supported ++ by a specific PCD Network Environment Characteristics module. ++ ++ Each unit represent a protocol or a group of protocols that may ++ be used later by the different PCD engines to distinguish ++ between flows. ++*//***************************************************************************/ ++typedef struct t_FmPcdNetEnvParams { ++ uint8_t numOfDistinctionUnits; /**< Number of different units to be identified */ ++ t_FmPcdDistinctionUnit units[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; /**< An array of numOfDistinctionUnits of the ++ different units to be identified */ ++} t_FmPcdNetEnvParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining a single extraction action when ++ creating a key ++*//***************************************************************************/ ++typedef struct t_FmPcdExtractEntry { ++ e_FmPcdExtractType type; /**< Extraction type select */ ++ union { ++ struct { ++ e_NetHeaderType hdr; /**< Header selection */ ++ bool ignoreProtocolValidation; ++ /**< Ignore protocol validation */ ++ e_FmPcdHdrIndex hdrIndex; /**< Relevant only for MPLS, VLAN and tunneled ++ IP. Otherwise should be cleared. */ ++ e_FmPcdExtractByHdrType type; /**< Header extraction type select */ ++ union { ++ t_FmPcdFromHdr fromHdr; /**< Extract bytes from header parameters */ ++ t_FmPcdFromField fromField; /**< Extract bytes from field parameters */ ++ t_FmPcdFields fullField; /**< Extract full filed parameters */ ++ } extractByHdrType; ++ } extractByHdr; /**< used when type = e_FM_PCD_KG_EXTRACT_BY_HDR */ ++ struct { ++ e_FmPcdExtractFrom src; /**< Non-header extraction source */ ++ e_FmPcdAction action; /**< Relevant for CC Only */ ++ uint16_t icIndxMask; /**< Relevant only for CC when ++ action = e_FM_PCD_ACTION_INDEXED_LOOKUP; ++ Note that the number of bits that are set within ++ this mask must be log2 of the CC-node 'numOfKeys'. ++ Note that the mask cannot be set on the lower bits. */ ++ uint8_t offset; /**< Byte offset */ ++ uint8_t size; /**< Size in byte */ ++ } extractNonHdr; /**< used when type = e_FM_PCD_KG_EXTRACT_NON_HDR */ ++ }; ++} t_FmPcdExtractEntry; ++ ++/**************************************************************************//** ++ @Description Parameters for defining masks for each extracted field in the key. ++*//***************************************************************************/ ++typedef struct t_FmPcdKgExtractMask { ++ uint8_t extractArrayIndex; /**< Index in the extraction array, as initialized by user */ ++ uint8_t offset; /**< Byte offset */ ++ uint8_t mask; /**< A byte mask (selected bits will be used) */ ++} t_FmPcdKgExtractMask; ++ ++/**************************************************************************//** ++ @Description Parameters for defining default selection per groups of fields ++*//***************************************************************************/ ++typedef struct t_FmPcdKgExtractDflt { ++ e_FmPcdKgKnownFieldsDfltTypes type; /**< Default type select */ ++ e_FmPcdKgExtractDfltSelect dfltSelect; /**< Default register select */ ++} t_FmPcdKgExtractDflt; ++ ++/**************************************************************************//** ++ @Description Parameters for defining key extraction and hashing ++*//***************************************************************************/ ++typedef struct t_FmPcdKgKeyExtractAndHashParams { ++ uint32_t privateDflt0; /**< Scheme default register 0 */ ++ uint32_t privateDflt1; /**< Scheme default register 1 */ ++ uint8_t numOfUsedExtracts; /**< defines the valid size of the following array */ ++ t_FmPcdExtractEntry extractArray [FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY]; /**< An array of extractions definition. */ ++ uint8_t numOfUsedDflts; /**< defines the valid size of the following array */ ++ t_FmPcdKgExtractDflt dflts[FM_PCD_KG_NUM_OF_DEFAULT_GROUPS]; ++ /**< For each extraction used in this scheme, specify the required ++ default register to be used when header is not found. ++ types not specified in this array will get undefined value. */ ++ uint8_t numOfUsedMasks; /**< defines the valid size of the following array */ ++ t_FmPcdKgExtractMask masks[FM_PCD_KG_NUM_OF_EXTRACT_MASKS]; ++ uint8_t hashShift; /**< hash result right shift. Select the 24 bits out of the 64 hash ++ result. 0 means using the 24 LSB's, otherwise use the ++ 24 LSB's after shifting right.*/ ++ uint32_t hashDistributionNumOfFqids; /**< must be > 1 and a power of 2. Represents the range ++ of queues for the key and hash functionality */ ++ uint8_t hashDistributionFqidsShift; /**< selects the FQID bits that will be effected by the hash */ ++ bool symmetricHash; /**< TRUE to generate the same hash for frames with swapped source and ++ destination fields on all layers; If TRUE, driver will check that for ++ all layers, if SRC extraction is selected, DST extraction must also be ++ selected, and vice versa. */ ++} t_FmPcdKgKeyExtractAndHashParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining a single FQID mask (extracted OR). ++*//***************************************************************************/ ++typedef struct t_FmPcdKgExtractedOrParams { ++ e_FmPcdExtractType type; /**< Extraction type select */ ++ union { ++ struct { /**< used when type = e_FM_PCD_KG_EXTRACT_BY_HDR */ ++ e_NetHeaderType hdr; ++ e_FmPcdHdrIndex hdrIndex; /**< Relevant only for MPLS, VLAN and tunneled ++ IP. Otherwise should be cleared.*/ ++ bool ignoreProtocolValidation; ++ /**< continue extraction even if protocol is not recognized */ ++ } extractByHdr; /**< Header to extract by */ ++ e_FmPcdExtractFrom src; /**< used when type = e_FM_PCD_KG_EXTRACT_NON_HDR */ ++ }; ++ uint8_t extractionOffset; /**< Offset for extraction (in bytes). */ ++ e_FmPcdKgExtractDfltSelect dfltValue; /**< Select register from which extraction is taken if ++ field not found */ ++ uint8_t mask; /**< Extraction mask (specified bits are used) */ ++ uint8_t bitOffsetInFqid; /**< 0-31, Selects which bits of the 24 FQID bits to effect using ++ the extracted byte; Assume byte is placed as the 8 MSB's in ++ a 32 bit word where the lower bits ++ are the FQID; i.e if bitOffsetInFqid=1 than its LSB ++ will effect the FQID MSB, if bitOffsetInFqid=24 than the ++ extracted byte will effect the 8 LSB's of the FQID, ++ if bitOffsetInFqid=31 than the byte's MSB will effect ++ the FQID's LSB; 0 means - no effect on FQID; ++ Note that one, and only one of ++ bitOffsetInFqid or bitOffsetInPlcrProfile must be set (i.e, ++ extracted byte must effect either FQID or Policer profile).*/ ++ uint8_t bitOffsetInPlcrProfile; ++ /**< 0-15, Selects which bits of the 8 policer profile id bits to ++ effect using the extracted byte; Assume byte is placed ++ as the 8 MSB's in a 16 bit word where the lower bits ++ are the policer profile id; i.e if bitOffsetInPlcrProfile=1 ++ than its LSB will effect the profile MSB, if bitOffsetInFqid=8 ++ than the extracted byte will effect the whole policer profile id, ++ if bitOffsetInFqid=15 than the byte's MSB will effect ++ the Policer Profile id's LSB; ++ 0 means - no effect on policer profile; Note that one, and only one of ++ bitOffsetInFqid or bitOffsetInPlcrProfile must be set (i.e, ++ extracted byte must effect either FQID or Policer profile).*/ ++} t_FmPcdKgExtractedOrParams; ++ ++/**************************************************************************//** ++ @Description Parameters for configuring a scheme counter ++*//***************************************************************************/ ++typedef struct t_FmPcdKgSchemeCounter { ++ bool update; /**< FALSE to keep the current counter state ++ and continue from that point, TRUE to update/reset ++ the counter when the scheme is written. */ ++ uint32_t value; /**< If update=TRUE, this value will be written into the ++ counter. clear this field to reset the counter. */ ++} t_FmPcdKgSchemeCounter; ++ ++/**************************************************************************//** ++ @Description Parameters for configuring a policer profile for a KeyGen scheme ++ (when policer is the next engine after this scheme). ++*//***************************************************************************/ ++typedef struct t_FmPcdKgPlcrProfile { ++ bool sharedProfile; /**< TRUE if this profile is shared between ports ++ (managed by master partition); Must not be TRUE ++ if profile is after Coarse Classification*/ ++ bool direct; /**< if TRUE, directRelativeProfileId only selects the profile ++ id, if FALSE fqidOffsetRelativeProfileIdBase is used ++ together with fqidOffsetShift and numOfProfiles ++ parameters, to define a range of profiles from ++ which the KeyGen result will determine the ++ destination policer profile. */ ++ union { ++ uint16_t directRelativeProfileId; /**< Used if 'direct' is TRUE, to select policer profile. ++ should indicate the policer profile offset within the ++ port's policer profiles or shared window. */ ++ struct { ++ uint8_t fqidOffsetShift; /**< Shift on the KeyGen create FQID offset (i.e. not the ++ final FQID - without the FQID base). */ ++ uint8_t fqidOffsetRelativeProfileIdBase; ++ /**< The base of the FMan Port's relative Storage-Profile ID; ++ this value will be "OR'ed" with the KeyGen create FQID ++ offset (i.e. not the final FQID - without the FQID base); ++ the final result should indicate the Storage-Profile offset ++ within the FMan Port's relative Storage-Profiles window/ ++ (or the SHARED window depends on 'sharedProfile'). */ ++ uint8_t numOfProfiles; /**< Range of profiles starting at base */ ++ } indirectProfile; /**< Indirect profile parameters */ ++ } profileSelect; /**< Direct/indirect profile selection and parameters */ ++} t_FmPcdKgPlcrProfile; ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Description Parameters for configuring a storage profile for a KeyGen scheme. ++*//***************************************************************************/ ++typedef struct t_FmPcdKgStorageProfile { ++ bool direct; /**< If TRUE, directRelativeProfileId only selects the ++ profile id; ++ If FALSE, fqidOffsetRelativeProfileIdBase is used ++ together with fqidOffsetShift and numOfProfiles ++ parameters to define a range of profiles from which ++ the KeyGen result will determine the destination ++ storage profile. */ ++ union { ++ uint16_t directRelativeProfileId; /**< Used when 'direct' is TRUE, to select a storage profile; ++ should indicate the storage profile offset within the ++ port's storage profiles window. */ ++ struct { ++ uint8_t fqidOffsetShift; /**< Shift on the KeyGen create FQID offset (i.e. not the ++ final FQID - without the FQID base). */ ++ uint8_t fqidOffsetRelativeProfileIdBase; ++ /**< The base of the FMan Port's relative Storage-Profile ID; ++ this value will be "OR'ed" with the KeyGen create FQID ++ offset (i.e. not the final FQID - without the FQID base); ++ the final result should indicate the Storage-Profile offset ++ within the FMan Port's relative Storage-Profiles window. */ ++ uint8_t numOfProfiles; /**< Range of profiles starting at base. */ ++ } indirectProfile; /**< Indirect profile parameters. */ ++ } profileSelect; /**< Direct/indirect profile selection and parameters. */ ++} t_FmPcdKgStorageProfile; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++/**************************************************************************//** ++ @Description Parameters for defining CC as the next engine after KeyGen ++*//***************************************************************************/ ++typedef struct t_FmPcdKgCc { ++ t_Handle h_CcTree; /**< A handle to a CC Tree */ ++ uint8_t grpId; /**< CC group id within the CC tree */ ++ bool plcrNext; /**< TRUE if after CC, in case of data frame, ++ policing is required. */ ++ bool bypassPlcrProfileGeneration; /**< TRUE to bypass KeyGen policer profile generation; ++ selected profile is the one set at port initialization. */ ++ t_FmPcdKgPlcrProfile plcrProfile; /**< Valid only if plcrNext = TRUE and ++ bypassPlcrProfileGeneration = FALSE */ ++} t_FmPcdKgCc; ++ ++/**************************************************************************//** ++ @Description Parameters for defining initializing a KeyGen scheme ++*//***************************************************************************/ ++typedef struct t_FmPcdKgSchemeParams { ++ bool modify; /**< TRUE to change an existing scheme */ ++ union ++ { ++ uint8_t relativeSchemeId; /**< if modify=FALSE:Partition relative scheme id */ ++ t_Handle h_Scheme; /**< if modify=TRUE: a handle of the existing scheme */ ++ } id; ++ bool alwaysDirect; /**< This scheme is reached only directly, i.e. no need ++ for match vector; KeyGen will ignore it when matching */ ++ struct { /**< HL Relevant only if alwaysDirect = FALSE */ ++ t_Handle h_NetEnv; /**< A handle to the Network environment as returned ++ by FM_PCD_NetEnvCharacteristicsSet() */ ++ uint8_t numOfDistinctionUnits; /**< Number of NetEnv units listed in unitIds array */ ++ uint8_t unitIds[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; ++ /**< Indexes as passed to SetNetEnvCharacteristics array*/ ++ } netEnvParams; ++ bool useHash; /**< use the KeyGen Hash functionality */ ++ t_FmPcdKgKeyExtractAndHashParams keyExtractAndHashParams; ++ /**< used only if useHash = TRUE */ ++ bool bypassFqidGeneration; /**< Normally - FALSE, TRUE to avoid FQID update in the IC; ++ In such a case FQID after KeyGen will be the default FQID ++ defined for the relevant port, or the FQID defined by CC ++ in cases where CC was the previous engine. */ ++ uint32_t baseFqid; /**< Base FQID; Relevant only if bypassFqidGeneration = FALSE; ++ If hash is used and an even distribution is expected ++ according to hashDistributionNumOfFqids, baseFqid must be aligned to ++ hashDistributionNumOfFqids. */ ++ uint8_t numOfUsedExtractedOrs; /**< Number of FQID masks listed in extractedOrs array */ ++ t_FmPcdKgExtractedOrParams extractedOrs[FM_PCD_KG_NUM_OF_GENERIC_REGS]; ++ /**< FM_PCD_KG_NUM_OF_GENERIC_REGS ++ registers are shared between qidMasks ++ functionality and some of the extraction ++ actions; Normally only some will be used ++ for qidMask. Driver will return error if ++ resource is full at initialization time. */ ++ ++#if (DPAA_VERSION >= 11) ++ bool overrideStorageProfile; /**< TRUE if KeyGen override previously decided storage profile */ ++ t_FmPcdKgStorageProfile storageProfile; /**< Used when overrideStorageProfile TRUE */ ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ e_FmPcdEngine nextEngine; /**< may be BMI, PLCR or CC */ ++ union { /**< depends on nextEngine */ ++ e_FmPcdDoneAction doneAction; /**< Used when next engine is BMI (done) */ ++ t_FmPcdKgPlcrProfile plcrProfile; /**< Used when next engine is PLCR */ ++ t_FmPcdKgCc cc; /**< Used when next engine is CC */ ++ } kgNextEngineParams; ++ t_FmPcdKgSchemeCounter schemeCounter; /**< A structure of parameters for updating ++ the scheme counter */ ++} t_FmPcdKgSchemeParams; ++ ++/**************************************************************************//** ++ @Collection Definitions for CC statistics ++*//***************************************************************************/ ++#if (DPAA_VERSION >= 11) ++#define FM_PCD_CC_STATS_MAX_NUM_OF_FLR 10 /* Maximal supported number of frame length ranges */ ++#define FM_PCD_CC_STATS_FLR_SIZE 2 /* Size in bytes of a frame length range limit */ ++#endif /* (DPAA_VERSION >= 11) */ ++#define FM_PCD_CC_STATS_COUNTER_SIZE 4 /* Size in bytes of a frame length range counter */ ++/* @} */ ++ ++/**************************************************************************//** ++ @Description Parameters for defining CC as the next engine after a CC node. ++*//***************************************************************************/ ++typedef struct t_FmPcdCcNextCcParams { ++ t_Handle h_CcNode; /**< A handle of the next CC node */ ++} t_FmPcdCcNextCcParams; ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Description Parameters for defining Frame replicator as the next engine after a CC node. ++*//***************************************************************************/ ++typedef struct t_FmPcdCcNextFrParams { ++ t_Handle h_FrmReplic; /**< A handle of the next frame replicator group */ ++} t_FmPcdCcNextFrParams; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++/**************************************************************************//** ++ @Description Parameters for defining Policer as the next engine after a CC node. ++*//***************************************************************************/ ++typedef struct t_FmPcdCcNextPlcrParams { ++ bool overrideParams; /**< TRUE if CC override previously decided parameters*/ ++ bool sharedProfile; /**< Relevant only if overrideParams=TRUE: ++ TRUE if this profile is shared between ports */ ++ uint16_t newRelativeProfileId; /**< Relevant only if overrideParams=TRUE: ++ (otherwise profile id is taken from KeyGen); ++ This parameter should indicate the policer ++ profile offset within the port's ++ policer profiles or from SHARED window.*/ ++ uint32_t newFqid; /**< Relevant only if overrideParams=TRUE: ++ FQID for enqueuing the frame; ++ In earlier chips if policer next engine is KEYGEN, ++ this parameter can be 0, because the KEYGEN ++ always decides the enqueue FQID.*/ ++#if (DPAA_VERSION >= 11) ++ uint8_t newRelativeStorageProfileId; ++ /**< Indicates the relative storage profile offset within ++ the port's storage profiles window; ++ Relevant only if the port was configured with VSP. */ ++#endif /* (DPAA_VERSION >= 11) */ ++} t_FmPcdCcNextPlcrParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining enqueue as the next action after a CC node. ++*//***************************************************************************/ ++typedef struct t_FmPcdCcNextEnqueueParams { ++ e_FmPcdDoneAction action; /**< Action - when next engine is BMI (done) */ ++ bool overrideFqid; /**< TRUE if CC override previously decided fqid and vspid, ++ relevant if action = e_FM_PCD_ENQ_FRAME */ ++ uint32_t newFqid; /**< Valid if overrideFqid=TRUE, FQID for enqueuing the frame ++ (otherwise FQID is taken from KeyGen), ++ relevant if action = e_FM_PCD_ENQ_FRAME */ ++#if (DPAA_VERSION >= 11) ++ uint8_t newRelativeStorageProfileId; ++ /**< Valid if overrideFqid=TRUE, Indicates the relative virtual ++ storage profile offset within the port's storage profiles ++ window; Relevant only if the port was configured with VSP. */ ++#endif /* (DPAA_VERSION >= 11) */ ++} t_FmPcdCcNextEnqueueParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining KeyGen as the next engine after a CC node. ++*//***************************************************************************/ ++typedef struct t_FmPcdCcNextKgParams { ++ bool overrideFqid; /**< TRUE if CC override previously decided fqid and vspid, ++ Note - this parameters irrelevant for earlier chips */ ++ uint32_t newFqid; /**< Valid if overrideFqid=TRUE, FQID for enqueuing the frame ++ (otherwise FQID is taken from KeyGen), ++ Note - this parameters irrelevant for earlier chips */ ++#if (DPAA_VERSION >= 11) ++ uint8_t newRelativeStorageProfileId; ++ /**< Valid if overrideFqid=TRUE, Indicates the relative virtual ++ storage profile offset within the port's storage profiles ++ window; Relevant only if the port was configured with VSP. */ ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ t_Handle h_DirectScheme; /**< Direct scheme handle to go to. */ ++} t_FmPcdCcNextKgParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining the next engine after a CC node. ++*//***************************************************************************/ ++typedef struct t_FmPcdCcNextEngineParams { ++ e_FmPcdEngine nextEngine; /**< User has to initialize parameters ++ according to nextEngine definition */ ++ union { ++ t_FmPcdCcNextCcParams ccParams; /**< Parameters in case next engine is CC */ ++ t_FmPcdCcNextPlcrParams plcrParams; /**< Parameters in case next engine is PLCR */ ++ t_FmPcdCcNextEnqueueParams enqueueParams; /**< Parameters in case next engine is BMI */ ++ t_FmPcdCcNextKgParams kgParams; /**< Parameters in case next engine is KG */ ++#if (DPAA_VERSION >= 11) ++ t_FmPcdCcNextFrParams frParams; /**< Parameters in case next engine is FR */ ++#endif /* (DPAA_VERSION >= 11) */ ++ } params; /**< union used for all the next-engine parameters options */ ++ ++ t_Handle h_Manip; /**< Handle to Manipulation object. ++ Relevant if next engine is of type result ++ (e_FM_PCD_PLCR, e_FM_PCD_KG, e_FM_PCD_DONE) */ ++ ++ bool statisticsEn; /**< If TRUE, statistics counters are incremented ++ for each frame passing through this ++ Coarse Classification entry. */ ++} t_FmPcdCcNextEngineParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining a single CC key ++*//***************************************************************************/ ++typedef struct t_FmPcdCcKeyParams { ++ uint8_t *p_Key; /**< Relevant only if 'action' = e_FM_PCD_ACTION_EXACT_MATCH; ++ pointer to the key of the size defined in keySize */ ++ uint8_t *p_Mask; /**< Relevant only if 'action' = e_FM_PCD_ACTION_EXACT_MATCH; ++ pointer to the Mask per key of the size defined ++ in keySize. p_Key and p_Mask (if defined) has to be ++ of the same size defined in the keySize; ++ NOTE that if this value is equal for all entries whithin ++ this table, the driver will automatically use global-mask ++ (i.e. one common mask for all entries) instead of private ++ one; that is done in order to spare some memory and for ++ better performance. */ ++ t_FmPcdCcNextEngineParams ccNextEngineParams; ++ /**< parameters for the next for the defined Key in ++ the p_Key */ ++} t_FmPcdCcKeyParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining CC keys parameters ++ The driver supports two methods for CC node allocation: dynamic and static. ++ Static mode was created in order to prevent runtime alloc/free ++ of FMan memory (MURAM), which may cause fragmentation; in this mode, ++ the driver automatically allocates the memory according to ++ 'maxNumOfKeys' parameter. The driver calculates the maximal memory ++ size that may be used for this CC-Node taking into consideration ++ 'maskSupport' and 'statisticsMode' parameters. ++ When 'action' = e_FM_PCD_ACTION_INDEXED_LOOKUP in the extraction ++ parameters of this node, 'maxNumOfKeys' must be equal to 'numOfKeys'. ++ In dynamic mode, 'maxNumOfKeys' must be zero. At initialization, ++ all required structures are allocated according to 'numOfKeys' ++ parameter. During runtime modification, these structures are ++ re-allocated according to the updated number of keys. ++ ++ Please note that 'action' and 'icIndxMask' mentioned in the ++ specific parameter explanations are passed in the extraction ++ parameters of the node (fields of extractCcParams.extractNonHdr). ++*//***************************************************************************/ ++typedef struct t_KeysParams { ++ uint16_t maxNumOfKeys; /**< Maximum number of keys that will (ever) be used in this CC-Node; ++ A value of zero may be used for dynamic memory allocation. */ ++ bool maskSupport; /**< This parameter is relevant only if a node is initialized with ++ 'action' = e_FM_PCD_ACTION_EXACT_MATCH and maxNumOfKeys > 0; ++ Should be TRUE to reserve table memory for key masks, even if ++ initial keys do not contain masks, or if the node was initialized ++ as 'empty' (without keys); this will allow user to add keys with ++ masks at runtime. ++ NOTE that if user want to use only global-masks (i.e. one common mask ++ for all the entries within this table, this parameter should set to 'FALSE'. */ ++ e_FmPcdCcStatsMode statisticsMode; /**< Determines the supported statistics mode for all node's keys. ++ To enable statistics gathering, statistics should be enabled per ++ every key, using 'statisticsEn' in next engine parameters structure ++ of that key; ++ If 'maxNumOfKeys' is set, all required structures will be ++ preallocated for all keys. */ ++#if (DPAA_VERSION >= 11) ++ uint16_t frameLengthRanges[FM_PCD_CC_STATS_MAX_NUM_OF_FLR]; ++ /**< Relevant only for 'RMON' statistics mode ++ (this feature is supported only on B4860 device); ++ Holds a list of programmable thresholds - for each received frame, ++ its length in bytes is examined against these range thresholds and ++ the appropriate counter is incremented by 1 - for example, to belong ++ to range i, the following should hold: ++ range i-1 threshold < frame length <= range i threshold ++ Each range threshold must be larger then its preceding range ++ threshold, and last range threshold must be 0xFFFF. */ ++#endif /* (DPAA_VERSION >= 11) */ ++ uint16_t numOfKeys; /**< Number of initial keys; ++ Note that in case of 'action' = e_FM_PCD_ACTION_INDEXED_LOOKUP, ++ this field should be power-of-2 of the number of bits that are ++ set in 'icIndxMask'. */ ++ uint8_t keySize; /**< Size of key - for extraction of type FULL_FIELD, 'keySize' has ++ to be the standard size of the selected key; For other extraction ++ types, 'keySize' has to be as size of extraction; When 'action' = ++ e_FM_PCD_ACTION_INDEXED_LOOKUP, 'keySize' must be 2. */ ++ t_FmPcdCcKeyParams keyParams[FM_PCD_MAX_NUM_OF_KEYS]; ++ /**< An array with 'numOfKeys' entries, each entry specifies the ++ corresponding key parameters; ++ When 'action' = e_FM_PCD_ACTION_EXACT_MATCH, this value must not ++ exceed 255 (FM_PCD_MAX_NUM_OF_KEYS-1) as the last entry is saved ++ for the 'miss' entry. */ ++ t_FmPcdCcNextEngineParams ccNextEngineParamsForMiss; ++ /**< Parameters for defining the next engine when a key is not matched; ++ Not relevant if action = e_FM_PCD_ACTION_INDEXED_LOOKUP. */ ++} t_KeysParams; ++ ++ ++/**************************************************************************//** ++ @Description Parameters for defining a CC node ++*//***************************************************************************/ ++typedef struct t_FmPcdCcNodeParams { ++ t_FmPcdExtractEntry extractCcParams; /**< Extraction parameters */ ++ t_KeysParams keysParams; /**< Keys definition matching the selected extraction */ ++} t_FmPcdCcNodeParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining a hash table ++*//***************************************************************************/ ++typedef struct t_FmPcdHashTableParams { ++ uint16_t maxNumOfKeys; /**< Maximum Number Of Keys that will (ever) be used in this Hash-table */ ++ e_FmPcdCcStatsMode statisticsMode; /**< If not e_FM_PCD_CC_STATS_MODE_NONE, the required structures for the ++ requested statistics mode will be allocated according to maxNumOfKeys. */ ++ uint8_t kgHashShift; /**< KG-Hash-shift as it was configured in the KG-scheme ++ that leads to this hash-table. */ ++ uint16_t hashResMask; /**< Mask that will be used on the hash-result; ++ The number-of-sets for this hash will be calculated ++ as (2^(number of bits set in 'hashResMask')); ++ The 4 lower bits must be cleared. */ ++ uint8_t hashShift; /**< Byte offset from the beginning of the KeyGen hash result to the ++ 2-bytes to be used as hash index. */ ++ uint8_t matchKeySize; /**< Size of the exact match keys held by the hash buckets */ ++ ++ t_FmPcdCcNextEngineParams ccNextEngineParamsForMiss; /**< Parameters for defining the next engine when a key is not matched */ ++ ++} t_FmPcdHashTableParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining a CC tree group. ++ ++ This structure defines a CC group in terms of NetEnv units ++ and the action to be taken in each case. The unitIds list must ++ be given in order from low to high indices. ++ ++ t_FmPcdCcNextEngineParams is a list of 2^numOfDistinctionUnits ++ structures where each defines the next action to be taken for ++ each units combination. for example: ++ numOfDistinctionUnits = 2 ++ unitIds = {1,3} ++ p_NextEnginePerEntriesInGrp[0] = t_FmPcdCcNextEngineParams for the case that ++ unit 1 - not found; unit 3 - not found; ++ p_NextEnginePerEntriesInGrp[1] = t_FmPcdCcNextEngineParams for the case that ++ unit 1 - not found; unit 3 - found; ++ p_NextEnginePerEntriesInGrp[2] = t_FmPcdCcNextEngineParams for the case that ++ unit 1 - found; unit 3 - not found; ++ p_NextEnginePerEntriesInGrp[3] = t_FmPcdCcNextEngineParams for the case that ++ unit 1 - found; unit 3 - found; ++*//***************************************************************************/ ++typedef struct t_FmPcdCcGrpParams { ++ uint8_t numOfDistinctionUnits; /**< Up to 4 */ ++ uint8_t unitIds[FM_PCD_MAX_NUM_OF_CC_UNITS]; ++ /**< Indices of the units as defined in ++ FM_PCD_NetEnvCharacteristicsSet() */ ++ t_FmPcdCcNextEngineParams nextEnginePerEntriesInGrp[FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP]; ++ /**< Maximum entries per group is 16 */ ++} t_FmPcdCcGrpParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining CC tree groups ++*//***************************************************************************/ ++typedef struct t_FmPcdCcTreeParams { ++ t_Handle h_NetEnv; /**< A handle to the Network environment as returned ++ by FM_PCD_NetEnvCharacteristicsSet() */ ++ uint8_t numOfGrps; /**< Number of CC groups within the CC tree */ ++ t_FmPcdCcGrpParams ccGrpParams[FM_PCD_MAX_NUM_OF_CC_GROUPS]; ++ /**< Parameters for each group. */ ++} t_FmPcdCcTreeParams; ++ ++ ++/**************************************************************************//** ++ @Description CC key statistics structure ++*//***************************************************************************/ ++typedef struct t_FmPcdCcKeyStatistics { ++ uint32_t byteCount; /**< This counter reflects byte count of frames that ++ were matched by this key. */ ++ uint32_t frameCount; /**< This counter reflects count of frames that ++ were matched by this key. */ ++#if (DPAA_VERSION >= 11) ++ uint32_t frameLengthRangeCount[FM_PCD_CC_STATS_MAX_NUM_OF_FLR]; ++ /**< These counters reflect how many frames matched ++ this key in 'RMON' statistics mode: ++ Each counter holds the number of frames of a ++ specific frames length range, according to the ++ ranges provided at initialization. */ ++#endif /* (DPAA_VERSION >= 11) */ ++} t_FmPcdCcKeyStatistics; ++ ++/**************************************************************************//** ++ @Description Parameters for defining policer byte rate ++*//***************************************************************************/ ++typedef struct t_FmPcdPlcrByteRateModeParams { ++ e_FmPcdPlcrFrameLengthSelect frameLengthSelection; /**< Frame length selection */ ++ e_FmPcdPlcrRollBackFrameSelect rollBackFrameSelection; /**< relevant option only e_FM_PCD_PLCR_L2_FRM_LEN, ++ e_FM_PCD_PLCR_FULL_FRM_LEN */ ++} t_FmPcdPlcrByteRateModeParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining the policer profile (based on ++ RFC-2698 or RFC-4115 attributes). ++*//***************************************************************************/ ++typedef struct t_FmPcdPlcrNonPassthroughAlgParams { ++ e_FmPcdPlcrRateMode rateMode; /**< Byte mode or Packet mode */ ++ t_FmPcdPlcrByteRateModeParams byteModeParams; /**< Valid for Byte NULL for Packet */ ++ uint32_t committedInfoRate; /**< KBits/Second or Packets/Second */ ++ uint32_t committedBurstSize; /**< Bytes/Packets */ ++ uint32_t peakOrExcessInfoRate; /**< KBits/Second or Packets/Second */ ++ uint32_t peakOrExcessBurstSize; /**< Bytes/Packets */ ++} t_FmPcdPlcrNonPassthroughAlgParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining the next engine after policer ++*//***************************************************************************/ ++typedef union u_FmPcdPlcrNextEngineParams { ++ e_FmPcdDoneAction action; /**< Action - when next engine is BMI (done) */ ++ t_Handle h_Profile; /**< Policer profile handle - used when next engine ++ is Policer, must be a SHARED profile */ ++ t_Handle h_DirectScheme; /**< Direct scheme select - when next engine is KeyGen */ ++} u_FmPcdPlcrNextEngineParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining the policer profile entry ++*//***************************************************************************/ ++typedef struct t_FmPcdPlcrProfileParams { ++ bool modify; /**< TRUE to change an existing profile */ ++ union { ++ struct { ++ e_FmPcdProfileTypeSelection profileType; /**< Type of policer profile */ ++ t_Handle h_FmPort; /**< Relevant for per-port profiles only */ ++ uint16_t relativeProfileId; /**< Profile id - relative to shared group or to port */ ++ } newParams; /**< use it when modify = FALSE */ ++ t_Handle h_Profile; /**< A handle to a profile - use it when modify=TRUE */ ++ } id; ++ e_FmPcdPlcrAlgorithmSelection algSelection; /**< Profile Algorithm PASS_THROUGH, RFC_2698, RFC_4115 */ ++ e_FmPcdPlcrColorMode colorMode; /**< COLOR_BLIND, COLOR_AWARE */ ++ ++ union { ++ e_FmPcdPlcrColor dfltColor; /**< For Color-Blind Pass-Through mode; the policer will re-color ++ any incoming packet with the default value. */ ++ e_FmPcdPlcrColor override; /**< For Color-Aware modes; the profile response to a ++ pre-color value of 2'b11. */ ++ } color; ++ ++ t_FmPcdPlcrNonPassthroughAlgParams nonPassthroughAlgParams; /**< RFC2698 or RFC4115 parameters */ ++ ++ e_FmPcdEngine nextEngineOnGreen; /**< Next engine for green-colored frames */ ++ u_FmPcdPlcrNextEngineParams paramsOnGreen; /**< Next engine parameters for green-colored frames */ ++ ++ e_FmPcdEngine nextEngineOnYellow; /**< Next engine for yellow-colored frames */ ++ u_FmPcdPlcrNextEngineParams paramsOnYellow; /**< Next engine parameters for yellow-colored frames */ ++ ++ e_FmPcdEngine nextEngineOnRed; /**< Next engine for red-colored frames */ ++ u_FmPcdPlcrNextEngineParams paramsOnRed; /**< Next engine parameters for red-colored frames */ ++ ++ bool trapProfileOnFlowA; /**< Obsolete - do not use */ ++ bool trapProfileOnFlowB; /**< Obsolete - do not use */ ++ bool trapProfileOnFlowC; /**< Obsolete - do not use */ ++} t_FmPcdPlcrProfileParams; ++ ++/**************************************************************************//** ++ @Description Parameters for selecting a location for requested manipulation ++*//***************************************************************************/ ++typedef struct t_FmManipHdrInfo { ++ e_NetHeaderType hdr; /**< Header selection */ ++ e_FmPcdHdrIndex hdrIndex; /**< Relevant only for MPLS, VLAN and tunneled IP. Otherwise should be cleared. */ ++ bool byField; /**< TRUE if the location of manipulation is according to some field in the specific header*/ ++ t_FmPcdFields fullField; /**< Relevant only when byField = TRUE: Extract field */ ++} t_FmManipHdrInfo; ++ ++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) ++/**************************************************************************//** ++ @Description Parameters for defining an insertion manipulation ++ of type e_FM_PCD_MANIP_INSRT_TO_START_OF_FRAME_TEMPLATE ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrInsrtByTemplateParams { ++ uint8_t size; /**< Size of insert template to the start of the frame. */ ++ uint8_t hdrTemplate[FM_PCD_MAX_MANIP_INSRT_TEMPLATE_SIZE]; ++ /**< Array of the insertion template. */ ++ ++ bool modifyOuterIp; /**< TRUE if user want to modify some fields in outer IP. */ ++ struct { ++ uint16_t ipOuterOffset; /**< Offset of outer IP in the insert template, relevant if modifyOuterIp = TRUE.*/ ++ uint16_t dscpEcn; /**< value of dscpEcn in IP outer, relevant if modifyOuterIp = TRUE. ++ in IPV4 dscpEcn only byte - it has to be adjusted to the right*/ ++ bool udpPresent; /**< TRUE if UDP is present in the insert template, relevant if modifyOuterIp = TRUE.*/ ++ uint8_t udpOffset; /**< Offset in the insert template of UDP, relevant if modifyOuterIp = TRUE and udpPresent=TRUE.*/ ++ uint8_t ipIdentGenId; /**< Used by FMan-CTRL to calculate IP-identification field,relevant if modifyOuterIp = TRUE.*/ ++ bool recalculateLength; /**< TRUE if recalculate length has to be performed due to the engines in the path which can change the frame later, relevant if modifyOuterIp = TRUE.*/ ++ struct { ++ uint8_t blockSize; /**< The CAAM block-size; Used by FMan-CTRL to calculate the IP Total Length field.*/ ++ uint8_t extraBytesAddedAlignedToBlockSize; /**< Used by FMan-CTRL to calculate the IP Total Length field and UDP length*/ ++ uint8_t extraBytesAddedNotAlignedToBlockSize;/**< Used by FMan-CTRL to calculate the IP Total Length field and UDP length.*/ ++ } recalculateLengthParams; /**< Recalculate length parameters - relevant if modifyOuterIp = TRUE and recalculateLength = TRUE */ ++ } modifyOuterIpParams; /**< Outer IP modification parameters - ignored if modifyOuterIp is FALSE */ ++ ++ bool modifyOuterVlan; /**< TRUE if user wants to modify VPri field in the outer VLAN header*/ ++ struct { ++ uint8_t vpri; /**< Value of VPri, relevant if modifyOuterVlan = TRUE ++ VPri only 3 bits, it has to be adjusted to the right*/ ++ } modifyOuterVlanParams; ++} t_FmPcdManipHdrInsrtByTemplateParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining CAPWAP fragmentation ++*//***************************************************************************/ ++typedef struct t_CapwapFragmentationParams { ++ uint16_t sizeForFragmentation; /**< if length of the frame is greater than this value, CAPWAP fragmentation will be executed.*/ ++ bool headerOptionsCompr; /**< TRUE - first fragment include the CAPWAP header options field, ++ and all other fragments exclude the CAPWAP options field, ++ FALSE - all fragments include CAPWAP header options field. */ ++} t_CapwapFragmentationParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining CAPWAP reassembly ++*//***************************************************************************/ ++typedef struct t_CapwapReassemblyParams { ++ uint16_t maxNumFramesInProcess; /**< Number of frames which can be reassembled concurrently; must be power of 2. ++ In case numOfFramesPerHashEntry == e_FM_PCD_MANIP_FOUR_WAYS_HASH, ++ maxNumFramesInProcess has to be in the range of 4 - 512, ++ In case numOfFramesPerHashEntry == e_FM_PCD_MANIP_EIGHT_WAYS_HASH, ++ maxNumFramesInProcess has to be in the range of 8 - 2048 */ ++ bool haltOnDuplicationFrag; /**< If TRUE, reassembly process will be halted due to duplicated fragment, ++ and all processed fragments will be enqueued with error indication; ++ If FALSE, only duplicated fragments will be enqueued with error indication. */ ++ ++ e_FmPcdManipReassemTimeOutMode timeOutMode; /**< Expiration delay initialized by the reassembly process */ ++ uint32_t fqidForTimeOutFrames; /**< FQID in which time out frames will enqueue during Time Out Process */ ++ uint32_t timeoutRoutineRequestTime; ++ /**< Represents the time interval in microseconds between consecutive ++ timeout routine requests It has to be power of 2. */ ++ uint32_t timeoutThresholdForReassmProcess; ++ /**< Time interval (microseconds) for marking frames in process as too old; ++ Frames in process are those for which at least one fragment was received ++ but not all fragments. */ ++ ++ e_FmPcdManipReassemWaysNumber numOfFramesPerHashEntry;/**< Number of frames per hash entry (needed for the reassembly process) */ ++} t_CapwapReassemblyParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining fragmentation/reassembly manipulation ++*//***************************************************************************/ ++typedef struct t_FmPcdManipFragOrReasmParams { ++ bool frag; /**< TRUE if using the structure for fragmentation, ++ otherwise this structure is used for reassembly */ ++ uint8_t sgBpid; /**< Scatter/Gather buffer pool id; ++ Same LIODN number is used for these buffers as for ++ the received frames buffers, so buffers of this pool ++ need to be allocated in the same memory area as the ++ received buffers. If the received buffers arrive ++ from different sources, the Scatter/Gather BP id ++ should be mutual to all these sources. */ ++ e_NetHeaderType hdr; /**< Header selection */ ++ union { ++ t_CapwapFragmentationParams capwapFragParams; /**< Structure for CAPWAP fragmentation, ++ relevant if 'frag' = TRUE, 'hdr' = HEADER_TYPE_CAPWAP */ ++ t_CapwapReassemblyParams capwapReasmParams; /**< Structure for CAPWAP reassembly, ++ relevant if 'frag' = FALSE, 'hdr' = HEADER_TYPE_CAPWAP */ ++ } u; ++} t_FmPcdManipFragOrReasmParams; ++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ ++ ++ ++/**************************************************************************//** ++ @Description Parameters for defining header removal by header type ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrRmvByHdrParams { ++ e_FmPcdManipHdrRmvByHdrType type; /**< Selection of header removal location */ ++ union { ++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) ++ struct { ++ bool include; /**< If FALSE, remove until the specified header (not including the header); ++ If TRUE, remove also the specified header. */ ++ t_FmManipHdrInfo hdrInfo; ++ } fromStartByHdr; /**< Relevant when type = e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START */ ++#endif /* (DPAA_VERSION >= 11) || ... */ ++#if (DPAA_VERSION >= 11) ++ t_FmManipHdrInfo hdrInfo; /**< Relevant when type = e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START */ ++#endif /* (DPAA_VERSION >= 11) */ ++ e_FmPcdManipHdrRmvSpecificL2 specificL2; /**< Relevant when type = e_FM_PCD_MANIP_BY_HDR_SPECIFIC_L2; ++ Defines which L2 headers to remove. */ ++ } u; ++} t_FmPcdManipHdrRmvByHdrParams; ++ ++/**************************************************************************//** ++ @Description Parameters for configuring IP fragmentation manipulation ++ ++ Restrictions: ++ - IP Fragmentation output fragments must not be forwarded to application directly. ++ - Maximum number of fragments per frame is 16. ++ - Fragmentation of IP fragments is not supported. ++ - IPv4 packets containing header Option fields are fragmented by copying all option ++ fields to each fragment, regardless of the copy bit value. ++ - Transmit confirmation is not supported. ++ - Fragmentation after SEC can't handle S/G frames. ++ - Fragmentation nodes must be set as the last PCD action (i.e. the ++ corresponding CC node key must have next engine set to e_FM_PCD_DONE). ++ - Only BMan buffers shall be used for frames to be fragmented. ++ - IPF does not support VSP. Therefore, on the same port where we have IPF ++ we cannot support VSP. ++ - NOTE: The following comment is relevant only for FMAN v3 devices: IPF ++ does not support VSP. Therefore, on the same port where we have IPF we ++ cannot support VSP. ++*//***************************************************************************/ ++typedef struct t_FmPcdManipFragIpParams { ++ uint16_t sizeForFragmentation; /**< If length of the frame is greater than this value, ++ IP fragmentation will be executed.*/ ++#if (DPAA_VERSION == 10) ++ uint8_t scratchBpid; /**< Absolute buffer pool id according to BM configuration.*/ ++#endif /* (DPAA_VERSION == 10) */ ++ bool sgBpidEn; /**< Enable a dedicated buffer pool id for the Scatter/Gather buffer allocation; ++ If disabled, the Scatter/Gather buffer will be allocated from the same pool as the ++ received frame's buffer. */ ++ uint8_t sgBpid; /**< Scatter/Gather buffer pool id; ++ This parameters is relevant when 'sgBpidEn=TRUE'; ++ Same LIODN number is used for these buffers as for the received frames buffers, so buffers ++ of this pool need to be allocated in the same memory area as the received buffers. ++ If the received buffers arrive from different sources, the Scatter/Gather BP id should be ++ mutual to all these sources. */ ++ e_FmPcdManipDontFragAction dontFragAction; /**< Don't Fragment Action - If an IP packet is larger ++ than MTU and its DF bit is set, then this field will ++ determine the action to be taken.*/ ++} t_FmPcdManipFragIpParams; ++ ++/**************************************************************************//** ++ @Description Parameters for configuring IP reassembly manipulation. ++ ++ This is a common structure for both IPv4 and IPv6 reassembly ++ manipulation. For reassembly of both IPv4 and IPv6, make sure to ++ set the 'hdr' field in t_FmPcdManipReassemParams to HEADER_TYPE_IPv6. ++ ++ Restrictions: ++ - Application must define at least one scheme to catch the reassembled frames. ++ - Maximum number of fragments per frame is 16. ++ - Reassembly of IPv4 fragments containing Option fields is supported. ++ ++*//***************************************************************************/ ++typedef struct t_FmPcdManipReassemIpParams { ++ uint8_t relativeSchemeId[2]; /**< Partition relative scheme id: ++ relativeSchemeId[0] - Relative scheme ID for IPV4 Reassembly manipulation; ++ relativeSchemeId[1] - Relative scheme ID for IPV6 Reassembly manipulation; ++ NOTE: The following comment is relevant only for FMAN v2 devices: ++ Relative scheme ID for IPv4/IPv6 Reassembly manipulation must be smaller than ++ the user schemes id to ensure that the reassembly schemes will be first match; ++ Rest schemes, if defined, should have higher relative scheme ID. */ ++#if (DPAA_VERSION >= 11) ++ uint32_t nonConsistentSpFqid; /**< In case that other fragments of the frame corresponds to different storage ++ profile than the opening fragment (Non-Consistent-SP state) ++ then one of two possible scenarios occurs: ++ if 'nonConsistentSpFqid != 0', the reassembled frame will be enqueued to ++ this fqid, otherwise a 'Non Consistent SP' bit will be set in the FD[status].*/ ++#else ++ uint8_t sgBpid; /**< Buffer pool id for the S/G frame created by the reassembly process */ ++#endif /* (DPAA_VERSION >= 11) */ ++ uint8_t dataMemId; /**< Memory partition ID for the IPR's external tables structure */ ++ uint16_t dataLiodnOffset; /**< LIODN offset for access the IPR's external tables structure. */ ++ uint16_t minFragSize[2]; /**< Minimum fragment size: ++ minFragSize[0] - for ipv4, minFragSize[1] - for ipv6 */ ++ e_FmPcdManipReassemWaysNumber numOfFramesPerHashEntry[2]; ++ /**< Number of frames per hash entry needed for reassembly process: ++ numOfFramesPerHashEntry[0] - for ipv4 (max value is e_FM_PCD_MANIP_EIGHT_WAYS_HASH); ++ numOfFramesPerHashEntry[1] - for ipv6 (max value is e_FM_PCD_MANIP_SIX_WAYS_HASH). */ ++ uint16_t maxNumFramesInProcess; /**< Number of frames which can be processed by Reassembly in the same time; ++ Must be power of 2; ++ In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_FOUR_WAYS_HASH, ++ maxNumFramesInProcess has to be in the range of 4 - 512; ++ In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_EIGHT_WAYS_HASH, ++ maxNumFramesInProcess has to be in the range of 8 - 2048. */ ++ e_FmPcdManipReassemTimeOutMode timeOutMode; /**< Expiration delay initialized by Reassembly process */ ++ uint32_t fqidForTimeOutFrames; /**< FQID in which time out frames will enqueue during Time Out Process; ++ Recommended value for this field is 0; in this way timed-out frames will be discarded */ ++ uint32_t timeoutThresholdForReassmProcess; ++ /**< Represents the time interval in microseconds which defines ++ if opened frame (at least one fragment was processed but not all the fragments)is found as too old*/ ++} t_FmPcdManipReassemIpParams; ++ ++/**************************************************************************//** ++ @Description structure for defining IPSEC manipulation ++*//***************************************************************************/ ++typedef struct t_FmPcdManipSpecialOffloadIPSecParams { ++ bool decryption; /**< TRUE if being used in decryption direction; ++ FALSE if being used in encryption direction. */ ++ bool ecnCopy; /**< TRUE to copy the ECN bits from inner/outer to outer/inner ++ (direction depends on the 'decryption' field). */ ++ bool dscpCopy; /**< TRUE to copy the DSCP bits from inner/outer to outer/inner ++ (direction depends on the 'decryption' field). */ ++ bool variableIpHdrLen; /**< TRUE for supporting variable IP header length in decryption. */ ++ bool variableIpVersion; /**< TRUE for supporting both IP version on the same SA in encryption */ ++ uint8_t outerIPHdrLen; /**< if 'variableIpVersion == TRUE' then this field must be set to non-zero value; ++ It is specifies the length of the outer IP header that was configured in the ++ corresponding SA. */ ++ uint16_t arwSize; /**< if <> '0' then will perform ARW check for this SA; ++ The value must be a multiplication of 16 */ ++ uintptr_t arwAddr; /**< if arwSize <> '0' then this field must be set to non-zero value; ++ MUST be allocated from FMAN's MURAM that the post-sec op-port belongs to; ++ Must be 4B aligned. Required MURAM size is 'NEXT_POWER_OF_2(arwSize+32))/8+4' Bytes */ ++} t_FmPcdManipSpecialOffloadIPSecParams; ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Description Parameters for configuring CAPWAP fragmentation manipulation ++ ++ Restrictions: ++ - Maximum number of fragments per frame is 16. ++ - Transmit confirmation is not supported. ++ - Fragmentation nodes must be set as the last PCD action (i.e. the ++ corresponding CC node key must have next engine set to e_FM_PCD_DONE). ++ - Only BMan buffers shall be used for frames to be fragmented. ++ - NOTE: The following comment is relevant only for FMAN v3 devices: IPF ++ does not support VSP. Therefore, on the same port where we have IPF we ++ cannot support VSP. ++*//***************************************************************************/ ++typedef struct t_FmPcdManipFragCapwapParams { ++ uint16_t sizeForFragmentation; /**< If length of the frame is greater than this value, ++ CAPWAP fragmentation will be executed.*/ ++ bool sgBpidEn; /**< Enable a dedicated buffer pool id for the Scatter/Gather buffer allocation; ++ If disabled, the Scatter/Gather buffer will be allocated from the same pool as the ++ received frame's buffer. */ ++ uint8_t sgBpid; /**< Scatter/Gather buffer pool id; ++ This parameters is relevant when 'sgBpidEn=TRUE'; ++ Same LIODN number is used for these buffers as for the received frames buffers, so buffers ++ of this pool need to be allocated in the same memory area as the received buffers. ++ If the received buffers arrive from different sources, the Scatter/Gather BP id should be ++ mutual to all these sources. */ ++ bool compressModeEn; /**< CAPWAP Header Options Compress Enable mode; ++ When this mode is enabled then only the first fragment include the CAPWAP header options ++ field (if user provides it in the input frame) and all other fragments exclude the CAPWAP ++ options field (CAPWAP header is updated accordingly).*/ ++} t_FmPcdManipFragCapwapParams; ++ ++/**************************************************************************//** ++ @Description Parameters for configuring CAPWAP reassembly manipulation. ++ ++ Restrictions: ++ - Application must define one scheme to catch the reassembled frames. ++ - Maximum number of fragments per frame is 16. ++ ++*//***************************************************************************/ ++typedef struct t_FmPcdManipReassemCapwapParams { ++ uint8_t relativeSchemeId; /**< Partition relative scheme id; ++ NOTE: this id must be smaller than the user schemes id to ensure that the reassembly scheme will be first match; ++ Rest schemes, if defined, should have higher relative scheme ID. */ ++ uint8_t dataMemId; /**< Memory partition ID for the IPR's external tables structure */ ++ uint16_t dataLiodnOffset; /**< LIODN offset for access the IPR's external tables structure. */ ++ uint16_t maxReassembledFrameLength;/**< The maximum CAPWAP reassembled frame length in bytes; ++ If maxReassembledFrameLength == 0, any successful reassembled frame length is ++ considered as a valid length; ++ if maxReassembledFrameLength > 0, a successful reassembled frame which its length ++ exceeds this value is considered as an error frame (FD status[CRE] bit is set). */ ++ e_FmPcdManipReassemWaysNumber numOfFramesPerHashEntry; ++ /**< Number of frames per hash entry needed for reassembly process */ ++ uint16_t maxNumFramesInProcess; /**< Number of frames which can be processed by reassembly in the same time; ++ Must be power of 2; ++ In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_FOUR_WAYS_HASH, ++ maxNumFramesInProcess has to be in the range of 4 - 512; ++ In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_EIGHT_WAYS_HASH, ++ maxNumFramesInProcess has to be in the range of 8 - 2048. */ ++ e_FmPcdManipReassemTimeOutMode timeOutMode; /**< Expiration delay initialized by Reassembly process */ ++ uint32_t fqidForTimeOutFrames; /**< FQID in which time out frames will enqueue during Time Out Process; ++ Recommended value for this field is 0; in this way timed-out frames will be discarded */ ++ uint32_t timeoutThresholdForReassmProcess; ++ /**< Represents the time interval in microseconds which defines ++ if opened frame (at least one fragment was processed but not all the fragments)is found as too old*/ ++} t_FmPcdManipReassemCapwapParams; ++ ++/**************************************************************************//** ++ @Description structure for defining CAPWAP manipulation ++*//***************************************************************************/ ++typedef struct t_FmPcdManipSpecialOffloadCapwapParams { ++ bool dtls; /**< TRUE if continue to SEC DTLS encryption */ ++ e_FmPcdManipHdrQosSrc qosSrc; /**< TODO */ ++} t_FmPcdManipSpecialOffloadCapwapParams; ++ ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ ++/**************************************************************************//** ++ @Description Parameters for defining special offload manipulation ++*//***************************************************************************/ ++typedef struct t_FmPcdManipSpecialOffloadParams { ++ e_FmPcdManipSpecialOffloadType type; /**< Type of special offload manipulation */ ++ union ++ { ++ t_FmPcdManipSpecialOffloadIPSecParams ipsec; /**< Parameters for IPSec; Relevant when ++ type = e_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC */ ++#if (DPAA_VERSION >= 11) ++ t_FmPcdManipSpecialOffloadCapwapParams capwap; /**< Parameters for CAPWAP; Relevant when ++ type = e_FM_PCD_MANIP_SPECIAL_OFFLOAD_CAPWAP */ ++#endif /* (DPAA_VERSION >= 11) */ ++ } u; ++} t_FmPcdManipSpecialOffloadParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining insertion manipulation ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrInsrt { ++ uint8_t size; /**< size of inserted section */ ++ uint8_t *p_Data; /**< data to be inserted */ ++} t_FmPcdManipHdrInsrt; ++ ++ ++/**************************************************************************//** ++ @Description Parameters for defining generic removal manipulation ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrRmvGenericParams { ++ uint8_t offset; /**< Offset from beginning of header to the start ++ location of the removal */ ++ uint8_t size; /**< Size of removed section */ ++} t_FmPcdManipHdrRmvGenericParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining generic insertion manipulation ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrInsrtGenericParams { ++ uint8_t offset; /**< Offset from beginning of header to the start ++ location of the insertion */ ++ uint8_t size; /**< Size of inserted section */ ++ bool replace; /**< TRUE to override (replace) existing data at ++ 'offset', FALSE to insert */ ++ uint8_t *p_Data; /**< Pointer to data to be inserted */ ++} t_FmPcdManipHdrInsrtGenericParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header manipulation VLAN DSCP To Vpri translation ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrFieldUpdateVlanDscpToVpri { ++ uint8_t dscpToVpriTable[FM_PCD_MANIP_DSCP_TO_VLAN_TRANS]; ++ /**< A table of VPri values for each DSCP value; ++ The index is the DSCP value (0-0x3F) and the ++ value is the corresponding VPRI (0-15). */ ++ uint8_t vpriDefVal; /**< 0-7, Relevant only if if updateType = ++ e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN, ++ this field is the Q Tag default value if the ++ IP header is not found. */ ++} t_FmPcdManipHdrFieldUpdateVlanDscpToVpri; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header manipulation VLAN fields updates ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrFieldUpdateVlan { ++ e_FmPcdManipHdrFieldUpdateVlan updateType; /**< Selects VLAN update type */ ++ union { ++ uint8_t vpri; /**< 0-7, Relevant only if If updateType = ++ e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_PRI, this ++ is the new VLAN pri. */ ++ t_FmPcdManipHdrFieldUpdateVlanDscpToVpri dscpToVpri; /**< Parameters structure, Relevant only if updateType ++ = e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN. */ ++ } u; ++} t_FmPcdManipHdrFieldUpdateVlan; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header manipulation IPV4 fields updates ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrFieldUpdateIpv4 { ++ ipv4HdrManipUpdateFlags_t validUpdates; /**< ORed flag, selecting the required updates */ ++ uint8_t tos; /**< 8 bit New TOS; Relevant if validUpdates contains ++ HDR_MANIP_IPV4_TOS */ ++ uint16_t id; /**< 16 bit New IP ID; Relevant only if validUpdates ++ contains HDR_MANIP_IPV4_ID */ ++ uint32_t src; /**< 32 bit New IP SRC; Relevant only if validUpdates ++ contains HDR_MANIP_IPV4_SRC */ ++ uint32_t dst; /**< 32 bit New IP DST; Relevant only if validUpdates ++ contains HDR_MANIP_IPV4_DST */ ++} t_FmPcdManipHdrFieldUpdateIpv4; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header manipulation IPV6 fields updates ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrFieldUpdateIpv6 { ++ ipv6HdrManipUpdateFlags_t validUpdates; /**< ORed flag, selecting the required updates */ ++ uint8_t trafficClass; /**< 8 bit New Traffic Class; Relevant if validUpdates contains ++ HDR_MANIP_IPV6_TC */ ++ uint8_t src[NET_HEADER_FIELD_IPv6_ADDR_SIZE]; ++ /**< 16 byte new IP SRC; Relevant only if validUpdates ++ contains HDR_MANIP_IPV6_SRC */ ++ uint8_t dst[NET_HEADER_FIELD_IPv6_ADDR_SIZE]; ++ /**< 16 byte new IP DST; Relevant only if validUpdates ++ contains HDR_MANIP_IPV6_DST */ ++} t_FmPcdManipHdrFieldUpdateIpv6; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header manipulation TCP/UDP fields updates ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrFieldUpdateTcpUdp { ++ tcpUdpHdrManipUpdateFlags_t validUpdates; /**< ORed flag, selecting the required updates */ ++ uint16_t src; /**< 16 bit New TCP/UDP SRC; Relevant only if validUpdates ++ contains HDR_MANIP_TCP_UDP_SRC */ ++ uint16_t dst; /**< 16 bit New TCP/UDP DST; Relevant only if validUpdates ++ contains HDR_MANIP_TCP_UDP_DST */ ++} t_FmPcdManipHdrFieldUpdateTcpUdp; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header manipulation fields updates ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrFieldUpdateParams { ++ e_FmPcdManipHdrFieldUpdateType type; /**< Type of header field update manipulation */ ++ union { ++ t_FmPcdManipHdrFieldUpdateVlan vlan; /**< Parameters for VLAN update. Relevant when ++ type = e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN */ ++ t_FmPcdManipHdrFieldUpdateIpv4 ipv4; /**< Parameters for IPv4 update. Relevant when ++ type = e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4 */ ++ t_FmPcdManipHdrFieldUpdateIpv6 ipv6; /**< Parameters for IPv6 update. Relevant when ++ type = e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6 */ ++ t_FmPcdManipHdrFieldUpdateTcpUdp tcpUdp; /**< Parameters for TCP/UDP update. Relevant when ++ type = e_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP */ ++ } u; ++} t_FmPcdManipHdrFieldUpdateParams; ++ ++ ++ ++/**************************************************************************//** ++ @Description Parameters for defining custom header manipulation for generic field replacement ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrCustomGenFieldReplace { ++ uint8_t srcOffset; /**< Location of new data - Offset from ++ Parse Result (>= 16, srcOffset+size <= 32, ) */ ++ uint8_t dstOffset; /**< Location of data to be overwritten - Offset from ++ start of frame (dstOffset + size <= 256). */ ++ uint8_t size; /**< The number of bytes (<=16) to be replaced */ ++ uint8_t mask; /**< Optional 1 byte mask. Set to select bits for ++ replacement (1 - bit will be replaced); ++ Clear to use field as is. */ ++ uint8_t maskOffset; /**< Relevant if mask != 0; ++ Mask offset within the replaces "size" */ ++} t_FmPcdManipHdrCustomGenFieldReplace; ++ ++/**************************************************************************//** ++ @Description Parameters for defining custom header manipulation for IP replacement ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrCustomIpHdrReplace { ++ e_FmPcdManipHdrCustomIpReplace replaceType; /**< Selects replace update type */ ++ bool decTtlHl; /**< Decrement TTL (IPV4) or Hop limit (IPV6) by 1 */ ++ bool updateIpv4Id; /**< Relevant when replaceType = ++ e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4 */ ++ uint16_t id; /**< 16 bit New IP ID; Relevant only if ++ updateIpv4Id = TRUE */ ++ uint8_t hdrSize; /**< The size of the new IP header */ ++ uint8_t hdr[FM_PCD_MANIP_MAX_HDR_SIZE]; ++ /**< The new IP header */ ++} t_FmPcdManipHdrCustomIpHdrReplace; ++ ++/**************************************************************************//** ++ @Description Parameters for defining custom header manipulation ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrCustomParams { ++ e_FmPcdManipHdrCustomType type; /**< Type of header field update manipulation */ ++ union { ++ t_FmPcdManipHdrCustomIpHdrReplace ipHdrReplace; /**< Parameters IP header replacement */ ++ t_FmPcdManipHdrCustomGenFieldReplace genFieldReplace; /**< Parameters IP header replacement */ ++ } u; ++} t_FmPcdManipHdrCustomParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining specific L2 insertion manipulation ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrInsrtSpecificL2Params { ++ e_FmPcdManipHdrInsrtSpecificL2 specificL2; /**< Selects which L2 headers to insert */ ++ bool update; /**< TRUE to update MPLS header */ ++ uint8_t size; /**< size of inserted section */ ++ uint8_t *p_Data; /**< data to be inserted */ ++} t_FmPcdManipHdrInsrtSpecificL2Params; ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Description Parameters for defining IP insertion manipulation ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrInsrtIpParams { ++ bool calcL4Checksum; /**< Calculate L4 checksum. */ ++ e_FmPcdManipHdrQosMappingMode mappingMode; /**< TODO */ ++ uint8_t lastPidOffset; /**< the offset of the last Protocol within ++ the inserted header */ ++ uint16_t id; /**< 16 bit New IP ID */ ++ bool dontFragOverwrite; ++ /**< IPv4 only. DF is overwritten with the hash-result next-to-last byte. ++ * This byte is configured to be overwritten when RPD is set. */ ++ uint8_t lastDstOffset; ++ /**< IPv6 only. if routing extension exist, user should set the offset of the destination address ++ * in order to calculate UDP checksum pseudo header; ++ * Otherwise set it to '0'. */ ++ t_FmPcdManipHdrInsrt insrt; /**< size and data to be inserted. */ ++} t_FmPcdManipHdrInsrtIpParams; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++/**************************************************************************//** ++ @Description Parameters for defining header insertion manipulation by header type ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrInsrtByHdrParams { ++ e_FmPcdManipHdrInsrtByHdrType type; /**< Selects manipulation type */ ++ union { ++ ++ t_FmPcdManipHdrInsrtSpecificL2Params specificL2Params; ++ /**< Used when type = e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2: ++ Selects which L2 headers to insert */ ++#if (DPAA_VERSION >= 11) ++ t_FmPcdManipHdrInsrtIpParams ipParams; /**< Used when type = e_FM_PCD_MANIP_INSRT_BY_HDR_IP */ ++ t_FmPcdManipHdrInsrt insrt; /**< Used when type is one of e_FM_PCD_MANIP_INSRT_BY_HDR_UDP, ++ e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE, or ++ e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP */ ++#endif /* (DPAA_VERSION >= 11) */ ++ } u; ++} t_FmPcdManipHdrInsrtByHdrParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header insertion manipulation ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrInsrtParams { ++ e_FmPcdManipHdrInsrtType type; /**< Type of insertion manipulation */ ++ union { ++ t_FmPcdManipHdrInsrtByHdrParams byHdr; /**< Parameters for defining header insertion manipulation by header type, ++ relevant if 'type' = e_FM_PCD_MANIP_INSRT_BY_HDR */ ++ t_FmPcdManipHdrInsrtGenericParams generic; /**< Parameters for defining generic header insertion manipulation, ++ relevant if 'type' = e_FM_PCD_MANIP_INSRT_GENERIC */ ++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) ++ t_FmPcdManipHdrInsrtByTemplateParams byTemplate; /**< Parameters for defining header insertion manipulation by template, ++ relevant if 'type' = e_FM_PCD_MANIP_INSRT_BY_TEMPLATE */ ++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ ++ } u; ++} t_FmPcdManipHdrInsrtParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header removal manipulation ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrRmvParams { ++ e_FmPcdManipHdrRmvType type; /**< Type of header removal manipulation */ ++ union { ++ t_FmPcdManipHdrRmvByHdrParams byHdr; /**< Parameters for defining header removal manipulation by header type, ++ relevant if type = e_FM_PCD_MANIP_RMV_BY_HDR */ ++ t_FmPcdManipHdrRmvGenericParams generic; /**< Parameters for defining generic header removal manipulation, ++ relevant if type = e_FM_PCD_MANIP_RMV_GENERIC */ ++ } u; ++} t_FmPcdManipHdrRmvParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header manipulation node ++*//***************************************************************************/ ++typedef struct t_FmPcdManipHdrParams { ++ bool rmv; /**< TRUE, to define removal manipulation */ ++ t_FmPcdManipHdrRmvParams rmvParams; /**< Parameters for removal manipulation, relevant if 'rmv' = TRUE */ ++ ++ bool insrt; /**< TRUE, to define insertion manipulation */ ++ t_FmPcdManipHdrInsrtParams insrtParams; /**< Parameters for insertion manipulation, relevant if 'insrt' = TRUE */ ++ ++ bool fieldUpdate; /**< TRUE, to define field update manipulation */ ++ t_FmPcdManipHdrFieldUpdateParams fieldUpdateParams; /**< Parameters for field update manipulation, relevant if 'fieldUpdate' = TRUE */ ++ ++ bool custom; /**< TRUE, to define custom manipulation */ ++ t_FmPcdManipHdrCustomParams customParams; /**< Parameters for custom manipulation, relevant if 'custom' = TRUE */ ++ ++ bool dontParseAfterManip;/**< TRUE to de-activate the parser after the manipulation defined in this node. ++ Restrictions: ++ 1. MUST be set if the next engine after the CC is not another CC node ++ (but rather Policer or Keygen), and this is the last (no h_NextManip) in a chain ++ of manipulation nodes. This includes single nodes (i.e. no h_NextManip and ++ also never pointed as h_NextManip of other manipulation nodes) ++ 2. MUST be set if the next engine after the CC is another CC node, and ++ this is NOT the last manipulation node (i.e. it has h_NextManip).*/ ++} t_FmPcdManipHdrParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining fragmentation manipulation ++*//***************************************************************************/ ++typedef struct t_FmPcdManipFragParams { ++ e_NetHeaderType hdr; /**< Header selection */ ++ union { ++#if (DPAA_VERSION >= 11) ++ t_FmPcdManipFragCapwapParams capwapFrag; /**< Parameters for defining CAPWAP fragmentation, ++ relevant if 'hdr' = HEADER_TYPE_CAPWAP */ ++#endif /* (DPAA_VERSION >= 11) */ ++ t_FmPcdManipFragIpParams ipFrag; /**< Parameters for defining IP fragmentation, ++ relevant if 'hdr' = HEADER_TYPE_Ipv4 or HEADER_TYPE_Ipv6 */ ++ } u; ++} t_FmPcdManipFragParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining reassembly manipulation ++*//***************************************************************************/ ++typedef struct t_FmPcdManipReassemParams { ++ e_NetHeaderType hdr; /**< Header selection */ ++ union { ++#if (DPAA_VERSION >= 11) ++ t_FmPcdManipReassemCapwapParams capwapReassem; /**< Parameters for defining CAPWAP reassembly, ++ relevant if 'hdr' = HEADER_TYPE_CAPWAP */ ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ t_FmPcdManipReassemIpParams ipReassem; /**< Parameters for defining IP reassembly, ++ relevant if 'hdr' = HEADER_TYPE_Ipv4 or HEADER_TYPE_Ipv6 */ ++ } u; ++} t_FmPcdManipReassemParams; ++ ++/**************************************************************************//** ++ @Description Parameters for defining a manipulation node ++*//***************************************************************************/ ++typedef struct t_FmPcdManipParams { ++ e_FmPcdManipType type; /**< Selects type of manipulation node */ ++ union{ ++ t_FmPcdManipHdrParams hdr; /**< Parameters for defining header manipulation node */ ++ t_FmPcdManipReassemParams reassem; /**< Parameters for defining reassembly manipulation node */ ++ t_FmPcdManipFragParams frag; /**< Parameters for defining fragmentation manipulation node */ ++ t_FmPcdManipSpecialOffloadParams specialOffload; /**< Parameters for defining special offload manipulation node */ ++ } u; ++ ++ t_Handle h_NextManip; /**< Supported for Header Manipulation only; ++ Handle to another (previously defined) manipulation node; ++ Allows concatenation of manipulation actions; ++ This parameter is optional and may be NULL. */ ++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) ++ bool fragOrReasm; /**< TRUE, if defined fragmentation/reassembly manipulation */ ++ t_FmPcdManipFragOrReasmParams fragOrReasmParams; /**< Parameters for fragmentation/reassembly manipulation, ++ relevant if fragOrReasm = TRUE */ ++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ ++} t_FmPcdManipParams; ++ ++/**************************************************************************//** ++ @Description Structure for retrieving IP reassembly statistics ++*//***************************************************************************/ ++typedef struct t_FmPcdManipReassemIpStats { ++ /* common counters for both IPv4 and IPv6 */ ++ uint32_t timeout; /**< Counts the number of timeout occurrences */ ++ uint32_t rfdPoolBusy; /**< Counts the number of failed attempts to allocate ++ a Reassembly Frame Descriptor */ ++ uint32_t internalBufferBusy; /**< Counts the number of times an internal buffer busy occurred */ ++ uint32_t externalBufferBusy; /**< Counts the number of times external buffer busy occurred */ ++ uint32_t sgFragments; /**< Counts the number of Scatter/Gather fragments */ ++ uint32_t dmaSemaphoreDepletion; /**< Counts the number of failed attempts to allocate a DMA semaphore */ ++#if (DPAA_VERSION >= 11) ++ uint32_t nonConsistentSp; /**< Counts the number of Non Consistent Storage Profile events for ++ successfully reassembled frames */ ++#endif /* (DPAA_VERSION >= 11) */ ++ struct { ++ uint32_t successfullyReassembled; /**< Counts the number of successfully reassembled frames */ ++ uint32_t validFragments; /**< Counts the total number of valid fragments that ++ have been processed for all frames */ ++ uint32_t processedFragments; /**< Counts the number of processed fragments ++ (valid and error fragments) for all frames */ ++ uint32_t malformedFragments; /**< Counts the number of malformed fragments processed for all frames */ ++ uint32_t discardedFragments; /**< Counts the number of fragments discarded by the reassembly process */ ++ uint32_t autoLearnBusy; /**< Counts the number of times a busy condition occurs when attempting ++ to access an IP-Reassembly Automatic Learning Hash set */ ++ uint32_t moreThan16Fragments; /**< Counts the fragment occurrences in which the number of fragments-per-frame ++ exceeds 16 */ ++ } specificHdrStatistics[2]; /**< slot '0' is for IPv4, slot '1' is for IPv6 */ ++} t_FmPcdManipReassemIpStats; ++ ++/**************************************************************************//** ++ @Description Structure for retrieving IP fragmentation statistics ++*//***************************************************************************/ ++typedef struct t_FmPcdManipFragIpStats { ++ uint32_t totalFrames; /**< Number of frames that passed through the manipulation node */ ++ uint32_t fragmentedFrames; /**< Number of frames that were fragmented */ ++ uint32_t generatedFragments; /**< Number of fragments that were generated */ ++} t_FmPcdManipFragIpStats; ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Description Structure for retrieving CAPWAP reassembly statistics ++*//***************************************************************************/ ++typedef struct t_FmPcdManipReassemCapwapStats { ++ uint32_t timeout; /**< Counts the number of timeout occurrences */ ++ uint32_t rfdPoolBusy; /**< Counts the number of failed attempts to allocate ++ a Reassembly Frame Descriptor */ ++ uint32_t internalBufferBusy; /**< Counts the number of times an internal buffer busy occurred */ ++ uint32_t externalBufferBusy; /**< Counts the number of times external buffer busy occurred */ ++ uint32_t sgFragments; /**< Counts the number of Scatter/Gather fragments */ ++ uint32_t dmaSemaphoreDepletion; /**< Counts the number of failed attempts to allocate a DMA semaphore */ ++ uint32_t successfullyReassembled; /**< Counts the number of successfully reassembled frames */ ++ uint32_t validFragments; /**< Counts the total number of valid fragments that ++ have been processed for all frames */ ++ uint32_t processedFragments; /**< Counts the number of processed fragments ++ (valid and error fragments) for all frames */ ++ uint32_t malformedFragments; /**< Counts the number of malformed fragments processed for all frames */ ++ uint32_t autoLearnBusy; /**< Counts the number of times a busy condition occurs when attempting ++ to access an Reassembly Automatic Learning Hash set */ ++ uint32_t discardedFragments; /**< Counts the number of fragments discarded by the reassembly process */ ++ uint32_t moreThan16Fragments; /**< Counts the fragment occurrences in which the number of fragments-per-frame ++ exceeds 16 */ ++ uint32_t exceedMaxReassemblyFrameLen;/**< ounts the number of times that a successful reassembled frame ++ length exceeds MaxReassembledFrameLength value */ ++} t_FmPcdManipReassemCapwapStats; ++ ++/**************************************************************************//** ++ @Description Structure for retrieving CAPWAP fragmentation statistics ++*//***************************************************************************/ ++typedef struct t_FmPcdManipFragCapwapStats { ++ uint32_t totalFrames; /**< Number of frames that passed through the manipulation node */ ++ uint32_t fragmentedFrames; /**< Number of frames that were fragmented */ ++ uint32_t generatedFragments; /**< Number of fragments that were generated */ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ uint8_t sgAllocationFailure; /**< Number of allocation failure of s/g buffers */ ++#endif /* (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) */ ++} t_FmPcdManipFragCapwapStats; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++/**************************************************************************//** ++ @Description Structure for retrieving reassembly statistics ++*//***************************************************************************/ ++typedef struct t_FmPcdManipReassemStats { ++ union { ++ t_FmPcdManipReassemIpStats ipReassem; /**< Structure for IP reassembly statistics */ ++#if (DPAA_VERSION >= 11) ++ t_FmPcdManipReassemCapwapStats capwapReassem; /**< Structure for CAPWAP reassembly statistics */ ++#endif /* (DPAA_VERSION >= 11) */ ++ } u; ++} t_FmPcdManipReassemStats; ++ ++/**************************************************************************//** ++ @Description Structure for retrieving fragmentation statistics ++*//***************************************************************************/ ++typedef struct t_FmPcdManipFragStats { ++ union { ++ t_FmPcdManipFragIpStats ipFrag; /**< Structure for IP fragmentation statistics */ ++#if (DPAA_VERSION >= 11) ++ t_FmPcdManipFragCapwapStats capwapFrag; /**< Structure for CAPWAP fragmentation statistics */ ++#endif /* (DPAA_VERSION >= 11) */ ++ } u; ++} t_FmPcdManipFragStats; ++ ++/**************************************************************************//** ++ @Description Structure for selecting manipulation statistics ++*//***************************************************************************/ ++typedef struct t_FmPcdManipStats { ++ union { ++ t_FmPcdManipReassemStats reassem; /**< Structure for reassembly statistics */ ++ t_FmPcdManipFragStats frag; /**< Structure for fragmentation statistics */ ++ } u; ++} t_FmPcdManipStats; ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Description Parameters for defining frame replicator group and its members ++*//***************************************************************************/ ++typedef struct t_FmPcdFrmReplicGroupParams { ++ uint8_t maxNumOfEntries; /**< Maximal number of members in the group; ++ Must be at least 2. */ ++ uint8_t numOfEntries; /**< Number of members in the group; ++ Must be at least 1. */ ++ t_FmPcdCcNextEngineParams nextEngineParams[FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES]; ++ /**< Array of members' parameters */ ++} t_FmPcdFrmReplicGroupParams; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) ++/**************************************************************************//** ++ @Description structure for defining statistics node ++*//***************************************************************************/ ++typedef struct t_FmPcdStatsParams { ++ e_FmPcdStatsType type; /**< type of statistics node */ ++} t_FmPcdStatsParams; ++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ ++ ++/**************************************************************************//** ++ @Function FM_PCD_NetEnvCharacteristicsSet ++ ++ @Description Define a set of Network Environment Characteristics. ++ ++ When setting an environment it is important to understand its ++ application. It is not meant to describe the flows that will run ++ on the ports using this environment, but what the user means TO DO ++ with the PCD mechanisms in order to parse-classify-distribute those ++ frames. ++ By specifying a distinction unit, the user means it would use that option ++ for distinction between frames at either a KeyGen scheme or a coarse ++ classification action descriptor. Using interchangeable headers to define a ++ unit means that the user is indifferent to which of the interchangeable ++ headers is present in the frame, and wants the distinction to be based ++ on the presence of either one of them. ++ ++ Depending on context, there are limitations to the use of environments. A ++ port using the PCD functionality is bound to an environment. Some or even ++ all ports may share an environment but also an environment per port is ++ possible. When initializing a scheme, a classification plan group (see below), ++ or a coarse classification tree, one of the initialized environments must be ++ stated and related to. When a port is bound to a scheme, a classification ++ plan group, or a coarse classification tree, it MUST be bound to the same ++ environment. ++ ++ The different PCD modules, may relate (for flows definition) ONLY on ++ distinction units as defined by their environment. When initializing a ++ scheme for example, it may not choose to select IPV4 as a match for ++ recognizing flows unless it was defined in the relating environment. In ++ fact, to guide the user through the configuration of the PCD, each module's ++ characterization in terms of flows is not done using protocol names, but using ++ environment indexes. ++ ++ In terms of HW implementation, the list of distinction units sets the LCV vectors ++ and later used for match vector, classification plan vectors and coarse classification ++ indexing. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] p_NetEnvParams A structure of parameters for the initialization of ++ the network environment. ++ ++ @Return A handle to the initialized object on success; NULL code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++*//***************************************************************************/ ++t_Handle FM_PCD_NetEnvCharacteristicsSet(t_Handle h_FmPcd, t_FmPcdNetEnvParams *p_NetEnvParams); ++ ++/**************************************************************************//** ++ @Function FM_PCD_NetEnvCharacteristicsDelete ++ ++ @Description Deletes a set of Network Environment Characteristics. ++ ++ @Param[in] h_NetEnv A handle to the Network environment. ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_PCD_NetEnvCharacteristicsDelete(t_Handle h_NetEnv); ++ ++/**************************************************************************//** ++ @Function FM_PCD_KgSchemeSet ++ ++ @Description Initializing or modifying and enabling a scheme for the KeyGen. ++ This routine should be called for adding or modifying a scheme. ++ When a scheme needs modifying, the API requires that it will be ++ rewritten. In such a case 'modify' should be TRUE. If the ++ routine is called for a valid scheme and 'modify' is FALSE, ++ it will return error. ++ ++ @Param[in] h_FmPcd If this is a new scheme - A handle to an FM PCD Module. ++ Otherwise NULL (ignored by driver). ++ @Param[in,out] p_SchemeParams A structure of parameters for defining the scheme ++ ++ @Return A handle to the initialized scheme on success; NULL code otherwise. ++ When used as "modify" (rather than for setting a new scheme), ++ p_SchemeParams->id.h_Scheme will return NULL if action fails due to scheme ++ BUSY state. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++*//***************************************************************************/ ++t_Handle FM_PCD_KgSchemeSet(t_Handle h_FmPcd, ++ t_FmPcdKgSchemeParams *p_SchemeParams); ++ ++/**************************************************************************//** ++ @Function FM_PCD_KgSchemeDelete ++ ++ @Description Deleting an initialized scheme. ++ ++ @Param[in] h_Scheme scheme handle as returned by FM_PCD_KgSchemeSet() ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init() & FM_PCD_KgSchemeSet(). ++*//***************************************************************************/ ++t_Error FM_PCD_KgSchemeDelete(t_Handle h_Scheme); ++ ++/**************************************************************************//** ++ @Function FM_PCD_KgSchemeGetCounter ++ ++ @Description Reads scheme packet counter. ++ ++ @Param[in] h_Scheme scheme handle as returned by FM_PCD_KgSchemeSet(). ++ ++ @Return Counter's current value. ++ ++ @Cautions Allowed only following FM_PCD_Init() & FM_PCD_KgSchemeSet(). ++*//***************************************************************************/ ++uint32_t FM_PCD_KgSchemeGetCounter(t_Handle h_Scheme); ++ ++/**************************************************************************//** ++ @Function FM_PCD_KgSchemeSetCounter ++ ++ @Description Writes scheme packet counter. ++ ++ @Param[in] h_Scheme scheme handle as returned by FM_PCD_KgSchemeSet(). ++ @Param[in] value New scheme counter value - typically '0' for ++ resetting the counter. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init() & FM_PCD_KgSchemeSet(). ++*//***************************************************************************/ ++t_Error FM_PCD_KgSchemeSetCounter(t_Handle h_Scheme, uint32_t value); ++ ++/**************************************************************************//** ++ @Function FM_PCD_PlcrProfileSet ++ ++ @Description Sets a profile entry in the policer profile table. ++ The routine overrides any existing value. ++ ++ @Param[in] h_FmPcd A handle to an FM PCD Module. ++ @Param[in] p_Profile A structure of parameters for defining a ++ policer profile entry. ++ ++ @Return A handle to the initialized object on success; NULL code otherwise. ++ When used as "modify" (rather than for setting a new profile), ++ p_Profile->id.h_Profile will return NULL if action fails due to profile ++ BUSY state. ++ @Cautions Allowed only following FM_PCD_Init(). ++*//***************************************************************************/ ++t_Handle FM_PCD_PlcrProfileSet(t_Handle h_FmPcd, ++ t_FmPcdPlcrProfileParams *p_Profile); ++ ++/**************************************************************************//** ++ @Function FM_PCD_PlcrProfileDelete ++ ++ @Description Delete a profile entry in the policer profile table. ++ The routine set entry to invalid. ++ ++ @Param[in] h_Profile A handle to the profile. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++*//***************************************************************************/ ++t_Error FM_PCD_PlcrProfileDelete(t_Handle h_Profile); ++ ++/**************************************************************************//** ++ @Function FM_PCD_PlcrProfileGetCounter ++ ++ @Description Sets an entry in the classification plan. ++ The routine overrides any existing value. ++ ++ @Param[in] h_Profile A handle to the profile. ++ @Param[in] counter Counter selector. ++ ++ @Return specific counter value. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++*//***************************************************************************/ ++uint32_t FM_PCD_PlcrProfileGetCounter(t_Handle h_Profile, ++ e_FmPcdPlcrProfileCounters counter); ++ ++/**************************************************************************//** ++ @Function FM_PCD_PlcrProfileSetCounter ++ ++ @Description Sets an entry in the classification plan. ++ The routine overrides any existing value. ++ ++ @Param[in] h_Profile A handle to the profile. ++ @Param[in] counter Counter selector. ++ @Param[in] value value to set counter with. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++*//***************************************************************************/ ++t_Error FM_PCD_PlcrProfileSetCounter(t_Handle h_Profile, ++ e_FmPcdPlcrProfileCounters counter, ++ uint32_t value); ++ ++/**************************************************************************//** ++ @Function FM_PCD_CcRootBuild ++ ++ @Description This routine must be called to define a complete coarse ++ classification tree. This is the way to define coarse ++ classification to a certain flow - the KeyGen schemes ++ may point only to trees defined in this way. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] p_Params A structure of parameters to define the tree. ++ ++ @Return A handle to the initialized object on success; NULL code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++*//***************************************************************************/ ++t_Handle FM_PCD_CcRootBuild (t_Handle h_FmPcd, ++ t_FmPcdCcTreeParams *p_Params); ++ ++/**************************************************************************//** ++ @Function FM_PCD_CcRootDelete ++ ++ @Description Deleting an built tree. ++ ++ @Param[in] h_CcTree A handle to a CC tree. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++*//***************************************************************************/ ++t_Error FM_PCD_CcRootDelete(t_Handle h_CcTree); ++ ++/**************************************************************************//** ++ @Function FM_PCD_CcRootModifyNextEngine ++ ++ @Description Modify the Next Engine Parameters in the entry of the tree. ++ ++ @Param[in] h_CcTree A handle to the tree ++ @Param[in] grpId A Group index in the tree ++ @Param[in] index Entry index in the group defined by grpId ++ @Param[in] p_FmPcdCcNextEngineParams Pointer to new next engine parameters ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_CcBuildTree(). ++*//***************************************************************************/ ++t_Error FM_PCD_CcRootModifyNextEngine(t_Handle h_CcTree, ++ uint8_t grpId, ++ uint8_t index, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableSet ++ ++ @Description This routine should be called for each CC (coarse classification) ++ node. The whole CC tree should be built bottom up so that each ++ node points to already defined nodes. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] p_Param A structure of parameters defining the CC node ++ ++ @Return A handle to the initialized object on success; NULL code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++*//***************************************************************************/ ++t_Handle FM_PCD_MatchTableSet(t_Handle h_FmPcd, t_FmPcdCcNodeParams *p_Param); ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableDelete ++ ++ @Description Deleting an built node. ++ ++ @Param[in] h_CcNode A handle to a CC node. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++*//***************************************************************************/ ++t_Error FM_PCD_MatchTableDelete(t_Handle h_CcNode); ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableModifyMissNextEngine ++ ++ @Description Modify the Next Engine Parameters of the Miss key case of the node. ++ ++ @Param[in] h_CcNode A handle to the node ++ @Param[in] p_FmPcdCcNextEngineParams Parameters for defining next engine ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet(); ++ Not relevant in the case the node is of type 'INDEXED_LOOKUP'. ++ When configuring nextEngine = e_FM_PCD_CC, note that ++ p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different ++ from the currently changed table. ++ ++*//***************************************************************************/ ++t_Error FM_PCD_MatchTableModifyMissNextEngine(t_Handle h_CcNode, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableRemoveKey ++ ++ @Description Remove the key (including next engine parameters of this key) ++ defined by the index of the relevant node. ++ ++ @Param[in] h_CcNode A handle to the node ++ @Param[in] keyIndex Key index for removing ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet() was called for this ++ node and the nodes that lead to it. ++*//***************************************************************************/ ++t_Error FM_PCD_MatchTableRemoveKey(t_Handle h_CcNode, uint16_t keyIndex); ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableAddKey ++ ++ @Description Add the key (including next engine parameters of this key in the ++ index defined by the keyIndex. Note that 'FM_PCD_LAST_KEY_INDEX' ++ may be used by user that don't care about the position of the ++ key in the table - in that case, the key will be automatically ++ added by the driver in the last available entry. ++ ++ @Param[in] h_CcNode A handle to the node ++ @Param[in] keyIndex Key index for adding. ++ @Param[in] keySize Key size of added key ++ @Param[in] p_KeyParams A pointer to the parameters includes ++ new key with Next Engine Parameters ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet() was called for this ++ node and the nodes that lead to it. ++*//***************************************************************************/ ++t_Error FM_PCD_MatchTableAddKey(t_Handle h_CcNode, ++ uint16_t keyIndex, ++ uint8_t keySize, ++ t_FmPcdCcKeyParams *p_KeyParams); ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableModifyNextEngine ++ ++ @Description Modify the Next Engine Parameters in the relevant key entry of the node. ++ ++ @Param[in] h_CcNode A handle to the node ++ @Param[in] keyIndex Key index for Next Engine modifications ++ @Param[in] p_FmPcdCcNextEngineParams Parameters for defining next engine ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet(). ++ When configuring nextEngine = e_FM_PCD_CC, note that ++ p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different ++ from the currently changed table. ++ ++*//***************************************************************************/ ++t_Error FM_PCD_MatchTableModifyNextEngine(t_Handle h_CcNode, ++ uint16_t keyIndex, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableModifyKeyAndNextEngine ++ ++ @Description Modify the key and Next Engine Parameters of this key in the ++ index defined by the keyIndex. ++ ++ @Param[in] h_CcNode A handle to the node ++ @Param[in] keyIndex Key index for adding ++ @Param[in] keySize Key size of added key ++ @Param[in] p_KeyParams A pointer to the parameters includes ++ modified key and modified Next Engine Parameters ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet() was called for this ++ node and the nodes that lead to it. ++ When configuring nextEngine = e_FM_PCD_CC, note that ++ p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different ++ from the currently changed table. ++*//***************************************************************************/ ++t_Error FM_PCD_MatchTableModifyKeyAndNextEngine(t_Handle h_CcNode, ++ uint16_t keyIndex, ++ uint8_t keySize, ++ t_FmPcdCcKeyParams *p_KeyParams); ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableModifyKey ++ ++ @Description Modify the key in the index defined by the keyIndex. ++ ++ @Param[in] h_CcNode A handle to the node ++ @Param[in] keyIndex Key index for adding ++ @Param[in] keySize Key size of added key ++ @Param[in] p_Key A pointer to the new key ++ @Param[in] p_Mask A pointer to the new mask if relevant, ++ otherwise pointer to NULL ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet() was called for this ++ node and the nodes that lead to it. ++*//***************************************************************************/ ++t_Error FM_PCD_MatchTableModifyKey(t_Handle h_CcNode, ++ uint16_t keyIndex, ++ uint8_t keySize, ++ uint8_t *p_Key, ++ uint8_t *p_Mask); ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableFindNRemoveKey ++ ++ @Description Remove the key (including next engine parameters of this key) ++ defined by the key and mask. Note that this routine will search ++ the node to locate the index of the required key (& mask) to remove. ++ ++ @Param[in] h_CcNode A handle to the node ++ @Param[in] keySize Key size of the one to remove. ++ @Param[in] p_Key A pointer to the requested key to remove. ++ @Param[in] p_Mask A pointer to the mask if relevant, ++ otherwise pointer to NULL ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet() was called for this ++ node and the nodes that lead to it. ++*//***************************************************************************/ ++t_Error FM_PCD_MatchTableFindNRemoveKey(t_Handle h_CcNode, ++ uint8_t keySize, ++ uint8_t *p_Key, ++ uint8_t *p_Mask); ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableFindNModifyNextEngine ++ ++ @Description Modify the Next Engine Parameters in the relevant key entry of ++ the node. Note that this routine will search the node to locate ++ the index of the required key (& mask) to modify. ++ ++ @Param[in] h_CcNode A handle to the node ++ @Param[in] keySize Key size of the one to modify. ++ @Param[in] p_Key A pointer to the requested key to modify. ++ @Param[in] p_Mask A pointer to the mask if relevant, ++ otherwise pointer to NULL ++ @Param[in] p_FmPcdCcNextEngineParams Parameters for defining next engine ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet(). ++ When configuring nextEngine = e_FM_PCD_CC, note that ++ p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different ++ from the currently changed table. ++*//***************************************************************************/ ++t_Error FM_PCD_MatchTableFindNModifyNextEngine(t_Handle h_CcNode, ++ uint8_t keySize, ++ uint8_t *p_Key, ++ uint8_t *p_Mask, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableFindNModifyKeyAndNextEngine ++ ++ @Description Modify the key and Next Engine Parameters of this key in the ++ index defined by the keyIndex. Note that this routine will search ++ the node to locate the index of the required key (& mask) to modify. ++ ++ @Param[in] h_CcNode A handle to the node ++ @Param[in] keySize Key size of the one to modify. ++ @Param[in] p_Key A pointer to the requested key to modify. ++ @Param[in] p_Mask A pointer to the mask if relevant, ++ otherwise pointer to NULL ++ @Param[in] p_KeyParams A pointer to the parameters includes ++ modified key and modified Next Engine Parameters ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet() was called for this ++ node and the nodes that lead to it. ++ When configuring nextEngine = e_FM_PCD_CC, note that ++ p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different ++ from the currently changed table. ++*//***************************************************************************/ ++t_Error FM_PCD_MatchTableFindNModifyKeyAndNextEngine(t_Handle h_CcNode, ++ uint8_t keySize, ++ uint8_t *p_Key, ++ uint8_t *p_Mask, ++ t_FmPcdCcKeyParams *p_KeyParams); ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableFindNModifyKey ++ ++ @Description Modify the key in the index defined by the keyIndex. Note that ++ this routine will search the node to locate the index of the ++ required key (& mask) to modify. ++ ++ @Param[in] h_CcNode A handle to the node ++ @Param[in] keySize Key size of the one to modify. ++ @Param[in] p_Key A pointer to the requested key to modify. ++ @Param[in] p_Mask A pointer to the mask if relevant, ++ otherwise pointer to NULL ++ @Param[in] p_NewKey A pointer to the new key ++ @Param[in] p_NewMask A pointer to the new mask if relevant, ++ otherwise pointer to NULL ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet() was called for this ++ node and the nodes that lead to it. ++*//***************************************************************************/ ++t_Error FM_PCD_MatchTableFindNModifyKey(t_Handle h_CcNode, ++ uint8_t keySize, ++ uint8_t *p_Key, ++ uint8_t *p_Mask, ++ uint8_t *p_NewKey, ++ uint8_t *p_NewMask); ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableGetKeyCounter ++ ++ @Description This routine may be used to get a counter of specific key in a CC ++ Node; This counter reflects how many frames passed that were matched ++ this key. ++ ++ @Param[in] h_CcNode A handle to the node ++ @Param[in] keyIndex Key index for adding ++ ++ @Return The specific key counter. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet(). ++*//***************************************************************************/ ++uint32_t FM_PCD_MatchTableGetKeyCounter(t_Handle h_CcNode, uint16_t keyIndex); ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableGetKeyStatistics ++ ++ @Description This routine may be used to get statistics counters of specific key ++ in a CC Node. ++ ++ If 'e_FM_PCD_CC_STATS_MODE_FRAME' and ++ 'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node, ++ these counters reflect how many frames passed that were matched ++ this key; The total frames count will be returned in the counter ++ of the first range (as only one frame length range was defined). ++ If 'e_FM_PCD_CC_STATS_MODE_RMON' was set for this node, the total ++ frame count will be separated to frame length counters, based on ++ provided frame length ranges. ++ ++ @Param[in] h_CcNode A handle to the node ++ @Param[in] keyIndex Key index for adding ++ @Param[out] p_KeyStatistics Key statistics counters ++ ++ @Return The specific key statistics. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet(). ++*//***************************************************************************/ ++t_Error FM_PCD_MatchTableGetKeyStatistics(t_Handle h_CcNode, ++ uint16_t keyIndex, ++ t_FmPcdCcKeyStatistics *p_KeyStatistics); ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableGetMissStatistics ++ ++ @Description This routine may be used to get statistics counters of miss entry ++ in a CC Node. ++ ++ If 'e_FM_PCD_CC_STATS_MODE_FRAME' and ++ 'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node, ++ these counters reflect how many frames were not matched to any ++ existing key and therefore passed through the miss entry; The ++ total frames count will be returned in the counter of the ++ first range (as only one frame length range was defined). ++ ++ @Param[in] h_CcNode A handle to the node ++ @Param[out] p_MissStatistics Statistics counters for 'miss' ++ ++ @Return The statistics for 'miss'. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet(). ++*//***************************************************************************/ ++t_Error FM_PCD_MatchTableGetMissStatistics(t_Handle h_CcNode, ++ t_FmPcdCcKeyStatistics *p_MissStatistics); ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableFindNGetKeyStatistics ++ ++ @Description This routine may be used to get statistics counters of specific key ++ in a CC Node. ++ ++ If 'e_FM_PCD_CC_STATS_MODE_FRAME' and ++ 'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node, ++ these counters reflect how many frames passed that were matched ++ this key; The total frames count will be returned in the counter ++ of the first range (as only one frame length range was defined). ++ If 'e_FM_PCD_CC_STATS_MODE_RMON' was set for this node, the total ++ frame count will be separated to frame length counters, based on ++ provided frame length ranges. ++ Note that this routine will search the node to locate the index ++ of the required key based on received key parameters. ++ ++ @Param[in] h_CcNode A handle to the node ++ @Param[in] keySize Size of the requested key ++ @Param[in] p_Key A pointer to the requested key ++ @Param[in] p_Mask A pointer to the mask if relevant, ++ otherwise pointer to NULL ++ @Param[out] p_KeyStatistics Key statistics counters ++ ++ @Return The specific key statistics. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet(). ++*//***************************************************************************/ ++t_Error FM_PCD_MatchTableFindNGetKeyStatistics(t_Handle h_CcNode, ++ uint8_t keySize, ++ uint8_t *p_Key, ++ uint8_t *p_Mask, ++ t_FmPcdCcKeyStatistics *p_KeyStatistics); ++ ++/**************************************************************************//* ++ @Function FM_PCD_MatchTableGetNextEngine ++ ++ @Description Gets NextEngine of the relevant keyIndex. ++ ++ @Param[in] h_CcNode A handle to the node. ++ @Param[in] keyIndex keyIndex in the relevant node. ++ @Param[out] p_FmPcdCcNextEngineParams here updated nextEngine parameters for ++ the relevant keyIndex of the CC Node ++ received as parameter to this function ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++*//***************************************************************************/ ++t_Error FM_PCD_MatchTableGetNextEngine(t_Handle h_CcNode, ++ uint16_t keyIndex, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); ++ ++/**************************************************************************//* ++ @Function FM_PCD_MatchTableGetIndexedHashBucket ++ ++ @Description This routine simulates KeyGen operation on the provided key and ++ calculates to which hash bucket it will be mapped. ++ ++ @Param[in] h_CcNode A handle to the node. ++ @Param[in] kgKeySize Key size as it was configured in the KG ++ scheme that leads to this hash. ++ @Param[in] p_KgKey Pointer to the key; must be like the key ++ that the KG is generated, i.e. the same ++ extraction and with mask if exist. ++ @Param[in] kgHashShift Hash-shift as it was configured in the KG ++ scheme that leads to this hash. ++ @Param[out] p_CcNodeBucketHandle Pointer to the bucket of the provided key. ++ @Param[out] p_BucketIndex Index to the bucket of the provided key ++ @Param[out] p_LastIndex Pointer to last index in the bucket of the ++ provided key. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_HashTableSet() ++*//***************************************************************************/ ++t_Error FM_PCD_MatchTableGetIndexedHashBucket(t_Handle h_CcNode, ++ uint8_t kgKeySize, ++ uint8_t *p_KgKey, ++ uint8_t kgHashShift, ++ t_Handle *p_CcNodeBucketHandle, ++ uint8_t *p_BucketIndex, ++ uint16_t *p_LastIndex); ++ ++/**************************************************************************//** ++ @Function FM_PCD_HashTableSet ++ ++ @Description This routine initializes a hash table structure. ++ KeyGen hash result determines the hash bucket. ++ Next, KeyGen key is compared against all keys of this ++ bucket (exact match). ++ Number of sets (number of buckets) of the hash equals to the ++ number of 1-s in 'hashResMask' in the provided parameters. ++ Number of hash table ways is then calculated by dividing ++ 'maxNumOfKeys' equally between the hash sets. This is the maximal ++ number of keys that a hash bucket may hold. ++ The hash table is initialized empty and keys may be ++ added to it following the initialization. Keys masks are not ++ supported in current hash table implementation. ++ The initialized hash table can be integrated as a node in a ++ CC tree. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] p_Param A structure of parameters defining the hash table ++ ++ @Return A handle to the initialized object on success; NULL code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++*//***************************************************************************/ ++t_Handle FM_PCD_HashTableSet(t_Handle h_FmPcd, t_FmPcdHashTableParams *p_Param); ++ ++/**************************************************************************//** ++ @Function FM_PCD_HashTableDelete ++ ++ @Description This routine deletes the provided hash table and released all ++ its allocated resources. ++ ++ @Param[in] h_HashTbl A handle to a hash table ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_HashTableSet(). ++*//***************************************************************************/ ++t_Error FM_PCD_HashTableDelete(t_Handle h_HashTbl); ++ ++/**************************************************************************//** ++ @Function FM_PCD_HashTableAddKey ++ ++ @Description This routine adds the provided key (including next engine ++ parameters of this key) to the hash table. ++ The key is added as the last key of the bucket that it is ++ mapped to. ++ ++ @Param[in] h_HashTbl A handle to a hash table ++ @Param[in] keySize Key size of added key ++ @Param[in] p_KeyParams A pointer to the parameters includes ++ new key with next engine parameters; The pointer ++ to the key mask must be NULL, as masks are not ++ supported in hash table implementation. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_HashTableSet(). ++*//***************************************************************************/ ++t_Error FM_PCD_HashTableAddKey(t_Handle h_HashTbl, ++ uint8_t keySize, ++ t_FmPcdCcKeyParams *p_KeyParams); ++ ++/**************************************************************************//** ++ @Function FM_PCD_HashTableRemoveKey ++ ++ @Description This routine removes the requested key (including next engine ++ parameters of this key) from the hash table. ++ ++ @Param[in] h_HashTbl A handle to a hash table ++ @Param[in] keySize Key size of the one to remove. ++ @Param[in] p_Key A pointer to the requested key to remove. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_HashTableSet(). ++*//***************************************************************************/ ++t_Error FM_PCD_HashTableRemoveKey(t_Handle h_HashTbl, ++ uint8_t keySize, ++ uint8_t *p_Key); ++ ++/**************************************************************************//** ++ @Function FM_PCD_HashTableModifyNextEngine ++ ++ @Description This routine modifies the next engine for the provided key. The ++ key should be previously added to the hash table. ++ ++ @Param[in] h_HashTbl A handle to a hash table ++ @Param[in] keySize Key size of the key to modify. ++ @Param[in] p_Key A pointer to the requested key to modify. ++ @Param[in] p_FmPcdCcNextEngineParams A structure for defining new next engine ++ parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_HashTableSet(). ++ When configuring nextEngine = e_FM_PCD_CC, note that ++ p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different ++ from the currently changed table. ++*//***************************************************************************/ ++t_Error FM_PCD_HashTableModifyNextEngine(t_Handle h_HashTbl, ++ uint8_t keySize, ++ uint8_t *p_Key, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); ++ ++/**************************************************************************//** ++ @Function FM_PCD_HashTableModifyMissNextEngine ++ ++ @Description This routine modifies the next engine on key match miss. ++ ++ @Param[in] h_HashTbl A handle to a hash table ++ @Param[in] p_FmPcdCcNextEngineParams A structure for defining new next engine ++ parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_HashTableSet(). ++ When configuring nextEngine = e_FM_PCD_CC, note that ++ p_FmPcdCcNextEngineParams->ccParams.h_CcNode must be different ++ from the currently changed table. ++*//***************************************************************************/ ++t_Error FM_PCD_HashTableModifyMissNextEngine(t_Handle h_HashTbl, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); ++ ++/**************************************************************************//* ++ @Function FM_PCD_HashTableGetMissNextEngine ++ ++ @Description Gets NextEngine in case of key match miss. ++ ++ @Param[in] h_HashTbl A handle to a hash table ++ @Param[out] p_FmPcdCcNextEngineParams Next engine parameters for the specified ++ hash table. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_HashTableSet(). ++*//***************************************************************************/ ++t_Error FM_PCD_HashTableGetMissNextEngine(t_Handle h_HashTbl, ++ t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); ++ ++/**************************************************************************//** ++ @Function FM_PCD_HashTableFindNGetKeyStatistics ++ ++ @Description This routine may be used to get statistics counters of specific key ++ in a hash table. ++ ++ If 'e_FM_PCD_CC_STATS_MODE_FRAME' and ++ 'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node, ++ these counters reflect how many frames passed that were matched ++ this key; The total frames count will be returned in the counter ++ of the first range (as only one frame length range was defined). ++ If 'e_FM_PCD_CC_STATS_MODE_RMON' was set for this node, the total ++ frame count will be separated to frame length counters, based on ++ provided frame length ranges. ++ Note that this routine will identify the bucket of this key in ++ the hash table and will search the bucket to locate the index ++ of the required key based on received key parameters. ++ ++ @Param[in] h_HashTbl A handle to a hash table ++ @Param[in] keySize Size of the requested key ++ @Param[in] p_Key A pointer to the requested key ++ @Param[out] p_KeyStatistics Key statistics counters ++ ++ @Return The specific key statistics. ++ ++ @Cautions Allowed only following FM_PCD_HashTableSet(). ++*//***************************************************************************/ ++t_Error FM_PCD_HashTableFindNGetKeyStatistics(t_Handle h_HashTbl, ++ uint8_t keySize, ++ uint8_t *p_Key, ++ t_FmPcdCcKeyStatistics *p_KeyStatistics); ++ ++/**************************************************************************//** ++ @Function FM_PCD_HashTableGetMissStatistics ++ ++ @Description This routine may be used to get statistics counters of 'miss' ++ entry of the a hash table. ++ ++ If 'e_FM_PCD_CC_STATS_MODE_FRAME' and ++ 'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node, ++ these counters reflect how many frames were not matched to any ++ existing key and therefore passed through the miss entry; ++ ++ @Param[in] h_HashTbl A handle to a hash table ++ @Param[out] p_MissStatistics Statistics counters for 'miss' ++ ++ @Return The statistics for 'miss'. ++ ++ @Cautions Allowed only following FM_PCD_HashTableSet(). ++*//***************************************************************************/ ++t_Error FM_PCD_HashTableGetMissStatistics(t_Handle h_HashTbl, ++ t_FmPcdCcKeyStatistics *p_MissStatistics); ++ ++/**************************************************************************//** ++ @Function FM_PCD_ManipNodeSet ++ ++ @Description This routine should be called for defining a manipulation ++ node. A manipulation node must be defined before the CC node ++ that precedes it. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] p_FmPcdManipParams A structure of parameters defining the manipulation ++ ++ @Return A handle to the initialized object on success; NULL code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++*//***************************************************************************/ ++t_Handle FM_PCD_ManipNodeSet(t_Handle h_FmPcd, t_FmPcdManipParams *p_FmPcdManipParams); ++ ++/**************************************************************************//** ++ @Function FM_PCD_ManipNodeDelete ++ ++ @Description Delete an existing manipulation node. ++ ++ @Param[in] h_ManipNode A handle to a manipulation node. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_ManipNodeSet(). ++*//***************************************************************************/ ++t_Error FM_PCD_ManipNodeDelete(t_Handle h_ManipNode); ++ ++/**************************************************************************//** ++ @Function FM_PCD_ManipGetStatistics ++ ++ @Description Retrieve the manipulation statistics. ++ ++ @Param[in] h_ManipNode A handle to a manipulation node. ++ @Param[out] p_FmPcdManipStats A structure for retrieving the manipulation statistics ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_ManipNodeSet(). ++*//***************************************************************************/ ++t_Error FM_PCD_ManipGetStatistics(t_Handle h_ManipNode, t_FmPcdManipStats *p_FmPcdManipStats); ++ ++/**************************************************************************//** ++ @Function FM_PCD_ManipNodeReplace ++ ++ @Description Change existing manipulation node to be according to new requirement. ++ ++ @Param[in] h_ManipNode A handle to a manipulation node. ++ @Param[out] p_ManipParams A structure of parameters defining the change requirement ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_ManipNodeSet(). ++*//***************************************************************************/ ++t_Error FM_PCD_ManipNodeReplace(t_Handle h_ManipNode, t_FmPcdManipParams *p_ManipParams); ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Function FM_PCD_FrmReplicSetGroup ++ ++ @Description Initialize a Frame Replicator group. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] p_FrmReplicGroupParam A structure of parameters for the initialization of ++ the frame replicator group. ++ ++ @Return A handle to the initialized object on success; NULL code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++*//***************************************************************************/ ++t_Handle FM_PCD_FrmReplicSetGroup(t_Handle h_FmPcd, t_FmPcdFrmReplicGroupParams *p_FrmReplicGroupParam); ++ ++/**************************************************************************//** ++ @Function FM_PCD_FrmReplicDeleteGroup ++ ++ @Description Delete a Frame Replicator group. ++ ++ @Param[in] h_FrmReplicGroup A handle to the frame replicator group. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_FrmReplicSetGroup(). ++*//***************************************************************************/ ++t_Error FM_PCD_FrmReplicDeleteGroup(t_Handle h_FrmReplicGroup); ++ ++/**************************************************************************//** ++ @Function FM_PCD_FrmReplicAddMember ++ ++ @Description Add the member in the index defined by the memberIndex. ++ ++ @Param[in] h_FrmReplicGroup A handle to the frame replicator group. ++ @Param[in] memberIndex member index for adding. ++ @Param[in] p_MemberParams A pointer to the new member parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_FrmReplicSetGroup() of this group. ++*//***************************************************************************/ ++t_Error FM_PCD_FrmReplicAddMember(t_Handle h_FrmReplicGroup, ++ uint16_t memberIndex, ++ t_FmPcdCcNextEngineParams *p_MemberParams); ++ ++/**************************************************************************//** ++ @Function FM_PCD_FrmReplicRemoveMember ++ ++ @Description Remove the member defined by the index from the relevant group. ++ ++ @Param[in] h_FrmReplicGroup A handle to the frame replicator group. ++ @Param[in] memberIndex member index for removing. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_FrmReplicSetGroup() of this group. ++*//***************************************************************************/ ++t_Error FM_PCD_FrmReplicRemoveMember(t_Handle h_FrmReplicGroup, ++ uint16_t memberIndex); ++#endif /* (DPAA_VERSION >= 11) */ ++ ++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) ++/**************************************************************************//** ++ @Function FM_PCD_StatisticsSetNode ++ ++ @Description This routine should be called for defining a statistics node. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] p_FmPcdstatsParams A structure of parameters defining the statistics ++ ++ @Return A handle to the initialized object on success; NULL code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++*//***************************************************************************/ ++t_Handle FM_PCD_StatisticsSetNode(t_Handle h_FmPcd, t_FmPcdStatsParams *p_FmPcdstatsParams); ++#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ ++ ++/** @} */ /* end of FM_PCD_Runtime_build_grp group */ ++/** @} */ /* end of FM_PCD_Runtime_grp group */ ++/** @} */ /* end of FM_PCD_grp group */ ++/** @} */ /* end of FM_grp group */ ++ ++ ++#ifdef NCSW_BACKWARD_COMPATIBLE_API ++#define FM_PCD_MAX_NUM_OF_INTERCHANGABLE_HDRS FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS ++#define e_FM_PCD_MANIP_ONE_WAYS_HASH e_FM_PCD_MANIP_ONE_WAY_HASH ++#define e_FM_PCD_MANIP_TOW_WAYS_HASH e_FM_PCD_MANIP_TWO_WAYS_HASH ++ ++#define e_FM_PCD_MANIP_FRAGMENT_PACKECT e_FM_PCD_MANIP_FRAGMENT_PACKET /* Feb13 */ ++ ++#define FM_PCD_SetNetEnvCharacteristics(_pcd, _params) \ ++ FM_PCD_NetEnvCharacteristicsSet(_pcd, _params) ++#define FM_PCD_KgSetScheme(_pcd, _params) FM_PCD_KgSchemeSet(_pcd, _params) ++#define FM_PCD_CcBuildTree(_pcd, _params) FM_PCD_CcRootBuild(_pcd, _params) ++#define FM_PCD_CcSetNode(_pcd, _params) FM_PCD_MatchTableSet(_pcd, _params) ++#define FM_PCD_PlcrSetProfile(_pcd, _params) FM_PCD_PlcrProfileSet(_pcd, _params) ++#define FM_PCD_ManipSetNode(_pcd, _params) FM_PCD_ManipNodeSet(_pcd, _params) ++ ++#define FM_PCD_DeleteNetEnvCharacteristics(_pcd, ...) \ ++ FM_PCD_NetEnvCharacteristicsDelete(__VA_ARGS__) ++#define FM_PCD_KgDeleteScheme(_pcd, ...) \ ++ FM_PCD_KgSchemeDelete(__VA_ARGS__) ++#define FM_PCD_KgGetSchemeCounter(_pcd, ...) \ ++ FM_PCD_KgSchemeGetCounter(__VA_ARGS__) ++#define FM_PCD_KgSetSchemeCounter(_pcd, ...) \ ++ FM_PCD_KgSchemeSetCounter(__VA_ARGS__) ++#define FM_PCD_PlcrDeleteProfile(_pcd, ...) \ ++ FM_PCD_PlcrProfileDelete(__VA_ARGS__) ++#define FM_PCD_PlcrGetProfileCounter(_pcd, ...) \ ++ FM_PCD_PlcrProfileGetCounter(__VA_ARGS__) ++#define FM_PCD_PlcrSetProfileCounter(_pcd, ...) \ ++ FM_PCD_PlcrProfileSetCounter(__VA_ARGS__) ++#define FM_PCD_CcDeleteTree(_pcd, ...) \ ++ FM_PCD_CcRootDelete(__VA_ARGS__) ++#define FM_PCD_CcTreeModifyNextEngine(_pcd, ...) \ ++ FM_PCD_CcRootModifyNextEngine(__VA_ARGS__) ++#define FM_PCD_CcDeleteNode(_pcd, ...) \ ++ FM_PCD_MatchTableDelete(__VA_ARGS__) ++#define FM_PCD_CcNodeModifyMissNextEngine(_pcd, ...) \ ++ FM_PCD_MatchTableModifyMissNextEngine(__VA_ARGS__) ++#define FM_PCD_CcNodeRemoveKey(_pcd, ...) \ ++ FM_PCD_MatchTableRemoveKey(__VA_ARGS__) ++#define FM_PCD_CcNodeAddKey(_pcd, ...) \ ++ FM_PCD_MatchTableAddKey(__VA_ARGS__) ++#define FM_PCD_CcNodeModifyNextEngine(_pcd, ...) \ ++ FM_PCD_MatchTableModifyNextEngine(__VA_ARGS__) ++#define FM_PCD_CcNodeModifyKeyAndNextEngine(_pcd, ...) \ ++ FM_PCD_MatchTableModifyKeyAndNextEngine(__VA_ARGS__) ++#define FM_PCD_CcNodeModifyKey(_pcd, ...) \ ++ FM_PCD_MatchTableModifyKey(__VA_ARGS__) ++#define FM_PCD_CcNodeFindNRemoveKey(_pcd, ...) \ ++ FM_PCD_MatchTableFindNRemoveKey(__VA_ARGS__) ++#define FM_PCD_CcNodeFindNModifyNextEngine(_pcd, ...) \ ++ FM_PCD_MatchTableFindNModifyNextEngine(__VA_ARGS__) ++#define FM_PCD_CcNodeFindNModifyKeyAndNextEngine(_pcd, ...) \ ++ FM_PCD_MatchTableFindNModifyKeyAndNextEngine(__VA_ARGS__) ++#define FM_PCD_CcNodeFindNModifyKey(_pcd, ...) \ ++ FM_PCD_MatchTableFindNModifyKey(__VA_ARGS__) ++#define FM_PCD_CcIndexedHashNodeGetBucket(_pcd, ...) \ ++ FM_PCD_MatchTableGetIndexedHashBucket(__VA_ARGS__) ++#define FM_PCD_CcNodeGetNextEngine(_pcd, ...) \ ++ FM_PCD_MatchTableGetNextEngine(__VA_ARGS__) ++#define FM_PCD_CcNodeGetKeyCounter(_pcd, ...) \ ++ FM_PCD_MatchTableGetKeyCounter(__VA_ARGS__) ++#define FM_PCD_ManipDeleteNode(_pcd, ...) \ ++ FM_PCD_ManipNodeDelete(__VA_ARGS__) ++#endif /* NCSW_BACKWARD_COMPATIBLE_API */ ++ ++ ++#endif /* __FM_PCD_EXT */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_port_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_port_ext.h +new file mode 100644 +index 00000000..08a5aa59 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_port_ext.h +@@ -0,0 +1,2608 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File fm_port_ext.h ++ ++ @Description FM-Port Application Programming Interface. ++*//***************************************************************************/ ++#ifndef __FM_PORT_EXT ++#define __FM_PORT_EXT ++ ++#include "error_ext.h" ++#include "std_ext.h" ++#include "fm_pcd_ext.h" ++#include "fm_ext.h" ++#include "net_ext.h" ++ ++ ++/**************************************************************************//** ++ ++ @Group FM_grp Frame Manager API ++ ++ @Description FM API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group FM_PORT_grp FM Port ++ ++ @Description FM Port API ++ ++ The FM uses a general module called "port" to represent a Tx port ++ (MAC), an Rx port (MAC) or Offline Parsing port. ++ The number of ports in an FM varies between SOCs. ++ The SW driver manages these ports as sub-modules of the FM, i.e. ++ after an FM is initialized, its ports may be initialized and ++ operated upon. ++ ++ The port is initialized aware of its type, but other functions on ++ a port may be indifferent to its type. When necessary, the driver ++ verifies coherence and returns error if applicable. ++ ++ On initialization, user specifies the port type and it's index ++ (relative to the port's type) - always starting at 0. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description An enum for defining port PCD modes. ++ This enum defines the superset of PCD engines support - i.e. not ++ all engines have to be used, but all have to be enabled. The real ++ flow of a specific frame depends on the PCD configuration and the ++ frame headers and payload. ++ Note: the first engine and the first engine after the parser (if ++ exists) should be in order, the order is important as it will ++ define the flow of the port. However, as for the rest engines ++ (the ones that follows), the order is not important anymore as ++ it is defined by the PCD graph itself. ++*//***************************************************************************/ ++typedef enum e_FmPortPcdSupport { ++ e_FM_PORT_PCD_SUPPORT_NONE = 0 /**< BMI to BMI, PCD is not used */ ++ , e_FM_PORT_PCD_SUPPORT_PRS_ONLY /**< Use only Parser */ ++ , e_FM_PORT_PCD_SUPPORT_PLCR_ONLY /**< Use only Policer */ ++ , e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR /**< Use Parser and Policer */ ++ , e_FM_PORT_PCD_SUPPORT_PRS_AND_KG /**< Use Parser and Keygen */ ++ , e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC /**< Use Parser, Keygen and Coarse Classification */ ++ , e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR ++ /**< Use all PCD engines */ ++ , e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR /**< Use Parser, Keygen and Policer */ ++ , e_FM_PORT_PCD_SUPPORT_PRS_AND_CC /**< Use Parser and Coarse Classification */ ++ , e_FM_PORT_PCD_SUPPORT_PRS_AND_CC_AND_PLCR /**< Use Parser and Coarse Classification and Policer */ ++ , e_FM_PORT_PCD_SUPPORT_CC_ONLY /**< Use only Coarse Classification */ ++#ifdef FM_CAPWAP_SUPPORT ++ , e_FM_PORT_PCD_SUPPORT_CC_AND_KG /**< Use Coarse Classification,and Keygen */ ++ , e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR /**< Use Coarse Classification, Keygen and Policer */ ++#endif /* FM_CAPWAP_SUPPORT */ ++} e_FmPortPcdSupport; ++ ++/**************************************************************************//** ++ @Description Port interrupts ++*//***************************************************************************/ ++typedef enum e_FmPortExceptions { ++ e_FM_PORT_EXCEPTION_IM_BUSY /**< Independent-Mode Rx-BUSY */ ++} e_FmPortExceptions; ++ ++ ++/**************************************************************************//** ++ @Collection General FM Port defines ++*//***************************************************************************/ ++#define FM_PORT_PRS_RESULT_NUM_OF_WORDS 8 /**< Number of 4 bytes words in parser result */ ++/* @} */ ++ ++/**************************************************************************//** ++ @Collection FM Frame error ++*//***************************************************************************/ ++typedef uint32_t fmPortFrameErrSelect_t; /**< typedef for defining Frame Descriptor errors */ ++ ++#define FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT FM_FD_ERR_UNSUPPORTED_FORMAT /**< Not for Rx-Port! Unsupported Format */ ++#define FM_PORT_FRM_ERR_LENGTH FM_FD_ERR_LENGTH /**< Not for Rx-Port! Length Error */ ++#define FM_PORT_FRM_ERR_DMA FM_FD_ERR_DMA /**< DMA Data error */ ++#define FM_PORT_FRM_ERR_NON_FM FM_FD_RX_STATUS_ERR_NON_FM /**< non Frame-Manager error; probably come from SEC that ++ was chained to FM */ ++ ++#define FM_PORT_FRM_ERR_IPRE (FM_FD_ERR_IPR & ~FM_FD_IPR) /**< IPR error */ ++#define FM_PORT_FRM_ERR_IPR_NCSP (FM_FD_ERR_IPR_NCSP & ~FM_FD_IPR) /**< IPR non-consistent-sp */ ++ ++#define FM_PORT_FRM_ERR_IPFE 0 /**< Obsolete; will be removed in the future */ ++ ++#ifdef FM_CAPWAP_SUPPORT ++#define FM_PORT_FRM_ERR_CRE FM_FD_ERR_CRE ++#define FM_PORT_FRM_ERR_CHE FM_FD_ERR_CHE ++#endif /* FM_CAPWAP_SUPPORT */ ++ ++#define FM_PORT_FRM_ERR_PHYSICAL FM_FD_ERR_PHYSICAL /**< Rx FIFO overflow, FCS error, code error, running disparity ++ error (SGMII and TBI modes), FIFO parity error. PHY ++ Sequence error, PHY error control character detected. */ ++#define FM_PORT_FRM_ERR_SIZE FM_FD_ERR_SIZE /**< Frame too long OR Frame size exceeds max_length_frame */ ++#define FM_PORT_FRM_ERR_CLS_DISCARD FM_FD_ERR_CLS_DISCARD /**< indicates a classifier "drop" operation */ ++#define FM_PORT_FRM_ERR_EXTRACTION FM_FD_ERR_EXTRACTION /**< Extract Out of Frame */ ++#define FM_PORT_FRM_ERR_NO_SCHEME FM_FD_ERR_NO_SCHEME /**< No Scheme Selected */ ++#define FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW FM_FD_ERR_KEYSIZE_OVERFLOW /**< Keysize Overflow */ ++#define FM_PORT_FRM_ERR_COLOR_RED FM_FD_ERR_COLOR_RED /**< Frame color is red */ ++#define FM_PORT_FRM_ERR_COLOR_YELLOW FM_FD_ERR_COLOR_YELLOW /**< Frame color is yellow */ ++#define FM_PORT_FRM_ERR_ILL_PLCR FM_FD_ERR_ILL_PLCR /**< Illegal Policer Profile selected */ ++#define FM_PORT_FRM_ERR_PLCR_FRAME_LEN FM_FD_ERR_PLCR_FRAME_LEN /**< Policer frame length error */ ++#define FM_PORT_FRM_ERR_PRS_TIMEOUT FM_FD_ERR_PRS_TIMEOUT /**< Parser Time out Exceed */ ++#define FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT FM_FD_ERR_PRS_ILL_INSTRUCT /**< Invalid Soft Parser instruction */ ++#define FM_PORT_FRM_ERR_PRS_HDR_ERR FM_FD_ERR_PRS_HDR_ERR /**< Header error was identified during parsing */ ++#define FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED FM_FD_ERR_BLOCK_LIMIT_EXCEEDED /**< Frame parsed beyind 256 first bytes */ ++#define FM_PORT_FRM_ERR_PROCESS_TIMEOUT 0x00000001 /**< FPM Frame Processing Timeout Exceeded */ ++/* @} */ ++ ++ ++ ++/**************************************************************************//** ++ @Group FM_PORT_init_grp FM Port Initialization Unit ++ ++ @Description FM Port Initialization Unit ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description Exceptions user callback routine, will be called upon an ++ exception passing the exception identification. ++ ++ @Param[in] h_App - User's application descriptor. ++ @Param[in] exception - The exception. ++ *//***************************************************************************/ ++typedef void (t_FmPortExceptionCallback) (t_Handle h_App, e_FmPortExceptions exception); ++ ++/**************************************************************************//** ++ @Description User callback function called by driver with received data. ++ ++ User provides this function. Driver invokes it. ++ ++ @Param[in] h_App Application's handle originally specified to ++ the API Config function ++ @Param[in] p_Data A pointer to data received ++ @Param[in] length length of received data ++ @Param[in] status receive status and errors ++ @Param[in] position position of buffer in frame ++ @Param[in] h_BufContext A handle of the user acossiated with this buffer ++ ++ @Retval e_RX_STORE_RESPONSE_CONTINUE - order the driver to continue Rx ++ operation for all ready data. ++ @Retval e_RX_STORE_RESPONSE_PAUSE - order the driver to stop Rx operation. ++*//***************************************************************************/ ++typedef e_RxStoreResponse (t_FmPortImRxStoreCallback) (t_Handle h_App, ++ uint8_t *p_Data, ++ uint16_t length, ++ uint16_t status, ++ uint8_t position, ++ t_Handle h_BufContext); ++ ++/**************************************************************************//** ++ @Description User callback function called by driver when transmit completed. ++ ++ User provides this function. Driver invokes it. ++ ++ @Param[in] h_App Application's handle originally specified to ++ the API Config function ++ @Param[in] p_Data A pointer to data received ++ @Param[in] status transmit status and errors ++ @Param[in] lastBuffer is last buffer in frame ++ @Param[in] h_BufContext A handle of the user acossiated with this buffer ++ *//***************************************************************************/ ++typedef void (t_FmPortImTxConfCallback) (t_Handle h_App, ++ uint8_t *p_Data, ++ uint16_t status, ++ t_Handle h_BufContext); ++ ++/**************************************************************************//** ++ @Description A structure for additional Rx port parameters ++*//***************************************************************************/ ++typedef struct t_FmPortRxParams { ++ uint32_t errFqid; /**< Error Queue Id. */ ++ uint32_t dfltFqid; /**< Default Queue Id. */ ++ uint16_t liodnOffset; /**< Port's LIODN offset. */ ++ t_FmExtPools extBufPools; /**< Which external buffer pools are used ++ (up to FM_PORT_MAX_NUM_OF_EXT_POOLS), and their sizes. */ ++} t_FmPortRxParams; ++ ++/**************************************************************************//** ++ @Description A structure for additional non-Rx port parameters ++*//***************************************************************************/ ++typedef struct t_FmPortNonRxParams { ++ uint32_t errFqid; /**< Error Queue Id. */ ++ uint32_t dfltFqid; /**< For Tx - Default Confirmation queue, ++ 0 means no Tx confirmation for processed ++ frames. For OP port - default Rx queue. */ ++ uint32_t qmChannel; /**< QM-channel dedicated to this port; will be used ++ by the FM for dequeue. */ ++} t_FmPortNonRxParams; ++ ++/**************************************************************************//** ++ @Description A structure for additional Rx port parameters ++*//***************************************************************************/ ++typedef struct t_FmPortImRxTxParams { ++ t_Handle h_FmMuram; /**< A handle of the FM-MURAM partition */ ++ uint16_t liodnOffset; /**< For Rx ports only. Port's LIODN Offset. */ ++ uint8_t dataMemId; /**< Memory partition ID for data buffers */ ++ uint32_t dataMemAttributes; /**< Memory attributes for data buffers */ ++ t_BufferPoolInfo rxPoolParams; /**< For Rx ports only. */ ++ t_FmPortImRxStoreCallback *f_RxStore; /**< For Rx ports only. */ ++ t_FmPortImTxConfCallback *f_TxConf; /**< For Tx ports only. */ ++} t_FmPortImRxTxParams; ++ ++/**************************************************************************//** ++ @Description A union for additional parameters depending on port type ++*//***************************************************************************/ ++typedef union u_FmPortSpecificParams { ++ t_FmPortImRxTxParams imRxTxParams; /**< Rx/Tx Independent-Mode port parameter structure */ ++ t_FmPortRxParams rxParams; /**< Rx port parameters structure */ ++ t_FmPortNonRxParams nonRxParams; /**< Non-Rx port parameters structure */ ++} u_FmPortSpecificParams; ++ ++/**************************************************************************//** ++ @Description A structure representing FM initialization parameters ++*//***************************************************************************/ ++typedef struct t_FmPortParams { ++ uintptr_t baseAddr; /**< Virtual Address of memory mapped FM Port registers.*/ ++ t_Handle h_Fm; /**< A handle to the FM object this port related to */ ++ e_FmPortType portType; /**< Port type */ ++ uint8_t portId; /**< Port Id - relative to type; ++ NOTE: When configuring Offline Parsing port for ++ FMANv3 devices (DPAA_VERSION 11 and higher), ++ it is highly recommended NOT to use portId=0 due to lack ++ of HW resources on portId=0. */ ++ bool independentModeEnable; ++ /**< This port is Independent-Mode - Used for Rx/Tx ports only! */ ++ uint16_t liodnBase; /**< Irrelevant for P4080 rev 1. LIODN base for this port, to be ++ used together with LIODN offset. */ ++ u_FmPortSpecificParams specificParams; /**< Additional parameters depending on port ++ type. */ ++ ++ t_FmPortExceptionCallback *f_Exception; /**< Relevant for IM only Callback routine to be called on BUSY exception */ ++ t_Handle h_App; /**< A handle to an application layer object; This handle will ++ be passed by the driver upon calling the above callbacks */ ++} t_FmPortParams; ++ ++ ++/**************************************************************************//** ++ @Function FM_PORT_Config ++ ++ @Description Creates a descriptor for the FM PORT module. ++ ++ The routine returns a handle (descriptor) to the FM PORT object. ++ This descriptor must be passed as first parameter to all other ++ FM PORT function calls. ++ ++ No actual initialization or configuration of FM hardware is ++ done by this routine. ++ ++ @Param[in] p_FmPortParams - Pointer to data structure of parameters ++ ++ @Retval Handle to FM object, or NULL for Failure. ++*//***************************************************************************/ ++t_Handle FM_PORT_Config(t_FmPortParams *p_FmPortParams); ++ ++/**************************************************************************//** ++ @Function FM_PORT_Init ++ ++ @Description Initializes the FM PORT module by defining the software structure ++ and configuring the hardware registers. ++ ++ @Param[in] h_FmPort - FM PORT module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_PORT_Init(t_Handle h_FmPort); ++ ++/**************************************************************************//** ++ @Function FM_PORT_Free ++ ++ @Description Frees all resources that were assigned to FM PORT module. ++ ++ Calling this routine invalidates the descriptor. ++ ++ @Param[in] h_FmPort - FM PORT module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_PORT_Free(t_Handle h_FmPort); ++ ++ ++/**************************************************************************//** ++ @Group FM_PORT_advanced_init_grp FM Port Advanced Configuration Unit ++ ++ @Description Configuration functions used to change default values. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description enum for defining QM frame dequeue ++*//***************************************************************************/ ++typedef enum e_FmPortDeqType { ++ e_FM_PORT_DEQ_TYPE1, /**< Dequeue from the SP channel - with priority precedence, ++ and Intra-Class Scheduling respected. */ ++ e_FM_PORT_DEQ_TYPE2, /**< Dequeue from the SP channel - with active FQ precedence, ++ and Intra-Class Scheduling respected. */ ++ e_FM_PORT_DEQ_TYPE3 /**< Dequeue from the SP channel - with active FQ precedence, ++ and override Intra-Class Scheduling */ ++} e_FmPortDeqType; ++ ++/**************************************************************************//** ++ @Description enum for defining QM frame dequeue ++*//***************************************************************************/ ++typedef enum e_FmPortDeqPrefetchOption { ++ e_FM_PORT_DEQ_NO_PREFETCH, /**< QMI preforms a dequeue action for a single frame ++ only when a dedicated portID Tnum is waiting. */ ++ e_FM_PORT_DEQ_PARTIAL_PREFETCH, /**< QMI preforms a dequeue action for 3 frames when ++ one dedicated portId tnum is waiting. */ ++ e_FM_PORT_DEQ_FULL_PREFETCH /**< QMI preforms a dequeue action for 3 frames when ++ no dedicated portId tnums are waiting. */ ++ ++} e_FmPortDeqPrefetchOption; ++ ++/**************************************************************************//** ++ @Description enum for defining port default color ++*//***************************************************************************/ ++typedef enum e_FmPortColor { ++ e_FM_PORT_COLOR_GREEN, /**< Default port color is green */ ++ e_FM_PORT_COLOR_YELLOW, /**< Default port color is yellow */ ++ e_FM_PORT_COLOR_RED, /**< Default port color is red */ ++ e_FM_PORT_COLOR_OVERRIDE /**< Ignore color */ ++} e_FmPortColor; ++ ++/**************************************************************************//** ++ @Description A structure for defining Dual Tx rate limiting scale ++*//***************************************************************************/ ++typedef enum e_FmPortDualRateLimiterScaleDown { ++ e_FM_PORT_DUAL_RATE_LIMITER_NONE = 0, /**< Use only single rate limiter */ ++ e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_2, /**< Divide high rate limiter by 2 */ ++ e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_4, /**< Divide high rate limiter by 4 */ ++ e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8 /**< Divide high rate limiter by 8 */ ++} e_FmPortDualRateLimiterScaleDown; ++ ++ ++/**************************************************************************//** ++ @Description A structure for defining FM port resources ++*//***************************************************************************/ ++typedef struct t_FmPortRsrc { ++ uint32_t num; /**< Committed required resource */ ++ uint32_t extra; /**< Extra (not committed) required resource */ ++} t_FmPortRsrc; ++ ++/**************************************************************************//** ++ @Description A structure for defining observed pool depletion ++*//***************************************************************************/ ++typedef struct t_FmPortObservedBufPoolDepletion { ++ t_FmBufPoolDepletion poolDepletionParams;/**< parameters to define pool depletion */ ++ t_FmExtPools poolsParams; /**< Which external buffer pools are observed ++ (up to FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS), ++ and their sizes. */ ++} t_FmPortObservedBufPoolDepletion; ++ ++/**************************************************************************//** ++ @Description A structure for defining Tx rate limiting ++*//***************************************************************************/ ++typedef struct t_FmPortRateLimit { ++ uint16_t maxBurstSize; /**< in KBytes for Tx ports, in frames ++ for OP ports. (note that ++ for early chips burst size is ++ rounded up to a multiply of 1000 frames).*/ ++ uint32_t rateLimit; /**< in Kb/sec for Tx ports, in frame/sec for ++ OP ports. Rate limit refers to ++ data rate (rather than line rate). */ ++ e_FmPortDualRateLimiterScaleDown rateLimitDivider; /**< For OP ports only. Not-valid ++ for some earlier chip revisions */ ++} t_FmPortRateLimit; ++ ++/**************************************************************************//** ++ @Description A structure for defining the parameters of ++ the Rx port performance counters ++*//***************************************************************************/ ++typedef struct t_FmPortPerformanceCnt { ++ uint8_t taskCompVal; /**< Task compare value */ ++ uint8_t queueCompVal; /**< Rx queue/Tx confirm queue compare ++ value (unused for H/O) */ ++ uint8_t dmaCompVal; /**< Dma compare value */ ++ uint32_t fifoCompVal; /**< Fifo compare value (in bytes) */ ++} t_FmPortPerformanceCnt; ++ ++ ++/**************************************************************************//** ++ @Description A structure for defining the sizes of the Deep Sleep ++ the Auto Response tables ++*//***************************************************************************/ ++typedef struct t_FmPortDsarTablesSizes ++{ ++ uint16_t maxNumOfArpEntries; ++ uint16_t maxNumOfEchoIpv4Entries; ++ uint16_t maxNumOfNdpEntries; ++ uint16_t maxNumOfEchoIpv6Entries; ++ uint16_t maxNumOfSnmpIPV4Entries; ++ uint16_t maxNumOfSnmpIPV6Entries; ++ uint16_t maxNumOfSnmpOidEntries; ++ uint16_t maxNumOfSnmpOidChar; /* total amount of character needed for the snmp table */ ++ ++ uint16_t maxNumOfIpProtFiltering; ++ uint16_t maxNumOfTcpPortFiltering; ++ uint16_t maxNumOfUdpPortFiltering; ++} t_FmPortDsarTablesSizes; ++ ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigDsarSupport ++ ++ @Description This function will allocate the amount of MURAM needed for ++ this max number of entries for Deep Sleep Auto Response. ++ it will calculate all needed MURAM for autoresponse including ++ necesary common stuff. ++ ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] params A pointer to a structure containing the maximum ++ sizes of the auto response tables ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigDsarSupport(t_Handle h_FmPortRx, t_FmPortDsarTablesSizes *params); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigNumOfOpenDmas ++ ++ @Description Calling this routine changes the max number of open DMA's ++ available for this port. It changes this parameter in the ++ internal driver data base from its default configuration ++ [OP: 1] ++ [1G-RX, 1G-TX: 1 (+1)] ++ [10G-RX, 10G-TX: 8 (+8)] ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_OpenDmas A pointer to a structure of parameters defining ++ the open DMA allocation. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigNumOfOpenDmas(t_Handle h_FmPort, t_FmPortRsrc *p_OpenDmas); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigNumOfTasks ++ ++ @Description Calling this routine changes the max number of tasks ++ available for this port. It changes this parameter in the ++ internal driver data base from its default configuration ++ [OP: 1] ++ [1G-RX, 1G-TX: 3 (+2)] ++ [10G-RX, 10G-TX: 16 (+8)] ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_NumOfTasks A pointer to a structure of parameters defining ++ the tasks allocation. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigSizeOfFifo ++ ++ @Description Calling this routine changes the max FIFO size configured for this port. ++ ++ This function changes the internal driver data base from its ++ default configuration. Please refer to the driver's User Guide for ++ information on default FIFO sizes in the various devices. ++ [OP: 2KB] ++ [1G-RX, 1G-TX: 11KB] ++ [10G-RX, 10G-TX: 12KB] ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_SizeOfFifo A pointer to a structure of parameters defining ++ the FIFO allocation. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigDeqHighPriority ++ ++ @Description Calling this routine changes the dequeue priority in the ++ internal driver data base from its default configuration ++ 1G: [DEFAULT_PORT_deqHighPriority_1G] ++ 10G: [DEFAULT_PORT_deqHighPriority_10G] ++ ++ May be used for Non-Rx ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] highPri TRUE to select high priority, FALSE for normal operation. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigDeqHighPriority(t_Handle h_FmPort, bool highPri); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigDeqType ++ ++ @Description Calling this routine changes the dequeue type parameter in the ++ internal driver data base from its default configuration ++ [DEFAULT_PORT_deqType]. ++ ++ May be used for Non-Rx ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] deqType According to QM definition. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigDeqType(t_Handle h_FmPort, e_FmPortDeqType deqType); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigDeqPrefetchOption ++ ++ @Description Calling this routine changes the dequeue prefetch option parameter in the ++ internal driver data base from its default configuration ++ [DEFAULT_PORT_deqPrefetchOption] ++ Note: Available for some chips only ++ ++ May be used for Non-Rx ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] deqPrefetchOption New option ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigDeqPrefetchOption(t_Handle h_FmPort, e_FmPortDeqPrefetchOption deqPrefetchOption); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigDeqByteCnt ++ ++ @Description Calling this routine changes the dequeue byte count parameter in ++ the internal driver data base from its default configuration ++ 1G:[DEFAULT_PORT_deqByteCnt_1G]. ++ 10G:[DEFAULT_PORT_deqByteCnt_10G]. ++ ++ May be used for Non-Rx ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] deqByteCnt New byte count ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigDeqByteCnt(t_Handle h_FmPort, uint16_t deqByteCnt); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigBufferPrefixContent ++ ++ @Description Defines the structure, size and content of the application buffer. ++ The prefix will ++ In Tx ports, if 'passPrsResult', the application ++ should set a value to their offsets in the prefix of ++ the FM will save the first 'privDataSize', than, ++ depending on 'passPrsResult' and 'passTimeStamp', copy parse result ++ and timeStamp, and the packet itself (in this order), to the ++ application buffer, and to offset. ++ Calling this routine changes the buffer margins definitions ++ in the internal driver data base from its default ++ configuration: Data size: [DEFAULT_PORT_bufferPrefixContent_privDataSize] ++ Pass Parser result: [DEFAULT_PORT_bufferPrefixContent_passPrsResult]. ++ Pass timestamp: [DEFAULT_PORT_bufferPrefixContent_passTimeStamp]. ++ ++ May be used for all ports ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in,out] p_FmBufferPrefixContent A structure of parameters describing the ++ structure of the buffer. ++ Out parameter: Start margin - offset ++ of data from start of external buffer. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigBufferPrefixContent(t_Handle h_FmPort, ++ t_FmBufferPrefixContent *p_FmBufferPrefixContent); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigCheksumLastBytesIgnore ++ ++ @Description Calling this routine changes the number of checksum bytes to ignore ++ parameter in the internal driver data base from its default configuration ++ [DEFAULT_PORT_cheksumLastBytesIgnore] ++ ++ May be used by Tx & Rx ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] cheksumLastBytesIgnore New value ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigCheksumLastBytesIgnore(t_Handle h_FmPort, uint8_t cheksumLastBytesIgnore); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigCutBytesFromEnd ++ ++ @Description Calling this routine changes the number of bytes to cut from a ++ frame's end parameter in the internal driver data base ++ from its default configuration [DEFAULT_PORT_cutBytesFromEnd] ++ Note that if the result of (frame length before chop - cutBytesFromEnd) is ++ less than 14 bytes, the chop operation is not executed. ++ ++ May be used for Rx ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] cutBytesFromEnd New value ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigCutBytesFromEnd(t_Handle h_FmPort, uint8_t cutBytesFromEnd); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigPoolDepletion ++ ++ @Description Calling this routine enables pause frame generation depending on the ++ depletion status of BM pools. It also defines the conditions to activate ++ this functionality. By default, this functionality is disabled. ++ ++ May be used for Rx ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_BufPoolDepletion A structure of pool depletion parameters ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigPoolDepletion(t_Handle h_FmPort, t_FmBufPoolDepletion *p_BufPoolDepletion); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigObservedPoolDepletion ++ ++ @Description Calling this routine enables a mechanism to stop port enqueue ++ depending on the depletion status of selected BM pools. ++ It also defines the conditions to activate ++ this functionality. By default, this functionality is disabled. ++ ++ Note: Available for some chips only ++ ++ May be used for OP ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_FmPortObservedBufPoolDepletion A structure of parameters for pool depletion. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigObservedPoolDepletion(t_Handle h_FmPort, ++ t_FmPortObservedBufPoolDepletion *p_FmPortObservedBufPoolDepletion); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigExtBufPools ++ ++ @Description This routine should be called for OP ports ++ that internally use BM buffer pools. In such cases, e.g. for fragmentation and ++ re-assembly, the FM needs new BM buffers. By calling this routine the user ++ specifies the BM buffer pools that should be used. ++ ++ Note: Available for some chips only ++ ++ May be used for OP ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_FmExtPools A structure of parameters for the external pools. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigExtBufPools(t_Handle h_FmPort, t_FmExtPools *p_FmExtPools); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigBackupPools ++ ++ @Description Calling this routine allows the configuration of some of the BM pools ++ defined for this port as backup pools. ++ A pool configured to be a backup pool will be used only if all other ++ enabled non-backup pools are depleted. ++ ++ May be used for Rx ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_FmPortBackupBmPools An array of pool id's. All pools specified here will ++ be defined as backup pools. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigBackupPools(t_Handle h_FmPort, t_FmBackupBmPools *p_FmPortBackupBmPools); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigFrmDiscardOverride ++ ++ @Description Calling this routine changes the error frames destination parameter ++ in the internal driver data base from its default configuration: ++ override = [DEFAULT_PORT_frmDiscardOverride] ++ ++ May be used for Rx and OP ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] override TRUE to override discarding of error frames and ++ enqueueing them to error queue. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigFrmDiscardOverride(t_Handle h_FmPort, bool override); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigErrorsToDiscard ++ ++ @Description Calling this routine changes the behaviour on error parameter ++ in the internal driver data base from its default configuration: ++ [DEFAULT_PORT_errorsToDiscard]. ++ If a requested error was previously defined as "ErrorsToEnqueue" it's ++ definition will change and the frame will be discarded. ++ Errors that were not defined either as "ErrorsToEnqueue" nor as ++ "ErrorsToDiscard", will be forwarded to CPU. ++ ++ May be used for Rx and OP ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] errs A list of errors to discard ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigErrorsToDiscard(t_Handle h_FmPort, fmPortFrameErrSelect_t errs); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigDmaSwapData ++ ++ @Description Calling this routine changes the DMA swap data aparameter ++ in the internal driver data base from its default ++ configuration [DEFAULT_PORT_dmaSwapData] ++ ++ May be used for all port types ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] swapData New selection ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigDmaSwapData(t_Handle h_FmPort, e_FmDmaSwapOption swapData); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigDmaIcCacheAttr ++ ++ @Description Calling this routine changes the internal context cache ++ attribute parameter in the internal driver data base ++ from its default configuration [DEFAULT_PORT_dmaIntContextCacheAttr] ++ ++ May be used for all port types ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] intContextCacheAttr New selection ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigDmaIcCacheAttr(t_Handle h_FmPort, e_FmDmaCacheOption intContextCacheAttr); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigDmaHdrAttr ++ ++ @Description Calling this routine changes the header cache ++ attribute parameter in the internal driver data base ++ from its default configuration [DEFAULT_PORT_dmaHeaderCacheAttr] ++ ++ May be used for all port types ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] headerCacheAttr New selection ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigDmaHdrAttr(t_Handle h_FmPort, e_FmDmaCacheOption headerCacheAttr); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigDmaScatterGatherAttr ++ ++ @Description Calling this routine changes the scatter gather cache ++ attribute parameter in the internal driver data base ++ from its default configuration [DEFAULT_PORT_dmaScatterGatherCacheAttr] ++ ++ May be used for all port types ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] scatterGatherCacheAttr New selection ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigDmaScatterGatherAttr(t_Handle h_FmPort, e_FmDmaCacheOption scatterGatherCacheAttr); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigDmaWriteOptimize ++ ++ @Description Calling this routine changes the write optimization ++ parameter in the internal driver data base ++ from its default configuration: By default optimize = [DEFAULT_PORT_dmaWriteOptimize]. ++ Note: ++ ++ 1. For head optimization, data alignment must be >= 16 (supported by default). ++ ++ 3. For tail optimization, note that the optimization is performed by extending the write transaction ++ of the frame payload at the tail as needed to achieve optimal bus transfers, so that the last write ++ is extended to be on 16/64 bytes aligned block (chip dependent). ++ ++ Relevant for non-Tx port types ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] optimize TRUE to enable optimization, FALSE for normal operation ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigDmaWriteOptimize(t_Handle h_FmPort, bool optimize); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigNoScatherGather ++ ++ @Description Calling this routine changes the noScatherGather parameter in internal driver data base ++ from its default configuration. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] noScatherGather (TRUE - frame is discarded if can not be stored in single buffer, ++ FALSE - frame can be stored in scatter gather (S/G) format). ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigNoScatherGather(t_Handle h_FmPort, bool noScatherGather); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigDfltColor ++ ++ @Description Calling this routine changes the internal default color parameter ++ in the internal driver data base ++ from its default configuration [DEFAULT_PORT_color] ++ ++ May be used for all port types ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] color New selection ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigDfltColor(t_Handle h_FmPort, e_FmPortColor color); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigSyncReq ++ ++ @Description Calling this routine changes the synchronization attribute parameter ++ in the internal driver data base from its default configuration: ++ syncReq = [DEFAULT_PORT_syncReq] ++ ++ May be used for all port types ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] syncReq TRUE to request synchronization, FALSE otherwize. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigSyncReq(t_Handle h_FmPort, bool syncReq); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigForwardReuseIntContext ++ ++ @Description This routine is relevant for Rx ports that are routed to OP port. ++ It changes the internal context reuse option in the internal ++ driver data base from its default configuration: ++ reuse = [DEFAULT_PORT_forwardIntContextReuse] ++ ++ May be used for Rx ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] reuse TRUE to reuse internal context on frames ++ forwarded to OP port. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigForwardReuseIntContext(t_Handle h_FmPort, bool reuse); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigDontReleaseTxBufToBM ++ ++ @Description This routine should be called if no Tx confirmation ++ is done, and yet buffers should not be released to the BM. ++ Normally, buffers are returned using the Tx confirmation ++ process. When Tx confirmation is not used (defFqid=0), ++ buffers are typically released to the BM. This routine ++ may be called to avoid this behavior and not release the ++ buffers. ++ ++ May be used for Tx ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigDontReleaseTxBufToBM(t_Handle h_FmPort); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigIMMaxRxBufLength ++ ++ @Description Changes the maximum receive buffer length from its default ++ configuration: Closest rounded down power of 2 value of the ++ data buffer size. ++ ++ The maximum receive buffer length directly affects the structure ++ of received frames (single- or multi-buffered) and the performance ++ of both the FM and the driver. ++ ++ The selection between single- or multi-buffered frames should be ++ done according to the characteristics of the specific application. ++ The recommended mode is to use a single data buffer per packet, ++ as this mode provides the best performance. However, the user can ++ select to use multiple data buffers per packet. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] newVal Maximum receive buffer length (in bytes). ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++ This routine is to be used only if Independent-Mode is enabled. ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigIMMaxRxBufLength(t_Handle h_FmPort, uint16_t newVal); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigIMRxBdRingLength ++ ++ @Description Changes the receive BD ring length from its default ++ configuration:[DEFAULT_PORT_rxBdRingLength] ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] newVal The desired BD ring length. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++ This routine is to be used only if Independent-Mode is enabled. ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigIMRxBdRingLength(t_Handle h_FmPort, uint16_t newVal); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigIMTxBdRingLength ++ ++ @Description Changes the transmit BD ring length from its default ++ configuration:[DEFAULT_PORT_txBdRingLength] ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] newVal The desired BD ring length. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++ This routine is to be used only if Independent-Mode is enabled. ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigIMTxBdRingLength(t_Handle h_FmPort, uint16_t newVal); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigIMFmanCtrlExternalStructsMemory ++ ++ @Description Configures memory partition and attributes for FMan-Controller ++ data structures (e.g. BD rings). ++ Calling this routine changes the internal driver data base ++ from its default configuration ++ [DEFAULT_PORT_ImfwExtStructsMemId, DEFAULT_PORT_ImfwExtStructsMemAttr]. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] memId Memory partition ID. ++ @Param[in] memAttributes Memory attributes mask (a combination of MEMORY_ATTR_x flags). ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigIMFmanCtrlExternalStructsMemory(t_Handle h_FmPort, ++ uint8_t memId, ++ uint32_t memAttributes); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigIMPolling ++ ++ @Description Changes the Rx flow from interrupt driven (default) to polling. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++ This routine is to be used only if Independent-Mode is enabled. ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigIMPolling(t_Handle h_FmPort); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigMaxFrameLength ++ ++ @Description Changes the definition of the max size of frame that should be ++ transmitted/received on this port from its default value [DEFAULT_PORT_maxFrameLength]. ++ This parameter is used for confirmation of the minimum Fifo ++ size calculations and only for Tx ports or ports working in ++ independent mode. This should be larger than the maximum possible ++ MTU that will be used for this port (i.e. its MAC). ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] length Max size of frame ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++ This routine is to be used only if Independent-Mode is enabled. ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigMaxFrameLength(t_Handle h_FmPort, uint16_t length); ++ ++/**************************************************************************//* ++ @Function FM_PORT_ConfigTxFifoMinFillLevel ++ ++ @Description Calling this routine changes the fifo minimum ++ fill level parameter in the internal driver data base ++ from its default configuration [DEFAULT_PORT_txFifoMinFillLevel] ++ ++ May be used for Tx ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] minFillLevel New value ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigTxFifoMinFillLevel(t_Handle h_FmPort, uint32_t minFillLevel); ++ ++/**************************************************************************//* ++ @Function FM_PORT_ConfigFifoDeqPipelineDepth ++ ++ @Description Calling this routine changes the fifo dequeue ++ pipeline depth parameter in the internal driver data base ++ ++ from its default configuration: 1G ports: [DEFAULT_PORT_fifoDeqPipelineDepth_1G], ++ 10G port: [DEFAULT_PORT_fifoDeqPipelineDepth_10G], ++ OP port: [DEFAULT_PORT_fifoDeqPipelineDepth_OH] ++ ++ May be used for Tx/OP ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] deqPipelineDepth New value ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigFifoDeqPipelineDepth(t_Handle h_FmPort, uint8_t deqPipelineDepth); ++ ++/**************************************************************************//* ++ @Function FM_PORT_ConfigTxFifoLowComfLevel ++ ++ @Description Calling this routine changes the fifo low comfort level ++ parameter in internal driver data base ++ from its default configuration [DEFAULT_PORT_txFifoLowComfLevel] ++ ++ May be used for Tx ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] fifoLowComfLevel New value ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigTxFifoLowComfLevel(t_Handle h_FmPort, uint32_t fifoLowComfLevel); ++ ++/**************************************************************************//* ++ @Function FM_PORT_ConfigRxFifoThreshold ++ ++ @Description Calling this routine changes the threshold of the FIFO ++ fill level parameter in the internal driver data base ++ from its default configuration [DEFAULT_PORT_rxFifoThreshold] ++ ++ If the total number of buffers which are ++ currently in use and associated with the ++ specific RX port exceed this threshold, the ++ BMI will signal the MAC to send a pause frame ++ over the link. ++ ++ May be used for Rx ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] fifoThreshold New value ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigRxFifoThreshold(t_Handle h_FmPort, uint32_t fifoThreshold); ++ ++/**************************************************************************//* ++ @Function FM_PORT_ConfigRxFifoPriElevationLevel ++ ++ @Description Calling this routine changes the priority elevation level ++ parameter in the internal driver data base from its default ++ configuration [DEFAULT_PORT_rxFifoPriElevationLevel] ++ ++ If the total number of buffers which are currently in use and ++ associated with the specific RX port exceed the amount specified ++ in priElevationLevel, BMI will signal the main FM's DMA to ++ elevate the FM priority on the system bus. ++ ++ May be used for Rx ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] priElevationLevel New value ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigRxFifoPriElevationLevel(t_Handle h_FmPort, uint32_t priElevationLevel); ++ ++#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 ++/**************************************************************************//* ++ @Function FM_PORT_ConfigBCBWorkaround ++ ++ @Description Configures BCB errata workaround. ++ ++ When BCB errata is applicable, the workaround is always ++ performed by FM Controller. Thus, this functions doesn't ++ actually enable errata workaround but rather allows driver ++ to perform adjustments required due to errata workaround ++ execution in FM controller. ++ ++ Applying BCB workaround also configures FM_PORT_FRM_ERR_PHYSICAL ++ errors to be discarded. Thus FM_PORT_FRM_ERR_PHYSICAL can't be ++ set by FM_PORT_SetErrorsRoute() function. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigBCBWorkaround(t_Handle h_FmPort); ++#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */ ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//* ++ @Function FM_PORT_ConfigInternalBuffOffset ++ ++ @Description Configures internal buffer offset. ++ ++ May be used for Rx and OP ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] val New value ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ConfigInternalBuffOffset(t_Handle h_FmPort, uint8_t val); ++#endif /* (DPAA_VERSION >= 11) */ ++ ++/** @} */ /* end of FM_PORT_advanced_init_grp group */ ++/** @} */ /* end of FM_PORT_init_grp group */ ++ ++ ++/**************************************************************************//** ++ @Group FM_PORT_runtime_control_grp FM Port Runtime Control Unit ++ ++ @Description FM Port Runtime control unit API functions, definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description enum for defining FM Port counters ++*//***************************************************************************/ ++typedef enum e_FmPortCounters { ++ e_FM_PORT_COUNTERS_CYCLE, /**< BMI performance counter */ ++ e_FM_PORT_COUNTERS_TASK_UTIL, /**< BMI performance counter */ ++ e_FM_PORT_COUNTERS_QUEUE_UTIL, /**< BMI performance counter */ ++ e_FM_PORT_COUNTERS_DMA_UTIL, /**< BMI performance counter */ ++ e_FM_PORT_COUNTERS_FIFO_UTIL, /**< BMI performance counter */ ++ e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION, /**< BMI Rx only performance counter */ ++ e_FM_PORT_COUNTERS_FRAME, /**< BMI statistics counter */ ++ e_FM_PORT_COUNTERS_DISCARD_FRAME, /**< BMI statistics counter */ ++ e_FM_PORT_COUNTERS_DEALLOC_BUF, /**< BMI deallocate buffer statistics counter */ ++ e_FM_PORT_COUNTERS_RX_BAD_FRAME, /**< BMI Rx only statistics counter */ ++ e_FM_PORT_COUNTERS_RX_LARGE_FRAME, /**< BMI Rx only statistics counter */ ++ e_FM_PORT_COUNTERS_RX_FILTER_FRAME, /**< BMI Rx & OP only statistics counter */ ++ e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR, /**< BMI Rx, OP & HC only statistics counter */ ++ e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD, /**< BMI Rx, OP & HC statistics counter */ ++ e_FM_PORT_COUNTERS_PREPARE_TO_ENQUEUE_COUNTER, /**< BMI Rx, OP & HC only statistics counter */ ++ e_FM_PORT_COUNTERS_WRED_DISCARD, /**< BMI OP & HC only statistics counter */ ++ e_FM_PORT_COUNTERS_LENGTH_ERR, /**< BMI non-Rx statistics counter */ ++ e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT, /**< BMI non-Rx statistics counter */ ++ e_FM_PORT_COUNTERS_DEQ_TOTAL, /**< QMI total QM dequeues counter */ ++ e_FM_PORT_COUNTERS_ENQ_TOTAL, /**< QMI total QM enqueues counter */ ++ e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT, /**< QMI counter */ ++ e_FM_PORT_COUNTERS_DEQ_CONFIRM /**< QMI counter */ ++} e_FmPortCounters; ++ ++typedef struct t_FmPortBmiStats { ++ uint32_t cntCycle; ++ uint32_t cntTaskUtil; ++ uint32_t cntQueueUtil; ++ uint32_t cntDmaUtil; ++ uint32_t cntFifoUtil; ++ uint32_t cntRxPauseActivation; ++ uint32_t cntFrame; ++ uint32_t cntDiscardFrame; ++ uint32_t cntDeallocBuf; ++ uint32_t cntRxBadFrame; ++ uint32_t cntRxLargeFrame; ++ uint32_t cntRxFilterFrame; ++ uint32_t cntRxListDmaErr; ++ uint32_t cntRxOutOfBuffersDiscard; ++ uint32_t cntWredDiscard; ++ uint32_t cntLengthErr; ++ uint32_t cntUnsupportedFormat; ++} t_FmPortBmiStats; ++ ++/**************************************************************************//** ++ @Description Structure for Port id parameters. ++ Fields commented 'IN' are passed by the port module to be used ++ by the FM module. ++ Fields commented 'OUT' will be filled by FM before returning to port. ++*//***************************************************************************/ ++typedef struct t_FmPortCongestionGrps { ++ uint16_t numOfCongestionGrpsToConsider; /**< The number of required CGs ++ to define the size of the following array */ ++ uint8_t congestionGrpsToConsider[FM_PORT_NUM_OF_CONGESTION_GRPS]; ++ /**< An array of CG indexes; ++ Note that the size of the array should be ++ 'numOfCongestionGrpsToConsider'. */ ++#if (DPAA_VERSION >= 11) ++ bool pfcPrioritiesEn[FM_PORT_NUM_OF_CONGESTION_GRPS][FM_MAX_NUM_OF_PFC_PRIORITIES]; ++ /**< a matrix that represents the map between the CG ids ++ defined in 'congestionGrpsToConsider' to the priorties ++ mapping array. */ ++#endif /* (DPAA_VERSION >= 11) */ ++} t_FmPortCongestionGrps; ++ ++/**************************************************************************//** ++ @Description Structure for Deep Sleep Auto Response ARP Entry ++*//***************************************************************************/ ++typedef struct t_FmPortDsarArpEntry ++{ ++ uint32_t ipAddress; ++ uint8_t mac[6]; ++ bool isVlan; ++ uint16_t vid; ++} t_FmPortDsarArpEntry; ++ ++/**************************************************************************//** ++ @Description Structure for Deep Sleep Auto Response ARP info ++*//***************************************************************************/ ++typedef struct t_FmPortDsarArpInfo ++{ ++ uint8_t tableSize; ++ t_FmPortDsarArpEntry *p_AutoResTable; ++ bool enableConflictDetection; /* when TRUE Conflict Detection will be checked and wake the host if needed */ ++} t_FmPortDsarArpInfo; ++ ++/**************************************************************************//** ++ @Description Structure for Deep Sleep Auto Response NDP Entry ++*//***************************************************************************/ ++typedef struct t_FmPortDsarNdpEntry ++{ ++ uint32_t ipAddress[4]; ++ uint8_t mac[6]; ++ bool isVlan; ++ uint16_t vid; ++} t_FmPortDsarNdpEntry; ++ ++/**************************************************************************//** ++ @Description Structure for Deep Sleep Auto Response NDP info ++*//***************************************************************************/ ++typedef struct t_FmPortDsarNdpInfo ++{ ++ uint32_t multicastGroup; ++ ++ uint8_t tableSizeAssigned; ++ t_FmPortDsarNdpEntry *p_AutoResTableAssigned; /* This list refer to solicitation IP addresses. ++ Note that all IP adresses must be from the same multicast group. ++ This will be checked and if not operation will fail. */ ++ uint8_t tableSizeTmp; ++ t_FmPortDsarNdpEntry *p_AutoResTableTmp; /* This list refer to temp IP addresses. ++ Note that all temp IP adresses must be from the same multicast group. ++ This will be checked and if not operation will fail. */ ++ ++ bool enableConflictDetection; /* when TRUE Conflict Detection will be checked and wake the host if needed */ ++ ++} t_FmPortDsarNdpInfo; ++ ++/**************************************************************************//** ++ @Description Structure for Deep Sleep Auto Response ICMPV4 info ++*//***************************************************************************/ ++typedef struct t_FmPortDsarEchoIpv4Info ++{ ++ uint8_t tableSize; ++ t_FmPortDsarArpEntry *p_AutoResTable; ++} t_FmPortDsarEchoIpv4Info; ++ ++/**************************************************************************//** ++ @Description Structure for Deep Sleep Auto Response ICMPV6 info ++*//***************************************************************************/ ++typedef struct t_FmPortDsarEchoIpv6Info ++{ ++ uint8_t tableSize; ++ t_FmPortDsarNdpEntry *p_AutoResTable; ++} t_FmPortDsarEchoIpv6Info; ++ ++/**************************************************************************//** ++@Description Deep Sleep Auto Response SNMP OIDs table entry ++ ++*//***************************************************************************/ ++typedef struct { ++ uint16_t oidSize; ++ uint8_t *oidVal; /* only the oid string */ ++ uint16_t resSize; ++ uint8_t *resVal; /* resVal will be the entire reply, ++ i.e. "Type|Length|Value" */ ++} t_FmPortDsarOidsEntry; ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response SNMP IPv4 Addresses Table Entry ++ Refer to the FMan Controller spec for more details. ++*//***************************************************************************/ ++typedef struct ++{ ++ uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */ ++ bool isVlan; ++ uint16_t vid; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */ ++ /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */ ++} t_FmPortDsarSnmpIpv4AddrTblEntry; ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response SNMP IPv6 Addresses Table Entry ++ Refer to the FMan Controller spec for more details. ++*//***************************************************************************/ ++typedef struct ++{ ++ uint32_t ipv6Addr[4]; /*!< 4 * 32 bit IPv6 Address. */ ++ bool isVlan; ++ uint16_t vid; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */ ++ /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */ ++} t_FmPortDsarSnmpIpv6AddrTblEntry; ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response SNMP Descriptor ++ ++*//***************************************************************************/ ++typedef struct ++{ ++ uint16_t control; /**< Control bits [0-15]. */ ++ uint16_t maxSnmpMsgLength; /**< Maximal allowed SNMP message length. */ ++ uint16_t numOfIpv4Addresses; /**< Number of entries in IPv4 addresses table. */ ++ uint16_t numOfIpv6Addresses; /**< Number of entries in IPv6 addresses table. */ ++ t_FmPortDsarSnmpIpv4AddrTblEntry *p_Ipv4AddrTbl; /**< Pointer to IPv4 addresses table. */ ++ t_FmPortDsarSnmpIpv6AddrTblEntry *p_Ipv6AddrTbl; /**< Pointer to IPv6 addresses table. */ ++ uint8_t *p_RdOnlyCommunityStr; /**< Pointer to the Read Only Community String. */ ++ uint8_t *p_RdWrCommunityStr; /**< Pointer to the Read Write Community String. */ ++ t_FmPortDsarOidsEntry *p_OidsTbl; /**< Pointer to OIDs table. */ ++ uint32_t oidsTblSize; /**< Number of entries in OIDs table. */ ++} t_FmPortDsarSnmpInfo; ++ ++/**************************************************************************//** ++ @Description Structure for Deep Sleep Auto Response filtering Entry ++*//***************************************************************************/ ++typedef struct t_FmPortDsarFilteringEntry ++{ ++ uint16_t srcPort; ++ uint16_t dstPort; ++ uint16_t srcPortMask; ++ uint16_t dstPortMask; ++} t_FmPortDsarFilteringEntry; ++ ++/**************************************************************************//** ++ @Description Structure for Deep Sleep Auto Response filtering info ++*//***************************************************************************/ ++typedef struct t_FmPortDsarFilteringInfo ++{ ++ /* IP protocol filtering parameters */ ++ uint8_t ipProtTableSize; ++ uint8_t *p_IpProtTablePtr; ++ bool ipProtPassOnHit; /* when TRUE, miss in the table will cause the packet to be droped, ++ hit will pass the packet to UDP/TCP filters if needed and if not ++ to the classification tree. If the classification tree will pass ++ the packet to a queue it will cause a wake interupt. ++ When FALSE it the other way around. */ ++ /* UDP port filtering parameters */ ++ uint8_t udpPortsTableSize; ++ t_FmPortDsarFilteringEntry *p_UdpPortsTablePtr; ++ bool udpPortPassOnHit; /* when TRUE, miss in the table will cause the packet to be droped, ++ hit will pass the packet to classification tree. ++ If the classification tree will pass the packet to a queue it ++ will cause a wake interupt. ++ When FALSE it the other way around. */ ++ /* TCP port filtering parameters */ ++ uint16_t tcpFlagsMask; ++ uint8_t tcpPortsTableSize; ++ t_FmPortDsarFilteringEntry *p_TcpPortsTablePtr; ++ bool tcpPortPassOnHit; /* when TRUE, miss in the table will cause the packet to be droped, ++ hit will pass the packet to classification tree. ++ If the classification tree will pass the packet to a queue it ++ will cause a wake interupt. ++ When FALSE it the other way around. */ ++} t_FmPortDsarFilteringInfo; ++ ++/**************************************************************************//** ++ @Description Structure for Deep Sleep Auto Response parameters ++*//***************************************************************************/ ++typedef struct t_FmPortDsarParams ++{ ++ t_Handle h_FmPortTx; ++ t_FmPortDsarArpInfo *p_AutoResArpInfo; ++ t_FmPortDsarEchoIpv4Info *p_AutoResEchoIpv4Info; ++ t_FmPortDsarNdpInfo *p_AutoResNdpInfo; ++ t_FmPortDsarEchoIpv6Info *p_AutoResEchoIpv6Info; ++ t_FmPortDsarSnmpInfo *p_AutoResSnmpInfo; ++ t_FmPortDsarFilteringInfo *p_AutoResFilteringInfo; ++} t_FmPortDsarParams; ++ ++/**************************************************************************//** ++ @Function FM_PORT_EnterDsar ++ ++ @Description Enter Deep Sleep Auto Response mode. ++ This function write the apropriate values to in the relevant ++ tables in the MURAM. ++ ++ @Param[in] h_FmPortRx - FM PORT module descriptor ++ @Param[in] params - Auto Response parameters ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_EnterDsar(t_Handle h_FmPortRx, t_FmPortDsarParams *params); ++ ++/**************************************************************************//** ++ @Function FM_PORT_EnterDsarFinal ++ ++ @Description Enter Deep Sleep Auto Response mode. ++ This function sets the Tx port in independent mode as needed ++ and redirect the receive flow to go through the ++ Dsar Fman-ctrl code ++ ++ @Param[in] h_DsarRxPort - FM Rx PORT module descriptor ++ @Param[in] h_DsarTxPort - FM Tx PORT module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_EnterDsarFinal(t_Handle h_DsarRxPort, t_Handle h_DsarTxPort); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ExitDsar ++ ++ @Description Exit Deep Sleep Auto Response mode. ++ This function reverse the AR mode and put the ports back into ++ their original wake mode ++ ++ @Param[in] h_FmPortRx - FM PORT Rx module descriptor ++ @Param[in] h_FmPortTx - FM PORT Tx module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_EnterDsar(). ++*//***************************************************************************/ ++void FM_PORT_ExitDsar(t_Handle h_FmPortRx, t_Handle h_FmPortTx); ++ ++/**************************************************************************//** ++ @Function FM_PORT_IsInDsar ++ ++ @Description This function returns TRUE if the port was set as Auto Response ++ and FALSE if not. Once Exit AR mode it will return FALSE as well ++ until re-enabled once more. ++ ++ @Param[in] h_FmPort - FM PORT module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++bool FM_PORT_IsInDsar(t_Handle h_FmPort); ++ ++typedef struct t_FmPortDsarStats ++{ ++ uint32_t arpArCnt; ++ uint32_t echoIcmpv4ArCnt; ++ uint32_t ndpArCnt; ++ uint32_t echoIcmpv6ArCnt; ++ uint32_t snmpGetCnt; ++ uint32_t snmpGetNextCnt; ++} t_FmPortDsarStats; ++ ++/**************************************************************************//** ++ @Function FM_PORT_GetDsarStats ++ ++ @Description Return statistics for Deep Sleep Auto Response ++ ++ @Param[in] h_FmPortRx - FM PORT module descriptor ++ @Param[out] stats - structure containing the statistics counters ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_PORT_GetDsarStats(t_Handle h_FmPortRx, t_FmPortDsarStats *stats); ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++/**************************************************************************//** ++ @Function FM_PORT_DumpRegs ++ ++ @Description Dump all regs. ++ ++ Calling this routine invalidates the descriptor. ++ ++ @Param[in] h_FmPort - FM PORT module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_DumpRegs(t_Handle h_FmPort); ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++/**************************************************************************//** ++ @Function FM_PORT_GetBufferDataOffset ++ ++ @Description Relevant for Rx ports. ++ Returns the data offset from the beginning of the data buffer ++ ++ @Param[in] h_FmPort - FM PORT module descriptor ++ ++ @Return data offset. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++uint32_t FM_PORT_GetBufferDataOffset(t_Handle h_FmPort); ++ ++/**************************************************************************//** ++ @Function FM_PORT_GetBufferICInfo ++ ++ @Description Returns the Internal Context offset from the beginning of the data buffer ++ ++ @Param[in] h_FmPort - FM PORT module descriptor ++ @Param[in] p_Data - A pointer to the data buffer. ++ ++ @Return Internal context info pointer on success, NULL if 'allOtherInfo' was not ++ configured for this port. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++uint8_t * FM_PORT_GetBufferICInfo(t_Handle h_FmPort, char *p_Data); ++ ++/**************************************************************************//** ++ @Function FM_PORT_GetBufferPrsResult ++ ++ @Description Returns the pointer to the parse result in the data buffer. ++ In Rx ports this is relevant after reception, if parse ++ result is configured to be part of the data passed to the ++ application. For non Rx ports it may be used to get the pointer ++ of the area in the buffer where parse result should be ++ initialized - if so configured. ++ See FM_PORT_ConfigBufferPrefixContent for data buffer prefix ++ configuration. ++ ++ @Param[in] h_FmPort - FM PORT module descriptor ++ @Param[in] p_Data - A pointer to the data buffer. ++ ++ @Return Parse result pointer on success, NULL if parse result was not ++ configured for this port. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_FmPrsResult * FM_PORT_GetBufferPrsResult(t_Handle h_FmPort, char *p_Data); ++ ++/**************************************************************************//** ++ @Function FM_PORT_GetBufferTimeStamp ++ ++ @Description Returns the time stamp in the data buffer. ++ Relevant for Rx ports for getting the buffer time stamp. ++ See FM_PORT_ConfigBufferPrefixContent for data buffer prefix ++ configuration. ++ ++ @Param[in] h_FmPort - FM PORT module descriptor ++ @Param[in] p_Data - A pointer to the data buffer. ++ ++ @Return A pointer to the hash result on success, NULL otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++uint64_t * FM_PORT_GetBufferTimeStamp(t_Handle h_FmPort, char *p_Data); ++ ++/**************************************************************************//** ++ @Function FM_PORT_GetBufferHashResult ++ ++ @Description Given a data buffer, on the condition that hash result was defined ++ as a part of the buffer content (see FM_PORT_ConfigBufferPrefixContent) ++ this routine will return the pointer to the hash result location in the ++ buffer prefix. ++ ++ @Param[in] h_FmPort - FM PORT module descriptor ++ @Param[in] p_Data - A pointer to the data buffer. ++ ++ @Return A pointer to the hash result on success, NULL otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++uint8_t * FM_PORT_GetBufferHashResult(t_Handle h_FmPort, char *p_Data); ++ ++/**************************************************************************//** ++ @Function FM_PORT_Disable ++ ++ @Description Gracefully disable an FM port. The port will not start new tasks after all ++ tasks associated with the port are terminated. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++ This is a blocking routine, it returns after port is ++ gracefully stopped, i.e. the port will not except new frames, ++ but it will finish all frames or tasks which were already began ++*//***************************************************************************/ ++t_Error FM_PORT_Disable(t_Handle h_FmPort); ++ ++/**************************************************************************//** ++ @Function FM_PORT_Enable ++ ++ @Description A runtime routine provided to allow disable/enable of port. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_Enable(t_Handle h_FmPort); ++ ++/**************************************************************************//** ++ @Function FM_PORT_SetRateLimit ++ ++ @Description Calling this routine enables rate limit algorithm. ++ By default, this functionality is disabled. ++ Note that rate-limit mechanism uses the FM time stamp. ++ The selected rate limit specified here would be ++ rounded DOWN to the nearest 16M. ++ ++ May be used for Tx and OP ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_RateLimit A structure of rate limit parameters ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++ If rate limit is set on a port that need to send PFC frames, ++ it might violate the stop transmit timing. ++*//***************************************************************************/ ++t_Error FM_PORT_SetRateLimit(t_Handle h_FmPort, t_FmPortRateLimit *p_RateLimit); ++ ++/**************************************************************************//** ++ @Function FM_PORT_DeleteRateLimit ++ ++ @Description Calling this routine disables and clears rate limit ++ initialization. ++ ++ May be used for Tx and OP ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_DeleteRateLimit(t_Handle h_FmPort); ++ ++/**************************************************************************//** ++ @Function FM_PORT_SetPfcPrioritiesMappingToQmanWQ ++ ++ @Description Calling this routine maps each PFC received priority to the transmit WQ. ++ This WQ will be blocked upon receiving a PFC frame with this priority. ++ ++ May be used for Tx ports only. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] prio PFC priority (0-7). ++ @Param[in] wq Work Queue (0-7). ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_SetPfcPrioritiesMappingToQmanWQ(t_Handle h_FmPort, uint8_t prio, uint8_t wq); ++ ++/**************************************************************************//** ++ @Function FM_PORT_SetStatisticsCounters ++ ++ @Description Calling this routine enables/disables port's statistics counters. ++ By default, counters are enabled. ++ ++ May be used for all port types ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] enable TRUE to enable, FALSE to disable. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_SetStatisticsCounters(t_Handle h_FmPort, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_PORT_SetFrameQueueCounters ++ ++ @Description Calling this routine enables/disables port's enqueue/dequeue counters. ++ By default, counters are enabled. ++ ++ May be used for all ports ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] enable TRUE to enable, FALSE to disable. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_SetFrameQueueCounters(t_Handle h_FmPort, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_PORT_AnalyzePerformanceParams ++ ++ @Description User may call this routine to so the driver will analyze if the ++ basic performance parameters are correct and also the driver may ++ suggest of improvements; The basic parameters are FIFO sizes, number ++ of DMAs and number of TNUMs for the port. ++ ++ May be used for all port types ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_AnalyzePerformanceParams(t_Handle h_FmPort); ++ ++ ++/**************************************************************************//** ++ @Function FM_PORT_SetAllocBufCounter ++ ++ @Description Calling this routine enables/disables BM pool allocate ++ buffer counters. ++ By default, counters are enabled. ++ ++ May be used for Rx ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] poolId BM pool id. ++ @Param[in] enable TRUE to enable, FALSE to disable. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_SetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_PORT_GetBmiCounters ++ ++ @Description Read port's BMI stat counters and place them into ++ a designated structure of counters. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[out] p_BmiStats counters structure ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_GetBmiCounters(t_Handle h_FmPort, t_FmPortBmiStats *p_BmiStats); ++ ++/**************************************************************************//** ++ @Function FM_PORT_GetCounter ++ ++ @Description Reads one of the FM PORT counters. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] fmPortCounter The requested counter. ++ ++ @Return Counter's current value. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++ Note that it is user's responsibility to call this routine only ++ for enabled counters, and there will be no indication if a ++ disabled counter is accessed. ++*//***************************************************************************/ ++uint32_t FM_PORT_GetCounter(t_Handle h_FmPort, e_FmPortCounters fmPortCounter); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ModifyCounter ++ ++ @Description Sets a value to an enabled counter. Use "0" to reset the counter. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] fmPortCounter The requested counter. ++ @Param[in] value The requested value to be written into the counter. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ModifyCounter(t_Handle h_FmPort, e_FmPortCounters fmPortCounter, uint32_t value); ++ ++/**************************************************************************//** ++ @Function FM_PORT_GetAllocBufCounter ++ ++ @Description Reads one of the FM PORT buffer counters. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] poolId The requested pool. ++ ++ @Return Counter's current value. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++ Note that it is user's responsibility to call this routine only ++ for enabled counters, and there will be no indication if a ++ disabled counter is accessed. ++*//***************************************************************************/ ++uint32_t FM_PORT_GetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ModifyAllocBufCounter ++ ++ @Description Sets a value to an enabled counter. Use "0" to reset the counter. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] poolId The requested pool. ++ @Param[in] value The requested value to be written into the counter. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ModifyAllocBufCounter(t_Handle h_FmPort, uint8_t poolId, uint32_t value); ++ ++/**************************************************************************//** ++ @Function FM_PORT_AddCongestionGrps ++ ++ @Description This routine effects the corresponding Tx port. ++ It should be called in order to enable pause ++ frame transmission in case of congestion in one or more ++ of the congestion groups relevant to this port. ++ Each call to this routine may add one or more congestion ++ groups to be considered relevant to this port. ++ ++ May be used for Rx, or RX+OP ports only (depending on chip) ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_CongestionGrps A pointer to an array of congestion groups ++ id's to consider. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_AddCongestionGrps(t_Handle h_FmPort, t_FmPortCongestionGrps *p_CongestionGrps); ++ ++/**************************************************************************//** ++ @Function FM_PORT_RemoveCongestionGrps ++ ++ @Description This routine effects the corresponding Tx port. It should be ++ called when congestion groups were ++ defined for this port and are no longer relevant, or pause ++ frames transmitting is not required on their behalf. ++ Each call to this routine may remove one or more congestion ++ groups to be considered relevant to this port. ++ ++ May be used for Rx, or RX+OP ports only (depending on chip) ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_CongestionGrps A pointer to an array of congestion groups ++ id's to consider. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_RemoveCongestionGrps(t_Handle h_FmPort, t_FmPortCongestionGrps *p_CongestionGrps); ++ ++/**************************************************************************//** ++ @Function FM_PORT_IsStalled ++ ++ @Description A routine for checking whether the specified port is stalled. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ ++ @Return TRUE if port is stalled, FALSE otherwize ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++bool FM_PORT_IsStalled(t_Handle h_FmPort); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ReleaseStalled ++ ++ @Description This routine may be called in case the port was stalled and may ++ now be released. ++ Note that this routine is available only on older FMan revisions ++ (FMan v2, DPAA v1.0 only). ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_ReleaseStalled(t_Handle h_FmPort); ++ ++/**************************************************************************//** ++ @Function FM_PORT_SetRxL4ChecksumVerify ++ ++ @Description This routine is relevant for Rx ports (1G and 10G). The routine ++ set/clear the L3/L4 checksum verification (on RX side). ++ Note that this takes affect only if hw-parser is enabled! ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] l4Checksum boolean indicates whether to do L3/L4 checksum ++ on frames or not. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_SetRxL4ChecksumVerify(t_Handle h_FmPort, bool l4Checksum); ++ ++/**************************************************************************//** ++ @Function FM_PORT_SetErrorsRoute ++ ++ @Description Errors selected for this routine will cause a frame with that error ++ to be enqueued to error queue. ++ Errors not selected for this routine will cause a frame with that error ++ to be enqueued to the one of the other port queues. ++ By default all errors are defined to be enqueued to error queue. ++ Errors that were configured to be discarded (at initialization) ++ may not be selected here. ++ ++ May be used for Rx and OP ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] errs A list of errors to enqueue to error queue ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_SetErrorsRoute(t_Handle h_FmPort, fmPortFrameErrSelect_t errs); ++ ++/**************************************************************************//** ++ @Function FM_PORT_SetIMExceptions ++ ++ @Description Calling this routine enables/disables FM PORT interrupts. ++ ++ @Param[in] h_FmPort FM PORT module descriptor. ++ @Param[in] exception The exception to be selected. ++ @Param[in] enable TRUE to enable interrupt, FALSE to mask it. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++ This routine should NOT be called from guest-partition ++ (i.e. guestId != NCSW_MASTER_ID) ++*//***************************************************************************/ ++t_Error FM_PORT_SetIMExceptions(t_Handle h_FmPort, e_FmPortExceptions exception, bool enable); ++ ++/**************************************************************************//* ++ @Function FM_PORT_SetPerformanceCounters ++ ++ @Description Calling this routine enables/disables port's performance counters. ++ By default, counters are enabled. ++ ++ May be used for all port types ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] enable TRUE to enable, FALSE to disable. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_SetPerformanceCounters(t_Handle h_FmPort, bool enable); ++ ++/**************************************************************************//* ++ @Function FM_PORT_SetPerformanceCountersParams ++ ++ @Description Calling this routine defines port's performance ++ counters parameters. ++ ++ May be used for all port types ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_FmPortPerformanceCnt A pointer to a structure of performance ++ counters parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_SetPerformanceCountersParams(t_Handle h_FmPort, t_FmPortPerformanceCnt *p_FmPortPerformanceCnt); ++ ++/**************************************************************************//** ++ @Group FM_PORT_pcd_runtime_control_grp FM Port PCD Runtime Control Unit ++ ++ @Description FM Port PCD Runtime control unit API functions, definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description A structure defining the KG scheme after the parser. ++ This is relevant only to change scheme selection mode - from ++ direct to indirect and vice versa, or when the scheme is selected directly, ++ to select the scheme id. ++ ++*//***************************************************************************/ ++typedef struct t_FmPcdKgSchemeSelect { ++ bool direct; /**< TRUE to use 'h_Scheme' directly, FALSE to use LCV. */ ++ t_Handle h_DirectScheme; /**< Scheme handle, selects the scheme after parser; ++ Relevant only when 'direct' is TRUE. */ ++} t_FmPcdKgSchemeSelect; ++ ++/**************************************************************************//** ++ @Description A structure of scheme parameters ++*//***************************************************************************/ ++typedef struct t_FmPcdPortSchemesParams { ++ uint8_t numOfSchemes; /**< Number of schemes for port to be bound to. */ ++ t_Handle h_Schemes[FM_PCD_KG_NUM_OF_SCHEMES]; /**< Array of 'numOfSchemes' schemes for the ++ port to be bound to */ ++} t_FmPcdPortSchemesParams; ++ ++/**************************************************************************//** ++ @Description Union for defining port protocol parameters for parser ++*//***************************************************************************/ ++typedef union u_FmPcdHdrPrsOpts { ++ /* MPLS */ ++ struct { ++ bool labelInterpretationEnable; /**< When this bit is set, the last MPLS label will be ++ interpreted as described in HW spec table. When the bit ++ is cleared, the parser will advance to MPLS next parse */ ++ e_NetHeaderType nextParse; /**< must be equal or higher than IPv4 */ ++ } mplsPrsOptions; ++ /* VLAN */ ++ struct { ++ uint16_t tagProtocolId1; /**< User defined Tag Protocol Identifier, to be recognized ++ on VLAN TAG on top of 0x8100 and 0x88A8 */ ++ uint16_t tagProtocolId2; /**< User defined Tag Protocol Identifier, to be recognized ++ on VLAN TAG on top of 0x8100 and 0x88A8 */ ++ } vlanPrsOptions; ++ /* PPP */ ++ struct{ ++ bool enableMTUCheck; /**< Check validity of MTU according to RFC2516 */ ++ } pppoePrsOptions; ++ ++ /* IPV6 */ ++ struct{ ++ bool routingHdrEnable; /**< TRUE to enable routing header, otherwise ignore */ ++ } ipv6PrsOptions; ++ ++ /* UDP */ ++ struct{ ++ bool padIgnoreChecksum; /**< TRUE to ignore pad in checksum */ ++ } udpPrsOptions; ++ ++ /* TCP */ ++ struct { ++ bool padIgnoreChecksum; /**< TRUE to ignore pad in checksum */ ++ } tcpPrsOptions; ++} u_FmPcdHdrPrsOpts; ++ ++/**************************************************************************//** ++ @Description A structure for defining each header for the parser ++*//***************************************************************************/ ++typedef struct t_FmPcdPrsAdditionalHdrParams { ++ e_NetHeaderType hdr; /**< Selected header; use HEADER_TYPE_NONE ++ to indicate that sw parser is to run first ++ (before HW parser, and independent of the ++ existence of any protocol), in this case, ++ swPrsEnable must be set, and all other ++ parameters are irrelevant. */ ++ bool errDisable; /**< TRUE to disable error indication */ ++ bool swPrsEnable; /**< Enable jump to SW parser when this ++ header is recognized by the HW parser. */ ++ uint8_t indexPerHdr; /**< Normally 0, if more than one sw parser ++ attachments exists for the same header, ++ (in the main sw parser code) use this ++ index to distinguish between them. */ ++ bool usePrsOpts; /**< TRUE to use parser options. */ ++ u_FmPcdHdrPrsOpts prsOpts; /**< A union according to header type, ++ defining the parser options selected.*/ ++} t_FmPcdPrsAdditionalHdrParams; ++ ++/**************************************************************************//** ++ @Description struct for defining port PCD parameters ++*//***************************************************************************/ ++typedef struct t_FmPortPcdPrsParams { ++ uint8_t prsResultPrivateInfo; /**< The private info provides a method of inserting ++ port information into the parser result. This information ++ may be extracted by Keygen and be used for frames ++ distribution when a per-port distinction is required, ++ it may also be used as a port logical id for analyzing ++ incoming frames. */ ++ uint8_t parsingOffset; /**< Number of bytes from beginning of packet to start parsing */ ++ e_NetHeaderType firstPrsHdr; /**< The type of the first header expected at 'parsingOffset' */ ++ bool includeInPrsStatistics; /**< TRUE to include this port in the parser statistics; ++ NOTE: this field is not valid when the FM is in "guest" mode ++ and IPC is not available. */ ++ uint8_t numOfHdrsWithAdditionalParams; /**< Normally 0, some headers may get ++ special parameters */ ++ t_FmPcdPrsAdditionalHdrParams additionalParams[FM_PCD_PRS_NUM_OF_HDRS]; ++ /**< 'numOfHdrsWithAdditionalParams' structures ++ of additional parameters ++ for each header that requires them */ ++ bool setVlanTpid1; /**< TRUE to configure user selection of Ethertype to ++ indicate a VLAN tag (in addition to the TPID values ++ 0x8100 and 0x88A8). */ ++ uint16_t vlanTpid1; /**< extra tag to use if setVlanTpid1=TRUE. */ ++ bool setVlanTpid2; /**< TRUE to configure user selection of Ethertype to ++ indicate a VLAN tag (in addition to the TPID values ++ 0x8100 and 0x88A8). */ ++ uint16_t vlanTpid2; /**< extra tag to use if setVlanTpid1=TRUE. */ ++} t_FmPortPcdPrsParams; ++ ++/**************************************************************************//** ++ @Description struct for defining coarse alassification parameters ++*//***************************************************************************/ ++typedef struct t_FmPortPcdCcParams { ++ t_Handle h_CcTree; /**< A handle to a CC tree */ ++} t_FmPortPcdCcParams; ++ ++/**************************************************************************//** ++ @Description struct for defining keygen parameters ++*//***************************************************************************/ ++typedef struct t_FmPortPcdKgParams { ++ uint8_t numOfSchemes; /**< Number of schemes for port to be bound to. */ ++ t_Handle h_Schemes[FM_PCD_KG_NUM_OF_SCHEMES]; ++ /**< Array of 'numOfSchemes' schemes handles for the ++ port to be bound to */ ++ bool directScheme; /**< TRUE for going from parser to a specific scheme, ++ regardless of parser result */ ++ t_Handle h_DirectScheme; /**< relevant only if direct == TRUE, Scheme handle, ++ as returned by FM_PCD_KgSetScheme */ ++} t_FmPortPcdKgParams; ++ ++/**************************************************************************//** ++ @Description struct for defining policer parameters ++*//***************************************************************************/ ++typedef struct t_FmPortPcdPlcrParams { ++ t_Handle h_Profile; /**< Selected profile handle */ ++} t_FmPortPcdPlcrParams; ++ ++/**************************************************************************//** ++ @Description struct for defining port PCD parameters ++*//***************************************************************************/ ++typedef struct t_FmPortPcdParams { ++ e_FmPortPcdSupport pcdSupport; /**< Relevant for Rx and offline ports only. ++ Describes the active PCD engines for this port. */ ++ t_Handle h_NetEnv; /**< HL Unused in PLCR only mode */ ++ t_FmPortPcdPrsParams *p_PrsParams; /**< Parser parameters for this port */ ++ t_FmPortPcdCcParams *p_CcParams; /**< Coarse classification parameters for this port */ ++ t_FmPortPcdKgParams *p_KgParams; /**< Keygen parameters for this port */ ++ t_FmPortPcdPlcrParams *p_PlcrParams; /**< Policer parameters for this port; Relevant for one of ++ following cases: ++ e_FM_PORT_PCD_SUPPORT_PLCR_ONLY or ++ e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR were selected, ++ or if any flow uses a KG scheme were policer ++ profile is not generated ++ ('bypassPlcrProfileGeneration selected'). */ ++ t_Handle h_IpReassemblyManip; /**< IP Reassembly manipulation */ ++#if (DPAA_VERSION >= 11) ++ t_Handle h_CapwapReassemblyManip;/**< CAPWAP Reassembly manipulation */ ++#endif /* (DPAA_VERSION >= 11) */ ++} t_FmPortPcdParams; ++ ++/**************************************************************************//** ++ @Description A structure for defining the Parser starting point ++*//***************************************************************************/ ++typedef struct t_FmPcdPrsStart { ++ uint8_t parsingOffset; /**< Number of bytes from beginning of packet to ++ start parsing */ ++ e_NetHeaderType firstPrsHdr; /**< The type of the first header axpected at ++ 'parsingOffset' */ ++} t_FmPcdPrsStart; ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Description struct for defining external buffer margins ++*//***************************************************************************/ ++typedef struct t_FmPortVSPAllocParams { ++ uint8_t numOfProfiles; /**< Number of Virtual Storage Profiles; must be a power of 2 */ ++ uint8_t dfltRelativeId; /**< The default Virtual-Storage-Profile-id dedicated to Rx/OP port ++ The same default Virtual-Storage-Profile-id will be for coupled Tx port ++ if relevant function called for Rx port */ ++ t_Handle h_FmTxPort; /**< Handle to coupled Tx Port; not relevant for OP port. */ ++} t_FmPortVSPAllocParams; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ ++/**************************************************************************//** ++ @Function FM_PORT_SetPCD ++ ++ @Description Calling this routine defines the port's PCD configuration. ++ It changes it from its default configuration which is PCD ++ disabled (BMI to BMI) and configures it according to the passed ++ parameters. ++ ++ May be used for Rx and OP ports only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_FmPortPcd A Structure of parameters defining the port's PCD ++ configuration. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_SetPCD(t_Handle h_FmPort, t_FmPortPcdParams *p_FmPortPcd); ++ ++/**************************************************************************//** ++ @Function FM_PORT_DeletePCD ++ ++ @Description Calling this routine releases the port's PCD configuration. ++ The port returns to its default configuration which is PCD ++ disabled (BMI to BMI) and all PCD configuration is removed. ++ ++ May be used for Rx and OP ports which are ++ in PCD mode only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_DeletePCD(t_Handle h_FmPort); ++ ++/**************************************************************************//** ++ @Function FM_PORT_AttachPCD ++ ++ @Description This routine may be called after FM_PORT_DetachPCD was called, ++ to return to the originally configured PCD support flow. ++ The couple of routines are used to allow PCD configuration changes ++ that demand that PCD will not be used while changes take place. ++ ++ May be used for Rx and OP ports which are ++ in PCD mode only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++t_Error FM_PORT_AttachPCD(t_Handle h_FmPort); ++ ++/**************************************************************************//** ++ @Function FM_PORT_DetachPCD ++ ++ @Description Calling this routine detaches the port from its PCD functionality. ++ The port returns to its default flow which is BMI to BMI. ++ ++ May be used for Rx and OP ports which are ++ in PCD mode only ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_AttachPCD(). ++*//***************************************************************************/ ++t_Error FM_PORT_DetachPCD(t_Handle h_FmPort); ++ ++/**************************************************************************//** ++ @Function FM_PORT_PcdPlcrAllocProfiles ++ ++ @Description This routine may be called only for ports that use the Policer in ++ order to allocate private policer profiles. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] numOfProfiles The number of required policer profiles ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init() and FM_PCD_Init(), ++ and before FM_PORT_SetPCD(). ++*//***************************************************************************/ ++t_Error FM_PORT_PcdPlcrAllocProfiles(t_Handle h_FmPort, uint16_t numOfProfiles); ++ ++/**************************************************************************//** ++ @Function FM_PORT_PcdPlcrFreeProfiles ++ ++ @Description This routine should be called for freeing private policer profiles. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init() and FM_PCD_Init(), ++ and before FM_PORT_SetPCD(). ++*//***************************************************************************/ ++t_Error FM_PORT_PcdPlcrFreeProfiles(t_Handle h_FmPort); ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Function FM_PORT_VSPAlloc ++ ++ @Description This routine allocated VSPs per port and forces the port to work ++ in VSP mode. Note that the port is initialized by default with the ++ physical-storage-profile only. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_Params A structure of parameters for allocation VSP's per port ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(), and before FM_PORT_SetPCD() ++ and also before FM_PORT_Enable(); i.e. the port should be disabled. ++*//***************************************************************************/ ++t_Error FM_PORT_VSPAlloc(t_Handle h_FmPort, t_FmPortVSPAllocParams *p_Params); ++#endif /* (DPAA_VERSION >= 11) */ ++ ++/**************************************************************************//** ++ @Function FM_PORT_PcdKgModifyInitialScheme ++ ++ @Description This routine may be called only for ports that use the keygen in ++ order to change the initial scheme frame should be routed to. ++ The change may be of a scheme id (in case of direct mode), ++ from direct to indirect, or from indirect to direct - specifying the scheme id. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_FmPcdKgScheme A structure of parameters for defining whether ++ a scheme is direct/indirect, and if direct - scheme id. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init() and FM_PORT_SetPCD(). ++*//***************************************************************************/ ++t_Error FM_PORT_PcdKgModifyInitialScheme (t_Handle h_FmPort, t_FmPcdKgSchemeSelect *p_FmPcdKgScheme); ++ ++/**************************************************************************//** ++ @Function FM_PORT_PcdPlcrModifyInitialProfile ++ ++ @Description This routine may be called for ports with flows ++ e_FM_PORT_PCD_SUPPORT_PLCR_ONLY or e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR ++ only, to change the initial Policer profile frame should be ++ routed to. The change may be of a profile and/or absolute/direct ++ mode selection. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] h_Profile Policer profile handle ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init() and FM_PORT_SetPCD(). ++*//***************************************************************************/ ++t_Error FM_PORT_PcdPlcrModifyInitialProfile (t_Handle h_FmPort, t_Handle h_Profile); ++ ++/**************************************************************************//** ++ @Function FM_PORT_PcdCcModifyTree ++ ++ @Description This routine may be called for ports that use coarse classification tree ++ if the user wishes to replace the tree. The routine may not be called while port ++ receives packets using the PCD functionalities, therefor port must be first detached ++ from the PCD, only than the routine may be called, and than port be attached to PCD again. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] h_CcTree A CC tree that was already built. The tree id as returned from ++ the BuildTree routine. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(), FM_PORT_SetPCD() and FM_PORT_DetachPCD() ++*//***************************************************************************/ ++t_Error FM_PORT_PcdCcModifyTree (t_Handle h_FmPort, t_Handle h_CcTree); ++ ++/**************************************************************************//** ++ @Function FM_PORT_PcdKgBindSchemes ++ ++ @Description These routines may be called for adding more schemes for the ++ port to be bound to. The selected schemes are not added, ++ just this specific port starts using them. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_PortScheme A structure defining the list of schemes to be added. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init() and FM_PORT_SetPCD(). ++*//***************************************************************************/ ++t_Error FM_PORT_PcdKgBindSchemes (t_Handle h_FmPort, t_FmPcdPortSchemesParams *p_PortScheme); ++ ++/**************************************************************************//** ++ @Function FM_PORT_PcdKgUnbindSchemes ++ ++ @Description These routines may be called for adding more schemes for the ++ port to be bound to. The selected schemes are not removed or invalidated, ++ just this specific port stops using them. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_PortScheme A structure defining the list of schemes to be added. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init() and FM_PORT_SetPCD(). ++*//***************************************************************************/ ++t_Error FM_PORT_PcdKgUnbindSchemes (t_Handle h_FmPort, t_FmPcdPortSchemesParams *p_PortScheme); ++ ++/**************************************************************************//** ++ @Function FM_PORT_GetIPv4OptionsCount ++ ++ @Description TODO ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[out] p_Ipv4OptionsCount will hold the counter value ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init() ++*//***************************************************************************/ ++t_Error FM_PORT_GetIPv4OptionsCount(t_Handle h_FmPort, uint32_t *p_Ipv4OptionsCount); ++ ++/** @} */ /* end of FM_PORT_pcd_runtime_control_grp group */ ++/** @} */ /* end of FM_PORT_runtime_control_grp group */ ++ ++ ++/**************************************************************************//** ++ @Group FM_PORT_runtime_data_grp FM Port Runtime Data-path Unit ++ ++ @Description FM Port Runtime data unit API functions, definitions and enums. ++ This API is valid only if working in Independent-Mode. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function FM_PORT_ImTx ++ ++ @Description Tx function, called to transmit a data buffer on the port. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_Data A pointer to an LCP data buffer. ++ @Param[in] length Size of data for transmission. ++ @Param[in] lastBuffer Buffer position - TRUE for the last buffer ++ of a frame, including a single buffer frame ++ @Param[in] h_BufContext A handle of the user acossiated with this buffer ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++ NOTE - This routine can be used only when working in ++ Independent-Mode mode. ++*//***************************************************************************/ ++t_Error FM_PORT_ImTx( t_Handle h_FmPort, ++ uint8_t *p_Data, ++ uint16_t length, ++ bool lastBuffer, ++ t_Handle h_BufContext); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ImTxConf ++ ++ @Description Tx port confirmation routine, optional, may be called to verify ++ transmission of all frames. The procedure performed by this ++ routine will be performed automatically on next buffer transmission, ++ but if desired, calling this routine will invoke this action on ++ demand. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++ NOTE - This routine can be used only when working in ++ Independent-Mode mode. ++*//***************************************************************************/ ++void FM_PORT_ImTxConf(t_Handle h_FmPort); ++ ++/**************************************************************************//** ++ @Function FM_PORT_ImRx ++ ++ @Description Rx function, may be called to poll for received buffers. ++ Normally, Rx process is invoked by the driver on Rx interrupt. ++ Alternatively, this routine may be called on demand. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++ NOTE - This routine can be used only when working in ++ Independent-Mode mode. ++*//***************************************************************************/ ++t_Error FM_PORT_ImRx(t_Handle h_FmPort); ++ ++/** @} */ /* end of FM_PORT_runtime_data_grp group */ ++/** @} */ /* end of FM_PORT_grp group */ ++/** @} */ /* end of FM_grp group */ ++ ++ ++ ++#ifdef NCSW_BACKWARD_COMPATIBLE_API ++#define FM_PORT_ConfigTxFifoDeqPipelineDepth FM_PORT_ConfigFifoDeqPipelineDepth ++#endif /* NCSW_BACKWARD_COMPATIBLE_API */ ++ ++ ++#endif /* __FM_PORT_EXT */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_rtc_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_rtc_ext.h +new file mode 100644 +index 00000000..72078ac4 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_rtc_ext.h +@@ -0,0 +1,619 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File fm_rtc_ext.h ++ ++ @Description External definitions and API for FM RTC IEEE1588 Timer Module. ++ ++ @Cautions None. ++*//***************************************************************************/ ++ ++#ifndef __FM_RTC_EXT_H__ ++#define __FM_RTC_EXT_H__ ++ ++ ++#include "error_ext.h" ++#include "std_ext.h" ++#include "fsl_fman_rtc.h" ++ ++/**************************************************************************//** ++ ++ @Group FM_grp Frame Manager API ++ ++ @Description FM API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group fm_rtc_grp FM RTC ++ ++ @Description FM RTC functions, definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group fm_rtc_init_grp FM RTC Initialization Unit ++ ++ @Description FM RTC initialization API. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description FM RTC Alarm Polarity Options. ++*//***************************************************************************/ ++typedef enum e_FmRtcAlarmPolarity ++{ ++ e_FM_RTC_ALARM_POLARITY_ACTIVE_HIGH = E_FMAN_RTC_ALARM_POLARITY_ACTIVE_HIGH, /**< Active-high output polarity */ ++ e_FM_RTC_ALARM_POLARITY_ACTIVE_LOW = E_FMAN_RTC_ALARM_POLARITY_ACTIVE_LOW /**< Active-low output polarity */ ++} e_FmRtcAlarmPolarity; ++ ++/**************************************************************************//** ++ @Description FM RTC Trigger Polarity Options. ++*//***************************************************************************/ ++typedef enum e_FmRtcTriggerPolarity ++{ ++ e_FM_RTC_TRIGGER_ON_RISING_EDGE = E_FMAN_RTC_TRIGGER_ON_RISING_EDGE, /**< Trigger on rising edge */ ++ e_FM_RTC_TRIGGER_ON_FALLING_EDGE = E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE /**< Trigger on falling edge */ ++} e_FmRtcTriggerPolarity; ++ ++/**************************************************************************//** ++ @Description IEEE1588 Timer Module FM RTC Optional Clock Sources. ++*//***************************************************************************/ ++typedef enum e_FmSrcClock ++{ ++ e_FM_RTC_SOURCE_CLOCK_EXTERNAL = E_FMAN_RTC_SOURCE_CLOCK_EXTERNAL, /**< external high precision timer reference clock */ ++ e_FM_RTC_SOURCE_CLOCK_SYSTEM = E_FMAN_RTC_SOURCE_CLOCK_SYSTEM, /**< MAC system clock */ ++ e_FM_RTC_SOURCE_CLOCK_OSCILATOR = E_FMAN_RTC_SOURCE_CLOCK_OSCILATOR /**< RTC clock oscilator */ ++}e_FmSrcClk; ++ ++/**************************************************************************//** ++ @Description FM RTC configuration parameters structure. ++ ++ This structure should be passed to FM_RTC_Config(). ++*//***************************************************************************/ ++typedef struct t_FmRtcParams ++{ ++ t_Handle h_Fm; /**< FM Handle*/ ++ uintptr_t baseAddress; /**< Base address of FM RTC registers */ ++ t_Handle h_App; /**< A handle to an application layer object; This handle will ++ be passed by the driver upon calling the above callbacks */ ++} t_FmRtcParams; ++ ++ ++/**************************************************************************//** ++ @Function FM_RTC_Config ++ ++ @Description Configures the FM RTC module according to user's parameters. ++ ++ The driver assigns default values to some FM RTC parameters. ++ These parameters can be overwritten using the advanced ++ configuration routines. ++ ++ @Param[in] p_FmRtcParam - FM RTC configuration parameters. ++ ++ @Return Handle to the new FM RTC object; NULL pointer on failure. ++ ++ @Cautions None ++*//***************************************************************************/ ++t_Handle FM_RTC_Config(t_FmRtcParams *p_FmRtcParam); ++ ++/**************************************************************************//** ++ @Function FM_RTC_Init ++ ++ @Description Initializes the FM RTC driver and hardware. ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). ++*//***************************************************************************/ ++t_Error FM_RTC_Init(t_Handle h_FmRtc); ++ ++/**************************************************************************//** ++ @Function FM_RTC_Free ++ ++ @Description Frees the FM RTC object and all allocated resources. ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). ++*//***************************************************************************/ ++t_Error FM_RTC_Free(t_Handle h_FmRtc); ++ ++ ++/**************************************************************************//** ++ @Group fm_rtc_adv_config_grp FM RTC Advanced Configuration Unit ++ ++ @Description FM RTC advanced configuration functions. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function FM_RTC_ConfigPeriod ++ ++ @Description Configures the period of the timestamp if different than ++ default [DEFAULT_clockPeriod]. ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] period - Period in nano-seconds. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). ++*//***************************************************************************/ ++t_Error FM_RTC_ConfigPeriod(t_Handle h_FmRtc, uint32_t period); ++ ++/**************************************************************************//** ++ @Function FM_RTC_ConfigSourceClock ++ ++ @Description Configures the source clock of the RTC. ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] srcClk - Source clock selection. ++ @Param[in] freqInMhz - the source-clock frequency (in MHz). ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). ++*//***************************************************************************/ ++t_Error FM_RTC_ConfigSourceClock(t_Handle h_FmRtc, ++ e_FmSrcClk srcClk, ++ uint32_t freqInMhz); ++ ++/**************************************************************************//** ++ @Function FM_RTC_ConfigPulseRealignment ++ ++ @Description Configures the RTC to automatic FIPER pulse realignment in ++ response to timer adjustments [DEFAULT_pulseRealign] ++ ++ In this mode, the RTC clock is identical to the source clock. ++ This feature can be useful when the system contains an external ++ RTC with inherent frequency compensation. ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] enable - TRUE to enable automatic realignment. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). ++*//***************************************************************************/ ++t_Error FM_RTC_ConfigPulseRealignment(t_Handle h_FmRtc, bool enable); ++ ++/**************************************************************************//** ++ @Function FM_RTC_ConfigFrequencyBypass ++ ++ @Description Configures the RTC to bypass the frequency compensation ++ mechanism. [DEFAULT_bypass] ++ ++ In this mode, the RTC clock is identical to the source clock. ++ This feature can be useful when the system contains an external ++ RTC with inherent frequency compensation. ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] enabled - TRUE to bypass frequency compensation; ++ FALSE otherwise. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). ++*//***************************************************************************/ ++t_Error FM_RTC_ConfigFrequencyBypass(t_Handle h_FmRtc, bool enabled); ++ ++/**************************************************************************//** ++ @Function FM_RTC_ConfigInvertedInputClockPhase ++ ++ @Description Configures the RTC to invert the source clock phase on input. ++ [DEFAULT_invertInputClkPhase] ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] inverted - TRUE to invert the source clock phase on input. ++ FALSE otherwise. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). ++*//***************************************************************************/ ++t_Error FM_RTC_ConfigInvertedInputClockPhase(t_Handle h_FmRtc, bool inverted); ++ ++/**************************************************************************//** ++ @Function FM_RTC_ConfigInvertedOutputClockPhase ++ ++ @Description Configures the RTC to invert the output clock phase. ++ [DEFAULT_invertOutputClkPhase] ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] inverted - TRUE to invert the output clock phase. ++ FALSE otherwise. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). ++*//***************************************************************************/ ++t_Error FM_RTC_ConfigInvertedOutputClockPhase(t_Handle h_FmRtc, bool inverted); ++ ++/**************************************************************************//** ++ @Function FM_RTC_ConfigOutputClockDivisor ++ ++ @Description Configures the divisor for generating the output clock from ++ the RTC clock. [DEFAULT_outputClockDivisor] ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] divisor - Divisor for generation of the output clock. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). ++*//***************************************************************************/ ++t_Error FM_RTC_ConfigOutputClockDivisor(t_Handle h_FmRtc, uint16_t divisor); ++ ++/**************************************************************************//** ++ @Function FM_RTC_ConfigAlarmPolarity ++ ++ @Description Configures the polarity (active-high/active-low) of a specific ++ alarm signal. [DEFAULT_alarmPolarity] ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] alarmId - Alarm ID. ++ @Param[in] alarmPolarity - Alarm polarity. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). ++*//***************************************************************************/ ++t_Error FM_RTC_ConfigAlarmPolarity(t_Handle h_FmRtc, ++ uint8_t alarmId, ++ e_FmRtcAlarmPolarity alarmPolarity); ++ ++/**************************************************************************//** ++ @Function FM_RTC_ConfigExternalTriggerPolarity ++ ++ @Description Configures the polarity (rising/falling edge) of a specific ++ external trigger signal. [DEFAULT_triggerPolarity] ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] triggerId - Trigger ID. ++ @Param[in] triggerPolarity - Trigger polarity. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously created using FM_RTC_Config(). ++*//***************************************************************************/ ++t_Error FM_RTC_ConfigExternalTriggerPolarity(t_Handle h_FmRtc, ++ uint8_t triggerId, ++ e_FmRtcTriggerPolarity triggerPolarity); ++ ++/** @} */ /* end of fm_rtc_adv_config_grp */ ++/** @} */ /* end of fm_rtc_init_grp */ ++ ++ ++/**************************************************************************//** ++ @Group fm_rtc_control_grp FM RTC Control Unit ++ ++ @Description FM RTC runtime control API. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function t_FmRtcExceptionsCallback ++ ++ @Description Exceptions user callback routine, used for RTC different mechanisms. ++ ++ @Param[in] h_App - User's application descriptor. ++ @Param[in] id - source id. ++*//***************************************************************************/ ++typedef void (t_FmRtcExceptionsCallback) ( t_Handle h_App, uint8_t id); ++ ++/**************************************************************************//** ++ @Description FM RTC alarm parameters. ++*//***************************************************************************/ ++typedef struct t_FmRtcAlarmParams { ++ uint8_t alarmId; /**< 0 or 1 */ ++ uint64_t alarmTime; /**< In nanoseconds, the time when the alarm ++ should go off - must be a multiple of ++ the RTC period */ ++ t_FmRtcExceptionsCallback *f_AlarmCallback; /**< This routine will be called when RTC ++ reaches alarmTime */ ++ bool clearOnExpiration; /**< TRUE to turn off the alarm once expired. */ ++} t_FmRtcAlarmParams; ++ ++/**************************************************************************//** ++ @Description FM RTC Periodic Pulse parameters. ++*//***************************************************************************/ ++typedef struct t_FmRtcPeriodicPulseParams { ++ uint8_t periodicPulseId; /**< 0 or 1 */ ++ uint64_t periodicPulsePeriod; /**< In Nanoseconds. Must be ++ a multiple of the RTC period */ ++ t_FmRtcExceptionsCallback *f_PeriodicPulseCallback; /**< This routine will be called every ++ periodicPulsePeriod. */ ++} t_FmRtcPeriodicPulseParams; ++ ++/**************************************************************************//** ++ @Description FM RTC Periodic Pulse parameters. ++*//***************************************************************************/ ++typedef struct t_FmRtcExternalTriggerParams { ++ uint8_t externalTriggerId; /**< 0 or 1 */ ++ bool usePulseAsInput; /**< Use the pulse interrupt instead of ++ an external signal */ ++ t_FmRtcExceptionsCallback *f_ExternalTriggerCallback; /**< This routine will be called every ++ periodicPulsePeriod. */ ++} t_FmRtcExternalTriggerParams; ++ ++ ++/**************************************************************************//** ++ @Function FM_RTC_Enable ++ ++ @Description Enable the RTC (time count is started). ++ ++ The user can select to resume the time count from previous ++ point, or to restart the time count. ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] resetClock - Restart the time count from zero. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). ++*//***************************************************************************/ ++t_Error FM_RTC_Enable(t_Handle h_FmRtc, bool resetClock); ++ ++/**************************************************************************//** ++ @Function FM_RTC_Disable ++ ++ @Description Disables the RTC (time count is stopped). ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). ++*//***************************************************************************/ ++t_Error FM_RTC_Disable(t_Handle h_FmRtc); ++ ++/**************************************************************************//** ++ @Function FM_RTC_SetClockOffset ++ ++ @Description Sets the clock offset (usually relative to another clock). ++ ++ The user can pass a negative offset value. ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] offset - New clock offset (in nanoseconds). ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). ++*//***************************************************************************/ ++t_Error FM_RTC_SetClockOffset(t_Handle h_FmRtc, int64_t offset); ++ ++/**************************************************************************//** ++ @Function FM_RTC_SetAlarm ++ ++ @Description Schedules an alarm event to a given RTC time. ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] p_FmRtcAlarmParams - Alarm parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). ++ Must be called only prior to FM_RTC_Enable(). ++*//***************************************************************************/ ++t_Error FM_RTC_SetAlarm(t_Handle h_FmRtc, t_FmRtcAlarmParams *p_FmRtcAlarmParams); ++ ++/**************************************************************************//** ++ @Function FM_RTC_SetPeriodicPulse ++ ++ @Description Sets a periodic pulse. ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] p_FmRtcPeriodicPulseParams - Periodic pulse parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). ++ Must be called only prior to FM_RTC_Enable(). ++*//***************************************************************************/ ++t_Error FM_RTC_SetPeriodicPulse(t_Handle h_FmRtc, t_FmRtcPeriodicPulseParams *p_FmRtcPeriodicPulseParams); ++ ++/**************************************************************************//** ++ @Function FM_RTC_ClearPeriodicPulse ++ ++ @Description Clears a periodic pulse. ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] periodicPulseId - Periodic pulse id. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). ++*//***************************************************************************/ ++t_Error FM_RTC_ClearPeriodicPulse(t_Handle h_FmRtc, uint8_t periodicPulseId); ++ ++/**************************************************************************//** ++ @Function FM_RTC_SetExternalTrigger ++ ++ @Description Sets an external trigger indication and define a callback ++ routine to be called on such event. ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] p_FmRtcExternalTriggerParams - External Trigger parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). ++*//***************************************************************************/ ++t_Error FM_RTC_SetExternalTrigger(t_Handle h_FmRtc, t_FmRtcExternalTriggerParams *p_FmRtcExternalTriggerParams); ++ ++/**************************************************************************//** ++ @Function FM_RTC_ClearExternalTrigger ++ ++ @Description Clears external trigger indication. ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] id - External Trigger id. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). ++*//***************************************************************************/ ++t_Error FM_RTC_ClearExternalTrigger(t_Handle h_FmRtc, uint8_t id); ++ ++/**************************************************************************//** ++ @Function FM_RTC_GetExternalTriggerTimeStamp ++ ++ @Description Reads the External Trigger TimeStamp. ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] triggerId - External Trigger id. ++ @Param[out] p_TimeStamp - External Trigger timestamp (in nanoseconds). ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). ++*//***************************************************************************/ ++t_Error FM_RTC_GetExternalTriggerTimeStamp(t_Handle h_FmRtc, ++ uint8_t triggerId, ++ uint64_t *p_TimeStamp); ++ ++/**************************************************************************//** ++ @Function FM_RTC_GetCurrentTime ++ ++ @Description Returns the current RTC time. ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[out] p_Ts - returned time stamp (in nanoseconds). ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). ++*//***************************************************************************/ ++t_Error FM_RTC_GetCurrentTime(t_Handle h_FmRtc, uint64_t *p_Ts); ++ ++/**************************************************************************//** ++ @Function FM_RTC_SetCurrentTime ++ ++ @Description Sets the current RTC time. ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] ts - The new time stamp (in nanoseconds). ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). ++*//***************************************************************************/ ++t_Error FM_RTC_SetCurrentTime(t_Handle h_FmRtc, uint64_t ts); ++ ++/**************************************************************************//** ++ @Function FM_RTC_GetFreqCompensation ++ ++ @Description Retrieves the frequency compensation value ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[out] p_Compensation - A pointer to the returned value of compensation. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). ++*//***************************************************************************/ ++t_Error FM_RTC_GetFreqCompensation(t_Handle h_FmRtc, uint32_t *p_Compensation); ++ ++/**************************************************************************//** ++ @Function FM_RTC_SetFreqCompensation ++ ++ @Description Sets a new frequency compensation value. ++ ++ @Param[in] h_FmRtc - Handle to FM RTC object. ++ @Param[in] freqCompensation - The new frequency compensation value to set. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions h_FmRtc must have been previously initialized using FM_RTC_Init(). ++*//***************************************************************************/ ++t_Error FM_RTC_SetFreqCompensation(t_Handle h_FmRtc, uint32_t freqCompensation); ++ ++#ifdef CONFIG_PTP_1588_CLOCK_DPAA ++/**************************************************************************//** ++*@Function FM_RTC_EnableInterrupt ++* ++*@Description Enable interrupt of FM RTC. ++* ++*@Param[in] h_FmRtc - Handle to FM RTC object. ++*@Param[in] events - Interrupt events. ++* ++*@Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_RTC_EnableInterrupt(t_Handle h_FmRtc, uint32_t events); ++ ++/**************************************************************************//** ++*@Function FM_RTC_DisableInterrupt ++* ++*@Description Disable interrupt of FM RTC. ++* ++*@Param[in] h_FmRtc - Handle to FM RTC object. ++*@Param[in] events - Interrupt events. ++* ++*@Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_RTC_DisableInterrupt(t_Handle h_FmRtc, uint32_t events); ++#endif ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++/**************************************************************************//** ++ @Function FM_RTC_DumpRegs ++ ++ @Description Dumps all FM registers ++ ++ @Param[in] h_FmRtc A handle to an FM RTC Module. ++ ++ @Return E_OK on success; ++ ++ @Cautions Allowed only FM_Init(). ++*//***************************************************************************/ ++t_Error FM_RTC_DumpRegs(t_Handle h_FmRtc); ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++/** @} */ /* end of fm_rtc_control_grp */ ++/** @} */ /* end of fm_rtc_grp */ ++/** @} */ /* end of FM_grp group */ ++ ++ ++#endif /* __FM_RTC_EXT_H__ */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_vsp_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_vsp_ext.h +new file mode 100644 +index 00000000..f9aed036 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/fm_vsp_ext.h +@@ -0,0 +1,411 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File fm_vsp_ext.h ++ ++ @Description FM Virtual Storage-Profile ... ++*//***************************************************************************/ ++#ifndef __FM_VSP_EXT_H ++#define __FM_VSP_EXT_H ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "string_ext.h" ++#include "debug_ext.h" ++ ++#include "fm_ext.h" ++ ++ ++/**************************************************************************//** ++ ++ @Group FM_grp Frame Manager API ++ ++ @Description FM API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group FM_VSP_grp FM Virtual-Storage-Profile ++ ++ @Description FM Virtual-Storage-Profile API ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group FM_VSP_init_grp FM VSP Initialization Unit ++ ++ @Description FM VSP initialization API. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description Virtual Storage Profile ++*//***************************************************************************/ ++typedef struct t_FmVspParams { ++ t_Handle h_Fm; /**< A handle to the FM object this VSP related to */ ++ t_FmExtPools extBufPools; /**< Which external buffer pools are used ++ (up to FM_PORT_MAX_NUM_OF_EXT_POOLS), and their sizes. ++ parameter associated with Rx / OP port */ ++ uint16_t liodnOffset; /**< VSP's LIODN offset */ ++ struct { ++ e_FmPortType portType; /**< Port type */ ++ uint8_t portId; /**< Port Id - relative to type */ ++ } portParams; ++ uint8_t relativeProfileId; /**< VSP Id - relative to VSP's range ++ defined in relevant FM object */ ++} t_FmVspParams; ++ ++ ++/**************************************************************************//** ++ @Function FM_VSP_Config ++ ++ @Description Creates descriptor for the FM VSP module. ++ ++ The routine returns a handle (descriptor) to the FM VSP object. ++ This descriptor must be passed as first parameter to all other ++ FM VSP function calls. ++ ++ No actual initialization or configuration of FM hardware is ++ done by this routine. ++ ++@Param[in] p_FmVspParams Pointer to data structure of parameters ++ ++ @Retval Handle to FM VSP object, or NULL for Failure. ++*//***************************************************************************/ ++t_Handle FM_VSP_Config(t_FmVspParams *p_FmVspParams); ++ ++/**************************************************************************//** ++ @Function FM_VSP_Init ++ ++ @Description Initializes the FM VSP module ++ ++ @Param[in] h_FmVsp - FM VSP module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_VSP_Init(t_Handle h_FmVsp); ++ ++/**************************************************************************//** ++ @Function FM_VSP_Free ++ ++ @Description Frees all resources that were assigned to FM VSP module. ++ ++ Calling this routine invalidates the descriptor. ++ ++ @Param[in] h_FmVsp - FM VSP module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error FM_VSP_Free(t_Handle h_FmVsp); ++ ++ ++/**************************************************************************//** ++ @Group FM_VSP_adv_config_grp FM VSP Advanced Configuration Unit ++ ++ @Description FM VSP advanced configuration functions. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function FM_VSP_ConfigBufferPrefixContent ++ ++ @Description Defines the structure, size and content of the application buffer. ++ ++ The prefix will ++ In VSPs defined for Tx ports, if 'passPrsResult', the application ++ should set a value to their offsets in the prefix of ++ the FM will save the first 'privDataSize', than, ++ depending on 'passPrsResult' and 'passTimeStamp', copy parse result ++ and timeStamp, and the packet itself (in this order), to the ++ application buffer, and to offset. ++ ++ Calling this routine changes the buffer margins definitions ++ in the internal driver data base from its default ++ configuration: Data size: [DEFAULT_FM_SP_bufferPrefixContent_privDataSize] ++ Pass Parser result: [DEFAULT_FM_SP_bufferPrefixContent_passPrsResult]. ++ Pass timestamp: [DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp]. ++ ++ @Param[in] h_FmVsp A handle to a FM VSP module. ++ @Param[in,out] p_FmBufferPrefixContent A structure of parameters describing the ++ structure of the buffer. ++ Out parameter: Start margin - offset ++ of data from start of external buffer. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init(). ++*//***************************************************************************/ ++t_Error FM_VSP_ConfigBufferPrefixContent(t_Handle h_FmVsp, ++ t_FmBufferPrefixContent *p_FmBufferPrefixContent); ++ ++/**************************************************************************//** ++ @Function FM_VSP_ConfigDmaSwapData ++ ++ @Description Calling this routine changes the DMA swap data parameter ++ in the internal driver data base from its default ++ configuration [DEFAULT_FM_SP_dmaSwapData] ++ ++ @Param[in] h_FmVsp A handle to a FM VSP module. ++ @Param[in] swapData New selection ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init(). ++*//***************************************************************************/ ++t_Error FM_VSP_ConfigDmaSwapData(t_Handle h_FmVsp, e_FmDmaSwapOption swapData); ++ ++/**************************************************************************//** ++ @Function FM_VSP_ConfigDmaIcCacheAttr ++ ++ @Description Calling this routine changes the internal context cache ++ attribute parameter in the internal driver data base ++ from its default configuration [DEFAULT_FM_SP_dmaIntContextCacheAttr] ++ ++ @Param[in] h_FmVsp A handle to a FM VSP module. ++ @Param[in] intContextCacheAttr New selection ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init(). ++*//***************************************************************************/ ++t_Error FM_VSP_ConfigDmaIcCacheAttr(t_Handle h_FmVsp, ++ e_FmDmaCacheOption intContextCacheAttr); ++ ++/**************************************************************************//** ++ @Function FM_VSP_ConfigDmaHdrAttr ++ ++ @Description Calling this routine changes the header cache ++ attribute parameter in the internal driver data base ++ from its default configuration [DEFAULT_FM_SP_dmaHeaderCacheAttr] ++ ++ @Param[in] h_FmVsp A handle to a FM VSP module. ++ @Param[in] headerCacheAttr New selection ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init(). ++*//***************************************************************************/ ++t_Error FM_VSP_ConfigDmaHdrAttr(t_Handle h_FmVsp, e_FmDmaCacheOption headerCacheAttr); ++ ++/**************************************************************************//** ++ @Function FM_VSP_ConfigDmaScatterGatherAttr ++ ++ @Description Calling this routine changes the scatter gather cache ++ attribute parameter in the internal driver data base ++ from its default configuration [DEFAULT_FM_SP_dmaScatterGatherCacheAttr] ++ ++ @Param[in] h_FmVsp A handle to a FM VSP module. ++ @Param[in] scatterGatherCacheAttr New selection ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init(). ++*//***************************************************************************/ ++t_Error FM_VSP_ConfigDmaScatterGatherAttr(t_Handle h_FmVsp, ++ e_FmDmaCacheOption scatterGatherCacheAttr); ++ ++/**************************************************************************//** ++ @Function FM_VSP_ConfigDmaWriteOptimize ++ ++ @Description Calling this routine changes the write optimization ++ parameter in the internal driver data base ++ from its default configuration: optimize = [DEFAULT_FM_SP_dmaWriteOptimize] ++ ++ @Param[in] h_FmVsp A handle to a FM VSP module. ++ @Param[in] optimize TRUE to enable optimization, FALSE for normal operation ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init(). ++*//***************************************************************************/ ++t_Error FM_VSP_ConfigDmaWriteOptimize(t_Handle h_FmVsp, bool optimize); ++ ++/**************************************************************************//** ++ @Function FM_VSP_ConfigNoScatherGather ++ ++ @Description Calling this routine changes the possibility to receive S/G frame ++ in the internal driver data base ++ from its default configuration: optimize = [DEFAULT_FM_SP_noScatherGather] ++ ++ @Param[in] h_FmVsp A handle to a FM VSP module. ++ @Param[in] noScatherGather TRUE to operate without scatter/gather capability. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init(). ++*//***************************************************************************/ ++t_Error FM_VSP_ConfigNoScatherGather(t_Handle h_FmVsp, bool noScatherGather); ++ ++/**************************************************************************//** ++ @Function FM_VSP_ConfigPoolDepletion ++ ++ @Description Calling this routine enables pause frame generation depending on the ++ depletion status of BM pools. It also defines the conditions to activate ++ this functionality. By default, this functionality is disabled. ++ ++ @Param[in] h_FmVsp A handle to a FM VSP module. ++ @Param[in] p_BufPoolDepletion A structure of pool depletion parameters ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init(). ++*//***************************************************************************/ ++t_Error FM_VSP_ConfigPoolDepletion(t_Handle h_FmVsp, t_FmBufPoolDepletion *p_BufPoolDepletion); ++ ++/**************************************************************************//** ++ @Function FM_VSP_ConfigBackupPools ++ ++ @Description Calling this routine allows the configuration of some of the BM pools ++ defined for this port as backup pools. ++ A pool configured to be a backup pool will be used only if all other ++ enabled non-backup pools are depleted. ++ ++ @Param[in] h_FmVsp A handle to a FM VSP module. ++ @Param[in] p_BackupBmPools An array of pool id's. All pools specified here will ++ be defined as backup pools. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init(). ++*//***************************************************************************/ ++t_Error FM_VSP_ConfigBackupPools(t_Handle h_FmVsp, t_FmBackupBmPools *p_BackupBmPools); ++ ++/** @} */ /* end of FM_VSP_adv_config_grp group */ ++/** @} */ /* end of FM_VSP_init_grp group */ ++ ++ ++/**************************************************************************//** ++ @Group FM_VSP_control_grp FM VSP Control Unit ++ ++ @Description FM VSP runtime control API. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function FM_VSP_GetBufferDataOffset ++ ++ @Description Relevant for Rx ports. ++ Returns the data offset from the beginning of the data buffer ++ ++ @Param[in] h_FmVsp - FM PORT module descriptor ++ ++ @Return data offset. ++ ++ @Cautions Allowed only following FM_VSP_Init(). ++*//***************************************************************************/ ++uint32_t FM_VSP_GetBufferDataOffset(t_Handle h_FmVsp); ++ ++/**************************************************************************//** ++ @Function FM_VSP_GetBufferICInfo ++ ++ @Description Returns the Internal Context offset from the beginning of the data buffer ++ ++ @Param[in] h_FmVsp - FM PORT module descriptor ++ @Param[in] p_Data - A pointer to the data buffer. ++ ++ @Return Internal context info pointer on success, NULL if 'allOtherInfo' was not ++ configured for this port. ++ ++ @Cautions Allowed only following FM_VSP_Init(). ++*//***************************************************************************/ ++uint8_t * FM_VSP_GetBufferICInfo(t_Handle h_FmVsp, char *p_Data); ++ ++/**************************************************************************//** ++ @Function FM_VSP_GetBufferPrsResult ++ ++ @Description Returns the pointer to the parse result in the data buffer. ++ In Rx ports this is relevant after reception, if parse ++ result is configured to be part of the data passed to the ++ application. For non Rx ports it may be used to get the pointer ++ of the area in the buffer where parse result should be ++ initialized - if so configured. ++ See FM_VSP_ConfigBufferPrefixContent for data buffer prefix ++ configuration. ++ ++ @Param[in] h_FmVsp - FM PORT module descriptor ++ @Param[in] p_Data - A pointer to the data buffer. ++ ++ @Return Parse result pointer on success, NULL if parse result was not ++ configured for this port. ++ ++ @Cautions Allowed only following FM_VSP_Init(). ++*//***************************************************************************/ ++t_FmPrsResult * FM_VSP_GetBufferPrsResult(t_Handle h_FmVsp, char *p_Data); ++ ++/**************************************************************************//** ++ @Function FM_VSP_GetBufferTimeStamp ++ ++ @Description Returns the time stamp in the data buffer. ++ Relevant for Rx ports for getting the buffer time stamp. ++ See FM_VSP_ConfigBufferPrefixContent for data buffer prefix ++ configuration. ++ ++ @Param[in] h_FmVsp - FM PORT module descriptor ++ @Param[in] p_Data - A pointer to the data buffer. ++ ++ @Return A pointer to the hash result on success, NULL otherwise. ++ ++ @Cautions Allowed only following FM_VSP_Init(). ++*//***************************************************************************/ ++uint64_t * FM_VSP_GetBufferTimeStamp(t_Handle h_FmVsp, char *p_Data); ++ ++/**************************************************************************//** ++ @Function FM_VSP_GetBufferHashResult ++ ++ @Description Given a data buffer, on the condition that hash result was defined ++ as a part of the buffer content (see FM_VSP_ConfigBufferPrefixContent) ++ this routine will return the pointer to the hash result location in the ++ buffer prefix. ++ ++ @Param[in] h_FmVsp - FM PORT module descriptor ++ @Param[in] p_Data - A pointer to the data buffer. ++ ++ @Return A pointer to the hash result on success, NULL otherwise. ++ ++ @Cautions Allowed only following FM_VSP_Init(). ++*//***************************************************************************/ ++uint8_t * FM_VSP_GetBufferHashResult(t_Handle h_FmVsp, char *p_Data); ++ ++ ++/** @} */ /* end of FM_VSP_control_grp group */ ++/** @} */ /* end of FM_VSP_grp group */ ++/** @} */ /* end of FM_grp group */ ++ ++ ++#endif /* __FM_VSP_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/mii_acc_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/mii_acc_ext.h +new file mode 100644 +index 00000000..f635d3c2 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/Peripherals/mii_acc_ext.h +@@ -0,0 +1,76 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++ ++#ifndef __MII_ACC_EXT_H ++#define __MII_ACC_EXT_H ++ ++ ++/**************************************************************************//** ++ @Function MII_ReadPhyReg ++ ++ @Description This routine is called to read a specified PHY ++ register value. ++ ++ @Param[in] h_MiiAccess - Handle to MII configuration access registers ++ @Param[in] phyAddr - PHY address (0-31). ++ @Param[in] reg - PHY register to read ++ @Param[out] p_Data - Gets the register value. ++ ++ @Return Always zero (success). ++*//***************************************************************************/ ++int MII_ReadPhyReg(t_Handle h_MiiAccess, ++ uint8_t phyAddr, ++ uint8_t reg, ++ uint16_t *p_Data); ++ ++/**************************************************************************//** ++ @Function MII_WritePhyReg ++ ++ @Description This routine is called to write data to a specified PHY ++ register. ++ ++ @Param[in] h_MiiAccess - Handle to MII configuration access registers ++ @Param[in] phyAddr - PHY address (0-31). ++ @Param[in] reg - PHY register to write ++ @Param[in] data - Data to write in register. ++ ++ @Return Always zero (success). ++*//***************************************************************************/ ++int MII_WritePhyReg(t_Handle h_MiiAccess, ++ uint8_t phyAddr, ++ uint8_t reg, ++ uint16_t data); ++ ++ ++#endif /* __MII_ACC_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/core_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/core_ext.h +new file mode 100644 +index 00000000..ec89a6dd +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/core_ext.h +@@ -0,0 +1,90 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File core_ext.h ++ ++ @Description Generic interface to basic core operations. ++ ++ The system integrator must ensure that this interface is ++ mapped to a specific core implementation, by including the ++ appropriate header file. ++*//***************************************************************************/ ++#ifndef __CORE_EXT_H ++#define __CORE_EXT_H ++ ++#ifdef CONFIG_FMAN_ARM ++#include "arm_ext.h" ++#include ++#else ++#ifdef NCSW_PPC_CORE ++#include "ppc_ext.h" ++#elif defined(NCSW_VXWORKS) ++#include "core_vxw_ext.h" ++#else ++#error "Core is not defined!" ++#endif /* NCSW_CORE */ ++ ++#if (!defined(CORE_IS_LITTLE_ENDIAN) && !defined(CORE_IS_BIG_ENDIAN)) ++#error "Must define core as little-endian or big-endian!" ++#endif /* (!defined(CORE_IS_LITTLE_ENDIAN) && ... */ ++ ++#ifndef CORE_CACHELINE_SIZE ++#error "Must define the core cache-line size!" ++#endif /* !CORE_CACHELINE_SIZE */ ++ ++#endif /* CONFIG_FMAN_ARM */ ++ ++ ++/**************************************************************************//** ++ @Function CORE_GetId ++ ++ @Description Returns the core ID in the system. ++ ++ @Return Core ID. ++*//***************************************************************************/ ++uint32_t CORE_GetId(void); ++ ++/**************************************************************************//** ++ @Function CORE_MemoryBarrier ++ ++ @Description This routine will cause the core to stop executing any commands ++ until all previous memory read/write commands are completely out ++ of the core's pipeline. ++ ++ @Return None. ++*//***************************************************************************/ ++void CORE_MemoryBarrier(void); ++#define fsl_mem_core_barrier() CORE_MemoryBarrier() ++ ++#endif /* __CORE_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/cores/arm_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/cores/arm_ext.h +new file mode 100644 +index 00000000..e63444a7 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/cores/arm_ext.h +@@ -0,0 +1,55 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File arm_ext.h ++ ++ @Description Core API for ARM cores ++ ++ These routines must be implemented by each specific PowerPC ++ core driver. ++*//***************************************************************************/ ++#ifndef __ARM_EXT_H ++#define __ARM_EXT_H ++ ++#include "part_ext.h" ++ ++ ++#define CORE_IS_LITTLE_ENDIAN ++ ++static __inline__ void CORE_MemoryBarrier(void) ++{ ++ mb(); ++} ++ ++#endif /* __PPC_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/cores/e500v2_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/cores/e500v2_ext.h +new file mode 100644 +index 00000000..e79b1ddf +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/cores/e500v2_ext.h +@@ -0,0 +1,476 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File e500v2_ext.h ++ ++ @Description E500 external definitions prototypes ++ This file is not included by the E500 ++ source file as it is an assembly file. It is used ++ only for prototypes exposure, for inclusion ++ by user and other modules. ++*//***************************************************************************/ ++ ++#ifndef __E500V2_EXT_H ++#define __E500V2_EXT_H ++ ++#include "std_ext.h" ++ ++ ++/* Layer 1 Cache Manipulations ++ *============================== ++ * Should not be called directly by the user. ++ */ ++void L1DCache_Invalidate (void); ++void L1ICache_Invalidate(void); ++void L1DCache_Enable(void); ++void L1ICache_Enable(void); ++void L1DCache_Disable(void); ++void L1ICache_Disable(void); ++void L1DCache_Flush(void); ++void L1ICache_Flush(void); ++uint32_t L1ICache_IsEnabled(void); ++uint32_t L1DCache_IsEnabled(void); ++/* ++ * ++ */ ++uint32_t L1DCache_LineLock(uint32_t addr); ++uint32_t L1ICache_LineLock(uint32_t addr); ++void L1Cache_BroadCastEnable(void); ++void L1Cache_BroadCastDisable(void); ++ ++ ++#define CORE_DCacheEnable E500_DCacheEnable ++#define CORE_ICacheEnable E500_ICacheEnable ++#define CORE_DCacheDisable E500_DCacheDisable ++#define CORE_ICacheDisable E500_ICacheDisable ++#define CORE_GetId E500_GetId ++#define CORE_TestAndSet E500_TestAndSet ++#define CORE_MemoryBarrier E500_MemoryBarrier ++#define CORE_InstructionSync E500_InstructionSync ++ ++#define CORE_SetDozeMode E500_SetDozeMode ++#define CORE_SetNapMode E500_SetNapMode ++#define CORE_SetSleepMode E500_SetSleepMode ++#define CORE_SetJogMode E500_SetJogMode ++#define CORE_SetDeepSleepMode E500_SetDeepSleepMode ++ ++#define CORE_RecoverDozeMode E500_RecoverDozeMode ++#define CORE_RecoverNapMode E500_RecoverNapMode ++#define CORE_RecoverSleepMode E500_RecoverSleepMode ++#define CORE_RecoverJogMode E500_RecoverJogMode ++ ++void E500_SetDozeMode(void); ++void E500_SetNapMode(void); ++void E500_SetSleepMode(void); ++void E500_SetJogMode(void); ++t_Error E500_SetDeepSleepMode(uint32_t bptrAddress); ++ ++void E500_RecoverDozeMode(void); ++void E500_RecoverNapMode(void); ++void E500_RecoverSleepMode(void); ++void E500_RecoverJogMode(void); ++ ++ ++/**************************************************************************//** ++ @Group E500_id E500 Application Programming Interface ++ ++ @Description E500 API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group E500_init_grp E500 Initialization Unit ++ ++ @Description E500 initialization unit API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++ ++/**************************************************************************//** ++ @Function E500_DCacheEnable ++ ++ @Description Enables the data cache for memory pages that are ++ not cache inhibited. ++ ++ @Return None. ++*//***************************************************************************/ ++void E500_DCacheEnable(void); ++ ++/**************************************************************************//** ++ @Function E500_ICacheEnable ++ ++ @Description Enables the instruction cache for memory pages that are ++ not cache inhibited. ++ ++ @Return None. ++*//***************************************************************************/ ++void E500_ICacheEnable(void); ++ ++/**************************************************************************//** ++ @Function E500_DCacheDisable ++ ++ @Description Disables the data cache. ++ ++ @Return None. ++*//***************************************************************************/ ++void E500_DCacheDisable(void); ++ ++/**************************************************************************//** ++ @Function E500_ICacheDisable ++ ++ @Description Disables the instruction cache. ++ ++ @Return None. ++*//***************************************************************************/ ++void E500_ICacheDisable(void); ++ ++/**************************************************************************//** ++ @Function E500_DCacheFlush ++ ++ @Description Flushes the data cache ++ ++ @Return None. ++*//***************************************************************************/ ++void E500_DCacheFlush(void); ++ ++/**************************************************************************//** ++ @Function E500_ICacheFlush ++ ++ @Description Flushes the instruction cache. ++ ++ @Return None. ++*//***************************************************************************/ ++void E500_ICacheFlush(void); ++ ++/**************************************************************************//** ++ @Function E500_DCacheSetStashId ++ ++ @Description Set Stash Id for data cache ++ ++ @Param[in] stashId the stash id to be set. ++ ++ @Return None. ++*//***************************************************************************/ ++void E500_DCacheSetStashId(uint8_t stashId); ++ ++/**************************************************************************//** ++ @Description E500mc L2 Cache Operation Mode ++*//***************************************************************************/ ++typedef enum e_E500mcL2CacheMode ++{ ++ e_L2_CACHE_MODE_DATA_ONLY = 0x00000001, /**< Cache data only */ ++ e_L2_CACHE_MODE_INST_ONLY = 0x00000002, /**< Cache instructions only */ ++ e_L2_CACHE_MODE_DATA_AND_INST = 0x00000003 /**< Cache data and instructions */ ++} e_E500mcL2CacheMode; ++ ++#if defined(CORE_E500MC) || defined(CORE_E5500) ++/**************************************************************************//** ++ @Function E500_L2CacheEnable ++ ++ @Description Enables the cache for memory pages that are not cache inhibited. ++ ++ @param[in] mode - L2 cache mode: data only, instruction only or instruction and data. ++ ++ @Return None. ++ ++ @Cautions This routine must be call only ONCE for both caches. I.e. it is ++ not possible to call this routine for i-cache and than to call ++ again for d-cache; The second call will override the first one. ++*//***************************************************************************/ ++void E500_L2CacheEnable(e_E500mcL2CacheMode mode); ++ ++/**************************************************************************//** ++ @Function E500_L2CacheDisable ++ ++ @Description Disables the cache (data instruction or both). ++ ++ @Return None. ++ ++*//***************************************************************************/ ++void E500_L2CacheDisable(void); ++ ++/**************************************************************************//** ++ @Function E500_L2CacheFlush ++ ++ @Description Flushes the cache. ++ ++ @Return None. ++*//***************************************************************************/ ++void E500_L2CacheFlush(void); ++ ++/**************************************************************************//** ++ @Function E500_L2SetStashId ++ ++ @Description Set Stash Id ++ ++ @Param[in] stashId the stash id to be set. ++ ++ @Return None. ++*//***************************************************************************/ ++void E500_L2SetStashId(uint8_t stashId); ++#endif /* defined(CORE_E500MC) || defined(CORE_E5500) */ ++ ++#ifdef CORE_E6500 ++/**************************************************************************//** ++ @Function E6500_L2CacheEnable ++ ++ @Description Enables the cache for memory pages that are not cache inhibited. ++ ++ @param[in] mode - L2 cache mode: support data & instruction only. ++ ++ @Return None. ++ ++ @Cautions This routine must be call only ONCE for both caches. I.e. it is ++ not possible to call this routine for i-cache and than to call ++ again for d-cache; The second call will override the first one. ++*//***************************************************************************/ ++void E6500_L2CacheEnable(uintptr_t clusterBase); ++ ++/**************************************************************************//** ++ @Function E6500_L2CacheDisable ++ ++ @Description Disables the cache (data instruction or both). ++ ++ @Return None. ++ ++*//***************************************************************************/ ++void E6500_L2CacheDisable(uintptr_t clusterBase); ++ ++/**************************************************************************//** ++ @Function E6500_L2CacheFlush ++ ++ @Description Flushes the cache. ++ ++ @Return None. ++*//***************************************************************************/ ++void E6500_L2CacheFlush(uintptr_t clusterBase); ++ ++/**************************************************************************//** ++ @Function E6500_L2SetStashId ++ ++ @Description Set Stash Id ++ ++ @Param[in] stashId the stash id to be set. ++ ++ @Return None. ++*//***************************************************************************/ ++void E6500_L2SetStashId(uintptr_t clusterBase, uint8_t stashId); ++ ++/**************************************************************************//** ++ @Function E6500_GetCcsrBase ++ ++ @Description Obtain SoC CCSR base address ++ ++ @Param[in] None. ++ ++ @Return Physical CCSR base address. ++*//***************************************************************************/ ++physAddress_t E6500_GetCcsrBase(void); ++#endif /* CORE_E6500 */ ++ ++/**************************************************************************//** ++ @Function E500_AddressBusStreamingEnable ++ ++ @Description Enables address bus streaming on the CCB. ++ ++ This setting, along with the ECM streaming configuration ++ parameters, enables address bus streaming on the CCB. ++ ++ @Return None. ++*//***************************************************************************/ ++void E500_AddressBusStreamingEnable(void); ++ ++/**************************************************************************//** ++ @Function E500_AddressBusStreamingDisable ++ ++ @Description Disables address bus streaming on the CCB. ++ ++ @Return None. ++*//***************************************************************************/ ++void E500_AddressBusStreamingDisable(void); ++ ++/**************************************************************************//** ++ @Function E500_AddressBroadcastEnable ++ ++ @Description Enables address broadcast. ++ ++ The e500 broadcasts cache management instructions (dcbst, dcblc ++ (CT = 1), icblc (CT = 1), dcbf, dcbi, mbar, msync, tlbsync, icbi) ++ based on ABE. ABE must be set to allow management of external ++ L2 caches. ++ ++ @Return None. ++*//***************************************************************************/ ++void E500_AddressBroadcastEnable(void); ++ ++/**************************************************************************//** ++ @Function E500_AddressBroadcastDisable ++ ++ @Description Disables address broadcast. ++ ++ The e500 broadcasts cache management instructions (dcbst, dcblc ++ (CT = 1), icblc (CT = 1), dcbf, dcbi, mbar, msync, tlbsync, icbi) ++ based on ABE. ABE must be set to allow management of external ++ L2 caches. ++ ++ @Return None. ++*//***************************************************************************/ ++void E500_AddressBroadcastDisable(void); ++ ++/**************************************************************************//** ++ @Function E500_IsTaskletSupported ++ ++ @Description Checks if tasklets are supported by the e500 interrupt handler. ++ ++ @Retval TRUE - Tasklets are supported. ++ @Retval FALSE - Tasklets are not supported. ++*//***************************************************************************/ ++bool E500_IsTaskletSupported(void); ++ ++void E500_EnableTimeBase(void); ++void E500_DisableTimeBase(void); ++ ++uint64_t E500_GetTimeBaseTime(void); ++ ++void E500_GenericIntrInit(void); ++ ++t_Error E500_SetIntr(int ppcIntrSrc, ++ void (* Isr)(t_Handle handle), ++ t_Handle handle); ++ ++t_Error E500_ClearIntr(int ppcIntrSrc); ++ ++/**************************************************************************//** ++ @Function E500_GenericIntrHandler ++ ++ @Description This is the general e500 interrupt handler. ++ ++ It is called by the main assembly interrupt handler ++ when an exception occurs and no other function has been ++ assigned to this exception. ++ ++ @Param intrEntry - (In) The exception interrupt vector entry. ++*//***************************************************************************/ ++void E500_GenericIntrHandler(uint32_t intrEntry); ++ ++/**************************************************************************//** ++ @Function CriticalIntr ++ ++ @Description This is the specific critical e500 interrupt handler. ++ ++ It is called by the main assembly interrupt handler ++ when an critical interrupt. ++ ++ @Param intrEntry - (In) The exception interrupt vector entry. ++*//***************************************************************************/ ++void CriticalIntr(uint32_t intrEntry); ++ ++ ++/**************************************************************************//** ++ @Function E500_GetId ++ ++ @Description Returns the core ID in the system. ++ ++ @Return Core ID. ++*//***************************************************************************/ ++uint32_t E500_GetId(void); ++ ++/**************************************************************************//** ++ @Function E500_TestAndSet ++ ++ @Description This routine tries to atomically test-and-set an integer ++ in memory to a non-zero value. ++ ++ The memory will be set only if it is tested as zero, in which ++ case the routine returns the new non-zero value; otherwise the ++ routine returns zero. ++ ++ @Param[in] p - pointer to a volatile int in memory, on which test-and-set ++ operation should be made. ++ ++ @Retval Zero - Operation failed - memory was already set. ++ @Retval Non-zero - Operation succeeded - memory has been set. ++*//***************************************************************************/ ++int E500_TestAndSet(volatile int *p); ++ ++/**************************************************************************//** ++ @Function E500_MemoryBarrier ++ ++ @Description This routine will cause the core to stop executing any commands ++ until all previous memory read/write commands are completely out ++ of the core's pipeline. ++ ++ @Return None. ++*//***************************************************************************/ ++static __inline__ void E500_MemoryBarrier(void) ++{ ++#ifndef CORE_E500V2 ++ __asm__ ("mbar 1"); ++#else /* CORE_E500V2 */ ++ /**** ERRATA WORK AROUND START ****/ ++ /* ERRATA num: CPU1 */ ++ /* Description: "mbar MO = 1" instruction fails to order caching-inhibited ++ guarded loads and stores. */ ++ ++ /* "msync" instruction is used instead */ ++ ++ __asm__ ("msync"); ++ ++ /**** ERRATA WORK AROUND END ****/ ++#endif /* CORE_E500V2 */ ++} ++ ++/**************************************************************************//** ++ @Function E500_InstructionSync ++ ++ @Description This routine will cause the core to wait for previous instructions ++ (including any interrupts they generate) to complete before the ++ synchronization command executes, which purges all instructions ++ from the processor's pipeline and refetches the next instruction. ++ ++ @Return None. ++*//***************************************************************************/ ++static __inline__ void E500_InstructionSync(void) ++{ ++ __asm__ ("isync"); ++} ++ ++ ++/** @} */ /* end of E500_init_grp group */ ++/** @} */ /* end of E500_grp group */ ++ ++ ++#endif /* __E500V2_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/cores/ppc_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/cores/ppc_ext.h +new file mode 100644 +index 00000000..9344b3a1 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/cores/ppc_ext.h +@@ -0,0 +1,141 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File ppc_ext.h ++ ++ @Description Core API for PowerPC cores ++ ++ These routines must be implemented by each specific PowerPC ++ core driver. ++*//***************************************************************************/ ++#ifndef __PPC_EXT_H ++#define __PPC_EXT_H ++ ++#include "part_ext.h" ++ ++ ++#define CORE_IS_BIG_ENDIAN ++ ++#if defined(CORE_E300) || defined(CORE_E500V2) ++#define CORE_CACHELINE_SIZE 32 ++#elif defined(CORE_E500MC) || defined(CORE_E5500) || defined(CORE_E6500) ++#define CORE_CACHELINE_SIZE 64 ++#else ++#error "Core not defined!" ++#endif /* defined(CORE_E300) || ... */ ++ ++ ++/**************************************************************************//** ++ @Function CORE_TestAndSet ++ ++ @Description This routine tries to atomically test-and-set an integer ++ in memory to a non-zero value. ++ ++ The memory will be set only if it is tested as zero, in which ++ case the routine returns the new non-zero value; otherwise the ++ routine returns zero. ++ ++ @Param[in] p - pointer to a volatile int in memory, on which test-and-set ++ operation should be made. ++ ++ @Retval Zero - Operation failed - memory was already set. ++ @Retval Non-zero - Operation succeeded - memory has been set. ++*//***************************************************************************/ ++int CORE_TestAndSet(volatile int *p); ++ ++/**************************************************************************//** ++ @Function CORE_InstructionSync ++ ++ @Description This routine will cause the core to wait for previous instructions ++ (including any interrupts they generate) to complete before the ++ synchronization command executes, which purges all instructions ++ from the processor's pipeline and refetches the next instruction. ++ ++ @Return None. ++*//***************************************************************************/ ++void CORE_InstructionSync(void); ++ ++/**************************************************************************//** ++ @Function CORE_DCacheEnable ++ ++ @Description Enables the data cache for memory pages that are ++ not cache inhibited. ++ ++ @Return None. ++*//***************************************************************************/ ++void CORE_DCacheEnable(void); ++ ++/**************************************************************************//** ++ @Function CORE_ICacheEnable ++ ++ @Description Enables the instruction cache for memory pages that are ++ not cache inhibited. ++ ++ @Return None. ++*//***************************************************************************/ ++void CORE_ICacheEnable(void); ++ ++/**************************************************************************//** ++ @Function CORE_DCacheDisable ++ ++ @Description Disables the data cache. ++ ++ @Return None. ++*//***************************************************************************/ ++void CORE_DCacheDisable(void); ++ ++/**************************************************************************//** ++ @Function CORE_ICacheDisable ++ ++ @Description Disables the instruction cache. ++ ++ @Return None. ++*//***************************************************************************/ ++void CORE_ICacheDisable(void); ++ ++ ++ ++#if defined(CORE_E300) ++#include "e300_ext.h" ++#elif defined(CORE_E500V2) || defined(CORE_E500MC) || defined(CORE_E5500) || defined(CORE_E6500) ++#include "e500v2_ext.h" ++#if !defined(NCSW_LINUX) ++#include "e500v2_asm_ext.h" ++#endif ++#else ++#error "Core not defined!" ++#endif ++ ++ ++#endif /* __PPC_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/ddr_std_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/ddr_std_ext.h +new file mode 100644 +index 00000000..8bb343fc +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/ddr_std_ext.h +@@ -0,0 +1,77 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __DDR_SDT_EXT_H ++#define __DDR_SDT_EXT_H ++ ++ ++/**************************************************************************//** ++ @Group ddr_Generic_Resources ++ ++ @Description ddr generic functions, definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++ ++/**************************************************************************//** ++ @Description SPD maximum size ++*//***************************************************************************/ ++#define SPD_MAX_SIZE 256 ++ ++/**************************************************************************//** ++ @Description DDR types select ++*//***************************************************************************/ ++typedef enum e_DdrType ++{ ++ e_DDR_DDR1, ++ e_DDR_DDR2, ++ e_DDR_DDR3, ++ e_DDR_DDR3L, ++ e_DDR_DDR4 ++} e_DdrType; ++ ++/**************************************************************************//** ++ @Description DDR Mode. ++*//***************************************************************************/ ++typedef enum e_DdrMode ++{ ++ e_DDR_BUS_WIDTH_32BIT, ++ e_DDR_BUS_WIDTH_64BIT ++} e_DdrMode; ++ ++/** @} */ /* end of ddr_Generic_Resources group */ ++ ++ ++ ++#endif /* __DDR_SDT_EXT_H */ ++ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/debug_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/debug_ext.h +new file mode 100644 +index 00000000..57db0a14 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/debug_ext.h +@@ -0,0 +1,233 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File debug_ext.h ++ ++ @Description Debug mode definitions. ++*//***************************************************************************/ ++ ++#ifndef __DEBUG_EXT_H ++#define __DEBUG_EXT_H ++ ++#include "std_ext.h" ++#include "xx_ext.h" ++#include "memcpy_ext.h" ++#if (DEBUG_ERRORS > 0) ++#include "sprint_ext.h" ++#include "string_ext.h" ++#endif /* DEBUG_ERRORS > 0 */ ++ ++ ++#if (DEBUG_ERRORS > 0) ++ ++/* Internally used macros */ ++ ++#define DUMP_Print XX_Print ++#define DUMP_MAX_LEVELS 6 ++#define DUMP_IDX_LEN 6 ++#define DUMP_MAX_STR 64 ++ ++ ++#define _CREATE_DUMP_SUBSTR(phrase) \ ++ dumpTmpLevel = 0; dumpSubStr[0] = '\0'; \ ++ snprintf(dumpTmpStr, DUMP_MAX_STR, "%s", #phrase); \ ++ p_DumpToken = strtok(dumpTmpStr, (dumpIsArr[0] ? "[" : ".")); \ ++ while ((p_DumpToken != NULL) && (dumpTmpLevel < DUMP_MAX_LEVELS)) \ ++ { \ ++ strlcat(dumpSubStr, p_DumpToken, DUMP_MAX_STR); \ ++ if (dumpIsArr[dumpTmpLevel]) \ ++ { \ ++ strlcat(dumpSubStr, dumpIdxStr[dumpTmpLevel], DUMP_MAX_STR); \ ++ p_DumpToken = strtok(NULL, "."); \ ++ } \ ++ if ((p_DumpToken != NULL) && \ ++ ((p_DumpToken = strtok(NULL, (dumpIsArr[++dumpTmpLevel] ? "[" : "."))) != NULL)) \ ++ strlcat(dumpSubStr, ".", DUMP_MAX_STR); \ ++ } ++ ++ ++/**************************************************************************//** ++ @Group gen_id General Drivers Utilities ++ ++ @Description External routines. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group dump_id Memory and Registers Dump Mechanism ++ ++ @Description Macros for dumping memory mapped structures. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description Declaration of dump mechanism variables. ++ ++ This macro must be declared at the beginning of each routine ++ which uses the dump mechanism macros, before the routine's code ++ starts. ++*//***************************************************************************/ ++#define DECLARE_DUMP \ ++ char dumpIdxStr[DUMP_MAX_LEVELS + 1][DUMP_IDX_LEN] = { "", }; \ ++ char dumpSubStr[DUMP_MAX_STR] = ""; \ ++ char dumpTmpStr[DUMP_MAX_STR] = ""; \ ++ char *p_DumpToken = NULL; \ ++ int dumpArrIdx = 0, dumpArrSize = 0, dumpLevel = 0, dumpTmpLevel = 0; \ ++ uint8_t dumpIsArr[DUMP_MAX_LEVELS + 1] = { 0 }; \ ++ /* Prevent warnings if not all used */ \ ++ UNUSED(dumpIdxStr[0][0]); \ ++ UNUSED(dumpSubStr[0]); \ ++ UNUSED(dumpTmpStr[0]); \ ++ UNUSED(p_DumpToken); \ ++ UNUSED(dumpArrIdx); \ ++ UNUSED(dumpArrSize); \ ++ UNUSED(dumpLevel); \ ++ UNUSED(dumpTmpLevel); \ ++ UNUSED(dumpIsArr[0]); ++ ++ ++/**************************************************************************//** ++ @Description Prints a title for a subsequent dumped structure or memory. ++ ++ The inputs for this macro are the structure/memory title and ++ its base addresses. ++*//***************************************************************************/ ++#define DUMP_TITLE(addr, msg) \ ++ DUMP_Print("\r\n"); DUMP_Print msg; \ ++ if (addr) \ ++ DUMP_Print(" (%p)", (addr)); \ ++ DUMP_Print("\r\n---------------------------------------------------------\r\n"); ++ ++/**************************************************************************//** ++ @Description Prints a subtitle for a subsequent dumped sub-structure (optional). ++ ++ The inputs for this macro are the sub-structure subtitle. ++ A separating line with this subtitle will be printed. ++*//***************************************************************************/ ++#define DUMP_SUBTITLE(subtitle) \ ++ DUMP_Print("----------- "); DUMP_Print subtitle; DUMP_Print("\r\n") ++ ++ ++/**************************************************************************//** ++ @Description Dumps a memory region in 4-bytes aligned format. ++ ++ The inputs for this macro are the base addresses and size ++ (in bytes) of the memory region. ++*//***************************************************************************/ ++#define DUMP_MEMORY(addr, size) \ ++ MemDisp((uint8_t *)(addr), (int)(size)) ++ ++ ++/**************************************************************************//** ++ @Description Declares a dump loop, for dumping a sub-structure array. ++ ++ The inputs for this macro are: ++ - idx: an index variable, for indexing the sub-structure items ++ inside the loop. This variable must be declared separately ++ in the beginning of the routine. ++ - cnt: the number of times to repeat the loop. This number should ++ equal the number of items in the sub-structures array. ++ ++ Note, that the body of the loop must be written inside brackets. ++*//***************************************************************************/ ++#define DUMP_SUBSTRUCT_ARRAY(idx, cnt) \ ++ for (idx=0, dumpIsArr[dumpLevel++] = 1; \ ++ (idx < cnt) && (dumpLevel > 0) && snprintf(dumpIdxStr[dumpLevel-1], DUMP_IDX_LEN, "[%d]", idx); \ ++ idx++, ((idx < cnt) || (dumpIsArr[--dumpLevel] = 0))) ++ ++ ++/**************************************************************************//** ++ @Description Dumps a structure's member variable. ++ ++ The input for this macro is the full reference for the member ++ variable, where the structure is referenced using a pointer. ++ ++ Note, that a members array must be dumped using DUMP_ARR macro, ++ rather than using this macro. ++ ++ If the member variable is part of a sub-structure hierarchy, ++ the full hierarchy (including array indexing) must be specified. ++ ++ Examples: p_Struct->member ++ p_Struct->sub.member ++ p_Struct->sub[i].member ++*//***************************************************************************/ ++#define DUMP_VAR(st, phrase) \ ++ do { \ ++ void *addr = (void *)&((st)->phrase); \ ++ physAddress_t physAddr = XX_VirtToPhys(addr); \ ++ _CREATE_DUMP_SUBSTR(phrase); \ ++ DUMP_Print("0x%010llX: 0x%08x%8s\t%s\r\n", \ ++ physAddr, GET_UINT32(*(uint32_t*)addr), "", dumpSubStr); \ ++ } while (0) ++ ++ ++/**************************************************************************//** ++ @Description Dumps a structure's members array. ++ ++ The input for this macro is the full reference for the members ++ array, where the structure is referenced using a pointer. ++ ++ If the members array is part of a sub-structure hierarchy, ++ the full hierarchy (including array indexing) must be specified. ++ ++ Examples: p_Struct->array ++ p_Struct->sub.array ++ p_Struct->sub[i].array ++*//***************************************************************************/ ++#define DUMP_ARR(st, phrase) \ ++ do { \ ++ physAddress_t physAddr; \ ++ _CREATE_DUMP_SUBSTR(phrase); \ ++ dumpArrSize = ARRAY_SIZE((st)->phrase); \ ++ for (dumpArrIdx=0; dumpArrIdx < dumpArrSize; dumpArrIdx++) { \ ++ physAddr = XX_VirtToPhys((void *)&((st)->phrase[dumpArrIdx])); \ ++ DUMP_Print("0x%010llX: 0x%08x%8s\t%s[%d]\r\n", \ ++ physAddr, GET_UINT32((st)->phrase[dumpArrIdx]), "", dumpSubStr, dumpArrIdx); \ ++ } \ ++ } while (0) ++ ++ ++ ++#endif /* DEBUG_ERRORS > 0 */ ++ ++ ++/** @} */ /* end of dump_id group */ ++/** @} */ /* end of gen_id group */ ++ ++ ++#endif /* __DEBUG_EXT_H */ ++ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/endian_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/endian_ext.h +new file mode 100644 +index 00000000..5cdec668 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/endian_ext.h +@@ -0,0 +1,447 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ ++ @File endian_ext.h ++ ++ @Description Big/little endian swapping routines. ++*//***************************************************************************/ ++ ++#ifndef __ENDIAN_EXT_H ++#define __ENDIAN_EXT_H ++ ++#include "std_ext.h" ++ ++ ++/**************************************************************************//** ++ @Group gen_id General Drivers Utilities ++ ++ @Description General usage API. This API is intended for usage by both the ++ internal modules and the user's application. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group endian_id Big/Little-Endian Conversion ++ ++ @Description Routines and macros for Big/Little-Endian conversion and ++ general byte swapping. ++ ++ All routines and macros are expecting unsigned values as ++ parameters, but will generate the correct result also for ++ signed values. Therefore, signed/unsigned casting is allowed. ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Collection Byte-Swap Macros ++ ++ Macros for swapping byte order. ++ ++ @Cautions The parameters of these macros are evaluated multiple times. ++ For calculated expressions or expressions that contain function ++ calls it is recommended to use the byte-swap routines. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description Swaps the byte order of a given 16-bit value. ++ ++ @Param[in] val - The 16-bit value to swap. ++ ++ @Return The byte-swapped value.. ++ ++ @Cautions The given value is evaluated multiple times by this macro. ++ For calculated expressions or expressions that contain function ++ calls it is recommended to use the SwapUint16() routine. ++ ++ @hideinitializer ++*//***************************************************************************/ ++#define SWAP_UINT16(val) \ ++ ((uint16_t)((((val) & 0x00FF) << 8) | (((val) & 0xFF00) >> 8))) ++ ++/**************************************************************************//** ++ @Description Swaps the byte order of a given 32-bit value. ++ ++ @Param[in] val - The 32-bit value to swap. ++ ++ @Return The byte-swapped value.. ++ ++ @Cautions The given value is evaluated multiple times by this macro. ++ For calculated expressions or expressions that contain function ++ calls it is recommended to use the SwapUint32() routine. ++ ++ @hideinitializer ++*//***************************************************************************/ ++#define SWAP_UINT32(val) \ ++ ((uint32_t)((((val) & 0x000000FF) << 24) | \ ++ (((val) & 0x0000FF00) << 8) | \ ++ (((val) & 0x00FF0000) >> 8) | \ ++ (((val) & 0xFF000000) >> 24))) ++ ++/**************************************************************************//** ++ @Description Swaps the byte order of a given 64-bit value. ++ ++ @Param[in] val - The 64-bit value to swap. ++ ++ @Return The byte-swapped value.. ++ ++ @Cautions The given value is evaluated multiple times by this macro. ++ For calculated expressions or expressions that contain function ++ calls it is recommended to use the SwapUint64() routine. ++ ++ @hideinitializer ++*//***************************************************************************/ ++#define SWAP_UINT64(val) \ ++ ((uint64_t)((((val) & 0x00000000000000FFULL) << 56) | \ ++ (((val) & 0x000000000000FF00ULL) << 40) | \ ++ (((val) & 0x0000000000FF0000ULL) << 24) | \ ++ (((val) & 0x00000000FF000000ULL) << 8) | \ ++ (((val) & 0x000000FF00000000ULL) >> 8) | \ ++ (((val) & 0x0000FF0000000000ULL) >> 24) | \ ++ (((val) & 0x00FF000000000000ULL) >> 40) | \ ++ (((val) & 0xFF00000000000000ULL) >> 56))) ++ ++/* @} */ ++ ++/**************************************************************************//** ++ @Collection Byte-Swap Routines ++ ++ Routines for swapping the byte order of a given parameter and ++ returning the swapped value. ++ ++ These inline routines are safer than the byte-swap macros, ++ because they evaluate the parameter expression only once. ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function SwapUint16 ++ ++ @Description Returns the byte-swapped value of a given 16-bit value. ++ ++ @Param[in] val - The 16-bit value. ++ ++ @Return The byte-swapped value of the parameter. ++*//***************************************************************************/ ++static __inline__ uint16_t SwapUint16(uint16_t val) ++{ ++ return (uint16_t)(((val & 0x00FF) << 8) | ++ ((val & 0xFF00) >> 8)); ++} ++ ++/**************************************************************************//** ++ @Function SwapUint32 ++ ++ @Description Returns the byte-swapped value of a given 32-bit value. ++ ++ @Param[in] val - The 32-bit value. ++ ++ @Return The byte-swapped value of the parameter. ++*//***************************************************************************/ ++static __inline__ uint32_t SwapUint32(uint32_t val) ++{ ++ return (uint32_t)(((val & 0x000000FF) << 24) | ++ ((val & 0x0000FF00) << 8) | ++ ((val & 0x00FF0000) >> 8) | ++ ((val & 0xFF000000) >> 24)); ++} ++ ++/**************************************************************************//** ++ @Function SwapUint64 ++ ++ @Description Returns the byte-swapped value of a given 64-bit value. ++ ++ @Param[in] val - The 64-bit value. ++ ++ @Return The byte-swapped value of the parameter. ++*//***************************************************************************/ ++static __inline__ uint64_t SwapUint64(uint64_t val) ++{ ++ return (uint64_t)(((val & 0x00000000000000FFULL) << 56) | ++ ((val & 0x000000000000FF00ULL) << 40) | ++ ((val & 0x0000000000FF0000ULL) << 24) | ++ ((val & 0x00000000FF000000ULL) << 8) | ++ ((val & 0x000000FF00000000ULL) >> 8) | ++ ((val & 0x0000FF0000000000ULL) >> 24) | ++ ((val & 0x00FF000000000000ULL) >> 40) | ++ ((val & 0xFF00000000000000ULL) >> 56)); ++} ++ ++/* @} */ ++ ++/**************************************************************************//** ++ @Collection In-place Byte-Swap-And-Set Routines ++ ++ Routines for swapping the byte order of a given variable and ++ setting the swapped value back to the same variable. ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function SwapUint16P ++ ++ @Description Swaps the byte order of a given 16-bit variable. ++ ++ @Param[in] p_Val - Pointer to the 16-bit variable. ++ ++ @Return None. ++*//***************************************************************************/ ++static __inline__ void SwapUint16P(uint16_t *p_Val) ++{ ++ *p_Val = SwapUint16(*p_Val); ++} ++ ++/**************************************************************************//** ++ @Function SwapUint32P ++ ++ @Description Swaps the byte order of a given 32-bit variable. ++ ++ @Param[in] p_Val - Pointer to the 32-bit variable. ++ ++ @Return None. ++*//***************************************************************************/ ++static __inline__ void SwapUint32P(uint32_t *p_Val) ++{ ++ *p_Val = SwapUint32(*p_Val); ++} ++ ++/**************************************************************************//** ++ @Function SwapUint64P ++ ++ @Description Swaps the byte order of a given 64-bit variable. ++ ++ @Param[in] p_Val - Pointer to the 64-bit variable. ++ ++ @Return None. ++*//***************************************************************************/ ++static __inline__ void SwapUint64P(uint64_t *p_Val) ++{ ++ *p_Val = SwapUint64(*p_Val); ++} ++ ++/* @} */ ++ ++ ++/**************************************************************************//** ++ @Collection Little-Endian Conversion Macros ++ ++ These macros convert given parameters to or from Little-Endian ++ format. Use these macros when you want to read or write a specific ++ Little-Endian value in memory, without a-priori knowing the CPU ++ byte order. ++ ++ These macros use the byte-swap routines. For conversion of ++ constants in initialization structures, you may use the CONST ++ versions of these macros (see below), which are using the ++ byte-swap macros instead. ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description Converts a given 16-bit value from CPU byte order to ++ Little-Endian byte order. ++ ++ @Param[in] val - The 16-bit value to convert. ++ ++ @Return The converted value. ++ ++ @hideinitializer ++*//***************************************************************************/ ++#define CPU_TO_LE16(val) SwapUint16(val) ++ ++/**************************************************************************//** ++ @Description Converts a given 32-bit value from CPU byte order to ++ Little-Endian byte order. ++ ++ @Param[in] val - The 32-bit value to convert. ++ ++ @Return The converted value. ++ ++ @hideinitializer ++*//***************************************************************************/ ++#define CPU_TO_LE32(val) SwapUint32(val) ++ ++/**************************************************************************//** ++ @Description Converts a given 64-bit value from CPU byte order to ++ Little-Endian byte order. ++ ++ @Param[in] val - The 64-bit value to convert. ++ ++ @Return The converted value. ++ ++ @hideinitializer ++*//***************************************************************************/ ++#define CPU_TO_LE64(val) SwapUint64(val) ++ ++ ++/**************************************************************************//** ++ @Description Converts a given 16-bit value from Little-Endian byte order to ++ CPU byte order. ++ ++ @Param[in] val - The 16-bit value to convert. ++ ++ @Return The converted value. ++ ++ @hideinitializer ++*//***************************************************************************/ ++#define LE16_TO_CPU(val) CPU_TO_LE16(val) ++ ++/**************************************************************************//** ++ @Description Converts a given 32-bit value from Little-Endian byte order to ++ CPU byte order. ++ ++ @Param[in] val - The 32-bit value to convert. ++ ++ @Return The converted value. ++ ++ @hideinitializer ++*//***************************************************************************/ ++#define LE32_TO_CPU(val) CPU_TO_LE32(val) ++ ++/**************************************************************************//** ++ @Description Converts a given 64-bit value from Little-Endian byte order to ++ CPU byte order. ++ ++ @Param[in] val - The 64-bit value to convert. ++ ++ @Return The converted value. ++ ++ @hideinitializer ++*//***************************************************************************/ ++#define LE64_TO_CPU(val) CPU_TO_LE64(val) ++ ++/* @} */ ++ ++/**************************************************************************//** ++ @Collection Little-Endian Constant Conversion Macros ++ ++ These macros convert given constants to or from Little-Endian ++ format. Use these macros when you want to read or write a specific ++ Little-Endian constant in memory, without a-priori knowing the ++ CPU byte order. ++ ++ These macros use the byte-swap macros, therefore can be used for ++ conversion of constants in initialization structures. ++ ++ @Cautions The parameters of these macros are evaluated multiple times. ++ For non-constant expressions, use the non-CONST macro versions. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description Converts a given 16-bit constant from CPU byte order to ++ Little-Endian byte order. ++ ++ @Param[in] val - The 16-bit value to convert. ++ ++ @Return The converted value. ++ ++ @hideinitializer ++*//***************************************************************************/ ++#define CONST_CPU_TO_LE16(val) SWAP_UINT16(val) ++ ++/**************************************************************************//** ++ @Description Converts a given 32-bit constant from CPU byte order to ++ Little-Endian byte order. ++ ++ @Param[in] val - The 32-bit value to convert. ++ ++ @Return The converted value. ++ ++ @hideinitializer ++*//***************************************************************************/ ++#define CONST_CPU_TO_LE32(val) SWAP_UINT32(val) ++ ++/**************************************************************************//** ++ @Description Converts a given 64-bit constant from CPU byte order to ++ Little-Endian byte order. ++ ++ @Param[in] val - The 64-bit value to convert. ++ ++ @Return The converted value. ++ ++ @hideinitializer ++*//***************************************************************************/ ++#define CONST_CPU_TO_LE64(val) SWAP_UINT64(val) ++ ++ ++/**************************************************************************//** ++ @Description Converts a given 16-bit constant from Little-Endian byte order ++ to CPU byte order. ++ ++ @Param[in] val - The 16-bit value to convert. ++ ++ @Return The converted value. ++ ++ @hideinitializer ++*//***************************************************************************/ ++#define CONST_LE16_TO_CPU(val) CONST_CPU_TO_LE16(val) ++ ++/**************************************************************************//** ++ @Description Converts a given 32-bit constant from Little-Endian byte order ++ to CPU byte order. ++ ++ @Param[in] val - The 32-bit value to convert. ++ ++ @Return The converted value. ++ ++ @hideinitializer ++*//***************************************************************************/ ++#define CONST_LE32_TO_CPU(val) CONST_CPU_TO_LE32(val) ++ ++/**************************************************************************//** ++ @Description Converts a given 64-bit constant from Little-Endian byte order ++ to CPU byte order. ++ ++ @Param[in] val - The 64-bit value to convert. ++ ++ @Return The converted value. ++ ++ @hideinitializer ++*//***************************************************************************/ ++#define CONST_LE64_TO_CPU(val) CONST_CPU_TO_LE64(val) ++ ++/* @} */ ++ ++ ++/** @} */ /* end of endian_id group */ ++/** @} */ /* end of gen_id group */ ++ ++ ++#endif /* __ENDIAN_EXT_H */ ++ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/enet_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/enet_ext.h +new file mode 100644 +index 00000000..ef3bee55 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/enet_ext.h +@@ -0,0 +1,205 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File enet_ext.h ++ ++ @Description Ethernet generic definitions and enums. ++*//***************************************************************************/ ++ ++#ifndef __ENET_EXT_H ++#define __ENET_EXT_H ++ ++#include "fsl_enet.h" ++ ++#define ENET_NUM_OCTETS_PER_ADDRESS 6 /**< Number of octets (8-bit bytes) in an ethernet address */ ++#define ENET_GROUP_ADDR 0x01 /**< Group address mask for ethernet addresses */ ++ ++ ++/**************************************************************************//** ++ @Description Ethernet Address ++*//***************************************************************************/ ++typedef uint8_t t_EnetAddr[ENET_NUM_OCTETS_PER_ADDRESS]; ++ ++/**************************************************************************//** ++ @Description Ethernet Address Type. ++*//***************************************************************************/ ++typedef enum e_EnetAddrType ++{ ++ e_ENET_ADDR_TYPE_INDIVIDUAL, /**< Individual (unicast) address */ ++ e_ENET_ADDR_TYPE_GROUP, /**< Group (multicast) address */ ++ e_ENET_ADDR_TYPE_BROADCAST /**< Broadcast address */ ++} e_EnetAddrType; ++ ++/**************************************************************************//** ++ @Description Ethernet MAC-PHY Interface ++*//***************************************************************************/ ++typedef enum e_EnetInterface ++{ ++ e_ENET_IF_MII = E_ENET_IF_MII, /**< MII interface */ ++ e_ENET_IF_RMII = E_ENET_IF_RMII, /**< RMII interface */ ++ e_ENET_IF_SMII = E_ENET_IF_SMII, /**< SMII interface */ ++ e_ENET_IF_GMII = E_ENET_IF_GMII, /**< GMII interface */ ++ e_ENET_IF_RGMII = E_ENET_IF_RGMII, /**< RGMII interface */ ++ e_ENET_IF_TBI = E_ENET_IF_TBI, /**< TBI interface */ ++ e_ENET_IF_RTBI = E_ENET_IF_RTBI, /**< RTBI interface */ ++ e_ENET_IF_SGMII = E_ENET_IF_SGMII, /**< SGMII interface */ ++ e_ENET_IF_XGMII = E_ENET_IF_XGMII, /**< XGMII interface */ ++ e_ENET_IF_QSGMII= E_ENET_IF_QSGMII, /**< QSGMII interface */ ++ e_ENET_IF_XFI = E_ENET_IF_XFI /**< XFI interface */ ++} e_EnetInterface; ++ ++#define ENET_IF_SGMII_BASEX 0x80000000 /**< SGMII/QSGII interface with 1000BaseX ++ auto-negotiation between MAC and phy ++ or backplane; ++ Note: 1000BaseX auto-negotiation relates ++ only to interface between MAC and phy/backplane, ++ SGMII phy can still synchronize with far-end phy ++ at 10Mbps, 100Mbps or 1000Mbps */ ++ ++/**************************************************************************//** ++ @Description Ethernet Duplex Mode ++*//***************************************************************************/ ++typedef enum e_EnetDuplexMode ++{ ++ e_ENET_HALF_DUPLEX, /**< Half-Duplex mode */ ++ e_ENET_FULL_DUPLEX /**< Full-Duplex mode */ ++} e_EnetDuplexMode; ++ ++/**************************************************************************//** ++ @Description Ethernet Speed (nominal data rate) ++*//***************************************************************************/ ++typedef enum e_EnetSpeed ++{ ++ e_ENET_SPEED_10 = E_ENET_SPEED_10, /**< 10 Mbps */ ++ e_ENET_SPEED_100 = E_ENET_SPEED_100, /**< 100 Mbps */ ++ e_ENET_SPEED_1000 = E_ENET_SPEED_1000, /**< 1000 Mbps = 1 Gbps */ ++ e_ENET_SPEED_2500 = E_ENET_SPEED_2500, /**< 2500 Mbps = 2.5 Gbps */ ++ e_ENET_SPEED_10000 = E_ENET_SPEED_10000 /**< 10000 Mbps = 10 Gbps */ ++} e_EnetSpeed; ++ ++/**************************************************************************//** ++ @Description Ethernet mode (combination of MAC-PHY interface and speed) ++*//***************************************************************************/ ++typedef enum e_EnetMode ++{ ++ e_ENET_MODE_INVALID = 0, /**< Invalid Ethernet mode */ ++ e_ENET_MODE_MII_10 = (e_ENET_IF_MII | e_ENET_SPEED_10), /**< 10 Mbps MII */ ++ e_ENET_MODE_MII_100 = (e_ENET_IF_MII | e_ENET_SPEED_100), /**< 100 Mbps MII */ ++ e_ENET_MODE_RMII_10 = (e_ENET_IF_RMII | e_ENET_SPEED_10), /**< 10 Mbps RMII */ ++ e_ENET_MODE_RMII_100 = (e_ENET_IF_RMII | e_ENET_SPEED_100), /**< 100 Mbps RMII */ ++ e_ENET_MODE_SMII_10 = (e_ENET_IF_SMII | e_ENET_SPEED_10), /**< 10 Mbps SMII */ ++ e_ENET_MODE_SMII_100 = (e_ENET_IF_SMII | e_ENET_SPEED_100), /**< 100 Mbps SMII */ ++ e_ENET_MODE_GMII_1000 = (e_ENET_IF_GMII | e_ENET_SPEED_1000), /**< 1000 Mbps GMII */ ++ e_ENET_MODE_RGMII_10 = (e_ENET_IF_RGMII | e_ENET_SPEED_10), /**< 10 Mbps RGMII */ ++ e_ENET_MODE_RGMII_100 = (e_ENET_IF_RGMII | e_ENET_SPEED_100), /**< 100 Mbps RGMII */ ++ e_ENET_MODE_RGMII_1000 = (e_ENET_IF_RGMII | e_ENET_SPEED_1000), /**< 1000 Mbps RGMII */ ++ e_ENET_MODE_TBI_1000 = (e_ENET_IF_TBI | e_ENET_SPEED_1000), /**< 1000 Mbps TBI */ ++ e_ENET_MODE_RTBI_1000 = (e_ENET_IF_RTBI | e_ENET_SPEED_1000), /**< 1000 Mbps RTBI */ ++ e_ENET_MODE_SGMII_10 = (e_ENET_IF_SGMII | e_ENET_SPEED_10), ++ /**< 10 Mbps SGMII with auto-negotiation between MAC and ++ SGMII phy according to Cisco SGMII specification */ ++ e_ENET_MODE_SGMII_100 = (e_ENET_IF_SGMII | e_ENET_SPEED_100), ++ /**< 100 Mbps SGMII with auto-negotiation between MAC and ++ SGMII phy according to Cisco SGMII specification */ ++ e_ENET_MODE_SGMII_1000 = (e_ENET_IF_SGMII | e_ENET_SPEED_1000), ++ /**< 1000 Mbps SGMII with auto-negotiation between MAC and ++ SGMII phy according to Cisco SGMII specification */ ++ e_ENET_MODE_SGMII_2500 = (e_ENET_IF_SGMII | e_ENET_SPEED_2500), ++ e_ENET_MODE_SGMII_BASEX_10 = (ENET_IF_SGMII_BASEX | e_ENET_IF_SGMII | e_ENET_SPEED_10), ++ /**< 10 Mbps SGMII with 1000BaseX auto-negotiation between ++ MAC and SGMII phy or backplane */ ++ e_ENET_MODE_SGMII_BASEX_100 = (ENET_IF_SGMII_BASEX | e_ENET_IF_SGMII | e_ENET_SPEED_100), ++ /**< 100 Mbps SGMII with 1000BaseX auto-negotiation between ++ MAC and SGMII phy or backplane */ ++ e_ENET_MODE_SGMII_BASEX_1000 = (ENET_IF_SGMII_BASEX | e_ENET_IF_SGMII | e_ENET_SPEED_1000), ++ /**< 1000 Mbps SGMII with 1000BaseX auto-negotiation between ++ MAC and SGMII phy or backplane */ ++ e_ENET_MODE_QSGMII_1000 = (e_ENET_IF_QSGMII| e_ENET_SPEED_1000), ++ /**< 1000 Mbps QSGMII with auto-negotiation between MAC and ++ QSGMII phy according to Cisco QSGMII specification */ ++ e_ENET_MODE_QSGMII_BASEX_1000 = (ENET_IF_SGMII_BASEX | e_ENET_IF_QSGMII| e_ENET_SPEED_1000), ++ /**< 1000 Mbps QSGMII with 1000BaseX auto-negotiation between ++ MAC and QSGMII phy or backplane */ ++ e_ENET_MODE_XGMII_10000 = (e_ENET_IF_XGMII | e_ENET_SPEED_10000), /**< 10000 Mbps XGMII */ ++ e_ENET_MODE_XFI_10000 = (e_ENET_IF_XFI | e_ENET_SPEED_10000) /**< 10000 Mbps XFI */ ++} e_EnetMode; ++ ++ ++#define IS_ENET_MODE_VALID(mode) \ ++ (((mode) == e_ENET_MODE_MII_10 ) || \ ++ ((mode) == e_ENET_MODE_MII_100 ) || \ ++ ((mode) == e_ENET_MODE_RMII_10 ) || \ ++ ((mode) == e_ENET_MODE_RMII_100 ) || \ ++ ((mode) == e_ENET_MODE_SMII_10 ) || \ ++ ((mode) == e_ENET_MODE_SMII_100 ) || \ ++ ((mode) == e_ENET_MODE_GMII_1000 ) || \ ++ ((mode) == e_ENET_MODE_RGMII_10 ) || \ ++ ((mode) == e_ENET_MODE_RGMII_100 ) || \ ++ ((mode) == e_ENET_MODE_RGMII_1000 ) || \ ++ ((mode) == e_ENET_MODE_TBI_1000 ) || \ ++ ((mode) == e_ENET_MODE_RTBI_1000 ) || \ ++ ((mode) == e_ENET_MODE_SGMII_10 ) || \ ++ ((mode) == e_ENET_MODE_SGMII_100 ) || \ ++ ((mode) == e_ENET_MODE_SGMII_1000 ) || \ ++ ((mode) == e_ENET_MODE_SGMII_BASEX_10 ) || \ ++ ((mode) == e_ENET_MODE_SGMII_BASEX_100 ) || \ ++ ((mode) == e_ENET_MODE_SGMII_BASEX_1000 ) || \ ++ ((mode) == e_ENET_MODE_XGMII_10000) || \ ++ ((mode) == e_ENET_MODE_QSGMII_1000) || \ ++ ((mode) == e_ENET_MODE_QSGMII_BASEX_1000) || \ ++ ((mode) == e_ENET_MODE_XFI_10000)) ++ ++ ++#define MAKE_ENET_MODE(_interface, _speed) (e_EnetMode)((_interface) | (_speed)) ++ ++#define ENET_INTERFACE_FROM_MODE(mode) (e_EnetInterface)((mode) & 0x0FFF0000) ++#define ENET_SPEED_FROM_MODE(mode) (e_EnetSpeed)((mode) & 0x0000FFFF) ++ ++#define ENET_ADDR_TO_UINT64(_enetAddr) \ ++ (uint64_t)(((uint64_t)(_enetAddr)[0] << 40) | \ ++ ((uint64_t)(_enetAddr)[1] << 32) | \ ++ ((uint64_t)(_enetAddr)[2] << 24) | \ ++ ((uint64_t)(_enetAddr)[3] << 16) | \ ++ ((uint64_t)(_enetAddr)[4] << 8) | \ ++ ((uint64_t)(_enetAddr)[5])) ++ ++#define MAKE_ENET_ADDR_FROM_UINT64(_addr64, _enetAddr) \ ++ do { \ ++ int i; \ ++ for (i=0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++) \ ++ (_enetAddr)[i] = (uint8_t)((_addr64) >> ((5-i)*8)); \ ++ } while (0) ++ ++ ++#endif /* __ENET_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/error_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/error_ext.h +new file mode 100644 +index 00000000..2a5ad67b +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/error_ext.h +@@ -0,0 +1,529 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File error_ext.h ++ ++ @Description Error definitions. ++*//***************************************************************************/ ++ ++#ifndef __ERROR_EXT_H ++#define __ERROR_EXT_H ++ ++#if !defined(NCSW_LINUX) ++#include ++#endif ++ ++#include "std_ext.h" ++#include "xx_ext.h" ++#include "core_ext.h" ++ ++ ++ ++ ++/**************************************************************************//** ++ @Group gen_id General Drivers Utilities ++ ++ @Description External routines. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group gen_error_id Errors, Events and Debug ++ ++ @Description External routines. ++ ++ @{ ++*//***************************************************************************/ ++ ++/****************************************************************************** ++The scheme below provides the bits description for error codes: ++ ++ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ++| Reserved (should be zero) | Module ID | ++ ++ 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ++| Error Type | ++******************************************************************************/ ++ ++#define ERROR_CODE(_err) ((((uint32_t)_err) & 0x0000FFFF) | __ERR_MODULE__) ++ ++#define GET_ERROR_TYPE(_errcode) ((_errcode) & 0x0000FFFF) ++ /**< Extract module code from error code (#t_Error) */ ++ ++#define GET_ERROR_MODULE(_errcode) ((_errcode) & 0x00FF0000) ++ /**< Extract error type (#e_ErrorType) from ++ error code (#t_Error) */ ++ ++ ++/**************************************************************************//** ++ @Description Error Type Enumeration ++*//***************************************************************************/ ++typedef enum e_ErrorType /* Comments / Associated Message Strings */ ++{ /* ------------------------------------------------------------ */ ++ E_OK = 0 /* Never use "RETURN_ERROR" with E_OK; Use "return E_OK;" */ ++ ,E_WRITE_FAILED = EIO /**< Write access failed on memory/device. */ ++ /* String: none, or device name. */ ++ ,E_NO_DEVICE = ENXIO /**< The associated device is not initialized. */ ++ /* String: none. */ ++ ,E_NOT_AVAILABLE = EAGAIN ++ /**< Resource is unavailable. */ ++ /* String: none, unless the operation is not the main goal ++ of the function (in this case add resource description). */ ++ ,E_NO_MEMORY = ENOMEM /**< External memory allocation failed. */ ++ /* String: description of item for which allocation failed. */ ++ ,E_INVALID_ADDRESS = EFAULT ++ /**< Invalid address. */ ++ /* String: description of the specific violation. */ ++ ,E_BUSY = EBUSY /**< Resource or module is busy. */ ++ /* String: none, unless the operation is not the main goal ++ of the function (in this case add resource description). */ ++ ,E_ALREADY_EXISTS = EEXIST ++ /**< Requested resource or item already exists. */ ++ /* Use when resource duplication or sharing are not allowed. ++ String: none, unless the operation is not the main goal ++ of the function (in this case add item description). */ ++ ,E_INVALID_OPERATION = ENODEV ++ /**< The operation/command is invalid (unrecognized). */ ++ /* String: none. */ ++ ,E_INVALID_VALUE = EDOM /**< Invalid value. */ ++ /* Use for non-enumeration parameters, and ++ only when other error types are not suitable. ++ String: parameter description + "(should be )", ++ e.g: "Maximum Rx buffer length (should be divisible by 8)", ++ "Channel number (should be even)". */ ++ ,E_NOT_IN_RANGE = ERANGE/**< Parameter value is out of range. */ ++ /* Don't use this error for enumeration parameters. ++ String: parameter description + "(should be %d-%d)", ++ e.g: "Number of pad characters (should be 0-15)". */ ++ ,E_NOT_SUPPORTED = ENOSYS ++ /**< The function is not supported or not implemented. */ ++ /* String: none. */ ++ ,E_INVALID_STATE /**< The operation is not allowed in current module state. */ ++ /* String: none. */ ++ ,E_INVALID_HANDLE /**< Invalid handle of module or object. */ ++ /* String: none, unless the function takes in more than one ++ handle (in this case add the handle description) */ ++ ,E_INVALID_ID /**< Invalid module ID (usually enumeration or index). */ ++ /* String: none, unless the function takes in more than one ++ ID (in this case add the ID description) */ ++ ,E_NULL_POINTER /**< Unexpected NULL pointer. */ ++ /* String: pointer description. */ ++ ,E_INVALID_SELECTION /**< Invalid selection or mode. */ ++ /* Use for enumeration values, only when other error types ++ are not suitable. ++ String: parameter description. */ ++ ,E_INVALID_COMM_MODE /**< Invalid communication mode. */ ++ /* String: none, unless the function takes in more than one ++ communication mode indications (in this case add ++ parameter description). */ ++ ,E_INVALID_MEMORY_TYPE /**< Invalid memory type. */ ++ /* String: none, unless the function takes in more than one ++ memory types (in this case add memory description, ++ e.g: "Data memory", "Buffer descriptors memory"). */ ++ ,E_INVALID_CLOCK /**< Invalid clock. */ ++ /* String: none, unless the function takes in more than one ++ clocks (in this case add clock description, ++ e.g: "Rx clock", "Tx clock"). */ ++ ,E_CONFLICT /**< Some setting conflicts with another setting. */ ++ /* String: description of the conflicting settings. */ ++ ,E_NOT_ALIGNED /**< Non-aligned address. */ ++ /* String: parameter description + "(should be %d-bytes aligned)", ++ e.g: "Rx data buffer (should be 32-bytes aligned)". */ ++ ,E_NOT_FOUND /**< Requested resource or item was not found. */ ++ /* Use only when the resource/item is uniquely identified. ++ String: none, unless the operation is not the main goal ++ of the function (in this case add item description). */ ++ ,E_FULL /**< Resource is full. */ ++ /* String: none, unless the operation is not the main goal ++ of the function (in this case add resource description). */ ++ ,E_EMPTY /**< Resource is empty. */ ++ /* String: none, unless the operation is not the main goal ++ of the function (in this case add resource description). */ ++ ,E_ALREADY_FREE /**< Specified resource or item is already free or deleted. */ ++ /* String: none, unless the operation is not the main goal ++ of the function (in this case add item description). */ ++ ,E_READ_FAILED /**< Read access failed on memory/device. */ ++ /* String: none, or device name. */ ++ ,E_INVALID_FRAME /**< Invalid frame object (NULL handle or missing buffers). */ ++ /* String: none. */ ++ ,E_SEND_FAILED /**< Send operation failed on device. */ ++ /* String: none, or device name. */ ++ ,E_RECEIVE_FAILED /**< Receive operation failed on device. */ ++ /* String: none, or device name. */ ++ ,E_TIMEOUT/* = ETIMEDOUT*/ /**< The operation timed out. */ ++ /* String: none. */ ++ ++ ,E_DUMMY_LAST /* NEVER USED */ ++ ++} e_ErrorType; ++ ++/**************************************************************************//** ++ @Description Event Type Enumeration ++*//***************************************************************************/ ++typedef enum e_Event /* Comments / Associated Flags and Message Strings */ ++{ /* ------------------------------------------------------------ */ ++ EV_NO_EVENT = 0 /**< No event; Never used. */ ++ ++ ,EV_RX_DISCARD /**< Received packet discarded (by the driver, and only for ++ complete packets); ++ Flags: error flags in case of error, zero otherwise. */ ++ /* String: reason for discard, e.g: "Error in frame", ++ "Disordered frame", "Incomplete frame", "No frame object". */ ++ ,EV_RX_ERROR /**< Receive error (by hardware/firmware); ++ Flags: usually status flags from the buffer descriptor. */ ++ /* String: none. */ ++ ,EV_TX_ERROR /**< Transmit error (by hardware/firmware); ++ Flags: usually status flags from the buffer descriptor. */ ++ /* String: none. */ ++ ,EV_NO_BUFFERS /**< System ran out of buffer objects; ++ Flags: zero. */ ++ /* String: none. */ ++ ,EV_NO_MB_FRAMES /**< System ran out of multi-buffer frame objects; ++ Flags: zero. */ ++ /* String: none. */ ++ ,EV_NO_SB_FRAMES /**< System ran out of single-buffer frame objects; ++ Flags: zero. */ ++ /* String: none. */ ++ ,EV_TX_QUEUE_FULL /**< Transmit queue is full; ++ Flags: zero. */ ++ /* String: none. */ ++ ,EV_RX_QUEUE_FULL /**< Receive queue is full; ++ Flags: zero. */ ++ /* String: none. */ ++ ,EV_INTR_QUEUE_FULL /**< Interrupt queue overflow; ++ Flags: zero. */ ++ /* String: none. */ ++ ,EV_NO_DATA_BUFFER /**< Data buffer allocation (from higher layer) failed; ++ Flags: zero. */ ++ /* String: none. */ ++ ,EV_OBJ_POOL_EMPTY /**< Objects pool is empty; ++ Flags: zero. */ ++ /* String: object description (name). */ ++ ,EV_BUS_ERROR /**< Illegal access on bus; ++ Flags: the address (if available) or bus identifier */ ++ /* String: bus/address/module description. */ ++ ,EV_PTP_TXTS_QUEUE_FULL /**< PTP Tx timestamps queue is full; ++ Flags: zero. */ ++ /* String: none. */ ++ ,EV_PTP_RXTS_QUEUE_FULL /**< PTP Rx timestamps queue is full; ++ Flags: zero. */ ++ /* String: none. */ ++ ,EV_DUMMY_LAST ++ ++} e_Event; ++ ++ ++/**************************************************************************//** ++ @Collection Debug Levels for Errors and Events ++ ++ The level description refers to errors only. ++ For events, classification is done by the user. ++ ++ The TRACE, INFO and WARNING levels are allowed only when using ++ the DBG macro, and are not allowed when using the error macros ++ (RETURN_ERROR or REPORT_ERROR). ++ @{ ++*//***************************************************************************/ ++#define REPORT_LEVEL_CRITICAL 1 /**< Crasher: Incorrect flow, NULL pointers/handles. */ ++#define REPORT_LEVEL_MAJOR 2 /**< Cannot proceed: Invalid operation, parameters or ++ configuration. */ ++#define REPORT_LEVEL_MINOR 3 /**< Recoverable problem: a repeating call with the same ++ parameters may be successful. */ ++#define REPORT_LEVEL_WARNING 4 /**< Something is not exactly right, yet it is not an error. */ ++#define REPORT_LEVEL_INFO 5 /**< Messages which may be of interest to user/programmer. */ ++#define REPORT_LEVEL_TRACE 6 /**< Program flow messages. */ ++ ++#define EVENT_DISABLED 0xFF /**< Disabled event (not reported at all) */ ++ ++/* @} */ ++ ++ ++ ++#define NO_MSG ("") ++ ++#ifndef DEBUG_GLOBAL_LEVEL ++#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_WARNING ++#endif /* DEBUG_GLOBAL_LEVEL */ ++ ++#ifndef ERROR_GLOBAL_LEVEL ++#define ERROR_GLOBAL_LEVEL DEBUG_GLOBAL_LEVEL ++#endif /* ERROR_GLOBAL_LEVEL */ ++ ++#ifndef EVENT_GLOBAL_LEVEL ++#define EVENT_GLOBAL_LEVEL REPORT_LEVEL_MINOR ++#endif /* EVENT_GLOBAL_LEVEL */ ++ ++#ifdef EVENT_LOCAL_LEVEL ++#define EVENT_DYNAMIC_LEVEL EVENT_LOCAL_LEVEL ++#else ++#define EVENT_DYNAMIC_LEVEL EVENT_GLOBAL_LEVEL ++#endif /* EVENT_LOCAL_LEVEL */ ++ ++ ++#ifndef DEBUG_DYNAMIC_LEVEL ++#define DEBUG_USING_STATIC_LEVEL ++ ++#ifdef DEBUG_STATIC_LEVEL ++#define DEBUG_DYNAMIC_LEVEL DEBUG_STATIC_LEVEL ++#else ++#define DEBUG_DYNAMIC_LEVEL DEBUG_GLOBAL_LEVEL ++#endif /* DEBUG_STATIC_LEVEL */ ++ ++#else /* DEBUG_DYNAMIC_LEVEL */ ++#ifdef DEBUG_STATIC_LEVEL ++#error "Please use either DEBUG_STATIC_LEVEL or DEBUG_DYNAMIC_LEVEL (not both)" ++#else ++int DEBUG_DYNAMIC_LEVEL = DEBUG_GLOBAL_LEVEL; ++#endif /* DEBUG_STATIC_LEVEL */ ++#endif /* !DEBUG_DYNAMIC_LEVEL */ ++ ++ ++#ifndef ERROR_DYNAMIC_LEVEL ++ ++#ifdef ERROR_STATIC_LEVEL ++#define ERROR_DYNAMIC_LEVEL ERROR_STATIC_LEVEL ++#else ++#define ERROR_DYNAMIC_LEVEL ERROR_GLOBAL_LEVEL ++#endif /* ERROR_STATIC_LEVEL */ ++ ++#else /* ERROR_DYNAMIC_LEVEL */ ++#ifdef ERROR_STATIC_LEVEL ++#error "Please use either ERROR_STATIC_LEVEL or ERROR_DYNAMIC_LEVEL (not both)" ++#else ++int ERROR_DYNAMIC_LEVEL = ERROR_GLOBAL_LEVEL; ++#endif /* ERROR_STATIC_LEVEL */ ++#endif /* !ERROR_DYNAMIC_LEVEL */ ++ ++#define PRINT_FORMAT "[CPU%02d, %s:%d %s]" ++#define PRINT_FMT_PARAMS raw_smp_processor_id(), __FILE__, __LINE__, __FUNCTION__ ++ ++#if (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0)) ++/* No debug/error/event messages at all */ ++#define DBG(_level, _vmsg) ++ ++#define REPORT_ERROR(_level, _err, _vmsg) ++ ++#define RETURN_ERROR(_level, _err, _vmsg) \ ++ return ERROR_CODE(_err) ++ ++#if (REPORT_EVENTS > 0) ++ ++#define REPORT_EVENT(_ev, _appId, _flg, _vmsg) \ ++ do { \ ++ if (_ev##_LEVEL <= EVENT_DYNAMIC_LEVEL) { \ ++ XX_EventById((uint32_t)(_ev), (t_Handle)(_appId), (uint16_t)(_flg), NO_MSG); \ ++ } \ ++ } while (0) ++ ++#else ++ ++#define REPORT_EVENT(_ev, _appId, _flg, _vmsg) ++ ++#endif /* (REPORT_EVENTS > 0) */ ++ ++ ++#else /* DEBUG_ERRORS > 0 */ ++ ++extern const char *dbgLevelStrings[]; ++extern const char *moduleStrings[]; ++#if (REPORT_EVENTS > 0) ++extern const char *eventStrings[]; ++#endif /* (REPORT_EVENTS > 0) */ ++ ++char * ErrTypeStrings (e_ErrorType err); ++ ++ ++#if ((defined(DEBUG_USING_STATIC_LEVEL)) && (DEBUG_DYNAMIC_LEVEL < REPORT_LEVEL_WARNING)) ++/* No need for DBG macro - debug level is higher anyway */ ++#define DBG(_level, _vmsg) ++#else ++#define DBG(_level, _vmsg) \ ++ do { \ ++ if (REPORT_LEVEL_##_level <= DEBUG_DYNAMIC_LEVEL) { \ ++ XX_Print("> %s (%s) " PRINT_FORMAT ": ", \ ++ dbgLevelStrings[REPORT_LEVEL_##_level - 1], \ ++ moduleStrings[__ERR_MODULE__ >> 16], \ ++ PRINT_FMT_PARAMS); \ ++ XX_Print _vmsg; \ ++ XX_Print("\r\n"); \ ++ } \ ++ } while (0) ++#endif /* (defined(DEBUG_USING_STATIC_LEVEL) && (DEBUG_DYNAMIC_LEVEL < WARNING)) */ ++ ++ ++#define REPORT_ERROR(_level, _err, _vmsg) \ ++ do { \ ++ if (REPORT_LEVEL_##_level <= ERROR_DYNAMIC_LEVEL) { \ ++ XX_Print("! %s %s Error " PRINT_FORMAT ": %s; ", \ ++ dbgLevelStrings[REPORT_LEVEL_##_level - 1], \ ++ moduleStrings[__ERR_MODULE__ >> 16], \ ++ PRINT_FMT_PARAMS, \ ++ ErrTypeStrings((e_ErrorType)GET_ERROR_TYPE(_err))); \ ++ XX_Print _vmsg; \ ++ XX_Print("\r\n"); \ ++ } \ ++ } while (0) ++ ++ ++#define RETURN_ERROR(_level, _err, _vmsg) \ ++ do { \ ++ REPORT_ERROR(_level, (_err), _vmsg); \ ++ return ERROR_CODE(_err); \ ++ } while (0) ++ ++ ++#if (REPORT_EVENTS > 0) ++ ++#define REPORT_EVENT(_ev, _appId, _flg, _vmsg) \ ++ do { \ ++ if (_ev##_LEVEL <= EVENT_DYNAMIC_LEVEL) { \ ++ XX_Print("~ %s %s Event " PRINT_FORMAT ": %s (flags: 0x%04x); ", \ ++ dbgLevelStrings[_ev##_LEVEL - 1], \ ++ moduleStrings[__ERR_MODULE__ >> 16], \ ++ PRINT_FMT_PARAMS, \ ++ eventStrings[((_ev) - EV_NO_EVENT - 1)], \ ++ (uint16_t)(_flg)); \ ++ XX_Print _vmsg; \ ++ XX_Print("\r\n"); \ ++ XX_EventById((uint32_t)(_ev), (t_Handle)(_appId), (uint16_t)(_flg), NO_MSG); \ ++ } \ ++ } while (0) ++ ++#else /* not REPORT_EVENTS */ ++ ++#define REPORT_EVENT(_ev, _appId, _flg, _vmsg) ++ ++#endif /* (REPORT_EVENTS > 0) */ ++ ++#endif /* (DEBUG_ERRORS > 0) */ ++ ++ ++/**************************************************************************//** ++ @Function ASSERT_COND ++ ++ @Description Assertion macro. ++ ++ @Param[in] _cond - The condition being checked, in positive form; ++ Failure of the condition triggers the assert. ++*//***************************************************************************/ ++#ifdef DISABLE_ASSERTIONS ++#define ASSERT_COND(_cond) ++#else ++#define ASSERT_COND(_cond) \ ++ do { \ ++ if (!(_cond)) { \ ++ XX_Print("*** ASSERT_COND failed " PRINT_FORMAT "\r\n", \ ++ PRINT_FMT_PARAMS); \ ++ XX_Exit(1); \ ++ } \ ++ } while (0) ++#endif /* DISABLE_ASSERTIONS */ ++ ++ ++#ifdef DISABLE_INIT_PARAMETERS_CHECK ++ ++#define CHECK_INIT_PARAMETERS(handle, f_check) ++#define CHECK_INIT_PARAMETERS_RETURN_VALUE(handle, f_check, retval) ++ ++#else ++ ++#define CHECK_INIT_PARAMETERS(handle, f_check) \ ++ do { \ ++ t_Error err = f_check(handle); \ ++ if (err != E_OK) { \ ++ RETURN_ERROR(MAJOR, err, NO_MSG); \ ++ } \ ++ } while (0) ++ ++#define CHECK_INIT_PARAMETERS_RETURN_VALUE(handle, f_check, retval) \ ++ do { \ ++ t_Error err = f_check(handle); \ ++ if (err != E_OK) { \ ++ REPORT_ERROR(MAJOR, err, NO_MSG); \ ++ return (retval); \ ++ } \ ++ } while (0) ++ ++#endif /* DISABLE_INIT_PARAMETERS_CHECK */ ++ ++#ifdef DISABLE_SANITY_CHECKS ++ ++#define SANITY_CHECK_RETURN_ERROR(_cond, _err) ++#define SANITY_CHECK_RETURN_VALUE(_cond, _err, retval) ++#define SANITY_CHECK_RETURN(_cond, _err) ++#define SANITY_CHECK_EXIT(_cond, _err) ++ ++#else /* DISABLE_SANITY_CHECKS */ ++ ++#define SANITY_CHECK_RETURN_ERROR(_cond, _err) \ ++ do { \ ++ if (!(_cond)) { \ ++ RETURN_ERROR(CRITICAL, (_err), NO_MSG); \ ++ } \ ++ } while (0) ++ ++#define SANITY_CHECK_RETURN_VALUE(_cond, _err, retval) \ ++ do { \ ++ if (!(_cond)) { \ ++ REPORT_ERROR(CRITICAL, (_err), NO_MSG); \ ++ return (retval); \ ++ } \ ++ } while (0) ++ ++#define SANITY_CHECK_RETURN(_cond, _err) \ ++ do { \ ++ if (!(_cond)) { \ ++ REPORT_ERROR(CRITICAL, (_err), NO_MSG); \ ++ return; \ ++ } \ ++ } while (0) ++ ++#define SANITY_CHECK_EXIT(_cond, _err) \ ++ do { \ ++ if (!(_cond)) { \ ++ REPORT_ERROR(CRITICAL, (_err), NO_MSG); \ ++ XX_Exit(1); \ ++ } \ ++ } while (0) ++ ++#endif /* DISABLE_SANITY_CHECKS */ ++ ++/** @} */ /* end of Debug/error Utils group */ ++ ++/** @} */ /* end of General Utils group */ ++ ++#endif /* __ERROR_EXT_H */ ++ ++ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/etc/list_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/list_ext.h +new file mode 100644 +index 00000000..ee6b9f29 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/list_ext.h +@@ -0,0 +1,358 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ ++ @File list_ext.h ++ ++ @Description External prototypes for list.c ++*//***************************************************************************/ ++ ++#ifndef __LIST_EXT_H ++#define __LIST_EXT_H ++ ++ ++#include "std_ext.h" ++ ++ ++/**************************************************************************//** ++ @Group etc_id Utility Library Application Programming Interface ++ ++ @Description External routines. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group list_id List ++ ++ @Description List module functions,definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description List structure. ++*//***************************************************************************/ ++typedef struct List ++{ ++ struct List *p_Next; /**< A pointer to the next list object */ ++ struct List *p_Prev; /**< A pointer to the previous list object */ ++} t_List; ++ ++ ++/**************************************************************************//** ++ @Function LIST_FIRST/LIST_LAST/LIST_NEXT/LIST_PREV ++ ++ @Description Macro to get first/last/next/previous entry in a list. ++ ++ @Param[in] p_List - A pointer to a list. ++*//***************************************************************************/ ++#define LIST_FIRST(p_List) (p_List)->p_Next ++#define LIST_LAST(p_List) (p_List)->p_Prev ++#define LIST_NEXT LIST_FIRST ++#define LIST_PREV LIST_LAST ++ ++ ++/**************************************************************************//** ++ @Function LIST_INIT ++ ++ @Description Macro for initialization of a list struct. ++ ++ @Param[in] lst - The t_List object to initialize. ++*//***************************************************************************/ ++#define LIST_INIT(lst) {&(lst), &(lst)} ++ ++ ++/**************************************************************************//** ++ @Function LIST ++ ++ @Description Macro to declare of a list. ++ ++ @Param[in] listName - The list object name. ++*//***************************************************************************/ ++#define LIST(listName) t_List listName = LIST_INIT(listName) ++ ++ ++/**************************************************************************//** ++ @Function INIT_LIST ++ ++ @Description Macro to initialize a list pointer. ++ ++ @Param[in] p_List - The list pointer. ++*//***************************************************************************/ ++#define INIT_LIST(p_List) LIST_FIRST(p_List) = LIST_LAST(p_List) = (p_List) ++ ++ ++/**************************************************************************//** ++ @Function LIST_OBJECT ++ ++ @Description Macro to get the struct (object) for this entry. ++ ++ @Param[in] type - The type of the struct (object) this list is embedded in. ++ @Param[in] member - The name of the t_List object within the struct. ++ ++ @Return The structure pointer for this entry. ++*//***************************************************************************/ ++#define MEMBER_OFFSET(type, member) (PTR_TO_UINT(&((type *)0)->member)) ++#define LIST_OBJECT(p_List, type, member) \ ++ ((type *)((char *)(p_List)-MEMBER_OFFSET(type, member))) ++ ++ ++/**************************************************************************//** ++ @Function LIST_FOR_EACH ++ ++ @Description Macro to iterate over a list. ++ ++ @Param[in] p_Pos - A pointer to a list to use as a loop counter. ++ @Param[in] p_Head - A pointer to the head for your list pointer. ++ ++ @Cautions You can't delete items with this routine. ++ For deletion use LIST_FOR_EACH_SAFE(). ++*//***************************************************************************/ ++#define LIST_FOR_EACH(p_Pos, p_Head) \ ++ for (p_Pos = LIST_FIRST(p_Head); p_Pos != (p_Head); p_Pos = LIST_NEXT(p_Pos)) ++ ++ ++/**************************************************************************//** ++ @Function LIST_FOR_EACH_SAFE ++ ++ @Description Macro to iterate over a list safe against removal of list entry. ++ ++ @Param[in] p_Pos - A pointer to a list to use as a loop counter. ++ @Param[in] p_Tmp - Another pointer to a list to use as temporary storage. ++ @Param[in] p_Head - A pointer to the head for your list pointer. ++*//***************************************************************************/ ++#define LIST_FOR_EACH_SAFE(p_Pos, p_Tmp, p_Head) \ ++ for (p_Pos = LIST_FIRST(p_Head), p_Tmp = LIST_FIRST(p_Pos); \ ++ p_Pos != (p_Head); \ ++ p_Pos = p_Tmp, p_Tmp = LIST_NEXT(p_Pos)) ++ ++ ++/**************************************************************************//** ++ @Function LIST_FOR_EACH_OBJECT_SAFE ++ ++ @Description Macro to iterate over list of given type safely. ++ ++ @Param[in] p_Pos - A pointer to a list to use as a loop counter. ++ @Param[in] p_Tmp - Another pointer to a list to use as temporary storage. ++ @Param[in] type - The type of the struct this is embedded in. ++ @Param[in] p_Head - A pointer to the head for your list pointer. ++ @Param[in] member - The name of the list_struct within the struct. ++ ++ @Cautions You can't delete items with this routine. ++ For deletion use LIST_FOR_EACH_SAFE(). ++*//***************************************************************************/ ++#define LIST_FOR_EACH_OBJECT_SAFE(p_Pos, p_Tmp, p_Head, type, member) \ ++ for (p_Pos = LIST_OBJECT(LIST_FIRST(p_Head), type, member), \ ++ p_Tmp = LIST_OBJECT(LIST_FIRST(&p_Pos->member), type, member); \ ++ &p_Pos->member != (p_Head); \ ++ p_Pos = p_Tmp, \ ++ p_Tmp = LIST_OBJECT(LIST_FIRST(&p_Pos->member), type, member)) ++ ++/**************************************************************************//** ++ @Function LIST_FOR_EACH_OBJECT ++ ++ @Description Macro to iterate over list of given type. ++ ++ @Param[in] p_Pos - A pointer to a list to use as a loop counter. ++ @Param[in] type - The type of the struct this is embedded in. ++ @Param[in] p_Head - A pointer to the head for your list pointer. ++ @Param[in] member - The name of the list_struct within the struct. ++ ++ @Cautions You can't delete items with this routine. ++ For deletion use LIST_FOR_EACH_SAFE(). ++*//***************************************************************************/ ++#define LIST_FOR_EACH_OBJECT(p_Pos, type, p_Head, member) \ ++ for (p_Pos = LIST_OBJECT(LIST_FIRST(p_Head), type, member); \ ++ &p_Pos->member != (p_Head); \ ++ p_Pos = LIST_OBJECT(LIST_FIRST(&(p_Pos->member)), type, member)) ++ ++ ++/**************************************************************************//** ++ @Function LIST_Add ++ ++ @Description Add a new entry to a list. ++ ++ Insert a new entry after the specified head. ++ This is good for implementing stacks. ++ ++ @Param[in] p_New - A pointer to a new list entry to be added. ++ @Param[in] p_Head - A pointer to a list head to add it after. ++ ++ @Return none. ++*//***************************************************************************/ ++static __inline__ void LIST_Add(t_List *p_New, t_List *p_Head) ++{ ++ LIST_PREV(LIST_NEXT(p_Head)) = p_New; ++ LIST_NEXT(p_New) = LIST_NEXT(p_Head); ++ LIST_PREV(p_New) = p_Head; ++ LIST_NEXT(p_Head) = p_New; ++} ++ ++ ++/**************************************************************************//** ++ @Function LIST_AddToTail ++ ++ @Description Add a new entry to a list. ++ ++ Insert a new entry before the specified head. ++ This is useful for implementing queues. ++ ++ @Param[in] p_New - A pointer to a new list entry to be added. ++ @Param[in] p_Head - A pointer to a list head to add it before. ++ ++ @Return none. ++*//***************************************************************************/ ++static __inline__ void LIST_AddToTail(t_List *p_New, t_List *p_Head) ++{ ++ LIST_NEXT(LIST_PREV(p_Head)) = p_New; ++ LIST_PREV(p_New) = LIST_PREV(p_Head); ++ LIST_NEXT(p_New) = p_Head; ++ LIST_PREV(p_Head) = p_New; ++} ++ ++ ++/**************************************************************************//** ++ @Function LIST_Del ++ ++ @Description Deletes entry from a list. ++ ++ @Param[in] p_Entry - A pointer to the element to delete from the list. ++ ++ @Return none. ++ ++ @Cautions LIST_IsEmpty() on entry does not return true after this, ++ the entry is in an undefined state. ++*//***************************************************************************/ ++static __inline__ void LIST_Del(t_List *p_Entry) ++{ ++ LIST_PREV(LIST_NEXT(p_Entry)) = LIST_PREV(p_Entry); ++ LIST_NEXT(LIST_PREV(p_Entry)) = LIST_NEXT(p_Entry); ++} ++ ++ ++/**************************************************************************//** ++ @Function LIST_DelAndInit ++ ++ @Description Deletes entry from list and reinitialize it. ++ ++ @Param[in] p_Entry - A pointer to the element to delete from the list. ++ ++ @Return none. ++*//***************************************************************************/ ++static __inline__ void LIST_DelAndInit(t_List *p_Entry) ++{ ++ LIST_Del(p_Entry); ++ INIT_LIST(p_Entry); ++} ++ ++ ++/**************************************************************************//** ++ @Function LIST_Move ++ ++ @Description Delete from one list and add as another's head. ++ ++ @Param[in] p_Entry - A pointer to the list entry to move. ++ @Param[in] p_Head - A pointer to the list head that will precede our entry. ++ ++ @Return none. ++*//***************************************************************************/ ++static __inline__ void LIST_Move(t_List *p_Entry, t_List *p_Head) ++{ ++ LIST_Del(p_Entry); ++ LIST_Add(p_Entry, p_Head); ++} ++ ++ ++/**************************************************************************//** ++ @Function LIST_MoveToTail ++ ++ @Description Delete from one list and add as another's tail. ++ ++ @Param[in] p_Entry - A pointer to the entry to move. ++ @Param[in] p_Head - A pointer to the list head that will follow our entry. ++ ++ @Return none. ++*//***************************************************************************/ ++static __inline__ void LIST_MoveToTail(t_List *p_Entry, t_List *p_Head) ++{ ++ LIST_Del(p_Entry); ++ LIST_AddToTail(p_Entry, p_Head); ++} ++ ++ ++/**************************************************************************//** ++ @Function LIST_IsEmpty ++ ++ @Description Tests whether a list is empty. ++ ++ @Param[in] p_List - A pointer to the list to test. ++ ++ @Return 1 if the list is empty, 0 otherwise. ++*//***************************************************************************/ ++static __inline__ int LIST_IsEmpty(t_List *p_List) ++{ ++ return (LIST_FIRST(p_List) == p_List); ++} ++ ++ ++/**************************************************************************//** ++ @Function LIST_Append ++ ++ @Description Join two lists. ++ ++ @Param[in] p_NewList - A pointer to the new list to add. ++ @Param[in] p_Head - A pointer to the place to add it in the first list. ++ ++ @Return none. ++*//***************************************************************************/ ++void LIST_Append(t_List *p_NewList, t_List *p_Head); ++ ++ ++/**************************************************************************//** ++ @Function LIST_NumOfObjs ++ ++ @Description Counts number of objects in the list ++ ++ @Param[in] p_List - A pointer to the list which objects are to be counted. ++ ++ @Return Number of objects in the list. ++*//***************************************************************************/ ++int LIST_NumOfObjs(t_List *p_List); ++ ++/** @} */ /* end of list_id group */ ++/** @} */ /* end of etc_id group */ ++ ++ ++#endif /* __LIST_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/etc/mem_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/mem_ext.h +new file mode 100644 +index 00000000..d0565d41 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/mem_ext.h +@@ -0,0 +1,318 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ ++ @File mem_ext.h ++ ++ @Description External prototypes for the memory manager object ++*//***************************************************************************/ ++ ++#ifndef __MEM_EXT_H ++#define __MEM_EXT_H ++ ++#include "std_ext.h" ++#include "part_ext.h" ++ ++ ++/**************************************************************************//** ++ @Group etc_id Utility Library Application Programming Interface ++ ++ @Description External routines. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group mem_id Slab Memory Manager ++ ++ @Description Slab Memory Manager module functions, definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++/* Each block is of the following structure: ++ * ++ * ++ * +-----------+----------+---------------------------+-----------+-----------+ ++ * | Alignment | Prefix | Data | Postfix | Alignment | ++ * | field | field | field | field | Padding | ++ * | | | | | | ++ * +-----------+----------+---------------------------+-----------+-----------+ ++ * and at the beginning of all bytes, an additional optional padding might reside ++ * to ensure that the first blocks data field is aligned as requested. ++ */ ++ ++ ++#define MEM_MAX_NAME_LENGTH 8 ++ ++/**************************************************************************//* ++ @Description Memory Segment structure ++*//***************************************************************************/ ++ ++typedef struct ++{ ++ char name[MEM_MAX_NAME_LENGTH]; ++ /* The segment's name */ ++ uint8_t **p_Bases; /* Base addresses of the segments */ ++ uint8_t **p_BlocksStack; /* Array of pointers to blocks */ ++ t_Handle h_Spinlock; ++ uint16_t dataSize; /* Size of each data block */ ++ uint16_t prefixSize; /* How many bytes to reserve before the data */ ++ uint16_t postfixSize; /* How many bytes to reserve after the data */ ++ uint16_t alignment; /* Requested alignment for the data field */ ++ int allocOwner; /* Memory allocation owner */ ++ uint32_t getFailures; /* Number of times get failed */ ++ uint32_t num; /* Number of blocks in segment */ ++ uint32_t current; /* Current block */ ++ bool consecutiveMem; /* Allocate consecutive data blocks memory */ ++#ifdef DEBUG_MEM_LEAKS ++ void *p_MemDbg; /* MEM debug database (MEM leaks detection) */ ++ uint32_t blockOffset; ++ uint32_t blockSize; ++#endif /* DEBUG_MEM_LEAKS */ ++} t_MemorySegment; ++ ++ ++ ++/**************************************************************************//** ++ @Function MEM_Init ++ ++ @Description Create a new memory segment. ++ ++ @Param[in] name - Name of memory partition. ++ @Param[in] p_Handle - Handle to new segment is returned through here. ++ @Param[in] num - Number of blocks in new segment. ++ @Param[in] dataSize - Size of blocks in segment. ++ @Param[in] prefixSize - How many bytes to allocate before the data. ++ @Param[in] postfixSize - How many bytes to allocate after the data. ++ @Param[in] alignment - Requested alignment for data field (in bytes). ++ ++ @Return E_OK - success, E_NO_MEMORY - out of memory. ++*//***************************************************************************/ ++t_Error MEM_Init(char name[], ++ t_Handle *p_Handle, ++ uint32_t num, ++ uint16_t dataSize, ++ uint16_t prefixSize, ++ uint16_t postfixSize, ++ uint16_t alignment); ++ ++/**************************************************************************//** ++ @Function MEM_InitSmart ++ ++ @Description Create a new memory segment. ++ ++ @Param[in] name - Name of memory partition. ++ @Param[in] p_Handle - Handle to new segment is returned through here. ++ @Param[in] num - Number of blocks in new segment. ++ @Param[in] dataSize - Size of blocks in segment. ++ @Param[in] prefixSize - How many bytes to allocate before the data. ++ @Param[in] postfixSize - How many bytes to allocate after the data. ++ @Param[in] alignment - Requested alignment for data field (in bytes). ++ @Param[in] memPartitionId - Memory partition ID for allocation. ++ @Param[in] consecutiveMem - Whether to allocate the memory blocks ++ continuously or not. ++ ++ @Return E_OK - success, E_NO_MEMORY - out of memory. ++*//***************************************************************************/ ++t_Error MEM_InitSmart(char name[], ++ t_Handle *p_Handle, ++ uint32_t num, ++ uint16_t dataSize, ++ uint16_t prefixSize, ++ uint16_t postfixSize, ++ uint16_t alignment, ++ uint8_t memPartitionId, ++ bool consecutiveMem); ++ ++/**************************************************************************//** ++ @Function MEM_InitByAddress ++ ++ @Description Create a new memory segment with a specified base address. ++ ++ @Param[in] name - Name of memory partition. ++ @Param[in] p_Handle - Handle to new segment is returned through here. ++ @Param[in] num - Number of blocks in new segment. ++ @Param[in] dataSize - Size of blocks in segment. ++ @Param[in] prefixSize - How many bytes to allocate before the data. ++ @Param[in] postfixSize - How many bytes to allocate after the data. ++ @Param[in] alignment - Requested alignment for data field (in bytes). ++ @Param[in] address - The required base address. ++ ++ @Return E_OK - success, E_NO_MEMORY - out of memory. ++ *//***************************************************************************/ ++t_Error MEM_InitByAddress(char name[], ++ t_Handle *p_Handle, ++ uint32_t num, ++ uint16_t dataSize, ++ uint16_t prefixSize, ++ uint16_t postfixSize, ++ uint16_t alignment, ++ uint8_t *address); ++ ++/**************************************************************************//** ++ @Function MEM_Free ++ ++ @Description Free a specific memory segment. ++ ++ @Param[in] h_Mem - Handle to memory segment. ++ ++ @Return None. ++*//***************************************************************************/ ++void MEM_Free(t_Handle h_Mem); ++ ++/**************************************************************************//** ++ @Function MEM_Get ++ ++ @Description Get a block of memory from a segment. ++ ++ @Param[in] h_Mem - Handle to memory segment. ++ ++ @Return Pointer to new memory block on success,0 otherwise. ++*//***************************************************************************/ ++void * MEM_Get(t_Handle h_Mem); ++ ++/**************************************************************************//** ++ @Function MEM_GetN ++ ++ @Description Get up to N blocks of memory from a segment. ++ ++ The blocks are assumed to be of a fixed size (one size per segment). ++ ++ @Param[in] h_Mem - Handle to memory segment. ++ @Param[in] num - Number of blocks to allocate. ++ @Param[out] array - Array of at least num pointers to which the addresses ++ of the allocated blocks are written. ++ ++ @Return The number of blocks actually allocated. ++ ++ @Cautions Interrupts are disabled for all of the allocation loop. ++ Although this loop is very short for each block (several machine ++ instructions), you should not allocate a very large number ++ of blocks via this routine. ++*//***************************************************************************/ ++uint16_t MEM_GetN(t_Handle h_Mem, uint32_t num, void *array[]); ++ ++/**************************************************************************//** ++ @Function MEM_Put ++ ++ @Description Put a block of memory back to a segment. ++ ++ @Param[in] h_Mem - Handle to memory segment. ++ @Param[in] p_Block - The block to return. ++ ++ @Return Pointer to new memory block on success,0 otherwise. ++*//***************************************************************************/ ++t_Error MEM_Put(t_Handle h_Mem, void *p_Block); ++ ++/**************************************************************************//** ++ @Function MEM_ComputePartitionSize ++ ++ @Description calculate a tight upper boundary of the size of a partition with ++ given attributes. ++ ++ The returned value is suitable if one wants to use MEM_InitByAddress(). ++ ++ @Param[in] num - The number of blocks in the segment. ++ @Param[in] dataSize - Size of block to get. ++ @Param[in] prefixSize - The prefix size ++ @Param postfixSize - The postfix size ++ @Param[in] alignment - The requested alignment value (in bytes) ++ ++ @Return The memory block size a segment with the given attributes needs. ++*//***************************************************************************/ ++uint32_t MEM_ComputePartitionSize(uint32_t num, ++ uint16_t dataSize, ++ uint16_t prefixSize, ++ uint16_t postfixSize, ++ uint16_t alignment); ++ ++#ifdef DEBUG_MEM_LEAKS ++#if !((defined(__MWERKS__) || defined(__GNUC__)) && (__dest_os == __ppc_eabi)) ++#error "Memory-Leaks-Debug option is supported only for freescale CodeWarrior" ++#endif /* !(defined(__MWERKS__) && ... */ ++ ++/**************************************************************************//** ++ @Function MEM_CheckLeaks ++ ++ @Description Report MEM object leaks. ++ ++ This routine is automatically called by the MEM_Free() routine, ++ but it can also be invoked while the MEM object is alive. ++ ++ @Param[in] h_Mem - Handle to memory segment. ++ ++ @Return None. ++*//***************************************************************************/ ++void MEM_CheckLeaks(t_Handle h_Mem); ++ ++#else /* not DEBUG_MEM_LEAKS */ ++#define MEM_CheckLeaks(h_Mem) ++#endif /* not DEBUG_MEM_LEAKS */ ++ ++/**************************************************************************//** ++ @Description Get base of MEM ++*//***************************************************************************/ ++#define MEM_GetBase(h_Mem) ((t_MemorySegment *)(h_Mem))->p_Bases[0] ++ ++/**************************************************************************//** ++ @Description Get size of MEM block ++*//***************************************************************************/ ++#define MEM_GetSize(h_Mem) ((t_MemorySegment *)(h_Mem))->dataSize ++ ++/**************************************************************************//** ++ @Description Get prefix size of MEM block ++*//***************************************************************************/ ++#define MEM_GetPrefixSize(h_Mem) ((t_MemorySegment *)(h_Mem))->prefixSize ++ ++/**************************************************************************//** ++ @Description Get postfix size of MEM block ++*//***************************************************************************/ ++#define MEM_GetPostfixSize(h_Mem) ((t_MemorySegment *)(h_Mem))->postfixSize ++ ++/**************************************************************************//** ++ @Description Get alignment of MEM block (in bytes) ++*//***************************************************************************/ ++#define MEM_GetAlignment(h_Mem) ((t_MemorySegment *)(h_Mem))->alignment ++ ++/**************************************************************************//** ++ @Description Get the number of blocks in the segment ++*//***************************************************************************/ ++#define MEM_GetNumOfBlocks(h_Mem) ((t_MemorySegment *)(h_Mem))->num ++ ++/** @} */ /* end of MEM group */ ++/** @} */ /* end of etc_id group */ ++ ++ ++#endif /* __MEM_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/etc/memcpy_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/memcpy_ext.h +new file mode 100644 +index 00000000..1b3a2fac +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/memcpy_ext.h +@@ -0,0 +1,208 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ ++ @File memcpy_ext.h ++ ++ @Description Efficient functions for copying and setting blocks of memory. ++*//***************************************************************************/ ++ ++#ifndef __MEMCPY_EXT_H ++#define __MEMCPY_EXT_H ++ ++#include "std_ext.h" ++ ++ ++/**************************************************************************//** ++ @Group etc_id Utility Library Application Programming Interface ++ ++ @Description External routines. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group mem_cpy Memory Copy ++ ++ @Description Memory Copy module functions,definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function MemCpy32 ++ ++ @Description Copies one memory buffer into another one in 4-byte chunks! ++ Which should be more efficient than byte by byte. ++ ++ For large buffers (over 60 bytes) this function is about 4 times ++ more efficient than the trivial memory copy. For short buffers ++ it is reduced to the trivial copy and may be a bit worse. ++ ++ @Param[in] pDst - The address of the destination buffer. ++ @Param[in] pSrc - The address of the source buffer. ++ @Param[in] size - The number of bytes that will be copied from pSrc to pDst. ++ ++ @Return pDst (the address of the destination buffer). ++ ++ @Cautions There is no parameter or boundary checking! It is up to the user ++ to supply non-null parameters as source & destination and size ++ that actually fits into the destination buffer. ++*//***************************************************************************/ ++void * MemCpy32(void* pDst,void* pSrc, uint32_t size); ++void * IO2IOCpy32(void* pDst,void* pSrc, uint32_t size); ++void * IO2MemCpy32(void* pDst,void* pSrc, uint32_t size); ++void * Mem2IOCpy32(void* pDst,void* pSrc, uint32_t size); ++ ++/**************************************************************************//** ++ @Function MemCpy64 ++ ++ @Description Copies one memory buffer into another one in 8-byte chunks! ++ Which should be more efficient than byte by byte. ++ ++ For large buffers (over 60 bytes) this function is about 8 times ++ more efficient than the trivial memory copy. For short buffers ++ it is reduced to the trivial copy and may be a bit worse. ++ ++ Some testing suggests that MemCpy32() preforms better than ++ MemCpy64() over small buffers. On average they break even at ++ 100 byte buffers. For buffers larger than that MemCpy64 is ++ superior. ++ ++ @Param[in] pDst - The address of the destination buffer. ++ @Param[in] pSrc - The address of the source buffer. ++ @Param[in] size - The number of bytes that will be copied from pSrc to pDst. ++ ++ @Return pDst (the address of the destination buffer). ++ ++ @Cautions There is no parameter or boundary checking! It is up to the user ++ to supply non null parameters as source & destination and size ++ that actually fits into their buffer. ++ ++ Do not use under Linux. ++*//***************************************************************************/ ++void * MemCpy64(void* pDst,void* pSrc, uint32_t size); ++ ++/**************************************************************************//** ++ @Function MemSet32 ++ ++ @Description Sets all bytes of a memory buffer to a specific value, in ++ 4-byte chunks. ++ ++ @Param[in] pDst - The address of the destination buffer. ++ @Param[in] val - Value to set destination bytes to. ++ @Param[in] size - The number of bytes that will be set to val. ++ ++ @Return pDst (the address of the destination buffer). ++ ++ @Cautions There is no parameter or boundary checking! It is up to the user ++ to supply non null parameter as destination and size ++ that actually fits into the destination buffer. ++*//***************************************************************************/ ++void * MemSet32(void* pDst, uint8_t val, uint32_t size); ++void * IOMemSet32(void* pDst, uint8_t val, uint32_t size); ++ ++/**************************************************************************//** ++ @Function MemSet64 ++ ++ @Description Sets all bytes of a memory buffer to a specific value, in ++ 8-byte chunks. ++ ++ @Param[in] pDst - The address of the destination buffer. ++ @Param[in] val - Value to set destination bytes to. ++ @Param[in] size - The number of bytes that will be set to val. ++ ++ @Return pDst (the address of the destination buffer). ++ ++ @Cautions There is no parameter or boundary checking! It is up to the user ++ to supply non null parameter as destination and size ++ that actually fits into the destination buffer. ++*//***************************************************************************/ ++void * MemSet64(void* pDst, uint8_t val, uint32_t size); ++ ++/**************************************************************************//** ++ @Function MemDisp ++ ++ @Description Displays a block of memory in chunks of 32 bits. ++ ++ @Param[in] addr - The address of the memory to display. ++ @Param[in] size - The number of bytes that will be displayed. ++ ++ @Return None. ++ ++ @Cautions There is no parameter or boundary checking! It is up to the user ++ to supply non null parameter as destination and size ++ that actually fits into the destination buffer. ++*//***************************************************************************/ ++void MemDisp(uint8_t *addr, int size); ++ ++/**************************************************************************//** ++ @Function MemCpy8 ++ ++ @Description Trivial copy one memory buffer into another byte by byte ++ ++ @Param[in] pDst - The address of the destination buffer. ++ @Param[in] pSrc - The address of the source buffer. ++ @Param[in] size - The number of bytes that will be copied from pSrc to pDst. ++ ++ @Return pDst (the address of the destination buffer). ++ ++ @Cautions There is no parameter or boundary checking! It is up to the user ++ to supply non-null parameters as source & destination and size ++ that actually fits into the destination buffer. ++*//***************************************************************************/ ++void * MemCpy8(void* pDst,void* pSrc, uint32_t size); ++ ++/**************************************************************************//** ++ @Function MemSet8 ++ ++ @Description Sets all bytes of a memory buffer to a specific value byte by byte. ++ ++ @Param[in] pDst - The address of the destination buffer. ++ @Param[in] c - Value to set destination bytes to. ++ @Param[in] size - The number of bytes that will be set to val. ++ ++ @Return pDst (the address of the destination buffer). ++ ++ @Cautions There is no parameter or boundary checking! It is up to the user ++ to supply non null parameter as destination and size ++ that actually fits into the destination buffer. ++*//***************************************************************************/ ++void * MemSet8(void* pDst, int c, uint32_t size); ++ ++/** @} */ /* end of mem_cpy group */ ++/** @} */ /* end of etc_id group */ ++ ++ ++#endif /* __MEMCPY_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/etc/mm_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/mm_ext.h +new file mode 100644 +index 00000000..fa7c85e3 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/mm_ext.h +@@ -0,0 +1,310 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File mm_ext.h ++ ++ @Description Memory Manager Application Programming Interface ++*//***************************************************************************/ ++#ifndef __MM_EXT ++#define __MM_EXT ++ ++#include "std_ext.h" ++ ++#define MM_MAX_ALIGNMENT 20 /* Alignments from 2 to 128 are available ++ where maximum alignment defined as ++ MM_MAX_ALIGNMENT power of 2 */ ++ ++#define MM_MAX_NAME_LEN 32 ++ ++/**************************************************************************//** ++ @Group etc_id Utility Library Application Programming Interface ++ ++ @Description External routines. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group mm_grp Flexible Memory Manager ++ ++ @Description Flexible Memory Manager module functions,definitions and enums. ++ (All of the following functions,definitions and enums can be found in mm_ext.h) ++ ++ @{ ++*//***************************************************************************/ ++ ++ ++/**************************************************************************//** ++ @Function MM_Init ++ ++ @Description Initializes a new MM object. ++ ++ It initializes a new memory block consisting of base address ++ and size of the available memory by calling to MemBlock_Init ++ routine. It is also initializes a new free block for each ++ by calling FreeBlock_Init routine, which is pointed to ++ the almost all memory started from the required alignment ++ from the base address and to the end of the memory. ++ The handle to the new MM object is returned via "MM" ++ argument (passed by reference). ++ ++ @Param[in] h_MM - Handle to the MM object. ++ @Param[in] base - Base address of the MM. ++ @Param[in] size - Size of the MM. ++ ++ @Return E_OK is returned on success. E_NOMEMORY is returned if the new MM object or a new free block can not be initialized. ++*//***************************************************************************/ ++t_Error MM_Init(t_Handle *h_MM, uint64_t base, uint64_t size); ++ ++/**************************************************************************//** ++ @Function MM_Get ++ ++ @Description Allocates a block of memory according to the given size and the alignment. ++ ++ The Alignment argument tells from which ++ free list allocate a block of memory. 2^alignment indicates ++ the alignment that the base address of the allocated block ++ should have. So, the only values 1, 2, 4, 8, 16, 32 and 64 ++ are available for the alignment argument. ++ The routine passes through the specific free list of free ++ blocks and seeks for a first block that have anough memory ++ that is required (best fit). ++ After the block is found and data is allocated, it calls ++ the internal MM_CutFree routine to update all free lists ++ do not include a just allocated block. Of course, each ++ free list contains a free blocks with the same alignment. ++ It is also creates a busy block that holds ++ information about an allocated block. ++ ++ @Param[in] h_MM - Handle to the MM object. ++ @Param[in] size - Size of the MM. ++ @Param[in] alignment - Index as a power of two defines a required ++ alignment (in bytes); Should be 1, 2, 4, 8, 16, 32 or 64 ++ @Param[in] name - The name that specifies an allocated block. ++ ++ @Return base address of an allocated block ILLEGAL_BASE if can't allocate a block ++*//***************************************************************************/ ++uint64_t MM_Get(t_Handle h_MM, uint64_t size, uint64_t alignment, char *name); ++ ++/**************************************************************************//** ++ @Function MM_GetBase ++ ++ @Description Gets the base address of the required MM objects. ++ ++ @Param[in] h_MM - Handle to the MM object. ++ ++ @Return base address of the block. ++*//***************************************************************************/ ++uint64_t MM_GetBase(t_Handle h_MM); ++ ++/**************************************************************************//** ++ @Function MM_GetForce ++ ++ @Description Force memory allocation. ++ ++ It means to allocate a block of memory of the given ++ size from the given base address. ++ The routine checks if the required block can be allocated ++ (that is it is free) and then, calls the internal MM_CutFree ++ routine to update all free lists do not include that block. ++ ++ @Param[in] h_MM - Handle to the MM object. ++ @Param[in] base - Base address of the MM. ++ @Param[in] size - Size of the MM. ++ @Param[in] name - Name that specifies an allocated block. ++ ++ @Return base address of an allocated block, ILLEGAL_BASE if can't allocate a block. ++*//***************************************************************************/ ++uint64_t MM_GetForce(t_Handle h_MM, uint64_t base, uint64_t size, char *name); ++ ++/**************************************************************************//** ++ @Function MM_GetForceMin ++ ++ @Description Allocates a block of memory according to the given size, the alignment and minimum base address. ++ ++ The Alignment argument tells from which ++ free list allocate a block of memory. 2^alignment indicates ++ the alignment that the base address of the allocated block ++ should have. So, the only values 1, 2, 4, 8, 16, 32 and 64 ++ are available for the alignment argument. ++ The minimum baser address forces the location of the block ++ to be from a given address onward. ++ The routine passes through the specific free list of free ++ blocks and seeks for the first base address equal or smaller ++ than the required minimum address and end address larger than ++ than the required base + its size - i.e. that may contain ++ the required block. ++ After the block is found and data is allocated, it calls ++ the internal MM_CutFree routine to update all free lists ++ do not include a just allocated block. Of course, each ++ free list contains a free blocks with the same alignment. ++ It is also creates a busy block that holds ++ information about an allocated block. ++ ++ @Param[in] h_MM - Handle to the MM object. ++ @Param[in] size - Size of the MM. ++ @Param[in] alignment - Index as a power of two defines a required ++ alignment (in bytes); Should be 1, 2, 4, 8, 16, 32 or 64 ++ @Param[in] min - The minimum base address of the block. ++ @Param[in] name - Name that specifies an allocated block. ++ ++ @Return base address of an allocated block,ILLEGAL_BASE if can't allocate a block. ++*//***************************************************************************/ ++uint64_t MM_GetForceMin(t_Handle h_MM, ++ uint64_t size, ++ uint64_t alignment, ++ uint64_t min, ++ char *name); ++ ++/**************************************************************************//** ++ @Function MM_Put ++ ++ @Description Puts a block of memory of the given base address back to the memory. ++ ++ It checks if there is a busy block with the ++ given base address. If not, it returns 0, that ++ means can't free a block. Otherwise, it gets parameters of ++ the busy block and after it updates lists of free blocks, ++ removes that busy block from the list by calling to MM_CutBusy ++ routine. ++ After that it calls to MM_AddFree routine to add a new free ++ block to the free lists. ++ ++ @Param[in] h_MM - Handle to the MM object. ++ @Param[in] base - Base address of the MM. ++ ++ @Return The size of bytes released, 0 if failed. ++*//***************************************************************************/ ++uint64_t MM_Put(t_Handle h_MM, uint64_t base); ++ ++/**************************************************************************//** ++ @Function MM_PutForce ++ ++ @Description Releases a block of memory of the required size from the required base address. ++ ++ First, it calls to MM_CutBusy routine ++ to cut a free block from the busy list. And then, calls to ++ MM_AddFree routine to add the free block to the free lists. ++ ++ @Param[in] h_MM - Handle to the MM object. ++ @Param[in] base - Base address of of a block to free. ++ @Param[in] size - Size of a block to free. ++ ++ @Return The number of bytes released, 0 on failure. ++*//***************************************************************************/ ++uint64_t MM_PutForce(t_Handle h_MM, uint64_t base, uint64_t size); ++ ++/**************************************************************************//** ++ @Function MM_Add ++ ++ @Description Adds a new memory block for memory allocation. ++ ++ When a new memory block is initialized and added to the ++ memory list, it calls to MM_AddFree routine to add the ++ new free block to the free lists. ++ ++ @Param[in] h_MM - Handle to the MM object. ++ @Param[in] base - Base address of the memory block. ++ @Param[in] size - Size of the memory block. ++ ++ @Return E_OK on success, otherwise returns an error code. ++*//***************************************************************************/ ++t_Error MM_Add(t_Handle h_MM, uint64_t base, uint64_t size); ++ ++/**************************************************************************//** ++ @Function MM_Dump ++ ++ @Description Prints results of free and busy lists. ++ ++ @Param[in] h_MM - Handle to the MM object. ++*//***************************************************************************/ ++void MM_Dump(t_Handle h_MM); ++ ++/**************************************************************************//** ++ @Function MM_Free ++ ++ @Description Releases memory allocated for MM object. ++ ++ @Param[in] h_MM - Handle of the MM object. ++*//***************************************************************************/ ++void MM_Free(t_Handle h_MM); ++ ++/**************************************************************************//** ++ @Function MM_GetMemBlock ++ ++ @Description Returns base address of the memory block specified by the index. ++ ++ If index is 0, returns base address ++ of the first memory block, 1 - returns base address ++ of the second memory block, etc. ++ Note, those memory blocks are allocated by the ++ application before MM_Init or MM_Add and have to ++ be released by the application before or after invoking ++ the MM_Free routine. ++ ++ @Param[in] h_MM - Handle to the MM object. ++ @Param[in] index - Index of the memory block. ++ ++ @Return valid base address or ILLEGAL_BASE if no memory block specified by the index. ++*//***************************************************************************/ ++uint64_t MM_GetMemBlock(t_Handle h_MM, int index); ++ ++/**************************************************************************//** ++ @Function MM_InRange ++ ++ @Description Checks if a specific address is in the memory range of the passed MM object. ++ ++ @Param[in] h_MM - Handle to the MM object. ++ @Param[in] addr - The address to be checked. ++ ++ @Return TRUE if the address is in the address range of the block, FALSE otherwise. ++*//***************************************************************************/ ++bool MM_InRange(t_Handle h_MM, uint64_t addr); ++ ++/**************************************************************************//** ++ @Function MM_GetFreeMemSize ++ ++ @Description Returns the size (in bytes) of free memory. ++ ++ @Param[in] h_MM - Handle to the MM object. ++ ++ @Return Free memory size in bytes. ++*//***************************************************************************/ ++uint64_t MM_GetFreeMemSize(t_Handle h_MM); ++ ++ ++/** @} */ /* end of mm_grp group */ ++/** @} */ /* end of etc_id group */ ++ ++#endif /* __MM_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/etc/sprint_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/sprint_ext.h +new file mode 100644 +index 00000000..52f7a9dc +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/etc/sprint_ext.h +@@ -0,0 +1,118 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File sprint_ext.h ++ ++ @Description Debug routines (externals). ++ ++*//***************************************************************************/ ++ ++#ifndef __SPRINT_EXT_H ++#define __SPRINT_EXT_H ++ ++ ++#if defined(NCSW_LINUX) && defined(__KERNEL__) ++#include ++ ++#elif defined(NCSW_VXWORKS) ++#include "private/stdioP.h" ++ ++#else ++#include ++#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */ ++ ++#include "std_ext.h" ++ ++ ++/**************************************************************************//** ++ @Group etc_id Utility Library Application Programming Interface ++ ++ @Description External routines. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group sprint_id Sprint ++ ++ @Description Sprint & Sscan module functions,definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Function Sprint ++ ++ @Description Format a string and place it in a buffer. ++ ++ @Param[in] buff - The buffer to place the result into. ++ @Param[in] str - The format string to use. ++ @Param[in] ... - Arguments for the format string. ++ ++ @Return Number of bytes formatted. ++*//***************************************************************************/ ++int Sprint(char *buff, const char *str, ...); ++ ++/**************************************************************************//** ++ @Function Snprint ++ ++ @Description Format a string and place it in a buffer. ++ ++ @Param[in] buf - The buffer to place the result into. ++ @Param[in] size - The size of the buffer, including the trailing null space. ++ @Param[in] fmt - The format string to use. ++ @Param[in] ... - Arguments for the format string. ++ ++ @Return Number of bytes formatted. ++*//***************************************************************************/ ++int Snprint(char * buf, uint32_t size, const char *fmt, ...); ++ ++/**************************************************************************//** ++ @Function Sscan ++ ++ @Description Unformat a buffer into a list of arguments. ++ ++ @Param[in] buf - input buffer. ++ @Param[in] fmt - formatting of buffer. ++ @Param[out] ... - resulting arguments. ++ ++ @Return Number of bytes unformatted. ++*//***************************************************************************/ ++int Sscan(const char * buf, const char * fmt, ...); ++ ++/** @} */ /* end of sprint_id group */ ++/** @} */ /* end of etc_id group */ ++ ++ ++#endif /* __SPRINT_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/arch/ppc_access.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/arch/ppc_access.h +new file mode 100644 +index 00000000..c7b9b46f +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/arch/ppc_access.h +@@ -0,0 +1,37 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef FL_E500_MACROS_H ++#define FL_E500_MACROS_H ++ ++#endif /* FL_E500_MACROS_H */ ++ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/general.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/general.h +new file mode 100644 +index 00000000..b3f516fb +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/common/general.h +@@ -0,0 +1,52 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __GENERAL_H ++#define __GENERAL_H ++ ++#include "std_ext.h" ++#if !defined(NCSW_LINUX) ++#include "errno.h" ++#endif ++ ++ ++extern uint32_t get_mac_addr_crc(uint64_t _addr); ++ ++#ifndef CONFIG_FMAN_ARM ++#define iowrite32be(val, addr) WRITE_UINT32(*addr, val) ++#define ioread32be(addr) GET_UINT32(*addr) ++#endif ++ ++#define ether_crc(len, addr) get_mac_addr_crc(*(uint64_t *)(addr)>>16) ++ ++ ++#endif /* __GENERAL_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fman_common.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fman_common.h +new file mode 100755 +index 00000000..8b194e99 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fman_common.h +@@ -0,0 +1,78 @@ ++/* ++ * Copyright 2008-2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#ifndef __FMAN_COMMON_H ++#define __FMAN_COMMON_H ++ ++/**************************************************************************//** ++ @Description NIA Description ++*//***************************************************************************/ ++#define NIA_ORDER_RESTOR 0x00800000 ++#define NIA_ENG_FM_CTL 0x00000000 ++#define NIA_ENG_PRS 0x00440000 ++#define NIA_ENG_KG 0x00480000 ++#define NIA_ENG_PLCR 0x004C0000 ++#define NIA_ENG_BMI 0x00500000 ++#define NIA_ENG_QMI_ENQ 0x00540000 ++#define NIA_ENG_QMI_DEQ 0x00580000 ++#define NIA_ENG_MASK 0x007C0000 ++ ++#define NIA_FM_CTL_AC_CC 0x00000006 ++#define NIA_FM_CTL_AC_HC 0x0000000C ++#define NIA_FM_CTL_AC_IND_MODE_TX 0x00000008 ++#define NIA_FM_CTL_AC_IND_MODE_RX 0x0000000A ++#define NIA_FM_CTL_AC_FRAG 0x0000000e ++#define NIA_FM_CTL_AC_PRE_FETCH 0x00000010 ++#define NIA_FM_CTL_AC_POST_FETCH_PCD 0x00000012 ++#define NIA_FM_CTL_AC_POST_FETCH_PCD_UDP_LEN 0x00000018 ++#define NIA_FM_CTL_AC_POST_FETCH_NO_PCD 0x00000012 ++#define NIA_FM_CTL_AC_FRAG_CHECK 0x00000014 ++#define NIA_FM_CTL_AC_PRE_CC 0x00000020 ++ ++ ++#define NIA_BMI_AC_ENQ_FRAME 0x00000002 ++#define NIA_BMI_AC_TX_RELEASE 0x000002C0 ++#define NIA_BMI_AC_RELEASE 0x000000C0 ++#define NIA_BMI_AC_DISCARD 0x000000C1 ++#define NIA_BMI_AC_TX 0x00000274 ++#define NIA_BMI_AC_FETCH 0x00000208 ++#define NIA_BMI_AC_MASK 0x000003FF ++ ++#define NIA_KG_DIRECT 0x00000100 ++#define NIA_KG_CC_EN 0x00000200 ++#define NIA_PLCR_ABSOLUTE 0x00008000 ++ ++#define NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA 0x00000202 ++#define NIA_BMI_AC_FETCH_ALL_FRAME 0x0000020c ++ ++#endif /* __FMAN_COMMON_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_enet.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_enet.h +new file mode 100644 +index 00000000..caa87fc6 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_enet.h +@@ -0,0 +1,273 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __FSL_ENET_H ++#define __FSL_ENET_H ++ ++/** ++ @Description Ethernet MAC-PHY Interface ++*/ ++ ++enum enet_interface { ++ E_ENET_IF_MII = 0x00010000, /**< MII interface */ ++ E_ENET_IF_RMII = 0x00020000, /**< RMII interface */ ++ E_ENET_IF_SMII = 0x00030000, /**< SMII interface */ ++ E_ENET_IF_GMII = 0x00040000, /**< GMII interface */ ++ E_ENET_IF_RGMII = 0x00050000, /**< RGMII interface */ ++ E_ENET_IF_TBI = 0x00060000, /**< TBI interface */ ++ E_ENET_IF_RTBI = 0x00070000, /**< RTBI interface */ ++ E_ENET_IF_SGMII = 0x00080000, /**< SGMII interface */ ++ E_ENET_IF_XGMII = 0x00090000, /**< XGMII interface */ ++ E_ENET_IF_QSGMII = 0x000a0000, /**< QSGMII interface */ ++ E_ENET_IF_XFI = 0x000b0000 /**< XFI interface */ ++}; ++ ++/** ++ @Description Ethernet Speed (nominal data rate) ++*/ ++enum enet_speed { ++ E_ENET_SPEED_10 = 10, /**< 10 Mbps */ ++ E_ENET_SPEED_100 = 100, /**< 100 Mbps */ ++ E_ENET_SPEED_1000 = 1000, /**< 1000 Mbps = 1 Gbps */ ++ E_ENET_SPEED_2500 = 2500, /**< 2500 Mbps = 2.5 Gbps */ ++ E_ENET_SPEED_10000 = 10000 /**< 10000 Mbps = 10 Gbps */ ++}; ++ ++enum mac_type { ++ E_MAC_DTSEC, ++ E_MAC_TGEC, ++ E_MAC_MEMAC ++}; ++ ++/**************************************************************************//** ++ @Description Enum for inter-module interrupts registration ++*//***************************************************************************/ ++enum fman_event_modules { ++ E_FMAN_MOD_PRS, /**< Parser event */ ++ E_FMAN_MOD_KG, /**< Keygen event */ ++ E_FMAN_MOD_PLCR, /**< Policer event */ ++ E_FMAN_MOD_10G_MAC, /**< 10G MAC event */ ++ E_FMAN_MOD_1G_MAC, /**< 1G MAC event */ ++ E_FMAN_MOD_TMR, /**< Timer event */ ++ E_FMAN_MOD_FMAN_CTRL, /**< FMAN Controller Timer event */ ++ E_FMAN_MOD_MACSEC, ++ E_FMAN_MOD_DUMMY_LAST ++}; ++ ++/**************************************************************************//** ++ @Description Enum for interrupts types ++*//***************************************************************************/ ++enum fman_intr_type { ++ E_FMAN_INTR_TYPE_ERR, ++ E_FMAN_INTR_TYPE_NORMAL ++}; ++ ++/**************************************************************************//** ++ @Description enum for defining MAC types ++*//***************************************************************************/ ++enum fman_mac_type { ++ E_FMAN_MAC_10G = 0, /**< 10G MAC */ ++ E_FMAN_MAC_1G /**< 1G MAC */ ++}; ++ ++enum fman_mac_exceptions { ++ E_FMAN_MAC_EX_10G_MDIO_SCAN_EVENTMDIO = 0, ++ /**< 10GEC MDIO scan event interrupt */ ++ E_FMAN_MAC_EX_10G_MDIO_CMD_CMPL, ++ /**< 10GEC MDIO command completion interrupt */ ++ E_FMAN_MAC_EX_10G_REM_FAULT, ++ /**< 10GEC, mEMAC Remote fault interrupt */ ++ E_FMAN_MAC_EX_10G_LOC_FAULT, ++ /**< 10GEC, mEMAC Local fault interrupt */ ++ E_FMAN_MAC_EX_10G_1TX_ECC_ER, ++ /**< 10GEC, mEMAC Transmit frame ECC error interrupt */ ++ E_FMAN_MAC_EX_10G_TX_FIFO_UNFL, ++ /**< 10GEC, mEMAC Transmit FIFO underflow interrupt */ ++ E_FMAN_MAC_EX_10G_TX_FIFO_OVFL, ++ /**< 10GEC, mEMAC Transmit FIFO overflow interrupt */ ++ E_FMAN_MAC_EX_10G_TX_ER, ++ /**< 10GEC Transmit frame error interrupt */ ++ E_FMAN_MAC_EX_10G_RX_FIFO_OVFL, ++ /**< 10GEC, mEMAC Receive FIFO overflow interrupt */ ++ E_FMAN_MAC_EX_10G_RX_ECC_ER, ++ /**< 10GEC, mEMAC Receive frame ECC error interrupt */ ++ E_FMAN_MAC_EX_10G_RX_JAB_FRM, ++ /**< 10GEC Receive jabber frame interrupt */ ++ E_FMAN_MAC_EX_10G_RX_OVRSZ_FRM, ++ /**< 10GEC Receive oversized frame interrupt */ ++ E_FMAN_MAC_EX_10G_RX_RUNT_FRM, ++ /**< 10GEC Receive runt frame interrupt */ ++ E_FMAN_MAC_EX_10G_RX_FRAG_FRM, ++ /**< 10GEC Receive fragment frame interrupt */ ++ E_FMAN_MAC_EX_10G_RX_LEN_ER, ++ /**< 10GEC Receive payload length error interrupt */ ++ E_FMAN_MAC_EX_10G_RX_CRC_ER, ++ /**< 10GEC Receive CRC error interrupt */ ++ E_FMAN_MAC_EX_10G_RX_ALIGN_ER, ++ /**< 10GEC Receive alignment error interrupt */ ++ E_FMAN_MAC_EX_1G_BAB_RX, ++ /**< dTSEC Babbling receive error */ ++ E_FMAN_MAC_EX_1G_RX_CTL, ++ /**< dTSEC Receive control (pause frame) interrupt */ ++ E_FMAN_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET, ++ /**< dTSEC Graceful transmit stop complete */ ++ E_FMAN_MAC_EX_1G_BAB_TX, ++ /**< dTSEC Babbling transmit error */ ++ E_FMAN_MAC_EX_1G_TX_CTL, ++ /**< dTSEC Transmit control (pause frame) interrupt */ ++ E_FMAN_MAC_EX_1G_TX_ERR, ++ /**< dTSEC Transmit error */ ++ E_FMAN_MAC_EX_1G_LATE_COL, ++ /**< dTSEC Late collision */ ++ E_FMAN_MAC_EX_1G_COL_RET_LMT, ++ /**< dTSEC Collision retry limit */ ++ E_FMAN_MAC_EX_1G_TX_FIFO_UNDRN, ++ /**< dTSEC Transmit FIFO underrun */ ++ E_FMAN_MAC_EX_1G_MAG_PCKT, ++ /**< dTSEC Magic Packet detection */ ++ E_FMAN_MAC_EX_1G_MII_MNG_RD_COMPLET, ++ /**< dTSEC MII management read completion */ ++ E_FMAN_MAC_EX_1G_MII_MNG_WR_COMPLET, ++ /**< dTSEC MII management write completion */ ++ E_FMAN_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET, ++ /**< dTSEC Graceful receive stop complete */ ++ E_FMAN_MAC_EX_1G_TX_DATA_ERR, ++ /**< dTSEC Internal data error on transmit */ ++ E_FMAN_MAC_EX_1G_RX_DATA_ERR, ++ /**< dTSEC Internal data error on receive */ ++ E_FMAN_MAC_EX_1G_1588_TS_RX_ERR, ++ /**< dTSEC Time-Stamp Receive Error */ ++ E_FMAN_MAC_EX_1G_RX_MIB_CNT_OVFL, ++ /**< dTSEC MIB counter overflow */ ++ E_FMAN_MAC_EX_TS_FIFO_ECC_ERR, ++ /**< mEMAC Time-stamp FIFO ECC error interrupt; ++ not supported on T4240/B4860 rev1 chips */ ++}; ++ ++#define ENET_IF_SGMII_BASEX 0x80000000 ++ /**< SGMII/QSGII interface with 1000BaseX auto-negotiation between MAC ++ and phy or backplane; ++ Note: 1000BaseX auto-negotiation relates only to interface between MAC ++ and phy/backplane, SGMII phy can still synchronize with far-end phy at ++ 10Mbps, 100Mbps or 1000Mbps */ ++ ++enum enet_mode { ++ E_ENET_MODE_INVALID = 0, ++ /**< Invalid Ethernet mode */ ++ E_ENET_MODE_MII_10 = (E_ENET_IF_MII | E_ENET_SPEED_10), ++ /**< 10 Mbps MII */ ++ E_ENET_MODE_MII_100 = (E_ENET_IF_MII | E_ENET_SPEED_100), ++ /**< 100 Mbps MII */ ++ E_ENET_MODE_RMII_10 = (E_ENET_IF_RMII | E_ENET_SPEED_10), ++ /**< 10 Mbps RMII */ ++ E_ENET_MODE_RMII_100 = (E_ENET_IF_RMII | E_ENET_SPEED_100), ++ /**< 100 Mbps RMII */ ++ E_ENET_MODE_SMII_10 = (E_ENET_IF_SMII | E_ENET_SPEED_10), ++ /**< 10 Mbps SMII */ ++ E_ENET_MODE_SMII_100 = (E_ENET_IF_SMII | E_ENET_SPEED_100), ++ /**< 100 Mbps SMII */ ++ E_ENET_MODE_GMII_1000 = (E_ENET_IF_GMII | E_ENET_SPEED_1000), ++ /**< 1000 Mbps GMII */ ++ E_ENET_MODE_RGMII_10 = (E_ENET_IF_RGMII | E_ENET_SPEED_10), ++ /**< 10 Mbps RGMII */ ++ E_ENET_MODE_RGMII_100 = (E_ENET_IF_RGMII | E_ENET_SPEED_100), ++ /**< 100 Mbps RGMII */ ++ E_ENET_MODE_RGMII_1000 = (E_ENET_IF_RGMII | E_ENET_SPEED_1000), ++ /**< 1000 Mbps RGMII */ ++ E_ENET_MODE_TBI_1000 = (E_ENET_IF_TBI | E_ENET_SPEED_1000), ++ /**< 1000 Mbps TBI */ ++ E_ENET_MODE_RTBI_1000 = (E_ENET_IF_RTBI | E_ENET_SPEED_1000), ++ /**< 1000 Mbps RTBI */ ++ E_ENET_MODE_SGMII_10 = (E_ENET_IF_SGMII | E_ENET_SPEED_10), ++ /**< 10 Mbps SGMII with auto-negotiation between MAC and ++ SGMII phy according to Cisco SGMII specification */ ++ E_ENET_MODE_SGMII_100 = (E_ENET_IF_SGMII | E_ENET_SPEED_100), ++ /**< 100 Mbps SGMII with auto-negotiation between MAC and ++ SGMII phy according to Cisco SGMII specification */ ++ E_ENET_MODE_SGMII_1000 = (E_ENET_IF_SGMII | E_ENET_SPEED_1000), ++ /**< 1000 Mbps SGMII with auto-negotiation between MAC and ++ SGMII phy according to Cisco SGMII specification */ ++ E_ENET_MODE_SGMII_BASEX_10 = (ENET_IF_SGMII_BASEX | E_ENET_IF_SGMII ++ | E_ENET_SPEED_10), ++ /**< 10 Mbps SGMII with 1000BaseX auto-negotiation between ++ MAC and SGMII phy or backplane */ ++ E_ENET_MODE_SGMII_BASEX_100 = (ENET_IF_SGMII_BASEX | E_ENET_IF_SGMII ++ | E_ENET_SPEED_100), ++ /**< 100 Mbps SGMII with 1000BaseX auto-negotiation between ++ MAC and SGMII phy or backplane */ ++ E_ENET_MODE_SGMII_BASEX_1000 = (ENET_IF_SGMII_BASEX | E_ENET_IF_SGMII ++ | E_ENET_SPEED_1000), ++ /**< 1000 Mbps SGMII with 1000BaseX auto-negotiation between ++ MAC and SGMII phy or backplane */ ++ E_ENET_MODE_QSGMII_1000 = (E_ENET_IF_QSGMII | E_ENET_SPEED_1000), ++ /**< 1000 Mbps QSGMII with auto-negotiation between MAC and ++ QSGMII phy according to Cisco QSGMII specification */ ++ E_ENET_MODE_QSGMII_BASEX_1000 = (ENET_IF_SGMII_BASEX | E_ENET_IF_QSGMII ++ | E_ENET_SPEED_1000), ++ /**< 1000 Mbps QSGMII with 1000BaseX auto-negotiation between ++ MAC and QSGMII phy or backplane */ ++ E_ENET_MODE_XGMII_10000 = (E_ENET_IF_XGMII | E_ENET_SPEED_10000), ++ /**< 10000 Mbps XGMII */ ++ E_ENET_MODE_XFI_10000 = (E_ENET_IF_XFI | E_ENET_SPEED_10000) ++ /**< 10000 Mbps XFI */ ++}; ++ ++enum fmam_mac_statistics_level { ++ E_FMAN_MAC_NONE_STATISTICS, /**< No statistics */ ++ E_FMAN_MAC_PARTIAL_STATISTICS, /**< Only error counters are available; ++ Optimized for performance */ ++ E_FMAN_MAC_FULL_STATISTICS /**< All counters available; Not ++ optimized for performance */ ++}; ++ ++#define _MAKE_ENET_MODE(_interface, _speed) (enum enet_mode)((_interface) \ ++ | (_speed)) ++ ++#define _ENET_INTERFACE_FROM_MODE(mode) (enum enet_interface) \ ++ ((mode) & 0x0FFF0000) ++#define _ENET_SPEED_FROM_MODE(mode) (enum enet_speed)((mode) & 0x0000FFFF) ++#define _ENET_ADDR_TO_UINT64(_enet_addr) \ ++ (uint64_t)(((uint64_t)(_enet_addr)[0] << 40) | \ ++ ((uint64_t)(_enet_addr)[1] << 32) | \ ++ ((uint64_t)(_enet_addr)[2] << 24) | \ ++ ((uint64_t)(_enet_addr)[3] << 16) | \ ++ ((uint64_t)(_enet_addr)[4] << 8) | \ ++ ((uint64_t)(_enet_addr)[5])) ++ ++#define _MAKE_ENET_ADDR_FROM_UINT64(_addr64, _enet_addr) \ ++ do { \ ++ int i; \ ++ for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++) \ ++ (_enet_addr)[i] = (uint8_t)((_addr64) >> ((5-i)*8));\ ++ } while (0) ++ ++#endif /* __FSL_ENET_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman.h +new file mode 100755 +index 00000000..96a63fa7 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman.h +@@ -0,0 +1,825 @@ ++/* ++ * Copyright 2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __FSL_FMAN_H ++#define __FSL_FMAN_H ++ ++#include "common/general.h" ++ ++struct fman_ext_pool_params { ++ uint8_t id; /**< External buffer pool id */ ++ uint16_t size; /**< External buffer pool buffer size */ ++}; ++ ++struct fman_ext_pools { ++ uint8_t num_pools_used; /**< Number of pools use by this port */ ++ struct fman_ext_pool_params *ext_buf_pool; ++ /**< Parameters for each port */ ++}; ++ ++struct fman_backup_bm_pools { ++ uint8_t num_backup_pools; /**< Number of BM backup pools - ++ must be smaller than the total number ++ of pools defined for the specified ++ port.*/ ++ uint8_t *pool_ids; /**< numOfBackupPools pool id's, ++ specifying which pools should be used ++ only as backup. Pool id's specified ++ here must be a subset of the pools ++ used by the specified port.*/ ++}; ++ ++/**************************************************************************//** ++ @Description A structure for defining BM pool depletion criteria ++*//***************************************************************************/ ++struct fman_buf_pool_depletion { ++ bool buf_pool_depletion_enabled; ++ bool pools_grp_mode_enable; /**< select mode in which pause frames ++ will be sent after a number of pools ++ (all together!) are depleted */ ++ uint8_t num_pools; /**< the number of depleted pools that ++ will invoke pause frames transmission. ++ */ ++ bool *pools_to_consider; /**< For each pool, TRUE if it should be ++ considered for depletion (Note - this ++ pool must be used by this port!). */ ++ bool single_pool_mode_enable; /**< select mode in which pause frames ++ will be sent after a single-pool ++ is depleted; */ ++ bool *pools_to_consider_for_single_mode; ++ /**< For each pool, TRUE if it should be ++ considered for depletion (Note - this ++ pool must be used by this port!) */ ++ bool has_pfc_priorities; ++ bool *pfc_priorities_en; /**< This field is used by the MAC as ++ the Priority Enable Vector in the PFC ++ frame which is transmitted */ ++}; ++ ++/**************************************************************************//** ++ @Description Enum for defining port DMA swap mode ++*//***************************************************************************/ ++enum fman_dma_swap_option { ++ FMAN_DMA_NO_SWP, /**< No swap, transfer data as is.*/ ++ FMAN_DMA_SWP_PPC_LE, /**< The transferred data should be swapped ++ in PowerPc Little Endian mode. */ ++ FMAN_DMA_SWP_BE /**< The transferred data should be swapped ++ in Big Endian mode */ ++}; ++ ++/**************************************************************************//** ++ @Description Enum for defining port DMA cache attributes ++*//***************************************************************************/ ++enum fman_dma_cache_option { ++ FMAN_DMA_NO_STASH = 0, /**< Cacheable, no Allocate (No Stashing) */ ++ FMAN_DMA_STASH = 1 /**< Cacheable and Allocate (Stashing on) */ ++}; ++ ++typedef struct t_FmPrsResult fm_prs_result_t; ++typedef enum e_EnetMode enet_mode_t; ++typedef t_Handle handle_t; ++ ++struct fman_revision_info { ++ uint8_t majorRev; /**< Major revision */ ++ uint8_t minorRev; /**< Minor revision */ ++}; ++ ++/* sizes */ ++#define CAPWAP_FRAG_EXTRA_SPACE 32 ++#define OFFSET_UNITS 16 ++#define MAX_INT_OFFSET 240 ++#define MAX_IC_SIZE 256 ++#define MAX_EXT_OFFSET 496 ++#define MAX_EXT_BUFFER_OFFSET 511 ++ ++/************************************************************************** ++ @Description Memory Mapped Registers ++***************************************************************************/ ++#define FMAN_LIODN_TBL 64 /* size of LIODN table */ ++ ++struct fman_fpm_regs { ++ uint32_t fmfp_tnc; /**< FPM TNUM Control 0x00 */ ++ uint32_t fmfp_prc; /**< FPM Port_ID FmCtl Association 0x04 */ ++ uint32_t fmfp_brkc; /**< FPM Breakpoint Control 0x08 */ ++ uint32_t fmfp_mxd; /**< FPM Flush Control 0x0c */ ++ uint32_t fmfp_dist1; /**< FPM Dispatch Thresholds1 0x10 */ ++ uint32_t fmfp_dist2; /**< FPM Dispatch Thresholds2 0x14 */ ++ uint32_t fm_epi; /**< FM Error Pending Interrupts 0x18 */ ++ uint32_t fm_rie; /**< FM Error Interrupt Enable 0x1c */ ++ uint32_t fmfp_fcev[4]; /**< FPM FMan-Controller Event 1-4 0x20-0x2f */ ++ uint32_t res0030[4]; /**< res 0x30 - 0x3f */ ++ uint32_t fmfp_cee[4]; /**< PM FMan-Controller Event 1-4 0x40-0x4f */ ++ uint32_t res0050[4]; /**< res 0x50-0x5f */ ++ uint32_t fmfp_tsc1; /**< FPM TimeStamp Control1 0x60 */ ++ uint32_t fmfp_tsc2; /**< FPM TimeStamp Control2 0x64 */ ++ uint32_t fmfp_tsp; /**< FPM Time Stamp 0x68 */ ++ uint32_t fmfp_tsf; /**< FPM Time Stamp Fraction 0x6c */ ++ uint32_t fm_rcr; /**< FM Rams Control 0x70 */ ++ uint32_t fmfp_extc; /**< FPM External Requests Control 0x74 */ ++ uint32_t fmfp_ext1; /**< FPM External Requests Config1 0x78 */ ++ uint32_t fmfp_ext2; /**< FPM External Requests Config2 0x7c */ ++ uint32_t fmfp_drd[16]; /**< FPM Data_Ram Data 0-15 0x80 - 0xbf */ ++ uint32_t fmfp_dra; /**< FPM Data Ram Access 0xc0 */ ++ uint32_t fm_ip_rev_1; /**< FM IP Block Revision 1 0xc4 */ ++ uint32_t fm_ip_rev_2; /**< FM IP Block Revision 2 0xc8 */ ++ uint32_t fm_rstc; /**< FM Reset Command 0xcc */ ++ uint32_t fm_cld; /**< FM Classifier Debug 0xd0 */ ++ uint32_t fm_npi; /**< FM Normal Pending Interrupts 0xd4 */ ++ uint32_t fmfp_exte; /**< FPM External Requests Enable 0xd8 */ ++ uint32_t fmfp_ee; /**< FPM Event & Mask 0xdc */ ++ uint32_t fmfp_cev[4]; /**< FPM CPU Event 1-4 0xe0-0xef */ ++ uint32_t res00f0[4]; /**< res 0xf0-0xff */ ++ uint32_t fmfp_ps[64]; /**< FPM Port Status 0x100-0x1ff */ ++ uint32_t fmfp_clfabc; /**< FPM CLFABC 0x200 */ ++ uint32_t fmfp_clfcc; /**< FPM CLFCC 0x204 */ ++ uint32_t fmfp_clfaval; /**< FPM CLFAVAL 0x208 */ ++ uint32_t fmfp_clfbval; /**< FPM CLFBVAL 0x20c */ ++ uint32_t fmfp_clfcval; /**< FPM CLFCVAL 0x210 */ ++ uint32_t fmfp_clfamsk; /**< FPM CLFAMSK 0x214 */ ++ uint32_t fmfp_clfbmsk; /**< FPM CLFBMSK 0x218 */ ++ uint32_t fmfp_clfcmsk; /**< FPM CLFCMSK 0x21c */ ++ uint32_t fmfp_clfamc; /**< FPM CLFAMC 0x220 */ ++ uint32_t fmfp_clfbmc; /**< FPM CLFBMC 0x224 */ ++ uint32_t fmfp_clfcmc; /**< FPM CLFCMC 0x228 */ ++ uint32_t fmfp_decceh; /**< FPM DECCEH 0x22c */ ++ uint32_t res0230[116]; /**< res 0x230 - 0x3ff */ ++ uint32_t fmfp_ts[128]; /**< 0x400: FPM Task Status 0x400 - 0x5ff */ ++ uint32_t res0600[0x400 - 384]; ++}; ++ ++struct fman_bmi_regs { ++ uint32_t fmbm_init; /**< BMI Initialization 0x00 */ ++ uint32_t fmbm_cfg1; /**< BMI Configuration 1 0x04 */ ++ uint32_t fmbm_cfg2; /**< BMI Configuration 2 0x08 */ ++ uint32_t res000c[5]; /**< 0x0c - 0x1f */ ++ uint32_t fmbm_ievr; /**< Interrupt Event Register 0x20 */ ++ uint32_t fmbm_ier; /**< Interrupt Enable Register 0x24 */ ++ uint32_t fmbm_ifr; /**< Interrupt Force Register 0x28 */ ++ uint32_t res002c[5]; /**< 0x2c - 0x3f */ ++ uint32_t fmbm_arb[8]; /**< BMI Arbitration 0x40 - 0x5f */ ++ uint32_t res0060[12]; /**<0x60 - 0x8f */ ++ uint32_t fmbm_dtc[3]; /**< Debug Trap Counter 0x90 - 0x9b */ ++ uint32_t res009c; /**< 0x9c */ ++ uint32_t fmbm_dcv[3][4]; /**< Debug Compare val 0xa0-0xcf */ ++ uint32_t fmbm_dcm[3][4]; /**< Debug Compare Mask 0xd0-0xff */ ++ uint32_t fmbm_gde; /**< BMI Global Debug Enable 0x100 */ ++ uint32_t fmbm_pp[63]; /**< BMI Port Parameters 0x104 - 0x1ff */ ++ uint32_t res0200; /**< 0x200 */ ++ uint32_t fmbm_pfs[63]; /**< BMI Port FIFO Size 0x204 - 0x2ff */ ++ uint32_t res0300; /**< 0x300 */ ++ uint32_t fmbm_spliodn[63]; /**< Port Partition ID 0x304 - 0x3ff */ ++}; ++ ++struct fman_qmi_regs { ++ uint32_t fmqm_gc; /**< General Configuration Register 0x00 */ ++ uint32_t res0004; /**< 0x04 */ ++ uint32_t fmqm_eie; /**< Error Interrupt Event Register 0x08 */ ++ uint32_t fmqm_eien; /**< Error Interrupt Enable Register 0x0c */ ++ uint32_t fmqm_eif; /**< Error Interrupt Force Register 0x10 */ ++ uint32_t fmqm_ie; /**< Interrupt Event Register 0x14 */ ++ uint32_t fmqm_ien; /**< Interrupt Enable Register 0x18 */ ++ uint32_t fmqm_if; /**< Interrupt Force Register 0x1c */ ++ uint32_t fmqm_gs; /**< Global Status Register 0x20 */ ++ uint32_t fmqm_ts; /**< Task Status Register 0x24 */ ++ uint32_t fmqm_etfc; /**< Enqueue Total Frame Counter 0x28 */ ++ uint32_t fmqm_dtfc; /**< Dequeue Total Frame Counter 0x2c */ ++ uint32_t fmqm_dc0; /**< Dequeue Counter 0 0x30 */ ++ uint32_t fmqm_dc1; /**< Dequeue Counter 1 0x34 */ ++ uint32_t fmqm_dc2; /**< Dequeue Counter 2 0x38 */ ++ uint32_t fmqm_dc3; /**< Dequeue Counter 3 0x3c */ ++ uint32_t fmqm_dfdc; /**< Dequeue FQID from Default Counter 0x40 */ ++ uint32_t fmqm_dfcc; /**< Dequeue FQID from Context Counter 0x44 */ ++ uint32_t fmqm_dffc; /**< Dequeue FQID from FD Counter 0x48 */ ++ uint32_t fmqm_dcc; /**< Dequeue Confirm Counter 0x4c */ ++ uint32_t res0050[7]; /**< 0x50 - 0x6b */ ++ uint32_t fmqm_tapc; /**< Tnum Aging Period Control 0x6c */ ++ uint32_t fmqm_dmcvc; /**< Dequeue MAC Command Valid Counter 0x70 */ ++ uint32_t fmqm_difdcc; /**< Dequeue Invalid FD Command Counter 0x74 */ ++ uint32_t fmqm_da1v; /**< Dequeue A1 Valid Counter 0x78 */ ++ uint32_t res007c; /**< 0x7c */ ++ uint32_t fmqm_dtc; /**< 0x80 Debug Trap Counter 0x80 */ ++ uint32_t fmqm_efddd; /**< 0x84 Enqueue Frame desc Dynamic dbg 0x84 */ ++ uint32_t res0088[2]; /**< 0x88 - 0x8f */ ++ struct { ++ uint32_t fmqm_dtcfg1; /**< 0x90 dbg trap cfg 1 Register 0x00 */ ++ uint32_t fmqm_dtval1; /**< Debug Trap Value 1 Register 0x04 */ ++ uint32_t fmqm_dtm1; /**< Debug Trap Mask 1 Register 0x08 */ ++ uint32_t fmqm_dtc1; /**< Debug Trap Counter 1 Register 0x0c */ ++ uint32_t fmqm_dtcfg2; /**< dbg Trap cfg 2 Register 0x10 */ ++ uint32_t fmqm_dtval2; /**< Debug Trap Value 2 Register 0x14 */ ++ uint32_t fmqm_dtm2; /**< Debug Trap Mask 2 Register 0x18 */ ++ uint32_t res001c; /**< 0x1c */ ++ } dbg_traps[3]; /**< 0x90 - 0xef */ ++ uint8_t res00f0[0x400 - 0xf0]; /**< 0xf0 - 0x3ff */ ++}; ++ ++struct fman_dma_regs { ++ uint32_t fmdmsr; /**< FM DMA status register 0x00 */ ++ uint32_t fmdmmr; /**< FM DMA mode register 0x04 */ ++ uint32_t fmdmtr; /**< FM DMA bus threshold register 0x08 */ ++ uint32_t fmdmhy; /**< FM DMA bus hysteresis register 0x0c */ ++ uint32_t fmdmsetr; /**< FM DMA SOS emergency Threshold Register 0x10 */ ++ uint32_t fmdmtah; /**< FM DMA transfer bus address high reg 0x14 */ ++ uint32_t fmdmtal; /**< FM DMA transfer bus address low reg 0x18 */ ++ uint32_t fmdmtcid; /**< FM DMA transfer bus communication ID reg 0x1c */ ++ uint32_t fmdmra; /**< FM DMA bus internal ram address register 0x20 */ ++ uint32_t fmdmrd; /**< FM DMA bus internal ram data register 0x24 */ ++ uint32_t fmdmwcr; /**< FM DMA CAM watchdog counter value 0x28 */ ++ uint32_t fmdmebcr; /**< FM DMA CAM base in MURAM register 0x2c */ ++ uint32_t fmdmccqdr; /**< FM DMA CAM and CMD Queue Debug reg 0x30 */ ++ uint32_t fmdmccqvr1; /**< FM DMA CAM and CMD Queue Value reg #1 0x34 */ ++ uint32_t fmdmccqvr2; /**< FM DMA CAM and CMD Queue Value reg #2 0x38 */ ++ uint32_t fmdmcqvr3; /**< FM DMA CMD Queue Value register #3 0x3c */ ++ uint32_t fmdmcqvr4; /**< FM DMA CMD Queue Value register #4 0x40 */ ++ uint32_t fmdmcqvr5; /**< FM DMA CMD Queue Value register #5 0x44 */ ++ uint32_t fmdmsefrc; /**< FM DMA Semaphore Entry Full Reject Cntr 0x48 */ ++ uint32_t fmdmsqfrc; /**< FM DMA Semaphore Queue Full Reject Cntr 0x4c */ ++ uint32_t fmdmssrc; /**< FM DMA Semaphore SYNC Reject Counter 0x50 */ ++ uint32_t fmdmdcr; /**< FM DMA Debug Counter 0x54 */ ++ uint32_t fmdmemsr; /**< FM DMA Emergency Smoother Register 0x58 */ ++ uint32_t res005c; /**< 0x5c */ ++ uint32_t fmdmplr[FMAN_LIODN_TBL / 2]; /**< DMA LIODN regs 0x60-0xdf */ ++ uint32_t res00e0[0x400 - 56]; ++}; ++ ++struct fman_rg { ++ struct fman_fpm_regs *fpm_rg; ++ struct fman_dma_regs *dma_rg; ++ struct fman_bmi_regs *bmi_rg; ++ struct fman_qmi_regs *qmi_rg; ++}; ++ ++enum fman_dma_cache_override { ++ E_FMAN_DMA_NO_CACHE_OR = 0, /**< No override of the Cache field */ ++ E_FMAN_DMA_NO_STASH_DATA, /**< No data stashing in system level cache */ ++ E_FMAN_DMA_MAY_STASH_DATA, /**< Stashing allowed in sys level cache */ ++ E_FMAN_DMA_STASH_DATA /**< Stashing performed in system level cache */ ++}; ++ ++enum fman_dma_aid_mode { ++ E_FMAN_DMA_AID_OUT_PORT_ID = 0, /**< 4 LSB of PORT_ID */ ++ E_FMAN_DMA_AID_OUT_TNUM /**< 4 LSB of TNUM */ ++}; ++ ++enum fman_dma_dbg_cnt_mode { ++ E_FMAN_DMA_DBG_NO_CNT = 0, /**< No counting */ ++ E_FMAN_DMA_DBG_CNT_DONE, /**< Count DONE commands */ ++ E_FMAN_DMA_DBG_CNT_COMM_Q_EM, /**< command Q emergency signal */ ++ E_FMAN_DMA_DBG_CNT_INT_READ_EM, /**< Read buf emergency signal */ ++ E_FMAN_DMA_DBG_CNT_INT_WRITE_EM, /**< Write buf emergency signal */ ++ E_FMAN_DMA_DBG_CNT_FPM_WAIT, /**< FPM WAIT signal */ ++ E_FMAN_DMA_DBG_CNT_SIGLE_BIT_ECC, /**< Single bit ECC errors */ ++ E_FMAN_DMA_DBG_CNT_RAW_WAR_PROT /**< RAW & WAR protection counter */ ++}; ++ ++enum fman_dma_emergency_level { ++ E_FMAN_DMA_EM_EBS = 0, /**< EBS emergency */ ++ E_FMAN_DMA_EM_SOS /**< SOS emergency */ ++}; ++ ++enum fman_catastrophic_err { ++ E_FMAN_CATAST_ERR_STALL_PORT = 0, /**< Port_ID stalled reset required */ ++ E_FMAN_CATAST_ERR_STALL_TASK /**< Only erroneous task is stalled */ ++}; ++ ++enum fman_dma_err { ++ E_FMAN_DMA_ERR_CATASTROPHIC = 0, /**< Catastrophic DMA error */ ++ E_FMAN_DMA_ERR_REPORT /**< Reported DMA error */ ++}; ++ ++struct fman_cfg { ++ uint16_t liodn_bs_pr_port[FMAN_LIODN_TBL];/* base per port */ ++ bool en_counters; ++ uint8_t disp_limit_tsh; ++ uint8_t prs_disp_tsh; ++ uint8_t plcr_disp_tsh; ++ uint8_t kg_disp_tsh; ++ uint8_t bmi_disp_tsh; ++ uint8_t qmi_enq_disp_tsh; ++ uint8_t qmi_deq_disp_tsh; ++ uint8_t fm_ctl1_disp_tsh; ++ uint8_t fm_ctl2_disp_tsh; ++ enum fman_dma_cache_override dma_cache_override; ++ enum fman_dma_aid_mode dma_aid_mode; ++ bool dma_aid_override; ++ uint8_t dma_axi_dbg_num_of_beats; ++ uint8_t dma_cam_num_of_entries; ++ uint32_t dma_watchdog; ++ uint8_t dma_comm_qtsh_asrt_emer; ++ uint8_t dma_write_buf_tsh_asrt_emer; ++ uint8_t dma_read_buf_tsh_asrt_emer; ++ uint8_t dma_comm_qtsh_clr_emer; ++ uint8_t dma_write_buf_tsh_clr_emer; ++ uint8_t dma_read_buf_tsh_clr_emer; ++ uint32_t dma_sos_emergency; ++ enum fman_dma_dbg_cnt_mode dma_dbg_cnt_mode; ++ bool dma_stop_on_bus_error; ++ bool dma_en_emergency; ++ uint32_t dma_emergency_bus_select; ++ enum fman_dma_emergency_level dma_emergency_level; ++ bool dma_en_emergency_smoother; ++ uint32_t dma_emergency_switch_counter; ++ bool halt_on_external_activ; ++ bool halt_on_unrecov_ecc_err; ++ enum fman_catastrophic_err catastrophic_err; ++ enum fman_dma_err dma_err; ++ bool en_muram_test_mode; ++ bool en_iram_test_mode; ++ bool external_ecc_rams_enable; ++ uint16_t tnum_aging_period; ++ uint32_t exceptions; ++ uint16_t clk_freq; ++ bool pedantic_dma; ++ uint32_t cam_base_addr; ++ uint32_t fifo_base_addr; ++ uint32_t total_fifo_size; ++ uint8_t total_num_of_tasks; ++ bool qmi_deq_option_support; ++ uint32_t qmi_def_tnums_thresh; ++ bool fman_partition_array; ++ uint8_t num_of_fman_ctrl_evnt_regs; ++}; ++ ++/**************************************************************************//** ++ @Description Exceptions ++*//***************************************************************************/ ++#define FMAN_EX_DMA_BUS_ERROR 0x80000000 ++#define FMAN_EX_DMA_READ_ECC 0x40000000 ++#define FMAN_EX_DMA_SYSTEM_WRITE_ECC 0x20000000 ++#define FMAN_EX_DMA_FM_WRITE_ECC 0x10000000 ++#define FMAN_EX_FPM_STALL_ON_TASKS 0x08000000 ++#define FMAN_EX_FPM_SINGLE_ECC 0x04000000 ++#define FMAN_EX_FPM_DOUBLE_ECC 0x02000000 ++#define FMAN_EX_QMI_SINGLE_ECC 0x01000000 ++#define FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID 0x00800000 ++#define FMAN_EX_QMI_DOUBLE_ECC 0x00400000 ++#define FMAN_EX_BMI_LIST_RAM_ECC 0x00200000 ++#define FMAN_EX_BMI_PIPELINE_ECC 0x00100000 ++#define FMAN_EX_BMI_STATISTICS_RAM_ECC 0x00080000 ++#define FMAN_EX_IRAM_ECC 0x00040000 ++#define FMAN_EX_NURAM_ECC 0x00020000 ++#define FMAN_EX_BMI_DISPATCH_RAM_ECC 0x00010000 ++ ++enum fman_exceptions { ++ E_FMAN_EX_DMA_BUS_ERROR = 0, /**< DMA bus error. */ ++ E_FMAN_EX_DMA_READ_ECC, /**< Read Buffer ECC error */ ++ E_FMAN_EX_DMA_SYSTEM_WRITE_ECC, /**< Write Buffer ECC err on sys side */ ++ E_FMAN_EX_DMA_FM_WRITE_ECC, /**< Write Buffer ECC error on FM side */ ++ E_FMAN_EX_FPM_STALL_ON_TASKS, /**< Stall of tasks on FPM */ ++ E_FMAN_EX_FPM_SINGLE_ECC, /**< Single ECC on FPM. */ ++ E_FMAN_EX_FPM_DOUBLE_ECC, /**< Double ECC error on FPM ram access */ ++ E_FMAN_EX_QMI_SINGLE_ECC, /**< Single ECC on QMI. */ ++ E_FMAN_EX_QMI_DOUBLE_ECC, /**< Double bit ECC occurred on QMI */ ++ E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,/**< DeQ from unknown port id */ ++ E_FMAN_EX_BMI_LIST_RAM_ECC, /**< Linked List RAM ECC error */ ++ E_FMAN_EX_BMI_STORAGE_PROFILE_ECC, /**< storage profile */ ++ E_FMAN_EX_BMI_STATISTICS_RAM_ECC, /**< Statistics RAM ECC Err Enable */ ++ E_FMAN_EX_BMI_DISPATCH_RAM_ECC, /**< Dispatch RAM ECC Error Enable */ ++ E_FMAN_EX_IRAM_ECC, /**< Double bit ECC occurred on IRAM*/ ++ E_FMAN_EX_MURAM_ECC /**< Double bit ECC occurred on MURAM*/ ++}; ++ ++enum fman_counters { ++ E_FMAN_COUNTERS_ENQ_TOTAL_FRAME = 0, /**< QMI tot enQ frames counter */ ++ E_FMAN_COUNTERS_DEQ_TOTAL_FRAME, /**< QMI tot deQ frames counter */ ++ E_FMAN_COUNTERS_DEQ_0, /**< QMI 0 frames from QMan counter */ ++ E_FMAN_COUNTERS_DEQ_1, /**< QMI 1 frames from QMan counter */ ++ E_FMAN_COUNTERS_DEQ_2, /**< QMI 2 frames from QMan counter */ ++ E_FMAN_COUNTERS_DEQ_3, /**< QMI 3 frames from QMan counter */ ++ E_FMAN_COUNTERS_DEQ_FROM_DEFAULT, /**< QMI deQ from dflt queue cntr */ ++ E_FMAN_COUNTERS_DEQ_FROM_CONTEXT, /**< QMI deQ from FQ context cntr */ ++ E_FMAN_COUNTERS_DEQ_FROM_FD, /**< QMI deQ from FD command field cntr */ ++ E_FMAN_COUNTERS_DEQ_CONFIRM, /**< QMI dequeue confirm counter */ ++ E_FMAN_COUNTERS_SEMAPHOR_ENTRY_FULL_REJECT, /**< DMA full entry cntr */ ++ E_FMAN_COUNTERS_SEMAPHOR_QUEUE_FULL_REJECT, /**< DMA full CAM Q cntr */ ++ E_FMAN_COUNTERS_SEMAPHOR_SYNC_REJECT /**< DMA sync counter */ ++}; ++ ++#define FPM_PRT_FM_CTL1 0x00000001 ++#define FPM_PRT_FM_CTL2 0x00000002 ++ ++/**************************************************************************//** ++ @Description DMA definitions ++*//***************************************************************************/ ++ ++/* masks */ ++#define DMA_MODE_AID_OR 0x20000000 ++#define DMA_MODE_SBER 0x10000000 ++#define DMA_MODE_BER 0x00200000 ++#define DMA_MODE_EB 0x00100000 ++#define DMA_MODE_ECC 0x00000020 ++#define DMA_MODE_PRIVILEGE_PROT 0x00001000 ++#define DMA_MODE_SECURE_PROT 0x00000800 ++#define DMA_MODE_EMER_READ 0x00080000 ++#define DMA_MODE_EMER_WRITE 0x00040000 ++#define DMA_MODE_CACHE_OR_MASK 0xC0000000 ++#define DMA_MODE_CEN_MASK 0x0000E000 ++#define DMA_MODE_DBG_MASK 0x00000380 ++#define DMA_MODE_AXI_DBG_MASK 0x0F000000 ++ ++#define DMA_EMSR_EMSTR_MASK 0x0000FFFF ++ ++#define DMA_TRANSFER_PORTID_MASK 0xFF000000 ++#define DMA_TRANSFER_TNUM_MASK 0x00FF0000 ++#define DMA_TRANSFER_LIODN_MASK 0x00000FFF ++ ++#define DMA_HIGH_LIODN_MASK 0x0FFF0000 ++#define DMA_LOW_LIODN_MASK 0x00000FFF ++ ++#define DMA_STATUS_CMD_QUEUE_NOT_EMPTY 0x10000000 ++#define DMA_STATUS_BUS_ERR 0x08000000 ++#define DMA_STATUS_READ_ECC 0x04000000 ++#define DMA_STATUS_SYSTEM_WRITE_ECC 0x02000000 ++#define DMA_STATUS_FM_WRITE_ECC 0x01000000 ++#define DMA_STATUS_SYSTEM_DPEXT_ECC 0x00800000 ++#define DMA_STATUS_FM_DPEXT_ECC 0x00400000 ++#define DMA_STATUS_SYSTEM_DPDAT_ECC 0x00200000 ++#define DMA_STATUS_FM_DPDAT_ECC 0x00100000 ++#define DMA_STATUS_FM_SPDAT_ECC 0x00080000 ++ ++#define FM_LIODN_BASE_MASK 0x00000FFF ++ ++/* shifts */ ++#define DMA_MODE_CACHE_OR_SHIFT 30 ++#define DMA_MODE_BUS_PRI_SHIFT 16 ++#define DMA_MODE_AXI_DBG_SHIFT 24 ++#define DMA_MODE_CEN_SHIFT 13 ++#define DMA_MODE_BUS_PROT_SHIFT 10 ++#define DMA_MODE_DBG_SHIFT 7 ++#define DMA_MODE_EMER_LVL_SHIFT 6 ++#define DMA_MODE_AID_MODE_SHIFT 4 ++#define DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS 16 ++#define DMA_MODE_MAX_CAM_NUM_OF_ENTRIES 32 ++ ++#define DMA_THRESH_COMMQ_SHIFT 24 ++#define DMA_THRESH_READ_INT_BUF_SHIFT 16 ++ ++#define DMA_LIODN_SHIFT 16 ++ ++#define DMA_TRANSFER_PORTID_SHIFT 24 ++#define DMA_TRANSFER_TNUM_SHIFT 16 ++ ++/* sizes */ ++#define DMA_MAX_WATCHDOG 0xffffffff ++ ++/* others */ ++#define DMA_CAM_SIZEOF_ENTRY 0x40 ++#define DMA_CAM_ALIGN 0x1000 ++#define DMA_CAM_UNITS 8 ++ ++/**************************************************************************//** ++ @Description General defines ++*//***************************************************************************/ ++ ++#define FM_DEBUG_STATUS_REGISTER_OFFSET 0x000d1084UL ++#define FM_UCODE_DEBUG_INSTRUCTION 0x6ffff805UL ++ ++/**************************************************************************//** ++ @Description FPM defines ++*//***************************************************************************/ ++ ++/* masks */ ++#define FPM_EV_MASK_DOUBLE_ECC 0x80000000 ++#define FPM_EV_MASK_STALL 0x40000000 ++#define FPM_EV_MASK_SINGLE_ECC 0x20000000 ++#define FPM_EV_MASK_RELEASE_FM 0x00010000 ++#define FPM_EV_MASK_DOUBLE_ECC_EN 0x00008000 ++#define FPM_EV_MASK_STALL_EN 0x00004000 ++#define FPM_EV_MASK_SINGLE_ECC_EN 0x00002000 ++#define FPM_EV_MASK_EXTERNAL_HALT 0x00000008 ++#define FPM_EV_MASK_ECC_ERR_HALT 0x00000004 ++ ++#define FPM_RAM_RAMS_ECC_EN 0x80000000 ++#define FPM_RAM_IRAM_ECC_EN 0x40000000 ++#define FPM_RAM_MURAM_ECC 0x00008000 ++#define FPM_RAM_IRAM_ECC 0x00004000 ++#define FPM_RAM_MURAM_TEST_ECC 0x20000000 ++#define FPM_RAM_IRAM_TEST_ECC 0x10000000 ++#define FPM_RAM_RAMS_ECC_EN_SRC_SEL 0x08000000 ++ ++#define FPM_IRAM_ECC_ERR_EX_EN 0x00020000 ++#define FPM_MURAM_ECC_ERR_EX_EN 0x00040000 ++ ++#define FPM_REV1_MAJOR_MASK 0x0000FF00 ++#define FPM_REV1_MINOR_MASK 0x000000FF ++ ++#define FPM_REV2_INTEG_MASK 0x00FF0000 ++#define FPM_REV2_ERR_MASK 0x0000FF00 ++#define FPM_REV2_CFG_MASK 0x000000FF ++ ++#define FPM_TS_FRACTION_MASK 0x0000FFFF ++#define FPM_TS_CTL_EN 0x80000000 ++ ++#define FPM_PRC_REALSE_STALLED 0x00800000 ++ ++#define FPM_PS_STALLED 0x00800000 ++#define FPM_PS_FM_CTL1_SEL 0x80000000 ++#define FPM_PS_FM_CTL2_SEL 0x40000000 ++#define FPM_PS_FM_CTL_SEL_MASK (FPM_PS_FM_CTL1_SEL | FPM_PS_FM_CTL2_SEL) ++ ++#define FPM_RSTC_FM_RESET 0x80000000 ++#define FPM_RSTC_10G0_RESET 0x04000000 ++#define FPM_RSTC_1G0_RESET 0x40000000 ++#define FPM_RSTC_1G1_RESET 0x20000000 ++#define FPM_RSTC_1G2_RESET 0x10000000 ++#define FPM_RSTC_1G3_RESET 0x08000000 ++#define FPM_RSTC_1G4_RESET 0x02000000 ++ ++ ++#define FPM_DISP_LIMIT_MASK 0x1F000000 ++#define FPM_THR1_PRS_MASK 0xFF000000 ++#define FPM_THR1_KG_MASK 0x00FF0000 ++#define FPM_THR1_PLCR_MASK 0x0000FF00 ++#define FPM_THR1_BMI_MASK 0x000000FF ++ ++#define FPM_THR2_QMI_ENQ_MASK 0xFF000000 ++#define FPM_THR2_QMI_DEQ_MASK 0x000000FF ++#define FPM_THR2_FM_CTL1_MASK 0x00FF0000 ++#define FPM_THR2_FM_CTL2_MASK 0x0000FF00 ++ ++/* shifts */ ++#define FPM_DISP_LIMIT_SHIFT 24 ++ ++#define FPM_THR1_PRS_SHIFT 24 ++#define FPM_THR1_KG_SHIFT 16 ++#define FPM_THR1_PLCR_SHIFT 8 ++#define FPM_THR1_BMI_SHIFT 0 ++ ++#define FPM_THR2_QMI_ENQ_SHIFT 24 ++#define FPM_THR2_QMI_DEQ_SHIFT 0 ++#define FPM_THR2_FM_CTL1_SHIFT 16 ++#define FPM_THR2_FM_CTL2_SHIFT 8 ++ ++#define FPM_EV_MASK_CAT_ERR_SHIFT 1 ++#define FPM_EV_MASK_DMA_ERR_SHIFT 0 ++ ++#define FPM_REV1_MAJOR_SHIFT 8 ++#define FPM_REV1_MINOR_SHIFT 0 ++ ++#define FPM_REV2_INTEG_SHIFT 16 ++#define FPM_REV2_ERR_SHIFT 8 ++#define FPM_REV2_CFG_SHIFT 0 ++ ++#define FPM_TS_INT_SHIFT 16 ++ ++#define FPM_PORT_FM_CTL_PORTID_SHIFT 24 ++ ++#define FPM_PS_FM_CTL_SEL_SHIFT 30 ++#define FPM_PRC_ORA_FM_CTL_SEL_SHIFT 16 ++ ++#define FPM_DISP_LIMIT_SHIFT 24 ++ ++/* Interrupts defines */ ++#define FPM_EVENT_FM_CTL_0 0x00008000 ++#define FPM_EVENT_FM_CTL 0x0000FF00 ++#define FPM_EVENT_FM_CTL_BRK 0x00000080 ++ ++/* others */ ++#define FPM_MAX_DISP_LIMIT 31 ++#define FPM_RSTC_FM_RESET 0x80000000 ++#define FPM_RSTC_1G0_RESET 0x40000000 ++#define FPM_RSTC_1G1_RESET 0x20000000 ++#define FPM_RSTC_1G2_RESET 0x10000000 ++#define FPM_RSTC_1G3_RESET 0x08000000 ++#define FPM_RSTC_10G0_RESET 0x04000000 ++#define FPM_RSTC_1G4_RESET 0x02000000 ++#define FPM_RSTC_1G5_RESET 0x01000000 ++#define FPM_RSTC_1G6_RESET 0x00800000 ++#define FPM_RSTC_1G7_RESET 0x00400000 ++#define FPM_RSTC_10G1_RESET 0x00200000 ++/**************************************************************************//** ++ @Description BMI defines ++*//***************************************************************************/ ++/* masks */ ++#define BMI_INIT_START 0x80000000 ++#define BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC 0x80000000 ++#define BMI_ERR_INTR_EN_LIST_RAM_ECC 0x40000000 ++#define BMI_ERR_INTR_EN_STATISTICS_RAM_ECC 0x20000000 ++#define BMI_ERR_INTR_EN_DISPATCH_RAM_ECC 0x10000000 ++#define BMI_NUM_OF_TASKS_MASK 0x3F000000 ++#define BMI_NUM_OF_EXTRA_TASKS_MASK 0x000F0000 ++#define BMI_NUM_OF_DMAS_MASK 0x00000F00 ++#define BMI_NUM_OF_EXTRA_DMAS_MASK 0x0000000F ++#define BMI_FIFO_SIZE_MASK 0x000003FF ++#define BMI_EXTRA_FIFO_SIZE_MASK 0x03FF0000 ++#define BMI_CFG2_DMAS_MASK 0x0000003F ++#define BMI_TOTAL_FIFO_SIZE_MASK 0x07FF0000 ++#define BMI_TOTAL_NUM_OF_TASKS_MASK 0x007F0000 ++ ++/* shifts */ ++#define BMI_CFG2_TASKS_SHIFT 16 ++#define BMI_CFG2_DMAS_SHIFT 0 ++#define BMI_CFG1_FIFO_SIZE_SHIFT 16 ++#define BMI_FIFO_SIZE_SHIFT 0 ++#define BMI_EXTRA_FIFO_SIZE_SHIFT 16 ++#define BMI_NUM_OF_TASKS_SHIFT 24 ++#define BMI_EXTRA_NUM_OF_TASKS_SHIFT 16 ++#define BMI_NUM_OF_DMAS_SHIFT 8 ++#define BMI_EXTRA_NUM_OF_DMAS_SHIFT 0 ++ ++/* others */ ++#define BMI_FIFO_ALIGN 0x100 ++#define FMAN_BMI_FIFO_UNITS 0x100 ++ ++ ++/**************************************************************************//** ++ @Description QMI defines ++*//***************************************************************************/ ++/* masks */ ++#define QMI_CFG_ENQ_EN 0x80000000 ++#define QMI_CFG_DEQ_EN 0x40000000 ++#define QMI_CFG_EN_COUNTERS 0x10000000 ++#define QMI_CFG_SOFT_RESET 0x01000000 ++#define QMI_CFG_DEQ_MASK 0x0000003F ++#define QMI_CFG_ENQ_MASK 0x00003F00 ++ ++#define QMI_ERR_INTR_EN_DOUBLE_ECC 0x80000000 ++#define QMI_ERR_INTR_EN_DEQ_FROM_DEF 0x40000000 ++#define QMI_INTR_EN_SINGLE_ECC 0x80000000 ++ ++/* shifts */ ++#define QMI_CFG_ENQ_SHIFT 8 ++#define QMI_TAPC_TAP 22 ++ ++#define QMI_GS_HALT_NOT_BUSY 0x00000002 ++ ++/**************************************************************************//** ++ @Description IRAM defines ++*//***************************************************************************/ ++/* masks */ ++#define IRAM_IADD_AIE 0x80000000 ++#define IRAM_READY 0x80000000 ++ ++uint32_t fman_get_bmi_err_event(struct fman_bmi_regs *bmi_rg); ++uint32_t fman_get_qmi_err_event(struct fman_qmi_regs *qmi_rg); ++uint32_t fman_get_dma_com_id(struct fman_dma_regs *dma_rg); ++uint64_t fman_get_dma_addr(struct fman_dma_regs *dma_rg); ++uint32_t fman_get_dma_err_event(struct fman_dma_regs *dma_rg); ++uint32_t fman_get_fpm_err_event(struct fman_fpm_regs *fpm_rg); ++uint32_t fman_get_muram_err_event(struct fman_fpm_regs *fpm_rg); ++uint32_t fman_get_iram_err_event(struct fman_fpm_regs *fpm_rg); ++uint32_t fman_get_qmi_event(struct fman_qmi_regs *qmi_rg); ++uint32_t fman_get_fpm_error_interrupts(struct fman_fpm_regs *fpm_rg); ++uint32_t fman_get_ctrl_intr(struct fman_fpm_regs *fpm_rg, ++ uint8_t event_reg_id); ++uint8_t fman_get_qmi_deq_th(struct fman_qmi_regs *qmi_rg); ++uint8_t fman_get_qmi_enq_th(struct fman_qmi_regs *qmi_rg); ++uint16_t fman_get_size_of_fifo(struct fman_bmi_regs *bmi_rg, uint8_t port_id); ++uint32_t fman_get_total_fifo_size(struct fman_bmi_regs *bmi_rg); ++uint16_t fman_get_size_of_extra_fifo(struct fman_bmi_regs *bmi_rg, ++ uint8_t port_id); ++uint8_t fman_get_num_of_tasks(struct fman_bmi_regs *bmi_rg, uint8_t port_id); ++uint8_t fman_get_num_extra_tasks(struct fman_bmi_regs *bmi_rg, ++ uint8_t port_id); ++uint8_t fman_get_num_of_dmas(struct fman_bmi_regs *bmi_rg, uint8_t port_id); ++uint8_t fman_get_num_extra_dmas(struct fman_bmi_regs *bmi_rg, ++ uint8_t port_id); ++uint32_t fman_get_normal_pending(struct fman_fpm_regs *fpm_rg); ++uint32_t fman_get_controller_event(struct fman_fpm_regs *fpm_rg, ++ uint8_t reg_id); ++uint32_t fman_get_error_pending(struct fman_fpm_regs *fpm_rg); ++void fman_get_revision(struct fman_fpm_regs *fpm_rg, uint8_t *major, ++ uint8_t *minor); ++uint32_t fman_get_counter(struct fman_rg *fman_rg, ++ enum fman_counters reg_name); ++uint32_t fman_get_dma_status(struct fman_dma_regs *dma_rg); ++ ++ ++int fman_set_erratum_10gmac_a004_wa(struct fman_fpm_regs *fpm_rg); ++void fman_set_ctrl_intr(struct fman_fpm_regs *fpm_rg, uint8_t event_reg_id, ++ uint32_t enable_events); ++void fman_set_num_of_riscs_per_port(struct fman_fpm_regs *fpm_rg, ++ uint8_t port_id, ++ uint8_t num_fman_ctrls, ++ uint32_t or_fman_ctrl); ++void fman_set_order_restoration_per_port(struct fman_fpm_regs *fpm_rg, ++ uint8_t port_id, ++ bool independent_mode, ++ bool is_rx_port); ++void fman_set_qmi_enq_th(struct fman_qmi_regs *qmi_rg, uint8_t val); ++void fman_set_qmi_deq_th(struct fman_qmi_regs *qmi_rg, uint8_t val); ++void fman_set_liodn_per_port(struct fman_rg *fman_rg, ++ uint8_t port_id, ++ uint16_t liodn_base, ++ uint16_t liodn_offset); ++void fman_set_size_of_fifo(struct fman_bmi_regs *bmi_rg, ++ uint8_t port_id, ++ uint32_t size_of_fifo, ++ uint32_t extra_size_of_fifo); ++void fman_set_num_of_tasks(struct fman_bmi_regs *bmi_rg, ++ uint8_t port_id, ++ uint8_t num_of_tasks, ++ uint8_t num_of_extra_tasks); ++void fman_set_num_of_open_dmas(struct fman_bmi_regs *bmi_rg, ++ uint8_t port_id, ++ uint8_t num_of_open_dmas, ++ uint8_t num_of_extra_open_dmas, ++ uint8_t total_num_of_dmas); ++void fman_set_ports_bandwidth(struct fman_bmi_regs *bmi_rg, uint8_t *weights); ++int fman_set_exception(struct fman_rg *fman_rg, ++ enum fman_exceptions exception, ++ bool enable); ++void fman_set_dma_emergency(struct fman_dma_regs *dma_rg, bool is_write, ++ bool enable); ++void fman_set_dma_ext_bus_pri(struct fman_dma_regs *dma_rg, uint32_t pri); ++void fman_set_congestion_group_pfc_priority(uint32_t *cpg_rg, ++ uint32_t congestion_group_id, ++ uint8_t piority_bit_map, ++ uint32_t reg_num); ++ ++ ++void fman_defconfig(struct fman_cfg *cfg, bool is_master); ++void fman_regconfig(struct fman_rg *fman_rg, struct fman_cfg *cfg); ++int fman_fpm_init(struct fman_fpm_regs *fpm_rg, struct fman_cfg *cfg); ++int fman_bmi_init(struct fman_bmi_regs *bmi_rg, struct fman_cfg *cfg); ++int fman_qmi_init(struct fman_qmi_regs *qmi_rg, struct fman_cfg *cfg); ++int fman_dma_init(struct fman_dma_regs *dma_rg, struct fman_cfg *cfg); ++void fman_free_resources(struct fman_rg *fman_rg); ++int fman_enable(struct fman_rg *fman_rg, struct fman_cfg *cfg); ++void fman_reset(struct fman_fpm_regs *fpm_rg); ++void fman_resume(struct fman_fpm_regs *fpm_rg); ++ ++ ++void fman_enable_time_stamp(struct fman_fpm_regs *fpm_rg, ++ uint8_t count1ubit, ++ uint16_t fm_clk_freq); ++void fman_enable_rams_ecc(struct fman_fpm_regs *fpm_rg); ++void fman_qmi_disable_dispatch_limit(struct fman_fpm_regs *fpm_rg); ++void fman_disable_rams_ecc(struct fman_fpm_regs *fpm_rg); ++void fman_resume_stalled_port(struct fman_fpm_regs *fpm_rg, uint8_t port_id); ++int fman_reset_mac(struct fman_fpm_regs *fpm_rg, uint8_t macId, bool is_10g); ++bool fman_is_port_stalled(struct fman_fpm_regs *fpm_rg, uint8_t port_id); ++bool fman_rams_ecc_is_external_ctl(struct fman_fpm_regs *fpm_rg); ++bool fman_is_qmi_halt_not_busy_state(struct fman_qmi_regs *qmi_rg); ++int fman_modify_counter(struct fman_rg *fman_rg, ++ enum fman_counters reg_name, ++ uint32_t val); ++void fman_force_intr(struct fman_rg *fman_rg, ++ enum fman_exceptions exception); ++void fman_set_vsp_window(struct fman_bmi_regs *bmi_rg, ++ uint8_t port_id, ++ uint8_t base_storage_profile, ++ uint8_t log2_num_of_profiles); ++ ++/**************************************************************************//** ++ @Description default values ++*//***************************************************************************/ ++#define DEFAULT_CATASTROPHIC_ERR E_FMAN_CATAST_ERR_STALL_PORT ++#define DEFAULT_DMA_ERR E_FMAN_DMA_ERR_CATASTROPHIC ++#define DEFAULT_HALT_ON_EXTERNAL_ACTIVATION FALSE /* do not change! if changed, must be disabled for rev1 ! */ ++#define DEFAULT_HALT_ON_UNRECOVERABLE_ECC_ERROR FALSE /* do not change! if changed, must be disabled for rev1 ! */ ++#define DEFAULT_EXTERNAL_ECC_RAMS_ENABLE FALSE ++#define DEFAULT_AID_OVERRIDE FALSE ++#define DEFAULT_AID_MODE E_FMAN_DMA_AID_OUT_TNUM ++#define DEFAULT_DMA_COMM_Q_LOW 0x2A ++#define DEFAULT_DMA_COMM_Q_HIGH 0x3F ++#define DEFAULT_CACHE_OVERRIDE E_FMAN_DMA_NO_CACHE_OR ++#define DEFAULT_DMA_CAM_NUM_OF_ENTRIES 64 ++#define DEFAULT_DMA_DBG_CNT_MODE E_FMAN_DMA_DBG_NO_CNT ++#define DEFAULT_DMA_EN_EMERGENCY FALSE ++#define DEFAULT_DMA_SOS_EMERGENCY 0 ++#define DEFAULT_DMA_WATCHDOG 0 /* disabled */ ++#define DEFAULT_DMA_EN_EMERGENCY_SMOOTHER FALSE ++#define DEFAULT_DMA_EMERGENCY_SWITCH_COUNTER 0 ++#define DEFAULT_DISP_LIMIT 0 ++#define DEFAULT_PRS_DISP_TH 16 ++#define DEFAULT_PLCR_DISP_TH 16 ++#define DEFAULT_KG_DISP_TH 16 ++#define DEFAULT_BMI_DISP_TH 16 ++#define DEFAULT_QMI_ENQ_DISP_TH 16 ++#define DEFAULT_QMI_DEQ_DISP_TH 16 ++#define DEFAULT_FM_CTL1_DISP_TH 16 ++#define DEFAULT_FM_CTL2_DISP_TH 16 ++#define DEFAULT_TNUM_AGING_PERIOD 4 ++ ++ ++#endif /* __FSL_FMAN_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec.h +new file mode 100644 +index 00000000..6004e478 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec.h +@@ -0,0 +1,1096 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __FSL_FMAN_DTSEC_H ++#define __FSL_FMAN_DTSEC_H ++ ++#include "common/general.h" ++#include "fsl_enet.h" ++ ++/** ++ * DOC: dTSEC Init sequence ++ * ++ * To prepare dTSEC block for transfer use the following call sequence: ++ * ++ * - fman_dtsec_defconfig() - This step is optional and yet recommended. Its ++ * use is to obtain the default dTSEC configuration parameters. ++ * ++ * - Change dtsec configuration in &dtsec_cfg. This structure will be used ++ * to customize the dTSEC behavior. ++ * ++ * - fman_dtsec_init() - Applies the configuration on dTSEC hardware. Note that ++ * dTSEC is initialized while both Tx and Rx are disabled. ++ * ++ * - fman_dtsec_set_mac_address() - Set the station address (mac address). ++ * This is used by dTSEC to match against received packets. ++ * ++ * - fman_dtsec_adjust_link() - Set the link speed and duplex parameters ++ * after the PHY establishes the link. ++ * ++ * - dtsec_enable_tx() and dtsec_enable_rx() to enable transmission and ++ * reception. ++ */ ++ ++/** ++ * DOC: dTSEC Graceful stop ++ * ++ * To temporary stop dTSEC activity use fman_dtsec_stop_tx() and ++ * fman_dtsec_stop_rx(). Note that these functions request dTSEC graceful stop ++ * but return before this stop is complete. To query for graceful stop ++ * completion use fman_dtsec_get_event() and check DTSEC_IEVENT_GTSC and ++ * DTSEC_IEVENT_GRSC bits. Alternatively the dTSEC interrupt mask can be set to ++ * enable graceful stop interrupts. ++ * ++ * To resume operation after graceful stop use fman_dtsec_start_tx() and ++ * fman_dtsec_start_rx(). ++ */ ++ ++/** ++ * DOC: dTSEC interrupt handling ++ * ++ * This code does not provide an interrupt handler for dTSEC. Instead this ++ * handler should be implemented and registered to the operating system by the ++ * caller. Some primitives for accessing the event status and mask registers ++ * are provided. ++ * ++ * See "dTSEC Events" section for a list of events that dTSEC can generate. ++ */ ++ ++/** ++ * DOC: dTSEC Events ++ * ++ * Interrupt events cause dTSEC event bits to be set. Software may poll the ++ * event register at any time to check for pending interrupts. If an event ++ * occurs and its corresponding enable bit is set in the interrupt mask ++ * register, the event also causes a hardware interrupt at the PIC. ++ * ++ * To poll for event status use the fman_dtsec_get_event() function. ++ * To configure the interrupt mask use fman_dtsec_enable_interrupt() and ++ * fman_dtsec_disable_interrupt() functions. ++ * After servicing a dTSEC interrupt use fman_dtsec_ack_event to reset the ++ * serviced event bit. ++ * ++ * The following events may be signaled by dTSEC hardware: ++ * ++ * %DTSEC_IEVENT_BABR - Babbling receive error. This bit indicates that ++ * a frame was received with length in excess of the MAC's maximum frame length ++ * register. ++ * ++ * %DTSEC_IEVENT_RXC - Receive control (pause frame) interrupt. A pause ++ * control frame was received while Rx pause frame handling is enabled. ++ * Also see fman_dtsec_handle_rx_pause(). ++ * ++ * %DTSEC_IEVENT_MSRO - MIB counter overflow. The count for one of the MIB ++ * counters has exceeded the size of its register. ++ * ++ * %DTSEC_IEVENT_GTSC - Graceful transmit stop complete. Graceful stop is now ++ * complete. The transmitter is in a stopped state, in which only pause frames ++ * can be transmitted. ++ * Also see fman_dtsec_stop_tx(). ++ * ++ * %DTSEC_IEVENT_BABT - Babbling transmit error. The transmitted frame length ++ * has exceeded the value in the MAC's Maximum Frame Length register. ++ * ++ * %DTSEC_IEVENT_TXC - Transmit control (pause frame) interrupt. his bit ++ * indicates that a control frame was transmitted. ++ * ++ * %DTSEC_IEVENT_TXE - Transmit error. This bit indicates that an error ++ * occurred on the transmitted channel. This bit is set whenever any transmit ++ * error occurs which causes the dTSEC to discard all or part of a frame ++ * (LC, CRL, XFUN). ++ * ++ * %DTSEC_IEVENT_LC - Late collision. This bit indicates that a collision ++ * occurred beyond the collision window (slot time) in half-duplex mode. ++ * The frame is truncated with a bad CRC and the remainder of the frame ++ * is discarded. ++ * ++ * %DTSEC_IEVENT_CRL - Collision retry limit. is bit indicates that the number ++ * of successive transmission collisions has exceeded the MAC's half-duplex ++ * register's retransmission maximum count. The frame is discarded without ++ * being transmitted and transmission of the next frame commences. This only ++ * occurs while in half-duplex mode. ++ * The number of retransmit attempts can be set in ++ * &dtsec_halfdup_cfg.@retransmit before calling fman_dtsec_init(). ++ * ++ * %DTSEC_IEVENT_XFUN - Transmit FIFO underrun. This bit indicates that the ++ * transmit FIFO became empty before the complete frame was transmitted. ++ * The frame is truncated with a bad CRC and the remainder of the frame is ++ * discarded. ++ * ++ * %DTSEC_IEVENT_MAG - TBD ++ * ++ * %DTSEC_IEVENT_MMRD - MII management read completion. ++ * ++ * %DTSEC_IEVENT_MMWR - MII management write completion. ++ * ++ * %DTSEC_IEVENT_GRSC - Graceful receive stop complete. It allows the user to ++ * know if the system has completed the stop and it is safe to write to receive ++ * registers (status, control or configuration registers) that are used by the ++ * system during normal operation. ++ * ++ * %DTSEC_IEVENT_TDPE - Internal data error on transmit. This bit indicates ++ * that the dTSEC has detected a parity error on its stored transmit data, which ++ * is likely to compromise the validity of recently transferred frames. ++ * ++ * %DTSEC_IEVENT_RDPE - Internal data error on receive. This bit indicates that ++ * the dTSEC has detected a parity error on its stored receive data, which is ++ * likely to compromise the validity of recently transferred frames. ++ */ ++/* Interrupt Mask Register (IMASK) */ ++#define DTSEC_IMASK_BREN 0x80000000 ++#define DTSEC_IMASK_RXCEN 0x40000000 ++#define DTSEC_IMASK_MSROEN 0x04000000 ++#define DTSEC_IMASK_GTSCEN 0x02000000 ++#define DTSEC_IMASK_BTEN 0x01000000 ++#define DTSEC_IMASK_TXCEN 0x00800000 ++#define DTSEC_IMASK_TXEEN 0x00400000 ++#define DTSEC_IMASK_LCEN 0x00040000 ++#define DTSEC_IMASK_CRLEN 0x00020000 ++#define DTSEC_IMASK_XFUNEN 0x00010000 ++#define DTSEC_IMASK_ABRTEN 0x00008000 ++#define DTSEC_IMASK_IFERREN 0x00004000 ++#define DTSEC_IMASK_MAGEN 0x00000800 ++#define DTSEC_IMASK_MMRDEN 0x00000400 ++#define DTSEC_IMASK_MMWREN 0x00000200 ++#define DTSEC_IMASK_GRSCEN 0x00000100 ++#define DTSEC_IMASK_TDPEEN 0x00000002 ++#define DTSEC_IMASK_RDPEEN 0x00000001 ++ ++#define DTSEC_EVENTS_MASK \ ++ ((uint32_t)(DTSEC_IMASK_BREN | \ ++ DTSEC_IMASK_RXCEN | \ ++ DTSEC_IMASK_BTEN | \ ++ DTSEC_IMASK_TXCEN | \ ++ DTSEC_IMASK_TXEEN | \ ++ DTSEC_IMASK_ABRTEN | \ ++ DTSEC_IMASK_LCEN | \ ++ DTSEC_IMASK_CRLEN | \ ++ DTSEC_IMASK_XFUNEN | \ ++ DTSEC_IMASK_IFERREN | \ ++ DTSEC_IMASK_MAGEN | \ ++ DTSEC_IMASK_TDPEEN | \ ++ DTSEC_IMASK_RDPEEN)) ++ ++/* dtsec timestamp event bits */ ++#define TMR_PEMASK_TSREEN 0x00010000 ++#define TMR_PEVENT_TSRE 0x00010000 ++ ++/* Group address bit indication */ ++#define MAC_GROUP_ADDRESS 0x0000010000000000ULL ++/* size in bytes of L2 address */ ++#define MAC_ADDRLEN 6 ++ ++#define DEFAULT_HALFDUP_ON FALSE ++#define DEFAULT_HALFDUP_RETRANSMIT 0xf ++#define DEFAULT_HALFDUP_COLL_WINDOW 0x37 ++#define DEFAULT_HALFDUP_EXCESS_DEFER TRUE ++#define DEFAULT_HALFDUP_NO_BACKOFF FALSE ++#define DEFAULT_HALFDUP_BP_NO_BACKOFF FALSE ++#define DEFAULT_HALFDUP_ALT_BACKOFF_VAL 0x0A ++#define DEFAULT_HALFDUP_ALT_BACKOFF_EN FALSE ++#define DEFAULT_RX_DROP_BCAST FALSE ++#define DEFAULT_RX_SHORT_FRM TRUE ++#define DEFAULT_RX_LEN_CHECK FALSE ++#define DEFAULT_TX_PAD_CRC TRUE ++#define DEFAULT_TX_CRC FALSE ++#define DEFAULT_RX_CTRL_ACC FALSE ++#define DEFAULT_TX_PAUSE_TIME 0xf000 ++#define DEFAULT_TBIPA 5 ++#define DEFAULT_RX_PREPEND 0 ++#define DEFAULT_PTP_TSU_EN TRUE ++#define DEFAULT_PTP_EXCEPTION_EN TRUE ++#define DEFAULT_PREAMBLE_LEN 7 ++#define DEFAULT_RX_PREAMBLE FALSE ++#define DEFAULT_TX_PREAMBLE FALSE ++#define DEFAULT_LOOPBACK FALSE ++#define DEFAULT_RX_TIME_STAMP_EN FALSE ++#define DEFAULT_TX_TIME_STAMP_EN FALSE ++#define DEFAULT_RX_FLOW TRUE ++#define DEFAULT_TX_FLOW TRUE ++#define DEFAULT_RX_GROUP_HASH_EXD FALSE ++#define DEFAULT_TX_PAUSE_TIME_EXTD 0 ++#define DEFAULT_RX_PROMISC FALSE ++#define DEFAULT_NON_BACK_TO_BACK_IPG1 0x40 ++#define DEFAULT_NON_BACK_TO_BACK_IPG2 0x60 ++#define DEFAULT_MIN_IFG_ENFORCEMENT 0x50 ++#define DEFAULT_BACK_TO_BACK_IPG 0x60 ++#define DEFAULT_MAXIMUM_FRAME 0x600 ++#define DEFAULT_TBI_PHY_ADDR 5 ++#define DEFAULT_WAKE_ON_LAN FALSE ++ ++/* register related defines (bits, field offsets..) */ ++#define DTSEC_ID1_ID 0xffff0000 ++#define DTSEC_ID1_REV_MJ 0x0000FF00 ++#define DTSEC_ID1_REV_MN 0x000000ff ++ ++#define DTSEC_ID2_INT_REDUCED_OFF 0x00010000 ++#define DTSEC_ID2_INT_NORMAL_OFF 0x00020000 ++ ++#define DTSEC_ECNTRL_CLRCNT 0x00004000 ++#define DTSEC_ECNTRL_AUTOZ 0x00002000 ++#define DTSEC_ECNTRL_STEN 0x00001000 ++#define DTSEC_ECNTRL_CFG_RO 0x80000000 ++#define DTSEC_ECNTRL_GMIIM 0x00000040 ++#define DTSEC_ECNTRL_TBIM 0x00000020 ++#define DTSEC_ECNTRL_SGMIIM 0x00000002 ++#define DTSEC_ECNTRL_RPM 0x00000010 ++#define DTSEC_ECNTRL_R100M 0x00000008 ++#define DTSEC_ECNTRL_RMM 0x00000004 ++#define DTSEC_ECNTRL_QSGMIIM 0x00000001 ++ ++#define DTSEC_TCTRL_THDF 0x00000800 ++#define DTSEC_TCTRL_TTSE 0x00000040 ++#define DTSEC_TCTRL_GTS 0x00000020 ++#define DTSEC_TCTRL_TFC_PAUSE 0x00000010 ++ ++/* PTV offsets */ ++#define PTV_PTE_OFST 16 ++ ++#define RCTRL_CFA 0x00008000 ++#define RCTRL_GHTX 0x00000400 ++#define RCTRL_RTSE 0x00000040 ++#define RCTRL_GRS 0x00000020 ++#define RCTRL_BC_REJ 0x00000010 ++#define RCTRL_MPROM 0x00000008 ++#define RCTRL_RSF 0x00000004 ++#define RCTRL_UPROM 0x00000001 ++#define RCTRL_PROM (RCTRL_UPROM | RCTRL_MPROM) ++ ++#define TMR_CTL_ESFDP 0x00000800 ++#define TMR_CTL_ESFDE 0x00000400 ++ ++#define MACCFG1_SOFT_RESET 0x80000000 ++#define MACCFG1_LOOPBACK 0x00000100 ++#define MACCFG1_RX_FLOW 0x00000020 ++#define MACCFG1_TX_FLOW 0x00000010 ++#define MACCFG1_TX_EN 0x00000001 ++#define MACCFG1_RX_EN 0x00000004 ++#define MACCFG1_RESET_RxMC 0x00080000 ++#define MACCFG1_RESET_TxMC 0x00040000 ++#define MACCFG1_RESET_RxFUN 0x00020000 ++#define MACCFG1_RESET_TxFUN 0x00010000 ++ ++#define MACCFG2_NIBBLE_MODE 0x00000100 ++#define MACCFG2_BYTE_MODE 0x00000200 ++#define MACCFG2_PRE_AM_Rx_EN 0x00000080 ++#define MACCFG2_PRE_AM_Tx_EN 0x00000040 ++#define MACCFG2_LENGTH_CHECK 0x00000010 ++#define MACCFG2_MAGIC_PACKET_EN 0x00000008 ++#define MACCFG2_PAD_CRC_EN 0x00000004 ++#define MACCFG2_CRC_EN 0x00000002 ++#define MACCFG2_FULL_DUPLEX 0x00000001 ++ ++#define PREAMBLE_LENGTH_SHIFT 12 ++ ++#define IPGIFG_NON_BACK_TO_BACK_IPG_1_SHIFT 24 ++#define IPGIFG_NON_BACK_TO_BACK_IPG_2_SHIFT 16 ++#define IPGIFG_MIN_IFG_ENFORCEMENT_SHIFT 8 ++ ++#define IPGIFG_NON_BACK_TO_BACK_IPG_1 0x7F000000 ++#define IPGIFG_NON_BACK_TO_BACK_IPG_2 0x007F0000 ++#define IPGIFG_MIN_IFG_ENFORCEMENT 0x0000FF00 ++#define IPGIFG_BACK_TO_BACK_IPG 0x0000007F ++ ++#define HAFDUP_ALT_BEB 0x00080000 ++#define HAFDUP_BP_NO_BACKOFF 0x00040000 ++#define HAFDUP_NO_BACKOFF 0x00020000 ++#define HAFDUP_EXCESS_DEFER 0x00010000 ++#define HAFDUP_COLLISION_WINDOW 0x000003ff ++ ++#define HAFDUP_ALTERNATE_BEB_TRUNCATION_SHIFT 20 ++#define HAFDUP_RETRANSMISSION_MAX_SHIFT 12 ++#define HAFDUP_RETRANSMISSION_MAX 0x0000f000 ++ ++#define NUM_OF_HASH_REGS 8 /* Number of hash table registers */ ++ ++/* CAR1/2 bits */ ++#define DTSEC_CAR1_TR64 0x80000000 ++#define DTSEC_CAR1_TR127 0x40000000 ++#define DTSEC_CAR1_TR255 0x20000000 ++#define DTSEC_CAR1_TR511 0x10000000 ++#define DTSEC_CAR1_TRK1 0x08000000 ++#define DTSEC_CAR1_TRMAX 0x04000000 ++#define DTSEC_CAR1_TRMGV 0x02000000 ++ ++#define DTSEC_CAR1_RBYT 0x00010000 ++#define DTSEC_CAR1_RPKT 0x00008000 ++#define DTSEC_CAR1_RFCS 0x00004000 ++#define DTSEC_CAR1_RMCA 0x00002000 ++#define DTSEC_CAR1_RBCA 0x00001000 ++#define DTSEC_CAR1_RXCF 0x00000800 ++#define DTSEC_CAR1_RXPF 0x00000400 ++#define DTSEC_CAR1_RXUO 0x00000200 ++#define DTSEC_CAR1_RALN 0x00000100 ++#define DTSEC_CAR1_RFLR 0x00000080 ++#define DTSEC_CAR1_RCDE 0x00000040 ++#define DTSEC_CAR1_RCSE 0x00000020 ++#define DTSEC_CAR1_RUND 0x00000010 ++#define DTSEC_CAR1_ROVR 0x00000008 ++#define DTSEC_CAR1_RFRG 0x00000004 ++#define DTSEC_CAR1_RJBR 0x00000002 ++#define DTSEC_CAR1_RDRP 0x00000001 ++ ++#define DTSEC_CAR2_TJBR 0x00080000 ++#define DTSEC_CAR2_TFCS 0x00040000 ++#define DTSEC_CAR2_TXCF 0x00020000 ++#define DTSEC_CAR2_TOVR 0x00010000 ++#define DTSEC_CAR2_TUND 0x00008000 ++#define DTSEC_CAR2_TFRG 0x00004000 ++#define DTSEC_CAR2_TBYT 0x00002000 ++#define DTSEC_CAR2_TPKT 0x00001000 ++#define DTSEC_CAR2_TMCA 0x00000800 ++#define DTSEC_CAR2_TBCA 0x00000400 ++#define DTSEC_CAR2_TXPF 0x00000200 ++#define DTSEC_CAR2_TDFR 0x00000100 ++#define DTSEC_CAR2_TEDF 0x00000080 ++#define DTSEC_CAR2_TSCL 0x00000040 ++#define DTSEC_CAR2_TMCL 0x00000020 ++#define DTSEC_CAR2_TLCL 0x00000010 ++#define DTSEC_CAR2_TXCL 0x00000008 ++#define DTSEC_CAR2_TNCL 0x00000004 ++#define DTSEC_CAR2_TDRP 0x00000001 ++ ++#define CAM1_ERRORS_ONLY \ ++ (DTSEC_CAR1_RXPF | DTSEC_CAR1_RALN | DTSEC_CAR1_RFLR \ ++ | DTSEC_CAR1_RCDE | DTSEC_CAR1_RCSE | DTSEC_CAR1_RUND \ ++ | DTSEC_CAR1_ROVR | DTSEC_CAR1_RFRG | DTSEC_CAR1_RJBR \ ++ | DTSEC_CAR1_RDRP) ++ ++#define CAM2_ERRORS_ONLY (DTSEC_CAR2_TFCS | DTSEC_CAR2_TXPF | DTSEC_CAR2_TDRP) ++ ++/* ++ * Group of dTSEC specific counters relating to the standard RMON MIB Group 1 ++ * (or Ethernet) statistics. ++ */ ++#define CAM1_MIB_GRP_1 \ ++ (DTSEC_CAR1_RDRP | DTSEC_CAR1_RBYT | DTSEC_CAR1_RPKT | DTSEC_CAR1_RMCA\ ++ | DTSEC_CAR1_RBCA | DTSEC_CAR1_RALN | DTSEC_CAR1_RUND | DTSEC_CAR1_ROVR\ ++ | DTSEC_CAR1_RFRG | DTSEC_CAR1_RJBR \ ++ | DTSEC_CAR1_TR64 | DTSEC_CAR1_TR127 | DTSEC_CAR1_TR255 \ ++ | DTSEC_CAR1_TR511 | DTSEC_CAR1_TRMAX) ++ ++#define CAM2_MIB_GRP_1 (DTSEC_CAR2_TNCL | DTSEC_CAR2_TDRP) ++ ++/* memory map */ ++ ++struct dtsec_regs { ++ /* dTSEC General Control and Status Registers */ ++ uint32_t tsec_id; /* 0x000 ETSEC_ID register */ ++ uint32_t tsec_id2; /* 0x004 ETSEC_ID2 register */ ++ uint32_t ievent; /* 0x008 Interrupt event register */ ++ uint32_t imask; /* 0x00C Interrupt mask register */ ++ uint32_t reserved0010[1]; ++ uint32_t ecntrl; /* 0x014 E control register */ ++ uint32_t ptv; /* 0x018 Pause time value register */ ++ uint32_t tbipa; /* 0x01C TBI PHY address register */ ++ uint32_t tmr_ctrl; /* 0x020 Time-stamp Control register */ ++ uint32_t tmr_pevent; /* 0x024 Time-stamp event register */ ++ uint32_t tmr_pemask; /* 0x028 Timer event mask register */ ++ uint32_t reserved002c[5]; ++ uint32_t tctrl; /* 0x040 Transmit control register */ ++ uint32_t reserved0044[3]; ++ uint32_t rctrl; /* 0x050 Receive control register */ ++ uint32_t reserved0054[11]; ++ uint32_t igaddr[8]; /* 0x080-0x09C Individual/group address */ ++ uint32_t gaddr[8]; /* 0x0A0-0x0BC Group address registers 0-7 */ ++ uint32_t reserved00c0[16]; ++ uint32_t maccfg1; /* 0x100 MAC configuration #1 */ ++ uint32_t maccfg2; /* 0x104 MAC configuration #2 */ ++ uint32_t ipgifg; /* 0x108 IPG/IFG */ ++ uint32_t hafdup; /* 0x10C Half-duplex */ ++ uint32_t maxfrm; /* 0x110 Maximum frame */ ++ uint32_t reserved0114[10]; ++ uint32_t ifstat; /* 0x13C Interface status */ ++ uint32_t macstnaddr1; /* 0x140 Station Address,part 1 */ ++ uint32_t macstnaddr2; /* 0x144 Station Address,part 2 */ ++ struct { ++ uint32_t exact_match1; /* octets 1-4 */ ++ uint32_t exact_match2; /* octets 5-6 */ ++ } macaddr[15]; /* 0x148-0x1BC mac exact match addresses 1-15 */ ++ uint32_t reserved01c0[16]; ++ uint32_t tr64; /* 0x200 transmit and receive 64 byte frame counter */ ++ uint32_t tr127; /* 0x204 transmit and receive 65 to 127 byte frame ++ * counter */ ++ uint32_t tr255; /* 0x208 transmit and receive 128 to 255 byte frame ++ * counter */ ++ uint32_t tr511; /* 0x20C transmit and receive 256 to 511 byte frame ++ * counter */ ++ uint32_t tr1k; /* 0x210 transmit and receive 512 to 1023 byte frame ++ * counter */ ++ uint32_t trmax; /* 0x214 transmit and receive 1024 to 1518 byte frame ++ * counter */ ++ uint32_t trmgv; /* 0x218 transmit and receive 1519 to 1522 byte good ++ * VLAN frame count */ ++ uint32_t rbyt; /* 0x21C receive byte counter */ ++ uint32_t rpkt; /* 0x220 receive packet counter */ ++ uint32_t rfcs; /* 0x224 receive FCS error counter */ ++ uint32_t rmca; /* 0x228 RMCA receive multicast packet counter */ ++ uint32_t rbca; /* 0x22C receive broadcast packet counter */ ++ uint32_t rxcf; /* 0x230 receive control frame packet counter */ ++ uint32_t rxpf; /* 0x234 receive pause frame packet counter */ ++ uint32_t rxuo; /* 0x238 receive unknown OP code counter */ ++ uint32_t raln; /* 0x23C receive alignment error counter */ ++ uint32_t rflr; /* 0x240 receive frame length error counter */ ++ uint32_t rcde; /* 0x244 receive code error counter */ ++ uint32_t rcse; /* 0x248 receive carrier sense error counter */ ++ uint32_t rund; /* 0x24C receive undersize packet counter */ ++ uint32_t rovr; /* 0x250 receive oversize packet counter */ ++ uint32_t rfrg; /* 0x254 receive fragments counter */ ++ uint32_t rjbr; /* 0x258 receive jabber counter */ ++ uint32_t rdrp; /* 0x25C receive drop */ ++ uint32_t tbyt; /* 0x260 transmit byte counter */ ++ uint32_t tpkt; /* 0x264 transmit packet counter */ ++ uint32_t tmca; /* 0x268 transmit multicast packet counter */ ++ uint32_t tbca; /* 0x26C transmit broadcast packet counter */ ++ uint32_t txpf; /* 0x270 transmit pause control frame counter */ ++ uint32_t tdfr; /* 0x274 transmit deferral packet counter */ ++ uint32_t tedf; /* 0x278 transmit excessive deferral packet counter */ ++ uint32_t tscl; /* 0x27C transmit single collision packet counter */ ++ uint32_t tmcl; /* 0x280 transmit multiple collision packet counter */ ++ uint32_t tlcl; /* 0x284 transmit late collision packet counter */ ++ uint32_t txcl; /* 0x288 transmit excessive collision packet counter */ ++ uint32_t tncl; /* 0x28C transmit total collision counter */ ++ uint32_t reserved0290[1]; ++ uint32_t tdrp; /* 0x294 transmit drop frame counter */ ++ uint32_t tjbr; /* 0x298 transmit jabber frame counter */ ++ uint32_t tfcs; /* 0x29C transmit FCS error counter */ ++ uint32_t txcf; /* 0x2A0 transmit control frame counter */ ++ uint32_t tovr; /* 0x2A4 transmit oversize frame counter */ ++ uint32_t tund; /* 0x2A8 transmit undersize frame counter */ ++ uint32_t tfrg; /* 0x2AC transmit fragments frame counter */ ++ uint32_t car1; /* 0x2B0 carry register one register* */ ++ uint32_t car2; /* 0x2B4 carry register two register* */ ++ uint32_t cam1; /* 0x2B8 carry register one mask register */ ++ uint32_t cam2; /* 0x2BC carry register two mask register */ ++ uint32_t reserved02c0[848]; ++}; ++ ++/** ++ * struct dtsec_mib_grp_1_counters - MIB counter overflows ++ * ++ * @tr64: Transmit and Receive 64 byte frame count. Increment for each ++ * good or bad frame, of any type, transmitted or received, which ++ * is 64 bytes in length. ++ * @tr127: Transmit and Receive 65 to 127 byte frame count. Increments for ++ * each good or bad frame of any type, transmitted or received, ++ * which is 65-127 bytes in length. ++ * @tr255: Transmit and Receive 128 to 255 byte frame count. Increments ++ * for each good or bad frame, of any type, transmitted or ++ * received, which is 128-255 bytes in length. ++ * @tr511: Transmit and Receive 256 to 511 byte frame count. Increments ++ * for each good or bad frame, of any type, transmitted or ++ * received, which is 256-511 bytes in length. ++ * @tr1k: Transmit and Receive 512 to 1023 byte frame count. Increments ++ * for each good or bad frame, of any type, transmitted or ++ * received, which is 512-1023 bytes in length. ++ * @trmax: Transmit and Receive 1024 to 1518 byte frame count. Increments ++ * for each good or bad frame, of any type, transmitted or ++ * received, which is 1024-1518 bytes in length. ++ * @rfrg: Receive fragments count. Increments for each received frame ++ * which is less than 64 bytes in length and contains an invalid ++ * FCS. This includes integral and non-integral lengths. ++ * @rjbr: Receive jabber count. Increments for received frames which ++ * exceed 1518 (non VLAN) or 1522 (VLAN) bytes and contain an ++ * invalid FCS. This includes alignment errors. ++ * @rdrp: Receive dropped packets count. Increments for received frames ++ * which are streamed to system but are later dropped due to lack ++ * of system resources. Does not increment for frames rejected due ++ * to address filtering. ++ * @raln: Receive alignment error count. Increments for each received ++ * frame from 64 to 1518 (non VLAN) or 1522 (VLAN) which contains ++ * an invalid FCS and is not an integral number of bytes. ++ * @rund: Receive undersize packet count. Increments each time a frame is ++ * received which is less than 64 bytes in length and contains a ++ * valid FCS and is otherwise well formed. This count does not ++ * include range length errors. ++ * @rovr: Receive oversize packet count. Increments each time a frame is ++ * received which exceeded 1518 (non VLAN) or 1522 (VLAN) and ++ * contains a valid FCS and is otherwise well formed. ++ * @rbyt: Receive byte count. Increments by the byte count of frames ++ * received, including those in bad packets, excluding preamble and ++ * SFD but including FCS bytes. ++ * @rpkt: Receive packet count. Increments for each received frame ++ * (including bad packets, all unicast, broadcast, and multicast ++ * packets). ++ * @rmca: Receive multicast packet count. Increments for each multicast ++ * frame with valid CRC and of lengths 64 to 1518 (non VLAN) or ++ * 1522 (VLAN), excluding broadcast frames. This count does not ++ * include range/length errors. ++ * @rbca: Receive broadcast packet count. Increments for each broadcast ++ * frame with valid CRC and of lengths 64 to 1518 (non VLAN) or ++ * 1522 (VLAN), excluding multicast frames. Does not include ++ * range/length errors. ++ * @tdrp: Transmit drop frame count. Increments each time a memory error ++ * or an underrun has occurred. ++ * @tncl: Transmit total collision counter. Increments by the number of ++ * collisions experienced during the transmission of a frame. Does ++ * not increment for aborted frames. ++ * ++ * The structure contains a group of dTSEC HW specific counters relating to the ++ * standard RMON MIB Group 1 (or Ethernet statistics) counters. This structure ++ * is counting only the carry events of the corresponding HW counters. ++ * ++ * tr64 to trmax notes: Frame sizes specified are considered excluding preamble ++ * and SFD but including FCS bytes. ++ */ ++struct dtsec_mib_grp_1_counters { ++ uint64_t rdrp; ++ uint64_t tdrp; ++ uint64_t rbyt; ++ uint64_t rpkt; ++ uint64_t rbca; ++ uint64_t rmca; ++ uint64_t raln; ++ uint64_t rund; ++ uint64_t rovr; ++ uint64_t rfrg; ++ uint64_t rjbr; ++ uint64_t tncl; ++ uint64_t tr64; ++ uint64_t tr127; ++ uint64_t tr255; ++ uint64_t tr511; ++ uint64_t tr1k; ++ uint64_t trmax; ++}; ++ ++enum dtsec_stat_counters { ++ E_DTSEC_STAT_TR64, ++ E_DTSEC_STAT_TR127, ++ E_DTSEC_STAT_TR255, ++ E_DTSEC_STAT_TR511, ++ E_DTSEC_STAT_TR1K, ++ E_DTSEC_STAT_TRMAX, ++ E_DTSEC_STAT_TRMGV, ++ E_DTSEC_STAT_RBYT, ++ E_DTSEC_STAT_RPKT, ++ E_DTSEC_STAT_RMCA, ++ E_DTSEC_STAT_RBCA, ++ E_DTSEC_STAT_RXPF, ++ E_DTSEC_STAT_RALN, ++ E_DTSEC_STAT_RFLR, ++ E_DTSEC_STAT_RCDE, ++ E_DTSEC_STAT_RCSE, ++ E_DTSEC_STAT_RUND, ++ E_DTSEC_STAT_ROVR, ++ E_DTSEC_STAT_RFRG, ++ E_DTSEC_STAT_RJBR, ++ E_DTSEC_STAT_RDRP, ++ E_DTSEC_STAT_TFCS, ++ E_DTSEC_STAT_TBYT, ++ E_DTSEC_STAT_TPKT, ++ E_DTSEC_STAT_TMCA, ++ E_DTSEC_STAT_TBCA, ++ E_DTSEC_STAT_TXPF, ++ E_DTSEC_STAT_TNCL, ++ E_DTSEC_STAT_TDRP ++}; ++ ++enum dtsec_stat_level { ++ /* No statistics */ ++ E_MAC_STAT_NONE = 0, ++ /* Only RMON MIB group 1 (ether stats). Optimized for performance */ ++ E_MAC_STAT_MIB_GRP1, ++ /* Only error counters are available. Optimized for performance */ ++ E_MAC_STAT_PARTIAL, ++ /* All counters available. Not optimized for performance */ ++ E_MAC_STAT_FULL ++}; ++ ++ ++/** ++ * struct dtsec_cfg - dTSEC configuration ++ * ++ * @halfdup_on: Transmit half-duplex flow control, under software ++ * control for 10/100-Mbps half-duplex media. If set, ++ * back pressure is applied to media by raising carrier. ++ * @halfdup_retransmit: Number of retransmission attempts following a collision. ++ * If this is exceeded dTSEC aborts transmission due to ++ * excessive collisions. The standard specifies the ++ * attempt limit to be 15. ++ * @halfdup_coll_window:The number of bytes of the frame during which ++ * collisions may occur. The default value of 55 ++ * corresponds to the frame byte at the end of the ++ * standard 512-bit slot time window. If collisions are ++ * detected after this byte, the late collision event is ++ * asserted and transmission of current frame is aborted. ++ * @rx_drop_bcast: Discard broadcast frames. If set, all broadcast frames ++ * will be discarded by dTSEC. ++ * @rx_short_frm: Accept short frames. If set, dTSEC will accept frames ++ * of length 14..63 bytes. ++ * @rx_len_check: Length check for received frames. If set, the MAC ++ * checks the frame's length field on receive to ensure it ++ * matches the actual data field length. This only works ++ * for received frames with length field less than 1500. ++ * No check is performed for larger frames. ++ * @tx_pad_crc: Pad and append CRC. If set, the MAC pads all ++ * transmitted short frames and appends a CRC to every ++ * frame regardless of padding requirement. ++ * @tx_crc: Transmission CRC enable. If set, the MAC appends a CRC ++ * to all frames. If frames presented to the MAC have a ++ * valid length and contain a valid CRC, @tx_crc should be ++ * reset. ++ * This field is ignored if @tx_pad_crc is set. ++ * @rx_ctrl_acc: Control frame accept. If set, this overrides 802.3 ++ * standard control frame behavior, and all Ethernet frames ++ * that have an ethertype of 0x8808 are treated as normal ++ * Ethernet frames and passed up to the packet interface on ++ * a DA match. Received pause control frames are passed to ++ * the packet interface only if Rx flow control is also ++ * disabled. See fman_dtsec_handle_rx_pause() function. ++ * @tx_pause_time: Transmit pause time value. This pause value is used as ++ * part of the pause frame to be sent when a transmit pause ++ * frame is initiated. If set to 0 this disables ++ * transmission of pause frames. ++ * @rx_preamble: Receive preamble enable. If set, the MAC recovers the ++ * received Ethernet 7-byte preamble and passes it to the ++ * packet interface at the start of each received frame. ++ * This field should be reset for internal MAC loop-back ++ * mode. ++ * @tx_preamble: User defined preamble enable for transmitted frames. ++ * If set, a user-defined preamble must passed to the MAC ++ * and it is transmitted instead of the standard preamble. ++ * @preamble_len: Length, in bytes, of the preamble field preceding each ++ * Ethernet start-of-frame delimiter byte. The default ++ * value of 0x7 should be used in order to guarantee ++ * reliable operation with IEEE 802.3 compliant hardware. ++ * @rx_prepend: Packet alignment padding length. The specified number ++ * of bytes (1-31) of zero padding are inserted before the ++ * start of each received frame. For Ethernet, where ++ * optional preamble extraction is enabled, the padding ++ * appears before the preamble, otherwise the padding ++ * precedes the layer 2 header. ++ * ++ * This structure contains basic dTSEC configuration and must be passed to ++ * fman_dtsec_init() function. A default set of configuration values can be ++ * obtained by calling fman_dtsec_defconfig(). ++ */ ++struct dtsec_cfg { ++ bool halfdup_on; ++ bool halfdup_alt_backoff_en; ++ bool halfdup_excess_defer; ++ bool halfdup_no_backoff; ++ bool halfdup_bp_no_backoff; ++ uint8_t halfdup_alt_backoff_val; ++ uint16_t halfdup_retransmit; ++ uint16_t halfdup_coll_window; ++ bool rx_drop_bcast; ++ bool rx_short_frm; ++ bool rx_len_check; ++ bool tx_pad_crc; ++ bool tx_crc; ++ bool rx_ctrl_acc; ++ unsigned short tx_pause_time; ++ unsigned short tbipa; ++ bool ptp_tsu_en; ++ bool ptp_exception_en; ++ bool rx_preamble; ++ bool tx_preamble; ++ unsigned char preamble_len; ++ unsigned char rx_prepend; ++ bool loopback; ++ bool rx_time_stamp_en; ++ bool tx_time_stamp_en; ++ bool rx_flow; ++ bool tx_flow; ++ bool rx_group_hash_exd; ++ bool rx_promisc; ++ uint8_t tbi_phy_addr; ++ uint16_t tx_pause_time_extd; ++ uint16_t maximum_frame; ++ uint32_t non_back_to_back_ipg1; ++ uint32_t non_back_to_back_ipg2; ++ uint32_t min_ifg_enforcement; ++ uint32_t back_to_back_ipg; ++ bool wake_on_lan; ++}; ++ ++ ++/** ++ * fman_dtsec_defconfig() - Get default dTSEC configuration ++ * @cfg: pointer to configuration structure. ++ * ++ * Call this function to obtain a default set of configuration values for ++ * initializing dTSEC. The user can overwrite any of the values before calling ++ * fman_dtsec_init(), if specific configuration needs to be applied. ++ */ ++void fman_dtsec_defconfig(struct dtsec_cfg *cfg); ++ ++/** ++ * fman_dtsec_init() - Init dTSEC hardware block ++ * @regs: Pointer to dTSEC register block ++ * @cfg: dTSEC configuration data ++ * @iface_mode: dTSEC interface mode, the type of MAC - PHY interface. ++ * @iface_speed: 1G or 10G ++ * @macaddr: MAC station address to be assigned to the device ++ * @fm_rev_maj: major rev number ++ * @fm_rev_min: minor rev number ++ * @exceptions_mask: initial exceptions mask ++ * ++ * This function initializes dTSEC and applies basic configuration. ++ * ++ * dTSEC initialization sequence: ++ * Before enabling Rx/Tx call dtsec_set_address() to set MAC address, ++ * fman_dtsec_adjust_link() to configure interface speed and duplex and finally ++ * dtsec_enable_tx()/dtsec_enable_rx() to start transmission and reception. ++ * ++ * Returns: 0 if successful, an error code otherwise. ++ */ ++int fman_dtsec_init(struct dtsec_regs *regs, struct dtsec_cfg *cfg, ++ enum enet_interface iface_mode, ++ enum enet_speed iface_speed, ++ uint8_t *macaddr, uint8_t fm_rev_maj, ++ uint8_t fm_rev_min, ++ uint32_t exception_mask); ++ ++/** ++ * fman_dtsec_enable() - Enable dTSEC Tx and Tx ++ * @regs: Pointer to dTSEC register block ++ * @apply_rx: enable rx side ++ * @apply_tx: enable tx side ++ * ++ * This function resets Tx and Rx graceful stop bit and enables dTSEC Tx and Rx. ++ */ ++void fman_dtsec_enable(struct dtsec_regs *regs, bool apply_rx, bool apply_tx); ++ ++/** ++ * fman_dtsec_disable() - Disable dTSEC Tx and Rx ++ * @regs: Pointer to dTSEC register block ++ * @apply_rx: disable rx side ++ * @apply_tx: disable tx side ++ * ++ * This function disables Tx and Rx in dTSEC. ++ */ ++void fman_dtsec_disable(struct dtsec_regs *regs, bool apply_rx, bool apply_tx); ++ ++/** ++ * fman_dtsec_get_revision() - Get dTSEC hardware revision ++ * @regs: Pointer to dTSEC register block ++ * ++ * Returns dtsec_id content ++ * ++ * Call this function to obtain the dTSEC hardware version. ++ */ ++uint32_t fman_dtsec_get_revision(struct dtsec_regs *regs); ++ ++/** ++ * fman_dtsec_set_mac_address() - Set MAC station address ++ * @regs: Pointer to dTSEC register block ++ * @macaddr: MAC address array ++ * ++ * This function sets MAC station address. To enable unicast reception call ++ * this after fman_dtsec_init(). While promiscuous mode is disabled dTSEC will ++ * match the destination address of received unicast frames against this ++ * address. ++ */ ++void fman_dtsec_set_mac_address(struct dtsec_regs *regs, uint8_t *macaddr); ++ ++/** ++ * fman_dtsec_get_mac_address() - Query MAC station address ++ * @regs: Pointer to dTSEC register block ++ * @macaddr: MAC address array ++ */ ++void fman_dtsec_get_mac_address(struct dtsec_regs *regs, uint8_t *macaddr); ++ ++/** ++ * fman_dtsec_set_uc_promisc() - Sets unicast promiscuous mode ++ * @regs: Pointer to dTSEC register block ++ * @enable: Enable unicast promiscuous mode ++ * ++ * Use this function to enable/disable dTSEC L2 address filtering. If the ++ * address filtering is disabled all unicast packets are accepted. ++ * To set dTSEC in promiscuous mode call both fman_dtsec_set_uc_promisc() and ++ * fman_dtsec_set_mc_promisc() to disable filtering for both unicast and ++ * multicast addresses. ++ */ ++void fman_dtsec_set_uc_promisc(struct dtsec_regs *regs, bool enable); ++ ++/** ++ * fman_dtsec_set_wol() - Enable/Disable wake on lan ++ * (magic packet support) ++ * @regs: Pointer to dTSEC register block ++ * @en: Enable Wake On Lan support in dTSEC ++ * ++ */ ++void fman_dtsec_set_wol(struct dtsec_regs *regs, bool en); ++ ++/** ++ * fman_dtsec_adjust_link() - Adjust dTSEC speed/duplex settings ++ * @regs: Pointer to dTSEC register block ++ * @iface_mode: dTSEC interface mode ++ * @speed: Link speed ++ * @full_dx: True for full-duplex, false for half-duplex. ++ * ++ * This function configures the MAC to function and the desired rates. Use it ++ * to configure dTSEC after fman_dtsec_init() and whenever the link speed ++ * changes (for instance following PHY auto-negociation). ++ * ++ * Returns: 0 if successful, an error code otherwise. ++ */ ++int fman_dtsec_adjust_link(struct dtsec_regs *regs, ++ enum enet_interface iface_mode, ++ enum enet_speed speed, bool full_dx); ++ ++/** ++ * fman_dtsec_set_tbi_phy_addr() - Updates TBI address field ++ * @regs: Pointer to dTSEC register block ++ * @address: Valid PHY address in the range of 1 to 31. 0 is reserved. ++ * ++ * In SGMII mode, the dTSEC's TBIPA field must contain a valid TBI PHY address ++ * so that the associated TBI PHY (i.e. the link) may be initialized. ++ * ++ * Returns: 0 if successful, an error code otherwise. ++ */ ++int fman_dtsec_set_tbi_phy_addr(struct dtsec_regs *regs, ++ uint8_t addr); ++ ++/** ++ * fman_dtsec_set_max_frame_len() - Set max frame length ++ * @regs: Pointer to dTSEC register block ++ * @length: Max frame length. ++ * ++ * Sets maximum frame length for received and transmitted frames. Frames that ++ * exceeds this length are truncated. ++ */ ++void fman_dtsec_set_max_frame_len(struct dtsec_regs *regs, uint16_t length); ++ ++/** ++ * fman_dtsec_get_max_frame_len() - Query max frame length ++ * @regs: Pointer to dTSEC register block ++ * ++ * Returns: the current value of the maximum frame length. ++ */ ++uint16_t fman_dtsec_get_max_frame_len(struct dtsec_regs *regs); ++ ++/** ++ * fman_dtsec_handle_rx_pause() - Configure pause frame handling ++ * @regs: Pointer to dTSEC register block ++ * @en: Enable pause frame handling in dTSEC ++ * ++ * If enabled, dTSEC will handle pause frames internally. This must be disabled ++ * if dTSEC is set in half-duplex mode. ++ * If pause frame handling is disabled and &dtsec_cfg.rx_ctrl_acc is set, pause ++ * frames will be transferred to the packet interface just like regular Ethernet ++ * frames. ++ */ ++void fman_dtsec_handle_rx_pause(struct dtsec_regs *regs, bool en); ++ ++/** ++ * fman_dtsec_set_tx_pause_frames() - Configure Tx pause time ++ * @regs: Pointer to dTSEC register block ++ * @time: Time value included in pause frames ++ * ++ * Call this function to set the time value used in transmitted pause frames. ++ * If time is 0, transmission of pause frames is disabled ++ */ ++void fman_dtsec_set_tx_pause_frames(struct dtsec_regs *regs, uint16_t time); ++ ++/** ++ * fman_dtsec_ack_event() - Acknowledge handled events ++ * @regs: Pointer to dTSEC register block ++ * @ev_mask: Events to acknowledge ++ * ++ * After handling events signaled by dTSEC in either polling or interrupt mode, ++ * call this function to reset the associated status bits in dTSEC event ++ * register. ++ */ ++void fman_dtsec_ack_event(struct dtsec_regs *regs, uint32_t ev_mask); ++ ++/** ++ * fman_dtsec_get_event() - Returns currently asserted events ++ * @regs: Pointer to dTSEC register block ++ * @ev_mask: Mask of relevant events ++ * ++ * Call this function to obtain a bit-mask of events that are currently asserted ++ * in dTSEC, taken from IEVENT register. ++ * ++ * Returns: a bit-mask of events asserted in dTSEC. ++ */ ++uint32_t fman_dtsec_get_event(struct dtsec_regs *regs, uint32_t ev_mask); ++ ++/** ++ * fman_dtsec_get_interrupt_mask() - Returns a bit-mask of enabled interrupts ++ * @regs: Pointer to dTSEC register block ++ * ++ * Call this function to obtain a bit-mask of enabled interrupts ++ * in dTSEC, taken from IMASK register. ++ * ++ * Returns: a bit-mask of enabled interrupts in dTSEC. ++ */ ++uint32_t fman_dtsec_get_interrupt_mask(struct dtsec_regs *regs); ++ ++void fman_dtsec_clear_addr_in_paddr(struct dtsec_regs *regs, ++ uint8_t paddr_num); ++ ++void fman_dtsec_add_addr_in_paddr(struct dtsec_regs *regs, ++ uint64_t addr, ++ uint8_t paddr_num); ++ ++void fman_dtsec_enable_tmr_interrupt (struct dtsec_regs *regs); ++ ++void fman_dtsec_disable_tmr_interrupt(struct dtsec_regs *regs); ++ ++/** ++ * fman_dtsec_disable_interrupt() - Disables interrupts for the specified events ++ * @regs: Pointer to dTSEC register block ++ * @ev_mask: Mask of relevant events ++ * ++ * Call this function to disable interrupts in dTSEC for the specified events. ++ * To enable interrupts use fman_dtsec_enable_interrupt(). ++ */ ++void fman_dtsec_disable_interrupt(struct dtsec_regs *regs, uint32_t ev_mask); ++ ++/** ++ * fman_dtsec_enable_interrupt() - Enable interrupts for the specified events ++ * @regs: Pointer to dTSEC register block ++ * @ev_mask: Mask of relevant events ++ * ++ * Call this function to enable interrupts in dTSEC for the specified events. ++ * To disable interrupts use fman_dtsec_disable_interrupt(). ++ */ ++void fman_dtsec_enable_interrupt(struct dtsec_regs *regs, uint32_t ev_mask); ++ ++/** ++ * fman_dtsec_set_ts() - Enables dTSEC timestamps ++ * @regs: Pointer to dTSEC register block ++ * @en: true to enable timestamps, false to disable them ++ * ++ * Call this function to enable/disable dTSEC timestamps. This affects both ++ * Tx and Rx. ++ */ ++void fman_dtsec_set_ts(struct dtsec_regs *regs, bool en); ++ ++/** ++ * fman_dtsec_set_bucket() - Enables/disables a filter bucket ++ * @regs: Pointer to dTSEC register block ++ * @bucket: Bucket index ++ * @enable: true/false to enable/disable this bucket ++ * ++ * This function enables or disables the specified bucket. Enabling a bucket ++ * associated with an address configures dTSEC to accept received packets ++ * with that destination address. ++ * Multiple addresses may be associated with the same bucket. Disabling a ++ * bucket will affect all addresses associated with that bucket. A bucket that ++ * is enabled requires further filtering and verification in the upper layers ++ * ++ */ ++void fman_dtsec_set_bucket(struct dtsec_regs *regs, int bucket, bool enable); ++ ++/** ++ * dtsec_set_hash_table() - insert a crc code into thr filter table ++ * @regs: Pointer to dTSEC register block ++ * @crc: crc to insert ++ * @mcast: true is this is a multicast address ++ * @ghtx: true if we are in ghtx mode ++ * ++ * This function inserts a crc code into the filter table. ++ */ ++void fman_dtsec_set_hash_table(struct dtsec_regs *regs, uint32_t crc, ++ bool mcast, bool ghtx); ++ ++/** ++ * fman_dtsec_reset_filter_table() - Resets the address filtering table ++ * @regs: Pointer to dTSEC register block ++ * @mcast: Reset multicast entries ++ * @ucast: Reset unicast entries ++ * ++ * Resets all entries in L2 address filter table. After calling this function ++ * all buckets enabled using fman_dtsec_set_bucket() will be disabled. ++ * If dtsec_init_filter_table() was called with @unicast_hash set to false, ++ * @ucast argument is ignored. ++ * This does not affect the primary nor the 15 additional addresses configured ++ * using dtsec_set_address() or dtsec_set_match_address(). ++ */ ++void fman_dtsec_reset_filter_table(struct dtsec_regs *regs, bool mcast, ++ bool ucast); ++ ++/** ++ * fman_dtsec_set_mc_promisc() - Set multicast promiscuous mode ++ * @regs: Pointer to dTSEC register block ++ * @enable: Enable multicast promiscuous mode ++ * ++ * Call this to enable/disable L2 address filtering for multicast packets. ++ */ ++void fman_dtsec_set_mc_promisc(struct dtsec_regs *regs, bool enable); ++ ++/* statistics APIs */ ++ ++/** ++ * fman_dtsec_set_stat_level() - Enable a group of MIB statistics counters ++ * @regs: Pointer to dTSEC register block ++ * @level: Specifies a certain group of dTSEC MIB HW counters or _all_, ++ * to specify all the existing counters. ++ * If set to _none_, it disables all the counters. ++ * ++ * Enables the MIB statistics hw counters and sets up the carry interrupt ++ * masks for the counters corresponding to the @level input parameter. ++ * ++ * Returns: error if invalid @level value given. ++ */ ++int fman_dtsec_set_stat_level(struct dtsec_regs *regs, ++ enum dtsec_stat_level level); ++ ++/** ++ * fman_dtsec_reset_stat() - Completely resets all dTSEC HW counters ++ * @regs: Pointer to dTSEC register block ++ */ ++void fman_dtsec_reset_stat(struct dtsec_regs *regs); ++ ++/** ++ * fman_dtsec_get_clear_carry_regs() - Read and clear carry bits (CAR1-2 registers) ++ * @regs: Pointer to dTSEC register block ++ * @car1: car1 register value ++ * @car2: car2 register value ++ * ++ * When set, the carry bits signal that an overflow occurred on the ++ * corresponding counters. ++ * Note that the carry bits (CAR1-2 registers) will assert the ++ * %DTSEC_IEVENT_MSRO interrupt if unmasked (via CAM1-2 regs). ++ * ++ * Returns: true if overflow occurred, otherwise - false ++ */ ++bool fman_dtsec_get_clear_carry_regs(struct dtsec_regs *regs, ++ uint32_t *car1, uint32_t *car2); ++ ++uint32_t fman_dtsec_check_and_clear_tmr_event(struct dtsec_regs *regs); ++ ++uint32_t fman_dtsec_get_stat_counter(struct dtsec_regs *regs, ++ enum dtsec_stat_counters reg_name); ++ ++void fman_dtsec_start_tx(struct dtsec_regs *regs); ++void fman_dtsec_start_rx(struct dtsec_regs *regs); ++void fman_dtsec_stop_tx(struct dtsec_regs *regs); ++void fman_dtsec_stop_rx(struct dtsec_regs *regs); ++uint32_t fman_dtsec_get_rctrl(struct dtsec_regs *regs); ++ ++ ++#endif /* __FSL_FMAN_DTSEC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec_mii_acc.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec_mii_acc.h +new file mode 100644 +index 00000000..0dda09c3 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_dtsec_mii_acc.h +@@ -0,0 +1,107 @@ ++/* ++ * Copyright 2008-2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __FSL_FMAN_DTSEC_MII_ACC_H ++#define __FSL_FMAN_DTSEC_MII_ACC_H ++ ++#include "common/general.h" ++ ++ ++/* MII Management Configuration Register */ ++#define MIIMCFG_RESET_MGMT 0x80000000 ++#define MIIMCFG_MGNTCLK_MASK 0x00000007 ++#define MIIMCFG_MGNTCLK_SHIFT 0 ++ ++/* MII Management Command Register */ ++#define MIIMCOM_SCAN_CYCLE 0x00000002 ++#define MIIMCOM_READ_CYCLE 0x00000001 ++ ++/* MII Management Address Register */ ++#define MIIMADD_PHY_ADDR_SHIFT 8 ++#define MIIMADD_PHY_ADDR_MASK 0x00001f00 ++ ++#define MIIMADD_REG_ADDR_SHIFT 0 ++#define MIIMADD_REG_ADDR_MASK 0x0000001f ++ ++/* MII Management Indicator Register */ ++#define MIIMIND_BUSY 0x00000001 ++ ++ ++/* PHY Control Register */ ++#define PHY_CR_PHY_RESET 0x8000 ++#define PHY_CR_LOOPBACK 0x4000 ++#define PHY_CR_SPEED0 0x2000 ++#define PHY_CR_ANE 0x1000 ++#define PHY_CR_RESET_AN 0x0200 ++#define PHY_CR_FULLDUPLEX 0x0100 ++#define PHY_CR_SPEED1 0x0040 ++ ++#define PHY_TBICON_SRESET 0x8000 ++#define PHY_TBICON_SPEED2 0x0020 ++#define PHY_TBICON_CLK_SEL 0x0020 ++#define PHY_TBIANA_SGMII 0x4001 ++#define PHY_TBIANA_1000X 0x01a0 ++/* register map */ ++ ++/* MII Configuration Control Memory Map Registers */ ++struct dtsec_mii_reg { ++ uint32_t reserved1[72]; ++ uint32_t miimcfg; /* MII Mgmt:configuration */ ++ uint32_t miimcom; /* MII Mgmt:command */ ++ uint32_t miimadd; /* MII Mgmt:address */ ++ uint32_t miimcon; /* MII Mgmt:control 3 */ ++ uint32_t miimstat; /* MII Mgmt:status */ ++ uint32_t miimind; /* MII Mgmt:indicators */ ++}; ++ ++/* dTSEC MII API */ ++ ++/* functions to access the mii registers for phy configuration. ++ * this functionality may not be available for all dtsecs in the system. ++ * consult the reference manual for details */ ++void fman_dtsec_mii_reset(struct dtsec_mii_reg *regs); ++/* frequency is in MHz. ++ * note that dtsec clock is 1/2 of fman clock */ ++void fman_dtsec_mii_init(struct dtsec_mii_reg *regs, uint16_t dtsec_freq); ++int fman_dtsec_mii_write_reg(struct dtsec_mii_reg *regs, ++ uint8_t addr, ++ uint8_t reg, ++ uint16_t data, ++ uint16_t dtsec_freq); ++ ++int fman_dtsec_mii_read_reg(struct dtsec_mii_reg *regs, ++ uint8_t addr, ++ uint8_t reg, ++ uint16_t *data, ++ uint16_t dtsec_freq); ++ ++#endif /* __FSL_FMAN_DTSEC_MII_ACC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_kg.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_kg.h +new file mode 100644 +index 00000000..010e4b70 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_kg.h +@@ -0,0 +1,514 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __FSL_FMAN_KG_H ++#define __FSL_FMAN_KG_H ++ ++#include "common/general.h" ++ ++#define FM_KG_NUM_OF_GENERIC_REGS 8 /**< Num of generic KeyGen regs */ ++#define FMAN_MAX_NUM_OF_HW_PORTS 64 ++/**< Total num of masks allowed on KG extractions */ ++#define FM_KG_EXTRACT_MASKS_NUM 4 ++#define FM_KG_NUM_CLS_PLAN_ENTR 8 /**< Num of class. plan regs */ ++#define FM_KG_CLS_PLAN_GRPS_NUM 32 /**< Max num of class. groups */ ++ ++struct fman_kg_regs { ++ uint32_t fmkg_gcr; ++ uint32_t res004; ++ uint32_t res008; ++ uint32_t fmkg_eer; ++ uint32_t fmkg_eeer; ++ uint32_t res014; ++ uint32_t res018; ++ uint32_t fmkg_seer; ++ uint32_t fmkg_seeer; ++ uint32_t fmkg_gsr; ++ uint32_t fmkg_tpc; ++ uint32_t fmkg_serc; ++ uint32_t res030[4]; ++ uint32_t fmkg_fdor; ++ uint32_t fmkg_gdv0r; ++ uint32_t fmkg_gdv1r; ++ uint32_t res04c[6]; ++ uint32_t fmkg_feer; ++ uint32_t res068[38]; ++ uint32_t fmkg_indirect[63]; ++ uint32_t fmkg_ar; ++}; ++ ++struct fman_kg_scheme_regs { ++ uint32_t kgse_mode; /**< MODE */ ++ uint32_t kgse_ekfc; /**< Extract Known Fields Command */ ++ uint32_t kgse_ekdv; /**< Extract Known Default Value */ ++ uint32_t kgse_bmch; /**< Bit Mask Command High */ ++ uint32_t kgse_bmcl; /**< Bit Mask Command Low */ ++ uint32_t kgse_fqb; /**< Frame Queue Base */ ++ uint32_t kgse_hc; /**< Hash Command */ ++ uint32_t kgse_ppc; /**< Policer Profile Command */ ++ uint32_t kgse_gec[FM_KG_NUM_OF_GENERIC_REGS]; ++ /**< Generic Extract Command */ ++ uint32_t kgse_spc; /**< KeyGen Scheme Entry Statistic Packet Counter */ ++ uint32_t kgse_dv0; /**< KeyGen Scheme Entry Default Value 0 */ ++ uint32_t kgse_dv1; /**< KeyGen Scheme Entry Default Value 1 */ ++ uint32_t kgse_ccbs; /**< KeyGen Scheme Entry Coarse Classification Bit*/ ++ uint32_t kgse_mv; /**< KeyGen Scheme Entry Match vector */ ++ uint32_t kgse_om; /**< KeyGen Scheme Entry Operation Mode bits */ ++ uint32_t kgse_vsp; /**< KeyGen Scheme Entry Virtual Storage Profile */ ++}; ++ ++struct fman_kg_pe_regs{ ++ uint32_t fmkg_pe_sp; ++ uint32_t fmkg_pe_cpp; ++}; ++ ++struct fman_kg_cp_regs { ++ uint32_t kgcpe[FM_KG_NUM_CLS_PLAN_ENTR]; ++}; ++ ++ ++#define FM_KG_KGAR_GO 0x80000000 ++#define FM_KG_KGAR_READ 0x40000000 ++#define FM_KG_KGAR_WRITE 0x00000000 ++#define FM_KG_KGAR_SEL_SCHEME_ENTRY 0x00000000 ++#define FM_KG_KGAR_SCM_WSEL_UPDATE_CNT 0x00008000 ++ ++#define KG_SCH_PP_SHIFT_HIGH 0x80000000 ++#define KG_SCH_PP_NO_GEN 0x10000000 ++#define KG_SCH_PP_SHIFT_LOW 0x0000F000 ++#define KG_SCH_MODE_NIA_PLCR 0x40000000 ++#define KG_SCH_GEN_EXTRACT_TYPE 0x00008000 ++#define KG_SCH_BITMASK_MASK 0x000000FF ++#define KG_SCH_GEN_VALID 0x80000000 ++#define KG_SCH_GEN_MASK 0x00FF0000 ++#define FM_PCD_KG_KGAR_ERR 0x20000000 ++#define FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY 0x01000000 ++#define FM_PCD_KG_KGAR_SEL_PORT_ENTRY 0x02000000 ++#define FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP 0x00008000 ++#define FM_PCD_KG_KGAR_SEL_PORT_WSEL_CPP 0x00004000 ++#define FM_PCD_KG_KGAR_WSEL_MASK 0x0000FF00 ++#define KG_SCH_HASH_CONFIG_NO_FQID 0x80000000 ++#define KG_SCH_HASH_CONFIG_SYM 0x40000000 ++ ++#define FM_EX_KG_DOUBLE_ECC 0x80000000 ++#define FM_EX_KG_KEYSIZE_OVERFLOW 0x40000000 ++ ++/* ECC capture register */ ++#define KG_FMKG_SERC_CAP 0x80000000 ++#define KG_FMKG_SERC_CET 0x40000000 ++#define KG_FMKG_SERC_CNT_MSK 0x00FF0000 ++#define KG_FMKG_SERC_CNT_SHIFT 16 ++#define KG_FMKG_SERC_ADDR_MSK 0x000003FF ++ ++/* Masks */ ++#define FM_KG_KGGCR_EN 0x80000000 ++#define KG_SCH_GEN_VALID 0x80000000 ++#define KG_SCH_GEN_EXTRACT_TYPE 0x00008000 ++#define KG_ERR_TYPE_DOUBLE 0x40000000 ++#define KG_ERR_ADDR_MASK 0x00000FFF ++#define KG_SCH_MODE_EN 0x80000000 ++ ++/* shifts */ ++#define FM_KG_KGAR_NUM_SHIFT 16 ++#define FM_KG_PE_CPP_MASK_SHIFT 16 ++#define FM_KG_KGAR_WSEL_SHIFT 8 ++ ++#define FM_KG_SCH_GEN_HT_INVALID 0 ++ ++#define FM_KG_MASK_SEL_GEN_BASE 0x20 ++ ++#define KG_GET_MASK_SEL_SHIFT(shift, i) \ ++switch (i) \ ++{ \ ++ case 0: (shift) = 26; break; \ ++ case 1: (shift) = 20; break; \ ++ case 2: (shift) = 10; break; \ ++ case 3: (shift) = 4; break; \ ++ default: (shift) = 0; \ ++} ++ ++#define KG_GET_MASK_OFFSET_SHIFT(shift, i) \ ++switch (i) \ ++{ \ ++ case 0: (shift) = 16; break; \ ++ case 1: (shift) = 0; break; \ ++ case 2: (shift) = 28; break; \ ++ case 3: (shift) = 24; break; \ ++ default: (shift) = 0; \ ++} ++ ++#define KG_GET_MASK_SHIFT(shift, i) \ ++switch (i) \ ++{ \ ++ case 0: shift = 24; break; \ ++ case 1: shift = 16; break; \ ++ case 2: shift = 8; break; \ ++ case 3: shift = 0; break; \ ++ default: shift = 0; \ ++} ++ ++/* Port entry CPP register */ ++#define FMAN_KG_PE_CPP_MASK_SHIFT 16 ++ ++/* Scheme registers */ ++#define FMAN_KG_SCH_MODE_EN 0x80000000 ++#define FMAN_KG_SCH_MODE_NIA_PLCR 0x40000000 ++#define FMAN_KG_SCH_MODE_CCOBASE_SHIFT 24 ++ ++#define FMAN_KG_SCH_DEF_MAC_ADDR_SHIFT 30 ++#define FMAN_KG_SCH_DEF_VLAN_TCI_SHIFT 28 ++#define FMAN_KG_SCH_DEF_ETYPE_SHIFT 26 ++#define FMAN_KG_SCH_DEF_PPP_SID_SHIFT 24 ++#define FMAN_KG_SCH_DEF_PPP_PID_SHIFT 22 ++#define FMAN_KG_SCH_DEF_MPLS_SHIFT 20 ++#define FMAN_KG_SCH_DEF_IP_ADDR_SHIFT 18 ++#define FMAN_KG_SCH_DEF_PTYPE_SHIFT 16 ++#define FMAN_KG_SCH_DEF_IP_TOS_TC_SHIFT 14 ++#define FMAN_KG_SCH_DEF_IPv6_FL_SHIFT 12 ++#define FMAN_KG_SCH_DEF_IPSEC_SPI_SHIFT 10 ++#define FMAN_KG_SCH_DEF_L4_PORT_SHIFT 8 ++#define FMAN_KG_SCH_DEF_TCP_FLG_SHIFT 6 ++ ++#define FMAN_KG_SCH_GEN_VALID 0x80000000 ++#define FMAN_KG_SCH_GEN_SIZE_MAX 16 ++#define FMAN_KG_SCH_GEN_OR 0x00008000 ++ ++#define FMAN_KG_SCH_GEN_DEF_SHIFT 29 ++#define FMAN_KG_SCH_GEN_SIZE_SHIFT 24 ++#define FMAN_KG_SCH_GEN_MASK_SHIFT 16 ++#define FMAN_KG_SCH_GEN_HT_SHIFT 8 ++ ++#define FMAN_KG_SCH_HASH_HSHIFT_SHIFT 24 ++#define FMAN_KG_SCH_HASH_HSHIFT_MAX 0x28 ++#define FMAN_KG_SCH_HASH_SYM 0x40000000 ++#define FMAN_KG_SCH_HASH_NO_FQID_GEN 0x80000000 ++ ++#define FMAN_KG_SCH_PP_SH_SHIFT 27 ++#define FMAN_KG_SCH_PP_SL_SHIFT 12 ++#define FMAN_KG_SCH_PP_SH_MASK 0x80000000 ++#define FMAN_KG_SCH_PP_SL_MASK 0x0000F000 ++#define FMAN_KG_SCH_PP_SHIFT_MAX 0x17 ++#define FMAN_KG_SCH_PP_MASK_SHIFT 16 ++#define FMAN_KG_SCH_PP_NO_GEN 0x10000000 ++ ++enum fman_kg_gen_extract_src { ++ E_FMAN_KG_GEN_EXTRACT_ETH, ++ E_FMAN_KG_GEN_EXTRACT_ETYPE, ++ E_FMAN_KG_GEN_EXTRACT_SNAP, ++ E_FMAN_KG_GEN_EXTRACT_VLAN_TCI_1, ++ E_FMAN_KG_GEN_EXTRACT_VLAN_TCI_N, ++ E_FMAN_KG_GEN_EXTRACT_PPPoE, ++ E_FMAN_KG_GEN_EXTRACT_MPLS_1, ++ E_FMAN_KG_GEN_EXTRACT_MPLS_2, ++ E_FMAN_KG_GEN_EXTRACT_MPLS_3, ++ E_FMAN_KG_GEN_EXTRACT_MPLS_N, ++ E_FMAN_KG_GEN_EXTRACT_IPv4_1, ++ E_FMAN_KG_GEN_EXTRACT_IPv6_1, ++ E_FMAN_KG_GEN_EXTRACT_IPv4_2, ++ E_FMAN_KG_GEN_EXTRACT_IPv6_2, ++ E_FMAN_KG_GEN_EXTRACT_MINENCAP, ++ E_FMAN_KG_GEN_EXTRACT_IP_PID, ++ E_FMAN_KG_GEN_EXTRACT_GRE, ++ E_FMAN_KG_GEN_EXTRACT_TCP, ++ E_FMAN_KG_GEN_EXTRACT_UDP, ++ E_FMAN_KG_GEN_EXTRACT_SCTP, ++ E_FMAN_KG_GEN_EXTRACT_DCCP, ++ E_FMAN_KG_GEN_EXTRACT_IPSEC_AH, ++ E_FMAN_KG_GEN_EXTRACT_IPSEC_ESP, ++ E_FMAN_KG_GEN_EXTRACT_SHIM_1, ++ E_FMAN_KG_GEN_EXTRACT_SHIM_2, ++ E_FMAN_KG_GEN_EXTRACT_FROM_DFLT, ++ E_FMAN_KG_GEN_EXTRACT_FROM_FRAME_START, ++ E_FMAN_KG_GEN_EXTRACT_FROM_PARSE_RESULT, ++ E_FMAN_KG_GEN_EXTRACT_FROM_END_OF_PARSE, ++ E_FMAN_KG_GEN_EXTRACT_FROM_FQID ++}; ++ ++struct fman_kg_ex_ecc_attr ++{ ++ bool valid; ++ bool double_ecc; ++ uint16_t addr; ++ uint8_t single_ecc_count; ++}; ++ ++enum fman_kg_def_select ++{ ++ E_FMAN_KG_DEF_GLOBAL_0, ++ E_FMAN_KG_DEF_GLOBAL_1, ++ E_FMAN_KG_DEF_SCHEME_0, ++ E_FMAN_KG_DEF_SCHEME_1 ++}; ++ ++struct fman_kg_extract_def ++{ ++ enum fman_kg_def_select mac_addr; ++ enum fman_kg_def_select vlan_tci; ++ enum fman_kg_def_select etype; ++ enum fman_kg_def_select ppp_sid; ++ enum fman_kg_def_select ppp_pid; ++ enum fman_kg_def_select mpls; ++ enum fman_kg_def_select ip_addr; ++ enum fman_kg_def_select ptype; ++ enum fman_kg_def_select ip_tos_tc; ++ enum fman_kg_def_select ipv6_fl; ++ enum fman_kg_def_select ipsec_spi; ++ enum fman_kg_def_select l4_port; ++ enum fman_kg_def_select tcp_flg; ++}; ++ ++enum fman_kg_gen_extract_type ++{ ++ E_FMAN_KG_HASH_EXTRACT, ++ E_FMAN_KG_OR_EXTRACT ++}; ++ ++struct fman_kg_gen_extract_params ++{ ++ /* Hash or Or-ed extract */ ++ enum fman_kg_gen_extract_type type; ++ enum fman_kg_gen_extract_src src; ++ bool no_validation; ++ /* Extraction offset from the header location specified above */ ++ uint8_t offset; ++ /* Size of extraction for FMAN_KG_HASH_EXTRACT, ++ * hash result shift for FMAN_KG_OR_EXTRACT */ ++ uint8_t extract; ++ uint8_t mask; ++ /* Default value to use when header specified ++ * by fman_kg_gen_extract_src doesn't present */ ++ enum fman_kg_def_select def_val; ++}; ++ ++struct fman_kg_extract_mask ++{ ++ /**< Indication if mask is on known field extraction or ++ * on general extraction; TRUE for known field */ ++ bool is_known; ++ /**< One of FMAN_KG_EXTRACT_xxx defines for known fields mask and ++ * generic register index for generic extracts mask */ ++ uint32_t field_or_gen_idx; ++ /**< Byte offset from start of the extracted data specified ++ * by field_or_gen_idx */ ++ uint8_t offset; ++ /**< Byte mask (selected bits will be used) */ ++ uint8_t mask; ++}; ++ ++struct fman_kg_extract_params ++{ ++ /* Or-ed mask of FMAN_KG_EXTRACT_xxx defines */ ++ uint32_t known_fields; ++ struct fman_kg_extract_def known_fields_def; ++ /* Number of entries in gen_extract */ ++ uint8_t gen_extract_num; ++ struct fman_kg_gen_extract_params gen_extract[FM_KG_NUM_OF_GENERIC_REGS]; ++ /* Number of entries in masks */ ++ uint8_t masks_num; ++ struct fman_kg_extract_mask masks[FM_KG_EXTRACT_MASKS_NUM]; ++ uint32_t def_scheme_0; ++ uint32_t def_scheme_1; ++}; ++ ++struct fman_kg_hash_params ++{ ++ bool use_hash; ++ uint8_t shift_r; ++ uint32_t mask; /**< 24-bit mask */ ++ bool sym; /**< Symmetric hash for src and dest pairs */ ++}; ++ ++struct fman_kg_pp_params ++{ ++ uint8_t base; ++ uint8_t shift; ++ uint8_t mask; ++ bool bypass_pp_gen; ++}; ++ ++struct fman_kg_cc_params ++{ ++ uint8_t base_offset; ++ uint32_t qlcv_bits_sel; ++}; ++ ++enum fman_pcd_engine ++{ ++ E_FMAN_PCD_INVALID = 0, /**< Invalid PCD engine indicated*/ ++ E_FMAN_PCD_DONE, /**< No PCD Engine indicated */ ++ E_FMAN_PCD_KG, /**< Keygen indicated */ ++ E_FMAN_PCD_CC, /**< Coarse classification indicated */ ++ E_FMAN_PCD_PLCR, /**< Policer indicated */ ++ E_FMAN_PCD_PRS /**< Parser indicated */ ++}; ++ ++struct fman_kg_cls_plan_params ++{ ++ uint8_t entries_mask; ++ uint32_t mask_vector[FM_KG_NUM_CLS_PLAN_ENTR]; ++}; ++ ++struct fman_kg_scheme_params ++{ ++ uint32_t match_vector; ++ struct fman_kg_extract_params extract_params; ++ struct fman_kg_hash_params hash_params; ++ uint32_t base_fqid; ++ /* What we do w/features supported per FM version ?? */ ++ bool bypass_fqid_gen; ++ struct fman_kg_pp_params policer_params; ++ struct fman_kg_cc_params cc_params; ++ bool update_counter; ++ /**< counter_value: Set scheme counter to the specified value; ++ * relevant only when update_counter = TRUE. */ ++ uint32_t counter_value; ++ enum fman_pcd_engine next_engine; ++ /**< Next engine action code */ ++ uint32_t next_engine_action; ++}; ++ ++ ++ ++int fman_kg_write_ar_wait(struct fman_kg_regs *regs, uint32_t fmkg_ar); ++void fman_kg_write_sp(struct fman_kg_regs *regs, uint32_t sp, bool add); ++void fman_kg_write_cpp(struct fman_kg_regs *regs, uint32_t cpp); ++void fman_kg_get_event(struct fman_kg_regs *regs, ++ uint32_t *event, ++ uint32_t *scheme_idx); ++void fman_kg_init(struct fman_kg_regs *regs, ++ uint32_t exceptions, ++ uint32_t dflt_nia); ++void fman_kg_enable_scheme_interrupts(struct fman_kg_regs *regs); ++void fman_kg_enable(struct fman_kg_regs *regs); ++void fman_kg_disable(struct fman_kg_regs *regs); ++int fman_kg_write_bind_cls_plans(struct fman_kg_regs *regs, ++ uint8_t hwport_id, ++ uint32_t bind_cls_plans); ++int fman_kg_build_bind_cls_plans(uint8_t grp_base, ++ uint8_t grp_mask, ++ uint32_t *bind_cls_plans); ++int fman_kg_write_bind_schemes(struct fman_kg_regs *regs, ++ uint8_t hwport_id, ++ uint32_t schemes); ++int fman_kg_write_cls_plan(struct fman_kg_regs *regs, ++ uint8_t grp_id, ++ uint8_t entries_mask, ++ uint8_t hwport_id, ++ struct fman_kg_cp_regs *cls_plan_regs); ++int fman_kg_build_cls_plan(struct fman_kg_cls_plan_params *params, ++ struct fman_kg_cp_regs *cls_plan_regs); ++uint32_t fman_kg_get_schemes_total_counter(struct fman_kg_regs *regs); ++int fman_kg_set_scheme_counter(struct fman_kg_regs *regs, ++ uint8_t scheme_id, ++ uint8_t hwport_id, ++ uint32_t counter); ++int fman_kg_get_scheme_counter(struct fman_kg_regs *regs, ++ uint8_t scheme_id, ++ uint8_t hwport_id, ++ uint32_t *counter); ++int fman_kg_delete_scheme(struct fman_kg_regs *regs, ++ uint8_t scheme_id, ++ uint8_t hwport_id); ++int fman_kg_write_scheme(struct fman_kg_regs *regs, ++ uint8_t scheme_id, ++ uint8_t hwport_id, ++ struct fman_kg_scheme_regs *scheme_regs, ++ bool update_counter); ++int fman_kg_build_scheme(struct fman_kg_scheme_params *params, ++ struct fman_kg_scheme_regs *scheme_regs); ++void fman_kg_get_capture(struct fman_kg_regs *regs, ++ struct fman_kg_ex_ecc_attr *ecc_attr, ++ bool clear); ++void fman_kg_get_exception(struct fman_kg_regs *regs, ++ uint32_t *events, ++ uint32_t *scheme_ids, ++ bool clear); ++void fman_kg_set_exception(struct fman_kg_regs *regs, ++ uint32_t exception, ++ bool enable); ++void fman_kg_set_dflt_val(struct fman_kg_regs *regs, ++ uint8_t def_id, ++ uint32_t val); ++void fman_kg_set_data_after_prs(struct fman_kg_regs *regs, uint8_t offset); ++ ++ ++ ++/**************************************************************************//** ++ @Description NIA Description ++*//***************************************************************************/ ++#define KG_NIA_ORDER_RESTOR 0x00800000 ++#define KG_NIA_ENG_FM_CTL 0x00000000 ++#define KG_NIA_ENG_PRS 0x00440000 ++#define KG_NIA_ENG_KG 0x00480000 ++#define KG_NIA_ENG_PLCR 0x004C0000 ++#define KG_NIA_ENG_BMI 0x00500000 ++#define KG_NIA_ENG_QMI_ENQ 0x00540000 ++#define KG_NIA_ENG_QMI_DEQ 0x00580000 ++#define KG_NIA_ENG_MASK 0x007C0000 ++ ++#define KG_NIA_AC_MASK 0x0003FFFF ++ ++#define KG_NIA_INVALID 0xFFFFFFFF ++ ++static __inline__ uint32_t fm_kg_build_nia(enum fman_pcd_engine next_engine, ++ uint32_t next_engine_action) ++{ ++ uint32_t nia; ++ ++ if (next_engine_action & ~KG_NIA_AC_MASK) ++ return KG_NIA_INVALID; ++ ++ switch (next_engine) { ++ case E_FMAN_PCD_DONE: ++ nia = KG_NIA_ENG_BMI | next_engine_action; ++ break; ++ ++ case E_FMAN_PCD_KG: ++ nia = KG_NIA_ENG_KG | next_engine_action; ++ break; ++ ++ case E_FMAN_PCD_CC: ++ nia = KG_NIA_ENG_FM_CTL | next_engine_action; ++ break; ++ ++ case E_FMAN_PCD_PLCR: ++ nia = KG_NIA_ENG_PLCR | next_engine_action; ++ break; ++ ++ default: ++ nia = KG_NIA_INVALID; ++ } ++ ++ return nia; ++} ++ ++#endif /* __FSL_FMAN_KG_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac.h +new file mode 100644 +index 00000000..0dd8286b +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac.h +@@ -0,0 +1,427 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#ifndef __FSL_FMAN_MEMAC_H ++#define __FSL_FMAN_MEMAC_H ++ ++#include "common/general.h" ++#include "fsl_enet.h" ++ ++ ++#define MEMAC_NUM_OF_PADDRS 7 /* Num of additional exact match MAC adr regs */ ++ ++/* Control and Configuration Register (COMMAND_CONFIG) */ ++#define CMD_CFG_MG 0x80000000 /* 00 Magic Packet detection */ ++#define CMD_CFG_REG_LOWP_RXETY 0x01000000 /* 07 Rx low power indication */ ++#define CMD_CFG_TX_LOWP_ENA 0x00800000 /* 08 Tx Low Power Idle Enable */ ++#define CMD_CFG_SFD_ANY 0x00200000 /* 10 Disable SFD check */ ++#define CMD_CFG_PFC_MODE 0x00080000 /* 12 Enable PFC */ ++#define CMD_CFG_NO_LEN_CHK 0x00020000 /* 14 Payload length check disable */ ++#define CMD_CFG_SEND_IDLE 0x00010000 /* 15 Force idle generation */ ++#define CMD_CFG_CNT_FRM_EN 0x00002000 /* 18 Control frame rx enable */ ++#define CMD_CFG_SW_RESET 0x00001000 /* 19 S/W Reset, self clearing bit */ ++#define CMD_CFG_TX_PAD_EN 0x00000800 /* 20 Enable Tx padding of frames */ ++#define CMD_CFG_LOOPBACK_EN 0x00000400 /* 21 XGMII/GMII loopback enable */ ++#define CMD_CFG_TX_ADDR_INS 0x00000200 /* 22 Tx source MAC addr insertion */ ++#define CMD_CFG_PAUSE_IGNORE 0x00000100 /* 23 Ignore Pause frame quanta */ ++#define CMD_CFG_PAUSE_FWD 0x00000080 /* 24 Terminate/frwd Pause frames */ ++#define CMD_CFG_CRC_FWD 0x00000040 /* 25 Terminate/frwd CRC of frames */ ++#define CMD_CFG_PAD_EN 0x00000020 /* 26 Frame padding removal */ ++#define CMD_CFG_PROMIS_EN 0x00000010 /* 27 Promiscuous operation enable */ ++#define CMD_CFG_WAN_MODE 0x00000008 /* 28 WAN mode enable */ ++#define CMD_CFG_RX_EN 0x00000002 /* 30 MAC receive path enable */ ++#define CMD_CFG_TX_EN 0x00000001 /* 31 MAC transmit path enable */ ++ ++/* Transmit FIFO Sections Register (TX_FIFO_SECTIONS) */ ++#define TX_FIFO_SECTIONS_TX_EMPTY_MASK 0xFFFF0000 ++#define TX_FIFO_SECTIONS_TX_AVAIL_MASK 0x0000FFFF ++#define TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G 0x00400000 ++#define TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G 0x00100000 ++#define TX_FIFO_SECTIONS_TX_EMPTY_PFC_10G 0x00360000 ++#define TX_FIFO_SECTIONS_TX_EMPTY_PFC_1G 0x00040000 ++#define TX_FIFO_SECTIONS_TX_AVAIL_10G 0x00000019 ++#define TX_FIFO_SECTIONS_TX_AVAIL_1G 0x00000020 ++#define TX_FIFO_SECTIONS_TX_AVAIL_SLOW_10G 0x00000060 ++ ++#define GET_TX_EMPTY_DEFAULT_VALUE(_val) \ ++_val &= ~TX_FIFO_SECTIONS_TX_EMPTY_MASK; \ ++((_val == TX_FIFO_SECTIONS_TX_AVAIL_10G) ? \ ++ (_val |= TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G) : \ ++ (_val |= TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G)); ++ ++#define GET_TX_EMPTY_PFC_VALUE(_val) \ ++_val &= ~TX_FIFO_SECTIONS_TX_EMPTY_MASK; \ ++((_val == TX_FIFO_SECTIONS_TX_AVAIL_10G) ? \ ++ (_val |= TX_FIFO_SECTIONS_TX_EMPTY_PFC_10G) : \ ++ (_val |= TX_FIFO_SECTIONS_TX_EMPTY_PFC_1G)); ++ ++/* Interface Mode Register (IF_MODE) */ ++#define IF_MODE_MASK 0x00000003 /* 30-31 Mask on i/f mode bits */ ++#define IF_MODE_XGMII 0x00000000 /* 30-31 XGMII (10G) interface */ ++#define IF_MODE_GMII 0x00000002 /* 30-31 GMII (1G) interface */ ++#define IF_MODE_RGMII 0x00000004 ++#define IF_MODE_RGMII_AUTO 0x00008000 ++#define IF_MODE_RGMII_1000 0x00004000 /* 10 - 1000Mbps RGMII */ ++#define IF_MODE_RGMII_100 0x00000000 /* 00 - 100Mbps RGMII */ ++#define IF_MODE_RGMII_10 0x00002000 /* 01 - 10Mbps RGMII */ ++#define IF_MODE_RGMII_SP_MASK 0x00006000 /* Setsp mask bits */ ++#define IF_MODE_RGMII_FD 0x00001000 /* Full duplex RGMII */ ++#define IF_MODE_HD 0x00000040 /* Half duplex operation */ ++ ++/* Hash table Control Register (HASHTABLE_CTRL) */ ++#define HASH_CTRL_MCAST_SHIFT 26 ++#define HASH_CTRL_MCAST_EN 0x00000100 /* 23 Mcast frame rx for hash */ ++#define HASH_CTRL_ADDR_MASK 0x0000003F /* 26-31 Hash table address code */ ++ ++#define GROUP_ADDRESS 0x0000010000000000LL /* MAC mcast indication */ ++#define HASH_TABLE_SIZE 64 /* Hash tbl size */ ++ ++/* Transmit Inter-Packet Gap Length Register (TX_IPG_LENGTH) */ ++#define MEMAC_TX_IPG_LENGTH_MASK 0x0000003F ++ ++/* Statistics Configuration Register (STATN_CONFIG) */ ++#define STATS_CFG_CLR 0x00000004 /* 29 Reset all counters */ ++#define STATS_CFG_CLR_ON_RD 0x00000002 /* 30 Clear on read */ ++#define STATS_CFG_SATURATE 0x00000001 /* 31 Saturate at the maximum val */ ++ ++/* Interrupt Mask Register (IMASK) */ ++#define MEMAC_IMASK_MGI 0x40000000 /* 1 Magic pkt detect indication */ ++#define MEMAC_IMASK_TSECC_ER 0x20000000 /* 2 Timestamp FIFO ECC error evnt */ ++#define MEMAC_IMASK_TECC_ER 0x02000000 /* 6 Transmit frame ECC error evnt */ ++#define MEMAC_IMASK_RECC_ER 0x01000000 /* 7 Receive frame ECC error evnt */ ++ ++#define MEMAC_ALL_ERRS_IMASK \ ++ ((uint32_t)(MEMAC_IMASK_TSECC_ER | \ ++ MEMAC_IMASK_TECC_ER | \ ++ MEMAC_IMASK_RECC_ER | \ ++ MEMAC_IMASK_MGI)) ++ ++#define MEMAC_IEVNT_PCS 0x80000000 /* PCS (XG). Link sync (G) */ ++#define MEMAC_IEVNT_AN 0x40000000 /* Auto-negotiation */ ++#define MEMAC_IEVNT_LT 0x20000000 /* Link Training/New page */ ++#define MEMAC_IEVNT_MGI 0x00004000 /* Magic pkt detection */ ++#define MEMAC_IEVNT_TS_ECC_ER 0x00002000 /* Timestamp FIFO ECC error */ ++#define MEMAC_IEVNT_RX_FIFO_OVFL 0x00001000 /* Rx FIFO overflow */ ++#define MEMAC_IEVNT_TX_FIFO_UNFL 0x00000800 /* Tx FIFO underflow */ ++#define MEMAC_IEVNT_TX_FIFO_OVFL 0x00000400 /* Tx FIFO overflow */ ++#define MEMAC_IEVNT_TX_ECC_ER 0x00000200 /* Tx frame ECC error */ ++#define MEMAC_IEVNT_RX_ECC_ER 0x00000100 /* Rx frame ECC error */ ++#define MEMAC_IEVNT_LI_FAULT 0x00000080 /* Link Interruption flt */ ++#define MEMAC_IEVNT_RX_EMPTY 0x00000040 /* Rx FIFO empty */ ++#define MEMAC_IEVNT_TX_EMPTY 0x00000020 /* Tx FIFO empty */ ++#define MEMAC_IEVNT_RX_LOWP 0x00000010 /* Low Power Idle */ ++#define MEMAC_IEVNT_PHY_LOS 0x00000004 /* Phy loss of signal */ ++#define MEMAC_IEVNT_REM_FAULT 0x00000002 /* Remote fault (XGMII) */ ++#define MEMAC_IEVNT_LOC_FAULT 0x00000001 /* Local fault (XGMII) */ ++ ++enum memac_counters { ++ E_MEMAC_COUNTER_R64, ++ E_MEMAC_COUNTER_R127, ++ E_MEMAC_COUNTER_R255, ++ E_MEMAC_COUNTER_R511, ++ E_MEMAC_COUNTER_R1023, ++ E_MEMAC_COUNTER_R1518, ++ E_MEMAC_COUNTER_R1519X, ++ E_MEMAC_COUNTER_RFRG, ++ E_MEMAC_COUNTER_RJBR, ++ E_MEMAC_COUNTER_RDRP, ++ E_MEMAC_COUNTER_RALN, ++ E_MEMAC_COUNTER_TUND, ++ E_MEMAC_COUNTER_ROVR, ++ E_MEMAC_COUNTER_RXPF, ++ E_MEMAC_COUNTER_TXPF, ++ E_MEMAC_COUNTER_ROCT, ++ E_MEMAC_COUNTER_RMCA, ++ E_MEMAC_COUNTER_RBCA, ++ E_MEMAC_COUNTER_RPKT, ++ E_MEMAC_COUNTER_RUCA, ++ E_MEMAC_COUNTER_RERR, ++ E_MEMAC_COUNTER_TOCT, ++ E_MEMAC_COUNTER_TMCA, ++ E_MEMAC_COUNTER_TBCA, ++ E_MEMAC_COUNTER_TUCA, ++ E_MEMAC_COUNTER_TERR ++}; ++ ++#define DEFAULT_PAUSE_QUANTA 0xf000 ++#define DEFAULT_FRAME_LENGTH 0x600 ++#define DEFAULT_TX_IPG_LENGTH 12 ++ ++/* ++ * memory map ++ */ ++ ++struct mac_addr { ++ uint32_t mac_addr_l; /* Lower 32 bits of 48-bit MAC address */ ++ uint32_t mac_addr_u; /* Upper 16 bits of 48-bit MAC address */ ++}; ++ ++struct memac_regs { ++ /* General Control and Status */ ++ uint32_t res0000[2]; ++ uint32_t command_config; /* 0x008 Ctrl and cfg */ ++ struct mac_addr mac_addr0; /* 0x00C-0x010 MAC_ADDR_0...1 */ ++ uint32_t maxfrm; /* 0x014 Max frame length */ ++ uint32_t res0018[1]; ++ uint32_t rx_fifo_sections; /* Receive FIFO configuration reg */ ++ uint32_t tx_fifo_sections; /* Transmit FIFO configuration reg */ ++ uint32_t res0024[2]; ++ uint32_t hashtable_ctrl; /* 0x02C Hash table control */ ++ uint32_t res0030[4]; ++ uint32_t ievent; /* 0x040 Interrupt event */ ++ uint32_t tx_ipg_length; /* 0x044 Transmitter inter-packet-gap */ ++ uint32_t res0048; ++ uint32_t imask; /* 0x04C Interrupt mask */ ++ uint32_t res0050; ++ uint32_t pause_quanta[4]; /* 0x054 Pause quanta */ ++ uint32_t pause_thresh[4]; /* 0x064 Pause quanta threshold */ ++ uint32_t rx_pause_status; /* 0x074 Receive pause status */ ++ uint32_t res0078[2]; ++ struct mac_addr mac_addr[MEMAC_NUM_OF_PADDRS]; /* 0x80-0x0B4 mac padr */ ++ uint32_t lpwake_timer; /* 0x0B8 Low Power Wakeup Timer */ ++ uint32_t sleep_timer; /* 0x0BC Transmit EEE Low Power Timer */ ++ uint32_t res00c0[8]; ++ uint32_t statn_config; /* 0x0E0 Statistics configuration */ ++ uint32_t res00e4[7]; ++ /* Rx Statistics Counter */ ++ uint32_t reoct_l; ++ uint32_t reoct_u; ++ uint32_t roct_l; ++ uint32_t roct_u; ++ uint32_t raln_l; ++ uint32_t raln_u; ++ uint32_t rxpf_l; ++ uint32_t rxpf_u; ++ uint32_t rfrm_l; ++ uint32_t rfrm_u; ++ uint32_t rfcs_l; ++ uint32_t rfcs_u; ++ uint32_t rvlan_l; ++ uint32_t rvlan_u; ++ uint32_t rerr_l; ++ uint32_t rerr_u; ++ uint32_t ruca_l; ++ uint32_t ruca_u; ++ uint32_t rmca_l; ++ uint32_t rmca_u; ++ uint32_t rbca_l; ++ uint32_t rbca_u; ++ uint32_t rdrp_l; ++ uint32_t rdrp_u; ++ uint32_t rpkt_l; ++ uint32_t rpkt_u; ++ uint32_t rund_l; ++ uint32_t rund_u; ++ uint32_t r64_l; ++ uint32_t r64_u; ++ uint32_t r127_l; ++ uint32_t r127_u; ++ uint32_t r255_l; ++ uint32_t r255_u; ++ uint32_t r511_l; ++ uint32_t r511_u; ++ uint32_t r1023_l; ++ uint32_t r1023_u; ++ uint32_t r1518_l; ++ uint32_t r1518_u; ++ uint32_t r1519x_l; ++ uint32_t r1519x_u; ++ uint32_t rovr_l; ++ uint32_t rovr_u; ++ uint32_t rjbr_l; ++ uint32_t rjbr_u; ++ uint32_t rfrg_l; ++ uint32_t rfrg_u; ++ uint32_t rcnp_l; ++ uint32_t rcnp_u; ++ uint32_t rdrntp_l; ++ uint32_t rdrntp_u; ++ uint32_t res01d0[12]; ++ /* Tx Statistics Counter */ ++ uint32_t teoct_l; ++ uint32_t teoct_u; ++ uint32_t toct_l; ++ uint32_t toct_u; ++ uint32_t res0210[2]; ++ uint32_t txpf_l; ++ uint32_t txpf_u; ++ uint32_t tfrm_l; ++ uint32_t tfrm_u; ++ uint32_t tfcs_l; ++ uint32_t tfcs_u; ++ uint32_t tvlan_l; ++ uint32_t tvlan_u; ++ uint32_t terr_l; ++ uint32_t terr_u; ++ uint32_t tuca_l; ++ uint32_t tuca_u; ++ uint32_t tmca_l; ++ uint32_t tmca_u; ++ uint32_t tbca_l; ++ uint32_t tbca_u; ++ uint32_t res0258[2]; ++ uint32_t tpkt_l; ++ uint32_t tpkt_u; ++ uint32_t tund_l; ++ uint32_t tund_u; ++ uint32_t t64_l; ++ uint32_t t64_u; ++ uint32_t t127_l; ++ uint32_t t127_u; ++ uint32_t t255_l; ++ uint32_t t255_u; ++ uint32_t t511_l; ++ uint32_t t511_u; ++ uint32_t t1023_l; ++ uint32_t t1023_u; ++ uint32_t t1518_l; ++ uint32_t t1518_u; ++ uint32_t t1519x_l; ++ uint32_t t1519x_u; ++ uint32_t res02a8[6]; ++ uint32_t tcnp_l; ++ uint32_t tcnp_u; ++ uint32_t res02c8[14]; ++ /* Line Interface Control */ ++ uint32_t if_mode; /* 0x300 Interface Mode Control */ ++ uint32_t if_status; /* 0x304 Interface Status */ ++ uint32_t res0308[14]; ++ /* HiGig/2 */ ++ uint32_t hg_config; /* 0x340 Control and cfg */ ++ uint32_t res0344[3]; ++ uint32_t hg_pause_quanta; /* 0x350 Pause quanta */ ++ uint32_t res0354[3]; ++ uint32_t hg_pause_thresh; /* 0x360 Pause quanta threshold */ ++ uint32_t res0364[3]; ++ uint32_t hgrx_pause_status; /* 0x370 Receive pause status */ ++ uint32_t hg_fifos_status; /* 0x374 fifos status */ ++ uint32_t rhm; /* 0x378 rx messages counter */ ++ uint32_t thm; /* 0x37C tx messages counter */ ++}; ++ ++struct memac_cfg { ++ bool reset_on_init; ++ bool rx_error_discard; ++ bool pause_ignore; ++ bool pause_forward_enable; ++ bool no_length_check_enable; ++ bool cmd_frame_enable; ++ bool send_idle_enable; ++ bool wan_mode_enable; ++ bool promiscuous_mode_enable; ++ bool tx_addr_ins_enable; ++ bool loopback_enable; ++ bool lgth_check_nostdr; ++ bool time_stamp_enable; ++ bool pad_enable; ++ bool phy_tx_ena_on; ++ bool rx_sfd_any; ++ bool rx_pbl_fwd; ++ bool tx_pbl_fwd; ++ bool debug_mode; ++ bool wake_on_lan; ++ uint16_t max_frame_length; ++ uint16_t pause_quanta; ++ uint32_t tx_ipg_length; ++}; ++ ++ ++/** ++ * fman_memac_defconfig() - Get default MEMAC configuration ++ * @cfg: pointer to configuration structure. ++ * ++ * Call this function to obtain a default set of configuration values for ++ * initializing MEMAC. The user can overwrite any of the values before calling ++ * fman_memac_init(), if specific configuration needs to be applied. ++ */ ++void fman_memac_defconfig(struct memac_cfg *cfg); ++ ++int fman_memac_init(struct memac_regs *regs, ++ struct memac_cfg *cfg, ++ enum enet_interface enet_interface, ++ enum enet_speed enet_speed, ++ bool slow_10g_if, ++ uint32_t exceptions); ++ ++void fman_memac_enable(struct memac_regs *regs, bool apply_rx, bool apply_tx); ++ ++void fman_memac_disable(struct memac_regs *regs, bool apply_rx, bool apply_tx); ++ ++void fman_memac_set_promiscuous(struct memac_regs *regs, bool val); ++ ++void fman_memac_add_addr_in_paddr(struct memac_regs *regs, ++ uint8_t *adr, ++ uint8_t paddr_num); ++ ++void fman_memac_clear_addr_in_paddr(struct memac_regs *regs, ++ uint8_t paddr_num); ++ ++uint64_t fman_memac_get_counter(struct memac_regs *regs, ++ enum memac_counters reg_name); ++ ++void fman_memac_set_tx_pause_frames(struct memac_regs *regs, ++ uint8_t priority, uint16_t pauseTime, uint16_t threshTime); ++ ++uint16_t fman_memac_get_max_frame_len(struct memac_regs *regs); ++ ++void fman_memac_set_exception(struct memac_regs *regs, uint32_t val, ++ bool enable); ++ ++void fman_memac_reset_stat(struct memac_regs *regs); ++ ++void fman_memac_reset(struct memac_regs *regs); ++ ++void fman_memac_reset_filter_table(struct memac_regs *regs); ++ ++void fman_memac_set_hash_table_entry(struct memac_regs *regs, uint32_t crc); ++ ++void fman_memac_set_hash_table(struct memac_regs *regs, uint32_t val); ++ ++void fman_memac_set_rx_ignore_pause_frames(struct memac_regs *regs, ++ bool enable); ++ ++void fman_memac_set_wol(struct memac_regs *regs, bool enable); ++ ++uint32_t fman_memac_get_event(struct memac_regs *regs, uint32_t ev_mask); ++ ++void fman_memac_ack_event(struct memac_regs *regs, uint32_t ev_mask); ++ ++uint32_t fman_memac_get_interrupt_mask(struct memac_regs *regs); ++ ++void fman_memac_adjust_link(struct memac_regs *regs, ++ enum enet_interface iface_mode, ++ enum enet_speed speed, bool full_dx); ++ ++ ++ ++#endif /*__FSL_FMAN_MEMAC_H*/ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac_mii_acc.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac_mii_acc.h +new file mode 100755 +index 00000000..b4304450 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_memac_mii_acc.h +@@ -0,0 +1,78 @@ ++/* ++ * Copyright 2008-2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __FSL_FMAN_MEMAC_MII_ACC_H ++#define __FSL_FMAN_MEMAC_MII_ACC_H ++ ++#include "common/general.h" ++#include "fsl_enet.h" ++/* MII Management Registers */ ++#define MDIO_CFG_CLK_DIV_MASK 0x0080ff80 ++#define MDIO_CFG_CLK_DIV_SHIFT 7 ++#define MDIO_CFG_HOLD_MASK 0x0000001c ++#define MDIO_CFG_ENC45 0x00000040 ++#define MDIO_CFG_READ_ERR 0x00000002 ++#define MDIO_CFG_BSY 0x00000001 ++ ++#define MDIO_CTL_PHY_ADDR_SHIFT 5 ++#define MDIO_CTL_READ 0x00008000 ++ ++#define MDIO_DATA_BSY 0x80000000 ++ ++/*MEMAC Internal PHY Registers - SGMII */ ++#define PHY_SGMII_CR_PHY_RESET 0x8000 ++#define PHY_SGMII_CR_RESET_AN 0x0200 ++#define PHY_SGMII_CR_DEF_VAL 0x1140 ++#define PHY_SGMII_DEV_ABILITY_SGMII 0x4001 ++#define PHY_SGMII_DEV_ABILITY_1000X 0x01A0 ++#define PHY_SGMII_IF_MODE_AN 0x0002 ++#define PHY_SGMII_IF_MODE_SGMII 0x0001 ++#define PHY_SGMII_IF_MODE_1000X 0x0000 ++ ++/*----------------------------------------------------*/ ++/* MII Configuration Control Memory Map Registers */ ++/*----------------------------------------------------*/ ++struct memac_mii_access_mem_map { ++ uint32_t mdio_cfg; /* 0x030 */ ++ uint32_t mdio_ctrl; /* 0x034 */ ++ uint32_t mdio_data; /* 0x038 */ ++ uint32_t mdio_addr; /* 0x03c */ ++}; ++ ++int fman_memac_mii_read_phy_reg(struct memac_mii_access_mem_map *mii_regs, ++ uint8_t phy_addr, uint8_t reg, uint16_t *data, ++ enum enet_speed enet_speed); ++int fman_memac_mii_write_phy_reg(struct memac_mii_access_mem_map *mii_regs, ++ uint8_t phy_addr, uint8_t reg, uint16_t data, ++ enum enet_speed enet_speed); ++ ++#endif /* __MAC_API_MEMAC_MII_ACC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_port.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_port.h +new file mode 100755 +index 00000000..080a23e9 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_port.h +@@ -0,0 +1,593 @@ ++/* ++ * Copyright 2008-2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __FSL_FMAN_PORT_H ++#define __FSL_FMAN_PORT_H ++ ++#include "fsl_fman_sp.h" ++ ++/** @Collection Registers bit fields */ ++ ++/** @Description BMI defines */ ++#define BMI_EBD_EN 0x80000000 ++ ++#define BMI_PORT_CFG_EN 0x80000000 ++#define BMI_PORT_CFG_FDOVR 0x02000000 ++#define BMI_PORT_CFG_IM 0x01000000 ++ ++#define BMI_PORT_STATUS_BSY 0x80000000 ++ ++#define BMI_DMA_ATTR_SWP_SHIFT FMAN_SP_DMA_ATTR_SWP_SHIFT ++#define BMI_DMA_ATTR_IC_STASH_ON 0x10000000 ++#define BMI_DMA_ATTR_HDR_STASH_ON 0x04000000 ++#define BMI_DMA_ATTR_SG_STASH_ON 0x01000000 ++#define BMI_DMA_ATTR_WRITE_OPTIMIZE FMAN_SP_DMA_ATTR_WRITE_OPTIMIZE ++ ++#define BMI_RX_FIFO_PRI_ELEVATION_SHIFT 16 ++#define BMI_RX_FIFO_THRESHOLD_ETHE 0x80000000 ++ ++#define BMI_TX_FRAME_END_CS_IGNORE_SHIFT 24 ++#define BMI_RX_FRAME_END_CS_IGNORE_SHIFT 24 ++#define BMI_RX_FRAME_END_CUT_SHIFT 16 ++ ++#define BMI_IC_TO_EXT_SHIFT FMAN_SP_IC_TO_EXT_SHIFT ++#define BMI_IC_FROM_INT_SHIFT FMAN_SP_IC_FROM_INT_SHIFT ++ ++#define BMI_INT_BUF_MARG_SHIFT 28 ++#define BMI_EXT_BUF_MARG_START_SHIFT FMAN_SP_EXT_BUF_MARG_START_SHIFT ++ ++#define BMI_CMD_MR_LEAC 0x00200000 ++#define BMI_CMD_MR_SLEAC 0x00100000 ++#define BMI_CMD_MR_MA 0x00080000 ++#define BMI_CMD_MR_DEAS 0x00040000 ++#define BMI_CMD_RX_MR_DEF (BMI_CMD_MR_LEAC | \ ++ BMI_CMD_MR_SLEAC | \ ++ BMI_CMD_MR_MA | \ ++ BMI_CMD_MR_DEAS) ++#define BMI_CMD_TX_MR_DEF 0 ++#define BMI_CMD_OP_MR_DEF (BMI_CMD_MR_DEAS | \ ++ BMI_CMD_MR_MA) ++ ++#define BMI_CMD_ATTR_ORDER 0x80000000 ++#define BMI_CMD_ATTR_SYNC 0x02000000 ++#define BMI_CMD_ATTR_COLOR_SHIFT 26 ++ ++#define BMI_FIFO_PIPELINE_DEPTH_SHIFT 12 ++#define BMI_NEXT_ENG_FD_BITS_SHIFT 24 ++#define BMI_FRAME_END_CS_IGNORE_SHIFT 24 ++ ++#define BMI_COUNTERS_EN 0x80000000 ++ ++#define BMI_EXT_BUF_POOL_VALID FMAN_SP_EXT_BUF_POOL_VALID ++#define BMI_EXT_BUF_POOL_EN_COUNTER FMAN_SP_EXT_BUF_POOL_EN_COUNTER ++#define BMI_EXT_BUF_POOL_BACKUP FMAN_SP_EXT_BUF_POOL_BACKUP ++#define BMI_EXT_BUF_POOL_ID_SHIFT 16 ++#define BMI_EXT_BUF_POOL_ID_MASK 0x003F0000 ++#define BMI_POOL_DEP_NUM_OF_POOLS_SHIFT 16 ++ ++#define BMI_TX_FIFO_MIN_FILL_SHIFT 16 ++#define BMI_TX_FIFO_PIPELINE_DEPTH_SHIFT 12 ++ ++#define MAX_PERFORMANCE_TASK_COMP 64 ++#define MAX_PERFORMANCE_RX_QUEUE_COMP 64 ++#define MAX_PERFORMANCE_TX_QUEUE_COMP 8 ++#define MAX_PERFORMANCE_DMA_COMP 16 ++#define MAX_PERFORMANCE_FIFO_COMP 1024 ++ ++#define BMI_PERFORMANCE_TASK_COMP_SHIFT 24 ++#define BMI_PERFORMANCE_QUEUE_COMP_SHIFT 16 ++#define BMI_PERFORMANCE_DMA_COMP_SHIFT 12 ++ ++#define BMI_RATE_LIMIT_GRAN_TX 16000 /* In Kbps */ ++#define BMI_RATE_LIMIT_GRAN_OP 10000 /* In frames */ ++#define BMI_RATE_LIMIT_MAX_RATE_IN_GRAN_UNITS 1024 ++#define BMI_RATE_LIMIT_MAX_BURST_SIZE 1024 /* In KBytes */ ++#define BMI_RATE_LIMIT_MAX_BURST_SHIFT 16 ++#define BMI_RATE_LIMIT_HIGH_BURST_SIZE_GRAN 0x80000000 ++#define BMI_RATE_LIMIT_SCALE_TSBS_SHIFT 16 ++#define BMI_RATE_LIMIT_SCALE_EN 0x80000000 ++#define BMI_SG_DISABLE FMAN_SP_SG_DISABLE ++ ++/** @Description QMI defines */ ++#define QMI_PORT_CFG_EN 0x80000000 ++#define QMI_PORT_CFG_EN_COUNTERS 0x10000000 ++ ++#define QMI_PORT_STATUS_DEQ_TNUM_BSY 0x80000000 ++#define QMI_PORT_STATUS_DEQ_FD_BSY 0x20000000 ++ ++#define QMI_DEQ_CFG_PRI 0x80000000 ++#define QMI_DEQ_CFG_TYPE1 0x10000000 ++#define QMI_DEQ_CFG_TYPE2 0x20000000 ++#define QMI_DEQ_CFG_TYPE3 0x30000000 ++#define QMI_DEQ_CFG_PREFETCH_PARTIAL 0x01000000 ++#define QMI_DEQ_CFG_PREFETCH_FULL 0x03000000 ++#define QMI_DEQ_CFG_SP_MASK 0xf ++#define QMI_DEQ_CFG_SP_SHIFT 20 ++ ++ ++/** @Description General port defines */ ++#define FMAN_PORT_EXT_POOLS_NUM(fm_rev_maj) \ ++ (((fm_rev_maj) == 4) ? 4 : 8) ++#define FMAN_PORT_MAX_EXT_POOLS_NUM 8 ++#define FMAN_PORT_OBS_EXT_POOLS_NUM 2 ++#define FMAN_PORT_CG_MAP_NUM 8 ++#define FMAN_PORT_PRS_RESULT_WORDS_NUM 8 ++#define FMAN_PORT_BMI_FIFO_UNITS 0x100 ++#define FMAN_PORT_IC_OFFSET_UNITS 0x10 ++ ++ ++/** @Collection FM Port Register Map */ ++ ++/** @Description BMI Rx port register map */ ++struct fman_port_rx_bmi_regs { ++ uint32_t fmbm_rcfg; /**< Rx Configuration */ ++ uint32_t fmbm_rst; /**< Rx Status */ ++ uint32_t fmbm_rda; /**< Rx DMA attributes*/ ++ uint32_t fmbm_rfp; /**< Rx FIFO Parameters*/ ++ uint32_t fmbm_rfed; /**< Rx Frame End Data*/ ++ uint32_t fmbm_ricp; /**< Rx Internal Context Parameters*/ ++ uint32_t fmbm_rim; /**< Rx Internal Buffer Margins*/ ++ uint32_t fmbm_rebm; /**< Rx External Buffer Margins*/ ++ uint32_t fmbm_rfne; /**< Rx Frame Next Engine*/ ++ uint32_t fmbm_rfca; /**< Rx Frame Command Attributes.*/ ++ uint32_t fmbm_rfpne; /**< Rx Frame Parser Next Engine*/ ++ uint32_t fmbm_rpso; /**< Rx Parse Start Offset*/ ++ uint32_t fmbm_rpp; /**< Rx Policer Profile */ ++ uint32_t fmbm_rccb; /**< Rx Coarse Classification Base */ ++ uint32_t fmbm_reth; /**< Rx Excessive Threshold */ ++ uint32_t reserved003c[1]; /**< (0x03C 0x03F) */ ++ uint32_t fmbm_rprai[FMAN_PORT_PRS_RESULT_WORDS_NUM]; ++ /**< Rx Parse Results Array Init*/ ++ uint32_t fmbm_rfqid; /**< Rx Frame Queue ID*/ ++ uint32_t fmbm_refqid; /**< Rx Error Frame Queue ID*/ ++ uint32_t fmbm_rfsdm; /**< Rx Frame Status Discard Mask*/ ++ uint32_t fmbm_rfsem; /**< Rx Frame Status Error Mask*/ ++ uint32_t fmbm_rfene; /**< Rx Frame Enqueue Next Engine */ ++ uint32_t reserved0074[0x2]; /**< (0x074-0x07C) */ ++ uint32_t fmbm_rcmne; /**< Rx Frame Continuous Mode Next Engine */ ++ uint32_t reserved0080[0x20];/**< (0x080 0x0FF) */ ++ uint32_t fmbm_ebmpi[FMAN_PORT_MAX_EXT_POOLS_NUM]; ++ /**< Buffer Manager pool Information-*/ ++ uint32_t fmbm_acnt[FMAN_PORT_MAX_EXT_POOLS_NUM]; ++ /**< Allocate Counter-*/ ++ uint32_t reserved0130[8]; ++ /**< 0x130/0x140 - 0x15F reserved -*/ ++ uint32_t fmbm_rcgm[FMAN_PORT_CG_MAP_NUM]; ++ /**< Congestion Group Map*/ ++ uint32_t fmbm_mpd; /**< BM Pool Depletion */ ++ uint32_t reserved0184[0x1F]; /**< (0x184 0x1FF) */ ++ uint32_t fmbm_rstc; /**< Rx Statistics Counters*/ ++ uint32_t fmbm_rfrc; /**< Rx Frame Counter*/ ++ uint32_t fmbm_rfbc; /**< Rx Bad Frames Counter*/ ++ uint32_t fmbm_rlfc; /**< Rx Large Frames Counter*/ ++ uint32_t fmbm_rffc; /**< Rx Filter Frames Counter*/ ++ uint32_t fmbm_rfdc; /**< Rx Frame Discard Counter*/ ++ uint32_t fmbm_rfldec; /**< Rx Frames List DMA Error Counter*/ ++ uint32_t fmbm_rodc; /**< Rx Out of Buffers Discard nntr*/ ++ uint32_t fmbm_rbdc; /**< Rx Buffers Deallocate Counter*/ ++ uint32_t reserved0224[0x17]; /**< (0x224 0x27F) */ ++ uint32_t fmbm_rpc; /**< Rx Performance Counters*/ ++ uint32_t fmbm_rpcp; /**< Rx Performance Count Parameters*/ ++ uint32_t fmbm_rccn; /**< Rx Cycle Counter*/ ++ uint32_t fmbm_rtuc; /**< Rx Tasks Utilization Counter*/ ++ uint32_t fmbm_rrquc; /**< Rx Receive Queue Utilization cntr*/ ++ uint32_t fmbm_rduc; /**< Rx DMA Utilization Counter*/ ++ uint32_t fmbm_rfuc; /**< Rx FIFO Utilization Counter*/ ++ uint32_t fmbm_rpac; /**< Rx Pause Activation Counter*/ ++ uint32_t reserved02a0[0x18]; /**< (0x2A0 0x2FF) */ ++ uint32_t fmbm_rdbg; /**< Rx Debug-*/ ++}; ++ ++/** @Description BMI Tx port register map */ ++struct fman_port_tx_bmi_regs { ++ uint32_t fmbm_tcfg; /**< Tx Configuration */ ++ uint32_t fmbm_tst; /**< Tx Status */ ++ uint32_t fmbm_tda; /**< Tx DMA attributes */ ++ uint32_t fmbm_tfp; /**< Tx FIFO Parameters */ ++ uint32_t fmbm_tfed; /**< Tx Frame End Data */ ++ uint32_t fmbm_ticp; /**< Tx Internal Context Parameters */ ++ uint32_t fmbm_tfdne; /**< Tx Frame Dequeue Next Engine. */ ++ uint32_t fmbm_tfca; /**< Tx Frame Command attribute. */ ++ uint32_t fmbm_tcfqid; /**< Tx Confirmation Frame Queue ID. */ ++ uint32_t fmbm_tefqid; /**< Tx Frame Error Queue ID */ ++ uint32_t fmbm_tfene; /**< Tx Frame Enqueue Next Engine */ ++ uint32_t fmbm_trlmts; /**< Tx Rate Limiter Scale */ ++ uint32_t fmbm_trlmt; /**< Tx Rate Limiter */ ++ uint32_t reserved0034[0x0e]; /**< (0x034-0x6c) */ ++ uint32_t fmbm_tccb; /**< Tx Coarse Classification base */ ++ uint32_t fmbm_tfne; /**< Tx Frame Next Engine */ ++ uint32_t fmbm_tpfcm[0x02]; /**< Tx Priority based Flow Control (PFC) Mapping */ ++ uint32_t fmbm_tcmne; /**< Tx Frame Continuous Mode Next Engine */ ++ uint32_t reserved0080[0x60]; /**< (0x080-0x200) */ ++ uint32_t fmbm_tstc; /**< Tx Statistics Counters */ ++ uint32_t fmbm_tfrc; /**< Tx Frame Counter */ ++ uint32_t fmbm_tfdc; /**< Tx Frames Discard Counter */ ++ uint32_t fmbm_tfledc; /**< Tx Frame len error discard cntr */ ++ uint32_t fmbm_tfufdc; /**< Tx Frame unsprt frmt discard cntr*/ ++ uint32_t fmbm_tbdc; /**< Tx Buffers Deallocate Counter */ ++ uint32_t reserved0218[0x1A]; /**< (0x218-0x280) */ ++ uint32_t fmbm_tpc; /**< Tx Performance Counters*/ ++ uint32_t fmbm_tpcp; /**< Tx Performance Count Parameters*/ ++ uint32_t fmbm_tccn; /**< Tx Cycle Counter*/ ++ uint32_t fmbm_ttuc; /**< Tx Tasks Utilization Counter*/ ++ uint32_t fmbm_ttcquc; /**< Tx Transmit conf Q util Counter*/ ++ uint32_t fmbm_tduc; /**< Tx DMA Utilization Counter*/ ++ uint32_t fmbm_tfuc; /**< Tx FIFO Utilization Counter*/ ++}; ++ ++/** @Description BMI O/H port register map */ ++struct fman_port_oh_bmi_regs { ++ uint32_t fmbm_ocfg; /**< O/H Configuration */ ++ uint32_t fmbm_ost; /**< O/H Status */ ++ uint32_t fmbm_oda; /**< O/H DMA attributes */ ++ uint32_t fmbm_oicp; /**< O/H Internal Context Parameters */ ++ uint32_t fmbm_ofdne; /**< O/H Frame Dequeue Next Engine */ ++ uint32_t fmbm_ofne; /**< O/H Frame Next Engine */ ++ uint32_t fmbm_ofca; /**< O/H Frame Command Attributes. */ ++ uint32_t fmbm_ofpne; /**< O/H Frame Parser Next Engine */ ++ uint32_t fmbm_opso; /**< O/H Parse Start Offset */ ++ uint32_t fmbm_opp; /**< O/H Policer Profile */ ++ uint32_t fmbm_occb; /**< O/H Coarse Classification base */ ++ uint32_t fmbm_oim; /**< O/H Internal margins*/ ++ uint32_t fmbm_ofp; /**< O/H Fifo Parameters*/ ++ uint32_t fmbm_ofed; /**< O/H Frame End Data*/ ++ uint32_t reserved0030[2]; /**< (0x038 - 0x03F) */ ++ uint32_t fmbm_oprai[FMAN_PORT_PRS_RESULT_WORDS_NUM]; ++ /**< O/H Parse Results Array Initialization */ ++ uint32_t fmbm_ofqid; /**< O/H Frame Queue ID */ ++ uint32_t fmbm_oefqid; /**< O/H Error Frame Queue ID */ ++ uint32_t fmbm_ofsdm; /**< O/H Frame Status Discard Mask */ ++ uint32_t fmbm_ofsem; /**< O/H Frame Status Error Mask */ ++ uint32_t fmbm_ofene; /**< O/H Frame Enqueue Next Engine */ ++ uint32_t fmbm_orlmts; /**< O/H Rate Limiter Scale */ ++ uint32_t fmbm_orlmt; /**< O/H Rate Limiter */ ++ uint32_t fmbm_ocmne; /**< O/H Continuous Mode Next Engine */ ++ uint32_t reserved0080[0x20]; /**< 0x080 - 0x0FF Reserved */ ++ uint32_t fmbm_oebmpi[2]; /**< Buf Mngr Observed Pool Info */ ++ uint32_t reserved0108[0x16]; /**< 0x108 - 0x15F Reserved */ ++ uint32_t fmbm_ocgm[FMAN_PORT_CG_MAP_NUM]; /**< Observed Congestion Group Map */ ++ uint32_t fmbm_ompd; /**< Observed BMan Pool Depletion */ ++ uint32_t reserved0184[0x1F]; /**< 0x184 - 0x1FF Reserved */ ++ uint32_t fmbm_ostc; /**< O/H Statistics Counters */ ++ uint32_t fmbm_ofrc; /**< O/H Frame Counter */ ++ uint32_t fmbm_ofdc; /**< O/H Frames Discard Counter */ ++ uint32_t fmbm_ofledc; /**< O/H Frames Len Err Discard Cntr */ ++ uint32_t fmbm_ofufdc; /**< O/H Frames Unsprtd Discard Cutr */ ++ uint32_t fmbm_offc; /**< O/H Filter Frames Counter */ ++ uint32_t fmbm_ofwdc; /**< Rx Frames WRED Discard Counter */ ++ uint32_t fmbm_ofldec; /**< O/H Frames List DMA Error Cntr */ ++ uint32_t fmbm_obdc; /**< O/H Buffers Deallocate Counter */ ++ uint32_t reserved0218[0x17]; /**< (0x218 - 0x27F) */ ++ uint32_t fmbm_opc; /**< O/H Performance Counters */ ++ uint32_t fmbm_opcp; /**< O/H Performance Count Parameters */ ++ uint32_t fmbm_occn; /**< O/H Cycle Counter */ ++ uint32_t fmbm_otuc; /**< O/H Tasks Utilization Counter */ ++ uint32_t fmbm_oduc; /**< O/H DMA Utilization Counter */ ++ uint32_t fmbm_ofuc; /**< O/H FIFO Utilization Counter */ ++}; ++ ++/** @Description BMI port register map */ ++union fman_port_bmi_regs { ++ struct fman_port_rx_bmi_regs rx; ++ struct fman_port_tx_bmi_regs tx; ++ struct fman_port_oh_bmi_regs oh; ++}; ++ ++/** @Description QMI port register map */ ++struct fman_port_qmi_regs { ++ uint32_t fmqm_pnc; /**< PortID n Configuration Register */ ++ uint32_t fmqm_pns; /**< PortID n Status Register */ ++ uint32_t fmqm_pnts; /**< PortID n Task Status Register */ ++ uint32_t reserved00c[4]; /**< 0xn00C - 0xn01B */ ++ uint32_t fmqm_pnen; /**< PortID n Enqueue NIA Register */ ++ uint32_t fmqm_pnetfc; /**< PortID n Enq Total Frame Counter */ ++ uint32_t reserved024[2]; /**< 0xn024 - 0x02B */ ++ uint32_t fmqm_pndn; /**< PortID n Dequeue NIA Register */ ++ uint32_t fmqm_pndc; /**< PortID n Dequeue Config Register */ ++ uint32_t fmqm_pndtfc; /**< PortID n Dequeue tot Frame cntr */ ++ uint32_t fmqm_pndfdc; /**< PortID n Dequeue FQID Dflt Cntr */ ++ uint32_t fmqm_pndcc; /**< PortID n Dequeue Confirm Counter */ ++}; ++ ++ ++enum fman_port_dma_swap { ++ E_FMAN_PORT_DMA_NO_SWAP, /**< No swap, transfer data as is */ ++ E_FMAN_PORT_DMA_SWAP_LE, ++ /**< The transferred data should be swapped in PPC Little Endian mode */ ++ E_FMAN_PORT_DMA_SWAP_BE ++ /**< The transferred data should be swapped in Big Endian mode */ ++}; ++ ++/* Default port color */ ++enum fman_port_color { ++ E_FMAN_PORT_COLOR_GREEN, /**< Default port color is green */ ++ E_FMAN_PORT_COLOR_YELLOW, /**< Default port color is yellow */ ++ E_FMAN_PORT_COLOR_RED, /**< Default port color is red */ ++ E_FMAN_PORT_COLOR_OVERRIDE /**< Ignore color */ ++}; ++ ++/* QMI dequeue from the SP channel - types */ ++enum fman_port_deq_type { ++ E_FMAN_PORT_DEQ_BY_PRI, ++ /**< Priority precedence and Intra-Class scheduling */ ++ E_FMAN_PORT_DEQ_ACTIVE_FQ, ++ /**< Active FQ precedence and Intra-Class scheduling */ ++ E_FMAN_PORT_DEQ_ACTIVE_FQ_NO_ICS ++ /**< Active FQ precedence and override Intra-Class scheduling */ ++}; ++ ++/* QMI dequeue prefetch modes */ ++enum fman_port_deq_prefetch { ++ E_FMAN_PORT_DEQ_NO_PREFETCH, /**< No prefetch mode */ ++ E_FMAN_PORT_DEQ_PART_PREFETCH, /**< Partial prefetch mode */ ++ E_FMAN_PORT_DEQ_FULL_PREFETCH /**< Full prefetch mode */ ++}; ++ ++/* Parameters for defining performance counters behavior */ ++struct fman_port_perf_cnt_params { ++ uint8_t task_val; /**< Task compare value */ ++ uint8_t queue_val; ++ /**< Rx or Tx conf queue compare value (unused for O/H ports) */ ++ uint8_t dma_val; /**< Dma compare value */ ++ uint32_t fifo_val; /**< Fifo compare value (in bytes) */ ++}; ++ ++/** @Description FM Port configuration structure, used at init */ ++struct fman_port_cfg { ++ struct fman_port_perf_cnt_params perf_cnt_params; ++ /* BMI parameters */ ++ enum fman_port_dma_swap dma_swap_data; ++ bool dma_ic_stash_on; ++ bool dma_header_stash_on; ++ bool dma_sg_stash_on; ++ bool dma_write_optimize; ++ uint16_t ic_ext_offset; ++ uint8_t ic_int_offset; ++ uint16_t ic_size; ++ enum fman_port_color color; ++ bool sync_req; ++ bool discard_override; ++ uint8_t checksum_bytes_ignore; ++ uint8_t rx_cut_end_bytes; ++ uint32_t rx_pri_elevation; ++ uint32_t rx_fifo_thr; ++ uint8_t rx_fd_bits; ++ uint8_t int_buf_start_margin; ++ uint16_t ext_buf_start_margin; ++ uint16_t ext_buf_end_margin; ++ uint32_t tx_fifo_min_level; ++ uint32_t tx_fifo_low_comf_level; ++ uint8_t tx_fifo_deq_pipeline_depth; ++ bool stats_counters_enable; ++ bool perf_counters_enable; ++ /* QMI parameters */ ++ bool deq_high_pri; ++ enum fman_port_deq_type deq_type; ++ enum fman_port_deq_prefetch deq_prefetch_opt; ++ uint16_t deq_byte_cnt; ++ bool queue_counters_enable; ++ bool no_scatter_gather; ++ int errata_A006675; ++ int errata_A006320; ++ int excessive_threshold_register; ++ int fmbm_rebm_has_sgd; ++ int fmbm_tfne_has_features; ++ int qmi_deq_options_support; ++}; ++ ++enum fman_port_type { ++ E_FMAN_PORT_TYPE_OP = 0, ++ /**< Offline parsing port, shares id-s with ++ * host command, so must have exclusive id-s */ ++ E_FMAN_PORT_TYPE_RX, /**< 1G Rx port */ ++ E_FMAN_PORT_TYPE_RX_10G, /**< 10G Rx port */ ++ E_FMAN_PORT_TYPE_TX, /**< 1G Tx port */ ++ E_FMAN_PORT_TYPE_TX_10G, /**< 10G Tx port */ ++ E_FMAN_PORT_TYPE_DUMMY, ++ E_FMAN_PORT_TYPE_HC = E_FMAN_PORT_TYPE_DUMMY ++ /**< Host command port, shares id-s with ++ * offline parsing ports, so must have exclusive id-s */ ++}; ++ ++struct fman_port_params { ++ uint32_t discard_mask; ++ uint32_t err_mask; ++ uint32_t dflt_fqid; ++ uint32_t err_fqid; ++ uint8_t deq_sp; ++ bool dont_release_buf; ++}; ++ ++/* Port context - used by most API functions */ ++struct fman_port { ++ enum fman_port_type type; ++ uint8_t fm_rev_maj; ++ uint8_t fm_rev_min; ++ union fman_port_bmi_regs *bmi_regs; ++ struct fman_port_qmi_regs *qmi_regs; ++ bool im_en; ++ uint8_t ext_pools_num; ++}; ++ ++/** @Description External buffer pools configuration */ ++struct fman_port_bpools { ++ uint8_t count; /**< Num of pools to set up */ ++ bool counters_enable; /**< Enable allocate counters */ ++ uint8_t grp_bp_depleted_num; ++ /**< Number of depleted pools - if reached the BMI indicates ++ * the MAC to send a pause frame */ ++ struct { ++ uint8_t bpid; /**< BM pool ID */ ++ uint16_t size; ++ /**< Pool's size - must be in ascending order */ ++ bool is_backup; ++ /**< If this is a backup pool */ ++ bool grp_bp_depleted; ++ /**< Consider this buffer in multiple pools depletion criteria*/ ++ bool single_bp_depleted; ++ /**< Consider this buffer in single pool depletion criteria */ ++ bool pfc_priorities_en; ++ } bpool[FMAN_PORT_MAX_EXT_POOLS_NUM]; ++}; ++ ++enum fman_port_rate_limiter_scale_down { ++ E_FMAN_PORT_RATE_DOWN_NONE, ++ E_FMAN_PORT_RATE_DOWN_BY_2, ++ E_FMAN_PORT_RATE_DOWN_BY_4, ++ E_FMAN_PORT_RATE_DOWN_BY_8 ++}; ++ ++/* Rate limiter configuration */ ++struct fman_port_rate_limiter { ++ uint8_t count_1micro_bit; ++ bool high_burst_size_gran; ++ /**< Defines burst_size granularity for OP ports; when TRUE, ++ * burst_size below counts in frames, otherwise in 10^3 frames */ ++ uint16_t burst_size; ++ /**< Max burst size, in KBytes for Tx port, according to ++ * high_burst_size_gran definition for OP port */ ++ uint32_t rate; ++ /**< In Kbps for Tx port, in frames/sec for OP port */ ++ enum fman_port_rate_limiter_scale_down rate_factor; ++}; ++ ++/* BMI statistics counters */ ++enum fman_port_stats_counters { ++ E_FMAN_PORT_STATS_CNT_FRAME, ++ /**< Number of processed frames; valid for all ports */ ++ E_FMAN_PORT_STATS_CNT_DISCARD, ++ /**< For Rx ports - frames discarded by QMAN, for Tx or O/H ports - ++ * frames discarded due to DMA error; valid for all ports */ ++ E_FMAN_PORT_STATS_CNT_DEALLOC_BUF, ++ /**< Number of buffer deallocate operations; valid for all ports */ ++ E_FMAN_PORT_STATS_CNT_RX_BAD_FRAME, ++ /**< Number of bad Rx frames, like CRC error, Rx FIFO overflow etc; ++ * valid for Rx ports only */ ++ E_FMAN_PORT_STATS_CNT_RX_LARGE_FRAME, ++ /**< Number of Rx oversized frames, that is frames exceeding max frame ++ * size configured for the corresponding ETH controller; ++ * valid for Rx ports only */ ++ E_FMAN_PORT_STATS_CNT_RX_OUT_OF_BUF, ++ /**< Frames discarded due to lack of external buffers; valid for ++ * Rx ports only */ ++ E_FMAN_PORT_STATS_CNT_LEN_ERR, ++ /**< Frames discarded due to frame length error; valid for Tx and ++ * O/H ports only */ ++ E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT, ++ /**< Frames discarded due to unsupported FD format; valid for Tx ++ * and O/H ports only */ ++ E_FMAN_PORT_STATS_CNT_FILTERED_FRAME, ++ /**< Number of frames filtered out by PCD module; valid for ++ * Rx and OP ports only */ ++ E_FMAN_PORT_STATS_CNT_DMA_ERR, ++ /**< Frames rejected by QMAN that were not able to release their ++ * buffers due to DMA error; valid for Rx and O/H ports only */ ++ E_FMAN_PORT_STATS_CNT_WRED_DISCARD ++ /**< Frames going through O/H port that were not able to to enter the ++ * return queue due to WRED algorithm; valid for O/H ports only */ ++}; ++ ++/* BMI performance counters */ ++enum fman_port_perf_counters { ++ E_FMAN_PORT_PERF_CNT_CYCLE, /**< Cycle counter */ ++ E_FMAN_PORT_PERF_CNT_TASK_UTIL, /**< Tasks utilization counter */ ++ E_FMAN_PORT_PERF_CNT_QUEUE_UTIL, ++ /**< For Rx ports - Rx queue utilization, for Tx ports - Tx conf queue ++ * utilization; not valid for O/H ports */ ++ E_FMAN_PORT_PERF_CNT_DMA_UTIL, /**< DMA utilization counter */ ++ E_FMAN_PORT_PERF_CNT_FIFO_UTIL, /**< FIFO utilization counter */ ++ E_FMAN_PORT_PERF_CNT_RX_PAUSE ++ /**< Number of cycles in which Rx pause activation control is on; ++ * valid for Rx ports only */ ++}; ++ ++/* QMI counters */ ++enum fman_port_qmi_counters { ++ E_FMAN_PORT_ENQ_TOTAL, /**< EnQ tot frame cntr */ ++ E_FMAN_PORT_DEQ_TOTAL, /**< DeQ tot frame cntr; invalid for Rx ports */ ++ E_FMAN_PORT_DEQ_FROM_DFLT, ++ /**< Dequeue from default FQID counter not valid for Rx ports */ ++ E_FMAN_PORT_DEQ_CONFIRM /**< DeQ confirm cntr invalid for Rx ports */ ++}; ++ ++ ++/** @Collection FM Port API */ ++void fman_port_defconfig(struct fman_port_cfg *cfg, enum fman_port_type type); ++int fman_port_init(struct fman_port *port, ++ struct fman_port_cfg *cfg, ++ struct fman_port_params *params); ++int fman_port_enable(struct fman_port *port); ++int fman_port_disable(const struct fman_port *port); ++int fman_port_set_bpools(const struct fman_port *port, ++ const struct fman_port_bpools *bp); ++int fman_port_set_rate_limiter(struct fman_port *port, ++ struct fman_port_rate_limiter *rate_limiter); ++int fman_port_delete_rate_limiter(struct fman_port *port); ++int fman_port_set_err_mask(struct fman_port *port, uint32_t err_mask); ++int fman_port_set_discard_mask(struct fman_port *port, uint32_t discard_mask); ++int fman_port_modify_rx_fd_bits(struct fman_port *port, ++ uint8_t rx_fd_bits, ++ bool add); ++int fman_port_set_perf_cnt_params(struct fman_port *port, ++ struct fman_port_perf_cnt_params *params); ++int fman_port_set_stats_cnt_mode(struct fman_port *port, bool enable); ++int fman_port_set_perf_cnt_mode(struct fman_port *port, bool enable); ++int fman_port_set_queue_cnt_mode(struct fman_port *port, bool enable); ++int fman_port_set_bpool_cnt_mode(struct fman_port *port, ++ uint8_t bpid, ++ bool enable); ++uint32_t fman_port_get_stats_counter(struct fman_port *port, ++ enum fman_port_stats_counters counter); ++void fman_port_set_stats_counter(struct fman_port *port, ++ enum fman_port_stats_counters counter, ++ uint32_t value); ++uint32_t fman_port_get_perf_counter(struct fman_port *port, ++ enum fman_port_perf_counters counter); ++void fman_port_set_perf_counter(struct fman_port *port, ++ enum fman_port_perf_counters counter, ++ uint32_t value); ++uint32_t fman_port_get_qmi_counter(struct fman_port *port, ++ enum fman_port_qmi_counters counter); ++void fman_port_set_qmi_counter(struct fman_port *port, ++ enum fman_port_qmi_counters counter, ++ uint32_t value); ++uint32_t fman_port_get_bpool_counter(struct fman_port *port, uint8_t bpid); ++void fman_port_set_bpool_counter(struct fman_port *port, ++ uint8_t bpid, ++ uint32_t value); ++int fman_port_add_congestion_grps(struct fman_port *port, ++ uint32_t grps_map[FMAN_PORT_CG_MAP_NUM]); ++int fman_port_remove_congestion_grps(struct fman_port *port, ++ uint32_t grps_map[FMAN_PORT_CG_MAP_NUM]); ++ ++ ++#endif /* __FSL_FMAN_PORT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_prs.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_prs.h +new file mode 100644 +index 00000000..b18997dc +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_prs.h +@@ -0,0 +1,102 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __FSL_FMAN_PRS_H ++#define __FSL_FMAN_PRS_H ++ ++#include "common/general.h" ++ ++#define FM_PCD_EX_PRS_DOUBLE_ECC 0x02000000 ++#define FM_PCD_EX_PRS_SINGLE_ECC 0x01000000 ++ ++#define FM_PCD_PRS_PPSC_ALL_PORTS 0xffff0000 ++#define FM_PCD_PRS_RPIMAC_EN 0x00000001 ++#define FM_PCD_PRS_PORT_IDLE_STS 0xffff0000 ++#define FM_PCD_PRS_SINGLE_ECC 0x00004000 ++#define FM_PCD_PRS_DOUBLE_ECC 0x00004000 ++#define PRS_MAX_CYCLE_LIMIT 8191 ++ ++#define DEFAULT_MAX_PRS_CYC_LIM 0 ++ ++struct fman_prs_regs { ++ uint32_t fmpr_rpclim; ++ uint32_t fmpr_rpimac; ++ uint32_t pmeec; ++ uint32_t res00c[5]; ++ uint32_t fmpr_pevr; ++ uint32_t fmpr_pever; ++ uint32_t res028; ++ uint32_t fmpr_perr; ++ uint32_t fmpr_perer; ++ uint32_t res034; ++ uint32_t res038[10]; ++ uint32_t fmpr_ppsc; ++ uint32_t res064; ++ uint32_t fmpr_pds; ++ uint32_t fmpr_l2rrs; ++ uint32_t fmpr_l3rrs; ++ uint32_t fmpr_l4rrs; ++ uint32_t fmpr_srrs; ++ uint32_t fmpr_l2rres; ++ uint32_t fmpr_l3rres; ++ uint32_t fmpr_l4rres; ++ uint32_t fmpr_srres; ++ uint32_t fmpr_spcs; ++ uint32_t fmpr_spscs; ++ uint32_t fmpr_hxscs; ++ uint32_t fmpr_mrcs; ++ uint32_t fmpr_mwcs; ++ uint32_t fmpr_mrscs; ++ uint32_t fmpr_mwscs; ++ uint32_t fmpr_fcscs; ++}; ++ ++struct fman_prs_cfg { ++ uint32_t port_id_stat; ++ uint16_t max_prs_cyc_lim; ++ uint32_t prs_exceptions; ++}; ++ ++uint32_t fman_prs_get_err_event(struct fman_prs_regs *regs, uint32_t ev_mask); ++uint32_t fman_prs_get_err_ev_mask(struct fman_prs_regs *regs); ++void fman_prs_ack_err_event(struct fman_prs_regs *regs, uint32_t event); ++uint32_t fman_prs_get_expt_event(struct fman_prs_regs *regs, uint32_t ev_mask); ++uint32_t fman_prs_get_expt_ev_mask(struct fman_prs_regs *regs); ++void fman_prs_ack_expt_event(struct fman_prs_regs *regs, uint32_t event); ++void fman_prs_defconfig(struct fman_prs_cfg *cfg); ++int fman_prs_init(struct fman_prs_regs *regs, struct fman_prs_cfg *cfg); ++void fman_prs_enable(struct fman_prs_regs *regs); ++void fman_prs_disable(struct fman_prs_regs *regs); ++int fman_prs_is_enabled(struct fman_prs_regs *regs); ++void fman_prs_set_stst_port_msk(struct fman_prs_regs *regs, uint32_t pid_msk); ++void fman_prs_set_stst(struct fman_prs_regs *regs, bool enable); ++#endif /* __FSL_FMAN_PRS_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_rtc.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_rtc.h +new file mode 100755 +index 00000000..f6b69a1f +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_rtc.h +@@ -0,0 +1,449 @@ ++/* ++ * Copyright 2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __FSL_FMAN_RTC_H ++#define __FSL_FMAN_RTC_H ++ ++#include "common/general.h" ++ ++/* FM RTC Registers definitions */ ++#define FMAN_RTC_TMR_CTRL_ALMP1 0x80000000 ++#define FMAN_RTC_TMR_CTRL_ALMP2 0x40000000 ++#define FMAN_RTC_TMR_CTRL_FS 0x10000000 ++#define FMAN_RTC_TMR_CTRL_PP1L 0x08000000 ++#define FMAN_RTC_TMR_CTRL_PP2L 0x04000000 ++#define FMAN_RTC_TMR_CTRL_TCLK_PERIOD_MASK 0x03FF0000 ++#define FMAN_RTC_TMR_CTRL_FRD 0x00004000 ++#define FMAN_RTC_TMR_CTRL_SLV 0x00002000 ++#define FMAN_RTC_TMR_CTRL_ETEP1 0x00000100 ++#define FMAN_RTC_TMR_CTRL_COPH 0x00000080 ++#define FMAN_RTC_TMR_CTRL_CIPH 0x00000040 ++#define FMAN_RTC_TMR_CTRL_TMSR 0x00000020 ++#define FMAN_RTC_TMR_CTRL_DBG 0x00000010 ++#define FMAN_RTC_TMR_CTRL_BYP 0x00000008 ++#define FMAN_RTC_TMR_CTRL_TE 0x00000004 ++#define FMAN_RTC_TMR_CTRL_CKSEL_OSC_CLK 0x00000003 ++#define FMAN_RTC_TMR_CTRL_CKSEL_MAC_CLK 0x00000001 ++#define FMAN_RTC_TMR_CTRL_CKSEL_EXT_CLK 0x00000000 ++#define FMAN_RTC_TMR_CTRL_TCLK_PERIOD_SHIFT 16 ++ ++#define FMAN_RTC_TMR_TEVENT_ETS2 0x02000000 ++#define FMAN_RTC_TMR_TEVENT_ETS1 0x01000000 ++#define FMAN_RTC_TMR_TEVENT_ALM2 0x00020000 ++#define FMAN_RTC_TMR_TEVENT_ALM1 0x00010000 ++#define FMAN_RTC_TMR_TEVENT_PP1 0x00000080 ++#define FMAN_RTC_TMR_TEVENT_PP2 0x00000040 ++#define FMAN_RTC_TMR_TEVENT_PP3 0x00000020 ++#define FMAN_RTC_TMR_TEVENT_ALL (FMAN_RTC_TMR_TEVENT_ETS2 |\ ++ FMAN_RTC_TMR_TEVENT_ETS1 |\ ++ FMAN_RTC_TMR_TEVENT_ALM2 |\ ++ FMAN_RTC_TMR_TEVENT_ALM1 |\ ++ FMAN_RTC_TMR_TEVENT_PP1 |\ ++ FMAN_RTC_TMR_TEVENT_PP2 |\ ++ FMAN_RTC_TMR_TEVENT_PP3) ++ ++#define FMAN_RTC_TMR_PRSC_OCK_MASK 0x0000FFFF ++ ++/**************************************************************************//** ++ @Description FM RTC Alarm Polarity Options. ++*//***************************************************************************/ ++enum fman_rtc_alarm_polarity { ++ E_FMAN_RTC_ALARM_POLARITY_ACTIVE_HIGH, /**< Active-high output polarity */ ++ E_FMAN_RTC_ALARM_POLARITY_ACTIVE_LOW /**< Active-low output polarity */ ++}; ++ ++/**************************************************************************//** ++ @Description FM RTC Trigger Polarity Options. ++*//***************************************************************************/ ++enum fman_rtc_trigger_polarity { ++ E_FMAN_RTC_TRIGGER_ON_RISING_EDGE, /**< Trigger on rising edge */ ++ E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE /**< Trigger on falling edge */ ++}; ++ ++/**************************************************************************//** ++ @Description IEEE1588 Timer Module FM RTC Optional Clock Sources. ++*//***************************************************************************/ ++enum fman_src_clock { ++ E_FMAN_RTC_SOURCE_CLOCK_EXTERNAL, /**< external high precision timer ++ reference clock */ ++ E_FMAN_RTC_SOURCE_CLOCK_SYSTEM, /**< MAC system clock */ ++ E_FMAN_RTC_SOURCE_CLOCK_OSCILATOR /**< RTC clock oscilator */ ++}; ++ ++/* RTC default values */ ++#define DEFAULT_SRC_CLOCK E_FMAN_RTC_SOURCE_CLOCK_SYSTEM ++#define DEFAULT_INVERT_INPUT_CLK_PHASE FALSE ++#define DEFAULT_INVERT_OUTPUT_CLK_PHASE FALSE ++#define DEFAULT_ALARM_POLARITY E_FMAN_RTC_ALARM_POLARITY_ACTIVE_HIGH ++#define DEFAULT_TRIGGER_POLARITY E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE ++#define DEFAULT_PULSE_REALIGN FALSE ++ ++#define FMAN_RTC_MAX_NUM_OF_ALARMS 3 ++#define FMAN_RTC_MAX_NUM_OF_PERIODIC_PULSES 4 ++#define FMAN_RTC_MAX_NUM_OF_EXT_TRIGGERS 3 ++ ++/**************************************************************************//** ++ @Description FM RTC timer alarm ++*//***************************************************************************/ ++struct t_tmr_alarm{ ++ uint32_t tmr_alarm_h; /**< */ ++ uint32_t tmr_alarm_l; /**< */ ++}; ++ ++/**************************************************************************//** ++ @Description FM RTC timer Ex trigger ++*//***************************************************************************/ ++struct t_tmr_ext_trigger{ ++ uint32_t tmr_etts_h; /**< */ ++ uint32_t tmr_etts_l; /**< */ ++}; ++ ++struct rtc_regs { ++ uint32_t tmr_id; /* 0x000 Module ID register */ ++ uint32_t tmr_id2; /* 0x004 Controller ID register */ ++ uint32_t reserved0008[30]; ++ uint32_t tmr_ctrl; /* 0x0080 timer control register */ ++ uint32_t tmr_tevent; /* 0x0084 timer event register */ ++ uint32_t tmr_temask; /* 0x0088 timer event mask register */ ++ uint32_t reserved008c[3]; ++ uint32_t tmr_cnt_h; /* 0x0098 timer counter high register */ ++ uint32_t tmr_cnt_l; /* 0x009c timer counter low register */ ++ uint32_t tmr_add; /* 0x00a0 timer drift compensation addend register */ ++ uint32_t tmr_acc; /* 0x00a4 timer accumulator register */ ++ uint32_t tmr_prsc; /* 0x00a8 timer prescale */ ++ uint32_t reserved00ac; ++ uint32_t tmr_off_h; /* 0x00b0 timer offset high */ ++ uint32_t tmr_off_l; /* 0x00b4 timer offset low */ ++ struct t_tmr_alarm tmr_alarm[FMAN_RTC_MAX_NUM_OF_ALARMS]; /* 0x00b8 timer ++ alarm */ ++ uint32_t tmr_fiper[FMAN_RTC_MAX_NUM_OF_PERIODIC_PULSES]; /* 0x00d0 timer ++ fixed period interval */ ++ struct t_tmr_ext_trigger tmr_etts[FMAN_RTC_MAX_NUM_OF_EXT_TRIGGERS]; ++ /* 0x00e0 time stamp general purpose external */ ++ uint32_t reserved00f0[4]; ++}; ++ ++struct rtc_cfg { ++ enum fman_src_clock src_clk; ++ uint32_t ext_src_clk_freq; ++ uint32_t rtc_freq_hz; ++ bool timer_slave_mode; ++ bool invert_input_clk_phase; ++ bool invert_output_clk_phase; ++ uint32_t events_mask; ++ bool bypass; /**< Indicates if frequency compensation ++ is bypassed */ ++ bool pulse_realign; ++ enum fman_rtc_alarm_polarity alarm_polarity[FMAN_RTC_MAX_NUM_OF_ALARMS]; ++ enum fman_rtc_trigger_polarity trigger_polarity ++ [FMAN_RTC_MAX_NUM_OF_EXT_TRIGGERS]; ++}; ++ ++/** ++ * fman_rtc_defconfig() - Get default RTC configuration ++ * @cfg: pointer to configuration structure. ++ * ++ * Call this function to obtain a default set of configuration values for ++ * initializing RTC. The user can overwrite any of the values before calling ++ * fman_rtc_init(), if specific configuration needs to be applied. ++ */ ++void fman_rtc_defconfig(struct rtc_cfg *cfg); ++ ++/** ++ * fman_rtc_get_events() - Get the events ++ * @regs: Pointer to RTC register block ++ * ++ * Returns: The events ++ */ ++uint32_t fman_rtc_get_events(struct rtc_regs *regs); ++ ++/** ++ * fman_rtc_get_interrupt_mask() - Get the events mask ++ * @regs: Pointer to RTC register block ++ * ++ * Returns: The events mask ++ */ ++uint32_t fman_rtc_get_interrupt_mask(struct rtc_regs *regs); ++ ++ ++/** ++ * fman_rtc_set_interrupt_mask() - Set the events mask ++ * @regs: Pointer to RTC register block ++ * @mask: The mask to set ++ */ ++void fman_rtc_set_interrupt_mask(struct rtc_regs *regs, uint32_t mask); ++ ++/** ++ * fman_rtc_get_event() - Check if specific events occurred ++ * @regs: Pointer to RTC register block ++ * @ev_mask: a mask of the events to check ++ * ++ * Returns: 0 if the events did not occur. Non zero if one of the events occurred ++ */ ++uint32_t fman_rtc_get_event(struct rtc_regs *regs, uint32_t ev_mask); ++ ++/** ++ * fman_rtc_check_and_clear_event() - Clear events which are on ++ * @regs: Pointer to RTC register block ++ * ++ * Returns: A mask of the events which were cleared ++ */ ++uint32_t fman_rtc_check_and_clear_event(struct rtc_regs *regs); ++ ++/** ++ * fman_rtc_ack_event() - Clear events ++ * @regs: Pointer to RTC register block ++ * @events: The events to disable ++ */ ++void fman_rtc_ack_event(struct rtc_regs *regs, uint32_t events); ++ ++/** ++ * fman_rtc_enable_interupt() - Enable events interrupts ++ * @regs: Pointer to RTC register block ++ * @mask: The events to disable ++ */ ++void fman_rtc_enable_interupt(struct rtc_regs *regs, uint32_t mask); ++ ++/** ++ * fman_rtc_disable_interupt() - Disable events interrupts ++ * @regs: Pointer to RTC register block ++ * @mask: The events to disable ++ */ ++void fman_rtc_disable_interupt(struct rtc_regs *regs, uint32_t mask); ++ ++/** ++ * fman_rtc_get_timer_ctrl() - Get the control register ++ * @regs: Pointer to RTC register block ++ * ++ * Returns: The control register value ++ */ ++uint32_t fman_rtc_get_timer_ctrl(struct rtc_regs *regs); ++ ++/** ++ * fman_rtc_set_timer_ctrl() - Set timer control register ++ * @regs: Pointer to RTC register block ++ * @val: The value to set ++ */ ++void fman_rtc_set_timer_ctrl(struct rtc_regs *regs, uint32_t val); ++ ++/** ++ * fman_rtc_get_frequency_compensation() - Get the frequency compensation ++ * @regs: Pointer to RTC register block ++ * ++ * Returns: The timer counter ++ */ ++uint32_t fman_rtc_get_frequency_compensation(struct rtc_regs *regs); ++ ++/** ++ * fman_rtc_set_frequency_compensation() - Set frequency compensation ++ * @regs: Pointer to RTC register block ++ * @val: The value to set ++ */ ++void fman_rtc_set_frequency_compensation(struct rtc_regs *regs, uint32_t val); ++ ++/** ++ * fman_rtc_get_trigger_stamp() - Get a trigger stamp ++ * @regs: Pointer to RTC register block ++ * @id: The id of the trigger stamp ++ * ++ * Returns: The time stamp ++ */ ++uint64_t fman_rtc_get_trigger_stamp(struct rtc_regs *regs, int id); ++ ++/** ++ * fman_rtc_set_timer_alarm_l() - Set timer alarm low register ++ * @regs: Pointer to RTC register block ++ * @index: The index of alarm to set ++ * @val: The value to set ++ */ ++void fman_rtc_set_timer_alarm_l(struct rtc_regs *regs, int index, ++ uint32_t val); ++ ++/** ++ * fman_rtc_set_timer_alarm() - Set timer alarm ++ * @regs: Pointer to RTC register block ++ * @index: The index of alarm to set ++ * @val: The value to set ++ */ ++void fman_rtc_set_timer_alarm(struct rtc_regs *regs, int index, int64_t val); ++ ++/** ++ * fman_rtc_set_timer_fiper() - Set timer fiper ++ * @regs: Pointer to RTC register block ++ * @index: The index of fiper to set ++ * @val: The value to set ++ */ ++void fman_rtc_set_timer_fiper(struct rtc_regs *regs, int index, uint32_t val); ++ ++/** ++ * fman_rtc_set_timer_offset() - Set timer offset ++ * @regs: Pointer to RTC register block ++ * @val: The value to set ++ */ ++void fman_rtc_set_timer_offset(struct rtc_regs *regs, int64_t val); ++ ++/** ++ * fman_rtc_get_timer() - Get the timer counter ++ * @regs: Pointer to RTC register block ++ * ++ * Returns: The timer counter ++ */ ++static inline uint64_t fman_rtc_get_timer(struct rtc_regs *regs) ++{ ++ uint64_t time; ++ /* TMR_CNT_L must be read first to get an accurate value */ ++ time = (uint64_t)ioread32be(®s->tmr_cnt_l); ++ time |= ((uint64_t)ioread32be(®s->tmr_cnt_h) << 32); ++ ++ return time; ++} ++ ++/** ++ * fman_rtc_set_timer() - Set timer counter ++ * @regs: Pointer to RTC register block ++ * @val: The value to set ++ */ ++static inline void fman_rtc_set_timer(struct rtc_regs *regs, int64_t val) ++{ ++ iowrite32be((uint32_t)val, ®s->tmr_cnt_l); ++ iowrite32be((uint32_t)(val >> 32), ®s->tmr_cnt_h); ++} ++ ++/** ++ * fman_rtc_timers_soft_reset() - Soft reset ++ * @regs: Pointer to RTC register block ++ * ++ * Resets all the timer registers and state machines for the 1588 IP and ++ * the attached client 1588 ++ */ ++void fman_rtc_timers_soft_reset(struct rtc_regs *regs); ++ ++/** ++ * fman_rtc_clear_external_trigger() - Clear an external trigger ++ * @regs: Pointer to RTC register block ++ * @id: The id of the trigger to clear ++ */ ++void fman_rtc_clear_external_trigger(struct rtc_regs *regs, int id); ++ ++/** ++ * fman_rtc_clear_periodic_pulse() - Clear periodic pulse ++ * @regs: Pointer to RTC register block ++ * @id: The id of the fiper to clear ++ */ ++void fman_rtc_clear_periodic_pulse(struct rtc_regs *regs, int id); ++ ++/** ++ * fman_rtc_enable() - Enable RTC hardware block ++ * @regs: Pointer to RTC register block ++ */ ++void fman_rtc_enable(struct rtc_regs *regs, bool reset_clock); ++ ++/** ++ * fman_rtc_is_enabled() - Is RTC hardware block enabled ++ * @regs: Pointer to RTC register block ++ * ++ * Return: TRUE if enabled ++ */ ++bool fman_rtc_is_enabled(struct rtc_regs *regs); ++ ++/** ++ * fman_rtc_disable() - Disable RTC hardware block ++ * @regs: Pointer to RTC register block ++ */ ++void fman_rtc_disable(struct rtc_regs *regs); ++ ++/** ++ * fman_rtc_init() - Init RTC hardware block ++ * @cfg: RTC configuration data ++ * @regs: Pointer to RTC register block ++ * @num_alarms: Number of alarms in RTC ++ * @num_fipers: Number of fipers in RTC ++ * @num_ext_triggers: Number of external triggers in RTC ++ * @freq_compensation: Frequency compensation ++ * @output_clock_divisor: Output clock divisor ++ * ++ * This function initializes RTC and applies basic configuration. ++ */ ++void fman_rtc_init(struct rtc_cfg *cfg, struct rtc_regs *regs, int num_alarms, ++ int num_fipers, int num_ext_triggers, bool init_freq_comp, ++ uint32_t freq_compensation, uint32_t output_clock_divisor); ++ ++/** ++ * fman_rtc_set_alarm() - Set an alarm ++ * @regs: Pointer to RTC register block ++ * @id: id of alarm ++ * @val: value to write ++ * @enable: should interrupt be enabled ++ */ ++void fman_rtc_set_alarm(struct rtc_regs *regs, int id, uint32_t val, bool enable); ++ ++/** ++ * fman_rtc_set_periodic_pulse() - Set an alarm ++ * @regs: Pointer to RTC register block ++ * @id: id of fiper ++ * @val: value to write ++ * @enable: should interrupt be enabled ++ */ ++void fman_rtc_set_periodic_pulse(struct rtc_regs *regs, int id, uint32_t val, ++ bool enable); ++ ++/** ++ * fman_rtc_set_ext_trigger() - Set an external trigger ++ * @regs: Pointer to RTC register block ++ * @id: id of trigger ++ * @enable: should interrupt be enabled ++ * @use_pulse_as_input: use the pulse as input ++ */ ++void fman_rtc_set_ext_trigger(struct rtc_regs *regs, int id, bool enable, ++ bool use_pulse_as_input); ++ ++struct fm_rtc_alarm_params { ++ uint8_t alarm_id; /**< 0 or 1 */ ++ uint64_t alarm_time; /**< In nanoseconds, the time when the ++ alarm should go off - must be a ++ multiple of the RTC period */ ++ void (*f_alarm_callback)(void* app, uint8_t id); /**< This routine will ++ be called when RTC reaches alarmTime */ ++ bool clear_on_expiration; /**< TRUE to turn off the alarm once ++ expired.*/ ++}; ++ ++struct fm_rtc_periodic_pulse_params { ++ uint8_t periodic_pulse_id; /**< 0 or 1 */ ++ uint64_t periodic_pulse_period; /**< In Nanoseconds. Must be a multiple ++ of the RTC period */ ++ void (*f_periodic_pulse_callback)(void* app, uint8_t id); /**< This ++ routine will be called every ++ periodicPulsePeriod. */ ++}; ++ ++#endif /* __FSL_FMAN_RTC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_sp.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_sp.h +new file mode 100755 +index 00000000..f8ef7d56 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_sp.h +@@ -0,0 +1,138 @@ ++/* ++ * Copyright 2013 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __FSL_FMAN_SP_H ++#define __FSL_FMAN_SP_H ++ ++#include "common/general.h" ++#include "fsl_fman.h" ++ ++ ++struct fm_pcd_storage_profile_regs{ ++ uint32_t fm_sp_ebmpi[8]; ++ /*offset 0 - 0xc*/ ++ /**< Buffer Manager pool Information */ ++ ++ uint32_t fm_sp_acnt; /*offset 0x20*/ ++ uint32_t fm_sp_ebm; /*offset 0x24*/ ++ uint32_t fm_sp_da; /*offset 0x28*/ ++ uint32_t fm_sp_icp; /*offset 0x2c*/ ++ uint32_t fm_sp_mpd; /*offset 0x30*/ ++ uint32_t res1[2]; /*offset 0x34 - 0x38*/ ++ uint32_t fm_sp_spliodn; /*offset 0x3c*/ ++}; ++ ++/**************************************************************************//** ++ @Description structure for defining internal context copying ++*//***************************************************************************/ ++struct fman_sp_int_context_data_copy{ ++ uint16_t ext_buf_offset; /**< Offset in External buffer to which ++ internal context is copied to (Rx) ++ or taken from (Tx, Op). */ ++ uint8_t int_context_offset; /**< Offset within internal context to copy ++ from (Rx) or to copy to (Tx, Op).*/ ++ uint16_t size; /**< Internal offset size to be copied */ ++}; ++ ++/**************************************************************************//** ++ @Description struct for defining external buffer margins ++*//***************************************************************************/ ++struct fman_sp_buf_margins{ ++ uint16_t start_margins; /**< Number of bytes to be left at the ++ beginning of the external buffer (must be ++ divisible by 16) */ ++ uint16_t end_margins; /**< number of bytes to be left at the end of ++ the external buffer(must be divisible by 16)*/ ++}; ++ ++struct fm_storage_profile_params { ++ struct fman_ext_pools fm_ext_pools; ++ struct fman_backup_bm_pools backup_pools; ++ struct fman_sp_int_context_data_copy *int_context; ++ struct fman_sp_buf_margins *buf_margins; ++ enum fman_dma_swap_option dma_swap_data; ++ enum fman_dma_cache_option int_context_cache_attr; ++ enum fman_dma_cache_option header_cache_attr; ++ enum fman_dma_cache_option scatter_gather_cache_attr; ++ bool dma_write_optimize; ++ uint16_t liodn_offset; ++ bool no_scather_gather; ++ struct fman_buf_pool_depletion buf_pool_depletion; ++}; ++ ++/**************************************************************************//** ++ @Description Registers bit fields ++*//***************************************************************************/ ++#define FMAN_SP_EXT_BUF_POOL_EN_COUNTER 0x40000000 ++#define FMAN_SP_EXT_BUF_POOL_VALID 0x80000000 ++#define FMAN_SP_EXT_BUF_POOL_BACKUP 0x20000000 ++#define FMAN_SP_DMA_ATTR_WRITE_OPTIMIZE 0x00100000 ++#define FMAN_SP_SG_DISABLE 0x80000000 ++ ++/* shifts */ ++#define FMAN_SP_EXT_BUF_POOL_ID_SHIFT 16 ++#define FMAN_SP_POOL_DEP_NUM_OF_POOLS_SHIFT 16 ++#define FMAN_SP_EXT_BUF_MARG_START_SHIFT 16 ++#define FMAN_SP_EXT_BUF_MARG_END_SHIFT 0 ++#define FMAN_SP_DMA_ATTR_SWP_SHIFT 30 ++#define FMAN_SP_DMA_ATTR_IC_CACHE_SHIFT 28 ++#define FMAN_SP_DMA_ATTR_HDR_CACHE_SHIFT 26 ++#define FMAN_SP_DMA_ATTR_SG_CACHE_SHIFT 24 ++#define FMAN_SP_IC_TO_EXT_SHIFT 16 ++#define FMAN_SP_IC_FROM_INT_SHIFT 8 ++#define FMAN_SP_IC_SIZE_SHIFT 0 ++ ++/**************************************************************************//** ++ @Description defaults ++*//***************************************************************************/ ++#define DEFAULT_FMAN_SP_DMA_SWAP_DATA FMAN_DMA_NO_SWP ++#define DEFAULT_FMAN_SP_DMA_INT_CONTEXT_CACHE_ATTR FMAN_DMA_NO_STASH ++#define DEFAULT_FMAN_SP_DMA_HEADER_CACHE_ATTR FMAN_DMA_NO_STASH ++#define DEFAULT_FMAN_SP_DMA_SCATTER_GATHER_CACHE_ATTR FMAN_DMA_NO_STASH ++#define DEFAULT_FMAN_SP_DMA_WRITE_OPTIMIZE TRUE ++#define DEFAULT_FMAN_SP_NO_SCATTER_GATHER FALSE ++ ++void fman_vsp_defconfig(struct fm_storage_profile_params *cfg); ++ ++void fman_vsp_init(struct fm_pcd_storage_profile_regs *regs, ++ uint16_t index, struct fm_storage_profile_params *fm_vsp_params, ++ int port_max_num_of_ext_pools, int bm_max_num_of_pools, ++ int max_num_of_pfc_priorities); ++ ++uint32_t fman_vsp_get_statistics(struct fm_pcd_storage_profile_regs *regs, ++ uint16_t index); ++ ++void fman_vsp_set_statistics(struct fm_pcd_storage_profile_regs *regs, ++ uint16_t index, uint32_t value); ++ ++ ++#endif /* __FSL_FMAN_SP_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_tgec.h b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_tgec.h +new file mode 100644 +index 00000000..a0373141 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/flib/fsl_fman_tgec.h +@@ -0,0 +1,479 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __FSL_FMAN_TGEC_H ++#define __FSL_FMAN_TGEC_H ++ ++#include "common/general.h" ++#include "fsl_enet.h" ++ ++ ++/* Transmit Inter-Packet Gap Length Register (TX_IPG_LENGTH) */ ++#define TGEC_TX_IPG_LENGTH_MASK 0x000003ff ++ ++enum tgec_counters { ++ E_TGEC_COUNTER_R64, ++ E_TGEC_COUNTER_R127, ++ E_TGEC_COUNTER_R255, ++ E_TGEC_COUNTER_R511, ++ E_TGEC_COUNTER_R1023, ++ E_TGEC_COUNTER_R1518, ++ E_TGEC_COUNTER_R1519X, ++ E_TGEC_COUNTER_TRFRG, ++ E_TGEC_COUNTER_TRJBR, ++ E_TGEC_COUNTER_RDRP, ++ E_TGEC_COUNTER_RALN, ++ E_TGEC_COUNTER_TRUND, ++ E_TGEC_COUNTER_TROVR, ++ E_TGEC_COUNTER_RXPF, ++ E_TGEC_COUNTER_TXPF, ++ E_TGEC_COUNTER_ROCT, ++ E_TGEC_COUNTER_RMCA, ++ E_TGEC_COUNTER_RBCA, ++ E_TGEC_COUNTER_RPKT, ++ E_TGEC_COUNTER_RUCA, ++ E_TGEC_COUNTER_RERR, ++ E_TGEC_COUNTER_TOCT, ++ E_TGEC_COUNTER_TMCA, ++ E_TGEC_COUNTER_TBCA, ++ E_TGEC_COUNTER_TUCA, ++ E_TGEC_COUNTER_TERR ++}; ++ ++/* Command and Configuration Register (COMMAND_CONFIG) */ ++#define CMD_CFG_EN_TIMESTAMP 0x00100000 ++#define CMD_CFG_TX_ADDR_INS_SEL 0x00080000 ++#define CMD_CFG_NO_LEN_CHK 0x00020000 ++#define CMD_CFG_SEND_IDLE 0x00010000 ++#define CMD_CFG_RX_ER_DISC 0x00004000 ++#define CMD_CFG_CMD_FRM_EN 0x00002000 ++#define CMD_CFG_STAT_CLR 0x00001000 ++#define CMD_CFG_LOOPBACK_EN 0x00000400 ++#define CMD_CFG_TX_ADDR_INS 0x00000200 ++#define CMD_CFG_PAUSE_IGNORE 0x00000100 ++#define CMD_CFG_PAUSE_FWD 0x00000080 ++#define CMD_CFG_PROMIS_EN 0x00000010 ++#define CMD_CFG_WAN_MODE 0x00000008 ++#define CMD_CFG_RX_EN 0x00000002 ++#define CMD_CFG_TX_EN 0x00000001 ++ ++/* Interrupt Mask Register (IMASK) */ ++#define TGEC_IMASK_MDIO_SCAN_EVENT 0x00010000 ++#define TGEC_IMASK_MDIO_CMD_CMPL 0x00008000 ++#define TGEC_IMASK_REM_FAULT 0x00004000 ++#define TGEC_IMASK_LOC_FAULT 0x00002000 ++#define TGEC_IMASK_TX_ECC_ER 0x00001000 ++#define TGEC_IMASK_TX_FIFO_UNFL 0x00000800 ++#define TGEC_IMASK_TX_FIFO_OVFL 0x00000400 ++#define TGEC_IMASK_TX_ER 0x00000200 ++#define TGEC_IMASK_RX_FIFO_OVFL 0x00000100 ++#define TGEC_IMASK_RX_ECC_ER 0x00000080 ++#define TGEC_IMASK_RX_JAB_FRM 0x00000040 ++#define TGEC_IMASK_RX_OVRSZ_FRM 0x00000020 ++#define TGEC_IMASK_RX_RUNT_FRM 0x00000010 ++#define TGEC_IMASK_RX_FRAG_FRM 0x00000008 ++#define TGEC_IMASK_RX_LEN_ER 0x00000004 ++#define TGEC_IMASK_RX_CRC_ER 0x00000002 ++#define TGEC_IMASK_RX_ALIGN_ER 0x00000001 ++ ++#define TGEC_EVENTS_MASK \ ++ ((uint32_t)(TGEC_IMASK_MDIO_SCAN_EVENT | \ ++ TGEC_IMASK_MDIO_CMD_CMPL | \ ++ TGEC_IMASK_REM_FAULT | \ ++ TGEC_IMASK_LOC_FAULT | \ ++ TGEC_IMASK_TX_ECC_ER | \ ++ TGEC_IMASK_TX_FIFO_UNFL | \ ++ TGEC_IMASK_TX_FIFO_OVFL | \ ++ TGEC_IMASK_TX_ER | \ ++ TGEC_IMASK_RX_FIFO_OVFL | \ ++ TGEC_IMASK_RX_ECC_ER | \ ++ TGEC_IMASK_RX_JAB_FRM | \ ++ TGEC_IMASK_RX_OVRSZ_FRM | \ ++ TGEC_IMASK_RX_RUNT_FRM | \ ++ TGEC_IMASK_RX_FRAG_FRM | \ ++ TGEC_IMASK_RX_LEN_ER | \ ++ TGEC_IMASK_RX_CRC_ER | \ ++ TGEC_IMASK_RX_ALIGN_ER)) ++ ++/* Hashtable Control Register (HASHTABLE_CTRL) */ ++#define TGEC_HASH_MCAST_SHIFT 23 ++#define TGEC_HASH_MCAST_EN 0x00000200 ++#define TGEC_HASH_ADR_MSK 0x000001ff ++ ++#define DEFAULT_WAN_MODE_ENABLE FALSE ++#define DEFAULT_PROMISCUOUS_MODE_ENABLE FALSE ++#define DEFAULT_PAUSE_FORWARD_ENABLE FALSE ++#define DEFAULT_PAUSE_IGNORE FALSE ++#define DEFAULT_TX_ADDR_INS_ENABLE FALSE ++#define DEFAULT_LOOPBACK_ENABLE FALSE ++#define DEFAULT_CMD_FRAME_ENABLE FALSE ++#define DEFAULT_RX_ERROR_DISCARD FALSE ++#define DEFAULT_SEND_IDLE_ENABLE FALSE ++#define DEFAULT_NO_LENGTH_CHECK_ENABLE TRUE ++#define DEFAULT_LGTH_CHECK_NOSTDR FALSE ++#define DEFAULT_TIME_STAMP_ENABLE FALSE ++#define DEFAULT_TX_IPG_LENGTH 12 ++#define DEFAULT_MAX_FRAME_LENGTH 0x600 ++#define DEFAULT_PAUSE_QUANT 0xf000 ++ ++/* ++ * 10G memory map ++ */ ++struct tgec_regs { ++ uint32_t tgec_id; /* 0x000 Controller ID */ ++ uint32_t reserved001[1]; /* 0x004 */ ++ uint32_t command_config; /* 0x008 Control and configuration */ ++ uint32_t mac_addr_0; /* 0x00c Lower 32 bits of the MAC adr */ ++ uint32_t mac_addr_1; /* 0x010 Upper 16 bits of the MAC adr */ ++ uint32_t maxfrm; /* 0x014 Maximum frame length */ ++ uint32_t pause_quant; /* 0x018 Pause quanta */ ++ uint32_t rx_fifo_sections; /* 0x01c */ ++ uint32_t tx_fifo_sections; /* 0x020 */ ++ uint32_t rx_fifo_almost_f_e; /* 0x024 */ ++ uint32_t tx_fifo_almost_f_e; /* 0x028 */ ++ uint32_t hashtable_ctrl; /* 0x02c Hash table control*/ ++ uint32_t mdio_cfg_status; /* 0x030 */ ++ uint32_t mdio_command; /* 0x034 */ ++ uint32_t mdio_data; /* 0x038 */ ++ uint32_t mdio_regaddr; /* 0x03c */ ++ uint32_t status; /* 0x040 */ ++ uint32_t tx_ipg_len; /* 0x044 Transmitter inter-packet-gap */ ++ uint32_t mac_addr_2; /* 0x048 Lower 32 bits of 2nd MAC adr */ ++ uint32_t mac_addr_3; /* 0x04c Upper 16 bits of 2nd MAC adr */ ++ uint32_t rx_fifo_ptr_rd; /* 0x050 */ ++ uint32_t rx_fifo_ptr_wr; /* 0x054 */ ++ uint32_t tx_fifo_ptr_rd; /* 0x058 */ ++ uint32_t tx_fifo_ptr_wr; /* 0x05c */ ++ uint32_t imask; /* 0x060 Interrupt mask */ ++ uint32_t ievent; /* 0x064 Interrupt event */ ++ uint32_t udp_port; /* 0x068 Defines a UDP Port number */ ++ uint32_t type_1588v2; /* 0x06c Type field for 1588v2 */ ++ uint32_t reserved070[4]; /* 0x070 */ ++ /*10Ge Statistics Counter */ ++ uint32_t tfrm_u; /* 80 aFramesTransmittedOK */ ++ uint32_t tfrm_l; /* 84 aFramesTransmittedOK */ ++ uint32_t rfrm_u; /* 88 aFramesReceivedOK */ ++ uint32_t rfrm_l; /* 8c aFramesReceivedOK */ ++ uint32_t rfcs_u; /* 90 aFrameCheckSequenceErrors */ ++ uint32_t rfcs_l; /* 94 aFrameCheckSequenceErrors */ ++ uint32_t raln_u; /* 98 aAlignmentErrors */ ++ uint32_t raln_l; /* 9c aAlignmentErrors */ ++ uint32_t txpf_u; /* A0 aPAUSEMACCtrlFramesTransmitted */ ++ uint32_t txpf_l; /* A4 aPAUSEMACCtrlFramesTransmitted */ ++ uint32_t rxpf_u; /* A8 aPAUSEMACCtrlFramesReceived */ ++ uint32_t rxpf_l; /* Ac aPAUSEMACCtrlFramesReceived */ ++ uint32_t rlong_u; /* B0 aFrameTooLongErrors */ ++ uint32_t rlong_l; /* B4 aFrameTooLongErrors */ ++ uint32_t rflr_u; /* B8 aInRangeLengthErrors */ ++ uint32_t rflr_l; /* Bc aInRangeLengthErrors */ ++ uint32_t tvlan_u; /* C0 VLANTransmittedOK */ ++ uint32_t tvlan_l; /* C4 VLANTransmittedOK */ ++ uint32_t rvlan_u; /* C8 VLANReceivedOK */ ++ uint32_t rvlan_l; /* Cc VLANReceivedOK */ ++ uint32_t toct_u; /* D0 ifOutOctets */ ++ uint32_t toct_l; /* D4 ifOutOctets */ ++ uint32_t roct_u; /* D8 ifInOctets */ ++ uint32_t roct_l; /* Dc ifInOctets */ ++ uint32_t ruca_u; /* E0 ifInUcastPkts */ ++ uint32_t ruca_l; /* E4 ifInUcastPkts */ ++ uint32_t rmca_u; /* E8 ifInMulticastPkts */ ++ uint32_t rmca_l; /* Ec ifInMulticastPkts */ ++ uint32_t rbca_u; /* F0 ifInBroadcastPkts */ ++ uint32_t rbca_l; /* F4 ifInBroadcastPkts */ ++ uint32_t terr_u; /* F8 ifOutErrors */ ++ uint32_t terr_l; /* Fc ifOutErrors */ ++ uint32_t reserved100[2]; /* 100-108*/ ++ uint32_t tuca_u; /* 108 ifOutUcastPkts */ ++ uint32_t tuca_l; /* 10c ifOutUcastPkts */ ++ uint32_t tmca_u; /* 110 ifOutMulticastPkts */ ++ uint32_t tmca_l; /* 114 ifOutMulticastPkts */ ++ uint32_t tbca_u; /* 118 ifOutBroadcastPkts */ ++ uint32_t tbca_l; /* 11c ifOutBroadcastPkts */ ++ uint32_t rdrp_u; /* 120 etherStatsDropEvents */ ++ uint32_t rdrp_l; /* 124 etherStatsDropEvents */ ++ uint32_t reoct_u; /* 128 etherStatsOctets */ ++ uint32_t reoct_l; /* 12c etherStatsOctets */ ++ uint32_t rpkt_u; /* 130 etherStatsPkts */ ++ uint32_t rpkt_l; /* 134 etherStatsPkts */ ++ uint32_t trund_u; /* 138 etherStatsUndersizePkts */ ++ uint32_t trund_l; /* 13c etherStatsUndersizePkts */ ++ uint32_t r64_u; /* 140 etherStatsPkts64Octets */ ++ uint32_t r64_l; /* 144 etherStatsPkts64Octets */ ++ uint32_t r127_u; /* 148 etherStatsPkts65to127Octets */ ++ uint32_t r127_l; /* 14c etherStatsPkts65to127Octets */ ++ uint32_t r255_u; /* 150 etherStatsPkts128to255Octets */ ++ uint32_t r255_l; /* 154 etherStatsPkts128to255Octets */ ++ uint32_t r511_u; /* 158 etherStatsPkts256to511Octets */ ++ uint32_t r511_l; /* 15c etherStatsPkts256to511Octets */ ++ uint32_t r1023_u; /* 160 etherStatsPkts512to1023Octets */ ++ uint32_t r1023_l; /* 164 etherStatsPkts512to1023Octets */ ++ uint32_t r1518_u; /* 168 etherStatsPkts1024to1518Octets */ ++ uint32_t r1518_l; /* 16c etherStatsPkts1024to1518Octets */ ++ uint32_t r1519x_u; /* 170 etherStatsPkts1519toX */ ++ uint32_t r1519x_l; /* 174 etherStatsPkts1519toX */ ++ uint32_t trovr_u; /* 178 etherStatsOversizePkts */ ++ uint32_t trovr_l; /* 17c etherStatsOversizePkts */ ++ uint32_t trjbr_u; /* 180 etherStatsJabbers */ ++ uint32_t trjbr_l; /* 184 etherStatsJabbers */ ++ uint32_t trfrg_u; /* 188 etherStatsFragments */ ++ uint32_t trfrg_l; /* 18C etherStatsFragments */ ++ uint32_t rerr_u; /* 190 ifInErrors */ ++ uint32_t rerr_l; /* 194 ifInErrors */ ++}; ++ ++/** ++ * struct tgec_cfg - TGEC configuration ++ * ++ * @rx_error_discard: Receive Erroneous Frame Discard Enable. When set to 1 ++ * any frame received with an error is discarded in the ++ * Core and not forwarded to the Client interface. ++ * When set to 0 (Reset value), erroneous Frames are ++ * forwarded to the Client interface with ff_rx_err ++ * asserted. ++ * @pause_ignore: Ignore Pause Frame Quanta. If set to 1 received pause ++ * frames are ignored by the MAC. When set to 0 ++ * (Reset value) the transmit process is stopped for the ++ * amount of time specified in the pause quanta received ++ * within a pause frame. ++ * @pause_forward_enable: ++ * Terminate / Forward Pause Frames. If set to 1 pause ++ * frames are forwarded to the user application. When set ++ * to 0 (Reset value) pause frames are terminated and ++ * discarded within the MAC. ++ * @no_length_check_enable: ++ * Payload Length Check Disable. When set to 0 ++ * (Reset value), the Core checks the frame's payload ++ * length with the Frame Length/Type field, when set to 1 ++ * the payload length check is disabled. ++ * @cmd_frame_enable: Enables reception of all command frames. When set to 1 ++ * all Command Frames are accepted, when set to 0 ++ * (Reset Value) only Pause Frames are accepted and all ++ * other Command Frames are rejected. ++ * @send_idle_enable: Force Idle Generation. When set to 1, the MAC ++ * permanently sends XGMII Idle sequences even when faults ++ * are received. ++ * @wan_mode_enable: WAN Mode Enable. Sets WAN mode (1) or LAN mode ++ * (0, default) of operation. ++ * @promiscuous_mode_enable: ++ * Enables MAC promiscuous operation. When set to 1, all ++ * frames are received without any MAC address filtering, ++ * when set to 0 (Reset value) Unicast Frames with a ++ * destination address not matching the Core MAC Address ++ * (MAC Address programmed in Registers MAC_ADDR_0 and ++ * MAC_ADDR_1 or the MAC address programmed in Registers ++ * MAC_ADDR_2 and MAC_ADDR_3) are rejected. ++ * @tx_addr_ins_enable: Set Source MAC Address on Transmit. If set to 1 the ++ * MAC overwrites the source MAC address received from the ++ * Client Interface with one of the MAC addresses. If set ++ * to 0 (Reset value), the source MAC address from the ++ * Client Interface is transmitted unmodified to the line. ++ * @loopback_enable: PHY Interface Loopback. When set to 1, the signal ++ * loop_ena is set to '1', when set to 0 (Reset value) ++ * the signal loop_ena is set to 0. ++ * @lgth_check_nostdr: The Core interprets the Length/Type field differently ++ * depending on the value of this Bit ++ * @time_stamp_enable: This bit selects between enabling and disabling the ++ * IEEE 1588 functionality. 1: IEEE 1588 is enabled ++ * 0: IEEE 1588 is disabled ++ * @max_frame_length: Maximum supported received frame length. ++ * The 10GEC MAC supports reception of any frame size up ++ * to 16,352 bytes (0x3FE0). Typical settings are ++ * 0x05EE (1,518 bytes) for standard frames. ++ * Default setting is 0x0600 (1,536 bytes). ++ * Received frames that exceed this stated maximum ++ * are truncated. ++ * @pause_quant: Pause quanta value used with transmitted pause frames. ++ * Each quanta represents a 512 bit-times. ++ * @tx_ipg_length: Transmit Inter-Packet-Gap (IPG) value. A 6-bit value: ++ * Depending on LAN or WAN mode of operation the value has ++ * the following meaning: - LAN Mode: Number of octets in ++ * steps of 4. Valid values are 8, 12, 16, ... 100. DIC is ++ * fully supported (see 10.6.1 page 49) for any setting. A ++ * default of 12 (reset value) must be set to conform to ++ * IEEE802.3ae. Warning: When set to 8, PCS layers may not ++ * be able to perform clock rate compensation. - WAN Mode: ++ * Stretch factor. Valid values are 4..15. The stretch ++ * factor is calculated as (value+1)*8. A default of 12 ++ * (reset value) must be set to conform to IEEE 802.3ae ++ * (i.e. 13*8=104). A larger value shrinks the IPG ++ * (increasing bandwidth). ++ * ++ * This structure contains basic TGEC configuration and must be passed to ++ * fman_tgec_init() function. A default set of configuration values can be ++ * obtained by calling fman_tgec_defconfig(). ++ */ ++struct tgec_cfg { ++ bool rx_error_discard; ++ bool pause_ignore; ++ bool pause_forward_enable; ++ bool no_length_check_enable; ++ bool cmd_frame_enable; ++ bool send_idle_enable; ++ bool wan_mode_enable; ++ bool promiscuous_mode_enable; ++ bool tx_addr_ins_enable; ++ bool loopback_enable; ++ bool lgth_check_nostdr; ++ bool time_stamp_enable; ++ uint16_t max_frame_length; ++ uint16_t pause_quant; ++ uint32_t tx_ipg_length; ++ bool skip_fman11_workaround; ++}; ++ ++ ++void fman_tgec_defconfig(struct tgec_cfg *cfg); ++ ++/** ++ * fman_tgec_init() - Init tgec hardware block ++ * @regs: Pointer to tgec register block ++ * @cfg: tgec configuration data ++ * @exceptions_mask: initial exceptions mask ++ * ++ * This function initializes the tgec controller and applies its ++ * basic configuration. ++ * ++ * Returns: 0 if successful, an error code otherwise. ++ */ ++ ++int fman_tgec_init(struct tgec_regs *regs, struct tgec_cfg *cfg, ++ uint32_t exception_mask); ++ ++void fman_tgec_enable(struct tgec_regs *regs, bool apply_rx, bool apply_tx); ++ ++void fman_tgec_disable(struct tgec_regs *regs, bool apply_rx, bool apply_tx); ++ ++uint32_t fman_tgec_get_revision(struct tgec_regs *regs); ++ ++void fman_tgec_set_mac_address(struct tgec_regs *regs, uint8_t *macaddr); ++ ++void fman_tgec_set_promiscuous(struct tgec_regs *regs, bool val); ++ ++/** ++ * fman_tgec_reset_stat() - Completely resets all TGEC HW counters ++ * @regs: Pointer to TGEC register block ++ */ ++void fman_tgec_reset_stat(struct tgec_regs *regs); ++ ++/** ++ * fman_tgec_get_counter() - Reads TGEC HW counters ++ * @regs: Pointer to TGEC register block ++ * @reg_name: Counter name according to the appropriate enum ++ * ++ * Returns: Required counter value ++ */ ++uint64_t fman_tgec_get_counter(struct tgec_regs *regs, ++ enum tgec_counters reg_name); ++ ++/** ++ * fman_tgec_set_hash_table() - Sets the Hashtable Control Register ++ * @regs: Pointer to TGEC register block ++ * @value: Value to be written in Hashtable Control Register ++ */ ++void fman_tgec_set_hash_table(struct tgec_regs *regs, uint32_t value); ++ ++/** ++ * fman_tgec_set_tx_pause_frames() - Sets the Pause Quanta Register ++ * @regs: Pointer to TGEC register block ++ * @pause_time: Pause quanta value used with transmitted pause frames. ++ * Each quanta represents a 512 bit-times ++ */ ++void fman_tgec_set_tx_pause_frames(struct tgec_regs *regs, uint16_t pause_time); ++ ++/** ++ * fman_tgec_set_rx_ignore_pause_frames() - Changes the policy WRT pause frames ++ * @regs: Pointer to TGEC register block ++ * @en: Ignore/Respond to pause frame quanta ++ * ++ * Sets the value of PAUSE_IGNORE field in the COMMAND_CONFIG Register ++ * 0 - MAC stops transmit process for the duration specified ++ * in the Pause frame quanta of a received Pause frame. ++ * 1 - MAC ignores received Pause frames. ++ */ ++void fman_tgec_set_rx_ignore_pause_frames(struct tgec_regs *regs, bool en); ++ ++/** ++ * fman_tgec_enable_1588_time_stamp() - change timestamp functionality ++ * @regs: Pointer to TGEC register block ++ * @en: enable/disable timestamp functionality ++ * ++ * Sets the value of EN_TIMESTAMP field in the COMMAND_CONFIG Register ++ * IEEE 1588 timestamp functionality control: ++ * 0 disabled, 1 enabled ++ */ ++ ++void fman_tgec_enable_1588_time_stamp(struct tgec_regs *regs, bool en); ++ ++uint32_t fman_tgec_get_event(struct tgec_regs *regs, uint32_t ev_mask); ++ ++void fman_tgec_ack_event(struct tgec_regs *regs, uint32_t ev_mask); ++ ++uint32_t fman_tgec_get_interrupt_mask(struct tgec_regs *regs); ++ ++/** ++ * fman_tgec_add_addr_in_paddr() - Sets additional exact match MAC address ++ * @regs: Pointer to TGEC register block ++ * @addr_ptr: Pointer to 6-byte array containing the MAC address ++ * ++ * Sets the additional station MAC address ++ */ ++void fman_tgec_add_addr_in_paddr(struct tgec_regs *regs, uint8_t *addr_ptr); ++ ++void fman_tgec_clear_addr_in_paddr(struct tgec_regs *regs); ++ ++void fman_tgec_enable_interrupt(struct tgec_regs *regs, uint32_t ev_mask); ++ ++void fman_tgec_disable_interrupt(struct tgec_regs *regs, uint32_t ev_mask); ++ ++void fman_tgec_reset_filter_table(struct tgec_regs *regs); ++ ++void fman_tgec_set_hash_table_entry(struct tgec_regs *regs, uint32_t crc); ++ ++ ++/** ++ * fman_tgec_get_max_frame_len() - Returns the maximum frame length value ++ * @regs: Pointer to TGEC register block ++ */ ++uint16_t fman_tgec_get_max_frame_len(struct tgec_regs *regs); ++ ++/** ++ * fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007() - Initialize the ++ * main tgec configuration parameters ++ * @regs: Pointer to TGEC register block ++ * ++ * TODO ++ */ ++void fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007(struct tgec_regs ++ *regs); ++ ++ ++#endif /* __FSL_FMAN_TGEC_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/dpaa_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/dpaa_integration_ext.h +new file mode 100644 +index 00000000..0346cf60 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/dpaa_integration_ext.h +@@ -0,0 +1,291 @@ ++/* ++ * Copyright 2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/** ++ ++ @File dpaa_integration_ext.h ++ ++ @Description T4240 FM external definitions and structures. ++*//***************************************************************************/ ++#ifndef __DPAA_INTEGRATION_EXT_H ++#define __DPAA_INTEGRATION_EXT_H ++ ++#include "std_ext.h" ++ ++ ++#define DPAA_VERSION 11 ++ ++/**************************************************************************//** ++ @Description DPAA SW Portals Enumeration. ++*//***************************************************************************/ ++typedef enum ++{ ++ e_DPAA_SWPORTAL0 = 0, ++ e_DPAA_SWPORTAL1, ++ e_DPAA_SWPORTAL2, ++ e_DPAA_SWPORTAL3, ++ e_DPAA_SWPORTAL4, ++ e_DPAA_SWPORTAL5, ++ e_DPAA_SWPORTAL6, ++ e_DPAA_SWPORTAL7, ++ e_DPAA_SWPORTAL8, ++ e_DPAA_SWPORTAL9, ++ e_DPAA_SWPORTAL10, ++ e_DPAA_SWPORTAL11, ++ e_DPAA_SWPORTAL12, ++ e_DPAA_SWPORTAL13, ++ e_DPAA_SWPORTAL14, ++ e_DPAA_SWPORTAL15, ++ e_DPAA_SWPORTAL16, ++ e_DPAA_SWPORTAL17, ++ e_DPAA_SWPORTAL18, ++ e_DPAA_SWPORTAL19, ++ e_DPAA_SWPORTAL20, ++ e_DPAA_SWPORTAL21, ++ e_DPAA_SWPORTAL22, ++ e_DPAA_SWPORTAL23, ++ e_DPAA_SWPORTAL24, ++ e_DPAA_SWPORTAL_DUMMY_LAST ++} e_DpaaSwPortal; ++ ++/**************************************************************************//** ++ @Description DPAA Direct Connect Portals Enumeration. ++*//***************************************************************************/ ++typedef enum ++{ ++ e_DPAA_DCPORTAL0 = 0, ++ e_DPAA_DCPORTAL1, ++ e_DPAA_DCPORTAL2, ++ e_DPAA_DCPORTAL_DUMMY_LAST ++} e_DpaaDcPortal; ++ ++#define DPAA_MAX_NUM_OF_SW_PORTALS e_DPAA_SWPORTAL_DUMMY_LAST ++#define DPAA_MAX_NUM_OF_DC_PORTALS e_DPAA_DCPORTAL_DUMMY_LAST ++ ++/***************************************************************************** ++ QMan INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define QM_MAX_NUM_OF_POOL_CHANNELS 15 /**< Total number of channels, dedicated and pool */ ++#define QM_MAX_NUM_OF_WQ 8 /**< Number of work queues per channel */ ++#define QM_MAX_NUM_OF_CGS 256 /**< Congestion groups number */ ++#define QM_MAX_NUM_OF_FQIDS (16 * MEGABYTE) ++ /**< FQIDs range - 24 bits */ ++ ++/**************************************************************************//** ++ @Description Work Queue Channel assignments in QMan. ++*//***************************************************************************/ ++typedef enum ++{ ++ e_QM_FQ_CHANNEL_SWPORTAL0 = 0x0, /**< Dedicated channels serviced by software portals 0 to 24 */ ++ e_QM_FQ_CHANNEL_SWPORTAL1, ++ e_QM_FQ_CHANNEL_SWPORTAL2, ++ e_QM_FQ_CHANNEL_SWPORTAL3, ++ e_QM_FQ_CHANNEL_SWPORTAL4, ++ e_QM_FQ_CHANNEL_SWPORTAL5, ++ e_QM_FQ_CHANNEL_SWPORTAL6, ++ e_QM_FQ_CHANNEL_SWPORTAL7, ++ e_QM_FQ_CHANNEL_SWPORTAL8, ++ e_QM_FQ_CHANNEL_SWPORTAL9, ++ e_QM_FQ_CHANNEL_SWPORTAL10, ++ e_QM_FQ_CHANNEL_SWPORTAL11, ++ e_QM_FQ_CHANNEL_SWPORTAL12, ++ e_QM_FQ_CHANNEL_SWPORTAL13, ++ e_QM_FQ_CHANNEL_SWPORTAL14, ++ e_QM_FQ_CHANNEL_SWPORTAL15, ++ e_QM_FQ_CHANNEL_SWPORTAL16, ++ e_QM_FQ_CHANNEL_SWPORTAL17, ++ e_QM_FQ_CHANNEL_SWPORTAL18, ++ e_QM_FQ_CHANNEL_SWPORTAL19, ++ e_QM_FQ_CHANNEL_SWPORTAL20, ++ e_QM_FQ_CHANNEL_SWPORTAL21, ++ e_QM_FQ_CHANNEL_SWPORTAL22, ++ e_QM_FQ_CHANNEL_SWPORTAL23, ++ e_QM_FQ_CHANNEL_SWPORTAL24, ++ ++ e_QM_FQ_CHANNEL_POOL1 = 0x401, /**< Pool channels that can be serviced by any of the software portals */ ++ e_QM_FQ_CHANNEL_POOL2, ++ e_QM_FQ_CHANNEL_POOL3, ++ e_QM_FQ_CHANNEL_POOL4, ++ e_QM_FQ_CHANNEL_POOL5, ++ e_QM_FQ_CHANNEL_POOL6, ++ e_QM_FQ_CHANNEL_POOL7, ++ e_QM_FQ_CHANNEL_POOL8, ++ e_QM_FQ_CHANNEL_POOL9, ++ e_QM_FQ_CHANNEL_POOL10, ++ e_QM_FQ_CHANNEL_POOL11, ++ e_QM_FQ_CHANNEL_POOL12, ++ e_QM_FQ_CHANNEL_POOL13, ++ e_QM_FQ_CHANNEL_POOL14, ++ e_QM_FQ_CHANNEL_POOL15, ++ ++ e_QM_FQ_CHANNEL_FMAN0_SP0 = 0x800, /**< Dedicated channels serviced by Direct Connect Portal 0: ++ connected to FMan 0; assigned in incrementing order to ++ each sub-portal (SP) in the portal */ ++ e_QM_FQ_CHANNEL_FMAN0_SP1, ++ e_QM_FQ_CHANNEL_FMAN0_SP2, ++ e_QM_FQ_CHANNEL_FMAN0_SP3, ++ e_QM_FQ_CHANNEL_FMAN0_SP4, ++ e_QM_FQ_CHANNEL_FMAN0_SP5, ++ e_QM_FQ_CHANNEL_FMAN0_SP6, ++ e_QM_FQ_CHANNEL_FMAN0_SP7, ++ e_QM_FQ_CHANNEL_FMAN0_SP8, ++ e_QM_FQ_CHANNEL_FMAN0_SP9, ++ e_QM_FQ_CHANNEL_FMAN0_SP10, ++ e_QM_FQ_CHANNEL_FMAN0_SP11, ++ e_QM_FQ_CHANNEL_FMAN0_SP12, ++ e_QM_FQ_CHANNEL_FMAN0_SP13, ++ e_QM_FQ_CHANNEL_FMAN0_SP14, ++ e_QM_FQ_CHANNEL_FMAN0_SP15, ++ ++ e_QM_FQ_CHANNEL_RMAN_SP0 = 0x820, /**< Dedicated channels serviced by Direct Connect Portal 1: connected to RMan */ ++ e_QM_FQ_CHANNEL_RMAN_SP1, ++ ++ e_QM_FQ_CHANNEL_CAAM = 0x840 /**< Dedicated channel serviced by Direct Connect Portal 2: ++ connected to SEC */ ++} e_QmFQChannel; ++ ++/***************************************************************************** ++ BMan INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define BM_MAX_NUM_OF_POOLS 64 /**< Number of buffers pools */ ++ ++/***************************************************************************** ++ SEC INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define SEC_NUM_OF_DECOS 3 ++#define SEC_ALL_DECOS_MASK 0x00000003 ++ ++ ++/***************************************************************************** ++ FM INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define INTG_MAX_NUM_OF_FM 2 ++/* Ports defines */ ++#define FM_MAX_NUM_OF_1G_MACS 6 ++#define FM_MAX_NUM_OF_10G_MACS 2 ++#define FM_MAX_NUM_OF_MACS (FM_MAX_NUM_OF_1G_MACS + FM_MAX_NUM_OF_10G_MACS) ++#define FM_MAX_NUM_OF_OH_PORTS 6 ++ ++#define FM_MAX_NUM_OF_1G_RX_PORTS FM_MAX_NUM_OF_1G_MACS ++#define FM_MAX_NUM_OF_10G_RX_PORTS FM_MAX_NUM_OF_10G_MACS ++#define FM_MAX_NUM_OF_RX_PORTS (FM_MAX_NUM_OF_10G_RX_PORTS + FM_MAX_NUM_OF_1G_RX_PORTS) ++ ++#define FM_MAX_NUM_OF_1G_TX_PORTS FM_MAX_NUM_OF_1G_MACS ++#define FM_MAX_NUM_OF_10G_TX_PORTS FM_MAX_NUM_OF_10G_MACS ++#define FM_MAX_NUM_OF_TX_PORTS (FM_MAX_NUM_OF_10G_TX_PORTS + FM_MAX_NUM_OF_1G_TX_PORTS) ++ ++#define FM_PORT_MAX_NUM_OF_EXT_POOLS 4 /**< Number of external BM pools per Rx port */ ++#define FM_PORT_NUM_OF_CONGESTION_GRPS 256 /**< Total number of congestion groups in QM */ ++#define FM_MAX_NUM_OF_SUB_PORTALS 16 ++#define FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS 0 ++ ++#define FM_VSP_MAX_NUM_OF_ENTRIES 64 ++#define FM_MAX_NUM_OF_PFC_PRIORITIES 8 ++ ++/* RAMs defines */ ++#define FM_MURAM_SIZE (384 * KILOBYTE) ++#define FM_IRAM_SIZE(major, minor) (64 * KILOBYTE) ++#define FM_NUM_OF_CTRL 4 ++ ++/* PCD defines */ ++#define FM_PCD_PLCR_NUM_ENTRIES 256 /**< Total number of policer profiles */ ++#define FM_PCD_KG_NUM_OF_SCHEMES 32 /**< Total number of KG schemes */ ++#define FM_PCD_MAX_NUM_OF_CLS_PLANS 256 /**< Number of classification plan entries. */ ++#define FM_PCD_PRS_SW_PATCHES_SIZE 0x00000600 /**< Number of bytes saved for patches */ ++#define FM_PCD_SW_PRS_SIZE 0x00000800 /**< Total size of SW parser area */ ++ ++/* RTC defines */ ++#define FM_RTC_NUM_OF_ALARMS 2 /**< RTC number of alarms */ ++#define FM_RTC_NUM_OF_PERIODIC_PULSES 3 /**< RTC number of periodic pulses */ ++#define FM_RTC_NUM_OF_EXT_TRIGGERS 2 /**< RTC number of external triggers */ ++ ++/* QMI defines */ ++#define QMI_MAX_NUM_OF_TNUMS 64 ++#define QMI_DEF_TNUMS_THRESH 32 ++/* FPM defines */ ++#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS 4 ++ ++/* DMA defines */ ++#define DMA_THRESH_MAX_COMMQ 83 ++#define DMA_THRESH_MAX_BUF 127 ++ ++/* BMI defines */ ++#define BMI_MAX_NUM_OF_TASKS 128 ++#define BMI_MAX_NUM_OF_DMAS 84 ++ ++#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE) ++#define PORT_MAX_WEIGHT 16 ++ ++#define FM_CHECK_PORT_RESTRICTIONS(__validPorts, __newPortIndx) TRUE ++ ++/* Unique T4240 */ ++#define FM_OP_OPEN_DMA_MIN_LIMIT ++#define FM_NO_RESTRICT_ON_ACCESS_RSRC ++#define FM_NO_OP_OBSERVED_POOLS ++#define FM_FRAME_END_PARAMS_FOR_OP ++#define FM_DEQ_PIPELINE_PARAMS_FOR_OP ++#define FM_QMI_NO_SINGLE_ECC_EXCEPTION ++ ++#define FM_NO_GUARANTEED_RESET_VALUES ++ ++/* FM errata */ ++#define FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 ++#define FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 ++#define FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320 ++#define FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675 ++#define FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 ++#define FM_HANG_AT_RESET_MAC_CLK_DISABLED_ERRATA_FMAN_A007273 ++ ++#define FM_BCB_ERRATA_BMI_SW001 ++#define FM_LEN_CHECK_ERRATA_FMAN_SW002 ++#define FM_AID_MODE_NO_TNUM_SW005 /* refer to pdm TKT068794 - only support of port_id on aid */ ++#define FM_ERROR_VSP_NO_MATCH_SW006 /* refer to pdm TKT174304 - no match between errorQ and VSP */ ++ ++/***************************************************************************** ++ RMan INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define RM_MAX_NUM_OF_IB 4 /**< Number of inbound blocks */ ++#define RM_NUM_OF_IBCU 8 /**< NUmber of classification units in an inbound block */ ++ ++/* RMan erratas */ ++#define RM_ERRONEOUS_ACK_ERRATA_RMAN_A006756 ++ ++/***************************************************************************** ++ FM MACSEC INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define NUM_OF_RX_SC 16 ++#define NUM_OF_TX_SC 16 ++ ++#define NUM_OF_SA_PER_RX_SC 2 ++#define NUM_OF_SA_PER_TX_SC 2 ++ ++#endif /* __DPAA_INTEGRATION_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_ext.h +new file mode 100644 +index 00000000..0d62dd15 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_ext.h +@@ -0,0 +1,71 @@ ++/* ++ * Copyright 2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/**************************************************************************//** ++ ++ @File part_ext.h ++ ++ @Description Definitions for the part (integration) module. ++*//***************************************************************************/ ++ ++#ifndef __PART_EXT_H ++#define __PART_EXT_H ++ ++#include "std_ext.h" ++#include "part_integration_ext.h" ++ ++#if !(defined(P1023) || \ ++ defined(P2041) || \ ++ defined(P3041) || \ ++ defined(P4080) || \ ++ defined(P5020) || \ ++ defined(P5040) || \ ++ defined(B4860) || \ ++ defined(T4240)) ++#error "unable to proceed without chip-definition" ++#endif ++ ++ ++/**************************************************************************//* ++ @Description Part data structure - must be contained in any integration ++ data structure. ++*//***************************************************************************/ ++typedef struct t_Part ++{ ++ uintptr_t (* f_GetModuleBase)(t_Handle h_Part, e_ModuleId moduleId); ++ /**< Returns the address of the module's memory map base. */ ++ e_ModuleId (* f_GetModuleIdByBase)(t_Handle h_Part, uintptr_t baseAddress); ++ /**< Returns the module's ID according to its memory map base. */ ++} t_Part; ++ ++ ++#endif /* __PART_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_integration_ext.h +new file mode 100644 +index 00000000..3254c766 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3H/part_integration_ext.h +@@ -0,0 +1,304 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/** ++ ++ @File part_integration_ext.h ++ ++ @Description T4240 external definitions and structures. ++*//***************************************************************************/ ++#ifndef __PART_INTEGRATION_EXT_H ++#define __PART_INTEGRATION_EXT_H ++ ++#include "std_ext.h" ++#include "ddr_std_ext.h" ++#include "enet_ext.h" ++#include "dpaa_integration_ext.h" ++ ++ ++/**************************************************************************//** ++ @Group T4240_chip_id T4240 Application Programming Interface ++ ++ @Description T4240 Chip functions,definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++#define CORE_E6500 ++ ++#define INTG_MAX_NUM_OF_CORES 24 ++ ++ ++/**************************************************************************//** ++ @Description Module types. ++*//***************************************************************************/ ++typedef enum e_ModuleId ++{ ++ e_MODULE_ID_DUART_1 = 0, ++ e_MODULE_ID_DUART_2, ++ e_MODULE_ID_DUART_3, ++ e_MODULE_ID_DUART_4, ++ e_MODULE_ID_LAW, ++ e_MODULE_ID_IFC, ++ e_MODULE_ID_PAMU, ++ e_MODULE_ID_QM, /**< Queue manager module */ ++ e_MODULE_ID_BM, /**< Buffer manager module */ ++ e_MODULE_ID_QM_CE_PORTAL_0, ++ e_MODULE_ID_QM_CI_PORTAL_0, ++ e_MODULE_ID_QM_CE_PORTAL_1, ++ e_MODULE_ID_QM_CI_PORTAL_1, ++ e_MODULE_ID_QM_CE_PORTAL_2, ++ e_MODULE_ID_QM_CI_PORTAL_2, ++ e_MODULE_ID_QM_CE_PORTAL_3, ++ e_MODULE_ID_QM_CI_PORTAL_3, ++ e_MODULE_ID_QM_CE_PORTAL_4, ++ e_MODULE_ID_QM_CI_PORTAL_4, ++ e_MODULE_ID_QM_CE_PORTAL_5, ++ e_MODULE_ID_QM_CI_PORTAL_5, ++ e_MODULE_ID_QM_CE_PORTAL_6, ++ e_MODULE_ID_QM_CI_PORTAL_6, ++ e_MODULE_ID_QM_CE_PORTAL_7, ++ e_MODULE_ID_QM_CI_PORTAL_7, ++ e_MODULE_ID_QM_CE_PORTAL_8, ++ e_MODULE_ID_QM_CI_PORTAL_8, ++ e_MODULE_ID_QM_CE_PORTAL_9, ++ e_MODULE_ID_QM_CI_PORTAL_9, ++ e_MODULE_ID_BM_CE_PORTAL_0, ++ e_MODULE_ID_BM_CI_PORTAL_0, ++ e_MODULE_ID_BM_CE_PORTAL_1, ++ e_MODULE_ID_BM_CI_PORTAL_1, ++ e_MODULE_ID_BM_CE_PORTAL_2, ++ e_MODULE_ID_BM_CI_PORTAL_2, ++ e_MODULE_ID_BM_CE_PORTAL_3, ++ e_MODULE_ID_BM_CI_PORTAL_3, ++ e_MODULE_ID_BM_CE_PORTAL_4, ++ e_MODULE_ID_BM_CI_PORTAL_4, ++ e_MODULE_ID_BM_CE_PORTAL_5, ++ e_MODULE_ID_BM_CI_PORTAL_5, ++ e_MODULE_ID_BM_CE_PORTAL_6, ++ e_MODULE_ID_BM_CI_PORTAL_6, ++ e_MODULE_ID_BM_CE_PORTAL_7, ++ e_MODULE_ID_BM_CI_PORTAL_7, ++ e_MODULE_ID_BM_CE_PORTAL_8, ++ e_MODULE_ID_BM_CI_PORTAL_8, ++ e_MODULE_ID_BM_CE_PORTAL_9, ++ e_MODULE_ID_BM_CI_PORTAL_9, ++ e_MODULE_ID_FM, /**< Frame manager module */ ++ e_MODULE_ID_FM_RTC, /**< FM Real-Time-Clock */ ++ e_MODULE_ID_FM_MURAM, /**< FM Multi-User-RAM */ ++ e_MODULE_ID_FM_BMI, /**< FM BMI block */ ++ e_MODULE_ID_FM_QMI, /**< FM QMI block */ ++ e_MODULE_ID_FM_PARSER, /**< FM parser block */ ++ e_MODULE_ID_FM_PORT_HO1, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO2, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO3, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO4, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO5, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO6, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO7, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_1GRx1, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GRx2, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GRx3, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GRx4, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GRx5, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GRx6, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_10GRx1, /**< FM Rx 10G MAC port block */ ++ e_MODULE_ID_FM_PORT_10GRx2, /**< FM Rx 10G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx1, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx2, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx3, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx4, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx5, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx6, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_10GTx1, /**< FM Tx 10G MAC port block */ ++ e_MODULE_ID_FM_PORT_10GTx2, /**< FM Tx 10G MAC port block */ ++ e_MODULE_ID_FM_PLCR, /**< FM Policer */ ++ e_MODULE_ID_FM_KG, /**< FM Keygen */ ++ e_MODULE_ID_FM_DMA, /**< FM DMA */ ++ e_MODULE_ID_FM_FPM, /**< FM FPM */ ++ e_MODULE_ID_FM_IRAM, /**< FM Instruction-RAM */ ++ e_MODULE_ID_FM_1GMDIO, /**< FM 1G MDIO MAC */ ++ e_MODULE_ID_FM_10GMDIO, /**< FM 10G MDIO */ ++ e_MODULE_ID_FM_PRS_IRAM, /**< FM SW-parser Instruction-RAM */ ++ e_MODULE_ID_FM_1GMAC1, /**< FM 1G MAC #1 */ ++ e_MODULE_ID_FM_1GMAC2, /**< FM 1G MAC #2 */ ++ e_MODULE_ID_FM_1GMAC3, /**< FM 1G MAC #3 */ ++ e_MODULE_ID_FM_1GMAC4, /**< FM 1G MAC #4 */ ++ e_MODULE_ID_FM_1GMAC5, /**< FM 1G MAC #5 */ ++ e_MODULE_ID_FM_1GMAC6, /**< FM 1G MAC #6 */ ++ e_MODULE_ID_FM_10GMAC1, /**< FM 10G MAC */ ++ e_MODULE_ID_FM_10GMAC2, /**< FM 10G MAC */ ++ ++ e_MODULE_ID_SEC_GEN, /**< SEC 4.0 General registers */ ++ e_MODULE_ID_SEC_QI, /**< SEC 4.0 QI registers */ ++ e_MODULE_ID_SEC_JQ0, /**< SEC 4.0 JQ-0 registers */ ++ e_MODULE_ID_SEC_JQ1, /**< SEC 4.0 JQ-1 registers */ ++ e_MODULE_ID_SEC_JQ2, /**< SEC 4.0 JQ-2 registers */ ++ e_MODULE_ID_SEC_JQ3, /**< SEC 4.0 JQ-3 registers */ ++ e_MODULE_ID_SEC_RTIC, /**< SEC 4.0 RTIC registers */ ++ e_MODULE_ID_SEC_DECO0_CCB0, /**< SEC 4.0 DECO-0/CCB-0 registers */ ++ e_MODULE_ID_SEC_DECO1_CCB1, /**< SEC 4.0 DECO-1/CCB-1 registers */ ++ e_MODULE_ID_SEC_DECO2_CCB2, /**< SEC 4.0 DECO-2/CCB-2 registers */ ++ e_MODULE_ID_SEC_DECO3_CCB3, /**< SEC 4.0 DECO-3/CCB-3 registers */ ++ e_MODULE_ID_SEC_DECO4_CCB4, /**< SEC 4.0 DECO-4/CCB-4 registers */ ++ ++ e_MODULE_ID_PIC, /**< PIC */ ++ e_MODULE_ID_GPIO, /**< GPIO */ ++ e_MODULE_ID_SERDES, /**< SERDES */ ++ e_MODULE_ID_CPC_1, /**< CoreNet-Platform-Cache 1 */ ++ e_MODULE_ID_CPC_2, /**< CoreNet-Platform-Cache 2 */ ++ ++ e_MODULE_ID_SRIO_PORTS, /**< RapidIO controller */ ++ ++ e_MODULE_ID_DUMMY_LAST ++} e_ModuleId; ++ ++#define NUM_OF_MODULES e_MODULE_ID_DUMMY_LAST ++ ++#if 0 /* using unified values */ ++/***************************************************************************** ++ INTEGRATION-SPECIFIC MODULE CODES ++******************************************************************************/ ++#define MODULE_UNKNOWN 0x00000000 ++#define MODULE_MEM 0x00010000 ++#define MODULE_MM 0x00020000 ++#define MODULE_CORE 0x00030000 ++#define MODULE_T4240 0x00040000 ++#define MODULE_T4240_PLATFORM 0x00050000 ++#define MODULE_PM 0x00060000 ++#define MODULE_MMU 0x00070000 ++#define MODULE_PIC 0x00080000 ++#define MODULE_CPC 0x00090000 ++#define MODULE_DUART 0x000a0000 ++#define MODULE_SERDES 0x000b0000 ++#define MODULE_PIO 0x000c0000 ++#define MODULE_QM 0x000d0000 ++#define MODULE_BM 0x000e0000 ++#define MODULE_SEC 0x000f0000 ++#define MODULE_LAW 0x00100000 ++#define MODULE_LBC 0x00110000 ++#define MODULE_PAMU 0x00120000 ++#define MODULE_FM 0x00130000 ++#define MODULE_FM_MURAM 0x00140000 ++#define MODULE_FM_PCD 0x00150000 ++#define MODULE_FM_RTC 0x00160000 ++#define MODULE_FM_MAC 0x00170000 ++#define MODULE_FM_PORT 0x00180000 ++#define MODULE_FM_SP 0x00190000 ++#define MODULE_DPA_PORT 0x001a0000 ++#define MODULE_MII 0x001b0000 ++#define MODULE_I2C 0x001c0000 ++#define MODULE_DMA 0x001d0000 ++#define MODULE_DDR 0x001e0000 ++#define MODULE_ESPI 0x001f0000 ++#define MODULE_DPAA_IPSEC 0x00200000 ++#endif /* using unified values */ ++ ++/***************************************************************************** ++ PAMU INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define PAMU_NUM_OF_PARTITIONS 4 ++ ++/***************************************************************************** ++ LAW INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define LAW_NUM_OF_WINDOWS 32 ++#define LAW_MIN_WINDOW_SIZE 0x0000000000001000LL /**< 4 Kbytes */ ++#define LAW_MAX_WINDOW_SIZE 0x0000010000000000LL /**< 1 Tbytes for 40-bit address space */ ++ ++ ++/***************************************************************************** ++ LBC INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++/**************************************************************************//** ++ @Group lbc_exception_grp LBC Exception Unit ++ ++ @Description LBC Exception unit API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Anchor lbc_exbm ++ ++ @Collection LBC Errors Bit Mask ++ ++ These errors are reported through the exceptions callback.. ++ The values can be or'ed in any combination in the errors mask ++ parameter of the errors report structure. ++ ++ These errors can also be passed as a bit-mask to ++ LBC_EnableErrorChecking() or LBC_DisableErrorChecking(), ++ for enabling or disabling error checking. ++ @{ ++*//***************************************************************************/ ++#define LBC_ERR_BUS_MONITOR 0x80000000 /**< Bus monitor error */ ++#define LBC_ERR_PARITY_ECC 0x20000000 /**< Parity error for GPCM/UPM */ ++#define LBC_ERR_WRITE_PROTECT 0x04000000 /**< Write protection error */ ++#define LBC_ERR_CHIP_SELECT 0x00080000 /**< Unrecognized chip select */ ++ ++#define LBC_ERR_ALL (LBC_ERR_BUS_MONITOR | LBC_ERR_PARITY_ECC | \ ++ LBC_ERR_WRITE_PROTECT | LBC_ERR_CHIP_SELECT) ++ /**< All possible errors */ ++/* @} */ ++/** @} */ /* end of lbc_exception_grp group */ ++ ++#define LBC_INCORRECT_ERROR_REPORT_ERRATA ++ ++#define LBC_NUM_OF_BANKS 8 ++#define LBC_MAX_CS_SIZE 0x0000000100000000LL /* Up to 4G memory block size */ ++#define LBC_PARITY_SUPPORT ++#define LBC_ADDRESS_HOLD_TIME_CTRL ++#define LBC_HIGH_CLK_DIVIDERS ++#define LBC_FCM_AVAILABLE ++ ++/***************************************************************************** ++ GPIO INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define GPIO_PORT_OFFSET_0x1000 ++ ++#define GPIO_NUM_OF_PORTS 3 /**< Number of ports in GPIO module; ++ Each port contains up to 32 I/O pins. */ ++ ++#define GPIO_VALID_PIN_MASKS \ ++ { /* Port A */ 0xFFFFFFFF, \ ++ /* Port B */ 0xFFFFFFFF, \ ++ /* Port C */ 0xFFFFFFFF } ++ ++#define GPIO_VALID_INTR_MASKS \ ++ { /* Port A */ 0xFFFFFFFF, \ ++ /* Port B */ 0xFFFFFFFF, \ ++ /* Port C */ 0xFFFFFFFF } ++ ++ ++ ++#endif /* __PART_INTEGRATION_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/dpaa_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/dpaa_integration_ext.h +new file mode 100644 +index 00000000..f7f8eb07 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/dpaa_integration_ext.h +@@ -0,0 +1,293 @@ ++/* ++ * Copyright 2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/** ++ ++ @File dpaa_integration_ext.h ++ ++ @Description T4240 FM external definitions and structures. ++*//***************************************************************************/ ++#ifndef __DPAA_INTEGRATION_EXT_H ++#define __DPAA_INTEGRATION_EXT_H ++ ++#include "std_ext.h" ++ ++ ++#define DPAA_VERSION 11 ++ ++/**************************************************************************//** ++ @Description DPAA SW Portals Enumeration. ++*//***************************************************************************/ ++typedef enum ++{ ++ e_DPAA_SWPORTAL0 = 0, ++ e_DPAA_SWPORTAL1, ++ e_DPAA_SWPORTAL2, ++ e_DPAA_SWPORTAL3, ++ e_DPAA_SWPORTAL4, ++ e_DPAA_SWPORTAL5, ++ e_DPAA_SWPORTAL6, ++ e_DPAA_SWPORTAL7, ++ e_DPAA_SWPORTAL8, ++ e_DPAA_SWPORTAL9, ++ e_DPAA_SWPORTAL10, ++ e_DPAA_SWPORTAL11, ++ e_DPAA_SWPORTAL12, ++ e_DPAA_SWPORTAL13, ++ e_DPAA_SWPORTAL14, ++ e_DPAA_SWPORTAL15, ++ e_DPAA_SWPORTAL16, ++ e_DPAA_SWPORTAL17, ++ e_DPAA_SWPORTAL18, ++ e_DPAA_SWPORTAL19, ++ e_DPAA_SWPORTAL20, ++ e_DPAA_SWPORTAL21, ++ e_DPAA_SWPORTAL22, ++ e_DPAA_SWPORTAL23, ++ e_DPAA_SWPORTAL24, ++ e_DPAA_SWPORTAL_DUMMY_LAST ++} e_DpaaSwPortal; ++ ++/**************************************************************************//** ++ @Description DPAA Direct Connect Portals Enumeration. ++*//***************************************************************************/ ++typedef enum ++{ ++ e_DPAA_DCPORTAL0 = 0, ++ e_DPAA_DCPORTAL1, ++ e_DPAA_DCPORTAL2, ++ e_DPAA_DCPORTAL_DUMMY_LAST ++} e_DpaaDcPortal; ++ ++#define DPAA_MAX_NUM_OF_SW_PORTALS e_DPAA_SWPORTAL_DUMMY_LAST ++#define DPAA_MAX_NUM_OF_DC_PORTALS e_DPAA_DCPORTAL_DUMMY_LAST ++ ++/***************************************************************************** ++ QMan INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define QM_MAX_NUM_OF_POOL_CHANNELS 15 /**< Total number of channels, dedicated and pool */ ++#define QM_MAX_NUM_OF_WQ 8 /**< Number of work queues per channel */ ++#define QM_MAX_NUM_OF_CGS 256 /**< Congestion groups number */ ++#define QM_MAX_NUM_OF_FQIDS (16 * MEGABYTE) ++ /**< FQIDs range - 24 bits */ ++ ++/**************************************************************************//** ++ @Description Work Queue Channel assignments in QMan. ++*//***************************************************************************/ ++typedef enum ++{ ++ e_QM_FQ_CHANNEL_SWPORTAL0 = 0x0, /**< Dedicated channels serviced by software portals 0 to 24 */ ++ e_QM_FQ_CHANNEL_SWPORTAL1, ++ e_QM_FQ_CHANNEL_SWPORTAL2, ++ e_QM_FQ_CHANNEL_SWPORTAL3, ++ e_QM_FQ_CHANNEL_SWPORTAL4, ++ e_QM_FQ_CHANNEL_SWPORTAL5, ++ e_QM_FQ_CHANNEL_SWPORTAL6, ++ e_QM_FQ_CHANNEL_SWPORTAL7, ++ e_QM_FQ_CHANNEL_SWPORTAL8, ++ e_QM_FQ_CHANNEL_SWPORTAL9, ++ e_QM_FQ_CHANNEL_SWPORTAL10, ++ e_QM_FQ_CHANNEL_SWPORTAL11, ++ e_QM_FQ_CHANNEL_SWPORTAL12, ++ e_QM_FQ_CHANNEL_SWPORTAL13, ++ e_QM_FQ_CHANNEL_SWPORTAL14, ++ e_QM_FQ_CHANNEL_SWPORTAL15, ++ e_QM_FQ_CHANNEL_SWPORTAL16, ++ e_QM_FQ_CHANNEL_SWPORTAL17, ++ e_QM_FQ_CHANNEL_SWPORTAL18, ++ e_QM_FQ_CHANNEL_SWPORTAL19, ++ e_QM_FQ_CHANNEL_SWPORTAL20, ++ e_QM_FQ_CHANNEL_SWPORTAL21, ++ e_QM_FQ_CHANNEL_SWPORTAL22, ++ e_QM_FQ_CHANNEL_SWPORTAL23, ++ e_QM_FQ_CHANNEL_SWPORTAL24, ++ ++ e_QM_FQ_CHANNEL_POOL1 = 0x401, /**< Pool channels that can be serviced by any of the software portals */ ++ e_QM_FQ_CHANNEL_POOL2, ++ e_QM_FQ_CHANNEL_POOL3, ++ e_QM_FQ_CHANNEL_POOL4, ++ e_QM_FQ_CHANNEL_POOL5, ++ e_QM_FQ_CHANNEL_POOL6, ++ e_QM_FQ_CHANNEL_POOL7, ++ e_QM_FQ_CHANNEL_POOL8, ++ e_QM_FQ_CHANNEL_POOL9, ++ e_QM_FQ_CHANNEL_POOL10, ++ e_QM_FQ_CHANNEL_POOL11, ++ e_QM_FQ_CHANNEL_POOL12, ++ e_QM_FQ_CHANNEL_POOL13, ++ e_QM_FQ_CHANNEL_POOL14, ++ e_QM_FQ_CHANNEL_POOL15, ++ ++ e_QM_FQ_CHANNEL_FMAN0_SP0 = 0x800, /**< Dedicated channels serviced by Direct Connect Portal 0: ++ connected to FMan 0; assigned in incrementing order to ++ each sub-portal (SP) in the portal */ ++ e_QM_FQ_CHANNEL_FMAN0_SP1, ++ e_QM_FQ_CHANNEL_FMAN0_SP2, ++ e_QM_FQ_CHANNEL_FMAN0_SP3, ++ e_QM_FQ_CHANNEL_FMAN0_SP4, ++ e_QM_FQ_CHANNEL_FMAN0_SP5, ++ e_QM_FQ_CHANNEL_FMAN0_SP6, ++ e_QM_FQ_CHANNEL_FMAN0_SP7, ++ e_QM_FQ_CHANNEL_FMAN0_SP8, ++ e_QM_FQ_CHANNEL_FMAN0_SP9, ++ e_QM_FQ_CHANNEL_FMAN0_SP10, ++ e_QM_FQ_CHANNEL_FMAN0_SP11, ++ e_QM_FQ_CHANNEL_FMAN0_SP12, ++ e_QM_FQ_CHANNEL_FMAN0_SP13, ++ e_QM_FQ_CHANNEL_FMAN0_SP14, ++ e_QM_FQ_CHANNEL_FMAN0_SP15, ++ ++ e_QM_FQ_CHANNEL_RMAN_SP0 = 0x820, /**< Dedicated channels serviced by Direct Connect Portal 1: connected to RMan */ ++ e_QM_FQ_CHANNEL_RMAN_SP1, ++ ++ e_QM_FQ_CHANNEL_CAAM = 0x840 /**< Dedicated channel serviced by Direct Connect Portal 2: ++ connected to SEC */ ++} e_QmFQChannel; ++ ++/***************************************************************************** ++ BMan INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define BM_MAX_NUM_OF_POOLS 64 /**< Number of buffers pools */ ++ ++/***************************************************************************** ++ SEC INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define SEC_NUM_OF_DECOS 3 ++#define SEC_ALL_DECOS_MASK 0x00000003 ++ ++ ++/***************************************************************************** ++ FM INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define INTG_MAX_NUM_OF_FM 1 ++/* Ports defines */ ++#define FM_MAX_NUM_OF_1G_MACS 5 ++#define FM_MAX_NUM_OF_10G_MACS 1 ++#define FM_MAX_NUM_OF_MACS (FM_MAX_NUM_OF_1G_MACS + FM_MAX_NUM_OF_10G_MACS) ++#define FM_MAX_NUM_OF_OH_PORTS 4 ++ ++#define FM_MAX_NUM_OF_1G_RX_PORTS FM_MAX_NUM_OF_1G_MACS ++#define FM_MAX_NUM_OF_10G_RX_PORTS FM_MAX_NUM_OF_10G_MACS ++#define FM_MAX_NUM_OF_RX_PORTS (FM_MAX_NUM_OF_10G_RX_PORTS + FM_MAX_NUM_OF_1G_RX_PORTS) ++ ++#define FM_MAX_NUM_OF_1G_TX_PORTS FM_MAX_NUM_OF_1G_MACS ++#define FM_MAX_NUM_OF_10G_TX_PORTS FM_MAX_NUM_OF_10G_MACS ++#define FM_MAX_NUM_OF_TX_PORTS (FM_MAX_NUM_OF_10G_TX_PORTS + FM_MAX_NUM_OF_1G_TX_PORTS) ++ ++#define FM_MAX_NUM_OF_MACSECS 1 /* Should be updated */ ++ ++#define FM_PORT_MAX_NUM_OF_EXT_POOLS 4 /**< Number of external BM pools per Rx port */ ++#define FM_PORT_NUM_OF_CONGESTION_GRPS 256 /**< Total number of congestion groups in QM */ ++#define FM_MAX_NUM_OF_SUB_PORTALS 16 ++#define FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS 0 ++ ++#define FM_VSP_MAX_NUM_OF_ENTRIES 32 ++#define FM_MAX_NUM_OF_PFC_PRIORITIES 8 ++ ++/* RAMs defines */ ++#define FM_MURAM_SIZE (192 * KILOBYTE) ++#define FM_IRAM_SIZE(major, minor) \ ++ (((major == 6) && ((minor == 4) )) ? (64 * KILOBYTE) : (32 * KILOBYTE)) ++#define FM_NUM_OF_CTRL 2 ++ ++/* PCD defines */ ++#define FM_PCD_PLCR_NUM_ENTRIES 256 /**< Total number of policer profiles */ ++#define FM_PCD_KG_NUM_OF_SCHEMES 32 /**< Total number of KG schemes */ ++#define FM_PCD_MAX_NUM_OF_CLS_PLANS 256 /**< Number of classification plan entries. */ ++#define FM_PCD_PRS_SW_PATCHES_SIZE 0x00000600 /**< Number of bytes saved for patches */ ++#define FM_PCD_SW_PRS_SIZE 0x00000800 /**< Total size of SW parser area */ ++ ++/* RTC defines */ ++#define FM_RTC_NUM_OF_ALARMS 2 /**< RTC number of alarms */ ++#define FM_RTC_NUM_OF_PERIODIC_PULSES 3 /**< RTC number of periodic pulses */ ++#define FM_RTC_NUM_OF_EXT_TRIGGERS 2 /**< RTC number of external triggers */ ++ ++/* QMI defines */ ++#define QMI_MAX_NUM_OF_TNUMS 64 ++#define QMI_DEF_TNUMS_THRESH 32 ++/* FPM defines */ ++#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS 4 ++ ++/* DMA defines */ ++#define DMA_THRESH_MAX_COMMQ 83 ++#define DMA_THRESH_MAX_BUF 127 ++ ++/* BMI defines */ ++#define BMI_MAX_NUM_OF_TASKS 64 ++#define BMI_MAX_NUM_OF_DMAS 32 ++ ++#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE) ++#define PORT_MAX_WEIGHT 16 ++ ++#define FM_CHECK_PORT_RESTRICTIONS(__validPorts, __newPortIndx) TRUE ++ ++/* Unique T4240 */ ++#define FM_OP_OPEN_DMA_MIN_LIMIT ++#define FM_NO_RESTRICT_ON_ACCESS_RSRC ++#define FM_NO_OP_OBSERVED_POOLS ++#define FM_FRAME_END_PARAMS_FOR_OP ++#define FM_DEQ_PIPELINE_PARAMS_FOR_OP ++#define FM_QMI_NO_SINGLE_ECC_EXCEPTION ++ ++#define FM_NO_GUARANTEED_RESET_VALUES ++ ++/* FM errata */ ++#define FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 ++#define FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320 ++#define FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675 ++#define FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 ++#define FM_HANG_AT_RESET_MAC_CLK_DISABLED_ERRATA_FMAN_A007273 ++ ++#define FM_BCB_ERRATA_BMI_SW001 ++#define FM_LEN_CHECK_ERRATA_FMAN_SW002 ++#define FM_AID_MODE_NO_TNUM_SW005 /* refer to pdm TKT068794 - only support of port_id on aid */ ++#define FM_ERROR_VSP_NO_MATCH_SW006 /* refer to pdm TKT174304 - no match between errorQ and VSP */ ++ ++/***************************************************************************** ++ RMan INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define RM_MAX_NUM_OF_IB 4 /**< Number of inbound blocks */ ++#define RM_NUM_OF_IBCU 8 /**< NUmber of classification units in an inbound block */ ++ ++/* RMan erratas */ ++#define RM_ERRONEOUS_ACK_ERRATA_RMAN_A006756 ++ ++/***************************************************************************** ++ FM MACSEC INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define NUM_OF_RX_SC 16 ++#define NUM_OF_TX_SC 16 ++ ++#define NUM_OF_SA_PER_RX_SC 2 ++#define NUM_OF_SA_PER_TX_SC 2 ++ ++#endif /* __DPAA_INTEGRATION_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_ext.h +new file mode 100644 +index 00000000..ba9732ee +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_ext.h +@@ -0,0 +1,59 @@ ++/* ++ * Copyright 2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/**************************************************************************//** ++ ++ @File part_ext.h ++ ++ @Description Definitions for the part (integration) module. ++*//***************************************************************************/ ++ ++#ifndef __PART_EXT_H ++#define __PART_EXT_H ++ ++#include "std_ext.h" ++#include "part_integration_ext.h" ++ ++/**************************************************************************//* ++ @Description Part data structure - must be contained in any integration ++ data structure. ++*//***************************************************************************/ ++typedef struct t_Part ++{ ++ uintptr_t (* f_GetModuleBase)(t_Handle h_Part, e_ModuleId moduleId); ++ /**< Returns the address of the module's memory map base. */ ++ e_ModuleId (* f_GetModuleIdByBase)(t_Handle h_Part, uintptr_t baseAddress); ++ /**< Returns the module's ID according to its memory map base. */ ++} t_Part; ++ ++ ++#endif /* __PART_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_integration_ext.h +new file mode 100644 +index 00000000..3254c766 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/FMANV3L/part_integration_ext.h +@@ -0,0 +1,304 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/** ++ ++ @File part_integration_ext.h ++ ++ @Description T4240 external definitions and structures. ++*//***************************************************************************/ ++#ifndef __PART_INTEGRATION_EXT_H ++#define __PART_INTEGRATION_EXT_H ++ ++#include "std_ext.h" ++#include "ddr_std_ext.h" ++#include "enet_ext.h" ++#include "dpaa_integration_ext.h" ++ ++ ++/**************************************************************************//** ++ @Group T4240_chip_id T4240 Application Programming Interface ++ ++ @Description T4240 Chip functions,definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++#define CORE_E6500 ++ ++#define INTG_MAX_NUM_OF_CORES 24 ++ ++ ++/**************************************************************************//** ++ @Description Module types. ++*//***************************************************************************/ ++typedef enum e_ModuleId ++{ ++ e_MODULE_ID_DUART_1 = 0, ++ e_MODULE_ID_DUART_2, ++ e_MODULE_ID_DUART_3, ++ e_MODULE_ID_DUART_4, ++ e_MODULE_ID_LAW, ++ e_MODULE_ID_IFC, ++ e_MODULE_ID_PAMU, ++ e_MODULE_ID_QM, /**< Queue manager module */ ++ e_MODULE_ID_BM, /**< Buffer manager module */ ++ e_MODULE_ID_QM_CE_PORTAL_0, ++ e_MODULE_ID_QM_CI_PORTAL_0, ++ e_MODULE_ID_QM_CE_PORTAL_1, ++ e_MODULE_ID_QM_CI_PORTAL_1, ++ e_MODULE_ID_QM_CE_PORTAL_2, ++ e_MODULE_ID_QM_CI_PORTAL_2, ++ e_MODULE_ID_QM_CE_PORTAL_3, ++ e_MODULE_ID_QM_CI_PORTAL_3, ++ e_MODULE_ID_QM_CE_PORTAL_4, ++ e_MODULE_ID_QM_CI_PORTAL_4, ++ e_MODULE_ID_QM_CE_PORTAL_5, ++ e_MODULE_ID_QM_CI_PORTAL_5, ++ e_MODULE_ID_QM_CE_PORTAL_6, ++ e_MODULE_ID_QM_CI_PORTAL_6, ++ e_MODULE_ID_QM_CE_PORTAL_7, ++ e_MODULE_ID_QM_CI_PORTAL_7, ++ e_MODULE_ID_QM_CE_PORTAL_8, ++ e_MODULE_ID_QM_CI_PORTAL_8, ++ e_MODULE_ID_QM_CE_PORTAL_9, ++ e_MODULE_ID_QM_CI_PORTAL_9, ++ e_MODULE_ID_BM_CE_PORTAL_0, ++ e_MODULE_ID_BM_CI_PORTAL_0, ++ e_MODULE_ID_BM_CE_PORTAL_1, ++ e_MODULE_ID_BM_CI_PORTAL_1, ++ e_MODULE_ID_BM_CE_PORTAL_2, ++ e_MODULE_ID_BM_CI_PORTAL_2, ++ e_MODULE_ID_BM_CE_PORTAL_3, ++ e_MODULE_ID_BM_CI_PORTAL_3, ++ e_MODULE_ID_BM_CE_PORTAL_4, ++ e_MODULE_ID_BM_CI_PORTAL_4, ++ e_MODULE_ID_BM_CE_PORTAL_5, ++ e_MODULE_ID_BM_CI_PORTAL_5, ++ e_MODULE_ID_BM_CE_PORTAL_6, ++ e_MODULE_ID_BM_CI_PORTAL_6, ++ e_MODULE_ID_BM_CE_PORTAL_7, ++ e_MODULE_ID_BM_CI_PORTAL_7, ++ e_MODULE_ID_BM_CE_PORTAL_8, ++ e_MODULE_ID_BM_CI_PORTAL_8, ++ e_MODULE_ID_BM_CE_PORTAL_9, ++ e_MODULE_ID_BM_CI_PORTAL_9, ++ e_MODULE_ID_FM, /**< Frame manager module */ ++ e_MODULE_ID_FM_RTC, /**< FM Real-Time-Clock */ ++ e_MODULE_ID_FM_MURAM, /**< FM Multi-User-RAM */ ++ e_MODULE_ID_FM_BMI, /**< FM BMI block */ ++ e_MODULE_ID_FM_QMI, /**< FM QMI block */ ++ e_MODULE_ID_FM_PARSER, /**< FM parser block */ ++ e_MODULE_ID_FM_PORT_HO1, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO2, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO3, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO4, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO5, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO6, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO7, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_1GRx1, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GRx2, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GRx3, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GRx4, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GRx5, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GRx6, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_10GRx1, /**< FM Rx 10G MAC port block */ ++ e_MODULE_ID_FM_PORT_10GRx2, /**< FM Rx 10G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx1, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx2, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx3, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx4, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx5, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx6, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_10GTx1, /**< FM Tx 10G MAC port block */ ++ e_MODULE_ID_FM_PORT_10GTx2, /**< FM Tx 10G MAC port block */ ++ e_MODULE_ID_FM_PLCR, /**< FM Policer */ ++ e_MODULE_ID_FM_KG, /**< FM Keygen */ ++ e_MODULE_ID_FM_DMA, /**< FM DMA */ ++ e_MODULE_ID_FM_FPM, /**< FM FPM */ ++ e_MODULE_ID_FM_IRAM, /**< FM Instruction-RAM */ ++ e_MODULE_ID_FM_1GMDIO, /**< FM 1G MDIO MAC */ ++ e_MODULE_ID_FM_10GMDIO, /**< FM 10G MDIO */ ++ e_MODULE_ID_FM_PRS_IRAM, /**< FM SW-parser Instruction-RAM */ ++ e_MODULE_ID_FM_1GMAC1, /**< FM 1G MAC #1 */ ++ e_MODULE_ID_FM_1GMAC2, /**< FM 1G MAC #2 */ ++ e_MODULE_ID_FM_1GMAC3, /**< FM 1G MAC #3 */ ++ e_MODULE_ID_FM_1GMAC4, /**< FM 1G MAC #4 */ ++ e_MODULE_ID_FM_1GMAC5, /**< FM 1G MAC #5 */ ++ e_MODULE_ID_FM_1GMAC6, /**< FM 1G MAC #6 */ ++ e_MODULE_ID_FM_10GMAC1, /**< FM 10G MAC */ ++ e_MODULE_ID_FM_10GMAC2, /**< FM 10G MAC */ ++ ++ e_MODULE_ID_SEC_GEN, /**< SEC 4.0 General registers */ ++ e_MODULE_ID_SEC_QI, /**< SEC 4.0 QI registers */ ++ e_MODULE_ID_SEC_JQ0, /**< SEC 4.0 JQ-0 registers */ ++ e_MODULE_ID_SEC_JQ1, /**< SEC 4.0 JQ-1 registers */ ++ e_MODULE_ID_SEC_JQ2, /**< SEC 4.0 JQ-2 registers */ ++ e_MODULE_ID_SEC_JQ3, /**< SEC 4.0 JQ-3 registers */ ++ e_MODULE_ID_SEC_RTIC, /**< SEC 4.0 RTIC registers */ ++ e_MODULE_ID_SEC_DECO0_CCB0, /**< SEC 4.0 DECO-0/CCB-0 registers */ ++ e_MODULE_ID_SEC_DECO1_CCB1, /**< SEC 4.0 DECO-1/CCB-1 registers */ ++ e_MODULE_ID_SEC_DECO2_CCB2, /**< SEC 4.0 DECO-2/CCB-2 registers */ ++ e_MODULE_ID_SEC_DECO3_CCB3, /**< SEC 4.0 DECO-3/CCB-3 registers */ ++ e_MODULE_ID_SEC_DECO4_CCB4, /**< SEC 4.0 DECO-4/CCB-4 registers */ ++ ++ e_MODULE_ID_PIC, /**< PIC */ ++ e_MODULE_ID_GPIO, /**< GPIO */ ++ e_MODULE_ID_SERDES, /**< SERDES */ ++ e_MODULE_ID_CPC_1, /**< CoreNet-Platform-Cache 1 */ ++ e_MODULE_ID_CPC_2, /**< CoreNet-Platform-Cache 2 */ ++ ++ e_MODULE_ID_SRIO_PORTS, /**< RapidIO controller */ ++ ++ e_MODULE_ID_DUMMY_LAST ++} e_ModuleId; ++ ++#define NUM_OF_MODULES e_MODULE_ID_DUMMY_LAST ++ ++#if 0 /* using unified values */ ++/***************************************************************************** ++ INTEGRATION-SPECIFIC MODULE CODES ++******************************************************************************/ ++#define MODULE_UNKNOWN 0x00000000 ++#define MODULE_MEM 0x00010000 ++#define MODULE_MM 0x00020000 ++#define MODULE_CORE 0x00030000 ++#define MODULE_T4240 0x00040000 ++#define MODULE_T4240_PLATFORM 0x00050000 ++#define MODULE_PM 0x00060000 ++#define MODULE_MMU 0x00070000 ++#define MODULE_PIC 0x00080000 ++#define MODULE_CPC 0x00090000 ++#define MODULE_DUART 0x000a0000 ++#define MODULE_SERDES 0x000b0000 ++#define MODULE_PIO 0x000c0000 ++#define MODULE_QM 0x000d0000 ++#define MODULE_BM 0x000e0000 ++#define MODULE_SEC 0x000f0000 ++#define MODULE_LAW 0x00100000 ++#define MODULE_LBC 0x00110000 ++#define MODULE_PAMU 0x00120000 ++#define MODULE_FM 0x00130000 ++#define MODULE_FM_MURAM 0x00140000 ++#define MODULE_FM_PCD 0x00150000 ++#define MODULE_FM_RTC 0x00160000 ++#define MODULE_FM_MAC 0x00170000 ++#define MODULE_FM_PORT 0x00180000 ++#define MODULE_FM_SP 0x00190000 ++#define MODULE_DPA_PORT 0x001a0000 ++#define MODULE_MII 0x001b0000 ++#define MODULE_I2C 0x001c0000 ++#define MODULE_DMA 0x001d0000 ++#define MODULE_DDR 0x001e0000 ++#define MODULE_ESPI 0x001f0000 ++#define MODULE_DPAA_IPSEC 0x00200000 ++#endif /* using unified values */ ++ ++/***************************************************************************** ++ PAMU INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define PAMU_NUM_OF_PARTITIONS 4 ++ ++/***************************************************************************** ++ LAW INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define LAW_NUM_OF_WINDOWS 32 ++#define LAW_MIN_WINDOW_SIZE 0x0000000000001000LL /**< 4 Kbytes */ ++#define LAW_MAX_WINDOW_SIZE 0x0000010000000000LL /**< 1 Tbytes for 40-bit address space */ ++ ++ ++/***************************************************************************** ++ LBC INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++/**************************************************************************//** ++ @Group lbc_exception_grp LBC Exception Unit ++ ++ @Description LBC Exception unit API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Anchor lbc_exbm ++ ++ @Collection LBC Errors Bit Mask ++ ++ These errors are reported through the exceptions callback.. ++ The values can be or'ed in any combination in the errors mask ++ parameter of the errors report structure. ++ ++ These errors can also be passed as a bit-mask to ++ LBC_EnableErrorChecking() or LBC_DisableErrorChecking(), ++ for enabling or disabling error checking. ++ @{ ++*//***************************************************************************/ ++#define LBC_ERR_BUS_MONITOR 0x80000000 /**< Bus monitor error */ ++#define LBC_ERR_PARITY_ECC 0x20000000 /**< Parity error for GPCM/UPM */ ++#define LBC_ERR_WRITE_PROTECT 0x04000000 /**< Write protection error */ ++#define LBC_ERR_CHIP_SELECT 0x00080000 /**< Unrecognized chip select */ ++ ++#define LBC_ERR_ALL (LBC_ERR_BUS_MONITOR | LBC_ERR_PARITY_ECC | \ ++ LBC_ERR_WRITE_PROTECT | LBC_ERR_CHIP_SELECT) ++ /**< All possible errors */ ++/* @} */ ++/** @} */ /* end of lbc_exception_grp group */ ++ ++#define LBC_INCORRECT_ERROR_REPORT_ERRATA ++ ++#define LBC_NUM_OF_BANKS 8 ++#define LBC_MAX_CS_SIZE 0x0000000100000000LL /* Up to 4G memory block size */ ++#define LBC_PARITY_SUPPORT ++#define LBC_ADDRESS_HOLD_TIME_CTRL ++#define LBC_HIGH_CLK_DIVIDERS ++#define LBC_FCM_AVAILABLE ++ ++/***************************************************************************** ++ GPIO INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define GPIO_PORT_OFFSET_0x1000 ++ ++#define GPIO_NUM_OF_PORTS 3 /**< Number of ports in GPIO module; ++ Each port contains up to 32 I/O pins. */ ++ ++#define GPIO_VALID_PIN_MASKS \ ++ { /* Port A */ 0xFFFFFFFF, \ ++ /* Port B */ 0xFFFFFFFF, \ ++ /* Port C */ 0xFFFFFFFF } ++ ++#define GPIO_VALID_INTR_MASKS \ ++ { /* Port A */ 0xFFFFFFFF, \ ++ /* Port B */ 0xFFFFFFFF, \ ++ /* Port C */ 0xFFFFFFFF } ++ ++ ++ ++#endif /* __PART_INTEGRATION_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/dpaa_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/dpaa_integration_ext.h +new file mode 100644 +index 00000000..5a8f3583 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/dpaa_integration_ext.h +@@ -0,0 +1,291 @@ ++/* ++ * Copyright 2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/** ++ ++ @File dpaa_integration_ext.h ++ ++ @Description T4240 FM external definitions and structures. ++*//***************************************************************************/ ++#ifndef __DPAA_INTEGRATION_EXT_H ++#define __DPAA_INTEGRATION_EXT_H ++ ++#include "std_ext.h" ++ ++ ++#define DPAA_VERSION 11 ++ ++/**************************************************************************//** ++ @Description DPAA SW Portals Enumeration. ++*//***************************************************************************/ ++typedef enum ++{ ++ e_DPAA_SWPORTAL0 = 0, ++ e_DPAA_SWPORTAL1, ++ e_DPAA_SWPORTAL2, ++ e_DPAA_SWPORTAL3, ++ e_DPAA_SWPORTAL4, ++ e_DPAA_SWPORTAL5, ++ e_DPAA_SWPORTAL6, ++ e_DPAA_SWPORTAL7, ++ e_DPAA_SWPORTAL8, ++ e_DPAA_SWPORTAL9, ++ e_DPAA_SWPORTAL10, ++ e_DPAA_SWPORTAL11, ++ e_DPAA_SWPORTAL12, ++ e_DPAA_SWPORTAL13, ++ e_DPAA_SWPORTAL14, ++ e_DPAA_SWPORTAL15, ++ e_DPAA_SWPORTAL16, ++ e_DPAA_SWPORTAL17, ++ e_DPAA_SWPORTAL18, ++ e_DPAA_SWPORTAL19, ++ e_DPAA_SWPORTAL20, ++ e_DPAA_SWPORTAL21, ++ e_DPAA_SWPORTAL22, ++ e_DPAA_SWPORTAL23, ++ e_DPAA_SWPORTAL24, ++ e_DPAA_SWPORTAL_DUMMY_LAST ++} e_DpaaSwPortal; ++ ++/**************************************************************************//** ++ @Description DPAA Direct Connect Portals Enumeration. ++*//***************************************************************************/ ++typedef enum ++{ ++ e_DPAA_DCPORTAL0 = 0, ++ e_DPAA_DCPORTAL1, ++ e_DPAA_DCPORTAL2, ++ e_DPAA_DCPORTAL_DUMMY_LAST ++} e_DpaaDcPortal; ++ ++#define DPAA_MAX_NUM_OF_SW_PORTALS e_DPAA_SWPORTAL_DUMMY_LAST ++#define DPAA_MAX_NUM_OF_DC_PORTALS e_DPAA_DCPORTAL_DUMMY_LAST ++ ++/***************************************************************************** ++ QMan INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define QM_MAX_NUM_OF_POOL_CHANNELS 15 /**< Total number of channels, dedicated and pool */ ++#define QM_MAX_NUM_OF_WQ 8 /**< Number of work queues per channel */ ++#define QM_MAX_NUM_OF_CGS 256 /**< Congestion groups number */ ++#define QM_MAX_NUM_OF_FQIDS (16 * MEGABYTE) ++ /**< FQIDs range - 24 bits */ ++ ++/**************************************************************************//** ++ @Description Work Queue Channel assignments in QMan. ++*//***************************************************************************/ ++typedef enum ++{ ++ e_QM_FQ_CHANNEL_SWPORTAL0 = 0x0, /**< Dedicated channels serviced by software portals 0 to 24 */ ++ e_QM_FQ_CHANNEL_SWPORTAL1, ++ e_QM_FQ_CHANNEL_SWPORTAL2, ++ e_QM_FQ_CHANNEL_SWPORTAL3, ++ e_QM_FQ_CHANNEL_SWPORTAL4, ++ e_QM_FQ_CHANNEL_SWPORTAL5, ++ e_QM_FQ_CHANNEL_SWPORTAL6, ++ e_QM_FQ_CHANNEL_SWPORTAL7, ++ e_QM_FQ_CHANNEL_SWPORTAL8, ++ e_QM_FQ_CHANNEL_SWPORTAL9, ++ e_QM_FQ_CHANNEL_SWPORTAL10, ++ e_QM_FQ_CHANNEL_SWPORTAL11, ++ e_QM_FQ_CHANNEL_SWPORTAL12, ++ e_QM_FQ_CHANNEL_SWPORTAL13, ++ e_QM_FQ_CHANNEL_SWPORTAL14, ++ e_QM_FQ_CHANNEL_SWPORTAL15, ++ e_QM_FQ_CHANNEL_SWPORTAL16, ++ e_QM_FQ_CHANNEL_SWPORTAL17, ++ e_QM_FQ_CHANNEL_SWPORTAL18, ++ e_QM_FQ_CHANNEL_SWPORTAL19, ++ e_QM_FQ_CHANNEL_SWPORTAL20, ++ e_QM_FQ_CHANNEL_SWPORTAL21, ++ e_QM_FQ_CHANNEL_SWPORTAL22, ++ e_QM_FQ_CHANNEL_SWPORTAL23, ++ e_QM_FQ_CHANNEL_SWPORTAL24, ++ ++ e_QM_FQ_CHANNEL_POOL1 = 0x401, /**< Pool channels that can be serviced by any of the software portals */ ++ e_QM_FQ_CHANNEL_POOL2, ++ e_QM_FQ_CHANNEL_POOL3, ++ e_QM_FQ_CHANNEL_POOL4, ++ e_QM_FQ_CHANNEL_POOL5, ++ e_QM_FQ_CHANNEL_POOL6, ++ e_QM_FQ_CHANNEL_POOL7, ++ e_QM_FQ_CHANNEL_POOL8, ++ e_QM_FQ_CHANNEL_POOL9, ++ e_QM_FQ_CHANNEL_POOL10, ++ e_QM_FQ_CHANNEL_POOL11, ++ e_QM_FQ_CHANNEL_POOL12, ++ e_QM_FQ_CHANNEL_POOL13, ++ e_QM_FQ_CHANNEL_POOL14, ++ e_QM_FQ_CHANNEL_POOL15, ++ ++ e_QM_FQ_CHANNEL_FMAN0_SP0 = 0x800, /**< Dedicated channels serviced by Direct Connect Portal 0: ++ connected to FMan 0; assigned in incrementing order to ++ each sub-portal (SP) in the portal */ ++ e_QM_FQ_CHANNEL_FMAN0_SP1, ++ e_QM_FQ_CHANNEL_FMAN0_SP2, ++ e_QM_FQ_CHANNEL_FMAN0_SP3, ++ e_QM_FQ_CHANNEL_FMAN0_SP4, ++ e_QM_FQ_CHANNEL_FMAN0_SP5, ++ e_QM_FQ_CHANNEL_FMAN0_SP6, ++ e_QM_FQ_CHANNEL_FMAN0_SP7, ++ e_QM_FQ_CHANNEL_FMAN0_SP8, ++ e_QM_FQ_CHANNEL_FMAN0_SP9, ++ e_QM_FQ_CHANNEL_FMAN0_SP10, ++ e_QM_FQ_CHANNEL_FMAN0_SP11, ++ e_QM_FQ_CHANNEL_FMAN0_SP12, ++ e_QM_FQ_CHANNEL_FMAN0_SP13, ++ e_QM_FQ_CHANNEL_FMAN0_SP14, ++ e_QM_FQ_CHANNEL_FMAN0_SP15, ++ ++ e_QM_FQ_CHANNEL_RMAN_SP0 = 0x820, /**< Dedicated channels serviced by Direct Connect Portal 1: connected to RMan */ ++ e_QM_FQ_CHANNEL_RMAN_SP1, ++ ++ e_QM_FQ_CHANNEL_CAAM = 0x840 /**< Dedicated channel serviced by Direct Connect Portal 2: ++ connected to SEC */ ++} e_QmFQChannel; ++ ++/***************************************************************************** ++ BMan INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define BM_MAX_NUM_OF_POOLS 64 /**< Number of buffers pools */ ++ ++/***************************************************************************** ++ SEC INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define SEC_NUM_OF_DECOS 3 ++#define SEC_ALL_DECOS_MASK 0x00000003 ++ ++ ++/***************************************************************************** ++ FM INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define INTG_MAX_NUM_OF_FM 2 ++ ++/* Ports defines */ ++#define FM_MAX_NUM_OF_1G_MACS 6 ++#define FM_MAX_NUM_OF_10G_MACS 2 ++#define FM_MAX_NUM_OF_MACS (FM_MAX_NUM_OF_1G_MACS + FM_MAX_NUM_OF_10G_MACS) ++#define FM_MAX_NUM_OF_OH_PORTS 6 ++ ++#define FM_MAX_NUM_OF_1G_RX_PORTS FM_MAX_NUM_OF_1G_MACS ++#define FM_MAX_NUM_OF_10G_RX_PORTS FM_MAX_NUM_OF_10G_MACS ++#define FM_MAX_NUM_OF_RX_PORTS (FM_MAX_NUM_OF_10G_RX_PORTS + FM_MAX_NUM_OF_1G_RX_PORTS) ++ ++#define FM_MAX_NUM_OF_1G_TX_PORTS FM_MAX_NUM_OF_1G_MACS ++#define FM_MAX_NUM_OF_10G_TX_PORTS FM_MAX_NUM_OF_10G_MACS ++#define FM_MAX_NUM_OF_TX_PORTS (FM_MAX_NUM_OF_10G_TX_PORTS + FM_MAX_NUM_OF_1G_TX_PORTS) ++ ++#define FM_PORT_MAX_NUM_OF_EXT_POOLS 4 /**< Number of external BM pools per Rx port */ ++#define FM_PORT_NUM_OF_CONGESTION_GRPS 256 /**< Total number of congestion groups in QM */ ++#define FM_MAX_NUM_OF_SUB_PORTALS 16 ++#define FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS 0 ++ ++#define FM_VSP_MAX_NUM_OF_ENTRIES 64 ++#define FM_MAX_NUM_OF_PFC_PRIORITIES 8 ++ ++/* RAMs defines */ ++#define FM_MURAM_SIZE (384 * KILOBYTE) ++#define FM_IRAM_SIZE(major, minor) (64 * KILOBYTE) ++#define FM_NUM_OF_CTRL 4 ++ ++/* PCD defines */ ++#define FM_PCD_PLCR_NUM_ENTRIES 256 /**< Total number of policer profiles */ ++#define FM_PCD_KG_NUM_OF_SCHEMES 32 /**< Total number of KG schemes */ ++#define FM_PCD_MAX_NUM_OF_CLS_PLANS 256 /**< Number of classification plan entries. */ ++#define FM_PCD_PRS_SW_PATCHES_SIZE 0x00000600 /**< Number of bytes saved for patches */ ++#define FM_PCD_SW_PRS_SIZE 0x00000800 /**< Total size of SW parser area */ ++ ++/* RTC defines */ ++#define FM_RTC_NUM_OF_ALARMS 2 /**< RTC number of alarms */ ++#define FM_RTC_NUM_OF_PERIODIC_PULSES 3 /**< RTC number of periodic pulses */ ++#define FM_RTC_NUM_OF_EXT_TRIGGERS 2 /**< RTC number of external triggers */ ++ ++/* QMI defines */ ++#define QMI_MAX_NUM_OF_TNUMS 64 ++#define QMI_DEF_TNUMS_THRESH 32 ++/* FPM defines */ ++#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS 4 ++ ++/* DMA defines */ ++#define DMA_THRESH_MAX_COMMQ 83 ++#define DMA_THRESH_MAX_BUF 127 ++ ++/* BMI defines */ ++#define BMI_MAX_NUM_OF_TASKS 128 ++#define BMI_MAX_NUM_OF_DMAS 84 ++ ++#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE) ++#define PORT_MAX_WEIGHT 16 ++ ++#define FM_CHECK_PORT_RESTRICTIONS(__validPorts, __newPortIndx) TRUE ++ ++/* Unique T4240 */ ++#define FM_OP_OPEN_DMA_MIN_LIMIT ++#define FM_NO_RESTRICT_ON_ACCESS_RSRC ++#define FM_NO_OP_OBSERVED_POOLS ++#define FM_FRAME_END_PARAMS_FOR_OP ++#define FM_DEQ_PIPELINE_PARAMS_FOR_OP ++#define FM_QMI_NO_SINGLE_ECC_EXCEPTION ++ ++#define FM_NO_GUARANTEED_RESET_VALUES ++ ++/* FM errata */ ++#define FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 ++#define FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 ++#define FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320 ++#define FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675 ++#define FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 ++ ++#define FM_BCB_ERRATA_BMI_SW001 ++#define FM_LEN_CHECK_ERRATA_FMAN_SW002 ++#define FM_AID_MODE_NO_TNUM_SW005 /* refer to pdm TKT068794 - only support of port_id on aid */ ++#define FM_ERROR_VSP_NO_MATCH_SW006 /* refer to pdm TKT174304 - no match between errorQ and VSP */ ++ ++/***************************************************************************** ++ RMan INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define RM_MAX_NUM_OF_IB 4 /**< Number of inbound blocks */ ++#define RM_NUM_OF_IBCU 8 /**< NUmber of classification units in an inbound block */ ++ ++/* RMan erratas */ ++#define RM_ERRONEOUS_ACK_ERRATA_RMAN_A006756 ++ ++/***************************************************************************** ++ FM MACSEC INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define NUM_OF_RX_SC 16 ++#define NUM_OF_TX_SC 16 ++ ++#define NUM_OF_SA_PER_RX_SC 2 ++#define NUM_OF_SA_PER_TX_SC 2 ++ ++#endif /* __DPAA_INTEGRATION_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_ext.h +new file mode 100644 +index 00000000..4787e19c +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_ext.h +@@ -0,0 +1,64 @@ ++/* ++ * Copyright 2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/**************************************************************************//** ++ ++ @File part_ext.h ++ ++ @Description Definitions for the part (integration) module. ++*//***************************************************************************/ ++ ++#ifndef __PART_EXT_H ++#define __PART_EXT_H ++ ++#include "std_ext.h" ++#include "part_integration_ext.h" ++ ++#if !(defined(LS1043)) ++#error "unable to proceed without chip-definition" ++#endif ++ ++ ++/**************************************************************************//* ++ @Description Part data structure - must be contained in any integration ++ data structure. ++*//***************************************************************************/ ++typedef struct t_Part ++{ ++ uintptr_t (* f_GetModuleBase)(t_Handle h_Part, e_ModuleId moduleId); ++ /**< Returns the address of the module's memory map base. */ ++ e_ModuleId (* f_GetModuleIdByBase)(t_Handle h_Part, uintptr_t baseAddress); ++ /**< Returns the module's ID according to its memory map base. */ ++} t_Part; ++ ++ ++#endif /* __PART_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_integration_ext.h +new file mode 100644 +index 00000000..85ba2a47 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/LS1043/part_integration_ext.h +@@ -0,0 +1,185 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/** ++ ++ @File part_integration_ext.h ++ ++ @Description T4240 external definitions and structures. ++*//***************************************************************************/ ++#ifndef __PART_INTEGRATION_EXT_H ++#define __PART_INTEGRATION_EXT_H ++ ++#include "std_ext.h" ++#include "ddr_std_ext.h" ++#include "enet_ext.h" ++#include "dpaa_integration_ext.h" ++ ++ ++/**************************************************************************//** ++ @Group T4240_chip_id T4240 Application Programming Interface ++ ++ @Description T4240 Chip functions,definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++#define INTG_MAX_NUM_OF_CORES 4 ++ ++/**************************************************************************//** ++ @Description Module types. ++*//***************************************************************************/ ++typedef enum e_ModuleId ++{ ++ e_MODULE_ID_DUART_1 = 0, ++ e_MODULE_ID_DUART_2, ++ e_MODULE_ID_DUART_3, ++ e_MODULE_ID_DUART_4, ++ e_MODULE_ID_LAW, ++ e_MODULE_ID_IFC, ++ e_MODULE_ID_PAMU, ++ e_MODULE_ID_QM, /**< Queue manager module */ ++ e_MODULE_ID_BM, /**< Buffer manager module */ ++ e_MODULE_ID_QM_CE_PORTAL_0, ++ e_MODULE_ID_QM_CI_PORTAL_0, ++ e_MODULE_ID_QM_CE_PORTAL_1, ++ e_MODULE_ID_QM_CI_PORTAL_1, ++ e_MODULE_ID_QM_CE_PORTAL_2, ++ e_MODULE_ID_QM_CI_PORTAL_2, ++ e_MODULE_ID_QM_CE_PORTAL_3, ++ e_MODULE_ID_QM_CI_PORTAL_3, ++ e_MODULE_ID_QM_CE_PORTAL_4, ++ e_MODULE_ID_QM_CI_PORTAL_4, ++ e_MODULE_ID_QM_CE_PORTAL_5, ++ e_MODULE_ID_QM_CI_PORTAL_5, ++ e_MODULE_ID_QM_CE_PORTAL_6, ++ e_MODULE_ID_QM_CI_PORTAL_6, ++ e_MODULE_ID_QM_CE_PORTAL_7, ++ e_MODULE_ID_QM_CI_PORTAL_7, ++ e_MODULE_ID_QM_CE_PORTAL_8, ++ e_MODULE_ID_QM_CI_PORTAL_8, ++ e_MODULE_ID_QM_CE_PORTAL_9, ++ e_MODULE_ID_QM_CI_PORTAL_9, ++ e_MODULE_ID_BM_CE_PORTAL_0, ++ e_MODULE_ID_BM_CI_PORTAL_0, ++ e_MODULE_ID_BM_CE_PORTAL_1, ++ e_MODULE_ID_BM_CI_PORTAL_1, ++ e_MODULE_ID_BM_CE_PORTAL_2, ++ e_MODULE_ID_BM_CI_PORTAL_2, ++ e_MODULE_ID_BM_CE_PORTAL_3, ++ e_MODULE_ID_BM_CI_PORTAL_3, ++ e_MODULE_ID_BM_CE_PORTAL_4, ++ e_MODULE_ID_BM_CI_PORTAL_4, ++ e_MODULE_ID_BM_CE_PORTAL_5, ++ e_MODULE_ID_BM_CI_PORTAL_5, ++ e_MODULE_ID_BM_CE_PORTAL_6, ++ e_MODULE_ID_BM_CI_PORTAL_6, ++ e_MODULE_ID_BM_CE_PORTAL_7, ++ e_MODULE_ID_BM_CI_PORTAL_7, ++ e_MODULE_ID_BM_CE_PORTAL_8, ++ e_MODULE_ID_BM_CI_PORTAL_8, ++ e_MODULE_ID_BM_CE_PORTAL_9, ++ e_MODULE_ID_BM_CI_PORTAL_9, ++ e_MODULE_ID_FM, /**< Frame manager module */ ++ e_MODULE_ID_FM_RTC, /**< FM Real-Time-Clock */ ++ e_MODULE_ID_FM_MURAM, /**< FM Multi-User-RAM */ ++ e_MODULE_ID_FM_BMI, /**< FM BMI block */ ++ e_MODULE_ID_FM_QMI, /**< FM QMI block */ ++ e_MODULE_ID_FM_PARSER, /**< FM parser block */ ++ e_MODULE_ID_FM_PORT_HO1, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO2, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO3, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO4, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO5, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO6, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO7, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_1GRx1, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GRx2, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GRx3, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GRx4, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GRx5, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GRx6, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_10GRx1, /**< FM Rx 10G MAC port block */ ++ e_MODULE_ID_FM_PORT_10GRx2, /**< FM Rx 10G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx1, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx2, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx3, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx4, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx5, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx6, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_10GTx1, /**< FM Tx 10G MAC port block */ ++ e_MODULE_ID_FM_PORT_10GTx2, /**< FM Tx 10G MAC port block */ ++ e_MODULE_ID_FM_PLCR, /**< FM Policer */ ++ e_MODULE_ID_FM_KG, /**< FM Keygen */ ++ e_MODULE_ID_FM_DMA, /**< FM DMA */ ++ e_MODULE_ID_FM_FPM, /**< FM FPM */ ++ e_MODULE_ID_FM_IRAM, /**< FM Instruction-RAM */ ++ e_MODULE_ID_FM_1GMDIO, /**< FM 1G MDIO MAC */ ++ e_MODULE_ID_FM_10GMDIO, /**< FM 10G MDIO */ ++ e_MODULE_ID_FM_PRS_IRAM, /**< FM SW-parser Instruction-RAM */ ++ e_MODULE_ID_FM_1GMAC1, /**< FM 1G MAC #1 */ ++ e_MODULE_ID_FM_1GMAC2, /**< FM 1G MAC #2 */ ++ e_MODULE_ID_FM_1GMAC3, /**< FM 1G MAC #3 */ ++ e_MODULE_ID_FM_1GMAC4, /**< FM 1G MAC #4 */ ++ e_MODULE_ID_FM_1GMAC5, /**< FM 1G MAC #5 */ ++ e_MODULE_ID_FM_1GMAC6, /**< FM 1G MAC #6 */ ++ e_MODULE_ID_FM_10GMAC1, /**< FM 10G MAC */ ++ e_MODULE_ID_FM_10GMAC2, /**< FM 10G MAC */ ++ ++ e_MODULE_ID_SEC_GEN, /**< SEC 4.0 General registers */ ++ e_MODULE_ID_SEC_QI, /**< SEC 4.0 QI registers */ ++ e_MODULE_ID_SEC_JQ0, /**< SEC 4.0 JQ-0 registers */ ++ e_MODULE_ID_SEC_JQ1, /**< SEC 4.0 JQ-1 registers */ ++ e_MODULE_ID_SEC_JQ2, /**< SEC 4.0 JQ-2 registers */ ++ e_MODULE_ID_SEC_JQ3, /**< SEC 4.0 JQ-3 registers */ ++ e_MODULE_ID_SEC_RTIC, /**< SEC 4.0 RTIC registers */ ++ e_MODULE_ID_SEC_DECO0_CCB0, /**< SEC 4.0 DECO-0/CCB-0 registers */ ++ e_MODULE_ID_SEC_DECO1_CCB1, /**< SEC 4.0 DECO-1/CCB-1 registers */ ++ e_MODULE_ID_SEC_DECO2_CCB2, /**< SEC 4.0 DECO-2/CCB-2 registers */ ++ e_MODULE_ID_SEC_DECO3_CCB3, /**< SEC 4.0 DECO-3/CCB-3 registers */ ++ e_MODULE_ID_SEC_DECO4_CCB4, /**< SEC 4.0 DECO-4/CCB-4 registers */ ++ ++ e_MODULE_ID_PIC, /**< PIC */ ++ e_MODULE_ID_GPIO, /**< GPIO */ ++ e_MODULE_ID_SERDES, /**< SERDES */ ++ e_MODULE_ID_CPC_1, /**< CoreNet-Platform-Cache 1 */ ++ e_MODULE_ID_CPC_2, /**< CoreNet-Platform-Cache 2 */ ++ ++ e_MODULE_ID_SRIO_PORTS, /**< RapidIO controller */ ++ ++ e_MODULE_ID_DUMMY_LAST ++} e_ModuleId; ++ ++#define NUM_OF_MODULES e_MODULE_ID_DUMMY_LAST ++ ++ ++#endif /* __PART_INTEGRATION_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/dpaa_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/dpaa_integration_ext.h +new file mode 100644 +index 00000000..7b5390de +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/dpaa_integration_ext.h +@@ -0,0 +1,213 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/** ++ ++ @File dpaa_integration_ext.h ++ ++ @Description P1023 FM external definitions and structures. ++*//***************************************************************************/ ++#ifndef __DPAA_INTEGRATION_EXT_H ++#define __DPAA_INTEGRATION_EXT_H ++ ++#include "std_ext.h" ++ ++ ++#define DPAA_VERSION 10 ++ ++typedef enum e_DpaaSwPortal { ++ e_DPAA_SWPORTAL0 = 0, ++ e_DPAA_SWPORTAL1, ++ e_DPAA_SWPORTAL2, ++ e_DPAA_SWPORTAL_DUMMY_LAST ++} e_DpaaSwPortal; ++ ++typedef enum { ++ e_DPAA_DCPORTAL0 = 0, ++ e_DPAA_DCPORTAL2, ++ e_DPAA_DCPORTAL_DUMMY_LAST ++} e_DpaaDcPortal; ++ ++#define DPAA_MAX_NUM_OF_SW_PORTALS e_DPAA_SWPORTAL_DUMMY_LAST ++#define DPAA_MAX_NUM_OF_DC_PORTALS e_DPAA_DCPORTAL_DUMMY_LAST ++ ++/***************************************************************************** ++ QMAN INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define QM_MAX_NUM_OF_POOL_CHANNELS 3 ++#define QM_MAX_NUM_OF_WQ 8 ++#define QM_MAX_NUM_OF_SWP_AS 2 ++#define QM_MAX_NUM_OF_CGS 64 ++#define QM_MAX_NUM_OF_FQIDS (16*MEGABYTE) ++ ++typedef enum { ++ e_QM_FQ_CHANNEL_SWPORTAL0 = 0, ++ e_QM_FQ_CHANNEL_SWPORTAL1, ++ e_QM_FQ_CHANNEL_SWPORTAL2, ++ ++ e_QM_FQ_CHANNEL_POOL1 = 0x21, ++ e_QM_FQ_CHANNEL_POOL2, ++ e_QM_FQ_CHANNEL_POOL3, ++ ++ e_QM_FQ_CHANNEL_FMAN0_SP0 = 0x40, ++ e_QM_FQ_CHANNEL_FMAN0_SP1, ++ e_QM_FQ_CHANNEL_FMAN0_SP2, ++ e_QM_FQ_CHANNEL_FMAN0_SP3, ++ e_QM_FQ_CHANNEL_FMAN0_SP4, ++ e_QM_FQ_CHANNEL_FMAN0_SP5, ++ e_QM_FQ_CHANNEL_FMAN0_SP6, ++ ++ ++ e_QM_FQ_CHANNEL_CAAM = 0x80 ++} e_QmFQChannel; ++ ++/***************************************************************************** ++ BMAN INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define BM_MAX_NUM_OF_POOLS 8 ++ ++/***************************************************************************** ++ SEC INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define SEC_NUM_OF_DECOS 2 ++#define SEC_ALL_DECOS_MASK 0x00000003 ++#define SEC_RNGB ++#define SEC_NO_ESP_TRAILER_REMOVAL ++ ++/***************************************************************************** ++ FM INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define INTG_MAX_NUM_OF_FM 1 ++ ++/* Ports defines */ ++#define FM_MAX_NUM_OF_1G_MACS 2 ++#define FM_MAX_NUM_OF_10G_MACS 0 ++#define FM_MAX_NUM_OF_MACS (FM_MAX_NUM_OF_1G_MACS + FM_MAX_NUM_OF_10G_MACS) ++#define FM_MAX_NUM_OF_OH_PORTS 5 ++ ++#define FM_MAX_NUM_OF_1G_RX_PORTS FM_MAX_NUM_OF_1G_MACS ++#define FM_MAX_NUM_OF_10G_RX_PORTS FM_MAX_NUM_OF_10G_MACS ++#define FM_MAX_NUM_OF_RX_PORTS (FM_MAX_NUM_OF_10G_RX_PORTS + FM_MAX_NUM_OF_1G_RX_PORTS) ++ ++#define FM_MAX_NUM_OF_1G_TX_PORTS FM_MAX_NUM_OF_1G_MACS ++#define FM_MAX_NUM_OF_10G_TX_PORTS FM_MAX_NUM_OF_10G_MACS ++#define FM_MAX_NUM_OF_TX_PORTS (FM_MAX_NUM_OF_10G_TX_PORTS + FM_MAX_NUM_OF_1G_TX_PORTS) ++ ++#define FM_MAX_NUM_OF_MACSECS 1 ++ ++#define FM_MACSEC_SUPPORT ++ ++#define FM_LOW_END_RESTRICTION /* prevents the use of TX port 1 with OP port 0 */ ++ ++#define FM_PORT_MAX_NUM_OF_EXT_POOLS 4 /**< Number of external BM pools per Rx port */ ++#define FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS 2 /**< Number of Offline parsing port external BM pools per Rx port */ ++#define FM_PORT_NUM_OF_CONGESTION_GRPS 32 /**< Total number of congestion groups in QM */ ++#define FM_MAX_NUM_OF_SUB_PORTALS 7 ++ ++/* Rams defines */ ++#define FM_MURAM_SIZE (64*KILOBYTE) ++#define FM_IRAM_SIZE(major, minor) (32 * KILOBYTE) ++#define FM_NUM_OF_CTRL 2 ++ ++/* PCD defines */ ++#define FM_PCD_PLCR_NUM_ENTRIES 32 /**< Total number of policer profiles */ ++#define FM_PCD_KG_NUM_OF_SCHEMES 16 /**< Total number of KG schemes */ ++#define FM_PCD_MAX_NUM_OF_CLS_PLANS 128 /**< Number of classification plan entries. */ ++#define FM_PCD_PRS_SW_PATCHES_SIZE 0x00000240 /**< Number of bytes saved for patches */ ++#define FM_PCD_SW_PRS_SIZE 0x00000800 /**< Total size of SW parser area */ ++ ++/* RTC defines */ ++#define FM_RTC_NUM_OF_ALARMS 2 ++#define FM_RTC_NUM_OF_PERIODIC_PULSES 2 ++#define FM_RTC_NUM_OF_EXT_TRIGGERS 2 ++ ++/* QMI defines */ ++#define QMI_MAX_NUM_OF_TNUMS 15 ++ ++/* FPM defines */ ++#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS 4 ++ ++/* DMA defines */ ++#define DMA_THRESH_MAX_COMMQ 15 ++#define DMA_THRESH_MAX_BUF 7 ++ ++/* BMI defines */ ++#define BMI_MAX_NUM_OF_TASKS 64 ++#define BMI_MAX_NUM_OF_DMAS 16 ++#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE) ++#define PORT_MAX_WEIGHT 4 ++ ++/***************************************************************************** ++ FM MACSEC INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define NUM_OF_RX_SC 16 ++#define NUM_OF_TX_SC 16 ++ ++#define NUM_OF_SA_PER_RX_SC 2 ++#define NUM_OF_SA_PER_TX_SC 2 ++ ++/**************************************************************************//** ++ @Description Enum for inter-module interrupts registration ++*//***************************************************************************/ ++ ++/* 1023 unique features */ ++#define FM_QMI_NO_ECC_EXCEPTIONS ++#define FM_CSI_CFED_LIMIT ++#define FM_PEDANTIC_DMA ++#define FM_QMI_NO_DEQ_OPTIONS_SUPPORT ++#define FM_FIFO_ALLOCATION_ALG ++#define FM_DEQ_PIPELINE_PARAMS_FOR_OP ++#define FM_HAS_TOTAL_DMAS ++#define FM_KG_NO_IPPID_SUPPORT ++#define FM_NO_GUARANTEED_RESET_VALUES ++#define FM_MAC_RESET ++ ++/* FM erratas */ ++#define FM_RX_PREAM_4_ERRATA_DTSEC_A001 ++#define FM_MAGIC_PACKET_UNRECOGNIZED_ERRATA_DTSEC2 /* No implementation, Out of LLD scope */ ++ ++#define FM_DEBUG_TRACE_FMAN_A004 /* No implementation, Out of LLD scope */ ++#define FM_INT_BUF_LEAK_FMAN_A005 /* No implementation, Out of LLD scope. App must avoid S/G */ ++ ++#define FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839 ++ ++/* #define FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */ ++ ++/* ++TKT056919 - axi12axi0 can hang if read request follows the single byte write on the very next cycle ++TKT038900 - FM dma lockup occur due to AXI slave protocol violation ++*/ ++#define FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 ++ ++ ++#endif /* __DPAA_INTEGRATION_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_ext.h +new file mode 100644 +index 00000000..6814d5fb +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_ext.h +@@ -0,0 +1,82 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ ++ @File part_ext.h ++ ++ @Description Definitions for the part (integration) module. ++*//***************************************************************************/ ++ ++#ifndef __PART_EXT_H ++#define __PART_EXT_H ++ ++#include "std_ext.h" ++#include "part_integration_ext.h" ++ ++ ++#if !(defined(MPC8306) || \ ++ defined(MPC8309) || \ ++ defined(MPC834x) || \ ++ defined(MPC836x) || \ ++ defined(MPC832x) || \ ++ defined(MPC837x) || \ ++ defined(MPC8568) || \ ++ defined(MPC8569) || \ ++ defined(P1020) || \ ++ defined(P1021) || \ ++ defined(P1022) || \ ++ defined(P1023) || \ ++ defined(P2020) || \ ++ defined(P3041) || \ ++ defined(P4080) || \ ++ defined(P5020) || \ ++ defined(MSC814x)) ++#error "unable to proceed without chip-definition" ++#endif ++ ++ ++/**************************************************************************//* ++ @Description Part data structure - must be contained in any integration ++ data structure. ++*//***************************************************************************/ ++typedef struct t_Part ++{ ++ uint64_t (* f_GetModuleBase)(t_Handle h_Part, e_ModuleId moduleId); ++ /**< Returns the address of the module's memory map base. */ ++ e_ModuleId (* f_GetModuleIdByBase)(t_Handle h_Part, uint64_t baseAddress); ++ /**< Returns the module's ID according to its memory map base. */ ++} t_Part; ++ ++ ++#endif /* __PART_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_integration_ext.h +new file mode 100644 +index 00000000..e838283d +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P1023/part_integration_ext.h +@@ -0,0 +1,635 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/**************************************************************************//** ++ @File part_integration_ext.h ++ ++ @Description P1023 external definitions and structures. ++*//***************************************************************************/ ++#ifndef __PART_INTEGRATION_EXT_H ++#define __PART_INTEGRATION_EXT_H ++ ++#include "std_ext.h" ++#include "dpaa_integration_ext.h" ++ ++ ++/**************************************************************************//** ++ @Group 1023_chip_id P1023 Application Programming Interface ++ ++ @Description P1023 Chip functions,definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++#define INTG_MAX_NUM_OF_CORES 2 ++ ++ ++/**************************************************************************//** ++ @Description Module types. ++*//***************************************************************************/ ++typedef enum e_ModuleId ++{ ++ e_MODULE_ID_LAW, /**< Local Access module */ ++ e_MODULE_ID_ECM, /**< e500 Coherency Module */ ++ e_MODULE_ID_DDR, /**< DDR memory controller */ ++ e_MODULE_ID_I2C_1, /**< I2C 1 */ ++ e_MODULE_ID_I2C_2, /**< I2C 1 */ ++ e_MODULE_ID_DUART_1, /**< DUART module 1 */ ++ e_MODULE_ID_DUART_2, /**< DUART module 2 */ ++ e_MODULE_ID_LBC, /**< Local bus memory controller module */ ++ e_MODULE_ID_PCIE_1, /**< PCI Express 1 controller module */ ++ e_MODULE_ID_PCIE_ATMU_1, /**< PCI 1 ATMU Window */ ++ e_MODULE_ID_PCIE_2, /**< PCI Express 2 controller module */ ++ e_MODULE_ID_PCIE_ATMU_2, /**< PCI 2 ATMU Window */ ++ e_MODULE_ID_PCIE_3, /**< PCI Express 3 controller module */ ++ e_MODULE_ID_PCIE_ATMU_3, /**< PCI 3 ATMU Window */ ++ e_MODULE_ID_MSI, /**< MSI registers */ ++ e_MODULE_ID_L2_SRAM, /**< L2/SRAM Memory-Mapped controller module */ ++ e_MODULE_ID_DMA_1, /**< DMA controller 1 */ ++ e_MODULE_ID_DMA_2, /**< DMA controller 2 */ ++ e_MODULE_ID_EPIC, /**< Programmable interrupt controller */ ++ e_MODULE_ID_ESPI, /**< ESPI module */ ++ e_MODULE_ID_GPIO, /**< General Purpose I/O */ ++ e_MODULE_ID_SEC_GEN, /**< SEC 4.0 General registers */ ++ e_MODULE_ID_SEC_QI, /**< SEC 4.0 QI registers */ ++ e_MODULE_ID_SEC_JQ0, /**< SEC 4.0 JQ-0 registers */ ++ e_MODULE_ID_SEC_JQ1, /**< SEC 4.0 JQ-1 registers */ ++ e_MODULE_ID_SEC_JQ2, /**< SEC 4.0 JQ-2 registers */ ++ e_MODULE_ID_SEC_JQ3, /**< SEC 4.0 JQ-3 registers */ ++ e_MODULE_ID_SEC_RTIC, /**< SEC 4.0 RTIC registers */ ++ e_MODULE_ID_SEC_DECO0_CCB0, /**< SEC 4.0 DECO-0/CCB-0 registers */ ++ e_MODULE_ID_SEC_DECO1_CCB1, /**< SEC 4.0 DECO-1/CCB-1 registers */ ++ e_MODULE_ID_SEC_DECO2_CCB2, /**< SEC 4.0 DECO-2/CCB-2 registers */ ++ e_MODULE_ID_SEC_DECO3_CCB3, /**< SEC 4.0 DECO-3/CCB-3 registers */ ++ e_MODULE_ID_SEC_DECO4_CCB4, /**< SEC 4.0 DECO-4/CCB-4 registers */ ++ e_MODULE_ID_USB_DR_1, /**< USB 2.0 module 1 */ ++ e_MODULE_ID_USB_DR_2, /**< USB 2.0 module 2 */ ++ e_MODULE_ID_ETSEC_MII_MNG, /**< MII MNG registers */ ++ e_MODULE_ID_ETSEC_1, /**< ETSEC module 1 */ ++ e_MODULE_ID_ETSEC_2, /**< ETSEC module 2 */ ++ e_MODULE_ID_GUTS, /**< Serial DMA */ ++ e_MODULE_ID_PM, /**< Performance Monitor module */ ++ e_MODULE_ID_QM, /**< Queue manager module */ ++ e_MODULE_ID_BM, /**< Buffer manager module */ ++ e_MODULE_ID_QM_CE_PORTAL, ++ e_MODULE_ID_QM_CI_PORTAL, ++ e_MODULE_ID_BM_CE_PORTAL, ++ e_MODULE_ID_BM_CI_PORTAL, ++ e_MODULE_ID_FM, /**< Frame manager #1 module */ ++ e_MODULE_ID_FM_RTC, /**< FM Real-Time-Clock */ ++ e_MODULE_ID_FM_MURAM, /**< FM Multi-User-RAM */ ++ e_MODULE_ID_FM_BMI, /**< FM BMI block */ ++ e_MODULE_ID_FM_QMI, /**< FM QMI block */ ++ e_MODULE_ID_FM_PRS, /**< FM parser block */ ++ e_MODULE_ID_FM_PORT_HO0, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO1, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO2, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO3, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_HO4, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM_PORT_1GRx0, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GRx1, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx0, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PORT_1GTx1, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM_PLCR, /**< FM Policer */ ++ e_MODULE_ID_FM_KG, /**< FM Keygen */ ++ e_MODULE_ID_FM_DMA, /**< FM DMA */ ++ e_MODULE_ID_FM_FPM, /**< FM FPM */ ++ e_MODULE_ID_FM_IRAM, /**< FM Instruction-RAM */ ++ e_MODULE_ID_FM_1GMDIO0, /**< FM 1G MDIO MAC 0*/ ++ e_MODULE_ID_FM_1GMDIO1, /**< FM 1G MDIO MAC 1*/ ++ e_MODULE_ID_FM_PRS_IRAM, /**< FM SW-parser Instruction-RAM */ ++ e_MODULE_ID_FM_RISC0, /**< FM risc #0 */ ++ e_MODULE_ID_FM_RISC1, /**< FM risc #1 */ ++ e_MODULE_ID_FM_1GMAC0, /**< FM 1G MAC #0 */ ++ e_MODULE_ID_FM_1GMAC1, /**< FM 1G MAC #1 */ ++ e_MODULE_ID_FM_MACSEC, /**< FM MACSEC */ ++ ++ e_MODULE_ID_DUMMY_LAST ++} e_ModuleId; ++ ++#define NUM_OF_MODULES e_MODULE_ID_DUMMY_LAST ++ ++ ++#define P1023_OFFSET_LAW 0x00000C08 ++#define P1023_OFFSET_ECM 0x00001000 ++#define P1023_OFFSET_DDR 0x00002000 ++#define P1023_OFFSET_I2C1 0x00003000 ++#define P1023_OFFSET_I2C2 0x00003100 ++#define P1023_OFFSET_DUART1 0x00004500 ++#define P1023_OFFSET_DUART2 0x00004600 ++#define P1023_OFFSET_LBC 0x00005000 ++#define P1023_OFFSET_ESPI 0x00007000 ++#define P1023_OFFSET_PCIE2 0x00009000 ++#define P1023_OFFSET_PCIE2_ATMU 0x00009C00 ++#define P1023_OFFSET_PCIE1 0x0000A000 ++#define P1023_OFFSET_PCIE1_ATMU 0x0000AC00 ++#define P1023_OFFSET_PCIE3 0x0000B000 ++#define P1023_OFFSET_PCIE3_ATMU 0x0000BC00 ++#define P1023_OFFSET_DMA2 0x0000C100 ++#define P1023_OFFSET_GPIO 0x0000F000 ++#define P1023_OFFSET_L2_SRAM 0x00020000 ++#define P1023_OFFSET_DMA1 0x00021100 ++#define P1023_OFFSET_USB1 0x00022000 ++#define P1023_OFFSET_SEC_GEN 0x00030000 ++#define P1023_OFFSET_SEC_JQ0 0x00031000 ++#define P1023_OFFSET_SEC_JQ1 0x00032000 ++#define P1023_OFFSET_SEC_JQ2 0x00033000 ++#define P1023_OFFSET_SEC_JQ3 0x00034000 ++#define P1023_OFFSET_SEC_RTIC 0x00036000 ++#define P1023_OFFSET_SEC_QI 0x00037000 ++#define P1023_OFFSET_SEC_DECO0_CCB0 0x00038000 ++#define P1023_OFFSET_SEC_DECO1_CCB1 0x00039000 ++#define P1023_OFFSET_SEC_DECO2_CCB2 0x0003a000 ++#define P1023_OFFSET_SEC_DECO3_CCB3 0x0003b000 ++#define P1023_OFFSET_SEC_DECO4_CCB4 0x0003c000 ++#define P1023_OFFSET_PIC 0x00040000 ++#define P1023_OFFSET_MSI 0x00041600 ++#define P1023_OFFSET_AXI 0x00081000 ++#define P1023_OFFSET_QM 0x00088000 ++#define P1023_OFFSET_BM 0x0008A000 ++#define P1022_OFFSET_PM 0x000E1000 ++ ++#define P1023_OFFSET_GUTIL 0x000E0000 ++#define P1023_OFFSET_PM 0x000E1000 ++#define P1023_OFFSET_DEBUG 0x000E2000 ++#define P1023_OFFSET_SERDES 0x000E3000 ++#define P1023_OFFSET_ROM 0x000F0000 ++#define P1023_OFFSET_FM 0x00100000 ++ ++#define P1023_OFFSET_FM_MURAM (P1023_OFFSET_FM + 0x00000000) ++#define P1023_OFFSET_FM_BMI (P1023_OFFSET_FM + 0x00080000) ++#define P1023_OFFSET_FM_QMI (P1023_OFFSET_FM + 0x00080400) ++#define P1023_OFFSET_FM_PRS (P1023_OFFSET_FM + 0x00080800) ++#define P1023_OFFSET_FM_PORT_HO0 (P1023_OFFSET_FM + 0x00081000) ++#define P1023_OFFSET_FM_PORT_HO1 (P1023_OFFSET_FM + 0x00082000) ++#define P1023_OFFSET_FM_PORT_HO2 (P1023_OFFSET_FM + 0x00083000) ++#define P1023_OFFSET_FM_PORT_HO3 (P1023_OFFSET_FM + 0x00084000) ++#define P1023_OFFSET_FM_PORT_HO4 (P1023_OFFSET_FM + 0x00085000) ++#define P1023_OFFSET_FM_PORT_1GRX0 (P1023_OFFSET_FM + 0x00088000) ++#define P1023_OFFSET_FM_PORT_1GRX1 (P1023_OFFSET_FM + 0x00089000) ++#define P1023_OFFSET_FM_PORT_1GTX0 (P1023_OFFSET_FM + 0x000A8000) ++#define P1023_OFFSET_FM_PORT_1GTX1 (P1023_OFFSET_FM + 0x000A9000) ++#define P1023_OFFSET_FM_PLCR (P1023_OFFSET_FM + 0x000C0000) ++#define P1023_OFFSET_FM_KG (P1023_OFFSET_FM + 0x000C1000) ++#define P1023_OFFSET_FM_DMA (P1023_OFFSET_FM + 0x000C2000) ++#define P1023_OFFSET_FM_FPM (P1023_OFFSET_FM + 0x000C3000) ++#define P1023_OFFSET_FM_IRAM (P1023_OFFSET_FM + 0x000C4000) ++#define P1023_OFFSET_FM_PRS_IRAM (P1023_OFFSET_FM + 0x000C7000) ++#define P1023_OFFSET_FM_RISC0 (P1023_OFFSET_FM + 0x000D0000) ++#define P1023_OFFSET_FM_RISC1 (P1023_OFFSET_FM + 0x000D0400) ++#define P1023_OFFSET_FM_MACSEC (P1023_OFFSET_FM + 0x000D8000) ++#define P1023_OFFSET_FM_1GMAC0 (P1023_OFFSET_FM + 0x000E0000) ++#define P1023_OFFSET_FM_1GMDIO0 (P1023_OFFSET_FM + 0x000E1120) ++#define P1023_OFFSET_FM_1GMAC1 (P1023_OFFSET_FM + 0x000E2000) ++#define P1023_OFFSET_FM_1GMDIO1 (P1023_OFFSET_FM + 0x000E3000) ++#define P1023_OFFSET_FM_RTC (P1023_OFFSET_FM + 0x000FE000) ++ ++/* Offsets relative to QM or BM portals base */ ++#define P1023_OFFSET_PORTALS_CE_AREA 0x00000000 /* cache enabled area */ ++#define P1023_OFFSET_PORTALS_CI_AREA 0x00100000 /* cache inhibited area */ ++ ++#define P1023_OFFSET_PORTALS_CE(portal) (P1023_OFFSET_PORTALS_CE_AREA + 0x4000 * (portal)) ++#define P1023_OFFSET_PORTALS_CI(portal) (P1023_OFFSET_PORTALS_CI_AREA + 0x1000 * (portal)) ++ ++/**************************************************************************//** ++ @Description Transaction source ID (for memory controllers error reporting). ++*//***************************************************************************/ ++typedef enum e_TransSrc ++{ ++ e_TRANS_SRC_PCIE_2 = 0x01, /**< PCIe port 2 */ ++ e_TRANS_SRC_PCIE_1 = 0x02, /**< PCIe port 1 */ ++ e_TRANS_SRC_PCIE_3 = 0x03, /**< PCIe port 3 */ ++ e_TRANS_SRC_LBC = 0x04, /**< Enhanced local bus */ ++ e_TRANS_SRC_DPAA_SW_PORTALS = 0x0E, /**< DPAA software portals or SRAM */ ++ e_TRANS_SRC_DDR = 0x0F, /**< DDR controller */ ++ e_TRANS_SRC_CORE_INS_FETCH = 0x10, /**< Processor (instruction) */ ++ e_TRANS_SRC_CORE_DATA = 0x11, /**< Processor (data) */ ++ e_TRANS_SRC_DMA = 0x15 /**< DMA */ ++} e_TransSrc; ++ ++/**************************************************************************//** ++ @Description Local Access Window Target interface ID ++*//***************************************************************************/ ++typedef enum e_P1023LawTargetId ++{ ++ e_P1023_LAW_TARGET_PCIE_2 = 0x01, /**< PCI Express 2 target interface */ ++ e_P1023_LAW_TARGET_PCIE_1 = 0x02, /**< PCI Express 1 target interface */ ++ e_P1023_LAW_TARGET_PCIE_3 = 0x03, /**< PCI Express 3 target interface */ ++ e_P1023_LAW_TARGET_LBC = 0x04, /**< Local bus target interface */ ++ e_P1023_LAW_TARGET_QM_PORTALS = 0x0E, /**< Queue Manager Portals */ ++ e_P1023_LAW_TARGET_BM_PORTALS = 0x0E, /**< Buffer Manager Portals */ ++ e_P1023_LAW_TARGET_SRAM = 0x0E, /**< SRAM scratchpad */ ++ e_P1023_LAW_TARGET_DDR = 0x0F, /**< DDR target interface */ ++ e_P1023_LAW_TARGET_NONE = 0xFF /**< Invalid target interface */ ++} e_P1023LawTargetId; ++ ++ ++/**************************************************************************//** ++ @Group 1023_init_grp P1023 Initialization Unit ++ ++ @Description P1023 initialization unit API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description Part ID and revision number ++*//***************************************************************************/ ++typedef enum e_P1023DeviceName ++{ ++ e_P1023_REV_INVALID = 0x00000000, /**< Invalid revision */ ++ e_SC1023_REV_1_0 = (int)0x80FC0010, /**< SC1023 rev 1.0 */ ++ e_SC1023_REV_1_1 = (int)0x80FC0011, /**< SC1023 rev 1.1 */ ++ e_P1023_REV_1_0 = (int)0x80FE0010, /**< P1023 rev 1.0 with security */ ++ e_P1023_REV_1_1 = (int)0x80FE0011, /**< P1023 rev 1.1 with security */ ++ e_P1017_REV_1_1 = (int)0x80FF0011, /**< P1017 rev 1.1 with security */ ++ e_P1023_REV_1_0_NO_SEC = (int)0x80F60010, /**< P1023 rev 1.0 without security */ ++ e_P1023_REV_1_1_NO_SEC = (int)0x80F60011, /**< P1023 rev 1.1 without security */ ++ e_P1017_REV_1_1_NO_SEC = (int)0x80F70011 /**< P1017 rev 1.1 without security */ ++} e_P1023DeviceName; ++ ++/**************************************************************************//** ++ @Description structure representing P1023 initialization parameters ++*//***************************************************************************/ ++typedef struct t_P1023Params ++{ ++ uintptr_t ccsrBaseAddress; /**< CCSR base address (virtual) */ ++ uintptr_t bmPortalsBaseAddress; /**< Portals base address (virtual) */ ++ uintptr_t qmPortalsBaseAddress; /**< Portals base address (virtual) */ ++} t_P1023Params; ++ ++/**************************************************************************//** ++ @Function P1023_ConfigAndInit ++ ++ @Description General initiation of the chip registers. ++ ++ @Param[in] p_P1023Params - A pointer to data structure of parameters ++ ++ @Return A handle to the P1023 data structure. ++*//***************************************************************************/ ++t_Handle P1023_ConfigAndInit(t_P1023Params *p_P1023Params); ++ ++/**************************************************************************//** ++ @Function P1023_Free ++ ++ @Description Free all resources. ++ ++ @Param h_P1023 - (In) The handle of the initialized P1023 object. ++ ++ @Return E_OK on success; Other value otherwise. ++*//***************************************************************************/ ++t_Error P1023_Free(t_Handle h_P1023); ++ ++/**************************************************************************//** ++ @Function P1023_GetRevInfo ++ ++ @Description This routine enables access to chip and revision information. ++ ++ @Param[in] gutilBase - Base address of P1023 GUTIL registers. ++ ++ @Return Part ID and revision. ++*//***************************************************************************/ ++e_P1023DeviceName P1023_GetRevInfo(uintptr_t gutilBase); ++ ++/**************************************************************************//** ++ @Function P1023_GetE500Factor ++ ++ @Description Returns E500 core clock multiplication factor. ++ ++ @Param[in] gutilBase - Base address of P1023 GUTIL registers. ++ @Param[in] coreId - Id of the requested core. ++ @Param[out] p_E500MulFactor - Returns E500 to CCB multification factor. ++ @Param[out] p_E500DivFactor - Returns E500 to CCB division factor. ++ ++ @Return E_OK on success; Other value otherwise. ++* ++*//***************************************************************************/ ++t_Error P1023_GetE500Factor(uintptr_t gutilBase, ++ uint32_t coreId, ++ uint32_t *p_E500MulFactor, ++ uint32_t *p_E500DivFactor); ++ ++/**************************************************************************//** ++ @Function P1023_GetFmFactor ++ ++ @Description returns FM multiplication factors. (This value is returned using ++ two parameters to avoid using float parameter). ++ ++ @Param[in] gutilBase - Base address of P1023 GUTIL registers. ++ @Param[out] p_FmMulFactor - returns E500 to CCB multification factor. ++ @Param[out] p_FmDivFactor - returns E500 to CCB division factor. ++ ++ @Return E_OK on success; Other value otherwise. ++*//***************************************************************************/ ++t_Error P1023_GetFmFactor(uintptr_t gutilBase, uint32_t *p_FmMulFactor, uint32_t *p_FmDivFactor); ++ ++/**************************************************************************//** ++ @Function P1023_GetCcbFactor ++ ++ @Description returns system multiplication factor. ++ ++ @Param[in] gutilBase - Base address of P1023 GUTIL registers. ++ ++ @Return System multiplication factor. ++*//***************************************************************************/ ++uint32_t P1023_GetCcbFactor(uintptr_t gutilBase); ++ ++#if 0 ++/**************************************************************************//** ++ @Function P1023_GetDdrFactor ++ ++ @Description returns the multiplication factor of the clock in for the DDR clock . ++ Note: assumes the ddr_in_clk is identical to the sys_in_clk ++ ++ @Param[in] gutilBase - Base address of P1023 GUTIL registers. ++ @Param p_DdrMulFactor - returns DDR in clk multification factor. ++ @Param p_DdrDivFactor - returns DDR division factor. ++ ++ @Return E_OK on success; Other value otherwise.. ++*//***************************************************************************/ ++t_Error P1023_GetDdrFactor( uintptr_t gutilBase, ++ uint32_t *p_DdrMulFactor, ++ uint32_t *p_DdrDivFactor); ++ ++/**************************************************************************//** ++ @Function P1023_GetDdrType ++ ++ @Description returns the multiplication factor of the clock in for the DDR clock . ++ ++ @Param[in] gutilBase - Base address of P1023 GUTIL registers. ++ @Param p_DdrType - (Out) returns DDR type DDR1/DDR2/DDR3. ++ ++ @Return E_OK on success; Other value otherwise. ++*//***************************************************************************/ ++t_Error P1023_GetDdrType(uintptr_t gutilBase, e_DdrType *p_DdrType ); ++#endif ++ ++/** @} */ /* end of 1023_init_grp group */ ++/** @} */ /* end of 1023_grp group */ ++ ++#define CORE_E500V2 ++ ++#if 0 /* using unified values */ ++/***************************************************************************** ++ INTEGRATION-SPECIFIC MODULE CODES ++******************************************************************************/ ++#define MODULE_UNKNOWN 0x00000000 ++#define MODULE_MEM 0x00010000 ++#define MODULE_MM 0x00020000 ++#define MODULE_CORE 0x00030000 ++#define MODULE_P1023 0x00040000 ++#define MODULE_MII 0x00050000 ++#define MODULE_PM 0x00060000 ++#define MODULE_MMU 0x00070000 ++#define MODULE_PIC 0x00080000 ++#define MODULE_L2_CACHE 0x00090000 ++#define MODULE_DUART 0x000a0000 ++#define MODULE_SERDES 0x000b0000 ++#define MODULE_PIO 0x000c0000 ++#define MODULE_QM 0x000d0000 ++#define MODULE_BM 0x000e0000 ++#define MODULE_SEC 0x000f0000 ++#define MODULE_FM 0x00100000 ++#define MODULE_FM_MURAM 0x00110000 ++#define MODULE_FM_PCD 0x00120000 ++#define MODULE_FM_RTC 0x00130000 ++#define MODULE_FM_MAC 0x00140000 ++#define MODULE_FM_PORT 0x00150000 ++#define MODULE_FM_MACSEC 0x00160000 ++#define MODULE_FM_MACSEC_SECY 0x00170000 ++#define MODULE_FM_SP 0x00280000 ++#define MODULE_ECM 0x00190000 ++#define MODULE_DMA 0x001a0000 ++#define MODULE_DDR 0x001b0000 ++#define MODULE_LAW 0x001c0000 ++#define MODULE_LBC 0x001d0000 ++#define MODULE_I2C 0x001e0000 ++#define MODULE_ESPI 0x001f0000 ++#define MODULE_PCI 0x00200000 ++#define MODULE_DPA_PORT 0x00210000 ++#define MODULE_USB 0x00220000 ++#endif /* using unified values */ ++ ++/***************************************************************************** ++ LBC INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++/**************************************************************************//** ++ @Group lbc_exception_grp LBC Exception Unit ++ ++ @Description LBC Exception unit API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Anchor lbc_exbm ++ ++ @Collection LBC Errors Bit Mask ++ ++ These errors are reported through the exceptions callback.. ++ The values can be or'ed in any combination in the errors mask ++ parameter of the errors report structure. ++ ++ These errors can also be passed as a bit-mask to ++ LBC_EnableErrorChecking() or LBC_DisableErrorChecking(), ++ for enabling or disabling error checking. ++ @{ ++*//***************************************************************************/ ++#define LBC_ERR_BUS_MONITOR 0x80000000 /**< Bus monitor error */ ++#define LBC_ERR_PARITY_ECC 0x20000000 /**< Parity error for GPCM/UPM */ ++#define LBC_ERR_WRITE_PROTECT 0x04000000 /**< Write protection error */ ++#define LBC_ERR_CHIP_SELECT 0x00080000 /**< Unrecognized chip select */ ++ ++#define LBC_ERR_ALL (LBC_ERR_BUS_MONITOR | LBC_ERR_PARITY_ECC | \ ++ LBC_ERR_WRITE_PROTECT | LBC_ERR_CHIP_SELECT) ++ /**< All possible errors */ ++/* @} */ ++/** @} */ /* end of lbc_exception_grp group */ ++ ++#define LBC_NUM_OF_BANKS 2 ++#define LBC_MAX_CS_SIZE 0x0000000100000000LL ++#define LBC_ATOMIC_OPERATION_SUPPORT ++#define LBC_PARITY_SUPPORT ++#define LBC_ADDRESS_SHIFT_SUPPORT ++#define LBC_ADDRESS_HOLD_TIME_CTRL ++#define LBC_HIGH_CLK_DIVIDERS ++#define LBC_FCM_AVAILABLE ++ ++ ++/***************************************************************************** ++ LAW INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define LAW_ARCH_CCB ++#define LAW_NUM_OF_WINDOWS 12 ++#define LAW_MIN_WINDOW_SIZE 0x0000000000001000LL /**< 4KB */ ++#define LAW_MAX_WINDOW_SIZE 0x0000001000000000LL /**< 32GB */ ++ ++ ++/***************************************************************************** ++ SPI INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define SPI_NUM_OF_CONTROLLERS 1 ++ ++/***************************************************************************** ++ PCI/PCIe INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++ ++#define PCI_MAX_INBOUND_WINDOWS_NUM 4 ++#define PCI_MAX_OUTBOUND_WINDOWS_NUM 5 ++ ++/**************************************************************************//** ++ @Description Target interface of an inbound window ++*//***************************************************************************/ ++typedef enum e_PciTargetInterface ++{ ++ e_PCI_TARGET_PCIE_2 = 0x1, /**< PCI Express target interface 2 */ ++ e_PCI_TARGET_PCIE_1 = 0x2, /**< PCI Express target interface 1 */ ++ e_PCI_TARGET_PCIE_3 = 0x3, /**< PCI Express target interface 3 */ ++ e_PCI_TARGET_LOCAL_MEMORY = 0xF /**< Local Memory (DDR SDRAM, Local Bus, SRAM) target interface */ ++ ++} e_PciTargetInterface; ++ ++/***************************************************************************** ++ DDR INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define DDR_NUM_OF_VALID_CS 2 ++ ++/***************************************************************************** ++ SEC INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define SEC_ERRATA_STAT_REGS_UNUSABLE ++ ++/***************************************************************************** ++ DMA INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define DMA_NUM_OF_CONTROLLERS 2 ++ ++ ++ ++ ++/***************************************************************************** ++ 1588 INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define PTP_V2 ++ ++/**************************************************************************//** ++ @Function P1023_GetMuxControlReg ++ ++ @Description Returns the value of PMUXCR (Alternate Function Signal Multiplex ++ Control Register) ++ ++ @Param[in] gutilBase - Base address of P1023 GUTIL registers. ++ ++ @Return Value of PMUXCR ++*//***************************************************************************/ ++uint32_t P1023_GetMuxControlReg(uintptr_t gutilBase); ++ ++/**************************************************************************//** ++ @Function P1023_SetMuxControlReg ++ ++ @Description Sets the value of PMUXCR (Alternate Function Signal Multiplex ++ Control Register) ++ ++ @Param[in] gutilBase - Base address of P1023 GUTIL registers. ++ @Param[in] val - the new value for PMUXCR. ++ ++ @Return None ++*//***************************************************************************/ ++void P1023_SetMuxControlReg(uintptr_t gutilBase, uint32_t val); ++ ++/**************************************************************************//** ++ @Function P1023_GetDeviceDisableStatusRegister ++ ++ @Description Returns the value of DEVDISR (Device Disable Register) ++ ++ @Param[in] gutilBase - Base address of P1023 GUTIL registers. ++ ++ @Return Value of DEVDISR ++*//***************************************************************************/ ++uint32_t P1023_GetDeviceDisableStatusRegister(uintptr_t gutilBase); ++ ++/**************************************************************************//** ++ @Function P1023_GetPorDeviceStatusRegister ++ ++ @Description Returns the value of POR Device Status Register ++ ++ @Param[in] gutilBase - Base address of P1023 GUTIL registers. ++ ++ @Return POR Device Status Register ++*//***************************************************************************/ ++uint32_t P1023_GetPorDeviceStatusRegister(uintptr_t gutilBase); ++ ++/**************************************************************************//** ++ @Function P1023_GetPorBootModeStatusRegister ++ ++ @Description Returns the value of POR Boot Mode Status Register ++ ++ @Param[in] gutilBase - Base address of P1023 GUTIL registers. ++ ++ @Return POR Boot Mode Status Register value ++*//***************************************************************************/ ++uint32_t P1023_GetPorBootModeStatusRegister(uintptr_t gutilBase); ++ ++ ++#define PORDEVSR_SGMII1_DIS 0x10000000 ++#define PORDEVSR_SGMII2_DIS 0x08000000 ++#define PORDEVSR_ECP1 0x02000000 ++#define PORDEVSR_IO_SEL 0x00780000 ++#define PORDEVSR_IO_SEL_SHIFT 19 ++#define PORBMSR_HA 0x00070000 ++#define PORBMSR_HA_SHIFT 16 ++ ++#define DEVDISR_QM_BM 0x80000000 ++#define DEVDISR_FM 0x40000000 ++#define DEVDISR_PCIE1 0x20000000 ++#define DEVDISR_MAC_SEC 0x10000000 ++#define DEVDISR_ELBC 0x08000000 ++#define DEVDISR_PCIE2 0x04000000 ++#define DEVDISR_PCIE3 0x02000000 ++#define DEVDISR_CAAM 0x01000000 ++#define DEVDISR_USB0 0x00800000 ++#define DEVDISR_1588 0x00020000 ++#define DEVDISR_CORE0 0x00008000 ++#define DEVDISR_TB0 0x00004000 ++#define DEVDISR_CORE1 0x00002000 ++#define DEVDISR_TB1 0x00001000 ++#define DEVDISR_DMA1 0x00000400 ++#define DEVDISR_DMA2 0x00000200 ++#define DEVDISR_DDR 0x00000010 ++#define DEVDISR_TSEC1 0x00000080 ++#define DEVDISR_TSEC2 0x00000040 ++#define DEVDISR_SPI 0x00000008 ++#define DEVDISR_I2C 0x00000004 ++#define DEVDISR_DUART 0x00000002 ++ ++ ++#endif /* __PART_INTEGRATION_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/dpaa_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/dpaa_integration_ext.h +new file mode 100644 +index 00000000..6e2b925f +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/dpaa_integration_ext.h +@@ -0,0 +1,276 @@ ++/* Copyright (c) 2009-2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/**************************************************************************//** ++ @File dpaa_integration_ext.h ++ ++ @Description P3040/P4080/P5020 FM external definitions and structures. ++*//***************************************************************************/ ++#ifndef __DPAA_INTEGRATION_EXT_H ++#define __DPAA_INTEGRATION_EXT_H ++ ++#include "std_ext.h" ++ ++ ++#define DPAA_VERSION 10 ++ ++typedef enum { ++ e_DPAA_SWPORTAL0 = 0, ++ e_DPAA_SWPORTAL1, ++ e_DPAA_SWPORTAL2, ++ e_DPAA_SWPORTAL3, ++ e_DPAA_SWPORTAL4, ++ e_DPAA_SWPORTAL5, ++ e_DPAA_SWPORTAL6, ++ e_DPAA_SWPORTAL7, ++ e_DPAA_SWPORTAL8, ++ e_DPAA_SWPORTAL9, ++ e_DPAA_SWPORTAL_DUMMY_LAST ++} e_DpaaSwPortal; ++ ++typedef enum { ++ e_DPAA_DCPORTAL0 = 0, ++ e_DPAA_DCPORTAL1, ++ e_DPAA_DCPORTAL2, ++ e_DPAA_DCPORTAL3, ++ e_DPAA_DCPORTAL4, ++ e_DPAA_DCPORTAL_DUMMY_LAST ++} e_DpaaDcPortal; ++ ++#define DPAA_MAX_NUM_OF_SW_PORTALS e_DPAA_SWPORTAL_DUMMY_LAST ++#define DPAA_MAX_NUM_OF_DC_PORTALS e_DPAA_DCPORTAL_DUMMY_LAST ++ ++/***************************************************************************** ++ QMan INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define QM_MAX_NUM_OF_POOL_CHANNELS 15 /**< Total number of channels, dedicated and pool */ ++#define QM_MAX_NUM_OF_WQ 8 /**< Number of work queues per channel */ ++#define QM_MAX_NUM_OF_SWP_AS 4 ++#define QM_MAX_NUM_OF_CGS 256 /**< Number of congestion groups */ ++#define QM_MAX_NUM_OF_FQIDS (16 * MEGABYTE) /**< FQIDs range - 24 bits */ ++ ++/**************************************************************************//** ++ @Description Work Queue Channel assignments in QMan. ++*//***************************************************************************/ ++typedef enum ++{ ++ e_QM_FQ_CHANNEL_SWPORTAL0 = 0, /**< Dedicated channels serviced by software portals 0 to 9 */ ++ e_QM_FQ_CHANNEL_SWPORTAL1, ++ e_QM_FQ_CHANNEL_SWPORTAL2, ++ e_QM_FQ_CHANNEL_SWPORTAL3, ++ e_QM_FQ_CHANNEL_SWPORTAL4, ++ e_QM_FQ_CHANNEL_SWPORTAL5, ++ e_QM_FQ_CHANNEL_SWPORTAL6, ++ e_QM_FQ_CHANNEL_SWPORTAL7, ++ e_QM_FQ_CHANNEL_SWPORTAL8, ++ e_QM_FQ_CHANNEL_SWPORTAL9, ++ ++ e_QM_FQ_CHANNEL_POOL1 = 0x21, /**< Pool channels that can be serviced by any of the software portals */ ++ e_QM_FQ_CHANNEL_POOL2, ++ e_QM_FQ_CHANNEL_POOL3, ++ e_QM_FQ_CHANNEL_POOL4, ++ e_QM_FQ_CHANNEL_POOL5, ++ e_QM_FQ_CHANNEL_POOL6, ++ e_QM_FQ_CHANNEL_POOL7, ++ e_QM_FQ_CHANNEL_POOL8, ++ e_QM_FQ_CHANNEL_POOL9, ++ e_QM_FQ_CHANNEL_POOL10, ++ e_QM_FQ_CHANNEL_POOL11, ++ e_QM_FQ_CHANNEL_POOL12, ++ e_QM_FQ_CHANNEL_POOL13, ++ e_QM_FQ_CHANNEL_POOL14, ++ e_QM_FQ_CHANNEL_POOL15, ++ ++ e_QM_FQ_CHANNEL_FMAN0_SP0 = 0x40, /**< Dedicated channels serviced by Direct Connect Portal 0: ++ connected to FMan 0; assigned in incrementing order to ++ each sub-portal (SP) in the portal */ ++ e_QM_FQ_CHANNEL_FMAN0_SP1, ++ e_QM_FQ_CHANNEL_FMAN0_SP2, ++ e_QM_FQ_CHANNEL_FMAN0_SP3, ++ e_QM_FQ_CHANNEL_FMAN0_SP4, ++ e_QM_FQ_CHANNEL_FMAN0_SP5, ++ e_QM_FQ_CHANNEL_FMAN0_SP6, ++ e_QM_FQ_CHANNEL_FMAN0_SP7, ++ e_QM_FQ_CHANNEL_FMAN0_SP8, ++ e_QM_FQ_CHANNEL_FMAN0_SP9, ++ e_QM_FQ_CHANNEL_FMAN0_SP10, ++ e_QM_FQ_CHANNEL_FMAN0_SP11, ++/* difference between 5020 and 4080 :) */ ++ e_QM_FQ_CHANNEL_FMAN1_SP0 = 0x60, ++ e_QM_FQ_CHANNEL_FMAN1_SP1, ++ e_QM_FQ_CHANNEL_FMAN1_SP2, ++ e_QM_FQ_CHANNEL_FMAN1_SP3, ++ e_QM_FQ_CHANNEL_FMAN1_SP4, ++ e_QM_FQ_CHANNEL_FMAN1_SP5, ++ e_QM_FQ_CHANNEL_FMAN1_SP6, ++ e_QM_FQ_CHANNEL_FMAN1_SP7, ++ e_QM_FQ_CHANNEL_FMAN1_SP8, ++ e_QM_FQ_CHANNEL_FMAN1_SP9, ++ e_QM_FQ_CHANNEL_FMAN1_SP10, ++ e_QM_FQ_CHANNEL_FMAN1_SP11, ++ ++ e_QM_FQ_CHANNEL_CAAM = 0x80, /**< Dedicated channel serviced by Direct Connect Portal 2: ++ connected to SEC 4.x */ ++ ++ e_QM_FQ_CHANNEL_PME = 0xA0, /**< Dedicated channel serviced by Direct Connect Portal 3: ++ connected to PME */ ++ e_QM_FQ_CHANNEL_RAID = 0xC0 /**< Dedicated channel serviced by Direct Connect Portal 4: ++ connected to RAID */ ++} e_QmFQChannel; ++ ++/***************************************************************************** ++ BMan INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define BM_MAX_NUM_OF_POOLS 64 /**< Number of buffers pools */ ++ ++ ++/***************************************************************************** ++ FM INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define INTG_MAX_NUM_OF_FM 2 ++ ++/* Ports defines */ ++#define FM_MAX_NUM_OF_1G_MACS 5 ++#define FM_MAX_NUM_OF_10G_MACS 1 ++#define FM_MAX_NUM_OF_MACS (FM_MAX_NUM_OF_1G_MACS + FM_MAX_NUM_OF_10G_MACS) ++#define FM_MAX_NUM_OF_OH_PORTS 7 ++ ++#define FM_MAX_NUM_OF_1G_RX_PORTS FM_MAX_NUM_OF_1G_MACS ++#define FM_MAX_NUM_OF_10G_RX_PORTS FM_MAX_NUM_OF_10G_MACS ++#define FM_MAX_NUM_OF_RX_PORTS (FM_MAX_NUM_OF_10G_RX_PORTS + FM_MAX_NUM_OF_1G_RX_PORTS) ++ ++#define FM_MAX_NUM_OF_1G_TX_PORTS FM_MAX_NUM_OF_1G_MACS ++#define FM_MAX_NUM_OF_10G_TX_PORTS FM_MAX_NUM_OF_10G_MACS ++#define FM_MAX_NUM_OF_TX_PORTS (FM_MAX_NUM_OF_10G_TX_PORTS + FM_MAX_NUM_OF_1G_TX_PORTS) ++ ++#define FM_PORT_MAX_NUM_OF_EXT_POOLS 8 /**< Number of external BM pools per Rx port */ ++#define FM_PORT_NUM_OF_CONGESTION_GRPS 256 /**< Total number of congestion groups in QM */ ++#define FM_MAX_NUM_OF_SUB_PORTALS 12 ++#define FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS 0 ++ ++/* Rams defines */ ++#define FM_MURAM_SIZE (160*KILOBYTE) ++#define FM_IRAM_SIZE(major, minor) (64 * KILOBYTE) ++#define FM_NUM_OF_CTRL 2 ++ ++/* PCD defines */ ++#define FM_PCD_PLCR_NUM_ENTRIES 256 /**< Total number of policer profiles */ ++#define FM_PCD_KG_NUM_OF_SCHEMES 32 /**< Total number of KG schemes */ ++#define FM_PCD_MAX_NUM_OF_CLS_PLANS 256 /**< Number of classification plan entries. */ ++#define FM_PCD_PRS_SW_PATCHES_SIZE 0x00000200 /**< Number of bytes saved for patches */ ++#define FM_PCD_SW_PRS_SIZE 0x00000800 /**< Total size of SW parser area */ ++ ++/* RTC defines */ ++#define FM_RTC_NUM_OF_ALARMS 2 /**< RTC number of alarms */ ++#define FM_RTC_NUM_OF_PERIODIC_PULSES 2 /**< RTC number of periodic pulses */ ++#define FM_RTC_NUM_OF_EXT_TRIGGERS 2 /**< RTC number of external triggers */ ++ ++/* QMI defines */ ++#define QMI_MAX_NUM_OF_TNUMS 64 ++#define QMI_DEF_TNUMS_THRESH 48 ++ ++/* FPM defines */ ++#define FM_NUM_OF_FMAN_CTRL_EVENT_REGS 4 ++ ++/* DMA defines */ ++#define DMA_THRESH_MAX_COMMQ 31 ++#define DMA_THRESH_MAX_BUF 127 ++ ++/* BMI defines */ ++#define BMI_MAX_NUM_OF_TASKS 128 ++#define BMI_MAX_NUM_OF_DMAS 32 ++#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE) ++#define PORT_MAX_WEIGHT 16 ++ ++ ++#define FM_CHECK_PORT_RESTRICTIONS(__validPorts, __newPortIndx) TRUE ++ ++/* p4080-rev1 unique features */ ++#define QM_CGS_NO_FRAME_MODE ++ ++/* p4080 unique features */ ++#define FM_NO_DISPATCH_RAM_ECC ++#define FM_NO_WATCHDOG ++#define FM_NO_TNUM_AGING ++#define FM_KG_NO_BYPASS_FQID_GEN ++#define FM_KG_NO_BYPASS_PLCR_PROFILE_GEN ++#define FM_NO_BACKUP_POOLS ++#define FM_NO_OP_OBSERVED_POOLS ++#define FM_NO_ADVANCED_RATE_LIMITER ++#define FM_NO_OP_OBSERVED_CGS ++#define FM_HAS_TOTAL_DMAS ++#define FM_KG_NO_IPPID_SUPPORT ++#define FM_NO_GUARANTEED_RESET_VALUES ++#define FM_MAC_RESET ++ ++/* FM erratas */ ++#define FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 ++#define FM_TX_SHORT_FRAME_BAD_TS_ERRATA_10GMAC_A006 /* No implementation, Out of LLD scope */ ++#define FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007 ++#define FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008 ++#define FM_TX_INVALID_ECC_ERRATA_10GMAC_A009 /* Out of LLD scope, user may disable ECC exceptions using FM_DisableRamsEcc */ ++#define FM_BAD_VLAN_DETECT_ERRATA_10GMAC_A010 ++ ++#define FM_RX_PREAM_4_ERRATA_DTSEC_A001 ++#define FM_GRS_ERRATA_DTSEC_A002 ++#define FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 ++#define FM_GTS_ERRATA_DTSEC_A004 ++#define FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012 ++#define FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014 ++#define FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839 ++ ++#define FM_MAGIC_PACKET_UNRECOGNIZED_ERRATA_DTSEC2 /* No implementation, Out of LLD scope */ ++#define FM_TX_LOCKUP_ERRATA_DTSEC6 ++ ++#define FM_HC_DEF_FQID_ONLY_ERRATA_FMAN_A003 /* Implemented by ucode */ ++#define FM_DEBUG_TRACE_FMAN_A004 /* No implementation, Out of LLD scope */ ++ ++#define FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 ++ ++#define FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005 ++ ++#define FM_LEN_CHECK_ERRATA_FMAN_SW002 ++ ++#define FM_NO_CTXA_COPY_ERRATA_FMAN_SW001 ++#define FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004 ++ ++/***************************************************************************** ++ FM MACSEC INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define NUM_OF_RX_SC 16 ++#define NUM_OF_TX_SC 16 ++ ++#define NUM_OF_SA_PER_RX_SC 2 ++#define NUM_OF_SA_PER_TX_SC 2 ++ ++ ++#endif /* __DPAA_INTEGRATION_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_ext.h +new file mode 100644 +index 00000000..512f0baf +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_ext.h +@@ -0,0 +1,83 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/**************************************************************************//** ++ ++ @File part_ext.h ++ ++ @Description Definitions for the part (integration) module. ++*//***************************************************************************/ ++ ++#ifndef __PART_EXT_H ++#define __PART_EXT_H ++ ++#include "std_ext.h" ++#include "part_integration_ext.h" ++ ++ ++#if !(defined(MPC8306) || \ ++ defined(MPC8309) || \ ++ defined(MPC834x) || \ ++ defined(MPC836x) || \ ++ defined(MPC832x) || \ ++ defined(MPC837x) || \ ++ defined(MPC8568) || \ ++ defined(MPC8569) || \ ++ defined(P1020) || \ ++ defined(P1021) || \ ++ defined(P1022) || \ ++ defined(P1023) || \ ++ defined(P2020) || \ ++ defined(P2040) || \ ++ defined(P3041) || \ ++ defined(P4080) || \ ++ defined(SC4080) || \ ++ defined(P5020) || \ ++ defined(MSC814x)) ++#error "unable to proceed without chip-definition" ++#endif /* !(defined(MPC834x) || ... */ ++ ++ ++/**************************************************************************//* ++ @Description Part data structure - must be contained in any integration ++ data structure. ++*//***************************************************************************/ ++typedef struct t_Part ++{ ++ uintptr_t (* f_GetModuleBase)(t_Handle h_Part, e_ModuleId moduleId); ++ /**< Returns the address of the module's memory map base. */ ++ e_ModuleId (* f_GetModuleIdByBase)(t_Handle h_Part, uintptr_t baseAddress); ++ /**< Returns the module's ID according to its memory map base. */ ++} t_Part; ++ ++ ++#endif /* __PART_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_integration_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_integration_ext.h +new file mode 100644 +index 00000000..03c59b8b +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/integrations/P3040_P4080_P5020/part_integration_ext.h +@@ -0,0 +1,336 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/**************************************************************************//** ++ @File part_integration_ext.h ++ ++ @Description P3040/P4080/P5020 external definitions and structures. ++*//***************************************************************************/ ++#ifndef __PART_INTEGRATION_EXT_H ++#define __PART_INTEGRATION_EXT_H ++ ++#include "std_ext.h" ++#include "dpaa_integration_ext.h" ++ ++ ++/**************************************************************************//** ++ @Group P3040/P4080/P5020_chip_id P5020 Application Programming Interface ++ ++ @Description P3040/P4080/P5020 Chip functions,definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++#define CORE_E500MC ++ ++#define INTG_MAX_NUM_OF_CORES 1 ++ ++ ++/**************************************************************************//** ++ @Description Module types. ++*//***************************************************************************/ ++typedef enum e_ModuleId ++{ ++ e_MODULE_ID_DUART_1 = 0, ++ e_MODULE_ID_DUART_2, ++ e_MODULE_ID_DUART_3, ++ e_MODULE_ID_DUART_4, ++ e_MODULE_ID_LAW, ++ e_MODULE_ID_LBC, ++ e_MODULE_ID_PAMU, ++ e_MODULE_ID_QM, /**< Queue manager module */ ++ e_MODULE_ID_BM, /**< Buffer manager module */ ++ e_MODULE_ID_QM_CE_PORTAL_0, ++ e_MODULE_ID_QM_CI_PORTAL_0, ++ e_MODULE_ID_QM_CE_PORTAL_1, ++ e_MODULE_ID_QM_CI_PORTAL_1, ++ e_MODULE_ID_QM_CE_PORTAL_2, ++ e_MODULE_ID_QM_CI_PORTAL_2, ++ e_MODULE_ID_QM_CE_PORTAL_3, ++ e_MODULE_ID_QM_CI_PORTAL_3, ++ e_MODULE_ID_QM_CE_PORTAL_4, ++ e_MODULE_ID_QM_CI_PORTAL_4, ++ e_MODULE_ID_QM_CE_PORTAL_5, ++ e_MODULE_ID_QM_CI_PORTAL_5, ++ e_MODULE_ID_QM_CE_PORTAL_6, ++ e_MODULE_ID_QM_CI_PORTAL_6, ++ e_MODULE_ID_QM_CE_PORTAL_7, ++ e_MODULE_ID_QM_CI_PORTAL_7, ++ e_MODULE_ID_QM_CE_PORTAL_8, ++ e_MODULE_ID_QM_CI_PORTAL_8, ++ e_MODULE_ID_QM_CE_PORTAL_9, ++ e_MODULE_ID_QM_CI_PORTAL_9, ++ e_MODULE_ID_BM_CE_PORTAL_0, ++ e_MODULE_ID_BM_CI_PORTAL_0, ++ e_MODULE_ID_BM_CE_PORTAL_1, ++ e_MODULE_ID_BM_CI_PORTAL_1, ++ e_MODULE_ID_BM_CE_PORTAL_2, ++ e_MODULE_ID_BM_CI_PORTAL_2, ++ e_MODULE_ID_BM_CE_PORTAL_3, ++ e_MODULE_ID_BM_CI_PORTAL_3, ++ e_MODULE_ID_BM_CE_PORTAL_4, ++ e_MODULE_ID_BM_CI_PORTAL_4, ++ e_MODULE_ID_BM_CE_PORTAL_5, ++ e_MODULE_ID_BM_CI_PORTAL_5, ++ e_MODULE_ID_BM_CE_PORTAL_6, ++ e_MODULE_ID_BM_CI_PORTAL_6, ++ e_MODULE_ID_BM_CE_PORTAL_7, ++ e_MODULE_ID_BM_CI_PORTAL_7, ++ e_MODULE_ID_BM_CE_PORTAL_8, ++ e_MODULE_ID_BM_CI_PORTAL_8, ++ e_MODULE_ID_BM_CE_PORTAL_9, ++ e_MODULE_ID_BM_CI_PORTAL_9, ++ e_MODULE_ID_FM1, /**< Frame manager #1 module */ ++ e_MODULE_ID_FM1_RTC, /**< FM Real-Time-Clock */ ++ e_MODULE_ID_FM1_MURAM, /**< FM Multi-User-RAM */ ++ e_MODULE_ID_FM1_BMI, /**< FM BMI block */ ++ e_MODULE_ID_FM1_QMI, /**< FM QMI block */ ++ e_MODULE_ID_FM1_PRS, /**< FM parser block */ ++ e_MODULE_ID_FM1_PORT_HO0, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM1_PORT_HO1, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM1_PORT_HO2, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM1_PORT_HO3, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM1_PORT_HO4, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM1_PORT_HO5, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM1_PORT_HO6, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM1_PORT_1GRx0, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM1_PORT_1GRx1, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM1_PORT_1GRx2, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM1_PORT_1GRx3, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM1_PORT_1GRx4, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM1_PORT_10GRx0, /**< FM Rx 10G MAC port block */ ++ e_MODULE_ID_FM1_PORT_1GTx0, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM1_PORT_1GTx1, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM1_PORT_1GTx2, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM1_PORT_1GTx3, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM1_PORT_1GTx4, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM1_PORT_10GTx0, /**< FM Tx 10G MAC port block */ ++ e_MODULE_ID_FM1_PLCR, /**< FM Policer */ ++ e_MODULE_ID_FM1_KG, /**< FM Keygen */ ++ e_MODULE_ID_FM1_DMA, /**< FM DMA */ ++ e_MODULE_ID_FM1_FPM, /**< FM FPM */ ++ e_MODULE_ID_FM1_IRAM, /**< FM Instruction-RAM */ ++ e_MODULE_ID_FM1_1GMDIO0, /**< FM 1G MDIO MAC 0*/ ++ e_MODULE_ID_FM1_1GMDIO1, /**< FM 1G MDIO MAC 1*/ ++ e_MODULE_ID_FM1_1GMDIO2, /**< FM 1G MDIO MAC 2*/ ++ e_MODULE_ID_FM1_1GMDIO3, /**< FM 1G MDIO MAC 3*/ ++ e_MODULE_ID_FM1_10GMDIO, /**< FM 10G MDIO */ ++ e_MODULE_ID_FM1_PRS_IRAM, /**< FM SW-parser Instruction-RAM */ ++ e_MODULE_ID_FM1_1GMAC0, /**< FM 1G MAC #0 */ ++ e_MODULE_ID_FM1_1GMAC1, /**< FM 1G MAC #1 */ ++ e_MODULE_ID_FM1_1GMAC2, /**< FM 1G MAC #2 */ ++ e_MODULE_ID_FM1_1GMAC3, /**< FM 1G MAC #3 */ ++ e_MODULE_ID_FM1_10GMAC0, /**< FM 10G MAC #0 */ ++ ++ e_MODULE_ID_FM2, /**< Frame manager #2 module */ ++ e_MODULE_ID_FM2_RTC, /**< FM Real-Time-Clock */ ++ e_MODULE_ID_FM2_MURAM, /**< FM Multi-User-RAM */ ++ e_MODULE_ID_FM2_BMI, /**< FM BMI block */ ++ e_MODULE_ID_FM2_QMI, /**< FM QMI block */ ++ e_MODULE_ID_FM2_PRS, /**< FM parser block */ ++ e_MODULE_ID_FM2_PORT_HO0, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM2_PORT_HO1, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM2_PORT_HO2, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM2_PORT_HO3, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM2_PORT_HO4, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM2_PORT_HO5, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM2_PORT_HO6, /**< FM Host-command/offline-parsing port block */ ++ e_MODULE_ID_FM2_PORT_1GRx0, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM2_PORT_1GRx1, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM2_PORT_1GRx2, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM2_PORT_1GRx3, /**< FM Rx 1G MAC port block */ ++ e_MODULE_ID_FM2_PORT_10GRx0, /**< FM Rx 10G MAC port block */ ++ e_MODULE_ID_FM2_PORT_1GTx0, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM2_PORT_1GTx1, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM2_PORT_1GTx2, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM2_PORT_1GTx3, /**< FM Tx 1G MAC port block */ ++ e_MODULE_ID_FM2_PORT_10GTx0, /**< FM Tx 10G MAC port block */ ++ e_MODULE_ID_FM2_PLCR, /**< FM Policer */ ++ e_MODULE_ID_FM2_KG, /**< FM Keygen */ ++ e_MODULE_ID_FM2_DMA, /**< FM DMA */ ++ e_MODULE_ID_FM2_FPM, /**< FM FPM */ ++ e_MODULE_ID_FM2_IRAM, /**< FM Instruction-RAM */ ++ e_MODULE_ID_FM2_1GMDIO0, /**< FM 1G MDIO MAC 0*/ ++ e_MODULE_ID_FM2_1GMDIO1, /**< FM 1G MDIO MAC 1*/ ++ e_MODULE_ID_FM2_1GMDIO2, /**< FM 1G MDIO MAC 2*/ ++ e_MODULE_ID_FM2_1GMDIO3, /**< FM 1G MDIO MAC 3*/ ++ e_MODULE_ID_FM2_10GMDIO, /**< FM 10G MDIO */ ++ e_MODULE_ID_FM2_PRS_IRAM, /**< FM SW-parser Instruction-RAM */ ++ e_MODULE_ID_FM2_1GMAC0, /**< FM 1G MAC #0 */ ++ e_MODULE_ID_FM2_1GMAC1, /**< FM 1G MAC #1 */ ++ e_MODULE_ID_FM2_1GMAC2, /**< FM 1G MAC #2 */ ++ e_MODULE_ID_FM2_1GMAC3, /**< FM 1G MAC #3 */ ++ e_MODULE_ID_FM2_10GMAC0, /**< FM 10G MAC #0 */ ++ ++ e_MODULE_ID_SEC_GEN, /**< SEC 4.0 General registers */ ++ e_MODULE_ID_SEC_QI, /**< SEC 4.0 QI registers */ ++ e_MODULE_ID_SEC_JQ0, /**< SEC 4.0 JQ-0 registers */ ++ e_MODULE_ID_SEC_JQ1, /**< SEC 4.0 JQ-1 registers */ ++ e_MODULE_ID_SEC_JQ2, /**< SEC 4.0 JQ-2 registers */ ++ e_MODULE_ID_SEC_JQ3, /**< SEC 4.0 JQ-3 registers */ ++ e_MODULE_ID_SEC_RTIC, /**< SEC 4.0 RTIC registers */ ++ e_MODULE_ID_SEC_DECO0_CCB0, /**< SEC 4.0 DECO-0/CCB-0 registers */ ++ e_MODULE_ID_SEC_DECO1_CCB1, /**< SEC 4.0 DECO-1/CCB-1 registers */ ++ e_MODULE_ID_SEC_DECO2_CCB2, /**< SEC 4.0 DECO-2/CCB-2 registers */ ++ e_MODULE_ID_SEC_DECO3_CCB3, /**< SEC 4.0 DECO-3/CCB-3 registers */ ++ e_MODULE_ID_SEC_DECO4_CCB4, /**< SEC 4.0 DECO-4/CCB-4 registers */ ++ ++ e_MODULE_ID_MPIC, /**< MPIC */ ++ e_MODULE_ID_GPIO, /**< GPIO */ ++ e_MODULE_ID_SERDES, /**< SERDES */ ++ e_MODULE_ID_CPC_1, /**< CoreNet-Platform-Cache 1 */ ++ e_MODULE_ID_CPC_2, /**< CoreNet-Platform-Cache 2 */ ++ ++ e_MODULE_ID_SRIO_PORTS, /**< RapidIO controller */ ++ e_MODULE_ID_SRIO_MU, /**< RapidIO messaging unit module */ ++ ++ e_MODULE_ID_DUMMY_LAST ++} e_ModuleId; ++ ++#define NUM_OF_MODULES e_MODULE_ID_DUMMY_LAST ++ ++#if 0 /* using unified values */ ++/***************************************************************************** ++ INTEGRATION-SPECIFIC MODULE CODES ++******************************************************************************/ ++#define MODULE_UNKNOWN 0x00000000 ++#define MODULE_MEM 0x00010000 ++#define MODULE_MM 0x00020000 ++#define MODULE_CORE 0x00030000 ++#define MODULE_CHIP 0x00040000 ++#define MODULE_PLTFRM 0x00050000 ++#define MODULE_PM 0x00060000 ++#define MODULE_MMU 0x00070000 ++#define MODULE_PIC 0x00080000 ++#define MODULE_CPC 0x00090000 ++#define MODULE_DUART 0x000a0000 ++#define MODULE_SERDES 0x000b0000 ++#define MODULE_PIO 0x000c0000 ++#define MODULE_QM 0x000d0000 ++#define MODULE_BM 0x000e0000 ++#define MODULE_SEC 0x000f0000 ++#define MODULE_LAW 0x00100000 ++#define MODULE_LBC 0x00110000 ++#define MODULE_PAMU 0x00120000 ++#define MODULE_FM 0x00130000 ++#define MODULE_FM_MURAM 0x00140000 ++#define MODULE_FM_PCD 0x00150000 ++#define MODULE_FM_RTC 0x00160000 ++#define MODULE_FM_MAC 0x00170000 ++#define MODULE_FM_PORT 0x00180000 ++#define MODULE_FM_SP 0x00190000 ++#define MODULE_DPA_PORT 0x001a0000 ++#define MODULE_MII 0x001b0000 ++#define MODULE_I2C 0x001c0000 ++#define MODULE_DMA 0x001d0000 ++#define MODULE_DDR 0x001e0000 ++#define MODULE_ESPI 0x001f0000 ++#define MODULE_DPAA_IPSEC 0x00200000 ++#endif /* using unified values */ ++ ++/***************************************************************************** ++ PAMU INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define PAMU_NUM_OF_PARTITIONS 5 ++ ++#define PAMU_PICS_AVICS_ERRATA_PAMU3 ++ ++/***************************************************************************** ++ LAW INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define LAW_NUM_OF_WINDOWS 32 ++#define LAW_MIN_WINDOW_SIZE 0x0000000000001000LL /**< 4KB */ ++#define LAW_MAX_WINDOW_SIZE 0x0000002000000000LL /**< 64GB */ ++ ++ ++/***************************************************************************** ++ LBC INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++/**************************************************************************//** ++ @Group lbc_exception_grp LBC Exception Unit ++ ++ @Description LBC Exception unit API functions, definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Anchor lbc_exbm ++ ++ @Collection LBC Errors Bit Mask ++ ++ These errors are reported through the exceptions callback.. ++ The values can be or'ed in any combination in the errors mask ++ parameter of the errors report structure. ++ ++ These errors can also be passed as a bit-mask to ++ LBC_EnableErrorChecking() or LBC_DisableErrorChecking(), ++ for enabling or disabling error checking. ++ @{ ++*//***************************************************************************/ ++#define LBC_ERR_BUS_MONITOR 0x80000000 /**< Bus monitor error */ ++#define LBC_ERR_PARITY_ECC 0x20000000 /**< Parity error for GPCM/UPM */ ++#define LBC_ERR_WRITE_PROTECT 0x04000000 /**< Write protection error */ ++#define LBC_ERR_ATOMIC_WRITE 0x00800000 /**< Atomic write error */ ++#define LBC_ERR_ATOMIC_READ 0x00400000 /**< Atomic read error */ ++#define LBC_ERR_CHIP_SELECT 0x00080000 /**< Unrecognized chip select */ ++ ++#define LBC_ERR_ALL (LBC_ERR_BUS_MONITOR | LBC_ERR_PARITY_ECC | \ ++ LBC_ERR_WRITE_PROTECT | LBC_ERR_ATOMIC_WRITE | \ ++ LBC_ERR_ATOMIC_READ | LBC_ERR_CHIP_SELECT) ++ /**< All possible errors */ ++/* @} */ ++/** @} */ /* end of lbc_exception_grp group */ ++ ++#define LBC_INCORRECT_ERROR_REPORT_ERRATA ++ ++#define LBC_NUM_OF_BANKS 8 ++#define LBC_MAX_CS_SIZE 0x0000000100000000LL ++#define LBC_ATOMIC_OPERATION_SUPPORT ++#define LBC_PARITY_SUPPORT ++#define LBC_ADDRESS_HOLD_TIME_CTRL ++#define LBC_HIGH_CLK_DIVIDERS ++#define LBC_FCM_AVAILABLE ++ ++/***************************************************************************** ++ GPIO INTEGRATION-SPECIFIC DEFINITIONS ++******************************************************************************/ ++#define GPIO_NUM_OF_PORTS 1 /**< Number of ports in GPIO module; ++ Each port contains up to 32 i/O pins. */ ++ ++#define GPIO_VALID_PIN_MASKS \ ++ { /* Port A */ 0xFFFFFFFF } ++ ++#define GPIO_VALID_INTR_MASKS \ ++ { /* Port A */ 0xFFFFFFFF } ++ ++#endif /* __PART_INTEGRATION_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/math_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/math_ext.h +new file mode 100644 +index 00000000..4ecfc6ed +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/math_ext.h +@@ -0,0 +1,100 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#ifndef __MATH_EXT_H ++#define __MATH_EXT_H ++ ++ ++#if defined(NCSW_LINUX) && defined(__KERNEL__) ++#include ++#include ++ ++#elif defined(__MWERKS__) ++#define LOW(x) ( sizeof(x)==8 ? *(1+(int32_t*)&x) : (*(int32_t*)&x)) ++#define HIGH(x) (*(int32_t*)&x) ++#define ULOW(x) ( sizeof(x)==8 ? *(1+(uint32_t*)&x) : (*(uint32_t*)&x)) ++#define UHIGH(x) (*(uint32_t*)&x) ++ ++static const double big = 1.0e300; ++ ++/* Macro for checking if a number is a power of 2 */ ++static __inline__ double ceil(double x) ++{ ++ int32_t i0,i1,j0; /*- cc 020130 -*/ ++ uint32_t i,j; /*- cc 020130 -*/ ++ i0 = HIGH(x); ++ i1 = LOW(x); ++ j0 = ((i0>>20)&0x7ff)-0x3ff; ++ if(j0<20) { ++ if(j0<0) { /* raise inexact if x != 0 */ ++ if(big+x>0.0) {/* return 0*sign(x) if |x|<1 */ ++ if(i0<0) {i0=0x80000000;i1=0;} ++ else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;} ++ } ++ } else { ++ i = (uint32_t)(0x000fffff)>>j0; ++ if(((i0&i)|i1)==0) return x; /* x is integral */ ++ if(big+x>0.0) { /* raise inexact flag */ ++ if(i0>0) i0 += (0x00100000)>>j0; ++ i0 &= (~i); i1=0; ++ } ++ } ++ } else if (j0>51) { ++ if(j0==0x400) return x+x; /* inf or NaN */ ++ else return x; /* x is integral */ ++ } else { ++ i = ((uint32_t)(0xffffffff))>>(j0-20); /*- cc 020130 -*/ ++ if((i1&i)==0) return x; /* x is integral */ ++ if(big+x>0.0) { /* raise inexact flag */ ++ if(i0>0) { ++ if(j0==20) i0+=1; ++ else { ++ j = (uint32_t)(i1 + (1<<(52-j0))); ++ if(j ++#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */ ++ ++ ++#endif /* __MATH_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/ncsw_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/ncsw_ext.h +new file mode 100644 +index 00000000..dc32e249 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/ncsw_ext.h +@@ -0,0 +1,435 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File ncsw_ext.h ++ ++ @Description General NetCommSw Standard Definitions ++*//***************************************************************************/ ++ ++#ifndef __NCSW_EXT_H ++#define __NCSW_EXT_H ++ ++ ++#include "memcpy_ext.h" ++ ++#define WRITE_BLOCK IOMemSet32 /* include memcpy_ext.h */ ++#define COPY_BLOCK Mem2IOCpy32 /* include memcpy_ext.h */ ++ ++#define PTR_TO_UINT(_ptr) ((uintptr_t)(_ptr)) ++#define UINT_TO_PTR(_val) ((void*)(uintptr_t)(_val)) ++ ++#define PTR_MOVE(_ptr, _offset) (void*)((uint8_t*)(_ptr) + (_offset)) ++ ++ ++#define WRITE_UINT8_UINT24(arg, data08, data24) \ ++ WRITE_UINT32(arg,((uint32_t)(data08)<<24)|((uint32_t)(data24)&0x00FFFFFF)) ++#define WRITE_UINT24_UINT8(arg, data24, data08) \ ++ WRITE_UINT32(arg,((uint32_t)(data24)<< 8)|((uint32_t)(data08)&0x000000FF)) ++ ++/* Little-Endian access macros */ ++ ++#define WRITE_UINT16_LE(arg, data) \ ++ WRITE_UINT16((arg), SwapUint16(data)) ++ ++#define WRITE_UINT32_LE(arg, data) \ ++ WRITE_UINT32((arg), SwapUint32(data)) ++ ++#define WRITE_UINT64_LE(arg, data) \ ++ WRITE_UINT64((arg), SwapUint64(data)) ++ ++#define GET_UINT16_LE(arg) \ ++ SwapUint16(GET_UINT16(arg)) ++ ++#define GET_UINT32_LE(arg) \ ++ SwapUint32(GET_UINT32(arg)) ++ ++#define GET_UINT64_LE(arg) \ ++ SwapUint64(GET_UINT64(arg)) ++ ++/* Write and Read again macros */ ++#define WRITE_UINT_SYNC(size, arg, data) \ ++ do { \ ++ WRITE_UINT##size((arg), (data)); \ ++ CORE_MemoryBarrier(); \ ++ } while (0) ++ ++#define WRITE_UINT8_SYNC(arg, data) WRITE_UINT_SYNC(8, (arg), (data)) ++ ++#define WRITE_UINT16_SYNC(arg, data) WRITE_UINT_SYNC(16, (arg), (data)) ++#define WRITE_UINT32_SYNC(arg, data) WRITE_UINT_SYNC(32, (arg), (data)) ++ ++#define MAKE_UINT64(high32, low32) (((uint64_t)high32 << 32) | (low32)) ++ ++ ++/*----------------------*/ ++/* Miscellaneous macros */ ++/*----------------------*/ ++ ++#define UNUSED(_x) ((void)(_x)) ++ ++#define KILOBYTE 0x400UL /* 1024 */ ++#define MEGABYTE (KILOBYTE * KILOBYTE) /* 1024*1024 */ ++#define GIGABYTE ((uint64_t)(KILOBYTE * MEGABYTE)) /* 1024*1024*1024 */ ++#define TERABYTE ((uint64_t)(KILOBYTE * GIGABYTE)) /* 1024*1024*1024*1024 */ ++ ++#ifndef NO_IRQ ++#define NO_IRQ (0) ++#endif ++#define NCSW_MASTER_ID (0) ++ ++/* Macro for checking if a number is a power of 2 */ ++#define POWER_OF_2(n) (!((n) & ((n)-1))) ++ ++/* Macro for calculating log of base 2 */ ++#define LOG2(num, log2Num) \ ++ do \ ++ { \ ++ uint64_t tmp = (num); \ ++ log2Num = 0; \ ++ while (tmp > 1) \ ++ { \ ++ log2Num++; \ ++ tmp >>= 1; \ ++ } \ ++ } while (0) ++ ++#define NEXT_POWER_OF_2(_num, _nextPow) \ ++do \ ++{ \ ++ if (POWER_OF_2(_num)) \ ++ _nextPow = (_num); \ ++ else \ ++ { \ ++ uint64_t tmp = (_num); \ ++ _nextPow = 1; \ ++ while (tmp) \ ++ { \ ++ _nextPow <<= 1; \ ++ tmp >>= 1; \ ++ } \ ++ } \ ++} while (0) ++ ++/* Ceiling division - not the fastest way, but safer in terms of overflow */ ++#define DIV_CEIL(x,y) (div64_u64((x),(y)) + (((div64_u64((x),(y))*(y)) == (x)) ? 0 : 1)) ++ ++/* Round up a number to be a multiple of a second number */ ++#define ROUND_UP(x,y) ((((x) + (y) - 1) / (y)) * (y)) ++ ++/* Timing macro for converting usec units to number of ticks. */ ++/* (number of usec * clock_Hz) / 1,000,000) - since */ ++/* clk is in MHz units, no division needed. */ ++#define USEC_TO_CLK(usec,clk) ((usec) * (clk)) ++#define CYCLES_TO_USEC(cycles,clk) ((cycles) / (clk)) ++ ++/* Timing macros for converting between nsec units and number of clocks. */ ++#define NSEC_TO_CLK(nsec,clk) DIV_CEIL(((nsec) * (clk)), 1000) ++#define CYCLES_TO_NSEC(cycles,clk) (((cycles) * 1000) / (clk)) ++ ++/* Timing macros for converting between psec units and number of clocks. */ ++#define PSEC_TO_CLK(psec,clk) DIV_CEIL(((psec) * (clk)), 1000000) ++#define CYCLES_TO_PSEC(cycles,clk) (((cycles) * 1000000) / (clk)) ++ ++/* Min, Max macros */ ++#define MIN(a,b) ((a) < (b) ? (a) : (b)) ++#define MAX(a,b) ((a) > (b) ? (a) : (b)) ++#define IN_RANGE(min,val,max) ((min)<=(val) && (val)<=(max)) ++ ++#define ABS(a) ((a<0)?(a*-1):a) ++ ++#if !(defined(ARRAY_SIZE)) ++#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) ++#endif /* !defined(ARRAY_SIZE) */ ++ ++ ++/* possible alignments */ ++#define HALF_WORD_ALIGNMENT 2 ++#define WORD_ALIGNMENT 4 ++#define DOUBLE_WORD_ALIGNMENT 8 ++#define BURST_ALIGNMENT 32 ++ ++#define HALF_WORD_ALIGNED 0x00000001 ++#define WORD_ALIGNED 0x00000003 ++#define DOUBLE_WORD_ALIGNED 0x00000007 ++#define BURST_ALIGNED 0x0000001f ++#ifndef IS_ALIGNED ++#define IS_ALIGNED(n,align) (!((uint32_t)(n) & (align - 1))) ++#endif /* IS_ALIGNED */ ++ ++ ++#define LAST_BUF 1 ++#define FIRST_BUF 2 ++#define SINGLE_BUF (LAST_BUF | FIRST_BUF) ++#define MIDDLE_BUF 4 ++ ++#define ARRAY_END -1 ++ ++#define ILLEGAL_BASE (~0) ++ ++#define BUF_POSITION(first, last) state[(!!(last))<<1 | !!(first)] ++#define DECLARE_POSITION static uint8_t state[4] = { (uint8_t)MIDDLE_BUF, (uint8_t)FIRST_BUF, (uint8_t)LAST_BUF, (uint8_t)SINGLE_BUF }; ++ ++ ++/**************************************************************************//** ++ @Description Timers operation mode ++*//***************************************************************************/ ++typedef enum e_TimerMode ++{ ++ e_TIMER_MODE_INVALID = 0, ++ e_TIMER_MODE_FREE_RUN, /**< Free run - counter continues to increase ++ after reaching the reference value. */ ++ e_TIMER_MODE_PERIODIC, /**< Periodic - counter restarts counting from 0 ++ after reaching the reference value. */ ++ e_TIMER_MODE_SINGLE /**< Single (one-shot) - counter stops counting ++ after reaching the reference value. */ ++} e_TimerMode; ++ ++ ++/**************************************************************************//** ++ @Description Enumeration (bit flags) of communication modes (Transmit, ++ receive or both). ++*//***************************************************************************/ ++typedef enum e_CommMode ++{ ++ e_COMM_MODE_NONE = 0, /**< No transmit/receive communication */ ++ e_COMM_MODE_RX = 1, /**< Only receive communication */ ++ e_COMM_MODE_TX = 2, /**< Only transmit communication */ ++ e_COMM_MODE_RX_AND_TX = 3 /**< Both transmit and receive communication */ ++} e_CommMode; ++ ++/**************************************************************************//** ++ @Description General Diagnostic Mode ++*//***************************************************************************/ ++typedef enum e_DiagMode ++{ ++ e_DIAG_MODE_NONE = 0, /**< Normal operation; no diagnostic mode */ ++ e_DIAG_MODE_CTRL_LOOPBACK, /**< Loopback in the controller */ ++ e_DIAG_MODE_CHIP_LOOPBACK, /**< Loopback in the chip but not in the ++ controller; e.g. IO-pins, SerDes, etc. */ ++ e_DIAG_MODE_PHY_LOOPBACK, /**< Loopback in the external PHY */ ++ e_DIAG_MODE_EXT_LOOPBACK, /**< Loopback in the external line (beyond the PHY) */ ++ e_DIAG_MODE_CTRL_ECHO, /**< Echo incoming data by the controller */ ++ e_DIAG_MODE_PHY_ECHO /**< Echo incoming data by the PHY */ ++} e_DiagMode; ++ ++/**************************************************************************//** ++ @Description Possible RxStore callback responses. ++*//***************************************************************************/ ++typedef enum e_RxStoreResponse ++{ ++ e_RX_STORE_RESPONSE_PAUSE /**< Pause invoking callback with received data; ++ in polling mode, start again invoking callback ++ only next time user invokes the receive routine; ++ in interrupt mode, start again invoking callback ++ only next time a receive event triggers an interrupt; ++ in all cases, received data that are pending are not ++ lost, rather, their processing is temporarily deferred; ++ in all cases, received data are processed in the order ++ in which they were received. */ ++ , e_RX_STORE_RESPONSE_CONTINUE /**< Continue invoking callback with received data. */ ++} e_RxStoreResponse; ++ ++ ++/**************************************************************************//** ++ @Description General Handle ++*//***************************************************************************/ ++typedef void * t_Handle; /**< handle, used as object's descriptor */ ++ ++/**************************************************************************//** ++ @Description MUTEX type ++*//***************************************************************************/ ++typedef uint32_t t_Mutex; ++ ++/**************************************************************************//** ++ @Description Error Code. ++ ++ The high word of the error code is the code of the software ++ module (driver). The low word is the error type (e_ErrorType). ++ To get the values from the error code, use GET_ERROR_TYPE() ++ and GET_ERROR_MODULE(). ++*//***************************************************************************/ ++typedef uint32_t t_Error; ++ ++/**************************************************************************//** ++ @Description General prototype of interrupt service routine (ISR). ++ ++ @Param[in] handle - Optional handle of the module handling the interrupt. ++ ++ @Return None ++ *//***************************************************************************/ ++typedef void (t_Isr)(t_Handle handle); ++ ++/**************************************************************************//** ++ @Anchor mem_attr ++ ++ @Collection Memory Attributes ++ ++ Various attributes of memory partitions. These values may be ++ or'ed together to create a mask of all memory attributes. ++ @{ ++*//***************************************************************************/ ++#define MEMORY_ATTR_CACHEABLE 0x00000001 ++ /**< Memory is cacheable */ ++#define MEMORY_ATTR_QE_2ND_BUS_ACCESS 0x00000002 ++ /**< Memory can be accessed by QUICC Engine ++ through its secondary bus interface */ ++ ++/* @} */ ++ ++ ++/**************************************************************************//** ++ @Function t_GetBufFunction ++ ++ @Description User callback function called by driver to get data buffer. ++ ++ User provides this function. Driver invokes it. ++ ++ @Param[in] h_BufferPool - A handle to buffer pool manager ++ @Param[out] p_BufContextHandle - Returns the user's private context that ++ should be associated with the buffer ++ ++ @Return Pointer to data buffer, NULL if error ++ *//***************************************************************************/ ++typedef uint8_t * (t_GetBufFunction)(t_Handle h_BufferPool, ++ t_Handle *p_BufContextHandle); ++ ++/**************************************************************************//** ++ @Function t_PutBufFunction ++ ++ @Description User callback function called by driver to return data buffer. ++ ++ User provides this function. Driver invokes it. ++ ++ @Param[in] h_BufferPool - A handle to buffer pool manager ++ @Param[in] p_Buffer - A pointer to buffer to return ++ @Param[in] h_BufContext - The user's private context associated with ++ the returned buffer ++ ++ @Return E_OK on success; Error code otherwise ++ *//***************************************************************************/ ++typedef t_Error (t_PutBufFunction)(t_Handle h_BufferPool, ++ uint8_t *p_Buffer, ++ t_Handle h_BufContext); ++ ++/**************************************************************************//** ++ @Function t_PhysToVirt ++ ++ @Description Translates a physical address to the matching virtual address. ++ ++ @Param[in] addr - The physical address to translate. ++ ++ @Return Virtual address. ++*//***************************************************************************/ ++typedef void * t_PhysToVirt(physAddress_t addr); ++ ++/**************************************************************************//** ++ @Function t_VirtToPhys ++ ++ @Description Translates a virtual address to the matching physical address. ++ ++ @Param[in] addr - The virtual address to translate. ++ ++ @Return Physical address. ++*//***************************************************************************/ ++typedef physAddress_t t_VirtToPhys(void *addr); ++ ++/**************************************************************************//** ++ @Description Buffer Pool Information Structure. ++*//***************************************************************************/ ++typedef struct t_BufferPoolInfo ++{ ++ t_Handle h_BufferPool; /**< A handle to the buffer pool manager */ ++ t_GetBufFunction *f_GetBuf; /**< User callback to get a free buffer */ ++ t_PutBufFunction *f_PutBuf; /**< User callback to return a buffer */ ++ uint16_t bufferSize; /**< Buffer size (in bytes) */ ++ ++ t_PhysToVirt *f_PhysToVirt; /**< User callback to translate pool buffers ++ physical addresses to virtual addresses */ ++ t_VirtToPhys *f_VirtToPhys; /**< User callback to translate pool buffers ++ virtual addresses to physical addresses */ ++} t_BufferPoolInfo; ++ ++ ++/**************************************************************************//** ++ @Description User callback function called by driver when transmit completed. ++ ++ User provides this function. Driver invokes it. ++ ++ @Param[in] h_App - Application's handle, as was provided to the ++ driver by the user ++ @Param[in] queueId - Transmit queue ID ++ @Param[in] p_Data - Pointer to the data buffer ++ @Param[in] h_BufContext - The user's private context associated with ++ the given data buffer ++ @Param[in] status - Transmit status and errors ++ @Param[in] flags - Driver-dependent information ++ *//***************************************************************************/ ++typedef void (t_TxConfFunction)(t_Handle h_App, ++ uint32_t queueId, ++ uint8_t *p_Data, ++ t_Handle h_BufContext, ++ uint16_t status, ++ uint32_t flags); ++ ++/**************************************************************************//** ++ @Description User callback function called by driver with receive data. ++ ++ User provides this function. Driver invokes it. ++ ++ @Param[in] h_App - Application's handle, as was provided to the ++ driver by the user ++ @Param[in] queueId - Receive queue ID ++ @Param[in] p_Data - Pointer to the buffer with received data ++ @Param[in] h_BufContext - The user's private context associated with ++ the given data buffer ++ @Param[in] length - Length of received data ++ @Param[in] status - Receive status and errors ++ @Param[in] position - Position of buffer in frame ++ @Param[in] flags - Driver-dependent information ++ ++ @Retval e_RX_STORE_RESPONSE_CONTINUE - order the driver to continue Rx ++ operation for all ready data. ++ @Retval e_RX_STORE_RESPONSE_PAUSE - order the driver to stop Rx operation. ++ *//***************************************************************************/ ++typedef e_RxStoreResponse (t_RxStoreFunction)(t_Handle h_App, ++ uint32_t queueId, ++ uint8_t *p_Data, ++ t_Handle h_BufContext, ++ uint32_t length, ++ uint16_t status, ++ uint8_t position, ++ uint32_t flags); ++ ++ ++#endif /* __NCSW_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/net_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/net_ext.h +new file mode 100644 +index 00000000..8f3bc369 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/net_ext.h +@@ -0,0 +1,430 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File net_ext.h ++ ++ @Description This file contains common and general netcomm headers definitions. ++*//***************************************************************************/ ++#ifndef __NET_EXT_H ++#define __NET_EXT_H ++ ++#include "std_ext.h" ++ ++ ++typedef uint8_t headerFieldPpp_t; ++ ++#define NET_HEADER_FIELD_PPP_PID (1) ++#define NET_HEADER_FIELD_PPP_COMPRESSED (NET_HEADER_FIELD_PPP_PID << 1) ++#define NET_HEADER_FIELD_PPP_ALL_FIELDS ((NET_HEADER_FIELD_PPP_PID << 2) - 1) ++ ++ ++typedef uint8_t headerFieldPppoe_t; ++ ++#define NET_HEADER_FIELD_PPPoE_VER (1) ++#define NET_HEADER_FIELD_PPPoE_TYPE (NET_HEADER_FIELD_PPPoE_VER << 1) ++#define NET_HEADER_FIELD_PPPoE_CODE (NET_HEADER_FIELD_PPPoE_VER << 2) ++#define NET_HEADER_FIELD_PPPoE_SID (NET_HEADER_FIELD_PPPoE_VER << 3) ++#define NET_HEADER_FIELD_PPPoE_LEN (NET_HEADER_FIELD_PPPoE_VER << 4) ++#define NET_HEADER_FIELD_PPPoE_SESSION (NET_HEADER_FIELD_PPPoE_VER << 5) ++#define NET_HEADER_FIELD_PPPoE_PID (NET_HEADER_FIELD_PPPoE_VER << 6) ++#define NET_HEADER_FIELD_PPPoE_ALL_FIELDS ((NET_HEADER_FIELD_PPPoE_VER << 7) - 1) ++ ++#define NET_HEADER_FIELD_PPPMUX_PID (1) ++#define NET_HEADER_FIELD_PPPMUX_CKSUM (NET_HEADER_FIELD_PPPMUX_PID << 1) ++#define NET_HEADER_FIELD_PPPMUX_COMPRESSED (NET_HEADER_FIELD_PPPMUX_PID << 2) ++#define NET_HEADER_FIELD_PPPMUX_ALL_FIELDS ((NET_HEADER_FIELD_PPPMUX_PID << 3) - 1) ++ ++#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF (1) ++#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_LXT (NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 1) ++#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_LEN (NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 2) ++#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_PID (NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 3) ++#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_USE_PID (NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 4) ++#define NET_HEADER_FIELD_PPPMUX_SUBFRAME_ALL_FIELDS ((NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 5) - 1) ++ ++ ++typedef uint8_t headerFieldEth_t; ++ ++#define NET_HEADER_FIELD_ETH_DA (1) ++#define NET_HEADER_FIELD_ETH_SA (NET_HEADER_FIELD_ETH_DA << 1) ++#define NET_HEADER_FIELD_ETH_LENGTH (NET_HEADER_FIELD_ETH_DA << 2) ++#define NET_HEADER_FIELD_ETH_TYPE (NET_HEADER_FIELD_ETH_DA << 3) ++#define NET_HEADER_FIELD_ETH_FINAL_CKSUM (NET_HEADER_FIELD_ETH_DA << 4) ++#define NET_HEADER_FIELD_ETH_PADDING (NET_HEADER_FIELD_ETH_DA << 5) ++#define NET_HEADER_FIELD_ETH_ALL_FIELDS ((NET_HEADER_FIELD_ETH_DA << 6) - 1) ++ ++#define NET_HEADER_FIELD_ETH_ADDR_SIZE 6 ++ ++typedef uint16_t headerFieldIp_t; ++ ++#define NET_HEADER_FIELD_IP_VER (1) ++#define NET_HEADER_FIELD_IP_DSCP (NET_HEADER_FIELD_IP_VER << 2) ++#define NET_HEADER_FIELD_IP_ECN (NET_HEADER_FIELD_IP_VER << 3) ++#define NET_HEADER_FIELD_IP_PROTO (NET_HEADER_FIELD_IP_VER << 4) ++ ++#define NET_HEADER_FIELD_IP_PROTO_SIZE 1 ++ ++typedef uint16_t headerFieldIpv4_t; ++ ++#define NET_HEADER_FIELD_IPv4_VER (1) ++#define NET_HEADER_FIELD_IPv4_HDR_LEN (NET_HEADER_FIELD_IPv4_VER << 1) ++#define NET_HEADER_FIELD_IPv4_TOS (NET_HEADER_FIELD_IPv4_VER << 2) ++#define NET_HEADER_FIELD_IPv4_TOTAL_LEN (NET_HEADER_FIELD_IPv4_VER << 3) ++#define NET_HEADER_FIELD_IPv4_ID (NET_HEADER_FIELD_IPv4_VER << 4) ++#define NET_HEADER_FIELD_IPv4_FLAG_D (NET_HEADER_FIELD_IPv4_VER << 5) ++#define NET_HEADER_FIELD_IPv4_FLAG_M (NET_HEADER_FIELD_IPv4_VER << 6) ++#define NET_HEADER_FIELD_IPv4_OFFSET (NET_HEADER_FIELD_IPv4_VER << 7) ++#define NET_HEADER_FIELD_IPv4_TTL (NET_HEADER_FIELD_IPv4_VER << 8) ++#define NET_HEADER_FIELD_IPv4_PROTO (NET_HEADER_FIELD_IPv4_VER << 9) ++#define NET_HEADER_FIELD_IPv4_CKSUM (NET_HEADER_FIELD_IPv4_VER << 10) ++#define NET_HEADER_FIELD_IPv4_SRC_IP (NET_HEADER_FIELD_IPv4_VER << 11) ++#define NET_HEADER_FIELD_IPv4_DST_IP (NET_HEADER_FIELD_IPv4_VER << 12) ++#define NET_HEADER_FIELD_IPv4_OPTS (NET_HEADER_FIELD_IPv4_VER << 13) ++#define NET_HEADER_FIELD_IPv4_OPTS_COUNT (NET_HEADER_FIELD_IPv4_VER << 14) ++#define NET_HEADER_FIELD_IPv4_ALL_FIELDS ((NET_HEADER_FIELD_IPv4_VER << 15) - 1) ++ ++#define NET_HEADER_FIELD_IPv4_ADDR_SIZE 4 ++#define NET_HEADER_FIELD_IPv4_PROTO_SIZE 1 ++ ++ ++typedef uint8_t headerFieldIpv6_t; ++ ++#define NET_HEADER_FIELD_IPv6_VER (1) ++#define NET_HEADER_FIELD_IPv6_TC (NET_HEADER_FIELD_IPv6_VER << 1) ++#define NET_HEADER_FIELD_IPv6_SRC_IP (NET_HEADER_FIELD_IPv6_VER << 2) ++#define NET_HEADER_FIELD_IPv6_DST_IP (NET_HEADER_FIELD_IPv6_VER << 3) ++#define NET_HEADER_FIELD_IPv6_NEXT_HDR (NET_HEADER_FIELD_IPv6_VER << 4) ++#define NET_HEADER_FIELD_IPv6_FL (NET_HEADER_FIELD_IPv6_VER << 5) ++#define NET_HEADER_FIELD_IPv6_HOP_LIMIT (NET_HEADER_FIELD_IPv6_VER << 6) ++#define NET_HEADER_FIELD_IPv6_ALL_FIELDS ((NET_HEADER_FIELD_IPv6_VER << 7) - 1) ++ ++#define NET_HEADER_FIELD_IPv6_ADDR_SIZE 16 ++#define NET_HEADER_FIELD_IPv6_NEXT_HDR_SIZE 1 ++ ++#define NET_HEADER_FIELD_ICMP_TYPE (1) ++#define NET_HEADER_FIELD_ICMP_CODE (NET_HEADER_FIELD_ICMP_TYPE << 1) ++#define NET_HEADER_FIELD_ICMP_CKSUM (NET_HEADER_FIELD_ICMP_TYPE << 2) ++#define NET_HEADER_FIELD_ICMP_ID (NET_HEADER_FIELD_ICMP_TYPE << 3) ++#define NET_HEADER_FIELD_ICMP_SQ_NUM (NET_HEADER_FIELD_ICMP_TYPE << 4) ++#define NET_HEADER_FIELD_ICMP_ALL_FIELDS ((NET_HEADER_FIELD_ICMP_TYPE << 5) - 1) ++ ++#define NET_HEADER_FIELD_ICMP_CODE_SIZE 1 ++#define NET_HEADER_FIELD_ICMP_TYPE_SIZE 1 ++ ++#define NET_HEADER_FIELD_IGMP_VERSION (1) ++#define NET_HEADER_FIELD_IGMP_TYPE (NET_HEADER_FIELD_IGMP_VERSION << 1) ++#define NET_HEADER_FIELD_IGMP_CKSUM (NET_HEADER_FIELD_IGMP_VERSION << 2) ++#define NET_HEADER_FIELD_IGMP_DATA (NET_HEADER_FIELD_IGMP_VERSION << 3) ++#define NET_HEADER_FIELD_IGMP_ALL_FIELDS ((NET_HEADER_FIELD_IGMP_VERSION << 4) - 1) ++ ++ ++typedef uint16_t headerFieldTcp_t; ++ ++#define NET_HEADER_FIELD_TCP_PORT_SRC (1) ++#define NET_HEADER_FIELD_TCP_PORT_DST (NET_HEADER_FIELD_TCP_PORT_SRC << 1) ++#define NET_HEADER_FIELD_TCP_SEQ (NET_HEADER_FIELD_TCP_PORT_SRC << 2) ++#define NET_HEADER_FIELD_TCP_ACK (NET_HEADER_FIELD_TCP_PORT_SRC << 3) ++#define NET_HEADER_FIELD_TCP_OFFSET (NET_HEADER_FIELD_TCP_PORT_SRC << 4) ++#define NET_HEADER_FIELD_TCP_FLAGS (NET_HEADER_FIELD_TCP_PORT_SRC << 5) ++#define NET_HEADER_FIELD_TCP_WINDOW (NET_HEADER_FIELD_TCP_PORT_SRC << 6) ++#define NET_HEADER_FIELD_TCP_CKSUM (NET_HEADER_FIELD_TCP_PORT_SRC << 7) ++#define NET_HEADER_FIELD_TCP_URGPTR (NET_HEADER_FIELD_TCP_PORT_SRC << 8) ++#define NET_HEADER_FIELD_TCP_OPTS (NET_HEADER_FIELD_TCP_PORT_SRC << 9) ++#define NET_HEADER_FIELD_TCP_OPTS_COUNT (NET_HEADER_FIELD_TCP_PORT_SRC << 10) ++#define NET_HEADER_FIELD_TCP_ALL_FIELDS ((NET_HEADER_FIELD_TCP_PORT_SRC << 11) - 1) ++ ++#define NET_HEADER_FIELD_TCP_PORT_SIZE 2 ++ ++ ++typedef uint8_t headerFieldSctp_t; ++ ++#define NET_HEADER_FIELD_SCTP_PORT_SRC (1) ++#define NET_HEADER_FIELD_SCTP_PORT_DST (NET_HEADER_FIELD_SCTP_PORT_SRC << 1) ++#define NET_HEADER_FIELD_SCTP_VER_TAG (NET_HEADER_FIELD_SCTP_PORT_SRC << 2) ++#define NET_HEADER_FIELD_SCTP_CKSUM (NET_HEADER_FIELD_SCTP_PORT_SRC << 3) ++#define NET_HEADER_FIELD_SCTP_ALL_FIELDS ((NET_HEADER_FIELD_SCTP_PORT_SRC << 4) - 1) ++ ++#define NET_HEADER_FIELD_SCTP_PORT_SIZE 2 ++ ++typedef uint8_t headerFieldDccp_t; ++ ++#define NET_HEADER_FIELD_DCCP_PORT_SRC (1) ++#define NET_HEADER_FIELD_DCCP_PORT_DST (NET_HEADER_FIELD_DCCP_PORT_SRC << 1) ++#define NET_HEADER_FIELD_DCCP_ALL_FIELDS ((NET_HEADER_FIELD_DCCP_PORT_SRC << 2) - 1) ++ ++#define NET_HEADER_FIELD_DCCP_PORT_SIZE 2 ++ ++ ++typedef uint8_t headerFieldUdp_t; ++ ++#define NET_HEADER_FIELD_UDP_PORT_SRC (1) ++#define NET_HEADER_FIELD_UDP_PORT_DST (NET_HEADER_FIELD_UDP_PORT_SRC << 1) ++#define NET_HEADER_FIELD_UDP_LEN (NET_HEADER_FIELD_UDP_PORT_SRC << 2) ++#define NET_HEADER_FIELD_UDP_CKSUM (NET_HEADER_FIELD_UDP_PORT_SRC << 3) ++#define NET_HEADER_FIELD_UDP_ALL_FIELDS ((NET_HEADER_FIELD_UDP_PORT_SRC << 4) - 1) ++ ++#define NET_HEADER_FIELD_UDP_PORT_SIZE 2 ++ ++typedef uint8_t headerFieldUdpLite_t; ++ ++#define NET_HEADER_FIELD_UDP_LITE_PORT_SRC (1) ++#define NET_HEADER_FIELD_UDP_LITE_PORT_DST (NET_HEADER_FIELD_UDP_LITE_PORT_SRC << 1) ++#define NET_HEADER_FIELD_UDP_LITE_ALL_FIELDS ((NET_HEADER_FIELD_UDP_LITE_PORT_SRC << 2) - 1) ++ ++#define NET_HEADER_FIELD_UDP_LITE_PORT_SIZE 2 ++ ++typedef uint8_t headerFieldUdpEncapEsp_t; ++ ++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC (1) ++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 1) ++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 2) ++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 3) ++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 4) ++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM (NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 5) ++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_ALL_FIELDS ((NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 6) - 1) ++ ++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SIZE 2 ++#define NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI_SIZE 4 ++ ++#define NET_HEADER_FIELD_IPHC_CID (1) ++#define NET_HEADER_FIELD_IPHC_CID_TYPE (NET_HEADER_FIELD_IPHC_CID << 1) ++#define NET_HEADER_FIELD_IPHC_HCINDEX (NET_HEADER_FIELD_IPHC_CID << 2) ++#define NET_HEADER_FIELD_IPHC_GEN (NET_HEADER_FIELD_IPHC_CID << 3) ++#define NET_HEADER_FIELD_IPHC_D_BIT (NET_HEADER_FIELD_IPHC_CID << 4) ++#define NET_HEADER_FIELD_IPHC_ALL_FIELDS ((NET_HEADER_FIELD_IPHC_CID << 5) - 1) ++ ++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE (1) ++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_FLAGS (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 1) ++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_LENGTH (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 2) ++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_TSN (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 3) ++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_STREAM_ID (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 4) ++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_STREAM_SQN (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 5) ++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_PAYLOAD_PID (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 6) ++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_UNORDERED (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 7) ++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_BEGGINING (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 8) ++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_END (NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 9) ++#define NET_HEADER_FIELD_SCTP_CHUNK_DATA_ALL_FIELDS ((NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 10) - 1) ++ ++#define NET_HEADER_FIELD_L2TPv2_TYPE_BIT (1) ++#define NET_HEADER_FIELD_L2TPv2_LENGTH_BIT (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 1) ++#define NET_HEADER_FIELD_L2TPv2_SEQUENCE_BIT (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 2) ++#define NET_HEADER_FIELD_L2TPv2_OFFSET_BIT (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 3) ++#define NET_HEADER_FIELD_L2TPv2_PRIORITY_BIT (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 4) ++#define NET_HEADER_FIELD_L2TPv2_VERSION (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 5) ++#define NET_HEADER_FIELD_L2TPv2_LEN (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 6) ++#define NET_HEADER_FIELD_L2TPv2_TUNNEL_ID (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 7) ++#define NET_HEADER_FIELD_L2TPv2_SESSION_ID (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 8) ++#define NET_HEADER_FIELD_L2TPv2_NS (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 9) ++#define NET_HEADER_FIELD_L2TPv2_NR (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 10) ++#define NET_HEADER_FIELD_L2TPv2_OFFSET_SIZE (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 11) ++#define NET_HEADER_FIELD_L2TPv2_FIRST_BYTE (NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 12) ++#define NET_HEADER_FIELD_L2TPv2_ALL_FIELDS ((NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 13) - 1) ++ ++#define NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT (1) ++#define NET_HEADER_FIELD_L2TPv3_CTRL_LENGTH_BIT (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 1) ++#define NET_HEADER_FIELD_L2TPv3_CTRL_SEQUENCE_BIT (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 2) ++#define NET_HEADER_FIELD_L2TPv3_CTRL_VERSION (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 3) ++#define NET_HEADER_FIELD_L2TPv3_CTRL_LENGTH (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 4) ++#define NET_HEADER_FIELD_L2TPv3_CTRL_CONTROL (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 5) ++#define NET_HEADER_FIELD_L2TPv3_CTRL_SENT (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 6) ++#define NET_HEADER_FIELD_L2TPv3_CTRL_RECV (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 7) ++#define NET_HEADER_FIELD_L2TPv3_CTRL_FIRST_BYTE (NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 8) ++#define NET_HEADER_FIELD_L2TPv3_CTRL_ALL_FIELDS ((NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 9) - 1) ++ ++#define NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT (1) ++#define NET_HEADER_FIELD_L2TPv3_SESS_VERSION (NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 1) ++#define NET_HEADER_FIELD_L2TPv3_SESS_ID (NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 2) ++#define NET_HEADER_FIELD_L2TPv3_SESS_COOKIE (NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 3) ++#define NET_HEADER_FIELD_L2TPv3_SESS_ALL_FIELDS ((NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 4) - 1) ++ ++ ++typedef uint8_t headerFieldVlan_t; ++ ++#define NET_HEADER_FIELD_VLAN_VPRI (1) ++#define NET_HEADER_FIELD_VLAN_CFI (NET_HEADER_FIELD_VLAN_VPRI << 1) ++#define NET_HEADER_FIELD_VLAN_VID (NET_HEADER_FIELD_VLAN_VPRI << 2) ++#define NET_HEADER_FIELD_VLAN_LENGTH (NET_HEADER_FIELD_VLAN_VPRI << 3) ++#define NET_HEADER_FIELD_VLAN_TYPE (NET_HEADER_FIELD_VLAN_VPRI << 4) ++#define NET_HEADER_FIELD_VLAN_ALL_FIELDS ((NET_HEADER_FIELD_VLAN_VPRI << 5) - 1) ++ ++#define NET_HEADER_FIELD_VLAN_TCI (NET_HEADER_FIELD_VLAN_VPRI | \ ++ NET_HEADER_FIELD_VLAN_CFI | \ ++ NET_HEADER_FIELD_VLAN_VID) ++ ++ ++typedef uint8_t headerFieldLlc_t; ++ ++#define NET_HEADER_FIELD_LLC_DSAP (1) ++#define NET_HEADER_FIELD_LLC_SSAP (NET_HEADER_FIELD_LLC_DSAP << 1) ++#define NET_HEADER_FIELD_LLC_CTRL (NET_HEADER_FIELD_LLC_DSAP << 2) ++#define NET_HEADER_FIELD_LLC_ALL_FIELDS ((NET_HEADER_FIELD_LLC_DSAP << 3) - 1) ++ ++#define NET_HEADER_FIELD_NLPID_NLPID (1) ++#define NET_HEADER_FIELD_NLPID_ALL_FIELDS ((NET_HEADER_FIELD_NLPID_NLPID << 1) - 1) ++ ++ ++typedef uint8_t headerFieldSnap_t; ++ ++#define NET_HEADER_FIELD_SNAP_OUI (1) ++#define NET_HEADER_FIELD_SNAP_PID (NET_HEADER_FIELD_SNAP_OUI << 1) ++#define NET_HEADER_FIELD_SNAP_ALL_FIELDS ((NET_HEADER_FIELD_SNAP_OUI << 2) - 1) ++ ++ ++typedef uint8_t headerFieldLlcSnap_t; ++ ++#define NET_HEADER_FIELD_LLC_SNAP_TYPE (1) ++#define NET_HEADER_FIELD_LLC_SNAP_ALL_FIELDS ((NET_HEADER_FIELD_LLC_SNAP_TYPE << 1) - 1) ++ ++#define NET_HEADER_FIELD_ARP_HTYPE (1) ++#define NET_HEADER_FIELD_ARP_PTYPE (NET_HEADER_FIELD_ARP_HTYPE << 1) ++#define NET_HEADER_FIELD_ARP_HLEN (NET_HEADER_FIELD_ARP_HTYPE << 2) ++#define NET_HEADER_FIELD_ARP_PLEN (NET_HEADER_FIELD_ARP_HTYPE << 3) ++#define NET_HEADER_FIELD_ARP_OPER (NET_HEADER_FIELD_ARP_HTYPE << 4) ++#define NET_HEADER_FIELD_ARP_SHA (NET_HEADER_FIELD_ARP_HTYPE << 5) ++#define NET_HEADER_FIELD_ARP_SPA (NET_HEADER_FIELD_ARP_HTYPE << 6) ++#define NET_HEADER_FIELD_ARP_THA (NET_HEADER_FIELD_ARP_HTYPE << 7) ++#define NET_HEADER_FIELD_ARP_TPA (NET_HEADER_FIELD_ARP_HTYPE << 8) ++#define NET_HEADER_FIELD_ARP_ALL_FIELDS ((NET_HEADER_FIELD_ARP_HTYPE << 9) - 1) ++ ++#define NET_HEADER_FIELD_RFC2684_LLC (1) ++#define NET_HEADER_FIELD_RFC2684_NLPID (NET_HEADER_FIELD_RFC2684_LLC << 1) ++#define NET_HEADER_FIELD_RFC2684_OUI (NET_HEADER_FIELD_RFC2684_LLC << 2) ++#define NET_HEADER_FIELD_RFC2684_PID (NET_HEADER_FIELD_RFC2684_LLC << 3) ++#define NET_HEADER_FIELD_RFC2684_VPN_OUI (NET_HEADER_FIELD_RFC2684_LLC << 4) ++#define NET_HEADER_FIELD_RFC2684_VPN_IDX (NET_HEADER_FIELD_RFC2684_LLC << 5) ++#define NET_HEADER_FIELD_RFC2684_ALL_FIELDS ((NET_HEADER_FIELD_RFC2684_LLC << 6) - 1) ++ ++#define NET_HEADER_FIELD_USER_DEFINED_SRCPORT (1) ++#define NET_HEADER_FIELD_USER_DEFINED_PCDID (NET_HEADER_FIELD_USER_DEFINED_SRCPORT << 1) ++#define NET_HEADER_FIELD_USER_DEFINED_ALL_FIELDS ((NET_HEADER_FIELD_USER_DEFINED_SRCPORT << 2) - 1) ++ ++#define NET_HEADER_FIELD_PAYLOAD_BUFFER (1) ++#define NET_HEADER_FIELD_PAYLOAD_SIZE (NET_HEADER_FIELD_PAYLOAD_BUFFER << 1) ++#define NET_HEADER_FIELD_MAX_FRM_SIZE (NET_HEADER_FIELD_PAYLOAD_BUFFER << 2) ++#define NET_HEADER_FIELD_MIN_FRM_SIZE (NET_HEADER_FIELD_PAYLOAD_BUFFER << 3) ++#define NET_HEADER_FIELD_PAYLOAD_TYPE (NET_HEADER_FIELD_PAYLOAD_BUFFER << 4) ++#define NET_HEADER_FIELD_FRAME_SIZE (NET_HEADER_FIELD_PAYLOAD_BUFFER << 5) ++#define NET_HEADER_FIELD_PAYLOAD_ALL_FIELDS ((NET_HEADER_FIELD_PAYLOAD_BUFFER << 6) - 1) ++ ++ ++typedef uint8_t headerFieldGre_t; ++ ++#define NET_HEADER_FIELD_GRE_TYPE (1) ++#define NET_HEADER_FIELD_GRE_ALL_FIELDS ((NET_HEADER_FIELD_GRE_TYPE << 1) - 1) ++ ++ ++typedef uint8_t headerFieldMinencap_t; ++ ++#define NET_HEADER_FIELD_MINENCAP_SRC_IP (1) ++#define NET_HEADER_FIELD_MINENCAP_DST_IP (NET_HEADER_FIELD_MINENCAP_SRC_IP << 1) ++#define NET_HEADER_FIELD_MINENCAP_TYPE (NET_HEADER_FIELD_MINENCAP_SRC_IP << 2) ++#define NET_HEADER_FIELD_MINENCAP_ALL_FIELDS ((NET_HEADER_FIELD_MINENCAP_SRC_IP << 3) - 1) ++ ++ ++typedef uint8_t headerFieldIpsecAh_t; ++ ++#define NET_HEADER_FIELD_IPSEC_AH_SPI (1) ++#define NET_HEADER_FIELD_IPSEC_AH_NH (NET_HEADER_FIELD_IPSEC_AH_SPI << 1) ++#define NET_HEADER_FIELD_IPSEC_AH_ALL_FIELDS ((NET_HEADER_FIELD_IPSEC_AH_SPI << 2) - 1) ++ ++ ++typedef uint8_t headerFieldIpsecEsp_t; ++ ++#define NET_HEADER_FIELD_IPSEC_ESP_SPI (1) ++#define NET_HEADER_FIELD_IPSEC_ESP_SEQUENCE_NUM (NET_HEADER_FIELD_IPSEC_ESP_SPI << 1) ++#define NET_HEADER_FIELD_IPSEC_ESP_ALL_FIELDS ((NET_HEADER_FIELD_IPSEC_ESP_SPI << 2) - 1) ++ ++#define NET_HEADER_FIELD_IPSEC_ESP_SPI_SIZE 4 ++ ++ ++typedef uint8_t headerFieldMpls_t; ++ ++#define NET_HEADER_FIELD_MPLS_LABEL_STACK (1) ++#define NET_HEADER_FIELD_MPLS_LABEL_STACK_ALL_FIELDS ((NET_HEADER_FIELD_MPLS_LABEL_STACK << 1) - 1) ++ ++ ++typedef uint8_t headerFieldMacsec_t; ++ ++#define NET_HEADER_FIELD_MACSEC_SECTAG (1) ++#define NET_HEADER_FIELD_MACSEC_ALL_FIELDS ((NET_HEADER_FIELD_MACSEC_SECTAG << 1) - 1) ++ ++ ++typedef enum { ++ HEADER_TYPE_NONE = 0, ++ HEADER_TYPE_PAYLOAD, ++ HEADER_TYPE_ETH, ++ HEADER_TYPE_VLAN, ++ HEADER_TYPE_IPv4, ++ HEADER_TYPE_IPv6, ++ HEADER_TYPE_IP, ++ HEADER_TYPE_TCP, ++ HEADER_TYPE_UDP, ++ HEADER_TYPE_UDP_LITE, ++ HEADER_TYPE_IPHC, ++ HEADER_TYPE_SCTP, ++ HEADER_TYPE_SCTP_CHUNK_DATA, ++ HEADER_TYPE_PPPoE, ++ HEADER_TYPE_PPP, ++ HEADER_TYPE_PPPMUX, ++ HEADER_TYPE_PPPMUX_SUBFRAME, ++ HEADER_TYPE_L2TPv2, ++ HEADER_TYPE_L2TPv3_CTRL, ++ HEADER_TYPE_L2TPv3_SESS, ++ HEADER_TYPE_LLC, ++ HEADER_TYPE_LLC_SNAP, ++ HEADER_TYPE_NLPID, ++ HEADER_TYPE_SNAP, ++ HEADER_TYPE_MPLS, ++ HEADER_TYPE_IPSEC_AH, ++ HEADER_TYPE_IPSEC_ESP, ++ HEADER_TYPE_UDP_ENCAP_ESP, /* RFC 3948 */ ++ HEADER_TYPE_MACSEC, ++ HEADER_TYPE_GRE, ++ HEADER_TYPE_MINENCAP, ++ HEADER_TYPE_DCCP, ++ HEADER_TYPE_ICMP, ++ HEADER_TYPE_IGMP, ++ HEADER_TYPE_ARP, ++ HEADER_TYPE_CAPWAP, ++ HEADER_TYPE_CAPWAP_DTLS, ++ HEADER_TYPE_RFC2684, ++ HEADER_TYPE_USER_DEFINED_L2, ++ HEADER_TYPE_USER_DEFINED_L3, ++ HEADER_TYPE_USER_DEFINED_L4, ++ HEADER_TYPE_USER_DEFINED_SHIM1, ++ HEADER_TYPE_USER_DEFINED_SHIM2, ++ MAX_HEADER_TYPE_COUNT ++} e_NetHeaderType; ++ ++ ++#endif /* __NET_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/std_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/std_ext.h +new file mode 100644 +index 00000000..d91e6fdd +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/std_ext.h +@@ -0,0 +1,48 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File std_ext.h ++ ++ @Description General Standard Definitions ++*//***************************************************************************/ ++ ++#ifndef __STD_EXT_H ++#define __STD_EXT_H ++ ++ ++#include "types_ext.h" ++#include "ncsw_ext.h" ++ ++ ++#endif /* __STD_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/stdarg_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/stdarg_ext.h +new file mode 100644 +index 00000000..3c8bb0a0 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/stdarg_ext.h +@@ -0,0 +1,49 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#ifndef __STDARG_EXT_H ++#define __STDARG_EXT_H ++ ++ ++#if defined(NCSW_LINUX) && defined(__KERNEL__) ++#include ++ ++#else ++#include ++ ++#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */ ++ ++#include "std_ext.h" ++ ++ ++#endif /* __STDARG_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/stdlib_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/stdlib_ext.h +new file mode 100644 +index 00000000..a47860cf +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/stdlib_ext.h +@@ -0,0 +1,162 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++ ++#ifndef __STDLIB_EXT_H ++#define __STDLIB_EXT_H ++ ++ ++#if (defined(NCSW_LINUX)) && defined(__KERNEL__) ++#include "stdarg_ext.h" ++#include "std_ext.h" ++ ++ ++/** ++ * strtoul - convert a string to an uint32_t ++ * @cp: The start of the string ++ * @endp: A pointer to the end of the parsed string will be placed here ++ * @base: The number base to use ++ */ ++uint32_t strtoul(const char *cp,char **endp,uint32_t base); ++ ++/** ++ * strtol - convert a string to a int32_t ++ * @cp: The start of the string ++ * @endp: A pointer to the end of the parsed string will be placed here ++ * @base: The number base to use ++ */ ++long strtol(const char *cp,char **endp,uint32_t base); ++ ++/** ++ * strtoull - convert a string to an uint64_t ++ * @cp: The start of the string ++ * @endp: A pointer to the end of the parsed string will be placed here ++ * @base: The number base to use ++ */ ++uint64_t strtoull(const char *cp,char **endp,uint32_t base); ++ ++/** ++ * strtoll - convert a string to a int64 long ++ * @cp: The start of the string ++ * @endp: A pointer to the end of the parsed string will be placed here ++ * @base: The number base to use ++ */ ++long long strtoll(const char *cp,char **endp,uint32_t base); ++ ++/** ++ * atoi - convert a character to a int ++ * @s: The start of the string ++ */ ++int atoi(const char *s); ++ ++/** ++ * strnlen - Find the length of a length-limited string ++ * @s: The string to be sized ++ * @count: The maximum number of bytes to search ++ */ ++size_t strnlen(const char * s, size_t count); ++ ++/** ++ * strlen - Find the length of a string ++ * @s: The string to be sized ++ */ ++size_t strlen(const char * s); ++ ++/** ++ * strtok - Split a string into tokens ++ * @s: The string to be searched ++ * @ct: The characters to search for ++ * ++ * WARNING: strtok is deprecated, use strsep instead. ++ */ ++char * strtok(char * s,const char * ct); ++ ++/** ++ * strncpy - Copy a length-limited, %NUL-terminated string ++ * @dest: Where to copy the string to ++ * @src: Where to copy the string from ++ * @count: The maximum number of bytes to copy ++ * ++ * Note that unlike userspace strncpy, this does not %NUL-pad the buffer. ++ * However, the result is not %NUL-terminated if the source exceeds ++ * @count bytes. ++ */ ++char * strncpy(char * dest,const char *src,size_t count); ++ ++/** ++ * strcpy - Copy a %NUL terminated string ++ * @dest: Where to copy the string to ++ * @src: Where to copy the string from ++ */ ++char * strcpy(char * dest,const char *src); ++ ++/** ++ * vsscanf - Unformat a buffer into a list of arguments ++ * @buf: input buffer ++ * @fmt: format of buffer ++ * @args: arguments ++ */ ++int vsscanf(const char * buf, const char * fmt, va_list args); ++ ++/** ++ * vsnprintf - Format a string and place it in a buffer ++ * @buf: The buffer to place the result into ++ * @size: The size of the buffer, including the trailing null space ++ * @fmt: The format string to use ++ * @args: Arguments for the format string ++ * ++ * Call this function if you are already dealing with a va_list. ++ * You probably want snprintf instead. ++ */ ++int vsnprintf(char *buf, size_t size, const char *fmt, va_list args); ++ ++/** ++ * vsprintf - Format a string and place it in a buffer ++ * @buf: The buffer to place the result into ++ * @fmt: The format string to use ++ * @args: Arguments for the format string ++ * ++ * Call this function if you are already dealing with a va_list. ++ * You probably want sprintf instead. ++ */ ++int vsprintf(char *buf, const char *fmt, va_list args); ++ ++#else ++#include ++#include ++#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */ ++ ++#include "std_ext.h" ++ ++ ++#endif /* __STDLIB_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/string_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/string_ext.h +new file mode 100644 +index 00000000..a5c6c7e0 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/string_ext.h +@@ -0,0 +1,56 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#ifndef __STRING_EXT_H ++#define __STRING_EXT_H ++ ++ ++#if defined(NCSW_LINUX) && defined(__KERNEL__) ++#include ++#include ++extern char * strtok ( char * str, const char * delimiters ); ++ ++#elif defined(__KERNEL__) ++#include "linux/types.h" ++#include "linux/posix_types.h" ++#include "linux/string.h" ++ ++#else ++#include ++ ++#endif /* defined(NCSW_LINUX) && defined(__KERNEL__) */ ++ ++#include "std_ext.h" ++ ++ ++#endif /* __STRING_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/types_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/types_ext.h +new file mode 100644 +index 00000000..8c87edb7 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/types_ext.h +@@ -0,0 +1,62 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File types_ext.h ++ ++ @Description General types Standard Definitions ++*//***************************************************************************/ ++ ++#ifndef __TYPES_EXT_H ++#define __TYPES_EXT_H ++ ++#if defined(NCSW_LINUX) ++#include "types_linux.h" ++ ++#elif defined(NCSW_VXWORKS) ++#include "types_vxworks.h" ++ ++#elif defined(__GNUC__) && defined(__cplusplus) ++#include "types_bb_gpp.h" ++ ++#elif defined(__GNUC__) ++#include "types_bb_gcc.h" ++ ++#elif defined(__ghs__) ++#include "types_ghs.h" ++ ++#else ++#include "types_dflt.h" ++#endif /* defined (__ROCOO__) */ ++ ++#endif /* __TYPES_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/xx_common.h b/drivers/net/ethernet/freescale/sdk_fman/inc/xx_common.h +new file mode 100644 +index 00000000..8e81094b +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/xx_common.h +@@ -0,0 +1,56 @@ ++/* ++ * Copyright 2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File debug_ext.h ++ ++ @Description Debug mode definitions. ++*//***************************************************************************/ ++ ++#ifndef __XX_COMMON_H ++#define __XX_COMMON_H ++ ++/***************************************************************************** ++ * UNIFIED MODULE CODES ++ *****************************************************************************/ ++#define MODULE_UNKNOWN 0x00000000 ++#define MODULE_FM 0x00010000 ++#define MODULE_FM_MURAM 0x00020000 ++#define MODULE_FM_PCD 0x00030000 ++#define MODULE_FM_RTC 0x00040000 ++#define MODULE_FM_MAC 0x00050000 ++#define MODULE_FM_PORT 0x00060000 ++#define MODULE_MM 0x00070000 ++#define MODULE_FM_SP 0x00080000 ++#define MODULE_FM_MACSEC 0x00090000 ++#endif /* __XX_COMMON_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/inc/xx_ext.h b/drivers/net/ethernet/freescale/sdk_fman/inc/xx_ext.h +new file mode 100644 +index 00000000..21b62d0a +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/inc/xx_ext.h +@@ -0,0 +1,791 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File xx_ext.h ++ ++ @Description Prototypes, externals and typedefs for system-supplied ++ (external) routines ++*//***************************************************************************/ ++ ++#ifndef __XX_EXT_H ++#define __XX_EXT_H ++ ++#include "std_ext.h" ++#include "xx_common.h" ++#include "part_ext.h" ++ ++ ++ ++/**************************************************************************//** ++ @Group xx_id XX Interface (System call hooks) ++ ++ @Description Prototypes, externals and typedefs for system-supplied ++ (external) routines ++ ++ @{ ++*//***************************************************************************/ ++ ++#ifdef DEBUG_XX_MALLOC ++void * XX_MallocDebug(uint32_t size, char *fname, int line); ++ ++void * XX_MallocSmartDebug(uint32_t size, ++ int memPartitionId, ++ uint32_t alignment, ++ char *fname, ++ int line); ++ ++#define XX_Malloc(sz) \ ++ XX_MallocDebug((sz), __FILE__, __LINE__) ++ ++#define XX_MallocSmart(sz, memt, al) \ ++ XX_MallocSmartDebug((sz), (memt), (al), __FILE__, __LINE__) ++ ++#else /* not DEBUG_XX_MALLOC */ ++/**************************************************************************//** ++ @Function XX_Malloc ++ ++ @Description allocates contiguous block of memory. ++ ++ @Param[in] size - Number of bytes to allocate. ++ ++ @Return The address of the newly allocated block on success, NULL on failure. ++*//***************************************************************************/ ++void * XX_Malloc(uint32_t size); ++ ++/**************************************************************************//** ++ @Function XX_MallocSmart ++ ++ @Description Allocates contiguous block of memory in a specified ++ alignment and from the specified segment. ++ ++ @Param[in] size - Number of bytes to allocate. ++ @Param[in] memPartitionId - Memory partition ID; The value zero must ++ be mapped to the default heap partition. ++ @Param[in] alignment - Required memory alignment (in bytes). ++ ++ @Return The address of the newly allocated block on success, NULL on failure. ++*//***************************************************************************/ ++void * XX_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment); ++#endif /* not DEBUG_XX_MALLOC */ ++ ++/**************************************************************************//** ++ @Function XX_FreeSmart ++ ++ @Description Frees the memory block pointed to by "p". ++ Only for memory allocated by XX_MallocSmart ++ ++ @Param[in] p_Memory - pointer to the memory block. ++ ++ @Return None. ++*//***************************************************************************/ ++void XX_FreeSmart(void *p_Memory); ++ ++/**************************************************************************//** ++ @Function XX_Free ++ ++ @Description frees the memory block pointed to by "p". ++ ++ @Param[in] p_Memory - pointer to the memory block. ++ ++ @Return None. ++*//***************************************************************************/ ++void XX_Free(void *p_Memory); ++ ++/**************************************************************************//** ++ @Function XX_Print ++ ++ @Description print a string. ++ ++ @Param[in] str - string to print. ++ ++ @Return None. ++*//***************************************************************************/ ++void XX_Print(char *str, ...); ++ ++/**************************************************************************//** ++ @Function XX_SetIntr ++ ++ @Description Set an interrupt service routine for a specific interrupt source. ++ ++ @Param[in] irq - Interrupt ID (system-specific number). ++ @Param[in] f_Isr - Callback routine that will be called when the interrupt occurs. ++ @Param[in] handle - The argument for the user callback routine. ++ ++ @Return E_OK on success; error code otherwise.. ++*//***************************************************************************/ ++t_Error XX_SetIntr(int irq, t_Isr *f_Isr, t_Handle handle); ++ ++/**************************************************************************//** ++ @Function XX_FreeIntr ++ ++ @Description Free a specific interrupt and a specific callback routine. ++ ++ @Param[in] irq - Interrupt ID (system-specific number). ++ ++ @Return E_OK on success; error code otherwise.. ++*//***************************************************************************/ ++t_Error XX_FreeIntr(int irq); ++ ++/**************************************************************************//** ++ @Function XX_EnableIntr ++ ++ @Description Enable a specific interrupt. ++ ++ @Param[in] irq - Interrupt ID (system-specific number). ++ ++ @Return E_OK on success; error code otherwise.. ++*//***************************************************************************/ ++t_Error XX_EnableIntr(int irq); ++ ++/**************************************************************************//** ++ @Function XX_DisableIntr ++ ++ @Description Disable a specific interrupt. ++ ++ @Param[in] irq - Interrupt ID (system-specific number). ++ ++ @Return E_OK on success; error code otherwise.. ++*//***************************************************************************/ ++t_Error XX_DisableIntr(int irq); ++ ++/**************************************************************************//** ++ @Function XX_DisableAllIntr ++ ++ @Description Disable all interrupts by masking them at the CPU. ++ ++ @Return A value that represents the interrupts state before the ++ operation, and should be passed to the matching ++ XX_RestoreAllIntr() call. ++*//***************************************************************************/ ++uint32_t XX_DisableAllIntr(void); ++ ++/**************************************************************************//** ++ @Function XX_RestoreAllIntr ++ ++ @Description Restore previous state of interrupts level at the CPU. ++ ++ @Param[in] flags - A value that represents the interrupts state to restore, ++ as returned by the matching call for XX_DisableAllIntr(). ++ ++ @Return None. ++*//***************************************************************************/ ++void XX_RestoreAllIntr(uint32_t flags); ++ ++ ++/**************************************************************************//** ++ @Function XX_Exit ++ ++ @Description Stop execution and report status (where it is applicable) ++ ++ @Param[in] status - exit status ++*//***************************************************************************/ ++void XX_Exit(int status); ++ ++ ++/*****************************************************************************/ ++/* Tasklet Service Routines */ ++/*****************************************************************************/ ++typedef t_Handle t_TaskletHandle; ++ ++/**************************************************************************//** ++ @Function XX_InitTasklet ++ ++ @Description Create and initialize a tasklet object. ++ ++ @Param[in] routine - A routine to be ran as a tasklet. ++ @Param[in] data - An argument to pass to the tasklet. ++ ++ @Return Tasklet handle is returned on success. NULL is returned otherwise. ++*//***************************************************************************/ ++t_TaskletHandle XX_InitTasklet (void (*routine)(void *), void *data); ++ ++/**************************************************************************//** ++ @Function XX_FreeTasklet ++ ++ @Description Free a tasklet object. ++ ++ @Param[in] h_Tasklet - A handle to a tasklet to be free. ++ ++ @Return None. ++*//***************************************************************************/ ++void XX_FreeTasklet (t_TaskletHandle h_Tasklet); ++ ++/**************************************************************************//** ++ @Function XX_ScheduleTask ++ ++ @Description Schedule a tasklet object. ++ ++ @Param[in] h_Tasklet - A handle to a tasklet to be scheduled. ++ @Param[in] immediate - Indicate whether to schedule this tasklet on ++ the immediate queue or on the delayed one. ++ ++ @Return 0 - on success. Error code - otherwise. ++*//***************************************************************************/ ++int XX_ScheduleTask(t_TaskletHandle h_Tasklet, int immediate); ++ ++/**************************************************************************//** ++ @Function XX_FlushScheduledTasks ++ ++ @Description Flush all tasks there are in the scheduled tasks queue. ++ ++ @Return None. ++*//***************************************************************************/ ++void XX_FlushScheduledTasks(void); ++ ++/**************************************************************************//** ++ @Function XX_TaskletIsQueued ++ ++ @Description Check if task is queued. ++ ++ @Param[in] h_Tasklet - A handle to a tasklet to be scheduled. ++ ++ @Return 1 - task is queued. 0 - otherwise. ++*//***************************************************************************/ ++int XX_TaskletIsQueued(t_TaskletHandle h_Tasklet); ++ ++/**************************************************************************//** ++ @Function XX_SetTaskletData ++ ++ @Description Set data to a scheduled task. Used to change data of already ++ scheduled task. ++ ++ @Param[in] h_Tasklet - A handle to a tasklet to be scheduled. ++ @Param[in] data - Data to be set. ++*//***************************************************************************/ ++void XX_SetTaskletData(t_TaskletHandle h_Tasklet, t_Handle data); ++ ++/**************************************************************************//** ++ @Function XX_GetTaskletData ++ ++ @Description Get the data of scheduled task. ++ ++ @Param[in] h_Tasklet - A handle to a tasklet to be scheduled. ++ ++ @Return handle to the data of the task. ++*//***************************************************************************/ ++t_Handle XX_GetTaskletData(t_TaskletHandle h_Tasklet); ++ ++/**************************************************************************//** ++ @Function XX_BottomHalf ++ ++ @Description Bottom half implementation, invoked by the interrupt handler. ++ ++ This routine handles all bottom-half tasklets with interrupts ++ enabled. ++ ++ @Return None. ++*//***************************************************************************/ ++void XX_BottomHalf(void); ++ ++ ++/*****************************************************************************/ ++/* Spinlock Service Routines */ ++/*****************************************************************************/ ++ ++/**************************************************************************//** ++ @Function XX_InitSpinlock ++ ++ @Description Creates a spinlock. ++ ++ @Return Spinlock handle is returned on success; NULL otherwise. ++*//***************************************************************************/ ++t_Handle XX_InitSpinlock(void); ++ ++/**************************************************************************//** ++ @Function XX_FreeSpinlock ++ ++ @Description Frees the memory allocated for the spinlock creation. ++ ++ @Param[in] h_Spinlock - A handle to a spinlock. ++ ++ @Return None. ++*//***************************************************************************/ ++void XX_FreeSpinlock(t_Handle h_Spinlock); ++ ++/**************************************************************************//** ++ @Function XX_LockSpinlock ++ ++ @Description Locks a spinlock. ++ ++ @Param[in] h_Spinlock - A handle to a spinlock. ++ ++ @Return None. ++*//***************************************************************************/ ++void XX_LockSpinlock(t_Handle h_Spinlock); ++ ++/**************************************************************************//** ++ @Function XX_UnlockSpinlock ++ ++ @Description Unlocks a spinlock. ++ ++ @Param[in] h_Spinlock - A handle to a spinlock. ++ ++ @Return None. ++*//***************************************************************************/ ++void XX_UnlockSpinlock(t_Handle h_Spinlock); ++ ++/**************************************************************************//** ++ @Function XX_LockIntrSpinlock ++ ++ @Description Locks a spinlock (interrupt safe). ++ ++ @Param[in] h_Spinlock - A handle to a spinlock. ++ ++ @Return A value that represents the interrupts state before the ++ operation, and should be passed to the matching ++ XX_UnlockIntrSpinlock() call. ++*//***************************************************************************/ ++uint32_t XX_LockIntrSpinlock(t_Handle h_Spinlock); ++ ++/**************************************************************************//** ++ @Function XX_UnlockIntrSpinlock ++ ++ @Description Unlocks a spinlock (interrupt safe). ++ ++ @Param[in] h_Spinlock - A handle to a spinlock. ++ @Param[in] intrFlags - A value that represents the interrupts state to ++ restore, as returned by the matching call for ++ XX_LockIntrSpinlock(). ++ ++ @Return None. ++*//***************************************************************************/ ++void XX_UnlockIntrSpinlock(t_Handle h_Spinlock, uint32_t intrFlags); ++ ++ ++/*****************************************************************************/ ++/* Timers Service Routines */ ++/*****************************************************************************/ ++ ++/**************************************************************************//** ++ @Function XX_CurrentTime ++ ++ @Description Returns current system time. ++ ++ @Return Current system time (in milliseconds). ++*//***************************************************************************/ ++uint32_t XX_CurrentTime(void); ++ ++/**************************************************************************//** ++ @Function XX_CreateTimer ++ ++ @Description Creates a timer. ++ ++ @Return Timer handle is returned on success; NULL otherwise. ++*//***************************************************************************/ ++t_Handle XX_CreateTimer(void); ++ ++/**************************************************************************//** ++ @Function XX_FreeTimer ++ ++ @Description Frees the memory allocated for the timer creation. ++ ++ @Param[in] h_Timer - A handle to a timer. ++ ++ @Return None. ++*//***************************************************************************/ ++void XX_FreeTimer(t_Handle h_Timer); ++ ++/**************************************************************************//** ++ @Function XX_StartTimer ++ ++ @Description Starts a timer. ++ ++ The user can select to start the timer as periodic timer or as ++ one-shot timer. The user should provide a callback routine that ++ will be called when the timer expires. ++ ++ @Param[in] h_Timer - A handle to a timer. ++ @Param[in] msecs - Timer expiration period (in milliseconds). ++ @Param[in] periodic - TRUE for a periodic timer; ++ FALSE for a one-shot timer.. ++ @Param[in] f_TimerExpired - A callback routine to be called when the ++ timer expires. ++ @Param[in] h_Arg - The argument to pass in the timer-expired ++ callback routine. ++ ++ @Return None. ++*//***************************************************************************/ ++void XX_StartTimer(t_Handle h_Timer, ++ uint32_t msecs, ++ bool periodic, ++ void (*f_TimerExpired)(t_Handle h_Arg), ++ t_Handle h_Arg); ++ ++/**************************************************************************//** ++ @Function XX_StopTimer ++ ++ @Description Frees the memory allocated for the timer creation. ++ ++ @Param[in] h_Timer - A handle to a timer. ++ ++ @Return None. ++*//***************************************************************************/ ++void XX_StopTimer(t_Handle h_Timer); ++ ++/**************************************************************************//** ++ @Function XX_ModTimer ++ ++ @Description Updates the expiration time of a timer. ++ ++ This routine adds the given time to the current system time, ++ and sets this value as the new expiration time of the timer. ++ ++ @Param[in] h_Timer - A handle to a timer. ++ @Param[in] msecs - The new interval until timer expiration ++ (in milliseconds). ++ ++ @Return None. ++*//***************************************************************************/ ++void XX_ModTimer(t_Handle h_Timer, uint32_t msecs); ++ ++/**************************************************************************//** ++ @Function XX_Sleep ++ ++ @Description Non-busy wait until the desired time (in milliseconds) has passed. ++ ++ @Param[in] msecs - The requested sleep time (in milliseconds). ++ ++ @Return Zero if the requested time has elapsed; Otherwise, the value ++ returned will be the unslept amount) in milliseconds. ++ ++ @Cautions This routine enables interrupts during its wait time. ++*//***************************************************************************/ ++uint32_t XX_Sleep(uint32_t msecs); ++ ++/**************************************************************************//** ++ @Function XX_UDelay ++ ++ @Description Busy-wait until the desired time (in microseconds) has passed. ++ ++ @Param[in] usecs - The requested delay time (in microseconds). ++ ++ @Return None. ++ ++ @Cautions It is highly unrecommended to call this routine during interrupt ++ time, because the system time may not be updated properly during ++ the delay loop. The behavior of this routine during interrupt ++ time is unexpected. ++*//***************************************************************************/ ++void XX_UDelay(uint32_t usecs); ++ ++ ++/*****************************************************************************/ ++/* Other Service Routines */ ++/*****************************************************************************/ ++ ++/**************************************************************************//** ++ @Function XX_PhysToVirt ++ ++ @Description Translates a physical address to the matching virtual address. ++ ++ @Param[in] addr - The physical address to translate. ++ ++ @Return Virtual address. ++*//***************************************************************************/ ++void * XX_PhysToVirt(physAddress_t addr); ++ ++/**************************************************************************//** ++ @Function XX_VirtToPhys ++ ++ @Description Translates a virtual address to the matching physical address. ++ ++ @Param[in] addr - The virtual address to translate. ++ ++ @Return Physical address. ++*//***************************************************************************/ ++physAddress_t XX_VirtToPhys(void *addr); ++ ++ ++/**************************************************************************//** ++ @Group xx_ipc XX Inter-Partition-Communication API ++ ++ @Description The following API is to be used when working with multiple ++ partitions configuration. ++ ++ @{ ++*//***************************************************************************/ ++ ++#define XX_IPC_MAX_ADDR_NAME_LENGTH 16 /**< Maximum length of an endpoint name string; ++ The IPC service can use this constant to limit ++ the storage space for IPC endpoint names. */ ++ ++ ++/**************************************************************************//** ++ @Function t_IpcMsgCompletion ++ ++ @Description Callback function used upon IPC non-blocking transaction completion ++ to return message buffer to the caller and to forward reply if available. ++ ++ This callback function may be attached by the source endpoint to any outgoing ++ IPC message to indicate a non-blocking send (see also XX_IpcSendMessage() routine). ++ Upon completion of an IPC transaction (consisting of a message and an optional reply), ++ the IPC service invokes this callback routine to return the message buffer to the sender ++ and to provide the received reply, if requested. ++ ++ User provides this function. Driver invokes it. ++ ++ @Param[in] h_Module - Abstract handle to the sending module - the same handle as was passed ++ in the XX_IpcSendMessage() function; This handle is typically used to point ++ to the internal data structure of the source endpoint. ++ @Param[in] p_Msg - Pointer to original (sent) message buffer; ++ The source endpoint can free (or reuse) this buffer when message ++ completion callback is called. ++ @Param[in] p_Reply - Pointer to (received) reply buffer; ++ This pointer is the same as was provided by the source endpoint in ++ XX_IpcSendMessage(). ++ @Param[in] replyLength - Length (in bytes) of actual data in the reply buffer. ++ @Param[in] status - Completion status - E_OK or failure indication, e.g. IPC transaction completion ++ timeout. ++ ++ @Return None ++ *//***************************************************************************/ ++typedef void (t_IpcMsgCompletion)(t_Handle h_Module, ++ uint8_t *p_Msg, ++ uint8_t *p_Reply, ++ uint32_t replyLength, ++ t_Error status); ++ ++/**************************************************************************//** ++ @Function t_IpcMsgHandler ++ ++ @Description Callback function used as IPC message handler. ++ ++ The IPC service invokes message handlers for each IPC message received. ++ The actual function pointer should be registered by each destination endpoint ++ via the XX_IpcRegisterMsgHandler() routine. ++ ++ User provides this function. Driver invokes it. ++ ++ @Param[in] h_Module - Abstract handle to the message handling module - the same handle as ++ was passed in the XX_IpcRegisterMsgHandler() function; this handle is ++ typically used to point to the internal data structure of the destination ++ endpoint. ++ @Param[in] p_Msg - Pointer to message buffer with data received from peer. ++ @Param[in] msgLength - Length (in bytes) of message data. ++ @Param[in] p_Reply - Pointer to reply buffer, to be filled by the message handler and then sent ++ by the IPC service; ++ The reply buffer is allocated by the IPC service with size equals to the ++ replyLength parameter provided in message handler registration (see ++ XX_IpcRegisterMsgHandler() function); ++ If replyLength was initially specified as zero during message handler registration, ++ the IPC service may set this pointer to NULL and assume that a reply is not needed; ++ The IPC service is also responsible for freeing the reply buffer after the ++ reply has been sent or dismissed. ++ @Param[in,out] p_ReplyLength - Pointer to reply length, which has a dual role in this function: ++ [In] equals the replyLength parameter provided in message handler ++ registration (see XX_IpcRegisterMsgHandler() function), and ++ [Out] should be updated by message handler to the actual reply length; if ++ this value is set to zero, the IPC service must assume that a reply should ++ not be sent; ++ Note: If p_Reply is not NULL, p_ReplyLength must not be NULL as well. ++ ++ @Return E_OK on success; Error code otherwise. ++ *//***************************************************************************/ ++typedef t_Error (t_IpcMsgHandler)(t_Handle h_Module, ++ uint8_t *p_Msg, ++ uint32_t msgLength, ++ uint8_t *p_Reply, ++ uint32_t *p_ReplyLength); ++ ++/**************************************************************************//** ++ @Function XX_IpcRegisterMsgHandler ++ ++ @Description IPC mailbox registration. ++ ++ This function is used for registering an IPC message handler in the IPC service. ++ This function is called by each destination endpoint to indicate that it is ready ++ to handle incoming messages. The IPC service invokes the message handler upon receiving ++ a message addressed to the specified destination endpoint. ++ ++ @Param[in] addr - The address name string associated with the destination endpoint; ++ This address must be unique across the IPC service domain to ensure ++ correct message routing. ++ @Param[in] f_MsgHandler - Pointer to the message handler callback for processing incoming ++ message; invoked by the IPC service upon receiving a message ++ addressed to the destination endpoint specified by the addr ++ parameter. ++ @Param[in] h_Module - Abstract handle to the message handling module, passed unchanged ++ to f_MsgHandler callback function. ++ @Param[in] replyLength - The maximal data length (in bytes) of any reply that the specified message handler ++ may generate; the IPC service provides the message handler with buffer ++ for reply according to the length specified here (refer also to the description ++ of #t_IpcMsgHandler callback function type); ++ This size shall be zero if the message handler never generates replies. ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error XX_IpcRegisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH], ++ t_IpcMsgHandler *f_MsgHandler, ++ t_Handle h_Module, ++ uint32_t replyLength); ++ ++/**************************************************************************//** ++ @Function XX_IpcUnregisterMsgHandler ++ ++ @Description Release IPC mailbox routine. ++ ++ This function is used for unregistering an IPC message handler from the IPC service. ++ This function is called by each destination endpoint to indicate that it is no longer ++ capable of handling incoming messages. ++ ++ @Param[in] addr - The address name string associated with the destination endpoint; ++ This address is the same as was used when the message handler was ++ registered via XX_IpcRegisterMsgHandler(). ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error XX_IpcUnregisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH]); ++ ++/**************************************************************************//** ++ @Function XX_IpcInitSession ++ ++ @Description This function is used for creating an IPC session between the source endpoint ++ and the destination endpoint. ++ ++ The actual implementation and representation of a session is left for the IPC service. ++ The function returns an abstract handle to the created session. This handle shall be used ++ by the source endpoint in subsequent calls to XX_IpcSendMessage(). ++ The IPC service assumes that before this function is called, no messages are sent from ++ the specified source endpoint to the specified destination endpoint. ++ ++ The IPC service may use a connection-oriented approach or a connectionless approach (or both) ++ as described below. ++ ++ @par Connection-Oriented Approach ++ ++ The IPC service may implement a session in a connection-oriented approach - when this function is called, ++ the IPC service should take the necessary steps to bring up a source-to-destination channel for messages ++ and a destination-to-source channel for replies. The returned handle should represent the internal ++ representation of these channels. ++ ++ @par Connectionless Approach ++ ++ The IPC service may implement a session in a connectionless approach - when this function is called, the ++ IPC service should not perform any particular steps, but it must store the pair of source and destination ++ addresses in some session representation and return it as a handle. When XX_IpcSendMessage() shall be ++ called, the IPC service may use this handle to provide the necessary identifiers for routing the messages ++ through the connectionless medium. ++ ++ @Param[in] destAddr - The address name string associated with the destination endpoint. ++ @Param[in] srcAddr - The address name string associated with the source endpoint. ++ ++ @Return Abstract handle to the initialized session, or NULL on error. ++*//***************************************************************************/ ++t_Handle XX_IpcInitSession(char destAddr[XX_IPC_MAX_ADDR_NAME_LENGTH], ++ char srcAddr[XX_IPC_MAX_ADDR_NAME_LENGTH]); ++ ++/**************************************************************************//** ++ @Function XX_IpcFreeSession ++ ++ @Description This function is used for terminating an existing IPC session between a source endpoint ++ and a destination endpoint. ++ ++ The IPC service assumes that after this function is called, no messages shall be sent from ++ the associated source endpoint to the associated destination endpoint. ++ ++ @Param[in] h_Session - Abstract handle to the IPC session - the same handle as was originally ++ returned by the XX_IpcInitSession() function. ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error XX_IpcFreeSession(t_Handle h_Session); ++ ++/**************************************************************************//** ++ @Function XX_IpcSendMessage ++ ++ @Description IPC message send routine. ++ ++ This function may be used by a source endpoint to send an IPC message to a destination ++ endpoint. The source endpoint cannot send a message to the destination endpoint without ++ first initiating a session with that destination endpoint via XX_IpcInitSession() routine. ++ ++ The source endpoint must provide the buffer pointer and length of the outgoing message. ++ Optionally, it may also provide a buffer for an expected reply. In the latter case, the ++ transaction is not considered complete by the IPC service until the reply has been received. ++ If the source endpoint does not provide a reply buffer, the transaction is considered ++ complete after the message has been sent. The source endpoint must keep the message (and ++ optional reply) buffers valid until the transaction is complete. ++ ++ @par Non-blocking mode ++ ++ The source endpoint may request a non-blocking send by providing a non-NULL pointer to a message ++ completion callback function (f_Completion). Upon completion of the IPC transaction (consisting of a ++ message and an optional reply), the IPC service invokes this callback routine to return the message ++ buffer to the sender and to provide the received reply, if requested. ++ ++ @par Blocking mode ++ ++ The source endpoint may request a blocking send by setting f_Completion to NULL. The function is ++ expected to block until the IPC transaction is complete - either the reply has been received or (if no reply ++ was requested) the message has been sent. ++ ++ @Param[in] h_Session - Abstract handle to the IPC session - the same handle as was originally ++ returned by the XX_IpcInitSession() function. ++ @Param[in] p_Msg - Pointer to message buffer to send. ++ @Param[in] msgLength - Length (in bytes) of actual data in the message buffer. ++ @Param[in] p_Reply - Pointer to reply buffer - if this buffer is not NULL, the IPC service ++ fills this buffer with the received reply data; ++ In blocking mode, the reply data must be valid when the function returns; ++ In non-blocking mode, the reply data is valid when f_Completion is called; ++ If this pointer is NULL, no reply is expected. ++ @Param[in,out] p_ReplyLength - Pointer to reply length, which has a dual role in this function: ++ [In] specifies the maximal length (in bytes) of the reply buffer pointed by ++ p_Reply, and ++ [Out] in non-blocking mode this value is updated by the IPC service to the ++ actual reply length (in bytes). ++ @Param[in] f_Completion - Pointer to a completion callback to be used in non-blocking send mode; ++ The completion callback is invoked by the IPC service upon ++ completion of the IPC transaction (consisting of a message and an optional ++ reply); ++ If this pointer is NULL, the function is expected to block until the IPC ++ transaction is complete. ++ @Param[in] h_Arg - Abstract handle to the sending module; passed unchanged to the f_Completion ++ callback function as the first argument. ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error XX_IpcSendMessage(t_Handle h_Session, ++ uint8_t *p_Msg, ++ uint32_t msgLength, ++ uint8_t *p_Reply, ++ uint32_t *p_ReplyLength, ++ t_IpcMsgCompletion *f_Completion, ++ t_Handle h_Arg); ++ ++ ++/** @} */ /* end of xx_ipc group */ ++/** @} */ /* end of xx_id group */ ++ ++ ++#endif /* __XX_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/ls1043_dflags.h b/drivers/net/ethernet/freescale/sdk_fman/ls1043_dflags.h +new file mode 100644 +index 00000000..c3a5a623 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/ls1043_dflags.h +@@ -0,0 +1,56 @@ ++/* ++ * Copyright 2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __dflags_h ++#define __dflags_h ++ ++ ++#define NCSW_LINUX ++ ++#define LS1043 ++ ++#define DEBUG_ERRORS 1 ++ ++#if defined(DEBUG) ++#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_INFO ++ ++#define DEBUG_XX_MALLOC ++#define DEBUG_MEM_LEAKS ++ ++#else ++#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_WARNING ++#endif /* (DEBUG) */ ++ ++#define REPORT_EVENTS 1 ++#define EVENT_GLOBAL_LEVEL REPORT_LEVEL_MINOR ++ ++#endif /* __dflags_h */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk b/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk +new file mode 100644 +index 00000000..586f9c79 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk +@@ -0,0 +1,53 @@ ++# ++# Makefile config for the Freescale NetcommSW ++# ++NET_DPA = $(srctree)/drivers/net ++DRV_DPA = $(srctree)/drivers/net/ethernet/freescale/sdk_dpaa ++FMAN = $(srctree)/drivers/net/ethernet/freescale/sdk_fman ++ ++ifeq ("$(CONFIG_FMAN_P3040_P4080_P5020)", "y") ++ccflags-y +=-include $(FMAN)/p3040_4080_5020_dflags.h ++endif ++ifeq ("$(CONFIG_FMAN_P1023)", "y") ++ccflags-y +=-include $(FMAN)/p1023_dflags.h ++endif ++ifdef CONFIG_FMAN_V3H ++ccflags-y +=-include $(FMAN)/fmanv3h_dflags.h ++endif ++ifdef CONFIG_FMAN_V3L ++ccflags-y +=-include $(FMAN)/fmanv3l_dflags.h ++endif ++ifdef CONFIG_FMAN_ARM ++ccflags-y +=-include $(FMAN)/ls1043_dflags.h ++endif ++ ++ccflags-y += -I$(DRV_DPA)/ ++ccflags-y += -I$(FMAN)/inc ++ccflags-y += -I$(FMAN)/inc/cores ++ccflags-y += -I$(FMAN)/inc/etc ++ccflags-y += -I$(FMAN)/inc/Peripherals ++ccflags-y += -I$(FMAN)/inc/flib ++ ++ifeq ("$(CONFIG_FMAN_P3040_P4080_P5020)", "y") ++ccflags-y += -I$(FMAN)/inc/integrations/P3040_P4080_P5020 ++endif ++ifeq ("$(CONFIG_FMAN_P1023)", "y") ++ccflags-y += -I$(FMAN)/inc/integrations/P1023 ++endif ++ifdef CONFIG_FMAN_V3H ++ccflags-y += -I$(FMAN)/inc/integrations/FMANV3H ++endif ++ifdef CONFIG_FMAN_V3L ++ccflags-y += -I$(FMAN)/inc/integrations/FMANV3L ++endif ++ifdef CONFIG_FMAN_ARM ++ccflags-y += -I$(FMAN)/inc/integrations/LS1043 ++endif ++ ++ccflags-y += -I$(FMAN)/src/inc ++ccflags-y += -I$(FMAN)/src/inc/system ++ccflags-y += -I$(FMAN)/src/inc/wrapper ++ccflags-y += -I$(FMAN)/src/inc/xx ++ccflags-y += -I$(srctree)/include/uapi/linux/fmd ++ccflags-y += -I$(srctree)/include/uapi/linux/fmd/Peripherals ++ccflags-y += -I$(srctree)/include/uapi/linux/fmd/integrations +diff --git a/drivers/net/ethernet/freescale/sdk_fman/p1023_dflags.h b/drivers/net/ethernet/freescale/sdk_fman/p1023_dflags.h +new file mode 100644 +index 00000000..b48819d7 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/p1023_dflags.h +@@ -0,0 +1,65 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __dflags_h ++#define __dflags_h ++ ++ ++#define NCSW_LINUX ++#if 0 ++#define DEBUG ++#endif ++ ++#define P1023 ++#define NCSW_PPC_CORE ++ ++#define DEBUG_ERRORS 1 ++ ++#if defined(DEBUG) ++#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_INFO ++ ++#define DEBUG_XX_MALLOC ++#define DEBUG_MEM_LEAKS ++ ++#else ++#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_WARNING ++#endif /* (DEBUG) */ ++ ++#define REPORT_EVENTS 1 ++#define EVENT_GLOBAL_LEVEL REPORT_LEVEL_MINOR ++ ++#ifdef CONFIG_P4080_SIM ++#error "Do not define CONFIG_P4080_SIM..." ++#endif ++ ++ ++#endif /* __dflags_h */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/p3040_4080_5020_dflags.h b/drivers/net/ethernet/freescale/sdk_fman/p3040_4080_5020_dflags.h +new file mode 100644 +index 00000000..74389742 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/p3040_4080_5020_dflags.h +@@ -0,0 +1,62 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __dflags_h ++#define __dflags_h ++ ++ ++#define NCSW_LINUX ++ ++#define P4080 ++#define NCSW_PPC_CORE ++ ++#define DEBUG_ERRORS 1 ++ ++#if defined(DEBUG) ++#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_INFO ++ ++#define DEBUG_XX_MALLOC ++#define DEBUG_MEM_LEAKS ++ ++#else ++#define DEBUG_GLOBAL_LEVEL REPORT_LEVEL_WARNING ++#endif /* (DEBUG) */ ++ ++#define REPORT_EVENTS 1 ++#define EVENT_GLOBAL_LEVEL REPORT_LEVEL_MINOR ++ ++#ifdef CONFIG_P4080_SIM ++#define SIMULATOR ++#endif /* CONFIG_P4080_SIM */ ++ ++ ++#endif /* __dflags_h */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/Makefile b/drivers/net/ethernet/freescale/sdk_fman/src/Makefile +new file mode 100644 +index 00000000..49405d0e +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/Makefile +@@ -0,0 +1,11 @@ ++# ++# Makefile for the Freescale Ethernet controllers ++# ++ccflags-y += -DVERSION=\"\" ++# ++#Include netcomm SW specific definitions ++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk ++# ++obj-y += system/ ++obj-y += wrapper/ ++obj-y += xx/ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_ext.h b/drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_ext.h +new file mode 100644 +index 00000000..20f27d29 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_ext.h +@@ -0,0 +1,118 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __SYS_EXT_H ++#define __SYS_EXT_H ++ ++#include "std_ext.h" ++ ++ ++/**************************************************************************//** ++ @Group sys_grp System Interfaces ++ ++ @Description Linux system programming interfaces. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group sys_gen_grp System General Interface ++ ++ @Description General definitions, structures and routines of the linux ++ system programming interface. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Collection Macros for Advanced Configuration Requests ++ @{ ++*//***************************************************************************/ ++#define SYS_MAX_ADV_CONFIG_ARGS 4 ++ /**< Maximum number of arguments in ++ an advanced configuration entry */ ++/* @} */ ++ ++/**************************************************************************//** ++ @Description System Object Advanced Configuration Entry ++ ++ This structure represents a single request for an advanced ++ configuration call on the initialized object. An array of such ++ requests may be contained in the settings structure of the ++ corresponding object. ++ ++ The maximum number of arguments is limited to #SYS_MAX_ADV_CONFIG_ARGS. ++*//***************************************************************************/ ++typedef struct t_SysObjectAdvConfigEntry ++{ ++ void *p_Function; /**< Pointer to advanced configuration routine */ ++ ++ uintptr_t args[SYS_MAX_ADV_CONFIG_ARGS]; ++ /**< Array of arguments for the specified routine; ++ All arguments should be casted to uint32_t. */ ++} t_SysObjectAdvConfigEntry; ++ ++ ++/** @} */ /* end of sys_gen_grp */ ++/** @} */ /* end of sys_grp */ ++ ++#define NCSW_PARAMS(_num, _params) ADV_CONFIG_PARAMS_##_num _params ++ ++#define ADV_CONFIG_PARAMS_1(_type) \ ++ , (_type)p_Entry->args[0] ++ ++#define SET_ADV_CONFIG_ARGS_1(_arg0) \ ++ p_Entry->args[0] = (uintptr_t )(_arg0); \ ++ ++#define ARGS(_num, _params) SET_ADV_CONFIG_ARGS_##_num _params ++ ++#define ADD_ADV_CONFIG_START(_p_Entries, _maxEntries) \ ++ { \ ++ t_SysObjectAdvConfigEntry *p_Entry; \ ++ t_SysObjectAdvConfigEntry *p_Entrys = (_p_Entries); \ ++ int i=0, max = (_maxEntries); \ ++ ++#define ADD_ADV_CONFIG_END \ ++ } ++ ++#define ADV_CONFIG_CHECK_START(_p_Entry) \ ++ { \ ++ t_SysObjectAdvConfigEntry *p_Entry = _p_Entry; \ ++ t_Error errCode; \ ++ ++#define ADV_CONFIG_CHECK(_handle, _func, _params) \ ++ if (p_Entry->p_Function == _func) \ ++ { \ ++ errCode = _func(_handle _params); \ ++ } else ++ ++#endif /* __SYS_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_io_ext.h b/drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_io_ext.h +new file mode 100644 +index 00000000..d6aa9d41 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/system/sys_io_ext.h +@@ -0,0 +1,46 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __SYS_IO_EXT_H ++#define __SYS_IO_EXT_H ++ ++#include "std_ext.h" ++#include "error_ext.h" ++ ++ ++t_Error SYS_RegisterIoMap (uint64_t virtAddr, uint64_t physAddr, uint32_t size); ++t_Error SYS_UnregisterIoMap (uint64_t virtAddr); ++uint64_t SYS_PhysToVirt (uint64_t addr); ++uint64_t SYS_VirtToPhys (uint64_t addr); ++ ++ ++#endif /* __SYS_IO_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/inc/types_linux.h b/drivers/net/ethernet/freescale/sdk_fman/src/inc/types_linux.h +new file mode 100644 +index 00000000..201ad699 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/types_linux.h +@@ -0,0 +1,208 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __TYPES_LINUX_H__ ++#define __TYPES_LINUX_H__ ++ ++#include ++ ++#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) ++#define MODVERSIONS ++#endif ++#ifdef MODVERSIONS ++#include ++#endif /* MODVERSIONS */ ++ ++#include ++#include ++#include ++#include ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) ++ #error "This kernel is probably not supported!!!" ++#elif (!((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) || \ ++ (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27)) || \ ++ (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,30)))) ++ #warning "This kernel is probably not supported!!! You may need to add some fixes." ++#endif /* LINUX_VERSION_CODE */ ++ ++ ++typedef float float_t; /* Single precision floating point */ ++typedef double double_t; /* Double precision floating point */ ++ ++ ++#define _Packed ++#define _PackedType __attribute__ ((packed)) ++ ++typedef phys_addr_t physAddress_t; ++ ++#define UINT8_MAX 0xFF ++#define UINT8_MIN 0 ++#define UINT16_MAX 0xFFFF ++#define UINT16_MIN 0 ++#define UINT32_MAX 0xFFFFFFFF ++#define UINT32_MIN 0 ++#define UINT64_MAX 0xFFFFFFFFFFFFFFFFLL ++#define UINT64_MIN 0 ++#define INT8_MAX 0x7F ++#define INT8_MIN 0x80 ++#define INT16_MAX 0x7FFF ++#define INT16_MIN 0x8000 ++#define INT32_MAX 0x7FFFFFFF ++#define INT32_MIN 0x80000000 ++#define INT64_MAX 0x7FFFFFFFFFFFFFFFLL ++#define INT64_MIN 0x8000000000000000LL ++ ++#define ON 1 ++#define OFF 0 ++ ++#define FALSE false ++#define TRUE true ++ ++ ++/************************/ ++/* memory access macros */ ++/************************/ ++#ifdef CONFIG_FMAN_ARM ++#define in_be16(a) __be16_to_cpu(__raw_readw(a)) ++#define in_be32(a) __be32_to_cpu(__raw_readl(a)) ++#define out_be16(a, v) __raw_writew(__cpu_to_be16(v), a) ++#define out_be32(a, v) __raw_writel(__cpu_to_be32(v), a) ++#endif ++ ++#define GET_UINT8(arg) *(volatile uint8_t *)(&(arg)) ++#define GET_UINT16(arg) in_be16(&(arg))//*(volatile uint16_t*)(&(arg)) ++#define GET_UINT32(arg) in_be32(&(arg))//*(volatile uint32_t*)(&(arg)) ++#define GET_UINT64(arg) *(volatile uint64_t*)(&(arg)) ++ ++#ifdef VERBOSE_WRITE ++void XX_Print(char *str, ...); ++#define WRITE_UINT8(arg, data) \ ++ do { XX_Print("ADDR: 0x%08x, VAL: 0x%02x\r\n", (uint32_t)&(arg), (data)); *(volatile uint8_t *)(&(arg)) = (data); } while (0) ++#define WRITE_UINT16(arg, data) \ ++ do { XX_Print("ADDR: 0x%08x, VAL: 0x%04x\r\n", (uint32_t)&(arg), (data)); out_be16(&(arg), data); /* *(volatile uint16_t*)(&(arg)) = (data);*/ } while (0) ++#define WRITE_UINT32(arg, data) \ ++ do { XX_Print("ADDR: 0x%08x, VAL: 0x%08x\r\n", (uint32_t)&(arg), (data)); out_be32(&(arg), data); /* *(volatile uint32_t*)(&(arg)) = (data);*/ } while (0) ++#define WRITE_UINT64(arg, data) \ ++ do { XX_Print("ADDR: 0x%08x, VAL: 0x%016llx\r\n", (uint32_t)&(arg), (data)); *(volatile uint64_t*)(&(arg)) = (data); } while (0) ++ ++#else /* not VERBOSE_WRITE */ ++#define WRITE_UINT8(arg, data) *(volatile uint8_t *)(&(arg)) = (data) ++#define WRITE_UINT16(arg, data) out_be16(&(arg), data)//*(volatile uint16_t*)(&(arg)) = (data) ++#define WRITE_UINT32(arg, data) out_be32(&(arg), data)//*(volatile unsigned int *)(&(arg)) = (data) ++#define WRITE_UINT64(arg, data) *(volatile uint64_t*)(&(arg)) = (data) ++#endif /* not VERBOSE_WRITE */ ++ ++ ++/*****************************************************************************/ ++/* General stuff */ ++/*****************************************************************************/ ++#ifdef ARRAY_SIZE ++#undef ARRAY_SIZE ++#endif /* ARRAY_SIZE */ ++ ++#ifdef MAJOR ++#undef MAJOR ++#endif /* MAJOR */ ++ ++#ifdef MINOR ++#undef MINOR ++#endif /* MINOR */ ++ ++#ifdef QE_SIZEOF_BD ++#undef QE_SIZEOF_BD ++#endif /* QE_SIZEOF_BD */ ++ ++#ifdef BD_BUFFER_CLEAR ++#undef BD_BUFFER_CLEAR ++#endif /* BD_BUFFER_CLEAR */ ++ ++#ifdef BD_BUFFER ++#undef BD_BUFFER ++#endif /* BD_BUFFER */ ++ ++#ifdef BD_STATUS_AND_LENGTH_SET ++#undef BD_STATUS_AND_LENGTH_SET ++#endif /* BD_STATUS_AND_LENGTH_SET */ ++ ++#ifdef BD_STATUS_AND_LENGTH ++#undef BD_STATUS_AND_LENGTH ++#endif /* BD_STATUS_AND_LENGTH */ ++ ++#ifdef BD_BUFFER_ARG ++#undef BD_BUFFER_ARG ++#endif /* BD_BUFFER_ARG */ ++ ++#ifdef BD_GET_NEXT ++#undef BD_GET_NEXT ++#endif /* BD_GET_NEXT */ ++ ++#ifdef QE_SDEBCR_BA_MASK ++#undef QE_SDEBCR_BA_MASK ++#endif /* QE_SDEBCR_BA_MASK */ ++ ++#ifdef BD_BUFFER_SET ++#undef BD_BUFFER_SET ++#endif /* BD_BUFFER_SET */ ++ ++#ifdef UPGCR_PROTOCOL ++#undef UPGCR_PROTOCOL ++#endif /* UPGCR_PROTOCOL */ ++ ++#ifdef UPGCR_TMS ++#undef UPGCR_TMS ++#endif /* UPGCR_TMS */ ++ ++#ifdef UPGCR_RMS ++#undef UPGCR_RMS ++#endif /* UPGCR_RMS */ ++ ++#ifdef UPGCR_ADDR ++#undef UPGCR_ADDR ++#endif /* UPGCR_ADDR */ ++ ++#ifdef UPGCR_DIAG ++#undef UPGCR_DIAG ++#endif /* UPGCR_DIAG */ ++ ++#ifdef NCSW_PARAMS ++#undef NCSW_PARAMS ++#endif /* NCSW_PARAMS */ ++ ++#ifdef NO_IRQ ++#undef NO_IRQ ++#endif /* NO_IRQ */ ++ ++#define PRINT_LINE XX_Print("%s:\n %s [%d]\n",__FILE__,__FUNCTION__,__LINE__); ++ ++ ++#endif /* __TYPES_LINUX_H__ */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/fsl_fman_test.h b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/fsl_fman_test.h +new file mode 100644 +index 00000000..0466a473 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/fsl_fman_test.h +@@ -0,0 +1,84 @@ ++/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/****************************************************************************** ++ @File fsl_fman_test.h ++ ++ @Description ++*//***************************************************************************/ ++ ++#ifndef __FSL_FMAN_TEST_H ++#define __FSL_FMAN_TEST_H ++ ++#include ++#include /* raw_smp_processor_id() */ ++ ++//#define FMT_K_DBG ++//#define FMT_K_DBG_RUNTIME ++ ++#define _fmt_prk(stage, format, arg...) \ ++ printk(stage "fmt (cpu:%u): " format, raw_smp_processor_id(), ##arg) ++ ++#define _fmt_inf(format, arg...) _fmt_prk(KERN_INFO, format, ##arg) ++#define _fmt_wrn(format, arg...) _fmt_prk(KERN_WARNING, format, ##arg) ++#define _fmt_err(format, arg...) _fmt_prk(KERN_ERR, format, ##arg) ++ ++/* there are two macros for debugging: for runtime and generic. ++ * Helps when the runtime functions are not targeted for debugging, ++ * thus all the unnecessary information will be skipped. ++ */ ++/* used for generic debugging */ ++#if defined(FMT_K_DBG) ++ #define _fmt_dbg(format, arg...) \ ++ printk("fmt [%s:%u](cpu:%u) - " format, \ ++ __func__, __LINE__, raw_smp_processor_id(), ##arg) ++#else ++# define _fmt_dbg(arg...) ++#endif ++ ++/* used for debugging runtime functions */ ++#if defined(FMT_K_DBG_RUNTIME) ++ #define _fmt_dbgr(format, arg...) \ ++ printk("fmt [%s:%u](cpu:%u) - " format, \ ++ __func__, __LINE__, raw_smp_processor_id(), ##arg) ++#else ++# define _fmt_dbgr(arg...) ++#endif ++ ++#define FMT_RX_ERR_Q 0xffffffff ++#define FMT_RX_DFLT_Q 0xfffffffe ++#define FMT_TX_ERR_Q 0xfffffffd ++#define FMT_TX_CONF_Q 0xfffffffc ++ ++#define FMAN_TEST_MAX_TX_FQS 8 ++ ++#endif /* __FSL_FMAN_TEST_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_exp_sym.h b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_exp_sym.h +new file mode 100644 +index 00000000..0c0c6c11 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_exp_sym.h +@@ -0,0 +1,128 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ @File lnxwrp_exp_sym.h ++ @Description FMan exported routines ++*/ ++ ++#ifndef __LNXWRP_EXP_SYM_H ++#define __LNXWRP_EXP_SYM_H ++ ++#include "fm_port_ext.h" ++#include "fm_pcd_ext.h" ++#include "fm_mac_ext.h" ++ ++ ++/* FMAN Port exported routines */ ++EXPORT_SYMBOL(FM_PORT_Disable); ++EXPORT_SYMBOL(FM_PORT_Enable); ++EXPORT_SYMBOL(FM_PORT_SetPCD); ++EXPORT_SYMBOL(FM_PORT_DeletePCD); ++ ++/* Runtime PCD exported routines */ ++EXPORT_SYMBOL(FM_PCD_Enable); ++EXPORT_SYMBOL(FM_PCD_Disable); ++EXPORT_SYMBOL(FM_PCD_GetCounter); ++EXPORT_SYMBOL(FM_PCD_PrsLoadSw); ++EXPORT_SYMBOL(FM_PCD_KgSetDfltValue); ++EXPORT_SYMBOL(FM_PCD_KgSetAdditionalDataAfterParsing); ++EXPORT_SYMBOL(FM_PCD_SetException); ++EXPORT_SYMBOL(FM_PCD_ModifyCounter); ++EXPORT_SYMBOL(FM_PCD_SetPlcrStatistics); ++EXPORT_SYMBOL(FM_PCD_SetPrsStatistics); ++EXPORT_SYMBOL(FM_PCD_ForceIntr); ++EXPORT_SYMBOL(FM_PCD_HcTxConf); ++ ++EXPORT_SYMBOL(FM_PCD_NetEnvCharacteristicsSet); ++EXPORT_SYMBOL(FM_PCD_NetEnvCharacteristicsDelete); ++EXPORT_SYMBOL(FM_PCD_KgSchemeSet); ++EXPORT_SYMBOL(FM_PCD_KgSchemeDelete); ++EXPORT_SYMBOL(FM_PCD_KgSchemeGetCounter); ++EXPORT_SYMBOL(FM_PCD_KgSchemeSetCounter); ++EXPORT_SYMBOL(FM_PCD_CcRootBuild); ++EXPORT_SYMBOL(FM_PCD_CcRootDelete); ++EXPORT_SYMBOL(FM_PCD_MatchTableSet); ++EXPORT_SYMBOL(FM_PCD_MatchTableDelete); ++EXPORT_SYMBOL(FM_PCD_CcRootModifyNextEngine); ++EXPORT_SYMBOL(FM_PCD_MatchTableModifyNextEngine); ++EXPORT_SYMBOL(FM_PCD_MatchTableFindNModifyNextEngine); ++EXPORT_SYMBOL(FM_PCD_MatchTableModifyMissNextEngine); ++EXPORT_SYMBOL(FM_PCD_MatchTableRemoveKey); ++EXPORT_SYMBOL(FM_PCD_MatchTableFindNRemoveKey); ++EXPORT_SYMBOL(FM_PCD_MatchTableAddKey); ++EXPORT_SYMBOL(FM_PCD_MatchTableModifyKeyAndNextEngine); ++EXPORT_SYMBOL(FM_PCD_MatchTableFindNModifyKeyAndNextEngine); ++EXPORT_SYMBOL(FM_PCD_MatchTableModifyKey); ++EXPORT_SYMBOL(FM_PCD_MatchTableFindNModifyKey); ++EXPORT_SYMBOL(FM_PCD_MatchTableGetIndexedHashBucket); ++EXPORT_SYMBOL(FM_PCD_MatchTableGetNextEngine); ++EXPORT_SYMBOL(FM_PCD_MatchTableGetKeyCounter); ++EXPORT_SYMBOL(FM_PCD_MatchTableGetKeyStatistics); ++EXPORT_SYMBOL(FM_PCD_MatchTableFindNGetKeyStatistics); ++EXPORT_SYMBOL(FM_PCD_MatchTableGetMissStatistics); ++EXPORT_SYMBOL(FM_PCD_HashTableGetMissStatistics); ++EXPORT_SYMBOL(FM_PCD_HashTableSet); ++EXPORT_SYMBOL(FM_PCD_HashTableDelete); ++EXPORT_SYMBOL(FM_PCD_HashTableAddKey); ++EXPORT_SYMBOL(FM_PCD_HashTableRemoveKey); ++EXPORT_SYMBOL(FM_PCD_HashTableModifyNextEngine); ++EXPORT_SYMBOL(FM_PCD_HashTableModifyMissNextEngine); ++EXPORT_SYMBOL(FM_PCD_HashTableGetMissNextEngine); ++EXPORT_SYMBOL(FM_PCD_HashTableFindNGetKeyStatistics); ++EXPORT_SYMBOL(FM_PCD_PlcrProfileSet); ++EXPORT_SYMBOL(FM_PCD_PlcrProfileDelete); ++EXPORT_SYMBOL(FM_PCD_PlcrProfileGetCounter); ++EXPORT_SYMBOL(FM_PCD_PlcrProfileSetCounter); ++EXPORT_SYMBOL(FM_PCD_ManipNodeSet); ++EXPORT_SYMBOL(FM_PCD_ManipNodeDelete); ++EXPORT_SYMBOL(FM_PCD_ManipGetStatistics); ++EXPORT_SYMBOL(FM_PCD_ManipNodeReplace); ++#if (DPAA_VERSION >= 11) ++EXPORT_SYMBOL(FM_PCD_FrmReplicSetGroup); ++EXPORT_SYMBOL(FM_PCD_FrmReplicDeleteGroup); ++EXPORT_SYMBOL(FM_PCD_FrmReplicAddMember); ++EXPORT_SYMBOL(FM_PCD_FrmReplicRemoveMember); ++#endif /* DPAA_VERSION >= 11 */ ++ ++#ifdef FM_CAPWAP_SUPPORT ++EXPORT_SYMBOL(FM_PCD_StatisticsSetNode); ++#endif /* FM_CAPWAP_SUPPORT */ ++ ++EXPORT_SYMBOL(FM_PCD_SetAdvancedOffloadSupport); ++ ++/* FMAN MAC exported routines */ ++EXPORT_SYMBOL(FM_MAC_GetStatistics); ++ ++EXPORT_SYMBOL(FM_GetSpecialOperationCoding); ++ ++#endif /* __LNXWRP_EXP_SYM_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fm_ext.h b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fm_ext.h +new file mode 100644 +index 00000000..a72c8670 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fm_ext.h +@@ -0,0 +1,163 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/****************************************************************************** ++ @File lnxwrp_fm_ext.h ++ ++ @Description TODO ++*//***************************************************************************/ ++ ++#ifndef __LNXWRP_FM_EXT_H ++#define __LNXWRP_FM_EXT_H ++ ++#include "std_ext.h" ++#include "sys_ext.h" ++#include "fm_ext.h" ++#include "fm_muram_ext.h" ++#include "fm_pcd_ext.h" ++#include "fm_port_ext.h" ++#include "fm_mac_ext.h" ++#include "fm_rtc_ext.h" ++ ++ ++/**************************************************************************//** ++ @Group FM_LnxKern_grp Frame Manager Linux wrapper API ++ ++ @Description FM API functions, definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group FM_LnxKern_init_grp Initialization Unit ++ ++ @Description Initialization Unit ++ ++ Initialization Flow: ++ Initialization of the FM Module will be carried out by the Linux ++ kernel according to the following sequence: ++ a. Calling the initialization routine with no parameters. ++ b. The driver will register to the Device-Tree. ++ c. The Linux Device-Tree will initiate a call to the driver for ++ initialization. ++ d. The driver will read the appropriate information from the Device-Tree ++ e. [Optional] Calling the advance initialization routines to change ++ driver's defaults. ++ f. Initialization of the device will be automatically upon using it. ++ ++ @{ ++*//***************************************************************************/ ++ ++typedef struct t_WrpFmDevSettings ++{ ++ t_FmParams param; ++ t_SysObjectAdvConfigEntry *advConfig; ++} t_WrpFmDevSettings; ++ ++typedef struct t_WrpFmPcdDevSettings ++{ ++ t_FmPcdParams param; ++ t_SysObjectAdvConfigEntry *advConfig; ++} t_WrpFmPcdDevSettings; ++ ++typedef struct t_WrpFmPortDevSettings ++{ ++ bool frag_enabled; ++ t_FmPortParams param; ++ t_SysObjectAdvConfigEntry *advConfig; ++} t_WrpFmPortDevSettings; ++ ++typedef struct t_WrpFmMacDevSettings ++{ ++ t_FmMacParams param; ++ t_SysObjectAdvConfigEntry *advConfig; ++} t_WrpFmMacDevSettings; ++ ++ ++/**************************************************************************//** ++ @Function LNXWRP_FM_Init ++ ++ @Description Initialize the FM linux wrapper. ++ ++ @Return A handle (descriptor) of the newly created FM Linux wrapper ++ structure. ++*//***************************************************************************/ ++t_Handle LNXWRP_FM_Init(void); ++ ++/**************************************************************************//** ++ @Function LNXWRP_FM_Free ++ ++ @Description Free the FM linux wrapper. ++ ++ @Param[in] h_LnxWrpFm - A handle to the FM linux wrapper. ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++t_Error LNXWRP_FM_Free(t_Handle h_LnxWrpFm); ++ ++/**************************************************************************//** ++ @Function LNXWRP_FM_GetMacHandle ++ ++ @Description Get the FM-MAC LLD handle from the FM linux wrapper. ++ ++ @Param[in] h_LnxWrpFm - A handle to the FM linux wrapper. ++ @Param[in] fmId - Index of the FM device to get the MAC handle from. ++ @Param[in] macId - Index of the mac handle. ++ ++ @Return A handle of the LLD compressor. ++*//***************************************************************************/ ++t_Handle LNXWRP_FM_GetMacHandle(t_Handle h_LnxWrpFm, uint8_t fmId, uint8_t macId); ++ ++#ifdef CONFIG_FSL_SDK_FMAN_TEST ++t_Handle LNXWRP_FM_TEST_Init(void); ++t_Error LNXWRP_FM_TEST_Free(t_Handle h_FmTestLnxWrp); ++#endif /* CONFIG_FSL_SDK_FMAN_TEST */ ++ ++/** @} */ /* end of FM_LnxKern_init_grp group */ ++ ++ ++/**************************************************************************//** ++ @Group FM_LnxKern_ctrl_grp Control Unit ++ ++ @Description Control Unit ++ ++ TODO ++ @{ ++*//***************************************************************************/ ++ ++#include "lnxwrp_fsl_fman.h" ++ ++/** @} */ /* end of FM_LnxKern_ctrl_grp group */ ++/** @} */ /* end of FM_LnxKern_grp group */ ++ ++ ++#endif /* __LNXWRP_FM_EXT_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h +new file mode 100644 +index 00000000..c50031cf +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/wrapper/lnxwrp_fsl_fman.h +@@ -0,0 +1,921 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/****************************************************************************** ++ @File lnxwrp_fsl_fman.h ++ ++ @Description Linux internal kernel API ++*//***************************************************************************/ ++ ++#ifndef __LNXWRP_FSL_FMAN_H ++#define __LNXWRP_FSL_FMAN_H ++ ++#include ++#include /* struct device */ ++#include /* struct qman_fq */ ++#include "dpaa_integration_ext.h" ++#include "fm_port_ext.h" ++#include "fm_mac_ext.h" ++#include "fm_macsec_ext.h" ++#include "fm_rtc_ext.h" ++ ++/**************************************************************************//** ++ @Group FM_LnxKern_grp Frame Manager Linux wrapper API ++ ++ @Description FM API functions, definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group FM_LnxKern_ctrl_grp Control Unit ++ ++ @Description Control Unit ++ ++ Internal Kernel Control Unit API ++ @{ ++*//***************************************************************************/ ++ ++/*****************************************************************************/ ++/* Internal Linux kernel routines */ ++/*****************************************************************************/ ++ ++/**************************************************************************//** ++ @Description MACSEC Exceptions wrapper ++*//***************************************************************************/ ++typedef enum fm_macsec_exception { ++ SINGLE_BIT_ECC = e_FM_MACSEC_EX_SINGLE_BIT_ECC, ++ MULTI_BIT_ECC = e_FM_MACSEC_EX_MULTI_BIT_ECC ++} fm_macsec_exception; ++ ++/**************************************************************************//** ++ @Description Unknown sci frame treatment wrapper ++*//***************************************************************************/ ++typedef enum fm_macsec_unknown_sci_frame_treatment { ++ SCI_DISCARD_BOTH = e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DISCARD_BOTH, ++ SCI_DISCARD_UNCTRL_DELIVER_DISCARD_CTRL = \ ++ e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DISCARD_UNCONTROLLED_DELIVER_OR_DISCARD_CONTROLLED, ++ SCI_DELIVER_UNCTRL_DISCARD_CTRL = \ ++ e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DELIVER_UNCONTROLLED_DISCARD_CONTROLLED, ++ SCI_DELIVER_DISCARD_UNCTRL_DELIVER_DISCARD_CTRL = \ ++ e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DELIVER_OR_DISCARD_UNCONTROLLED_DELIVER_OR_DISCARD_CONTROLLED ++} fm_macsec_unknown_sci_frame_treatment; ++ ++/**************************************************************************//** ++ @Description Untag frame treatment wrapper ++*//***************************************************************************/ ++typedef enum fm_macsec_untag_frame_treatment { ++ UNTAG_DELIVER_UNCTRL_DISCARD_CTRL = \ ++ e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DELIVER_UNCONTROLLED_DISCARD_CONTROLLED, ++ UNTAG_DISCARD_BOTH = e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DISCARD_BOTH, ++ UNTAG_DISCARD_UNCTRL_DELIVER_CTRL_UNMODIFIED = \ ++ e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DISCARD_UNCONTROLLED_DELIVER_CONTROLLED_UNMODIFIED ++} fm_macsec_untag_frame_treatment; ++ ++/**************************************************************************//** ++@Description MACSEC SECY Cipher Suite wrapper ++*//***************************************************************************/ ++typedef enum fm_macsec_secy_cipher_suite { ++ SECY_GCM_AES_128 = e_FM_MACSEC_SECY_GCM_AES_128, /**< GCM-AES-128 */ ++#if (DPAA_VERSION >= 11) ++ SECY_GCM_AES_256 = e_FM_MACSEC_SECY_GCM_AES_256 /**< GCM-AES-256 */ ++#endif /* (DPAA_VERSION >= 11) */ ++} fm_macsec_secy_cipher_suite; ++ ++/**************************************************************************//** ++ @Description MACSEC SECY Exceptions wrapper ++*//***************************************************************************/ ++typedef enum fm_macsec_secy_exception { ++ SECY_EX_FRAME_DISCARDED = e_FM_MACSEC_SECY_EX_FRAME_DISCARDED ++} fm_macsec_secy_exception; ++ ++/**************************************************************************//** ++ @Description MACSEC SECY Events wrapper ++*//***************************************************************************/ ++typedef enum fm_macsec_secy_event { ++ SECY_EV_NEXT_PN = e_FM_MACSEC_SECY_EV_NEXT_PN ++} fm_macsec_secy_event; ++ ++/**************************************************************************//** ++ @Description Valid frame behaviors wrapper ++*//***************************************************************************/ ++typedef enum fm_macsec_valid_frame_behavior { ++ VALID_FRAME_BEHAVIOR_DISABLE = e_FM_MACSEC_VALID_FRAME_BEHAVIOR_DISABLE, ++ VALID_FRAME_BEHAVIOR_CHECK = e_FM_MACSEC_VALID_FRAME_BEHAVIOR_CHECK, ++ VALID_FRAME_BEHAVIOR_STRICT = e_FM_MACSEC_VALID_FRAME_BEHAVIOR_STRICT ++} fm_macsec_valid_frame_behavior; ++ ++/**************************************************************************//** ++ @Description SCI insertion modes wrapper ++*//***************************************************************************/ ++typedef enum fm_macsec_sci_insertion_mode { ++ SCI_INSERTION_MODE_EXPLICIT_SECTAG = \ ++ e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_SECTAG, ++ SCI_INSERTION_MODE_EXPLICIT_MAC_SA = \ ++ e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_MAC_SA, ++ SCI_INSERTION_MODE_IMPLICT_PTP = e_FM_MACSEC_SCI_INSERTION_MODE_IMPLICT_PTP ++} fm_macsec_sci_insertion_mode; ++ ++typedef macsecSAKey_t macsec_sa_key_t; ++typedef macsecSCI_t macsec_sci_t; ++typedef macsecAN_t macsec_an_t; ++typedef t_Handle handle_t; ++ ++/**************************************************************************//** ++ @Function fm_macsec_secy_exception_callback wrapper ++ @Description Exceptions user callback routine, will be called upon an ++ exception passing the exception identification. ++ @Param[in] app_h A handle to an application layer object; This handle ++ will be passed by the driver upon calling this callback. ++ @Param[in] exception The exception. ++*//***************************************************************************/ ++typedef void (fm_macsec_secy_exception_callback) (handle_t app_h, ++ fm_macsec_secy_exception exception); ++ ++/**************************************************************************//** ++ @Function fm_macsec_secy_event_callback wrapper ++ @Description Events user callback routine, will be called upon an ++ event passing the event identification. ++ @Param[in] app_h A handle to an application layer object; This handle ++ will be passed by the driver upon calling this callback. ++ @Param[in] event The event. ++*//***************************************************************************/ ++typedef void (fm_macsec_secy_event_callback) (handle_t app_h, ++ fm_macsec_secy_event event); ++ ++/**************************************************************************//** ++ @Function fm_macsec_exception_callback wrapper ++ @Description Exceptions user callback routine, will be called upon an ++ exception passing the exception identification. ++ @Param[in] app_h A handle to an application layer object; This handle ++ will be passed by the driver upon calling this callback. ++ @Param[in] exception The exception. ++*//***************************************************************************/ ++typedef void (fm_macsec_exception_callback) (handle_t app_h, ++ fm_macsec_exception exception); ++ ++/**************************************************************************//** ++ @Description MACSEC SecY SC Params wrapper ++*//***************************************************************************/ ++struct fm_macsec_secy_sc_params { ++ macsec_sci_t sci; ++ fm_macsec_secy_cipher_suite cipher_suite; ++}; ++ ++/**************************************************************************//** ++ @Description FM MACSEC SecY config input wrapper ++*//***************************************************************************/ ++struct fm_macsec_secy_params { ++ handle_t fm_macsec_h; ++ struct fm_macsec_secy_sc_params tx_sc_params; ++ uint32_t num_receive_channels; ++ fm_macsec_secy_exception_callback *exception_f; ++ fm_macsec_secy_event_callback *event_f; ++ handle_t app_h; ++}; ++ ++/**************************************************************************//** ++ @Description FM MACSEC config input wrapper ++*//***************************************************************************/ ++struct fm_macsec_params { ++ handle_t fm_h; ++ bool guest_mode; ++ ++ union { ++ struct { ++ uint8_t fm_mac_id; ++ } guest_params; ++ ++ struct { ++ uintptr_t base_addr; ++ handle_t fm_mac_h; ++ fm_macsec_exception_callback *exception_f; ++ handle_t app_h; ++ } non_guest_params; ++ }; ++ ++}; ++ ++/**************************************************************************//** ++ @Description FM device opaque structure used for type checking ++*//***************************************************************************/ ++struct fm; ++ ++/**************************************************************************//** ++ @Description FM MAC device opaque structure used for type checking ++*//***************************************************************************/ ++struct fm_mac_dev; ++ ++/**************************************************************************//** ++ @Description FM MACSEC device opaque structure used for type checking ++*//***************************************************************************/ ++struct fm_macsec_dev; ++struct fm_macsec_secy_dev; ++ ++/**************************************************************************//** ++ @Description A structure .., ++*//***************************************************************************/ ++struct fm_port; ++ ++typedef int (*alloc_pcd_fqids)(struct device *dev, uint32_t num, ++ uint8_t alignment, uint32_t *base_fqid); ++ ++typedef int (*free_pcd_fqids)(struct device *dev, uint32_t base_fqid); ++ ++struct fm_port_pcd_param { ++ alloc_pcd_fqids cba; ++ free_pcd_fqids cbf; ++ struct device *dev; ++}; ++ ++/**************************************************************************//** ++ @Description A structure of information about each of the external ++ buffer pools used by the port, ++*//***************************************************************************/ ++struct fm_port_pool_param { ++ uint8_t id; /**< External buffer pool id */ ++ uint16_t size; /**< External buffer pool buffer size */ ++}; ++ ++/**************************************************************************//** ++ @Description structure for additional port parameters ++*//***************************************************************************/ ++struct fm_port_params { ++ uint32_t errq; /**< Error Queue Id. */ ++ uint32_t defq; /**< For Tx and HC - Default Confirmation queue, ++ 0 means no Tx conf for processed frames. ++ For Rx and OP - default Rx queue. */ ++ uint8_t num_pools; /**< Number of pools use by this port */ ++ struct fm_port_pool_param pool_param[FM_PORT_MAX_NUM_OF_EXT_POOLS]; ++ /**< Parameters for each pool */ ++ uint16_t priv_data_size; /**< Area that user may save for his own ++ need (E.g. save the SKB) */ ++ bool parse_results; /**< Put the parser-results in the Rx/Tx buffer */ ++ bool hash_results; /**< Put the hash-results in the Rx/Tx buffer */ ++ bool time_stamp; /**< Put the time-stamp in the Rx/Tx buffer */ ++ bool frag_enable; /**< Fragmentation support, for OP only */ ++ uint16_t data_align; /**< value for selecting a data alignment (must be a power of 2); ++ if write optimization is used, must be >= 16. */ ++ uint8_t manip_extra_space; /**< Maximum extra size needed (insertion-size minus removal-size); ++ Note that this field impacts the size of the buffer-prefix ++ (i.e. it pushes the data offset); */ ++}; ++ ++/**************************************************************************//** ++ @Function fm_bind ++ ++ @Description Bind to a specific FM device. ++ ++ @Param[in] fm_dev - the OF handle of the FM device. ++ ++ @Return A handle of the FM device. ++ ++ @Cautions Allowed only after the port was created. ++*//***************************************************************************/ ++struct fm *fm_bind(struct device *fm_dev); ++ ++/**************************************************************************//** ++ @Function fm_unbind ++ ++ @Description Un-bind from a specific FM device. ++ ++ @Param[in] fm - A handle of the FM device. ++ ++ @Cautions Allowed only after the port was created. ++*//***************************************************************************/ ++void fm_unbind(struct fm *fm); ++ ++void *fm_get_handle(struct fm *fm); ++void *fm_get_rtc_handle(struct fm *fm); ++struct resource *fm_get_mem_region(struct fm *fm); ++ ++/**************************************************************************//** ++ @Function fm_port_bind ++ ++ @Description Bind to a specific FM-port device (may be Rx or Tx port). ++ ++ @Param[in] fm_port_dev - the OF handle of the FM port device. ++ ++ @Return A handle of the FM port device. ++ ++ @Cautions Allowed only after the port was created. ++*//***************************************************************************/ ++struct fm_port *fm_port_bind(struct device *fm_port_dev); ++ ++/**************************************************************************//** ++ @Function fm_port_unbind ++ ++ @Description Un-bind from a specific FM-port device (may be Rx or Tx port). ++ ++ @Param[in] port - A handle of the FM port device. ++ ++ @Cautions Allowed only after the port was created. ++*//***************************************************************************/ ++void fm_port_unbind(struct fm_port *port); ++ ++/**************************************************************************//** ++ @Function fm_set_rx_port_params ++ ++ @Description Configure parameters for a specific Rx FM-port device. ++ ++ @Param[in] port - A handle of the FM port device. ++ @Param[in] params - Rx port parameters ++ ++ @Cautions Allowed only after the port is binded. ++*//***************************************************************************/ ++void fm_set_rx_port_params(struct fm_port *port, ++ struct fm_port_params *params); ++ ++/**************************************************************************//** ++ @Function fm_port_pcd_bind ++ ++ @Description Bind as a listener on a port PCD. ++ ++ @Param[in] port - A handle of the FM port device. ++ @Param[in] params - PCD port parameters ++ ++ @Cautions Allowed only after the port is binded. ++*//***************************************************************************/ ++void fm_port_pcd_bind (struct fm_port *port, struct fm_port_pcd_param *params); ++ ++/**************************************************************************//** ++ @Function fm_port_get_buff_layout_ext_params ++ ++ @Description Get data_align and manip_extra_space from the device tree ++ chosen node if applied. ++ This function will only update these two parameters. ++ When this port has no such parameters in the device tree ++ values will be set to 0. ++ ++ @Param[in] port - A handle of the FM port device. ++ @Param[in] params - PCD port parameters ++ ++ @Cautions Allowed only after the port is binded. ++*//***************************************************************************/ ++void fm_port_get_buff_layout_ext_params(struct fm_port *port, struct fm_port_params *params); ++ ++/**************************************************************************//** ++ @Function fm_get_tx_port_channel ++ ++ @Description Get qman-channel number for this Tx port. ++ ++ @Param[in] port - A handle of the FM port device. ++ ++ @Return qman-channel number for this Tx port. ++ ++ @Cautions Allowed only after the port is binded. ++*//***************************************************************************/ ++uint16_t fm_get_tx_port_channel(struct fm_port *port); ++ ++/**************************************************************************//** ++ @Function fm_set_tx_port_params ++ ++ @Description Configure parameters for a specific Tx FM-port device ++ ++ @Param[in] port - A handle of the FM port device. ++ @Param[in] params - Tx port parameters ++ ++ @Cautions Allowed only after the port is binded. ++*//***************************************************************************/ ++void fm_set_tx_port_params(struct fm_port *port, struct fm_port_params *params); ++ ++ ++/**************************************************************************//** ++ @Function fm_mac_set_handle ++ ++ @Description Set mac handle ++ ++ @Param[in] h_lnx_wrp_fm_dev - A handle of the LnxWrp FM device. ++ @Param[in] h_fm_mac - A handle of the LnxWrp FM MAC device. ++ @Param[in] mac_id - MAC id. ++*//***************************************************************************/ ++void fm_mac_set_handle(t_Handle h_lnx_wrp_fm_dev, t_Handle h_fm_mac, ++ int mac_id); ++ ++/**************************************************************************//** ++ @Function fm_port_enable ++ ++ @Description Enable specific FM-port device (may be Rx or Tx port). ++ ++ @Param[in] port - A handle of the FM port device. ++ ++ @Cautions Allowed only after the port is initialized. ++*//***************************************************************************/ ++int fm_port_enable(struct fm_port *port); ++ ++/**************************************************************************//** ++ @Function fm_port_disable ++ ++ @Description Disable specific FM-port device (may be Rx or Tx port). ++ ++ @Param[in] port - A handle of the FM port device. ++ ++ @Cautions Allowed only after the port is initialized. ++*//***************************************************************************/ ++int fm_port_disable(struct fm_port *port); ++ ++void *fm_port_get_handle(const struct fm_port *port); ++ ++u64 *fm_port_get_buffer_time_stamp(const struct fm_port *port, ++ const void *data); ++ ++/**************************************************************************//** ++ @Function fm_port_get_base_address ++ ++ @Description Get base address of this port. Useful for accessing ++ port-specific registers (i.e., not common ones). ++ ++ @Param[in] port - A handle of the FM port device. ++ ++ @Param[out] base_addr - The port's base addr (virtual address). ++*//***************************************************************************/ ++void fm_port_get_base_addr(const struct fm_port *port, uint64_t *base_addr); ++ ++/**************************************************************************//** ++ @Function fm_mutex_lock ++ ++ @Description Lock function required before any FMD/LLD call. ++*//***************************************************************************/ ++void fm_mutex_lock(void); ++ ++/**************************************************************************//** ++ @Function fm_mutex_unlock ++ ++ @Description Unlock function required after any FMD/LLD call. ++*//***************************************************************************/ ++void fm_mutex_unlock(void); ++ ++/**************************************************************************//** ++ @Function fm_get_max_frm ++ ++ @Description Get the maximum frame size ++*//***************************************************************************/ ++int fm_get_max_frm(void); ++ ++/**************************************************************************//** ++ @Function fm_get_rx_extra_headroom ++ ++ @Description Get the extra headroom size ++*//***************************************************************************/ ++int fm_get_rx_extra_headroom(void); ++ ++/**************************************************************************//** ++@Function fm_port_set_rate_limit ++ ++@Description Configure Shaper parameter on FM-port device (Tx port). ++ ++@Param[in] port - A handle of the FM port device. ++@Param[in] max_burst_size - Value of maximum burst size allowed. ++@Param[in] rate_limit - The required rate value. ++ ++@Cautions Allowed only after the port is initialized. ++*//***************************************************************************/ ++int fm_port_set_rate_limit(struct fm_port *port, ++ uint16_t max_burst_size, ++ uint32_t rate_limit); ++/**************************************************************************//** ++@Function fm_port_set_rate_limit ++ ++@Description Delete Shaper configuration on FM-port device (Tx port). ++ ++@Param[in] port - A handle of the FM port device. ++ ++@Cautions Allowed only after the port is initialized. ++*//***************************************************************************/ ++int fm_port_del_rate_limit(struct fm_port *port); ++ ++struct auto_res_tables_sizes ++{ ++ uint16_t max_num_of_arp_entries; ++ uint16_t max_num_of_echo_ipv4_entries; ++ uint16_t max_num_of_ndp_entries; ++ uint16_t max_num_of_echo_ipv6_entries; ++ uint16_t max_num_of_snmp_ipv4_entries; ++ uint16_t max_num_of_snmp_ipv6_entries; ++ uint16_t max_num_of_snmp_oid_entries; ++ uint16_t max_num_of_snmp_char; /* total amount of character needed ++ for the snmp table */ ++ uint16_t max_num_of_ip_prot_filtering; ++ uint16_t max_num_of_tcp_port_filtering; ++ uint16_t max_num_of_udp_port_filtering; ++}; ++/* ARP */ ++struct auto_res_arp_entry ++{ ++ uint32_t ip_address; ++ uint8_t mac[6]; ++ bool is_vlan; ++ uint16_t vid; ++}; ++struct auto_res_arp_info ++{ ++ uint8_t table_size; ++ struct auto_res_arp_entry *auto_res_table; ++ bool enable_conflict_detection; /* when TRUE ++ Conflict Detection will be checked and wake the host if ++ needed */ ++}; ++ ++/* NDP */ ++struct auto_res_ndp_entry ++{ ++ uint32_t ip_address[4]; ++ uint8_t mac[6]; ++ bool is_vlan; ++ uint16_t vid; ++}; ++struct auto_res_ndp_info ++{ ++ uint32_t multicast_group; ++ uint8_t table_size_assigned; ++ struct auto_res_ndp_entry *auto_res_table_assigned; /* This list ++ refer to solicitation IP addresses. Note that all IP adresses ++ must be from the same multicast group. This will be checked and ++ if not operation will fail. */ ++ uint8_t table_size_tmp; ++ struct auto_res_ndp_entry *auto_res_table_tmp; /* This list ++ refer to temp IP addresses. Note that all temp IP adresses must ++ be from the same multicast group. This will be checked and if ++ not operation will fail. */ ++ ++ bool enable_conflict_detection; /* when TRUE ++ Conflict Detection will be checked and wake the host if ++ needed */ ++}; ++ ++/* ICMP ECHO */ ++struct auto_res_echo_ipv4_info ++{ ++ uint8_t table_size; ++ struct auto_res_arp_entry *auto_res_table; ++}; ++ ++struct auto_res_echo_ipv6_info ++{ ++ uint8_t table_size; ++ struct auto_res_ndp_entry *auto_res_table; ++}; ++ ++/* SNMP */ ++struct auto_res_snmp_entry ++{ ++ uint16_t oidSize; ++ uint8_t *oidVal; /* only the oid string */ ++ uint16_t resSize; ++ uint8_t *resVal; /* resVal will be the entire reply, ++ i.e. "Type|Length|Value" */ ++}; ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response SNMP IPv4 Addresses Table Entry ++ Refer to the FMan Controller spec for more details. ++*//***************************************************************************/ ++struct auto_res_snmp_ipv4addr_tbl_entry ++{ ++ uint32_t ipv4addr; /*!< 32 bit IPv4 Address. */ ++ bool is_vlan; ++ uint16_t vid; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */ ++ /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */ ++}; ++ ++/**************************************************************************//** ++ @Description Deep Sleep Auto Response SNMP IPv6 Addresses Table Entry ++ Refer to the FMan Controller spec for more details. ++*//***************************************************************************/ ++struct auto_res_snmp_ipv6addr_tbl_entry ++{ ++ uint32_t ipv6Addr[4]; /*!< 4 * 32 bit IPv6 Address. */ ++ bool isVlan; ++ uint16_t vid; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */ ++ /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */ ++}; ++ ++struct auto_res_snmp_info ++{ ++ uint16_t control; /**< Control bits [0-15]. */ ++ uint16_t max_snmp_msg_length; /**< Maximal allowed SNMP message length. */ ++ uint16_t num_ipv4_addresses; /**< Number of entries in IPv4 addresses table. */ ++ uint16_t num_ipv6_addresses; /**< Number of entries in IPv6 addresses table. */ ++ struct auto_res_snmp_ipv4addr_tbl_entry *ipv4addr_tbl; /**< Pointer to IPv4 addresses table. */ ++ struct auto_res_snmp_ipv6addr_tbl_entry *ipv6addr_tbl; /**< Pointer to IPv6 addresses table. */ ++ char *community_read_write_string; ++ char *community_read_only_string; ++ struct auto_res_snmp_entry *oid_table; ++ uint32_t oid_table_size; ++ uint32_t *statistics; ++}; ++ ++/* Filtering */ ++struct auto_res_port_filtering_entry ++{ ++ uint16_t src_port; ++ uint16_t dst_port; ++ uint16_t src_port_mask; ++ uint16_t dst_port_mask; ++}; ++struct auto_res_filtering_info ++{ ++ /* IP protocol filtering parameters */ ++ uint8_t ip_prot_table_size; ++ uint8_t *ip_prot_table_ptr; ++ bool ip_prot_pass_on_hit; /* when TRUE, miss in the table will ++ cause the packet to be droped, hit will pass the packet to ++ UDP/TCP filters if needed and if not to the classification ++ tree. If the classification tree will pass the packet to a ++ queue it will cause a wake interupt. When FALSE it the other ++ way around. */ ++ /* UDP port filtering parameters */ ++ uint8_t udp_ports_table_size; ++ struct auto_res_port_filtering_entry *udp_ports_table_ptr; ++ bool udp_port_pass_on_hit; /* when TRUE, miss in the table will ++ cause the packet to be droped, hit will pass the packet to ++ classification tree. If the classification tree will pass the ++ packet to a queue it will cause a wake interupt. When FALSE it ++ the other way around. */ ++ /* TCP port filtering parameters */ ++ uint16_t tcp_flags_mask; ++ uint8_t tcp_ports_table_size; ++ struct auto_res_port_filtering_entry *tcp_ports_table_ptr; ++ bool tcp_port_pass_on_hit; /* when TRUE, miss in the table will ++ cause the packet to be droped, hit will pass the packet to ++ classification tree. If the classification tree will pass the ++ packet to a queue it will cause a wake interupt. When FALSE it ++ the other way around. */ ++}; ++ ++struct auto_res_port_params ++{ ++ t_Handle h_FmPortTx; ++ struct auto_res_arp_info *p_auto_res_arp_info; ++ struct auto_res_echo_ipv4_info *p_auto_res_echo_ipv4_info; ++ struct auto_res_ndp_info *p_auto_res_ndp_info; ++ struct auto_res_echo_ipv6_info *p_auto_res_echo_ipv6_info; ++ struct auto_res_snmp_info *p_auto_res_snmp_info; ++ struct auto_res_filtering_info *p_auto_res_filtering_info; ++}; ++ ++struct auto_res_port_stats ++{ ++ uint32_t arp_ar_cnt; ++ uint32_t echo_icmpv4_ar_cnt; ++ uint32_t ndp_ar_cnt; ++ uint32_t echo_icmpv6_ar_cnt; ++}; ++ ++int fm_port_config_autores_for_deepsleep_support(struct fm_port *port, ++ struct auto_res_tables_sizes *params); ++ ++int fm_port_enter_autores_for_deepsleep(struct fm_port *port, ++ struct auto_res_port_params *params); ++ ++void fm_port_exit_auto_res_for_deep_sleep(struct fm_port *port_rx, ++ struct fm_port *port_tx); ++ ++bool fm_port_is_in_auto_res_mode(struct fm_port *port); ++ ++struct auto_res_tables_sizes *fm_port_get_autores_maxsize( ++ struct fm_port *port); ++ ++int fm_port_get_autores_stats(struct fm_port *port, struct auto_res_port_stats ++ *stats); ++ ++int fm_port_resume(struct fm_port *port); ++ ++int fm_port_suspend(struct fm_port *port); ++ ++#ifdef CONFIG_FMAN_PFC ++/**************************************************************************//** ++@Function fm_port_set_pfc_priorities_mapping_to_qman_wq ++ ++@Description Associate a QMan Work Queue with a PFC priority on this ++ FM-port device (Tx port). ++ ++@Param[in] port - A handle of the FM port device. ++ ++@Param[in] prio - The PFC priority. ++ ++@Param[in] wq - The Work Queue associated with the PFC priority. ++ ++@Cautions Allowed only after the port is initialized. ++*//***************************************************************************/ ++int fm_port_set_pfc_priorities_mapping_to_qman_wq(struct fm_port *port, ++ uint8_t prio, uint8_t wq); ++#endif ++ ++/**************************************************************************//** ++@Function fm_mac_set_exception ++ ++@Description Set MAC exception state. ++ ++@Param[in] fm_mac_dev - A handle of the FM MAC device. ++@Param[in] exception - FM MAC exception type. ++@Param[in] enable - new state. ++ ++*//***************************************************************************/ ++int fm_mac_set_exception(struct fm_mac_dev *fm_mac_dev, ++ e_FmMacExceptions exception, bool enable); ++ ++int fm_mac_free(struct fm_mac_dev *fm_mac_dev); ++ ++struct fm_mac_dev *fm_mac_config(t_FmMacParams *params); ++ ++int fm_mac_config_max_frame_length(struct fm_mac_dev *fm_mac_dev, ++ int len); ++ ++int fm_mac_config_pad_and_crc(struct fm_mac_dev *fm_mac_dev, bool enable); ++ ++int fm_mac_config_half_duplex(struct fm_mac_dev *fm_mac_dev, bool enable); ++ ++int fm_mac_config_reset_on_init(struct fm_mac_dev *fm_mac_dev, bool enable); ++ ++int fm_mac_init(struct fm_mac_dev *fm_mac_dev); ++ ++int fm_mac_get_version(struct fm_mac_dev *fm_mac_dev, uint32_t *version); ++ ++int fm_mac_enable(struct fm_mac_dev *fm_mac_dev); ++ ++int fm_mac_disable(struct fm_mac_dev *fm_mac_dev); ++ ++int fm_mac_resume(struct fm_mac_dev *fm_mac_dev); ++ ++int fm_mac_set_promiscuous(struct fm_mac_dev *fm_mac_dev, ++ bool enable); ++ ++int fm_mac_remove_hash_mac_addr(struct fm_mac_dev *fm_mac_dev, ++ t_EnetAddr *mac_addr); ++ ++int fm_mac_add_hash_mac_addr(struct fm_mac_dev *fm_mac_dev, ++ t_EnetAddr *mac_addr); ++ ++int fm_mac_modify_mac_addr(struct fm_mac_dev *fm_mac_dev, ++ uint8_t *addr); ++ ++int fm_mac_adjust_link(struct fm_mac_dev *fm_mac_dev, ++ bool link, int speed, bool duplex); ++ ++int fm_mac_enable_1588_time_stamp(struct fm_mac_dev *fm_mac_dev); ++ ++int fm_mac_disable_1588_time_stamp(struct fm_mac_dev *fm_mac_dev); ++ ++int fm_mac_set_rx_pause_frames( ++ struct fm_mac_dev *fm_mac_dev, bool en); ++ ++int fm_mac_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev, ++ bool en); ++ ++int fm_rtc_enable(struct fm *fm_dev); ++ ++int fm_rtc_disable(struct fm *fm_dev); ++ ++int fm_rtc_get_cnt(struct fm *fm_dev, uint64_t *ts); ++ ++int fm_rtc_set_cnt(struct fm *fm_dev, uint64_t ts); ++ ++int fm_rtc_get_drift(struct fm *fm_dev, uint32_t *drift); ++ ++int fm_rtc_set_drift(struct fm *fm_dev, uint32_t drift); ++ ++int fm_rtc_set_alarm(struct fm *fm_dev, uint32_t id, ++ uint64_t time); ++ ++int fm_rtc_set_fiper(struct fm *fm_dev, uint32_t id, ++ uint64_t fiper); ++ ++int fm_mac_set_wol(struct fm_port *port, struct fm_mac_dev *fm_mac_dev, ++ bool en); ++ ++/**************************************************************************//** ++@Function fm_macsec_set_exception ++ ++@Description Set MACSEC exception state. ++ ++@Param[in] fm_macsec_dev - A handle of the FM MACSEC device. ++@Param[in] exception - FM MACSEC exception type. ++@Param[in] enable - new state. ++ ++*//***************************************************************************/ ++ ++int fm_macsec_set_exception(struct fm_macsec_dev *fm_macsec_dev, ++ fm_macsec_exception exception, bool enable); ++int fm_macsec_free(struct fm_macsec_dev *fm_macsec_dev); ++struct fm_macsec_dev *fm_macsec_config(struct fm_macsec_params *fm_params); ++int fm_macsec_init(struct fm_macsec_dev *fm_macsec_dev); ++int fm_macsec_config_unknown_sci_frame_treatment(struct fm_macsec_dev ++ *fm_macsec_dev, ++ fm_macsec_unknown_sci_frame_treatment treat_mode); ++int fm_macsec_config_invalid_tags_frame_treatment(struct fm_macsec_dev *fm_macsec_dev, ++ bool deliver_uncontrolled); ++int fm_macsec_config_kay_frame_treatment(struct fm_macsec_dev *fm_macsec_dev, ++ bool discard_uncontrolled); ++int fm_macsec_config_untag_frame_treatment(struct fm_macsec_dev *fm_macsec_dev, ++ fm_macsec_untag_frame_treatment treat_mode); ++int fm_macsec_config_pn_exhaustion_threshold(struct fm_macsec_dev *fm_macsec_dev, ++ uint32_t pnExhThr); ++int fm_macsec_config_keys_unreadable(struct fm_macsec_dev *fm_macsec_dev); ++int fm_macsec_config_sectag_without_sci(struct fm_macsec_dev *fm_macsec_dev); ++int fm_macsec_config_exception(struct fm_macsec_dev *fm_macsec_dev, ++ fm_macsec_exception exception, bool enable); ++int fm_macsec_get_revision(struct fm_macsec_dev *fm_macsec_dev, ++ int *macsec_revision); ++int fm_macsec_enable(struct fm_macsec_dev *fm_macsec_dev); ++int fm_macsec_disable(struct fm_macsec_dev *fm_macsec_dev); ++ ++ ++int fm_macsec_secy_config_exception(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ fm_macsec_secy_exception exception, ++ bool enable); ++int fm_macsec_secy_free(struct fm_macsec_secy_dev *fm_macsec_secy_dev); ++struct fm_macsec_secy_dev *fm_macsec_secy_config(struct fm_macsec_secy_params *secy_params); ++int fm_macsec_secy_init(struct fm_macsec_secy_dev *fm_macsec_secy_dev); ++int fm_macsec_secy_config_sci_insertion_mode(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ fm_macsec_sci_insertion_mode sci_insertion_mode); ++int fm_macsec_secy_config_protect_frames(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ bool protect_frames); ++int fm_macsec_secy_config_replay_window(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ bool replay_protect, uint32_t replay_window); ++int fm_macsec_secy_config_validation_mode(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ fm_macsec_valid_frame_behavior validate_frames); ++int fm_macsec_secy_config_confidentiality(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ bool confidentiality_enable, ++ uint32_t confidentiality_offset); ++int fm_macsec_secy_config_point_to_point(struct fm_macsec_secy_dev *fm_macsec_secy_dev); ++int fm_macsec_secy_config_event(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ fm_macsec_secy_event event, ++ bool enable); ++struct rx_sc_dev *fm_macsec_secy_create_rxsc(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct fm_macsec_secy_sc_params *params); ++int fm_macsec_secy_delete_rxsc(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc); ++int fm_macsec_secy_create_rx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc, macsec_an_t an, ++ uint32_t lowest_pn, macsec_sa_key_t key); ++int fm_macsec_secy_delete_rx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc, macsec_an_t an); ++int fm_macsec_secy_rxsa_enable_receive(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc, ++ macsec_an_t an); ++int fm_macsec_secy_rxsa_disable_receive(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc, ++ macsec_an_t an); ++int fm_macsec_secy_rxsa_update_next_pn(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc, ++ macsec_an_t an, uint32_t updt_next_pn); ++int fm_macsec_secy_rxsa_update_lowest_pn(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc, ++ macsec_an_t an, uint32_t updt_lowest_pn); ++int fm_macsec_secy_rxsa_modify_key(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc, ++ macsec_an_t an, macsec_sa_key_t key); ++int fm_macsec_secy_create_tx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ macsec_an_t an, macsec_sa_key_t key); ++int fm_macsec_secy_delete_tx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ macsec_an_t an); ++int fm_macsec_secy_txsa_modify_key(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ macsec_an_t next_active_an, ++ macsec_sa_key_t key); ++int fm_macsec_secy_txsa_set_active(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ macsec_an_t an); ++int fm_macsec_secy_txsa_get_active(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ macsec_an_t *p_an); ++int fm_macsec_secy_get_rxsc_phys_id(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc, uint32_t *sc_phys_id); ++int fm_macsec_secy_get_txsc_phys_id(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ uint32_t *sc_phys_id); ++ ++/** @} */ /* end of FM_LnxKern_ctrl_grp group */ ++/** @} */ /* end of FM_LnxKern_grp group */ ++ ++/* default values for initializing PTP 1588 timer clock */ ++#define DPA_PTP_NOMINAL_FREQ_PERIOD_SHIFT 2 /* power of 2 for better performance */ ++#define DPA_PTP_NOMINAL_FREQ_PERIOD_NS (1 << DPA_PTP_NOMINAL_FREQ_PERIOD_SHIFT) /* 4ns,250MHz */ ++ ++#endif /* __LNXWRP_FSL_FMAN_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/inc/xx/xx.h b/drivers/net/ethernet/freescale/sdk_fman/src/inc/xx/xx.h +new file mode 100644 +index 00000000..b183c86d +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/inc/xx/xx.h +@@ -0,0 +1,50 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __XX_H ++#define __XX_H ++ ++#include "xx_ext.h" ++ ++void * xx_Malloc(uint32_t n); ++void xx_Free(void *p); ++ ++void *xx_MallocSmart(uint32_t size, int memPartitionId, uint32_t align); ++void xx_FreeSmart(void *p); ++ ++/* never used: */ ++#define GetDeviceName(irq) ((char *)NULL) ++ ++int GetDeviceIrqNum(int irq); ++ ++ ++#endif /* __XX_H */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/system/Makefile b/drivers/net/ethernet/freescale/sdk_fman/src/system/Makefile +new file mode 100644 +index 00000000..667cd859 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/system/Makefile +@@ -0,0 +1,10 @@ ++# ++# Makefile for the Freescale Ethernet controllers ++# ++ccflags-y += -DVERSION=\"\" ++# ++#Include netcomm SW specific definitions ++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk ++# ++ ++obj-y += sys_io.o +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/system/sys_io.c b/drivers/net/ethernet/freescale/sdk_fman/src/system/sys_io.c +new file mode 100644 +index 00000000..c106a8b7 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/system/sys_io.c +@@ -0,0 +1,171 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++ ++#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) ++#define MODVERSIONS ++#endif ++#ifdef MODVERSIONS ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++#include ++#else ++#include ++#endif /* LINUX_VERSION_CODE */ ++#endif /* MODVERSIONS */ ++ ++#include ++#include ++ ++#include ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "string_ext.h" ++#include "list_ext.h" ++#include "sys_io_ext.h" ++ ++ ++#define __ERR_MODULE__ MODULE_UNKNOWN ++ ++ ++typedef struct { ++ uint64_t virtAddr; ++ uint64_t physAddr; ++ uint32_t size; ++ t_List node; ++} t_IoMap; ++#define IOMAP_OBJECT(ptr) LIST_OBJECT(ptr, t_IoMap, node) ++ ++LIST(mapsList); ++ ++ ++static void EnqueueIoMap(t_IoMap *p_IoMap) ++{ ++ uint32_t intFlags; ++ ++ intFlags = XX_DisableAllIntr(); ++ LIST_AddToTail(&p_IoMap->node, &mapsList); ++ XX_RestoreAllIntr(intFlags); ++} ++ ++static t_IoMap * FindIoMapByVirtAddr(uint64_t addr) ++{ ++ t_IoMap *p_IoMap; ++ t_List *p_Pos; ++ ++ LIST_FOR_EACH(p_Pos, &mapsList) ++ { ++ p_IoMap = IOMAP_OBJECT(p_Pos); ++ if ((addr >= p_IoMap->virtAddr) && (addr < p_IoMap->virtAddr+p_IoMap->size)) ++ return p_IoMap; ++ } ++ ++ return NULL; ++} ++ ++static t_IoMap * FindIoMapByPhysAddr(uint64_t addr) ++{ ++ t_IoMap *p_IoMap; ++ t_List *p_Pos; ++ ++ LIST_FOR_EACH(p_Pos, &mapsList) ++ { ++ p_IoMap = IOMAP_OBJECT(p_Pos); ++ if ((addr >= p_IoMap->physAddr) && (addr < p_IoMap->physAddr+p_IoMap->size)) ++ return p_IoMap; ++ } ++ ++ return NULL; ++} ++ ++t_Error SYS_RegisterIoMap (uint64_t virtAddr, uint64_t physAddr, uint32_t size) ++{ ++ t_IoMap *p_IoMap; ++ ++ p_IoMap = (t_IoMap*)XX_Malloc(sizeof(t_IoMap)); ++ if (!p_IoMap) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("message handler object!!!")); ++ memset(p_IoMap, 0, sizeof(t_IoMap)); ++ ++ p_IoMap->virtAddr = virtAddr; ++ p_IoMap->physAddr = physAddr; ++ p_IoMap->size = size; ++ ++ INIT_LIST(&p_IoMap->node); ++ EnqueueIoMap(p_IoMap); ++ ++ return E_OK; ++} ++ ++t_Error SYS_UnregisterIoMap (uint64_t virtAddr) ++{ ++ t_IoMap *p_IoMap = FindIoMapByVirtAddr(virtAddr); ++ if (!p_IoMap) ++ RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!")); ++ ++ LIST_Del(&p_IoMap->node); ++ XX_Free(p_IoMap); ++ ++ return E_OK; ++} ++ ++uint64_t SYS_PhysToVirt(uint64_t addr) ++{ ++ t_IoMap *p_IoMap = FindIoMapByPhysAddr(addr); ++ if (p_IoMap) ++ { ++ /* This is optimization - put the latest in the list-head - like a cache */ ++ if (mapsList.p_Next != &p_IoMap->node) ++ { ++ uint32_t intFlags = XX_DisableAllIntr(); ++ LIST_DelAndInit(&p_IoMap->node); ++ LIST_Add(&p_IoMap->node, &mapsList); ++ XX_RestoreAllIntr(intFlags); ++ } ++ return (uint64_t)(addr - p_IoMap->physAddr + p_IoMap->virtAddr); ++ } ++ return PTR_TO_UINT(phys_to_virt((unsigned long)addr)); ++} ++ ++uint64_t SYS_VirtToPhys(uint64_t addr) ++{ ++ t_IoMap *p_IoMap; ++ ++ if (addr == 0) ++ return 0; ++ ++ p_IoMap = FindIoMapByVirtAddr(addr); ++ if (p_IoMap) ++ return (uint64_t)(addr - p_IoMap->virtAddr + p_IoMap->physAddr); ++ return (uint64_t)virt_to_phys(UINT_TO_PTR(addr)); ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/Makefile b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/Makefile +new file mode 100644 +index 00000000..62713d62 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/Makefile +@@ -0,0 +1,19 @@ ++# ++# Makefile for the Freescale Ethernet controllers ++# ++ccflags-y += -DVERSION=\"\" ++# ++#Include netcomm SW specific definitions ++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk ++ ++NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc ++ ++ccflags-y += -I$(NCSW_FM_INC) ++ccflags-y += -I$(NET_DPA) ++ ++obj-y += fsl-ncsw-PFM.o ++obj-$(CONFIG_FSL_SDK_FMAN_TEST) += fman_test.o ++ ++fsl-ncsw-PFM-objs := lnxwrp_fm.o lnxwrp_fm_port.o lnxwrp_ioctls_fm.o \ ++ lnxwrp_sysfs.o lnxwrp_sysfs_fm.o lnxwrp_sysfs_fm_port.o ++obj-$(CONFIG_COMPAT) += lnxwrp_ioctls_fm_compat.o +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/fman_test.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/fman_test.c +new file mode 100644 +index 00000000..270d07b8 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/fman_test.c +@@ -0,0 +1,1665 @@ ++/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ @File fman_test.c ++ @Authors Pistirica Sorin Andrei ++ @Description FM Linux test environment ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* private headers */ ++#include "fm_ext.h" ++#include "lnxwrp_fsl_fman.h" ++#include "fm_port_ext.h" ++#if (DPAA_VERSION == 11) ++#include "../../Peripherals/FM/MAC/memac.h" ++#endif ++#include "fm_test_ioctls.h" ++#include "fsl_fman_test.h" ++ ++#include "dpaa_eth.h" ++#include "dpaa_eth_common.h" ++ ++#define FMT_FRM_WATERMARK 0xdeadbeefdeadbeeaLL ++ ++struct fmt_frame_s { ++ ioc_fmt_buff_desc_t buff; ++ struct list_head list; ++}; ++ ++struct fmt_fqs_s { ++ struct qman_fq fq_base; ++ bool init; ++ struct fmt_port_s *fmt_port_priv; ++}; ++ ++struct fmt_port_pcd_s { ++ int num_queues; ++ struct fmt_fqs_s *fmt_pcd_fqs; ++ uint32_t fqid_base; ++}; ++ ++/* char dev structure: fm test port */ ++struct fmt_port_s { ++ bool valid; ++ uint8_t id; ++ ioc_fmt_port_type port_type; ++ ioc_diag_mode diag; ++ bool compat_test_type; ++ ++ /* fm ports */ ++ /* ! for oh ports p_tx_fm_port_dev == p_rx_fm_port_dev && ++ * p_tx_port == p_rx_port */ ++ /* t_LnxWrpFmPortDev */ ++ struct fm_port *p_tx_port; ++ /* t_LnxWrpFmPortDev->h_Dev: t_FmPort */ ++ void *p_tx_fm_port_dev; ++ /* t_LnxWrpFmPortDev */ ++ struct fm_port *p_rx_port; ++ /* t_LnxWrpFmPortDev->h_Dev: t_FmPort */ ++ void *p_rx_fm_port_dev; ++ ++ void *p_mac_dev; ++ uint64_t fm_phys_base_addr; ++ ++ /* read/write queue manipulation */ ++ spinlock_t rx_q_lock; ++ struct list_head rx_q; ++ ++ /* tx queuee for injecting traffic */ ++ int num_of_tx_fqs; ++ struct fmt_fqs_s p_tx_fqs[FMAN_TEST_MAX_TX_FQS]; ++ ++ /* pcd private queues manipulation */ ++ struct fmt_port_pcd_s fmt_port_pcd; ++ ++ /* debugging stuff */ ++ ++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) ++ atomic_t enqueue_to_qman_frm; ++ atomic_t enqueue_to_rxq; ++ atomic_t dequeue_from_rxq; ++ atomic_t not_enqueue_to_rxq_wrong_frm; ++#endif ++ ++}; ++ ++/* The devices. */ ++struct fmt_s { ++ int major; ++ struct fmt_port_s ports[IOC_FMT_MAX_NUM_OF_PORTS]; ++ struct class *fmt_class; ++}; ++ ++/* fm test structure */ ++static struct fmt_s fm_test; ++ ++#if (DPAA_VERSION == 11) ++struct mac_priv_s { ++ t_Handle mac; ++}; ++#endif ++ ++#define DTSEC_BASE_ADDR 0x000e0000 ++#define DTSEC_MEM_RANGE 0x00002000 ++#define MAC_1G_MACCFG1 0x00000100 ++#define MAC_1G_LOOP_MASK 0x00000100 ++static int set_1gmac_loopback( ++ struct fmt_port_s *fmt_port, ++ bool en) ++{ ++#if (DPAA_VERSION <= 10) ++ uint32_t dtsec_idx = fmt_port->id; /* dtsec for which port */ ++ uint32_t dtsec_idx_off = dtsec_idx * DTSEC_MEM_RANGE; ++ phys_addr_t maccfg1_hw; ++ void *maccfg1_map; ++ uint32_t maccfg1_val; ++ ++ /* compute the maccfg1 register address */ ++ maccfg1_hw = fmt_port->fm_phys_base_addr + ++ (phys_addr_t)(DTSEC_BASE_ADDR + ++ dtsec_idx_off + ++ MAC_1G_MACCFG1); ++ ++ /* map register */ ++ maccfg1_map = ioremap(maccfg1_hw, sizeof(u32)); ++ ++ /* set register */ ++ maccfg1_val = in_be32(maccfg1_map); ++ if (en) ++ maccfg1_val |= MAC_1G_LOOP_MASK; ++ else ++ maccfg1_val &= ~MAC_1G_LOOP_MASK; ++ out_be32(maccfg1_map, maccfg1_val); ++ ++ /* unmap register */ ++ iounmap(maccfg1_map); ++#else ++ struct mac_device *mac_dev; ++ struct mac_priv_s *priv; ++ t_Memac *p_memac; ++ ++ if (!fmt_port) ++ return -EINVAL; ++ ++ mac_dev = (struct mac_device *)fmt_port->p_mac_dev; ++ ++ if (!mac_dev) ++ return -EINVAL; ++ ++ priv = macdev_priv(mac_dev); ++ ++ if (!priv) ++ return -EINVAL; ++ ++ p_memac = priv->mac; ++ ++ if (!p_memac) ++ return -EINVAL; ++ ++ memac_set_loopback(p_memac->p_MemMap, en); ++#endif ++ return 0; ++} ++ ++/* TODO: re-write this function */ ++static int set_10gmac_int_loopback( ++ struct fmt_port_s *fmt_port, ++ bool en) ++{ ++#ifndef FM_10G_MAC_NO_CTRL_LOOPBACK ++#define FM_10GMAC0_OFFSET 0x000f0000 ++#define FM_10GMAC_CMD_CONF_CTRL_OFFSET 0x8 ++#define CMD_CFG_LOOPBACK_EN 0x00000400 ++ ++ uint64_t base_addr, reg_addr; ++ uint32_t tmp_val; ++ ++ base_addr = fmt_port->fm_phys_base_addr + (FM_10GMAC0_OFFSET + ++ ((fmt_port->id-FM_MAX_NUM_OF_1G_RX_PORTS)*0x2000)); ++ ++ base_addr = PTR_TO_UINT(ioremap(base_addr, 0x1000)); ++ ++ reg_addr = base_addr + FM_10GMAC_CMD_CONF_CTRL_OFFSET; ++ tmp_val = GET_UINT32(*((uint32_t *)UINT_TO_PTR(reg_addr))); ++ if (en) ++ tmp_val |= CMD_CFG_LOOPBACK_EN; ++ else ++ tmp_val &= ~CMD_CFG_LOOPBACK_EN; ++ WRITE_UINT32(*((uint32_t *)UINT_TO_PTR(reg_addr)), tmp_val); ++ ++ iounmap(UINT_TO_PTR(base_addr)); ++ ++ return 0; ++#else ++ _fmt_err("TGEC don't have internal-loopback.\n"); ++ return -EPERM; ++#endif ++} ++ ++static int set_mac_int_loopback(struct fmt_port_s *fmt_port, bool en) ++{ ++ int _err = 0; ++ ++ switch (fmt_port->port_type) { ++ ++ case e_IOC_FMT_PORT_T_RXTX: ++ /* 1G port */ ++ if (fmt_port->id < FM_MAX_NUM_OF_1G_RX_PORTS) ++ _err = set_1gmac_loopback(fmt_port, en); ++ /* 10g port */ ++ else if ((fmt_port->id >= FM_MAX_NUM_OF_1G_RX_PORTS) && ++ (fmt_port->id < FM_MAX_NUM_OF_1G_RX_PORTS + ++ FM_MAX_NUM_OF_10G_RX_PORTS)) { ++ ++ _err = set_10gmac_int_loopback(fmt_port, en); ++ } else ++ _err = -EINVAL; ++ break; ++ /* op port does not have MAC (loopback mode) */ ++ case e_IOC_FMT_PORT_T_OP: ++ ++ _err = 0; ++ break; ++ default: ++ ++ _err = -EPERM; ++ break; ++ } ++ ++ return _err; ++} ++ ++static void enqueue_fmt_frame( ++ struct fmt_port_s *fmt_port, ++ struct fmt_frame_s *p_fmt_frame) ++{ ++ spinlock_t *rx_q_lock = NULL; ++ ++ rx_q_lock = &fmt_port->rx_q_lock; ++ ++ spin_lock(rx_q_lock); ++ list_add_tail(&p_fmt_frame->list, &fmt_port->rx_q); ++ spin_unlock(rx_q_lock); ++ ++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) ++ atomic_inc(&fmt_port->enqueue_to_rxq); ++#endif ++} ++ ++static struct fmt_frame_s *dequeue_fmt_frame( ++ struct fmt_port_s *fmt_port) ++{ ++ struct fmt_frame_s *p_fmt_frame = NULL; ++ spinlock_t *rx_q_lock = NULL; ++ ++ rx_q_lock = &fmt_port->rx_q_lock; ++ ++ spin_lock(rx_q_lock); ++ ++#define list_last_entry(ptr, type, member) list_entry((ptr)->prev, type, member) ++ ++ if (!list_empty(&fmt_port->rx_q)) { ++ p_fmt_frame = list_last_entry(&fmt_port->rx_q, ++ struct fmt_frame_s, ++ list); ++ list_del(&p_fmt_frame->list); ++ ++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) ++ atomic_inc(&fmt_port->dequeue_from_rxq); ++#endif ++ } ++ ++ spin_unlock(rx_q_lock); ++ ++ return p_fmt_frame; ++} ++ ++/* eth-dev -to- fmt port association */ ++struct fmt_port_s *match_dpa_to_fmt_port( ++ struct dpa_priv_s *dpa_priv) { ++ struct mac_device *mac_dev = dpa_priv->mac_dev; ++ struct fm_port *fm_port = (struct fm_port *) mac_dev; ++ struct fmt_port_s *fmt_port = NULL; ++ int i; ++ ++ _fmt_dbgr("calling...\n"); ++ ++ /* find the FM-test-port object */ ++ for (i = 0; i < IOC_FMT_MAX_NUM_OF_PORTS; i++) ++ if ((fm_test.ports[i].p_mac_dev && ++ mac_dev == fm_test.ports[i].p_mac_dev) || ++ fm_port == fm_test.ports[i].p_tx_port) { ++ ++ fmt_port = &fm_test.ports[i]; ++ break; ++ } ++ ++ _fmt_dbgr("called\n"); ++ return fmt_port; ++} ++ ++void dump_frame( ++ uint8_t *buffer, ++ uint32_t size) ++{ ++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) ++ unsigned int i; ++ ++ for (i = 0; i < size; i++) { ++ if (i%16 == 0) ++ printk(KERN_DEBUG "\n"); ++ printk(KERN_DEBUG "%2x ", *(buffer+i)); ++ } ++#endif ++ return; ++} ++ ++bool test_and_steal_frame(struct fmt_port_s *fmt_port, ++ uint32_t fqid, ++ uint8_t *buffer, ++ uint32_t size) ++{ ++ struct fmt_frame_s *p_fmt_frame = NULL; ++ bool test_and_steal_frame_frame; ++ uint32_t data_offset; ++ uint32_t i; ++ ++ _fmt_dbgr("calling...\n"); ++ ++ if (!fmt_port || !fmt_port->p_rx_fm_port_dev) ++ return false; ++ ++ /* check watermark */ ++ test_and_steal_frame_frame = false; ++ for (i = 0; i < size; i++) { ++ uint64_t temp = *((uint64_t *)(buffer + i)); ++ ++ if (temp == (uint64_t) FMT_FRM_WATERMARK) { ++ _fmt_dbgr("watermark found!\n"); ++ test_and_steal_frame_frame = true; ++ break; ++ } ++ } ++ ++ if (!test_and_steal_frame_frame) { ++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) ++ atomic_inc(&fmt_port->not_enqueue_to_rxq_wrong_frm); ++#endif ++ _fmt_dbgr("NOT watermark found!\n"); ++ return false; ++ } ++ ++ /* do not enqueue the tx conf/err frames */ ++ if ((fqid == FMT_TX_CONF_Q) || (fqid == FMT_TX_ERR_Q)) ++ goto _test_and_steal_frame_return_true; ++ ++ _fmt_dbgr("on port %d got FMUC frame\n", fmt_port->id); ++ data_offset = FM_PORT_GetBufferDataOffset( ++ fmt_port->p_rx_fm_port_dev); ++ ++ p_fmt_frame = kmalloc(sizeof(struct fmt_frame_s), GFP_KERNEL); ++ ++ /* dump frame... no more space left on device */ ++ if (p_fmt_frame == NULL) { ++ _fmt_err("no space left on device!\n"); ++ goto _test_and_steal_frame_return_true; ++ } ++ ++ memset(p_fmt_frame, 0, sizeof(struct fmt_frame_s)); ++ p_fmt_frame->buff.p_data = kmalloc(size * sizeof(uint8_t), GFP_KERNEL); ++ ++ /* No more space left on device*/ ++ if (p_fmt_frame->buff.p_data == NULL) { ++ _fmt_err("no space left on device!\n"); ++ kfree(p_fmt_frame); ++ goto _test_and_steal_frame_return_true; ++ } ++ ++ p_fmt_frame->buff.size = size-data_offset; ++ p_fmt_frame->buff.qid = fqid; ++ ++ memcpy(p_fmt_frame->buff.p_data, ++ (uint8_t *)PTR_MOVE(buffer, data_offset), ++ p_fmt_frame->buff.size); ++ ++ memcpy(p_fmt_frame->buff.buff_context.fm_prs_res, ++ FM_PORT_GetBufferPrsResult(fmt_port->p_rx_fm_port_dev, ++ (char *)buffer), ++ 32); ++ ++ /* enqueue frame - this frame will go to us */ ++ enqueue_fmt_frame(fmt_port, p_fmt_frame); ++ ++_test_and_steal_frame_return_true: ++ return true; ++} ++ ++static int fmt_fq_release(const struct qm_fd *fd) ++{ ++ struct dpa_bp *_dpa_bp; ++ struct bm_buffer _bmb; ++ ++ if (fd->format == qm_fd_contig) { ++ _dpa_bp = dpa_bpid2pool(fd->bpid); ++ BUG_ON(IS_ERR(_dpa_bp)); ++ ++ _bmb.hi = fd->addr_hi; ++ _bmb.lo = fd->addr_lo; ++ ++ while (bman_release(_dpa_bp->pool, &_bmb, 1, 0)) ++ cpu_relax(); ++ ++ } else { ++ _fmt_err("frame not supported !\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* sync it w/ dpaa_eth.c: DPA_BP_HEAD */ ++#define DPA_BP_HEADROOM (DPA_TX_PRIV_DATA_SIZE + \ ++ fm_get_rx_extra_headroom() + \ ++ DPA_PARSE_RESULTS_SIZE + \ ++ DPA_HASH_RESULTS_SIZE) ++#define MAC_HEADER_LENGTH 14 ++#define L2_AND_HEADROOM_OFF ((DPA_BP_HEADROOM) + (MAC_HEADER_LENGTH)) ++ ++/* dpa ingress hooks definition */ ++enum dpaa_eth_hook_result fmt_rx_default_hook( ++ struct sk_buff *skb, ++ struct net_device *net_dev, ++ u32 fqid) ++{ ++ struct dpa_priv_s *dpa_priv = NULL; ++ struct fmt_port_s *fmt_port = NULL; ++ uint8_t *buffer; ++ uint32_t buffer_len; ++ ++ _fmt_dbgr("calling...\n"); ++ ++ dpa_priv = netdev_priv(net_dev); ++ fmt_port = match_dpa_to_fmt_port(dpa_priv); ++ ++ /* conversion from skb to fd: ++ * skb cames processed for L3, so we need to go back for ++ * layer 2 offset */ ++ buffer = (uint8_t *)(skb->data - ((int)L2_AND_HEADROOM_OFF)); ++ buffer_len = skb->len + ((int)L2_AND_HEADROOM_OFF); ++ ++ /* if is not out frame let dpa to handle it */ ++ if (test_and_steal_frame(fmt_port, ++ FMT_RX_DFLT_Q, ++ buffer, ++ buffer_len)) ++ goto _fmt_rx_default_hook_stolen; ++ ++ _fmt_dbgr("called:DPAA_ETH_CONTINUE.\n"); ++ return DPAA_ETH_CONTINUE; ++ ++_fmt_rx_default_hook_stolen: ++ dev_kfree_skb(skb); ++ ++ _fmt_dbgr("called:DPAA_ETH_STOLEN.\n"); ++ return DPAA_ETH_STOLEN; ++} ++ ++enum dpaa_eth_hook_result fmt_rx_error_hook( ++ struct net_device *net_dev, ++ const struct qm_fd *fd, ++ u32 fqid) ++{ ++ struct dpa_priv_s *dpa_priv = NULL; ++ struct dpa_bp *dpa_bp = NULL; ++ struct fmt_port_s *fmt_port = NULL; ++ void *fd_virt_addr = NULL; ++ dma_addr_t addr = qm_fd_addr(fd); ++ ++ _fmt_dbgr("calling...\n"); ++ ++ dpa_priv = netdev_priv(net_dev); ++ fmt_port = match_dpa_to_fmt_port(dpa_priv); ++ ++ /* dpaa doesn't do this... we have to do it here */ ++ dpa_bp = dpa_bpid2pool(fd->bpid); ++ dma_unmap_single(dpa_bp->dev, addr, dpa_bp->size, DMA_BIDIRECTIONAL); ++ ++ fd_virt_addr = phys_to_virt(addr); ++ /* if is not out frame let dpa to handle it */ ++ if (test_and_steal_frame(fmt_port, ++ FMT_RX_ERR_Q, ++ fd_virt_addr, ++ fd->length20 + fd->offset)) { ++ goto _fmt_rx_error_hook_stolen; ++ } ++ ++ _fmt_dbgr("called:DPAA_ETH_CONTINUE.\n"); ++ return DPAA_ETH_CONTINUE; ++ ++_fmt_rx_error_hook_stolen: ++ /* the frame data doesn't matter, ++ * so, no mapping is needed */ ++ fmt_fq_release(fd); ++ ++ _fmt_dbgr("called:DPAA_ETH_STOLEN.\n"); ++ return DPAA_ETH_STOLEN; ++} ++ ++enum dpaa_eth_hook_result fmt_tx_confirm_hook( ++ struct net_device *net_dev, ++ const struct qm_fd *fd, ++ u32 fqid) ++{ ++ struct dpa_priv_s *dpa_priv = NULL; ++ struct fmt_port_s *fmt_port = NULL; ++ dma_addr_t addr = qm_fd_addr(fd); ++ void *fd_virt_addr = NULL; ++ uint32_t fd_len = 0; ++ ++ _fmt_dbgr("calling...\n"); ++ ++ dpa_priv = netdev_priv(net_dev); ++ fmt_port = match_dpa_to_fmt_port(dpa_priv); ++ ++ fd_virt_addr = phys_to_virt(addr); ++ fd_len = fd->length20 + fd->offset; ++ ++ if (fd_len > fm_get_max_frm()) { ++ _fmt_err("tx confirm bad frame size: %u!\n", fd_len); ++ goto _fmt_tx_confirm_hook_continue; ++ } ++ ++ if (test_and_steal_frame(fmt_port, ++ FMT_TX_CONF_Q, ++ fd_virt_addr, ++ fd_len)) ++ goto _fmt_tx_confirm_hook_stolen; ++ ++_fmt_tx_confirm_hook_continue: ++ _fmt_dbgr("called:DPAA_ETH_CONTINUE.\n"); ++ return DPAA_ETH_CONTINUE; ++ ++_fmt_tx_confirm_hook_stolen: ++ kfree(fd_virt_addr); ++ ++ _fmt_dbgr("called:DPAA_ETH_STOLEN.\n"); ++ return DPAA_ETH_STOLEN; ++} ++ ++enum dpaa_eth_hook_result fmt_tx_confirm_error_hook( ++ struct net_device *net_dev, ++ const struct qm_fd *fd, ++ u32 fqid) ++{ ++ struct dpa_priv_s *dpa_priv = NULL; ++ struct fmt_port_s *fmt_port = NULL; ++ dma_addr_t addr = qm_fd_addr(fd); ++ void *fd_virt_addr = NULL; ++ uint32_t fd_len = 0; ++ ++ _fmt_dbgr("calling...\n"); ++ ++ dpa_priv = netdev_priv(net_dev); ++ fmt_port = match_dpa_to_fmt_port(dpa_priv); ++ ++ fd_virt_addr = phys_to_virt(addr); ++ fd_len = fd->length20 + fd->offset; ++ ++ if (fd_len > fm_get_max_frm()) { ++ _fmt_err("tx confirm err bad frame size: %u !\n", fd_len); ++ goto _priv_ingress_tx_err_continue; ++ } ++ ++ if (test_and_steal_frame(fmt_port, FMT_TX_ERR_Q, fd_virt_addr, fd_len)) ++ goto _priv_ingress_tx_err_stolen; ++ ++_priv_ingress_tx_err_continue: ++ _fmt_dbgr("called:DPAA_ETH_CONTINUE.\n"); ++ return DPAA_ETH_CONTINUE; ++ ++_priv_ingress_tx_err_stolen: ++ kfree(fd_virt_addr); ++ ++ _fmt_dbgr("called:DPAA_ETH_STOLEN.\n"); ++ return DPAA_ETH_STOLEN; ++} ++ ++/* egress callbacks definition */ ++enum qman_cb_dqrr_result fmt_egress_dqrr( ++ struct qman_portal *portal, ++ struct qman_fq *fq, ++ const struct qm_dqrr_entry *dqrr) ++{ ++ /* this callback should never be called */ ++ BUG(); ++ return qman_cb_dqrr_consume; ++} ++ ++static void fmt_egress_error_dqrr( ++ struct qman_portal *p, ++ struct qman_fq *fq, ++ const struct qm_mr_entry *msg) ++{ ++ uint8_t *fd_virt_addr = NULL; ++ ++ /* tx failure, on the ern callback - release buffer */ ++ fd_virt_addr = (uint8_t *)phys_to_virt(qm_fd_addr(&msg->ern.fd)); ++ kfree(fd_virt_addr); ++ ++ return; ++} ++ ++static const struct qman_fq fmt_egress_fq = { ++ .cb = { .dqrr = fmt_egress_dqrr, ++ .ern = fmt_egress_error_dqrr, ++ .fqs = NULL} ++}; ++ ++int fmt_fq_alloc( ++ struct fmt_fqs_s *fmt_fqs, ++ const struct qman_fq *qman_fq, ++ uint32_t fqid, uint32_t flags, ++ uint16_t channel, uint8_t wq) ++{ ++ int _errno = 0; ++ ++ _fmt_dbg("calling...\n"); ++ ++ fmt_fqs->fq_base = *qman_fq; ++ ++ if (fqid == 0) { ++ flags |= QMAN_FQ_FLAG_DYNAMIC_FQID; ++ flags &= ~QMAN_FQ_FLAG_NO_MODIFY; ++ } else ++ flags &= ~QMAN_FQ_FLAG_DYNAMIC_FQID; ++ ++ fmt_fqs->init = !(flags & QMAN_FQ_FLAG_NO_MODIFY); ++ ++ _errno = qman_create_fq(fqid, flags, &fmt_fqs->fq_base); ++ if (_errno < 0) { ++ _fmt_err("frame queues create failed.\n"); ++ return -EINVAL; ++ } ++ ++ if (fmt_fqs->init) { ++ struct qm_mcc_initfq initfq; ++ ++ initfq.we_mask = QM_INITFQ_WE_DESTWQ; ++ initfq.fqd.dest.channel = channel; ++ initfq.fqd.dest.wq = wq; ++ ++ _errno = qman_init_fq(&fmt_fqs->fq_base, ++ QMAN_INITFQ_FLAG_SCHED, ++ &initfq); ++ if (_errno < 0) { ++ _fmt_err("frame queues init erorr.\n"); ++ qman_destroy_fq(&fmt_fqs->fq_base, 0); ++ return -EINVAL; ++ } ++ } ++ ++ _fmt_dbg("called.\n"); ++ return 0; ++} ++ ++static int fmt_fq_free(struct fmt_fqs_s *fmt_fq) ++{ ++ int _err = 0; ++ ++ _fmt_dbg("calling...\n"); ++ ++ if (fmt_fq->init) { ++ _err = qman_retire_fq(&fmt_fq->fq_base, NULL); ++ if (unlikely(_err < 0)) ++ _fmt_err("qman_retire_fq(%u) = %d\n", ++ qman_fq_fqid(&fmt_fq->fq_base), _err); ++ ++ _err = qman_oos_fq(&fmt_fq->fq_base); ++ if (unlikely(_err < 0)) ++ _fmt_err("qman_oos_fq(%u) = %d\n", ++ qman_fq_fqid(&fmt_fq->fq_base), _err); ++ } ++ ++ qman_destroy_fq(&fmt_fq->fq_base, 0); ++ ++ _fmt_dbg("called.\n"); ++ return _err; ++} ++ ++/* private pcd dqrr calbacks */ ++static enum qman_cb_dqrr_result fmt_pcd_dqrr( ++ struct qman_portal *portal, ++ struct qman_fq *fq, ++ const struct qm_dqrr_entry *dq) ++{ ++ struct dpa_bp *dpa_bp = NULL; ++ dma_addr_t addr = qm_fd_addr(&dq->fd); ++ uint8_t *fd_virt_addr = NULL; ++ struct fmt_port_s *fmt_port; ++ struct fmt_port_pcd_s *fmt_port_pcd; ++ uint32_t relative_fqid = 0; ++ uint32_t fd_len = 0; ++ ++ _fmt_dbgr("calling...\n"); ++ ++ /* upcast - from pcd_alloc_fq */ ++ fmt_port = ((struct fmt_fqs_s *)fq)->fmt_port_priv; ++ if (!fmt_port) { ++ _fmt_err(" wrong fmt port -to- fq match.\n"); ++ goto _fmt_pcd_dqrr_return; ++ } ++ fmt_port_pcd = &fmt_port->fmt_port_pcd; ++ ++ relative_fqid = dq->fqid - fmt_port_pcd->fqid_base; ++ _fmt_dbgr("pcd dqrr got frame on relative fq:%u@base:%u\n", ++ relative_fqid, fmt_port_pcd->fqid_base); ++ ++ fd_len = dq->fd.length20 + dq->fd.offset; ++ ++ if (fd_len > fm_get_max_frm()) { ++ _fmt_err("pcd dqrr wrong frame size: %u (%u:%u)!\n", ++ fd_len, dq->fd.length20, dq->fd.offset); ++ goto _fmt_pcd_dqrr_return; ++ } ++ ++ dpa_bp = dpa_bpid2pool(dq->fd.bpid); ++ dma_unmap_single(dpa_bp->dev, addr, dpa_bp->size, DMA_BIDIRECTIONAL); ++ ++ fd_virt_addr = phys_to_virt(addr); ++ if (!test_and_steal_frame(fmt_port, relative_fqid, fd_virt_addr, ++ fd_len)) { ++ ++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) ++ atomic_inc(&fmt_port->not_enqueue_to_rxq_wrong_frm); ++#endif ++ _fmt_wrn("pcd dqrr unrecognized frame@fqid: %u," ++ " frame len: %u (dropped).\n", ++ dq->fqid, dq->fd.length20); ++ dump_frame(fd_virt_addr, fd_len); ++ } ++ ++_fmt_pcd_dqrr_return: ++ /* no need to map again here */ ++ fmt_fq_release(&dq->fd); ++ ++ _fmt_dbgr("calle.\n"); ++ return qman_cb_dqrr_consume; ++} ++ ++static void fmt_pcd_err_dqrr( ++ struct qman_portal *qm, ++ struct qman_fq *fq, ++ const struct qm_mr_entry *msg) ++{ ++ _fmt_err("this callback should never be called.\n"); ++ BUG(); ++ return; ++} ++ ++static void fmt_pcd_fqs_dqrr( ++ struct qman_portal *qm, ++ struct qman_fq *fq, ++ const struct qm_mr_entry *msg) ++{ ++ _fmt_dbg(" fq state(0x%x)@fqid(%u.\n", msg->fq.fqs, msg->fq.fqid); ++ return; ++} ++ ++/* private pcd queue template */ ++static const struct qman_fq pcd_fq = { ++ .cb = { .dqrr = fmt_pcd_dqrr, ++ .ern = fmt_pcd_err_dqrr, ++ .fqs = fmt_pcd_fqs_dqrr} ++}; ++ ++/* defined as weak in dpaa driver. */ ++/* ! parameters come from IOCTL call - US */ ++int dpa_alloc_pcd_fqids( ++ struct device *dev, ++ uint32_t num, uint8_t alignment, ++ uint32_t *base_fqid) ++{ ++ int _err = 0, i; ++ struct net_device *net_dev = NULL; ++ struct dpa_priv_s *dpa_priv = NULL; ++ struct fmt_port_pcd_s *fmt_port_pcd = NULL; ++ struct fmt_fqs_s *fmt_fqs = NULL; ++ struct fmt_port_s *fmt_port = NULL; ++ int num_allocated = 0; ++ ++ _fmt_dbg("calling...\n"); ++ ++ net_dev = (typeof(net_dev))dev_get_drvdata(dev); ++ dpa_priv = (typeof(dpa_priv))netdev_priv(net_dev); ++ ++ if (!netif_msg_probe(dpa_priv)) { ++ _fmt_err("dpa not probe.\n"); ++ _err = -ENODEV; ++ goto _pcd_alloc_fqs_err; ++ } ++ ++ fmt_port = match_dpa_to_fmt_port(dpa_priv); ++ if (!fmt_port) { ++ _fmt_err("fmt port not found."); ++ _err = -EINVAL; ++ goto _pcd_alloc_fqs_err; ++ } ++ ++ fmt_port_pcd = &fmt_port->fmt_port_pcd; ++ ++ num_allocated = qman_alloc_fqid_range(base_fqid, num, alignment, 0); ++ ++ if ((num_allocated <= 0) || ++ (num_allocated < num) || ++ (alignment && (*base_fqid) % alignment)) { ++ *base_fqid = 0; ++ _fmt_err("Failed to alloc pcd fqs rang.\n"); ++ _err = -EINVAL; ++ goto _pcd_alloc_fqs_err; ++ } ++ ++ _fmt_dbg("wanted %d fqs(align %d), got %d fqids@%u.\n", ++ num, alignment, num_allocated, *base_fqid); ++ ++ /* alloc pcd queues */ ++ fmt_port_pcd->fmt_pcd_fqs = kmalloc(num_allocated * ++ sizeof(struct fmt_fqs_s), ++ GFP_KERNEL); ++ fmt_port_pcd->num_queues = num_allocated; ++ fmt_port_pcd->fqid_base = *base_fqid; ++ fmt_fqs = fmt_port_pcd->fmt_pcd_fqs; ++ ++ /* alloc the pcd queues */ ++ for (i = 0; i < num_allocated; i++, fmt_fqs++) { ++ _err = fmt_fq_alloc( ++ fmt_fqs, ++ &pcd_fq, ++ (*base_fqid) + i, QMAN_FQ_FLAG_NO_ENQUEUE, ++ dpa_priv->channel, 7); ++ ++ if (_err < 0) ++ goto _pcd_alloc_fqs_err; ++ ++ /* upcast to identify from where the frames came from */ ++ fmt_fqs->fmt_port_priv = fmt_port; ++ } ++ ++ _fmt_dbg("called.\n"); ++ return _err; ++_pcd_alloc_fqs_err: ++ if (num_allocated > 0) ++ qman_release_fqid_range(*base_fqid, num_allocated); ++ /*TODO: free fmt_pcd_fqs if are any */ ++ ++ _fmt_dbg("called(_err:%d).\n", _err); ++ return _err; ++} ++ ++/* defined as weak in dpaa driver. */ ++int dpa_free_pcd_fqids( ++ struct device *dev, ++ uint32_t base_fqid) ++{ ++ ++ int _err = 0, i; ++ struct net_device *net_dev = NULL; ++ struct dpa_priv_s *dpa_priv = NULL; ++ struct fmt_port_pcd_s *fmt_port_pcd = NULL; ++ struct fmt_fqs_s *fmt_fqs = NULL; ++ struct fmt_port_s *fmt_port = NULL; ++ int num_allocated = 0; ++ ++ _fmt_dbg("calling...\n"); ++ ++ net_dev = (typeof(net_dev))dev_get_drvdata(dev); ++ dpa_priv = (typeof(dpa_priv))netdev_priv(net_dev); ++ ++ if (!netif_msg_probe(dpa_priv)) { ++ _fmt_err("dpa not probe.\n"); ++ _err = -ENODEV; ++ goto _pcd_free_fqs_err; ++ } ++ ++ fmt_port = match_dpa_to_fmt_port(dpa_priv); ++ if (!fmt_port) { ++ _fmt_err("fmt port not found."); ++ _err = -EINVAL; ++ goto _pcd_free_fqs_err; ++ } ++ ++ fmt_port_pcd = &fmt_port->fmt_port_pcd; ++ num_allocated = fmt_port_pcd->num_queues; ++ fmt_fqs = fmt_port_pcd->fmt_pcd_fqs; ++ ++ for (i = 0; i < num_allocated; i++, fmt_fqs++) ++ fmt_fq_free(fmt_fqs); ++ ++ qman_release_fqid_range(base_fqid,num_allocated); ++ ++ kfree(fmt_port_pcd->fmt_pcd_fqs); ++ memset(fmt_port_pcd, 0, sizeof(*fmt_port_pcd)); ++ ++ /* debugging stuff */ ++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) ++ _fmt_dbg(" portid: %u.\n", fmt_port->id); ++ _fmt_dbg(" frames enqueue to qman: %u.\n", ++ atomic_read(&fmt_port->enqueue_to_qman_frm)); ++ _fmt_dbg(" frames enqueue to rxq: %u.\n", ++ atomic_read(&fmt_port->enqueue_to_rxq)); ++ _fmt_dbg(" frames dequeue from rxq: %u.\n", ++ atomic_read(&fmt_port->dequeue_from_rxq)); ++ _fmt_dbg(" frames not enqueue to rxq - wrong frm: %u.\n", ++ atomic_read(&fmt_port->not_enqueue_to_rxq_wrong_frm)); ++ atomic_set(&fmt_port->enqueue_to_qman_frm, 0); ++ atomic_set(&fmt_port->enqueue_to_rxq, 0); ++ atomic_set(&fmt_port->dequeue_from_rxq, 0); ++ atomic_set(&fmt_port->not_enqueue_to_rxq_wrong_frm, 0); ++#endif ++ return 0; ++ ++_pcd_free_fqs_err: ++ return _err; ++} ++ ++static int fmt_port_init( ++ struct fmt_port_s *fmt_port, ++ ioc_fmt_port_param_t *p_Params) ++{ ++ struct device_node *fm_node, *fm_port_node; ++ const uint32_t *uint32_prop; ++ int _errno = 0, lenp = 0, i; ++ static struct of_device_id fm_node_of_match[] = { ++ { .compatible = "fsl,fman", }, ++ { /* end of list */ }, ++ }; ++ ++ _fmt_dbg("calling...\n"); ++ ++ /* init send/receive tu US list */ ++ INIT_LIST_HEAD(&fmt_port->rx_q); ++ ++ /* check parameters */ ++ if (p_Params->num_tx_queues > FMAN_TEST_MAX_TX_FQS || ++ p_Params->fm_port_id > IOC_FMT_MAX_NUM_OF_PORTS) { ++ _fmt_dbg("wrong test parameters.\n"); ++ return -EINVAL; ++ } ++ ++ /* set port parameters */ ++ fmt_port->num_of_tx_fqs = p_Params->num_tx_queues; ++ fmt_port->id = p_Params->fm_port_id; ++ fmt_port->port_type = p_Params->fm_port_type; ++ fmt_port->diag = e_IOC_DIAG_MODE_NONE; ++ ++ /* init debugging stuff */ ++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) ++ atomic_set(&fmt_port->enqueue_to_qman_frm, 0); ++ atomic_set(&fmt_port->enqueue_to_rxq, 0); ++ atomic_set(&fmt_port->dequeue_from_rxq, 0); ++ atomic_set(&fmt_port->not_enqueue_to_rxq_wrong_frm, 0); ++#endif ++ ++ /* TODO: This should be done at probe time not at runtime ++ * very ugly function */ ++ /* fill fmt port properties from dts */ ++ for_each_matching_node(fm_node, fm_node_of_match) { ++ ++ uint32_prop = (uint32_t *)of_get_property(fm_node, ++ "cell-index", &lenp); ++ if (unlikely(uint32_prop == NULL)) { ++ _fmt_wrn("of_get_property(%s, cell-index) invalid", ++ fm_node->full_name); ++ return -EINVAL; ++ } ++ if (WARN_ON(lenp != sizeof(uint32_t))) { ++ _fmt_wrn("of_get_property(%s, cell-index) invalid", ++ fm_node->full_name); ++ return -EINVAL; ++ } ++ ++ if (*uint32_prop == p_Params->fm_id) { ++ struct resource res; ++ ++ /* Get the FM address */ ++ _errno = of_address_to_resource(fm_node, 0, &res); ++ if (unlikely(_errno < 0)) { ++ _fmt_wrn("of_address_to_resource() = %u.\n", _errno); ++ return -EINVAL; ++ } ++ ++ fmt_port->fm_phys_base_addr = res.start; ++ ++ for_each_child_of_node(fm_node, fm_port_node) { ++ struct platform_device *of_dev; ++ ++ if (!of_device_is_available(fm_port_node)) ++ continue; ++ ++ uint32_prop = (uint32_t *)of_get_property( ++ fm_port_node, ++ "cell-index", ++ &lenp); ++ if (uint32_prop == NULL) ++ continue; ++ ++ if (of_device_is_compatible(fm_port_node, ++ "fsl,fman-port-oh") && ++ (fmt_port->port_type == e_IOC_FMT_PORT_T_OP)) { ++ ++ if (*uint32_prop == fmt_port->id) { ++ of_dev = of_find_device_by_node(fm_port_node); ++ if (unlikely(of_dev == NULL)) { ++ _fmt_wrn("fm id invalid\n"); ++ return -EINVAL; ++ } ++ ++ fmt_port->p_tx_port = ++ fm_port_bind(&of_dev->dev); ++ fmt_port->p_tx_fm_port_dev = ++ (void *)fm_port_get_handle( ++ fmt_port->p_tx_port); ++ fmt_port->p_rx_port = ++ fmt_port->p_tx_port; ++ fmt_port->p_rx_fm_port_dev = ++ fmt_port->p_tx_fm_port_dev; ++ fmt_port->p_mac_dev = NULL; ++ break; ++ } ++ } else if ((*uint32_prop == fmt_port->id) && ++ fmt_port->port_type == e_IOC_FMT_PORT_T_RXTX) { ++ ++ of_dev = of_find_device_by_node(fm_port_node); ++ if (unlikely(of_dev == NULL)) { ++ _fmt_wrn("dtb fm id invalid value"); ++ return -EINVAL; ++ } ++ ++ if (of_device_is_compatible(fm_port_node, ++ "fsl,fman-port-1g-tx")) { ++ fmt_port->p_tx_port = ++ fm_port_bind(&of_dev->dev); ++ fmt_port->p_tx_fm_port_dev = (void *) ++ fm_port_get_handle( ++ fmt_port->p_tx_port); ++ } else if (of_device_is_compatible(fm_port_node, ++ "fsl,fman-port-1g-rx")) { ++ fmt_port->p_rx_port = ++ fm_port_bind(&of_dev->dev); ++ fmt_port->p_rx_fm_port_dev = (void *) ++ fm_port_get_handle( ++ fmt_port->p_rx_port); ++ } else if (of_device_is_compatible(fm_port_node, ++ "fsl,fman-1g-mac") || ++ of_device_is_compatible(fm_port_node, ++ "fsl,fman-memac")) ++ fmt_port->p_mac_dev = ++ (typeof(fmt_port->p_mac_dev)) ++ dev_get_drvdata(&of_dev->dev); ++ else ++ continue; ++ ++ if (fmt_port->p_tx_fm_port_dev && ++ fmt_port->p_rx_fm_port_dev && fmt_port->p_mac_dev) ++ break; ++ } else if (((*uint32_prop + FM_MAX_NUM_OF_1G_RX_PORTS) == ++ fmt_port->id) && ++ fmt_port->port_type == e_IOC_FMT_PORT_T_RXTX) { ++ ++ of_dev = of_find_device_by_node(fm_port_node); ++ if (unlikely(of_dev == NULL)) { ++ _fmt_wrn("dtb fm id invalid value\n"); ++ return -EINVAL; ++ } ++ ++ if (of_device_is_compatible(fm_port_node, ++ "fsl,fman-port-10g-tx")) { ++ fmt_port->p_tx_port = ++ fm_port_bind(&of_dev->dev); ++ fmt_port->p_tx_fm_port_dev = (void *) ++ fm_port_get_handle( ++ fmt_port->p_tx_port); ++ } else if (of_device_is_compatible(fm_port_node, ++ "fsl,fman-port-10g-rx")) { ++ fmt_port->p_rx_port = ++ fm_port_bind(&of_dev->dev); ++ fmt_port->p_rx_fm_port_dev = (void *) ++ fm_port_get_handle( ++ fmt_port->p_rx_port); ++ } else if (of_device_is_compatible(fm_port_node, ++ "fsl,fman-10g-mac") || ++ of_device_is_compatible(fm_port_node, ++ "fsl,fman-memac")) ++ fmt_port->p_mac_dev = ++ (typeof(fmt_port->p_mac_dev)) ++ dev_get_drvdata(&of_dev->dev); ++ else ++ continue; ++ ++ if (fmt_port->p_tx_fm_port_dev && ++ fmt_port->p_rx_fm_port_dev && fmt_port->p_mac_dev) ++ break; ++ } ++ } /* for_each_child */ ++ } ++ } /* for each matching node */ ++ ++ if (fmt_port->p_tx_fm_port_dev == 0 || ++ fmt_port->p_rx_fm_port_dev == 0) { ++ ++ _fmt_err("bad fm port pointers.\n"); ++ return -EINVAL; ++ } ++ ++ _fmt_dbg("alloc %u tx queues.\n", fmt_port->num_of_tx_fqs); ++ ++ /* init fman test egress dynamic frame queues */ ++ for (i = 0; i < fmt_port->num_of_tx_fqs; i++) { ++ int _errno; ++ _errno = fmt_fq_alloc( ++ &fmt_port->p_tx_fqs[i], ++ &fmt_egress_fq, ++ 0, ++ QMAN_FQ_FLAG_TO_DCPORTAL, ++ fm_get_tx_port_channel(fmt_port->p_tx_port), ++ i); ++ ++ if (_errno < 0) { ++ _fmt_err("tx queues allocation failed.\n"); ++ /* TODO: memory leak here if 1 queue is allocated and ++ * next queues are failing ... */ ++ return -EINVAL; ++ } ++ } ++ ++ /* port is valid and ready to use. */ ++ fmt_port->valid = TRUE; ++ ++ _fmt_dbg("called.\n"); ++ return 0; ++} ++ ++/* fm test chardev functions */ ++static int fmt_open(struct inode *inode, struct file *file) ++{ ++ unsigned int minor = iminor(inode); ++ ++ _fmt_dbg("calling...\n"); ++ ++ if (file->private_data != NULL) ++ return 0; ++ ++ /* The minor represent the port number. ++ * Set the port structure accordingly, thus all the operations ++ * will be done on this port. */ ++ if ((minor >= DEV_FM_TEST_PORTS_MINOR_BASE) && ++ (minor < DEV_FM_TEST_MAX_MINORS)) ++ file->private_data = &fm_test.ports[minor]; ++ else ++ return -ENXIO; ++ ++ _fmt_dbg("called.\n"); ++ return 0; ++} ++ ++static int fmt_close(struct inode *inode, struct file *file) ++{ ++ struct fmt_port_s *fmt_port = NULL; ++ struct fmt_frame_s *fmt_frame = NULL; ++ ++ int err = 0; ++ ++ _fmt_dbg("calling...\n"); ++ ++ fmt_port = file->private_data; ++ if (!fmt_port) ++ return -ENODEV; ++ ++ /* Close the current test port by invalidating it. */ ++ fmt_port->valid = FALSE; ++ ++ /* clean the fmt port queue */ ++ while ((fmt_frame = dequeue_fmt_frame(fmt_port)) != NULL) { ++ if (fmt_frame && fmt_frame->buff.p_data){ ++ kfree(fmt_frame->buff.p_data); ++ kfree(fmt_frame); ++ } ++ } ++ ++ /* !!! the qman queues are cleaning from fm_ioctl... ++ * - very ugly */ ++ ++ _fmt_dbg("called.\n"); ++ return err; ++} ++ ++static int fmt_ioctls(unsigned int minor, ++ struct file *file, ++ unsigned int cmd, ++ unsigned long arg, ++ bool compat) ++{ ++ struct fmt_port_s *fmt_port = NULL; ++ ++ _fmt_dbg("IOCTL minor:%u " ++ " arg:0x%08lx ioctl cmd (0x%08x):(0x%02x:0x%02x.\n", ++ minor, arg, cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); ++ ++ fmt_port = file->private_data; ++ if (!fmt_port) { ++ _fmt_err("invalid fmt port.\n"); ++ return -ENODEV; ++ } ++ ++ /* set test type properly */ ++ if (compat) ++ fmt_port->compat_test_type = true; ++ else ++ fmt_port->compat_test_type = false; ++ ++ switch (cmd) { ++ case FMT_PORT_IOC_INIT: ++ { ++ ioc_fmt_port_param_t param; ++ ++ if (fmt_port->valid) { ++ _fmt_wrn("port is already initialized.\n"); ++ return -EFAULT; ++ } ++#if defined(CONFIG_COMPAT) ++ if (compat) { ++ if (copy_from_user(¶m, ++ (ioc_fmt_port_param_t *)compat_ptr(arg), ++ sizeof(ioc_fmt_port_param_t))) ++ ++ return -EFAULT; ++ } else ++#endif ++ { ++ if (copy_from_user(¶m, ++ (ioc_fmt_port_param_t *) arg, ++ sizeof(ioc_fmt_port_param_t))) ++ ++ return -EFAULT; ++ } ++ ++ return fmt_port_init(fmt_port, ¶m); ++ } ++ ++ case FMT_PORT_IOC_SET_DIAG_MODE: ++ if (get_user(fmt_port->diag, (ioc_diag_mode *)arg)) ++ return -EFAULT; ++ ++ if (fmt_port->diag == e_IOC_DIAG_MODE_CTRL_LOOPBACK) ++ return set_mac_int_loopback(fmt_port, TRUE); ++ else ++ return set_mac_int_loopback(fmt_port, FALSE); ++ break; ++ ++ case FMT_PORT_IOC_SET_DPAECHO_MODE: ++ case FMT_PORT_IOC_SET_IP_HEADER_MANIP: ++ default: ++ _fmt_wrn("ioctl unimplemented minor:%u@ioctl" ++ " cmd:0x%08x(type:0x%02x, nr:0x%02x.\n", ++ minor, cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_COMPAT ++static long fmt_compat_ioctl( ++ struct file *file, ++ unsigned int cmd, ++ unsigned long arg) ++{ ++ unsigned int minor = iminor(file->f_path.dentry->d_inode); ++ ++ _fmt_dbg("calling...\n"); ++ return fmt_ioctls(minor, file, cmd, arg, true); ++} ++#endif ++ ++static long fmt_ioctl( ++ struct file *file, ++ unsigned int cmd, ++ unsigned long arg) ++{ ++ unsigned int minor = iminor(file->f_path.dentry->d_inode); ++ unsigned int res; ++ ++ _fmt_dbg("calling...\n"); ++ ++ fm_mutex_lock(); ++ res = fmt_ioctls(minor, file, cmd, arg, false); ++ fm_mutex_unlock(); ++ ++ _fmt_dbg("called.\n"); ++ ++ return res; ++} ++ ++#ifdef CONFIG_COMPAT ++void copy_compat_test_frame_buffer( ++ ioc_fmt_buff_desc_t *buff, ++ ioc_fmt_compat_buff_desc_t *compat_buff) ++{ ++ compat_buff->qid = buff->qid; ++ compat_buff->p_data = ptr_to_compat(buff->p_data); ++ compat_buff->size = buff->size; ++ compat_buff->status = buff->status; ++ ++ compat_buff->buff_context.p_user_priv = ++ ptr_to_compat(buff->buff_context.p_user_priv); ++ memcpy(compat_buff->buff_context.fm_prs_res, ++ buff->buff_context.fm_prs_res, ++ FM_PRS_MAX * sizeof(uint8_t)); ++ memcpy(compat_buff->buff_context.fm_time_stamp, ++ buff->buff_context.fm_time_stamp, ++ FM_TIME_STAMP_MAX * sizeof(uint8_t)); ++} ++#endif ++ ++ssize_t fmt_read( ++ struct file *file, ++ char __user *buf, ++ size_t size, ++ loff_t *ppos) ++{ ++ struct fmt_port_s *fmt_port = NULL; ++ struct fmt_frame_s *p_fmt_frame = NULL; ++ ssize_t cnt = 0; ++ ++ fmt_port = file->private_data; ++ if (!fmt_port || !fmt_port->valid) { ++ _fmt_err("fmt port not valid!\n"); ++ return -ENODEV; ++ } ++ ++ p_fmt_frame = dequeue_fmt_frame(fmt_port); ++ if (p_fmt_frame == NULL) ++ return 0; ++ ++ _fmt_dbgr("calling...\n"); ++ ++#ifdef CONFIG_COMPAT ++ if (fmt_port->compat_test_type){ ++ cnt = sizeof(ioc_fmt_compat_buff_desc_t); ++ } ++ else ++#endif ++ { ++ cnt = sizeof(ioc_fmt_buff_desc_t); ++ } ++ ++ if (size < cnt) { ++ _fmt_err("illegal buffer-size!\n"); ++ cnt = 0; ++ goto _fmt_read_return; ++ } ++ ++ /* Copy structure */ ++#ifdef CONFIG_COMPAT ++ if (fmt_port->compat_test_type) { ++ { ++ ioc_fmt_compat_buff_desc_t compat_buff; ++ copy_compat_test_frame_buffer(&p_fmt_frame->buff, ++ &compat_buff); ++ ++ if (copy_to_user(buf, &compat_buff, cnt)) { ++ _fmt_err("copy_to_user failed!\n"); ++ goto _fmt_read_return; ++ } ++ } ++ ++ ((ioc_fmt_compat_buff_desc_t *)buf)->p_data = ++ ptr_to_compat(buf+sizeof(ioc_fmt_compat_buff_desc_t)); ++ cnt += MIN(p_fmt_frame->buff.size, size-cnt); ++ } else ++#endif ++ { ++ if (copy_to_user(buf, &p_fmt_frame->buff, cnt)) { ++ _fmt_err("copy_to_user failed!\n"); ++ goto _fmt_read_return; ++ } ++ ++ ((ioc_fmt_buff_desc_t *)buf)->p_data = ++ buf + sizeof(ioc_fmt_buff_desc_t); ++ cnt += MIN(p_fmt_frame->buff.size, size-cnt); ++ } ++ ++ if (size < cnt) { ++ _fmt_err("illegal buffer-size!\n"); ++ goto _fmt_read_return; ++ } ++ ++ /* copy frame */ ++#ifdef CONFIG_COMPAT ++ if (fmt_port->compat_test_type) { ++ if (copy_to_user(buf+sizeof(ioc_fmt_compat_buff_desc_t), ++ p_fmt_frame->buff.p_data, cnt)) { ++ _fmt_err("copy_to_user failed!\n"); ++ goto _fmt_read_return; ++ } ++ } else ++#endif ++ { ++ if (copy_to_user(buf+sizeof(ioc_fmt_buff_desc_t), ++ p_fmt_frame->buff.p_data, cnt)) { ++ _fmt_err("copy_to_user failed!\n"); ++ goto _fmt_read_return; ++ } ++ } ++ ++_fmt_read_return: ++ kfree(p_fmt_frame->buff.p_data); ++ kfree(p_fmt_frame); ++ ++ _fmt_dbgr("called.\n"); ++ return cnt; ++} ++ ++ssize_t fmt_write( ++ struct file *file, ++ const char __user *buf, ++ size_t size, ++ loff_t *ppos) ++{ ++ struct fmt_port_s *fmt_port = NULL; ++ ioc_fmt_buff_desc_t buff_desc; ++#ifdef CONFIG_COMPAT ++ ioc_fmt_compat_buff_desc_t buff_desc_compat; ++#endif ++ uint8_t *p_data = NULL; ++ uint32_t data_offset; ++ int _errno; ++ t_DpaaFD fd; ++ ++ _fmt_dbgr("calling...\n"); ++ ++ fmt_port = file->private_data; ++ if (!fmt_port || !fmt_port->valid) { ++ _fmt_err("fmt port not valid.\n"); ++ return -EINVAL; ++ } ++ ++ /* If Compat (32B UserSpace - 64B KernelSpace) */ ++#ifdef CONFIG_COMPAT ++ if (fmt_port->compat_test_type) { ++ if (size < sizeof(ioc_fmt_compat_buff_desc_t)) { ++ _fmt_err("invalid buff_desc size.\n"); ++ return -EFAULT; ++ } ++ ++ if (copy_from_user(&buff_desc_compat, buf, ++ sizeof(ioc_fmt_compat_buff_desc_t))) ++ return -EFAULT; ++ ++ buff_desc.qid = buff_desc_compat.qid; ++ buff_desc.p_data = compat_ptr(buff_desc_compat.p_data); ++ buff_desc.size = buff_desc_compat.size; ++ buff_desc.status = buff_desc_compat.status; ++ ++ buff_desc.buff_context.p_user_priv = ++ compat_ptr(buff_desc_compat.buff_context.p_user_priv); ++ memcpy(buff_desc.buff_context.fm_prs_res, ++ buff_desc_compat.buff_context.fm_prs_res, ++ FM_PRS_MAX * sizeof(uint8_t)); ++ memcpy(buff_desc.buff_context.fm_time_stamp, ++ buff_desc_compat.buff_context.fm_time_stamp, ++ FM_TIME_STAMP_MAX * sizeof(uint8_t)); ++ } else ++#endif ++ { ++ if (size < sizeof(ioc_fmt_buff_desc_t)) { ++ _fmt_err("invalid buff_desc size.\n"); ++ return -EFAULT; ++ } ++ ++ if (copy_from_user(&buff_desc, (ioc_fmt_buff_desc_t *)buf, ++ sizeof(ioc_fmt_buff_desc_t))) ++ return -EFAULT; ++ } ++ ++ data_offset = FM_PORT_GetBufferDataOffset(fmt_port->p_tx_fm_port_dev); ++ p_data = kmalloc(buff_desc.size+data_offset, GFP_KERNEL); ++ if (!p_data) ++ return -ENOMEM; ++ ++ /* If Compat (32UserSpace - 64KernelSpace) the buff_desc.p_data is ok */ ++ if (copy_from_user((uint8_t *)PTR_MOVE(p_data, data_offset), ++ buff_desc.p_data, ++ buff_desc.size)) { ++ kfree(p_data); ++ return -EFAULT; ++ } ++ ++ /* TODO: dma_map_single here (cannot access the bpool struct) */ ++ ++ /* prepare fd */ ++ memset(&fd, 0, sizeof(fd)); ++ DPAA_FD_SET_ADDR(&fd, p_data); ++ DPAA_FD_SET_OFFSET(&fd, data_offset); ++ DPAA_FD_SET_LENGTH(&fd, buff_desc.size); ++ ++ _errno = qman_enqueue(&fmt_port->p_tx_fqs[buff_desc.qid].fq_base, ++ (struct qm_fd *)&fd, 0); ++ if (_errno) { ++ buff_desc.status = (uint32_t)_errno; ++ if (copy_to_user((ioc_fmt_buff_desc_t *)buf, &buff_desc, ++ sizeof(ioc_fmt_buff_desc_t))) { ++ kfree(p_data); ++ return -EFAULT; ++ } ++ } ++ ++ /* for debugging */ ++#if defined(FMT_K_DBG) || defined(FMT_K_DBG_RUNTIME) ++ atomic_inc(&fmt_port->enqueue_to_qman_frm); ++#endif ++ _fmt_dbgr("called.\n"); ++ return buff_desc.size; ++} ++ ++/* fm test character device definition */ ++static const struct file_operations fmt_fops = ++{ ++ .owner = THIS_MODULE, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = fmt_compat_ioctl, ++#endif ++ .unlocked_ioctl = fmt_ioctl, ++ .open = fmt_open, ++ .release = fmt_close, ++ .read = fmt_read, ++ .write = fmt_write, ++}; ++ ++static int fmt_init(void) ++{ ++ int id; ++ ++ _fmt_dbg("calling...\n"); ++ ++ /* Register to the /dev for IOCTL API */ ++ /* Register dynamically a new major number for the character device: */ ++ fm_test.major = register_chrdev(0, DEV_FM_TEST_NAME, &fmt_fops); ++ if (fm_test.major <= 0) { ++ _fmt_wrn("Failed to allocate major number for device %s.\n", ++ DEV_FM_TEST_NAME); ++ return -ENODEV; ++ } ++ ++ /* Creating class for FMan_test */ ++ fm_test.fmt_class = class_create(THIS_MODULE, DEV_FM_TEST_NAME); ++ if (IS_ERR(fm_test.fmt_class)) { ++ unregister_chrdev(fm_test.major, DEV_FM_TEST_NAME); ++ _fmt_wrn("Error creating %s class.\n", DEV_FM_TEST_NAME); ++ return -ENODEV; ++ } ++ ++ for (id = 0; id < IOC_FMT_MAX_NUM_OF_PORTS; id++) ++ if (NULL == device_create(fm_test.fmt_class, NULL, ++ MKDEV(fm_test.major, ++ DEV_FM_TEST_PORTS_MINOR_BASE + id), NULL, ++ DEV_FM_TEST_NAME "%d", id)) { ++ ++ _fmt_err("Error creating %s device.\n", ++ DEV_FM_TEST_NAME); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static void fmt_free(void) ++{ ++ int id; ++ ++ for (id = 0; id < IOC_FMT_MAX_NUM_OF_PORTS; id++) ++ device_destroy(fm_test.fmt_class, MKDEV(fm_test.major, ++ DEV_FM_TEST_PORTS_MINOR_BASE + id)); ++ class_destroy(fm_test.fmt_class); ++} ++ ++static int __init __cold fmt_load(void) ++{ ++ struct dpaa_eth_hooks_s priv_dpaa_eth_hooks; ++ ++ /* set dpaa hooks for default queues */ ++ memset(&priv_dpaa_eth_hooks, 0, sizeof(priv_dpaa_eth_hooks)); ++ priv_dpaa_eth_hooks.rx_default = fmt_rx_default_hook; ++ priv_dpaa_eth_hooks.rx_error = fmt_rx_error_hook; ++ priv_dpaa_eth_hooks.tx_confirm = fmt_tx_confirm_hook; ++ priv_dpaa_eth_hooks.tx_error = fmt_tx_confirm_error_hook; ++ ++ fsl_dpaa_eth_set_hooks(&priv_dpaa_eth_hooks); ++ ++ /* initialize the fman test environment */ ++ if (fmt_init() < 0) { ++ _fmt_err("Failed to init FM-test modul.\n"); ++ fmt_free(); ++ return -ENODEV; ++ } ++ ++ _fmt_inf("FSL FM test module loaded.\n"); ++ ++ return 0; ++} ++ ++static void __exit __cold fmt_unload(void) ++{ ++ fmt_free(); ++ _fmt_inf("FSL FM test module unloaded.\n"); ++} ++ ++module_init(fmt_load); ++module_exit(fmt_unload); +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c +new file mode 100755 +index 00000000..31f654b4 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.c +@@ -0,0 +1,2908 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ @File lnxwrp_fm.c ++ @Author Shlomi Gridish ++ @Description FM Linux wrapper functions. ++*/ ++ ++#include ++#include ++#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) ++#define MODVERSIONS ++#endif ++#ifdef MODVERSIONS ++#include ++#endif /* MODVERSIONS */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifndef CONFIG_FMAN_ARM ++#include ++#include ++#include ++#endif ++#include /* For file access mask */ ++#include ++#include ++ ++/* NetCommSw Headers --------------- */ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "sprint_ext.h" ++#include "debug_ext.h" ++#include "sys_io_ext.h" ++ ++#include "fm_ioctls.h" ++ ++#include "lnxwrp_fm.h" ++#include "lnxwrp_resources.h" ++#include "lnxwrp_sysfs_fm.h" ++#include "lnxwrp_sysfs_fm_port.h" ++#include "lnxwrp_exp_sym.h" ++#include "fm_common.h" ++#include "../../sdk_fman/Peripherals/FM/fm.h" ++#define __ERR_MODULE__ MODULE_FM ++ ++extern struct device_node *GetFmPortAdvArgsDevTreeNode (struct device_node *fm_node, ++ e_FmPortType portType, ++ uint8_t portId); ++ ++#define PROC_PRINT(args...) offset += sprintf(buf+offset,args) ++ ++#define ADD_ADV_CONFIG_NO_RET(_func, _param) \ ++ do { \ ++ if (ip_Function = _func; \ ++ _param \ ++ i++; \ ++ } \ ++ else \ ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE,\ ++ ("Number of advanced-configuration entries exceeded"));\ ++ } while (0) ++ ++/* Bootarg used to override the Kconfig FSL_FM_MAX_FRAME_SIZE value */ ++#define FSL_FM_MAX_FRM_BOOTARG "fsl_fm_max_frm" ++ ++/* Bootarg used to override FSL_FM_RX_EXTRA_HEADROOM Kconfig value */ ++#define FSL_FM_RX_EXTRA_HEADROOM_BOOTARG "fsl_fm_rx_extra_headroom" ++ ++/* Minimum and maximum value for the fsl_fm_rx_extra_headroom bootarg */ ++#define FSL_FM_RX_EXTRA_HEADROOM_MIN 16 ++#define FSL_FM_RX_EXTRA_HEADROOM_MAX 384 ++ ++#define FSL_FM_PAUSE_TIME_ENABLE 0xf000 ++#define FSL_FM_PAUSE_TIME_DISABLE 0 ++#define FSL_FM_PAUSE_THRESH_DEFAULT 0 ++ ++/* ++ * Max frame size, across all interfaces. ++ * Configurable from Kconfig or bootargs, to avoid allocating ++ * oversized (socket) buffers when not using jumbo frames. ++ * Must be large enough to accommodate the network MTU, but small enough ++ * to avoid wasting skb memory. ++ * ++ * Could be overridden once, at boot-time, via the ++ * fm_set_max_frm() callback. ++ */ ++int fsl_fm_max_frm = CONFIG_FSL_FM_MAX_FRAME_SIZE; ++ ++/* ++ * Extra headroom for Rx buffers. ++ * FMan is instructed to allocate, on the Rx path, this amount of ++ * space at the beginning of a data buffer, beside the DPA private ++ * data area and the IC fields. ++ * Does not impact Tx buffer layout. ++ * ++ * Configurable from Kconfig or bootargs. Zero by default, it's needed ++ * on particular forwarding scenarios that add extra headers to the ++ * forwarded frame. ++ */ ++int fsl_fm_rx_extra_headroom = CONFIG_FSL_FM_RX_EXTRA_HEADROOM; ++ ++#ifdef CONFIG_FMAN_PFC ++static int fsl_fm_pfc_quanta[] = { ++ CONFIG_FMAN_PFC_QUANTA_0, ++ CONFIG_FMAN_PFC_QUANTA_1, ++ CONFIG_FMAN_PFC_QUANTA_2, ++ CONFIG_FMAN_PFC_QUANTA_3 ++}; ++#endif ++ ++static t_LnxWrpFm lnxWrpFm; ++ ++int fm_get_max_frm() ++{ ++ return fsl_fm_max_frm; ++} ++EXPORT_SYMBOL(fm_get_max_frm); ++ ++int fm_get_rx_extra_headroom() ++{ ++ return ALIGN(fsl_fm_rx_extra_headroom, 16); ++} ++EXPORT_SYMBOL(fm_get_rx_extra_headroom); ++ ++static int __init fm_set_max_frm(char *str) ++{ ++ int ret = 0; ++ ++ ret = get_option(&str, &fsl_fm_max_frm); ++ if (ret != 1) { ++ /* ++ * This will only work if CONFIG_EARLY_PRINTK is compiled in, ++ * and something like "earlyprintk=serial,uart0,115200" is ++ * specified in the bootargs ++ */ ++ printk(KERN_WARNING "No suitable %s= prop in bootargs; " ++ "will use the default FSL_FM_MAX_FRAME_SIZE (%d) " ++ "from Kconfig.\n", FSL_FM_MAX_FRM_BOOTARG, ++ CONFIG_FSL_FM_MAX_FRAME_SIZE); ++ ++ fsl_fm_max_frm = CONFIG_FSL_FM_MAX_FRAME_SIZE; ++ return 1; ++ } ++ ++ /* Don't allow invalid bootargs; fallback to the Kconfig value */ ++ if (fsl_fm_max_frm < 64 || fsl_fm_max_frm > 9600) { ++ printk(KERN_WARNING "Invalid %s=%d in bootargs, valid range is " ++ "64-9600. Falling back to the FSL_FM_MAX_FRAME_SIZE (%d) " ++ "from Kconfig.\n", ++ FSL_FM_MAX_FRM_BOOTARG, fsl_fm_max_frm, ++ CONFIG_FSL_FM_MAX_FRAME_SIZE); ++ ++ fsl_fm_max_frm = CONFIG_FSL_FM_MAX_FRAME_SIZE; ++ return 1; ++ } ++ ++ printk(KERN_INFO "Using fsl_fm_max_frm=%d from bootargs\n", ++ fsl_fm_max_frm); ++ return 0; ++} ++early_param(FSL_FM_MAX_FRM_BOOTARG, fm_set_max_frm); ++ ++static int __init fm_set_rx_extra_headroom(char *str) ++{ ++ int ret; ++ ++ ret = get_option(&str, &fsl_fm_rx_extra_headroom); ++ ++ if (ret != 1) { ++ printk(KERN_WARNING "No suitable %s= prop in bootargs; " ++ "will use the default FSL_FM_RX_EXTRA_HEADROOM (%d) " ++ "from Kconfig.\n", FSL_FM_RX_EXTRA_HEADROOM_BOOTARG, ++ CONFIG_FSL_FM_RX_EXTRA_HEADROOM); ++ fsl_fm_rx_extra_headroom = CONFIG_FSL_FM_RX_EXTRA_HEADROOM; ++ ++ return 1; ++ } ++ ++ if (fsl_fm_rx_extra_headroom < FSL_FM_RX_EXTRA_HEADROOM_MIN || ++ fsl_fm_rx_extra_headroom > FSL_FM_RX_EXTRA_HEADROOM_MAX) { ++ printk(KERN_WARNING "Invalid value for %s=%d prop in " ++ "bootargs; will use the default " ++ "FSL_FM_RX_EXTRA_HEADROOM (%d) from Kconfig.\n", ++ FSL_FM_RX_EXTRA_HEADROOM_BOOTARG, ++ fsl_fm_rx_extra_headroom, ++ CONFIG_FSL_FM_RX_EXTRA_HEADROOM); ++ fsl_fm_rx_extra_headroom = CONFIG_FSL_FM_RX_EXTRA_HEADROOM; ++ } ++ ++ printk(KERN_INFO "Using fsl_fm_rx_extra_headroom=%d from bootargs\n", ++ fsl_fm_rx_extra_headroom); ++ ++ return 0; ++} ++early_param(FSL_FM_RX_EXTRA_HEADROOM_BOOTARG, fm_set_rx_extra_headroom); ++ ++static irqreturn_t fm_irq(int irq, void *_dev) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *)_dev; ++#ifdef CONFIG_PM_SLEEP ++ t_Fm *p_Fm = (t_Fm*)p_LnxWrpFmDev->h_Dev; ++#endif ++ if (!p_LnxWrpFmDev || !p_LnxWrpFmDev->h_Dev) ++ return IRQ_NONE; ++ ++#ifdef CONFIG_PM_SLEEP ++ if (fman_get_normal_pending(p_Fm->p_FmFpmRegs) & INTR_EN_WAKEUP) ++ { ++ pm_wakeup_event(p_LnxWrpFmDev->dev, 200); ++ } ++#endif ++ FM_EventIsr(p_LnxWrpFmDev->h_Dev); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t fm_err_irq(int irq, void *_dev) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *)_dev; ++ ++ if (!p_LnxWrpFmDev || !p_LnxWrpFmDev->h_Dev) ++ return IRQ_NONE; ++ ++ if (FM_ErrorIsr(p_LnxWrpFmDev->h_Dev) == E_OK) ++ return IRQ_HANDLED; ++ ++ return IRQ_NONE; ++} ++ ++/* used to protect FMD/LLD from concurrent calls in functions fm_mutex_lock / fm_mutex_unlock */ ++static struct mutex lnxwrp_mutex; ++ ++static t_LnxWrpFmDev * CreateFmDev(uint8_t id) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev; ++ int j; ++ ++ p_LnxWrpFmDev = (t_LnxWrpFmDev *)XX_Malloc(sizeof(t_LnxWrpFmDev)); ++ if (!p_LnxWrpFmDev) ++ { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); ++ return NULL; ++ } ++ ++ memset(p_LnxWrpFmDev, 0, sizeof(t_LnxWrpFmDev)); ++ p_LnxWrpFmDev->fmDevSettings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); ++ memset(p_LnxWrpFmDev->fmDevSettings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); ++ p_LnxWrpFmDev->fmPcdDevSettings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); ++ memset(p_LnxWrpFmDev->fmPcdDevSettings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); ++ p_LnxWrpFmDev->hcPort.settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); ++ memset(p_LnxWrpFmDev->hcPort.settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); ++ for (j=0; jrxPorts[j].settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); ++ memset(p_LnxWrpFmDev->rxPorts[j].settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); ++ } ++ for (j=0; jtxPorts[j].settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); ++ memset(p_LnxWrpFmDev->txPorts[j].settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); ++ } ++ for (j=0; jopPorts[j].settings.advConfig = (t_SysObjectAdvConfigEntry*)XX_Malloc(FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry)); ++ memset(p_LnxWrpFmDev->opPorts[j].settings.advConfig, 0, (FM_MAX_NUM_OF_ADV_SETTINGS*sizeof(t_SysObjectAdvConfigEntry))); ++ } ++ ++ return p_LnxWrpFmDev; ++} ++ ++static void DestroyFmDev(t_LnxWrpFmDev *p_LnxWrpFmDev) ++{ ++ int j; ++ ++ for (j=0; jopPorts[j].settings.advConfig) ++ XX_Free(p_LnxWrpFmDev->opPorts[j].settings.advConfig); ++ for (j=0; jtxPorts[j].settings.advConfig) ++ XX_Free(p_LnxWrpFmDev->txPorts[j].settings.advConfig); ++ for (j=0; jrxPorts[j].settings.advConfig) ++ XX_Free(p_LnxWrpFmDev->rxPorts[j].settings.advConfig); ++ if (p_LnxWrpFmDev->hcPort.settings.advConfig) ++ XX_Free(p_LnxWrpFmDev->hcPort.settings.advConfig); ++ if (p_LnxWrpFmDev->fmPcdDevSettings.advConfig) ++ XX_Free(p_LnxWrpFmDev->fmPcdDevSettings.advConfig); ++ if (p_LnxWrpFmDev->fmDevSettings.advConfig) ++ XX_Free(p_LnxWrpFmDev->fmDevSettings.advConfig); ++ ++ XX_Free(p_LnxWrpFmDev); ++} ++ ++static t_Error FillRestFmInfo(t_LnxWrpFmDev *p_LnxWrpFmDev) ++{ ++#define FM_BMI_PPIDS_OFFSET 0x00080304 ++#define FM_DMA_PLR_OFFSET 0x000c2060 ++#define FM_FPM_IP_REV_1_OFFSET 0x000c30c4 ++#define DMA_HIGH_LIODN_MASK 0x0FFF0000 ++#define DMA_LOW_LIODN_MASK 0x00000FFF ++#define DMA_LIODN_SHIFT 16 ++ ++typedef _Packed struct { ++ uint32_t plr[32]; ++} _PackedType t_Plr; ++ ++typedef _Packed struct { ++ volatile uint32_t fmbm_ppid[63]; ++} _PackedType t_Ppids; ++ ++ t_Plr *p_Plr; ++ t_Ppids *p_Ppids; ++ int i,j; ++ uint32_t fmRev; ++ ++ static const uint8_t phys1GRxPortId[] = {0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf}; ++ static const uint8_t phys10GRxPortId[] = {0x10,0x11}; ++#if (DPAA_VERSION >= 11) ++ static const uint8_t physOhPortId[] = {/* 0x1, */0x2,0x3,0x4,0x5,0x6,0x7}; ++#else ++ static const uint8_t physOhPortId[] = {0x1,0x2,0x3,0x4,0x5,0x6,0x7}; ++#endif ++ static const uint8_t phys1GTxPortId[] = {0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f}; ++ static const uint8_t phys10GTxPortId[] = {0x30,0x31}; ++ ++ fmRev = (uint32_t)(*((volatile uint32_t *)UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr+FM_FPM_IP_REV_1_OFFSET))); ++ fmRev &= 0xffff; ++ ++ p_Plr = (t_Plr *)UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr+FM_DMA_PLR_OFFSET); ++#ifdef MODULE ++ for (i=0;iplr[i] = 0; ++#endif /* MODULE */ ++ ++ for (i=0; iplr[i/2] & DMA_LOW_LIODN_MASK) : ++ ((p_Plr->plr[i/2] & DMA_HIGH_LIODN_MASK) >> DMA_LIODN_SHIFT)); ++#ifdef FM_PARTITION_ARRAY ++ /* TODO: this was .liodnPerPartition[i] = liodnBase; is the index meaning the same? */ ++ p_LnxWrpFmDev->fmDevSettings.param.liodnBasePerPort[i] = liodnBase; ++#endif /* FM_PARTITION_ARRAY */ ++ ++ if ((i >= phys1GRxPortId[0]) && ++ (i <= phys1GRxPortId[FM_MAX_NUM_OF_1G_RX_PORTS-1])) ++ { ++ for (j=0; jrxPorts[j].settings.param.liodnBase = liodnBase; ++ } ++ else if (FM_MAX_NUM_OF_10G_RX_PORTS && ++ (i >= phys10GRxPortId[0]) && ++ (i <= phys10GRxPortId[FM_MAX_NUM_OF_10G_RX_PORTS-1])) ++ { ++ for (j=0; jrxPorts[FM_MAX_NUM_OF_1G_RX_PORTS+j].settings.param.liodnBase = liodnBase; ++ } ++ else if ((i >= physOhPortId[0]) && ++ (i <= physOhPortId[FM_MAX_NUM_OF_OH_PORTS-1])) ++ { ++ for (j=0; jhcPort.settings.param.liodnBase = liodnBase; ++ else ++ p_LnxWrpFmDev->opPorts[j - 1].settings.param.liodnBase = liodnBase; ++ } ++ else if ((i >= phys1GTxPortId[0]) && ++ (i <= phys1GTxPortId[FM_MAX_NUM_OF_1G_TX_PORTS-1])) ++ { ++ for (j=0; jtxPorts[j].settings.param.liodnBase = liodnBase; ++ } ++ else if (FM_MAX_NUM_OF_10G_TX_PORTS && ++ (i >= phys10GTxPortId[0]) && ++ (i <= phys10GTxPortId[FM_MAX_NUM_OF_10G_TX_PORTS-1])) ++ { ++ for (j=0; jtxPorts[FM_MAX_NUM_OF_1G_TX_PORTS+j].settings.param.liodnBase = liodnBase; ++ } ++ } ++ ++ p_Ppids = (t_Ppids *)UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr+FM_BMI_PPIDS_OFFSET); ++ ++ for (i=0; irxPorts[i].settings.param.specificParams.rxParams.liodnOffset = ++ p_Ppids->fmbm_ppid[phys1GRxPortId[i]-1]; ++ ++ for (i=0; irxPorts[FM_MAX_NUM_OF_1G_RX_PORTS+i].settings.param.specificParams.rxParams.liodnOffset = ++ p_Ppids->fmbm_ppid[phys10GRxPortId[i]-1]; ++ ++ return E_OK; ++} ++ ++/* Structure that defines QE firmware binary files. ++ * ++ * See Documentation/powerpc/qe_firmware.txt for a description of these ++ * fields. ++ */ ++struct qe_firmware { ++ struct qe_header { ++ __be32 length; /* Length of the entire structure, in bytes */ ++ u8 magic[3]; /* Set to { 'Q', 'E', 'F' } */ ++ u8 version; /* Version of this layout. First ver is '1' */ ++ } header; ++ u8 id[62]; /* Null-terminated identifier string */ ++ u8 split; /* 0 = shared I-RAM, 1 = split I-RAM */ ++ u8 count; /* Number of microcode[] structures */ ++ struct { ++ __be16 model; /* The SOC model */ ++ u8 major; /* The SOC revision major */ ++ u8 minor; /* The SOC revision minor */ ++ } __attribute__ ((packed)) soc; ++ u8 padding[4]; /* Reserved, for alignment */ ++ __be64 extended_modes; /* Extended modes */ ++ __be32 vtraps[8]; /* Virtual trap addresses */ ++ u8 reserved[4]; /* Reserved, for future expansion */ ++ struct qe_microcode { ++ u8 id[32]; /* Null-terminated identifier */ ++ __be32 traps[16]; /* Trap addresses, 0 == ignore */ ++ __be32 eccr; /* The value for the ECCR register */ ++ __be32 iram_offset; /* Offset into I-RAM for the code */ ++ __be32 count; /* Number of 32-bit words of the code */ ++ __be32 code_offset; /* Offset of the actual microcode */ ++ u8 major; /* The microcode version major */ ++ u8 minor; /* The microcode version minor */ ++ u8 revision; /* The microcode version revision */ ++ u8 padding; /* Reserved, for alignment */ ++ u8 reserved[4]; /* Reserved, for future expansion */ ++ } __attribute__ ((packed)) microcode[1]; ++ /* All microcode binaries should be located here */ ++ /* CRC32 should be located here, after the microcode binaries */ ++} __attribute__ ((packed)); ++ ++ ++/** ++ * FindFmanMicrocode - find the Fman microcode ++ * ++ * This function returns a pointer to the QE Firmware blob that holds ++ * the Fman microcode. We use the QE Firmware structure because Fman microcode ++ * is similar to QE microcode, so there's no point in defining a new layout. ++ * ++ * Current versions of U-Boot embed the Fman firmware into the device tree, ++ * so we check for that first. Each Fman node in the device tree contains a ++ * node or a pointer to node that holds the firmware. Technically, we should ++ * be fetching the firmware node for the current Fman, but we don't have that ++ * information any more, so we assume that there is only one firmware node in ++ * the device tree, and that all Fmen use the same firmware. ++ */ ++static const struct qe_firmware *FindFmanMicrocode(void) ++{ ++ static const struct qe_firmware *P4080_UCPatch; ++ struct device_node *np; ++ ++ if (P4080_UCPatch) ++ return P4080_UCPatch; ++ ++ /* The firmware should be inside the device tree. */ ++ np = of_find_compatible_node(NULL, NULL, "fsl,fman-firmware"); ++ if (np) { ++ P4080_UCPatch = of_get_property(np, "fsl,firmware", NULL); ++ of_node_put(np); ++ if (P4080_UCPatch) ++ return P4080_UCPatch; ++ else ++ REPORT_ERROR(WARNING, E_NOT_FOUND, ("firmware node is incomplete")); ++ } ++ ++ /* Returning NULL here forces the reuse of the IRAM content */ ++ return NULL; ++} ++#define SVR_SECURITY_MASK 0x00080000 ++#define SVR_PERSONALITY_MASK 0x0000FF00 ++#define SVR_VER_IGNORE_MASK (SVR_SECURITY_MASK | SVR_PERSONALITY_MASK) ++#define SVR_B4860_REV1_VALUE 0x86800010 ++#define SVR_B4860_REV2_VALUE 0x86800020 ++#define SVR_T4240_VALUE 0x82400000 ++#define SVR_T4120_VALUE 0x82400100 ++#define SVR_T4160_VALUE 0x82410000 ++#define SVR_T4080_VALUE 0x82410200 ++#define SVR_T4_DEVICE_ID 0x82400000 ++#define SVR_DEVICE_ID_MASK 0xFFF00000 ++ ++#define OF_DEV_ID_NUM 2 /* one used, another one zeroed */ ++ ++/* searches for a subnode with the given name/compatible */ ++static bool HasFmPcdOfNode(struct device_node *fm_node, ++ struct of_device_id *ids, ++ const char *name, ++ const char *compatible) ++{ ++ struct device_node *dev_node; ++ bool ret = false; ++ ++ memset(ids, 0, OF_DEV_ID_NUM*sizeof(struct of_device_id)); ++ if (WARN_ON(strlen(name) >= sizeof(ids[0].name))) ++ return false; ++ strcpy(ids[0].name, name); ++ if (WARN_ON(strlen(compatible) >= sizeof(ids[0].compatible))) ++ return false; ++ strcpy(ids[0].compatible, compatible); ++ for_each_child_of_node(fm_node, dev_node) ++ if (of_match_node(ids, dev_node) != NULL) ++ ret = true; ++ return ret; ++} ++ ++static t_LnxWrpFmDev * ReadFmDevTreeNode (struct platform_device *of_dev) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev; ++ struct device_node *fm_node, *dev_node; ++ struct of_device_id ids[OF_DEV_ID_NUM]; ++ struct resource res; ++ struct clk *clk; ++ u32 clk_rate; ++ const uint32_t *uint32_prop; ++ int _errno=0, lenp; ++ uint32_t tmp_prop; ++ ++ fm_node = of_node_get(of_dev->dev.of_node); ++ ++ uint32_prop = (uint32_t *)of_get_property(fm_node, "cell-index", &lenp); ++ if (unlikely(uint32_prop == NULL)) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_get_property(%s, cell-index) failed", fm_node->full_name)); ++ return NULL; ++ } ++ tmp_prop = be32_to_cpu(*uint32_prop); ++ ++ if (WARN_ON(lenp != sizeof(uint32_t))) ++ return NULL; ++ ++ if (tmp_prop > INTG_MAX_NUM_OF_FM) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("fm id!")); ++ return NULL; ++ } ++ p_LnxWrpFmDev = CreateFmDev(tmp_prop); ++ if (!p_LnxWrpFmDev) { ++ REPORT_ERROR(MAJOR, E_NULL_POINTER, NO_MSG); ++ return NULL; ++ } ++ p_LnxWrpFmDev->dev = &of_dev->dev; ++ p_LnxWrpFmDev->id = tmp_prop; ++ ++ /* Get the FM interrupt */ ++ p_LnxWrpFmDev->irq = of_irq_to_resource(fm_node, 0, NULL); ++ if (unlikely(p_LnxWrpFmDev->irq == /*NO_IRQ*/0)) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_irq_to_resource() = %d", NO_IRQ)); ++ DestroyFmDev(p_LnxWrpFmDev); ++ return NULL; ++ } ++ ++ /* Get the FM error interrupt */ ++ p_LnxWrpFmDev->err_irq = of_irq_to_resource(fm_node, 1, NULL); ++ ++ if (unlikely(p_LnxWrpFmDev->err_irq == /*NO_IRQ*/0)) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_irq_to_resource() = %d", NO_IRQ)); ++ DestroyFmDev(p_LnxWrpFmDev); ++ return NULL; ++ } ++ ++ /* Get the FM address */ ++ _errno = of_address_to_resource(fm_node, 0, &res); ++ if (unlikely(_errno < 0)) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno)); ++ DestroyFmDev(p_LnxWrpFmDev); ++ return NULL; ++ } ++ ++ ++ p_LnxWrpFmDev->fmBaseAddr = 0; ++ p_LnxWrpFmDev->fmPhysBaseAddr = res.start; ++ p_LnxWrpFmDev->fmMemSize = res.end + 1 - res.start; ++ ++ clk = of_clk_get(fm_node, 0); ++ if (IS_ERR(clk)) { ++ dev_err(&of_dev->dev, "%s: Failed to get FM clock structure\n", ++ __func__); ++ of_node_put(fm_node); ++ DestroyFmDev(p_LnxWrpFmDev); ++ return NULL; ++ } ++ ++ clk_rate = clk_get_rate(clk); ++ if (!clk_rate) { ++ dev_err(&of_dev->dev, "%s: Failed to determine FM clock rate\n", ++ __func__); ++ of_node_put(fm_node); ++ DestroyFmDev(p_LnxWrpFmDev); ++ return NULL; ++ } ++ ++ p_LnxWrpFmDev->fmDevSettings.param.fmClkFreq = DIV_ROUND_UP(clk_rate, 1000000); /* In MHz, rounded */ ++ /* Get the MURAM base address and size */ ++ memset(ids, 0, sizeof(ids)); ++ if (WARN_ON(strlen("muram") >= sizeof(ids[0].name))) ++ return NULL; ++ strcpy(ids[0].name, "muram"); ++ if (WARN_ON(strlen("fsl,fman-muram") >= sizeof(ids[0].compatible))) ++ return NULL; ++ strcpy(ids[0].compatible, "fsl,fman-muram"); ++ for_each_child_of_node(fm_node, dev_node) { ++ if (likely(of_match_node(ids, dev_node) != NULL)) { ++ _errno = of_address_to_resource(dev_node, 0, &res); ++ if (unlikely(_errno < 0)) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno)); ++ DestroyFmDev(p_LnxWrpFmDev); ++ return NULL; ++ } ++ ++ p_LnxWrpFmDev->fmMuramBaseAddr = 0; ++ p_LnxWrpFmDev->fmMuramPhysBaseAddr = res.start; ++ p_LnxWrpFmDev->fmMuramMemSize = res.end + 1 - res.start; ++ ++#ifndef CONFIG_FMAN_ARM ++ { ++ uint32_t svr; ++ svr = mfspr(SPRN_SVR); ++ ++ if ((svr & ~SVR_VER_IGNORE_MASK) >= SVR_B4860_REV2_VALUE) ++ p_LnxWrpFmDev->fmMuramMemSize = 0x80000; ++ } ++#endif ++ } ++ } ++ ++ /* Get the RTC base address and size */ ++ memset(ids, 0, sizeof(ids)); ++ if (WARN_ON(strlen("ptp-timer") >= sizeof(ids[0].name))) ++ return NULL; ++ strcpy(ids[0].name, "ptp-timer"); ++ if (WARN_ON(strlen("fsl,fman-rtc") >= sizeof(ids[0].compatible))) ++ return NULL; ++ strcpy(ids[0].compatible, "fsl,fman-rtc"); ++ for_each_child_of_node(fm_node, dev_node) { ++ if (likely(of_match_node(ids, dev_node) != NULL)) { ++ _errno = of_address_to_resource(dev_node, 0, &res); ++ if (unlikely(_errno < 0)) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno)); ++ DestroyFmDev(p_LnxWrpFmDev); ++ return NULL; ++ } ++ ++ p_LnxWrpFmDev->fmRtcBaseAddr = 0; ++ p_LnxWrpFmDev->fmRtcPhysBaseAddr = res.start; ++ p_LnxWrpFmDev->fmRtcMemSize = res.end + 1 - res.start; ++ } ++ } ++ ++#if (DPAA_VERSION >= 11) ++ /* Get the VSP base address */ ++ for_each_child_of_node(fm_node, dev_node) { ++ if (of_device_is_compatible(dev_node, "fsl,fman-vsps")) { ++ _errno = of_address_to_resource(dev_node, 0, &res); ++ if (unlikely(_errno < 0)) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("of_address_to_resource() = %d", _errno)); ++ DestroyFmDev(p_LnxWrpFmDev); ++ return NULL; ++ } ++ p_LnxWrpFmDev->fmVspBaseAddr = 0; ++ p_LnxWrpFmDev->fmVspPhysBaseAddr = res.start; ++ p_LnxWrpFmDev->fmVspMemSize = res.end + 1 - res.start; ++ } ++ } ++#endif ++ ++ /* Get all PCD nodes */ ++ p_LnxWrpFmDev->prsActive = HasFmPcdOfNode(fm_node, ids, "parser", "fsl,fman-parser"); ++ p_LnxWrpFmDev->kgActive = HasFmPcdOfNode(fm_node, ids, "keygen", "fsl,fman-keygen"); ++ p_LnxWrpFmDev->ccActive = HasFmPcdOfNode(fm_node, ids, "cc", "fsl,fman-cc"); ++ p_LnxWrpFmDev->plcrActive = HasFmPcdOfNode(fm_node, ids, "policer", "fsl,fman-policer"); ++ ++ if (p_LnxWrpFmDev->prsActive || p_LnxWrpFmDev->kgActive || ++ p_LnxWrpFmDev->ccActive || p_LnxWrpFmDev->plcrActive) ++ p_LnxWrpFmDev->pcdActive = TRUE; ++ ++ if (p_LnxWrpFmDev->pcdActive) ++ { ++ const char *str_prop = (char *)of_get_property(fm_node, "fsl,default-pcd", &lenp); ++ if (str_prop) { ++ if (strncmp(str_prop, "3-tuple", strlen("3-tuple")) == 0) ++ p_LnxWrpFmDev->defPcd = e_FM_PCD_3_TUPLE; ++ } ++ else ++ p_LnxWrpFmDev->defPcd = e_NO_PCD; ++ } ++ ++ of_node_put(fm_node); ++ ++ p_LnxWrpFmDev->hcCh = ++ qman_affine_channel(cpumask_first(qman_affine_cpus())); ++ ++ p_LnxWrpFmDev->active = TRUE; ++ ++ return p_LnxWrpFmDev; ++} ++ ++struct device_node *GetFmAdvArgsDevTreeNode (uint8_t fmIndx) ++{ ++ struct device_node *dev_node; ++ const uint32_t *uint32_prop; ++ int lenp; ++ uint32_t tmp_prop; ++ ++ for_each_compatible_node(dev_node, NULL, "fsl,fman-extended-args") { ++ uint32_prop = (uint32_t *)of_get_property(dev_node, "cell-index", &lenp); ++ if (unlikely(uint32_prop == NULL)) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ++ ("of_get_property(%s, cell-index) failed", ++ dev_node->full_name)); ++ return NULL; ++ } ++ tmp_prop = be32_to_cpu(*uint32_prop); ++ if (WARN_ON(lenp != sizeof(uint32_t))) ++ return NULL; ++ if (tmp_prop > INTG_MAX_NUM_OF_FM) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("fm id!")); ++ return NULL; ++ } ++ if (fmIndx == tmp_prop) ++ return dev_node; ++ } ++ ++ return NULL; ++} ++ ++static t_Error CheckNConfigFmAdvArgs (t_LnxWrpFmDev *p_LnxWrpFmDev) ++{ ++ struct device_node *dev_node; ++ t_Error err = E_INVALID_VALUE; ++ const uint32_t *uint32_prop; ++ const char *str_prop; ++ int lenp; ++ uint32_t tmp_prop; ++ ++ dev_node = GetFmAdvArgsDevTreeNode(p_LnxWrpFmDev->id); ++ if (!dev_node) /* no advance parameters for FMan */ ++ return E_OK; ++ ++ str_prop = (char *)of_get_property(dev_node, "dma-aid-mode", &lenp); ++ if (str_prop) { ++ if (strcmp(str_prop, "port") == 0) ++ err = FM_ConfigDmaAidMode(p_LnxWrpFmDev->h_Dev, e_FM_DMA_AID_OUT_PORT_ID); ++ else if (strcmp(str_prop, "tnum") == 0) ++ err = FM_ConfigDmaAidMode(p_LnxWrpFmDev->h_Dev, e_FM_DMA_AID_OUT_TNUM); ++ ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ uint32_prop = (uint32_t *)of_get_property(dev_node, ++ "total-fifo-size", &lenp); ++ if (uint32_prop) { ++ tmp_prop = be32_to_cpu(*uint32_prop); ++ if (WARN_ON(lenp != sizeof(uint32_t))) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); ++ ++ if (FM_ConfigTotalFifoSize(p_LnxWrpFmDev->h_Dev, ++ tmp_prop) != E_OK) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); ++ } ++ ++ uint32_prop = (uint32_t *)of_get_property(dev_node, "tnum-aging-period", ++ &lenp); ++ if (uint32_prop) { ++ tmp_prop = be32_to_cpu(*uint32_prop); ++ if (WARN_ON(lenp != sizeof(uint32_t))) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); ++ ++ err = FM_ConfigTnumAgingPeriod(p_LnxWrpFmDev->h_Dev, ++ (uint16_t)tmp_prop/*tnumAgingPeriod*/); ++ ++ if (err != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ of_node_put(dev_node); ++ ++ return E_OK; ++} ++ ++static void LnxwrpFmDevExceptionsCb(t_Handle h_App, e_FmExceptions exception) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *)h_App; ++ ++ ASSERT_COND(p_LnxWrpFmDev); ++ ++ DBG(INFO, ("got fm exception %d", exception)); ++ ++ /* do nothing */ ++ UNUSED(exception); ++} ++ ++static void LnxwrpFmDevBusErrorCb(t_Handle h_App, ++ e_FmPortType portType, ++ uint8_t portId, ++ uint64_t addr, ++ uint8_t tnum, ++ uint16_t liodn) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *)h_App; ++ ++ ASSERT_COND(p_LnxWrpFmDev); ++ ++ /* do nothing */ ++ UNUSED(portType);UNUSED(portId);UNUSED(addr);UNUSED(tnum);UNUSED(liodn); ++} ++ ++static t_Error ConfigureFmDev(t_LnxWrpFmDev *p_LnxWrpFmDev) ++{ ++ struct resource *dev_res; ++ int _errno; ++ ++ if (!p_LnxWrpFmDev->active) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM not configured!!!")); ++ ++#ifndef MODULE ++ _errno = can_request_irq(p_LnxWrpFmDev->irq, 0); ++ if (unlikely(_errno < 0)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("can_request_irq() = %d", _errno)); ++#endif ++ _errno = devm_request_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->irq, fm_irq, 0, "fman", p_LnxWrpFmDev); ++ if (unlikely(_errno < 0)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("request_irq(%d) = %d", p_LnxWrpFmDev->irq, _errno)); ++ ++ enable_irq_wake(p_LnxWrpFmDev->irq); ++ ++ if (p_LnxWrpFmDev->err_irq != 0) { ++#ifndef MODULE ++ _errno = can_request_irq(p_LnxWrpFmDev->err_irq, 0); ++ if (unlikely(_errno < 0)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("can_request_irq() = %d", _errno)); ++#endif ++ _errno = devm_request_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->err_irq, fm_err_irq, IRQF_SHARED, "fman-err", p_LnxWrpFmDev); ++ if (unlikely(_errno < 0)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("request_irq(%d) = %d", p_LnxWrpFmDev->err_irq, _errno)); ++ ++ enable_irq_wake(p_LnxWrpFmDev->err_irq); ++ } ++ ++ p_LnxWrpFmDev->res = devm_request_mem_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize, "fman"); ++ if (unlikely(p_LnxWrpFmDev->res == NULL)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("request_mem_region() failed")); ++ ++ p_LnxWrpFmDev->fmBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize)); ++ if (unlikely(p_LnxWrpFmDev->fmBaseAddr == 0)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed")); ++ ++ if (SYS_RegisterIoMap((uint64_t)p_LnxWrpFmDev->fmBaseAddr, (uint64_t)p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM memory map")); ++ ++ dev_res = __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize, "fman-muram"); ++ if (unlikely(dev_res == NULL)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("__devm_request_region() failed")); ++ ++ p_LnxWrpFmDev->fmMuramBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize)); ++ if (unlikely(p_LnxWrpFmDev->fmMuramBaseAddr == 0)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed")); ++ ++ if (SYS_RegisterIoMap((uint64_t)p_LnxWrpFmDev->fmMuramBaseAddr, (uint64_t)p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM MURAM memory map")); ++ ++ if (p_LnxWrpFmDev->fmRtcPhysBaseAddr) ++ { ++ dev_res = __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize, "fman-rtc"); ++ if (unlikely(dev_res == NULL)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("__devm_request_region() failed")); ++ ++ p_LnxWrpFmDev->fmRtcBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize)); ++ if (unlikely(p_LnxWrpFmDev->fmRtcBaseAddr == 0)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed")); ++ ++ if (SYS_RegisterIoMap((uint64_t)p_LnxWrpFmDev->fmRtcBaseAddr, (uint64_t)p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-RTC memory map")); ++ } ++ ++#if (DPAA_VERSION >= 11) ++ if (p_LnxWrpFmDev->fmVspPhysBaseAddr) { ++ dev_res = __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmVspPhysBaseAddr, p_LnxWrpFmDev->fmVspMemSize, "fman-vsp"); ++ if (unlikely(dev_res == NULL)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("__devm_request_region() failed")); ++ ++ p_LnxWrpFmDev->fmVspBaseAddr = PTR_TO_UINT(devm_ioremap(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmVspPhysBaseAddr, p_LnxWrpFmDev->fmVspMemSize)); ++ if (unlikely(p_LnxWrpFmDev->fmVspBaseAddr == 0)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("devm_ioremap() failed")); ++ } ++#endif ++ ++ p_LnxWrpFmDev->fmDevSettings.param.baseAddr = p_LnxWrpFmDev->fmBaseAddr; ++ p_LnxWrpFmDev->fmDevSettings.param.fmId = p_LnxWrpFmDev->id; ++ p_LnxWrpFmDev->fmDevSettings.param.irq = NO_IRQ; ++ p_LnxWrpFmDev->fmDevSettings.param.errIrq = NO_IRQ; ++ p_LnxWrpFmDev->fmDevSettings.param.f_Exception = LnxwrpFmDevExceptionsCb; ++ p_LnxWrpFmDev->fmDevSettings.param.f_BusError = LnxwrpFmDevBusErrorCb; ++ p_LnxWrpFmDev->fmDevSettings.param.h_App = p_LnxWrpFmDev; ++ ++ return FillRestFmInfo(p_LnxWrpFmDev); ++} ++ ++#ifndef CONFIG_FMAN_ARM ++/* ++ * Table for matching compatible strings, for device tree ++ * guts node, for QorIQ SOCs. ++ * "fsl,qoriq-device-config-2.0" corresponds to T4 & B4 ++ * SOCs. For the older SOCs "fsl,qoriq-device-config-1.0" ++ * string would be used. ++*/ ++static const struct of_device_id guts_device_ids[] = { ++ { .compatible = "fsl,qoriq-device-config-1.0", }, ++ { .compatible = "fsl,qoriq-device-config-2.0", }, ++ {} ++}; ++ ++static unsigned int get_rcwsr(int regnum) ++{ ++ struct ccsr_guts __iomem *guts_regs = NULL; ++ struct device_node *guts_node; ++ ++ guts_node = of_find_matching_node(NULL, guts_device_ids); ++ if (!guts_node) { ++ pr_err("could not find GUTS node\n"); ++ return 0; ++ } ++ guts_regs = of_iomap(guts_node, 0); ++ of_node_put(guts_node); ++ if (!guts_regs) { ++ pr_err("ioremap of GUTS node failed\n"); ++ return 0; ++ } ++ ++ return ioread32be(&guts_regs->rcwsr[regnum]); ++} ++ ++#define FMAN1_ALL_MACS_MASK 0xFCC00000 ++#define FMAN2_ALL_MACS_MASK 0x000FCC00 ++ ++/** ++ * @Function ResetOnInitErrata_A007273 ++ * ++ * @Description Workaround for Errata A-007273 ++ * This workaround is required to avoid a FMan hang during reset on initialization. ++ * Enable all MACs in guts.devdisr2 register, ++ * then perform a regular FMan reset and then restore MACs to their original state. ++ * ++ * @Param[in] h_Fm - FM module descriptor ++ * ++ * @Return None. ++ */ ++void ResetOnInitErrata_A007273(t_Handle h_Fm) ++{ ++ struct ccsr_guts __iomem *guts_regs = NULL; ++ struct device_node *guts_node; ++ u32 devdisr2, enableMacs; ++ ++ /* Get guts registers */ ++ guts_node = of_find_matching_node(NULL, guts_device_ids); ++ if (!guts_node) { ++ pr_err("could not find GUTS node\n"); ++ return; ++ } ++ guts_regs = of_iomap(guts_node, 0); ++ of_node_put(guts_node); ++ if (!guts_regs) { ++ pr_err("ioremap of GUTS node failed\n"); ++ return; ++ } ++ ++ /* Read current state */ ++ devdisr2 = ioread32be(&guts_regs->devdisr2); ++ ++ if (FmGetId(h_Fm) == 0) ++ enableMacs = devdisr2 & ~FMAN1_ALL_MACS_MASK; ++ else ++ enableMacs = devdisr2 & ~FMAN2_ALL_MACS_MASK; ++ ++ /* Enable all MACs */ ++ iowrite32be(enableMacs, &guts_regs->devdisr2); ++ ++ /* Perform standard FMan reset */ ++ FmReset(h_Fm); ++ ++ /* Restore devdisr2 value */ ++ iowrite32be(devdisr2, &guts_regs->devdisr2); ++ ++ iounmap(guts_regs); ++} ++#endif ++ ++static t_Error InitFmDev(t_LnxWrpFmDev *p_LnxWrpFmDev) ++{ ++ const struct qe_firmware *fw; ++ ++ if (!p_LnxWrpFmDev->active) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM not configured!!!")); ++ ++ if ((p_LnxWrpFmDev->h_MuramDev = FM_MURAM_ConfigAndInit(p_LnxWrpFmDev->fmMuramBaseAddr, p_LnxWrpFmDev->fmMuramMemSize)) == NULL) ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-MURAM!")); ++ ++ /* Loading the fman-controller code */ ++ fw = FindFmanMicrocode(); ++ ++ if (!fw) { ++ /* this forces the reuse of the current IRAM content */ ++ p_LnxWrpFmDev->fmDevSettings.param.firmware.size = 0; ++ p_LnxWrpFmDev->fmDevSettings.param.firmware.p_Code = NULL; ++ } else { ++ p_LnxWrpFmDev->fmDevSettings.param.firmware.p_Code = ++ (void *) fw + be32_to_cpu(fw->microcode[0].code_offset); ++ p_LnxWrpFmDev->fmDevSettings.param.firmware.size = ++ sizeof(u32) * be32_to_cpu(fw->microcode[0].count); ++ DBG(INFO, ("Loading fman-controller code version %d.%d.%d", ++ fw->microcode[0].major, ++ fw->microcode[0].minor, ++ fw->microcode[0].revision)); ++ } ++ ++#ifdef CONFIG_FMAN_ARM ++ { /* endianness adjustments: byteswap the ucode retrieved from the f/w blob */ ++ int i; ++ int usz = p_LnxWrpFmDev->fmDevSettings.param.firmware.size; ++ void * p_Code = p_LnxWrpFmDev->fmDevSettings.param.firmware.p_Code; ++ u32 *dest = kzalloc(usz, GFP_KERNEL); ++ ++ if (p_Code && dest) ++ for(i=0; i < usz / 4; ++i) ++ dest[i] = be32_to_cpu(((u32 *)p_Code)[i]); ++ ++ p_LnxWrpFmDev->fmDevSettings.param.firmware.p_Code = dest; ++ } ++#endif ++ ++ p_LnxWrpFmDev->fmDevSettings.param.h_FmMuram = p_LnxWrpFmDev->h_MuramDev; ++ ++#if (DPAA_VERSION >= 11) ++ if (p_LnxWrpFmDev->fmVspBaseAddr) { ++ p_LnxWrpFmDev->fmDevSettings.param.vspBaseAddr = p_LnxWrpFmDev->fmVspBaseAddr; ++ p_LnxWrpFmDev->fmDevSettings.param.partVSPBase = 0; ++ p_LnxWrpFmDev->fmDevSettings.param.partNumOfVSPs = FM_VSP_MAX_NUM_OF_ENTRIES; ++ } ++#endif ++ ++#ifdef CONFIG_FMAN_ARM ++ p_LnxWrpFmDev->fmDevSettings.param.fmMacClkRatio = 1; ++#else ++ if(p_LnxWrpFmDev->fmDevSettings.param.fmId == 0) ++ p_LnxWrpFmDev->fmDevSettings.param.fmMacClkRatio = ++ !!(get_rcwsr(4) & 0x2); /* RCW[FM_MAC_RAT0] */ ++ else ++ p_LnxWrpFmDev->fmDevSettings.param.fmMacClkRatio = ++ !!(get_rcwsr(4) & 0x1); /* RCW[FM_MAC_RAT1] */ ++ ++ { ++ /* T4 Devices ClkRatio is always 1 regardless of RCW[FM_MAC_RAT1] */ ++ uint32_t svr; ++ svr = mfspr(SPRN_SVR); ++ ++ if ((svr & SVR_DEVICE_ID_MASK) == SVR_T4_DEVICE_ID) ++ p_LnxWrpFmDev->fmDevSettings.param.fmMacClkRatio = 1; ++ } ++#endif /* CONFIG_FMAN_ARM */ ++ ++ if ((p_LnxWrpFmDev->h_Dev = FM_Config(&p_LnxWrpFmDev->fmDevSettings.param)) == NULL) ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM")); ++ ++ ++ if (FM_ConfigResetOnInit(p_LnxWrpFmDev->h_Dev, TRUE) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM")); ++ ++#ifndef CONFIG_FMAN_ARM ++#ifdef FM_HANG_AT_RESET_MAC_CLK_DISABLED_ERRATA_FMAN_A007273 ++ if (FM_ConfigResetOnInitOverrideCallback(p_LnxWrpFmDev->h_Dev, ResetOnInitErrata_A007273) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM")); ++#endif /* FM_HANG_AT_RESET_MAC_CLK_DISABLED_ERRATA_FMAN_A007273 */ ++#endif /* CONFIG_FMAN_ARM */ ++ ++#ifdef CONFIG_FMAN_P1023 ++ if (FM_ConfigDmaAidOverride(p_LnxWrpFmDev->h_Dev, TRUE) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM")); ++#endif ++ ++ ++ CheckNConfigFmAdvArgs(p_LnxWrpFmDev); ++ ++ if (FM_Init(p_LnxWrpFmDev->h_Dev) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM")); ++ ++ /* TODO: Why we mask these interrupts? */ ++ if (p_LnxWrpFmDev->err_irq == 0) { ++ FM_SetException(p_LnxWrpFmDev->h_Dev, e_FM_EX_DMA_BUS_ERROR,FALSE); ++ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_READ_ECC,FALSE); ++ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_SYSTEM_WRITE_ECC,FALSE); ++ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_FM_WRITE_ECC,FALSE); ++ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_DMA_SINGLE_PORT_ECC, FALSE); ++ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_FPM_STALL_ON_TASKS , FALSE); ++ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_FPM_SINGLE_ECC, FALSE); ++ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_FPM_DOUBLE_ECC,FALSE); ++ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_QMI_SINGLE_ECC, FALSE); ++ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_QMI_DOUBLE_ECC,FALSE); ++ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,FALSE); ++ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_LIST_RAM_ECC,FALSE); ++ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_STORAGE_PROFILE_ECC, FALSE); ++ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_STATISTICS_RAM_ECC, FALSE); ++ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_BMI_DISPATCH_RAM_ECC, FALSE); ++ FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_IRAM_ECC,FALSE); ++ /* TODO: FmDisableRamsEcc assert for ramsEccOwners. ++ * FM_SetException(p_LnxWrpFmDev->h_Dev,e_FM_EX_MURAM_ECC,FALSE);*/ ++ } ++ ++ if (p_LnxWrpFmDev->fmRtcBaseAddr) ++ { ++ t_FmRtcParams fmRtcParam; ++ ++ memset(&fmRtcParam, 0, sizeof(fmRtcParam)); ++ fmRtcParam.h_App = p_LnxWrpFmDev; ++ fmRtcParam.h_Fm = p_LnxWrpFmDev->h_Dev; ++ fmRtcParam.baseAddress = p_LnxWrpFmDev->fmRtcBaseAddr; ++ ++ if(!(p_LnxWrpFmDev->h_RtcDev = FM_RTC_Config(&fmRtcParam))) ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-RTC")); ++ ++ if (FM_RTC_ConfigPeriod(p_LnxWrpFmDev->h_RtcDev, DPA_PTP_NOMINAL_FREQ_PERIOD_NS) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-RTC")); ++ ++ if (FM_RTC_Init(p_LnxWrpFmDev->h_RtcDev) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-RTC")); ++ } ++ ++ return E_OK; ++} ++ ++/* TODO: to be moved back here */ ++extern void FreeFmPcdDev(t_LnxWrpFmDev *p_LnxWrpFmDev); ++ ++static void FreeFmDev(t_LnxWrpFmDev *p_LnxWrpFmDev) ++{ ++ if (!p_LnxWrpFmDev->active) ++ return; ++ ++ FreeFmPcdDev(p_LnxWrpFmDev); ++ ++ if (p_LnxWrpFmDev->h_RtcDev) ++ FM_RTC_Free(p_LnxWrpFmDev->h_RtcDev); ++ ++ if (p_LnxWrpFmDev->h_Dev) ++ FM_Free(p_LnxWrpFmDev->h_Dev); ++ ++ if (p_LnxWrpFmDev->h_MuramDev) ++ FM_MURAM_Free(p_LnxWrpFmDev->h_MuramDev); ++ ++ if (p_LnxWrpFmDev->fmRtcBaseAddr) ++ { ++ SYS_UnregisterIoMap(p_LnxWrpFmDev->fmRtcBaseAddr); ++ devm_iounmap(p_LnxWrpFmDev->dev, UINT_TO_PTR(p_LnxWrpFmDev->fmRtcBaseAddr)); ++ __devm_release_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmRtcPhysBaseAddr, p_LnxWrpFmDev->fmRtcMemSize); ++ } ++ SYS_UnregisterIoMap(p_LnxWrpFmDev->fmMuramBaseAddr); ++ devm_iounmap(p_LnxWrpFmDev->dev, UINT_TO_PTR(p_LnxWrpFmDev->fmMuramBaseAddr)); ++ __devm_release_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, p_LnxWrpFmDev->fmMuramPhysBaseAddr, p_LnxWrpFmDev->fmMuramMemSize); ++ SYS_UnregisterIoMap(p_LnxWrpFmDev->fmBaseAddr); ++ devm_iounmap(p_LnxWrpFmDev->dev, UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr)); ++ devm_release_mem_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->fmPhysBaseAddr, p_LnxWrpFmDev->fmMemSize); ++ if (p_LnxWrpFmDev->err_irq != 0) { ++ devm_free_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->err_irq, p_LnxWrpFmDev); ++ } ++ ++ devm_free_irq(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->irq, p_LnxWrpFmDev); ++} ++ ++/* FMan character device file operations */ ++extern struct file_operations fm_fops; ++ ++static int /*__devinit*/ fm_probe(struct platform_device *of_dev) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev; ++ ++ if ((p_LnxWrpFmDev = ReadFmDevTreeNode(of_dev)) == NULL) ++ return -EIO; ++ if (ConfigureFmDev(p_LnxWrpFmDev) != E_OK) ++ return -EIO; ++ if (InitFmDev(p_LnxWrpFmDev) != E_OK) ++ return -EIO; ++ ++ /* IOCTL ABI checking */ ++ LnxWrpPCDIOCTLEnumChecking(); ++ LnxWrpPCDIOCTLTypeChecking(); ++ ++ Sprint (p_LnxWrpFmDev->name, "%s%d", DEV_FM_NAME, p_LnxWrpFmDev->id); ++ ++ /* Register to the /dev for IOCTL API */ ++ /* Register dynamically a new major number for the character device: */ ++ if ((p_LnxWrpFmDev->major = register_chrdev(0, p_LnxWrpFmDev->name, &fm_fops)) <= 0) { ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Failed to allocate a major number for device \"%s\"", p_LnxWrpFmDev->name)); ++ return -EIO; ++ } ++ ++ /* Creating classes for FM */ ++ DBG(TRACE ,("class_create fm_class")); ++ p_LnxWrpFmDev->fm_class = class_create(THIS_MODULE, p_LnxWrpFmDev->name); ++ if (IS_ERR(p_LnxWrpFmDev->fm_class)) { ++ unregister_chrdev(p_LnxWrpFmDev->major, p_LnxWrpFmDev->name); ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("class_create error fm_class")); ++ return -EIO; ++ } ++ ++ device_create(p_LnxWrpFmDev->fm_class, NULL, MKDEV(p_LnxWrpFmDev->major, DEV_FM_MINOR_BASE), NULL, ++ "fm%d", p_LnxWrpFmDev->id); ++ device_create(p_LnxWrpFmDev->fm_class, NULL, MKDEV(p_LnxWrpFmDev->major, DEV_FM_PCD_MINOR_BASE), NULL, ++ "fm%d-pcd", p_LnxWrpFmDev->id); ++ dev_set_drvdata(p_LnxWrpFmDev->dev, p_LnxWrpFmDev); ++ ++ /* create sysfs entries for stats and regs */ ++ if ( fm_sysfs_create(p_LnxWrpFmDev->dev) !=0 ) ++ { ++ FreeFmDev(p_LnxWrpFmDev); ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Unable to create sysfs entry - fm!!!")); ++ return -EIO; ++ } ++ ++#ifdef CONFIG_PM ++ device_set_wakeup_capable(p_LnxWrpFmDev->dev, true); ++#endif ++ ++ DBG(TRACE, ("FM%d probed", p_LnxWrpFmDev->id)); ++ ++ return 0; ++} ++ ++static int fm_remove(struct platform_device *of_dev) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev; ++ struct device *dev; ++ ++ dev = &of_dev->dev; ++ p_LnxWrpFmDev = dev_get_drvdata(dev); ++ ++ fm_sysfs_destroy(dev); ++ ++ DBG(TRACE, ("destroy fm_class")); ++ device_destroy(p_LnxWrpFmDev->fm_class, MKDEV(p_LnxWrpFmDev->major, DEV_FM_MINOR_BASE)); ++ device_destroy(p_LnxWrpFmDev->fm_class, MKDEV(p_LnxWrpFmDev->major, DEV_FM_PCD_MINOR_BASE)); ++ class_destroy(p_LnxWrpFmDev->fm_class); ++ ++ /* Destroy chardev */ ++ unregister_chrdev(p_LnxWrpFmDev->major, p_LnxWrpFmDev->name); ++ ++ FreeFmDev(p_LnxWrpFmDev); ++ ++ DestroyFmDev(p_LnxWrpFmDev); ++ ++ dev_set_drvdata(dev, NULL); ++ ++ return 0; ++} ++ ++static const struct of_device_id fm_match[] = { ++ { ++ .compatible = "fsl,fman" ++ }, ++ {} ++}; ++#ifndef MODULE ++MODULE_DEVICE_TABLE(of, fm_match); ++#endif /* !MODULE */ ++ ++#ifdef CONFIG_PM ++ ++#define SCFG_FMCLKDPSLPCR_ADDR 0xFFE0FC00C ++#define SCFG_FMCLKDPSLPCR_DS_VAL 0x48402000 ++#define SCFG_FMCLKDPSLPCR_NORMAL_VAL 0x00402000 ++ ++struct device *g_fm_dev; ++ ++static int fm_soc_suspend(struct device *dev) ++{ ++ int err = 0; ++ uint32_t *fmclk; ++ t_LnxWrpFmDev *p_LnxWrpFmDev = dev_get_drvdata(get_device(dev)); ++ g_fm_dev = dev; ++ fmclk = ioremap(SCFG_FMCLKDPSLPCR_ADDR, 4); ++ WRITE_UINT32(*fmclk, SCFG_FMCLKDPSLPCR_DS_VAL); ++ if (p_LnxWrpFmDev->h_DsarRxPort) ++ { ++#ifdef CONFIG_FSL_QORIQ_PM ++ device_set_wakeup_enable(p_LnxWrpFmDev->dev, 1); ++#endif ++ err = FM_PORT_EnterDsarFinal(p_LnxWrpFmDev->h_DsarRxPort, ++ p_LnxWrpFmDev->h_DsarTxPort); ++ } ++ return err; ++} ++ ++static int fm_soc_resume(struct device *dev) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev = dev_get_drvdata(get_device(dev)); ++ uint32_t *fmclk; ++ fmclk = ioremap(SCFG_FMCLKDPSLPCR_ADDR, 4); ++ WRITE_UINT32(*fmclk, SCFG_FMCLKDPSLPCR_NORMAL_VAL); ++ if (p_LnxWrpFmDev->h_DsarRxPort) ++ { ++#ifdef CONFIG_FSL_QORIQ_PM ++ device_set_wakeup_enable(p_LnxWrpFmDev->dev, 0); ++#endif ++ FM_PORT_ExitDsar(p_LnxWrpFmDev->h_DsarRxPort, ++ p_LnxWrpFmDev->h_DsarTxPort); ++ p_LnxWrpFmDev->h_DsarRxPort = 0; ++ p_LnxWrpFmDev->h_DsarTxPort = 0; ++ } ++ return 0; ++} ++ ++static const struct dev_pm_ops fm_pm_ops = { ++ .suspend = fm_soc_suspend, ++ .resume = fm_soc_resume, ++}; ++ ++#define FM_PM_OPS (&fm_pm_ops) ++ ++#else /* CONFIG_PM */ ++ ++#define FM_PM_OPS NULL ++ ++#endif /* CONFIG_PM */ ++ ++static struct platform_driver fm_driver = { ++ .driver = { ++ .name = "fsl-fman", ++ .of_match_table = fm_match, ++ .owner = THIS_MODULE, ++ .pm = FM_PM_OPS, ++ }, ++ .probe = fm_probe, ++ .remove = fm_remove ++}; ++ ++t_Handle LNXWRP_FM_Init(void) ++{ ++ memset(&lnxWrpFm, 0, sizeof(lnxWrpFm)); ++ mutex_init(&lnxwrp_mutex); ++ ++ /* Register to the DTB for basic FM API */ ++ platform_driver_register(&fm_driver); ++ ++ return &lnxWrpFm; ++} ++ ++t_Error LNXWRP_FM_Free(t_Handle h_LnxWrpFm) ++{ ++ platform_driver_unregister(&fm_driver); ++ mutex_destroy(&lnxwrp_mutex); ++ ++ return E_OK; ++} ++ ++ ++struct fm * fm_bind(struct device *fm_dev) ++{ ++ return (struct fm *)(dev_get_drvdata(get_device(fm_dev))); ++} ++EXPORT_SYMBOL(fm_bind); ++ ++void fm_unbind(struct fm *fm) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm; ++ ++ put_device(p_LnxWrpFmDev->dev); ++} ++EXPORT_SYMBOL(fm_unbind); ++ ++struct resource * fm_get_mem_region(struct fm *fm) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm; ++ ++ return p_LnxWrpFmDev->res; ++} ++EXPORT_SYMBOL(fm_get_mem_region); ++ ++void * fm_get_handle(struct fm *fm) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm; ++ ++ return (void *)p_LnxWrpFmDev->h_Dev; ++} ++EXPORT_SYMBOL(fm_get_handle); ++ ++void * fm_get_rtc_handle(struct fm *fm) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev*)fm; ++ ++ return (void *)p_LnxWrpFmDev->h_RtcDev; ++} ++EXPORT_SYMBOL(fm_get_rtc_handle); ++ ++struct fm_port * fm_port_bind (struct device *fm_port_dev) ++{ ++ return (struct fm_port *)(dev_get_drvdata(get_device(fm_port_dev))); ++} ++EXPORT_SYMBOL(fm_port_bind); ++ ++void fm_port_unbind(struct fm_port *port) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; ++ ++ put_device(p_LnxWrpFmPortDev->dev); ++} ++EXPORT_SYMBOL(fm_port_unbind); ++ ++void *fm_port_get_handle(const struct fm_port *port) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; ++ ++ return (void *)p_LnxWrpFmPortDev->h_Dev; ++} ++EXPORT_SYMBOL(fm_port_get_handle); ++ ++u64 *fm_port_get_buffer_time_stamp(const struct fm_port *port, ++ const void *data) ++{ ++ return FM_PORT_GetBufferTimeStamp(fm_port_get_handle(port), ++ (void *)data); ++} ++EXPORT_SYMBOL(fm_port_get_buffer_time_stamp); ++ ++void fm_port_get_base_addr(const struct fm_port *port, uint64_t *base_addr) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port; ++ ++ *base_addr = p_LnxWrpFmPortDev->settings.param.baseAddr; ++} ++EXPORT_SYMBOL(fm_port_get_base_addr); ++ ++void fm_port_pcd_bind (struct fm_port *port, struct fm_port_pcd_param *params) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; ++ ++ p_LnxWrpFmPortDev->pcd_owner_params.cba = params->cba; ++ p_LnxWrpFmPortDev->pcd_owner_params.cbf = params->cbf; ++ p_LnxWrpFmPortDev->pcd_owner_params.dev = params->dev; ++} ++EXPORT_SYMBOL(fm_port_pcd_bind); ++ ++void fm_port_get_buff_layout_ext_params(struct fm_port *port, struct fm_port_params *params) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port; ++ struct device_node *fm_node, *port_node; ++ const uint32_t *uint32_prop; ++ int lenp; ++ ++ params->data_align = 0; ++ params->manip_extra_space = 0; ++ ++ fm_node = GetFmAdvArgsDevTreeNode(((t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev)->id); ++ if (!fm_node) /* no advance parameters for FMan */ ++ return; ++ ++ port_node = GetFmPortAdvArgsDevTreeNode(fm_node, ++ p_LnxWrpFmPortDev->settings.param.portType, ++ p_LnxWrpFmPortDev->settings.param.portId); ++ if (!port_node) /* no advance parameters for FMan-Port */ ++ return; ++ ++ uint32_prop = (uint32_t *)of_get_property(port_node, "buffer-layout", &lenp); ++ if (uint32_prop) { ++ if (WARN_ON(lenp != sizeof(uint32_t)*2)) ++ return; ++ ++ params->manip_extra_space = (uint8_t)be32_to_cpu(uint32_prop[0]); ++ params->data_align = (uint16_t)be32_to_cpu(uint32_prop[1]); ++ } ++ ++ of_node_put(port_node); ++ of_node_put(fm_node); ++} ++EXPORT_SYMBOL(fm_port_get_buff_layout_ext_params); ++ ++uint16_t fm_get_tx_port_channel(struct fm_port *port) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; ++ ++ return p_LnxWrpFmPortDev->txCh; ++} ++EXPORT_SYMBOL(fm_get_tx_port_channel); ++ ++int fm_port_enable (struct fm_port *port) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; ++ t_Error err = FM_PORT_Enable(p_LnxWrpFmPortDev->h_Dev); ++ ++ return GET_ERROR_TYPE(err); ++} ++EXPORT_SYMBOL(fm_port_enable); ++ ++int fm_port_disable(struct fm_port *port) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)port; ++ t_Error err = FM_PORT_Disable(p_LnxWrpFmPortDev->h_Dev); ++ ++ return GET_ERROR_TYPE(err); ++} ++EXPORT_SYMBOL(fm_port_disable); ++ ++int fm_port_set_rate_limit(struct fm_port *port, ++ uint16_t max_burst_size, ++ uint32_t rate_limit) ++{ ++ t_FmPortRateLimit param; ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port; ++ int err = 0; ++ ++ param.maxBurstSize = max_burst_size; ++ param.rateLimit = rate_limit; ++ param.rateLimitDivider = 0; ++ ++ err = FM_PORT_SetRateLimit(p_LnxWrpFmPortDev->h_Dev, ¶m); ++ return err; ++} ++EXPORT_SYMBOL(fm_port_set_rate_limit); ++ ++int fm_port_del_rate_limit(struct fm_port *port) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port; ++ ++ FM_PORT_DeleteRateLimit(p_LnxWrpFmPortDev->h_Dev); ++ return 0; ++} ++EXPORT_SYMBOL(fm_port_del_rate_limit); ++ ++void FM_PORT_Dsar_DumpRegs(void); ++int ar_showmem(struct file *file, const char __user *buffer, ++ unsigned long count, void *data) ++{ ++ FM_PORT_Dsar_DumpRegs(); ++ return 2; ++} ++ ++struct auto_res_tables_sizes *fm_port_get_autores_maxsize( ++ struct fm_port *port) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port; ++ return &p_LnxWrpFmPortDev->dsar_table_sizes; ++} ++EXPORT_SYMBOL(fm_port_get_autores_maxsize); ++ ++int fm_port_enter_autores_for_deepsleep(struct fm_port *port, ++ struct auto_res_port_params *params) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port; ++ t_LnxWrpFmDev* p_LnxWrpFmDev = (t_LnxWrpFmDev*)p_LnxWrpFmPortDev->h_LnxWrpFmDev; ++ p_LnxWrpFmDev->h_DsarRxPort = p_LnxWrpFmPortDev->h_Dev; ++ p_LnxWrpFmDev->h_DsarTxPort = params->h_FmPortTx; ++ ++ /*Register other under /proc/autoresponse */ ++ if (WARN_ON(sizeof(t_FmPortDsarParams) != sizeof(struct auto_res_port_params))) ++ return -EFAULT; ++ ++ FM_PORT_EnterDsar(p_LnxWrpFmPortDev->h_Dev, (t_FmPortDsarParams*)params); ++ return 0; ++} ++EXPORT_SYMBOL(fm_port_enter_autores_for_deepsleep); ++ ++void fm_port_exit_auto_res_for_deep_sleep(struct fm_port *port_rx, ++ struct fm_port *port_tx) ++{ ++} ++EXPORT_SYMBOL(fm_port_exit_auto_res_for_deep_sleep); ++ ++int fm_port_get_autores_stats(struct fm_port *port, ++ struct auto_res_port_stats *stats) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port; ++ if (WARN_ON(sizeof(t_FmPortDsarStats) != sizeof(struct auto_res_port_stats))) ++ return -EFAULT; ++ return FM_PORT_GetDsarStats(p_LnxWrpFmPortDev->h_Dev, (t_FmPortDsarStats*)stats); ++} ++EXPORT_SYMBOL(fm_port_get_autores_stats); ++ ++int fm_port_suspend(struct fm_port *port) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port; ++ if (!FM_PORT_IsInDsar(p_LnxWrpFmPortDev->h_Dev)) ++ return FM_PORT_Disable(p_LnxWrpFmPortDev->h_Dev); ++ else ++ return 0; ++} ++EXPORT_SYMBOL(fm_port_suspend); ++ ++int fm_port_resume(struct fm_port *port) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port; ++ if (!FM_PORT_IsInDsar(p_LnxWrpFmPortDev->h_Dev)) ++ return FM_PORT_Enable(p_LnxWrpFmPortDev->h_Dev); ++ else ++ return 0; ++} ++EXPORT_SYMBOL(fm_port_resume); ++ ++bool fm_port_is_in_auto_res_mode(struct fm_port *port) ++{ ++ return FM_PORT_IsInDsar(port); ++} ++EXPORT_SYMBOL(fm_port_is_in_auto_res_mode); ++ ++#ifdef CONFIG_FMAN_PFC ++int fm_port_set_pfc_priorities_mapping_to_qman_wq(struct fm_port *port, ++ uint8_t prio, uint8_t wq) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port; ++ int err; ++ int _errno; ++ ++ err = FM_PORT_SetPfcPrioritiesMappingToQmanWQ(p_LnxWrpFmPortDev->h_Dev, ++ prio, wq); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_PORT_SetPfcPrioritiesMappingToQmanWQ() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_port_set_pfc_priorities_mapping_to_qman_wq); ++#endif ++ ++int fm_mac_set_exception(struct fm_mac_dev *fm_mac_dev, ++ e_FmMacExceptions exception, bool enable) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MAC_SetException(fm_mac_dev, exception, enable); ++ ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MAC_SetException() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_mac_set_exception); ++ ++int fm_mac_free(struct fm_mac_dev *fm_mac_dev) ++{ ++ int err; ++ int _error; ++ ++ err = FM_MAC_Free(fm_mac_dev); ++ _error = -GET_ERROR_TYPE(err); ++ ++ if (unlikely(_error < 0)) ++ pr_err("FM_MAC_Free() = 0x%08x\n", err); ++ ++ return _error; ++} ++EXPORT_SYMBOL(fm_mac_free); ++ ++struct fm_mac_dev *fm_mac_config(t_FmMacParams *params) ++{ ++ struct fm_mac_dev *fm_mac_dev; ++ ++ fm_mac_dev = FM_MAC_Config(params); ++ if (unlikely(fm_mac_dev == NULL)) ++ pr_err("FM_MAC_Config() failed\n"); ++ ++ return fm_mac_dev; ++} ++EXPORT_SYMBOL(fm_mac_config); ++ ++int fm_mac_config_max_frame_length(struct fm_mac_dev *fm_mac_dev, ++ int len) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MAC_ConfigMaxFrameLength(fm_mac_dev, len); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MAC_ConfigMaxFrameLength() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_mac_config_max_frame_length); ++ ++int fm_mac_config_pad_and_crc(struct fm_mac_dev *fm_mac_dev, bool enable) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MAC_ConfigPadAndCrc(fm_mac_dev, enable); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MAC_ConfigPadAndCrc() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_mac_config_pad_and_crc); ++ ++int fm_mac_config_half_duplex(struct fm_mac_dev *fm_mac_dev, bool enable) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MAC_ConfigHalfDuplex(fm_mac_dev, enable); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MAC_ConfigHalfDuplex() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_mac_config_half_duplex); ++ ++int fm_mac_config_reset_on_init(struct fm_mac_dev *fm_mac_dev, bool enable) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MAC_ConfigResetOnInit(fm_mac_dev, enable); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MAC_ConfigResetOnInit() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_mac_config_reset_on_init); ++ ++int fm_mac_init(struct fm_mac_dev *fm_mac_dev) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MAC_Init(fm_mac_dev); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MAC_Init() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_mac_init); ++ ++int fm_mac_get_version(struct fm_mac_dev *fm_mac_dev, uint32_t *version) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MAC_GetVesrion(fm_mac_dev, version); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MAC_GetVesrion() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_mac_get_version); ++ ++int fm_mac_enable(struct fm_mac_dev *fm_mac_dev) ++{ ++ int _errno; ++ t_Error err; ++ ++ err = FM_MAC_Enable(fm_mac_dev, e_COMM_MODE_RX_AND_TX); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MAC_Enable() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_mac_enable); ++ ++int fm_mac_disable(struct fm_mac_dev *fm_mac_dev) ++{ ++ int _errno; ++ t_Error err; ++ ++ err = FM_MAC_Disable(fm_mac_dev, e_COMM_MODE_RX_AND_TX); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MAC_Disable() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_mac_disable); ++ ++int fm_mac_resume(struct fm_mac_dev *fm_mac_dev) ++{ ++ int _errno; ++ t_Error err; ++ ++ err = FM_MAC_Resume(fm_mac_dev); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MAC_Resume() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_mac_resume); ++ ++int fm_mac_set_promiscuous(struct fm_mac_dev *fm_mac_dev, ++ bool enable) ++{ ++ int _errno; ++ t_Error err; ++ ++ err = FM_MAC_SetPromiscuous(fm_mac_dev, enable); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MAC_SetPromiscuous() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_mac_set_promiscuous); ++ ++int fm_mac_remove_hash_mac_addr(struct fm_mac_dev *fm_mac_dev, ++ t_EnetAddr *mac_addr) ++{ ++ int _errno; ++ t_Error err; ++ ++ err = FM_MAC_RemoveHashMacAddr(fm_mac_dev, mac_addr); ++ _errno = -GET_ERROR_TYPE(err); ++ if (_errno < 0) { ++ pr_err("FM_MAC_RemoveHashMacAddr() = 0x%08x\n", err); ++ return _errno; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(fm_mac_remove_hash_mac_addr); ++ ++int fm_mac_add_hash_mac_addr(struct fm_mac_dev *fm_mac_dev, ++ t_EnetAddr *mac_addr) ++{ ++ int _errno; ++ t_Error err; ++ ++ err = FM_MAC_AddHashMacAddr(fm_mac_dev, mac_addr); ++ _errno = -GET_ERROR_TYPE(err); ++ if (_errno < 0) { ++ pr_err("FM_MAC_AddHashMacAddr() = 0x%08x\n", err); ++ return _errno; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(fm_mac_add_hash_mac_addr); ++ ++int fm_mac_modify_mac_addr(struct fm_mac_dev *fm_mac_dev, ++ uint8_t *addr) ++{ ++ int _errno; ++ t_Error err; ++ ++ err = FM_MAC_ModifyMacAddr(fm_mac_dev, (t_EnetAddr *)addr); ++ _errno = -GET_ERROR_TYPE(err); ++ if (_errno < 0) ++ pr_err("FM_MAC_ModifyMacAddr() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_mac_modify_mac_addr); ++ ++int fm_mac_adjust_link(struct fm_mac_dev *fm_mac_dev, ++ bool link, int speed, bool duplex) ++{ ++ int _errno; ++ t_Error err; ++ ++ if (!link) { ++#if (DPAA_VERSION < 11) ++ FM_MAC_RestartAutoneg(fm_mac_dev); ++#endif ++ return 0; ++ } ++ ++ err = FM_MAC_AdjustLink(fm_mac_dev, speed, duplex); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MAC_AdjustLink() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_mac_adjust_link); ++ ++int fm_mac_enable_1588_time_stamp(struct fm_mac_dev *fm_mac_dev) ++{ ++ int _errno; ++ t_Error err; ++ ++ err = FM_MAC_Enable1588TimeStamp(fm_mac_dev); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MAC_Enable1588TimeStamp() = 0x%08x\n", err); ++ return _errno; ++} ++EXPORT_SYMBOL(fm_mac_enable_1588_time_stamp); ++ ++int fm_mac_disable_1588_time_stamp(struct fm_mac_dev *fm_mac_dev) ++{ ++ int _errno; ++ t_Error err; ++ ++ err = FM_MAC_Disable1588TimeStamp(fm_mac_dev); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MAC_Disable1588TimeStamp() = 0x%08x\n", err); ++ return _errno; ++} ++EXPORT_SYMBOL(fm_mac_disable_1588_time_stamp); ++ ++int fm_mac_set_rx_pause_frames( ++ struct fm_mac_dev *fm_mac_dev, bool en) ++{ ++ int _errno; ++ t_Error err; ++ ++ /* if rx pause is enabled, do NOT ignore pause frames */ ++ err = FM_MAC_SetRxIgnorePauseFrames(fm_mac_dev, !en); ++ ++ _errno = -GET_ERROR_TYPE(err); ++ if (_errno < 0) ++ pr_err("FM_MAC_SetRxIgnorePauseFrames() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_mac_set_rx_pause_frames); ++ ++#ifdef CONFIG_FMAN_PFC ++int fm_mac_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev, ++ bool en) ++{ ++ int _errno, i; ++ t_Error err; ++ ++ if (en) ++ for (i = 0; i < CONFIG_FMAN_PFC_COS_COUNT; i++) { ++ err = FM_MAC_SetTxPauseFrames(fm_mac_dev, ++ i, fsl_fm_pfc_quanta[i], ++ FSL_FM_PAUSE_THRESH_DEFAULT); ++ _errno = -GET_ERROR_TYPE(err); ++ if (_errno < 0) { ++ pr_err("FM_MAC_SetTxPauseFrames() = 0x%08x\n", err); ++ return _errno; ++ } ++ } ++ else ++ for (i = 0; i < CONFIG_FMAN_PFC_COS_COUNT; i++) { ++ err = FM_MAC_SetTxPauseFrames(fm_mac_dev, ++ i, FSL_FM_PAUSE_TIME_DISABLE, ++ FSL_FM_PAUSE_THRESH_DEFAULT); ++ _errno = -GET_ERROR_TYPE(err); ++ if (_errno < 0) { ++ pr_err("FM_MAC_SetTxPauseFrames() = 0x%08x\n", err); ++ return _errno; ++ } ++ } ++ ++ return _errno; ++} ++#else ++int fm_mac_set_tx_pause_frames(struct fm_mac_dev *fm_mac_dev, ++ bool en) ++{ ++ int _errno; ++ t_Error err; ++ ++ if (en) ++ err = FM_MAC_SetTxAutoPauseFrames(fm_mac_dev, ++ FSL_FM_PAUSE_TIME_ENABLE); ++ else ++ err = FM_MAC_SetTxAutoPauseFrames(fm_mac_dev, ++ FSL_FM_PAUSE_TIME_DISABLE); ++ ++ _errno = -GET_ERROR_TYPE(err); ++ if (_errno < 0) ++ pr_err("FM_MAC_SetTxAutoPauseFrames() = 0x%08x\n", err); ++ ++ return _errno; ++} ++#endif ++EXPORT_SYMBOL(fm_mac_set_tx_pause_frames); ++ ++int fm_rtc_enable(struct fm *fm_dev) ++{ ++ int _errno; ++ t_Error err; ++ ++ err = FM_RTC_Enable(fm_get_rtc_handle(fm_dev), 0); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_RTC_Enable = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_rtc_enable); ++ ++int fm_rtc_disable(struct fm *fm_dev) ++{ ++ int _errno; ++ t_Error err; ++ ++ err = FM_RTC_Disable(fm_get_rtc_handle(fm_dev)); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_RTC_Disable = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_rtc_disable); ++ ++int fm_rtc_get_cnt(struct fm *fm_dev, uint64_t *ts) ++{ ++ int _errno; ++ t_Error err; ++ ++ err = FM_RTC_GetCurrentTime(fm_get_rtc_handle(fm_dev), ts); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_RTC_GetCurrentTime = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_rtc_get_cnt); ++ ++int fm_rtc_set_cnt(struct fm *fm_dev, uint64_t ts) ++{ ++ int _errno; ++ t_Error err; ++ ++ err = FM_RTC_SetCurrentTime(fm_get_rtc_handle(fm_dev), ts); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_RTC_SetCurrentTime = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_rtc_set_cnt); ++ ++int fm_rtc_get_drift(struct fm *fm_dev, uint32_t *drift) ++{ ++ int _errno; ++ t_Error err; ++ ++ err = FM_RTC_GetFreqCompensation(fm_get_rtc_handle(fm_dev), ++ drift); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_RTC_GetFreqCompensation = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_rtc_get_drift); ++ ++int fm_rtc_set_drift(struct fm *fm_dev, uint32_t drift) ++{ ++ int _errno; ++ t_Error err; ++ ++ err = FM_RTC_SetFreqCompensation(fm_get_rtc_handle(fm_dev), ++ drift); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_RTC_SetFreqCompensation = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_rtc_set_drift); ++ ++int fm_rtc_set_alarm(struct fm *fm_dev, uint32_t id, ++ uint64_t time) ++{ ++ t_FmRtcAlarmParams alarm; ++ int _errno; ++ t_Error err; ++ ++ alarm.alarmId = id; ++ alarm.alarmTime = time; ++ alarm.f_AlarmCallback = NULL; ++ err = FM_RTC_SetAlarm(fm_get_rtc_handle(fm_dev), ++ &alarm); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_RTC_SetAlarm = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_rtc_set_alarm); ++ ++int fm_rtc_set_fiper(struct fm *fm_dev, uint32_t id, ++ uint64_t fiper) ++{ ++ t_FmRtcPeriodicPulseParams pp; ++ int _errno; ++ t_Error err; ++ ++ pp.periodicPulseId = id; ++ pp.periodicPulsePeriod = fiper; ++ pp.f_PeriodicPulseCallback = NULL; ++ err = FM_RTC_SetPeriodicPulse(fm_get_rtc_handle(fm_dev), &pp); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_RTC_SetPeriodicPulse = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_rtc_set_fiper); ++ ++#ifdef CONFIG_PTP_1588_CLOCK_DPAA ++int fm_rtc_enable_interrupt(struct fm *fm_dev, uint32_t events) ++{ ++ int _errno; ++ t_Error err; ++ ++ err = FM_RTC_EnableInterrupt(fm_get_rtc_handle(fm_dev), ++ events); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_RTC_EnableInterrupt = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_rtc_enable_interrupt); ++ ++int fm_rtc_disable_interrupt(struct fm *fm_dev, uint32_t events) ++{ ++ int _errno; ++ t_Error err; ++ ++ err = FM_RTC_DisableInterrupt(fm_get_rtc_handle(fm_dev), ++ events); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_RTC_DisableInterrupt = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_rtc_disable_interrupt); ++#endif ++ ++int fm_mac_set_wol(struct fm_port *port, struct fm_mac_dev *fm_mac_dev, bool en) ++{ ++ int _errno; ++ t_Error err; ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)port; ++ ++ /* Do not set WoL on AR ports */ ++ if (FM_PORT_IsInDsar(p_LnxWrpFmPortDev->h_Dev)) { ++ printk(KERN_WARNING "Port is AutoResponse enabled! WoL will not be set on this port!\n"); ++ return 0; ++ } ++ ++ err = FM_MAC_SetWakeOnLan(fm_mac_dev, en); ++ ++ _errno = -GET_ERROR_TYPE(err); ++ if (_errno < 0) ++ pr_err("FM_MAC_SetWakeOnLan() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_mac_set_wol); ++ ++void fm_mutex_lock(void) ++{ ++ mutex_lock(&lnxwrp_mutex); ++} ++EXPORT_SYMBOL(fm_mutex_lock); ++ ++void fm_mutex_unlock(void) ++{ ++ mutex_unlock(&lnxwrp_mutex); ++} ++EXPORT_SYMBOL(fm_mutex_unlock); ++ ++/*Macsec wrapper functions*/ ++struct fm_macsec_dev *fm_macsec_config(struct fm_macsec_params *fm_params) ++{ ++ struct fm_macsec_dev *fm_macsec_dev; ++ ++ fm_macsec_dev = FM_MACSEC_Config((t_FmMacsecParams *)fm_params); ++ if (unlikely(fm_macsec_dev == NULL)) ++ pr_err("FM_MACSEC_Config() failed\n"); ++ ++ return fm_macsec_dev; ++} ++EXPORT_SYMBOL(fm_macsec_config); ++ ++int fm_macsec_init(struct fm_macsec_dev *fm_macsec_dev) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_Init(fm_macsec_dev); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_Init() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_init); ++ ++int fm_macsec_free(struct fm_macsec_dev *fm_macsec_dev) ++{ ++ int err; ++ int _error; ++ ++ err = FM_MACSEC_Free(fm_macsec_dev); ++ _error = -GET_ERROR_TYPE(err); ++ ++ if (unlikely(_error < 0)) ++ pr_err("FM_MACSEC_Free() = 0x%08x\n", err); ++ ++ return _error; ++} ++EXPORT_SYMBOL(fm_macsec_free); ++ ++int fm_macsec_config_unknown_sci_frame_treatment(struct fm_macsec_dev ++ *fm_macsec_dev, ++ fm_macsec_unknown_sci_frame_treatment treat_mode) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_ConfigUnknownSciFrameTreatment(fm_macsec_dev, ++ treat_mode); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_ConfigUnknownSciFrameTreatmen() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_config_unknown_sci_frame_treatment); ++ ++int fm_macsec_config_invalid_tags_frame_treatment(struct fm_macsec_dev *fm_macsec_dev, ++ bool deliver_uncontrolled) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_ConfigInvalidTagsFrameTreatment(fm_macsec_dev, ++ deliver_uncontrolled); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MAC_ConfigMaxFrameLength() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_config_invalid_tags_frame_treatment); ++ ++int fm_macsec_config_kay_frame_treatment(struct fm_macsec_dev *fm_macsec_dev, ++ bool discard_uncontrolled) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment(fm_macsec_dev, ++ discard_uncontrolled); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatmen() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_config_kay_frame_treatment); ++ ++int fm_macsec_config_untag_frame_treatment(struct fm_macsec_dev *fm_macsec_dev, ++ fm_macsec_untag_frame_treatment treat_mode) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_ConfigUntagFrameTreatment(fm_macsec_dev, treat_mode); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_ConfigUntagFrameTreatment() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_config_untag_frame_treatment); ++ ++int fm_macsec_config_pn_exhaustion_threshold(struct fm_macsec_dev *fm_macsec_dev, ++ uint32_t pn_exh_thr) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_ConfigPnExhaustionThreshold(fm_macsec_dev, pn_exh_thr); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_ConfigPnExhaustionThreshold() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_config_pn_exhaustion_threshold); ++ ++int fm_macsec_config_keys_unreadable(struct fm_macsec_dev *fm_macsec_dev) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_ConfigKeysUnreadable(fm_macsec_dev); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_ConfigKeysUnreadable() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_config_keys_unreadable); ++ ++int fm_macsec_config_sectag_without_sci(struct fm_macsec_dev *fm_macsec_dev) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_ConfigSectagWithoutSCI(fm_macsec_dev); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_ConfigSectagWithoutSCI() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_config_sectag_without_sci); ++ ++int fm_macsec_config_exception(struct fm_macsec_dev *fm_macsec_dev, ++ fm_macsec_exception exception, bool enable) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_ConfigException(fm_macsec_dev, exception, enable); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_ConfigException() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_config_exception); ++ ++int fm_macsec_get_revision(struct fm_macsec_dev *fm_macsec_dev, ++ int *macsec_revision) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_GetRevision(fm_macsec_dev, macsec_revision); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_GetRevision() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_get_revision); ++ ++int fm_macsec_enable(struct fm_macsec_dev *fm_macsec_dev) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_Enable(fm_macsec_dev); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_Enable() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_enable); ++ ++int fm_macsec_disable(struct fm_macsec_dev *fm_macsec_dev) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_Disable(fm_macsec_dev); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_Disable() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_disable); ++ ++int fm_macsec_set_exception(struct fm_macsec_dev *fm_macsec_dev, ++ fm_macsec_exception exception, bool enable) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SetException(fm_macsec_dev, exception, enable); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SetException() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_set_exception); ++ ++/* Macsec SECY wrapper API */ ++struct fm_macsec_secy_dev *fm_macsec_secy_config(struct fm_macsec_secy_params *secy_params) ++{ ++ struct fm_macsec_secy_dev *fm_macsec_secy; ++ ++ fm_macsec_secy = FM_MACSEC_SECY_Config((t_FmMacsecSecYParams *)secy_params); ++ if (unlikely(fm_macsec_secy < 0)) ++ pr_err("FM_MACSEC_SECY_Config() failed\n"); ++ ++ return fm_macsec_secy; ++} ++EXPORT_SYMBOL(fm_macsec_secy_config); ++ ++int fm_macsec_secy_init(struct fm_macsec_secy_dev *fm_macsec_secy_dev) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_Init(fm_macsec_secy_dev); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_Init() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_init); ++ ++int fm_macsec_secy_free(struct fm_macsec_secy_dev *fm_macsec_secy_dev) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_Free(fm_macsec_secy_dev); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_Free() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_free); ++ ++int fm_macsec_secy_config_sci_insertion_mode(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ fm_macsec_sci_insertion_mode sci_insertion_mode) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_ConfigSciInsertionMode(fm_macsec_secy_dev, ++ sci_insertion_mode); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_ConfigSciInsertionMode() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_config_sci_insertion_mode); ++ ++int fm_macsec_secy_config_protect_frames(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ bool protect_frames) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_ConfigProtectFrames(fm_macsec_secy_dev, ++ protect_frames); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_ConfigProtectFrames() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_config_protect_frames); ++ ++int fm_macsec_secy_config_replay_window(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ bool replay_protect, uint32_t replay_window) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_ConfigReplayWindow(fm_macsec_secy_dev, ++ replay_protect, replay_window); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_ConfigReplayWindow() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_config_replay_window); ++ ++int fm_macsec_secy_config_validation_mode(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ fm_macsec_valid_frame_behavior validate_frames) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_ConfigValidationMode(fm_macsec_secy_dev, ++ validate_frames); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_ConfigValidationMode() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_config_validation_mode); ++ ++int fm_macsec_secy_config_confidentiality(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ bool confidentiality_enable, ++ uint32_t confidentiality_offset) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_ConfigConfidentiality(fm_macsec_secy_dev, ++ confidentiality_enable, ++ confidentiality_offset); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_ConfigConfidentiality() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_config_confidentiality); ++ ++int fm_macsec_secy_config_point_to_point(struct fm_macsec_secy_dev *fm_macsec_secy_dev) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_ConfigPointToPoint(fm_macsec_secy_dev); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_ConfigPointToPoint() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_config_point_to_point); ++ ++int fm_macsec_secy_config_exception(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ fm_macsec_secy_exception exception, ++ bool enable) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_ConfigException(fm_macsec_secy_dev, exception, ++ enable); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_ConfigException() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_config_exception); ++ ++int fm_macsec_secy_config_event(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ fm_macsec_secy_event event, ++ bool enable) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_ConfigEvent(fm_macsec_secy_dev, event, enable); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_ConfigEvent() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_config_event); ++ ++struct rx_sc_dev *fm_macsec_secy_create_rxsc(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct fm_macsec_secy_sc_params *params) ++{ ++ struct rx_sc_dev *rx_sc_dev; ++ ++ rx_sc_dev = FM_MACSEC_SECY_CreateRxSc(fm_macsec_secy_dev, (t_FmMacsecSecYSCParams *)params); ++ if (unlikely(rx_sc_dev == NULL)) ++ pr_err("FM_MACSEC_SECY_CreateRxSc() failed\n"); ++ ++ return rx_sc_dev; ++} ++EXPORT_SYMBOL(fm_macsec_secy_create_rxsc); ++ ++int fm_macsec_secy_delete_rxsc(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_DeleteRxSc(fm_macsec_secy_dev, sc); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_DeleteRxSc() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_delete_rxsc); ++ ++int fm_macsec_secy_create_rx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc, macsec_an_t an, ++ uint32_t lowest_pn, macsec_sa_key_t key) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_CreateRxSa(fm_macsec_secy_dev, sc, an, ++ lowest_pn, key); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_CreateRxSa() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_create_rx_sa); ++ ++int fm_macsec_secy_delete_rx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc, macsec_an_t an) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_DeleteRxSa(fm_macsec_secy_dev, sc, an); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_DeleteRxSa() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_delete_rx_sa); ++ ++int fm_macsec_secy_rxsa_enable_receive(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc, ++ macsec_an_t an) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_RxSaEnableReceive(fm_macsec_secy_dev, sc, an); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_RxSaEnableReceive() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_rxsa_enable_receive); ++ ++int fm_macsec_secy_rxsa_disable_receive(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc, ++ macsec_an_t an) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_RxSaDisableReceive(fm_macsec_secy_dev, sc, an); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_RxSaDisableReceive() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_rxsa_disable_receive); ++ ++int fm_macsec_secy_rxsa_update_next_pn(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc, ++ macsec_an_t an, uint32_t updt_next_pn) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_RxSaUpdateNextPn(fm_macsec_secy_dev, sc, an, ++ updt_next_pn); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_RxSaUpdateNextPn() = 0x%08x\n", err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_rxsa_update_next_pn); ++ ++int fm_macsec_secy_rxsa_update_lowest_pn(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc, ++ macsec_an_t an, uint32_t updt_lowest_pn) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_RxSaUpdateLowestPn(fm_macsec_secy_dev, sc, an, ++ updt_lowest_pn); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_RxSaUpdateLowestPn() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_rxsa_update_lowest_pn); ++ ++int fm_macsec_secy_rxsa_modify_key(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc, ++ macsec_an_t an, macsec_sa_key_t key) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_RxSaModifyKey(fm_macsec_secy_dev, sc, an, key); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_RxSaModifyKey() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_rxsa_modify_key); ++ ++int fm_macsec_secy_create_tx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ macsec_an_t an, macsec_sa_key_t key) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_CreateTxSa(fm_macsec_secy_dev, an, key); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_CreateTxSa() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_create_tx_sa); ++ ++int fm_macsec_secy_delete_tx_sa(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ macsec_an_t an) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_DeleteTxSa(fm_macsec_secy_dev, an); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_DeleteTxSa() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_delete_tx_sa); ++ ++int fm_macsec_secy_txsa_modify_key(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ macsec_an_t next_active_an, ++ macsec_sa_key_t key) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_TxSaModifyKey(fm_macsec_secy_dev, next_active_an, ++ key); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_TxSaModifyKey() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_txsa_modify_key); ++ ++int fm_macsec_secy_txsa_set_active(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ macsec_an_t an) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_TxSaSetActive(fm_macsec_secy_dev, an); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_TxSaSetActive() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_txsa_set_active); ++ ++int fm_macsec_secy_txsa_get_active(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ macsec_an_t *p_an) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_TxSaGetActive(fm_macsec_secy_dev, p_an); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_TxSaGetActive() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_txsa_get_active); ++ ++int fm_macsec_secy_get_rxsc_phys_id(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ struct rx_sc_dev *sc, uint32_t *sc_phys_id) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_GetRxScPhysId(fm_macsec_secy_dev, sc, sc_phys_id); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_GetRxScPhysId() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_get_rxsc_phys_id); ++ ++int fm_macsec_secy_get_txsc_phys_id(struct fm_macsec_secy_dev *fm_macsec_secy_dev, ++ uint32_t *sc_phys_id) ++{ ++ int err; ++ int _errno; ++ ++ err = FM_MACSEC_SECY_GetTxScPhysId(fm_macsec_secy_dev, sc_phys_id); ++ _errno = -GET_ERROR_TYPE(err); ++ if (unlikely(_errno < 0)) ++ pr_err("FM_MACSEC_SECY_GetTxScPhysId() = 0x%08x\n", ++ err); ++ ++ return _errno; ++} ++EXPORT_SYMBOL(fm_macsec_secy_get_txsc_phys_id); ++ ++static t_Handle h_FmLnxWrp; ++ ++static int __init __cold fm_load (void) ++{ ++ if ((h_FmLnxWrp = LNXWRP_FM_Init()) == NULL) ++ { ++ printk("Failed to init FM wrapper!\n"); ++ return -ENODEV; ++ } ++ ++ printk(KERN_CRIT "Freescale FM module," \ ++ " FMD API version %d.%d.%d\n", ++ FMD_API_VERSION_MAJOR, ++ FMD_API_VERSION_MINOR, ++ FMD_API_VERSION_RESPIN); ++ return 0; ++} ++ ++static void __exit __cold fm_unload (void) ++{ ++ if (h_FmLnxWrp) ++ LNXWRP_FM_Free(h_FmLnxWrp); ++} ++ ++module_init (fm_load); ++module_exit (fm_unload); +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.h b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.h +new file mode 100644 +index 00000000..09832563 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm.h +@@ -0,0 +1,294 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ @File lnxwrp_fm.h ++ ++ @Author Shlomi Gridish ++ ++ @Description FM Linux wrapper functions. ++ ++*/ ++ ++#ifndef __LNXWRP_FM_H__ ++#define __LNXWRP_FM_H__ ++ ++#include /* struct qman_fq */ ++ ++#include "std_ext.h" ++#include "error_ext.h" ++#include "list_ext.h" ++ ++#include "lnxwrp_fm_ext.h" ++ ++#define FM_MAX_NUM_OF_ADV_SETTINGS 10 ++ ++#define LNXWRP_FM_NUM_OF_SHARED_PROFILES 16 ++ ++#if defined(CONFIG_FMAN_DISABLE_OH_TO_REUSE_RESOURCES) ++#define FM_10G_OPENDMA_MIN_TRESHOLD 8 /* 10g minimum treshold if only HC is enabled and no OH port enabled */ ++#define FM_OPENDMA_RX_TX_RAPORT 2 /* RX = 2*TX */ ++#else ++#define FM_10G_OPENDMA_MIN_TRESHOLD 7 /* 10g minimum treshold if 7 OH ports are enabled */ ++#define FM_OPENDMA_RX_TX_RAPORT 1 /* RX = TX */ ++#endif ++#define FM_DEFAULT_TX10G_OPENDMA 8 /* default TX 10g open dmas */ ++#define FM_DEFAULT_RX10G_OPENDMA 8 /* default RX 10g open dmas */ ++ ++#define FRAG_MANIP_SPACE 128 ++#define FRAG_DATA_ALIGN 64 ++ ++#ifndef CONFIG_FSL_FM_MAX_FRAME_SIZE ++#define CONFIG_FSL_FM_MAX_FRAME_SIZE 0 ++#endif ++ ++#ifndef CONFIG_FSL_FM_RX_EXTRA_HEADROOM ++#define CONFIG_FSL_FM_RX_EXTRA_HEADROOM 16 ++#endif ++ ++typedef enum { ++ e_NO_PCD = 0, ++ e_FM_PCD_3_TUPLE ++} e_LnxWrpFmPortPcdDefUseCase; ++ ++ ++typedef struct t_FmTestFq { ++ struct qman_fq fq_base; ++ t_Handle h_Arg; ++} t_FmTestFq; ++ ++typedef struct { ++ uint8_t id; /* sw port id, see SW_PORT_ID_TO_HW_PORT_ID() in fm_common.h */ ++ int minor; ++ char name[20]; ++ bool active; ++ uint64_t phys_baseAddr; ++ uint64_t baseAddr; /* Port's *virtual* address */ ++ uint32_t memSize; ++ t_WrpFmPortDevSettings settings; ++ t_FmExtPools opExtPools; ++ uint8_t totalNumOfSchemes; ++ uint8_t schemesBase; ++ uint8_t numOfSchemesUsed; ++ uint32_t pcdBaseQ; ++ uint16_t pcdNumOfQs; ++ struct fm_port_pcd_param pcd_owner_params; ++ e_LnxWrpFmPortPcdDefUseCase defPcd; ++ t_Handle h_DefNetEnv; ++ t_Handle h_Schemes[FM_PCD_KG_NUM_OF_SCHEMES]; ++ t_FmBufferPrefixContent buffPrefixContent; ++ t_Handle h_Dev; ++ t_Handle h_DfltVsp; ++ t_Handle h_LnxWrpFmDev; ++ uint16_t txCh; ++ struct device *dev; ++ struct device_attribute *dev_attr_stats; ++ struct device_attribute *dev_attr_regs; ++ struct device_attribute *dev_attr_bmi_regs; ++ struct device_attribute *dev_attr_qmi_regs; ++#if (DPAA_VERSION >= 11) ++ struct device_attribute *dev_attr_ipv4_opt; ++#endif ++ struct device_attribute *dev_attr_dsar_regs; ++ struct device_attribute *dev_attr_dsar_mem; ++ struct auto_res_tables_sizes dsar_table_sizes; ++} t_LnxWrpFmPortDev; ++ ++typedef struct { ++ uint8_t id; ++ bool active; ++ uint64_t baseAddr; ++ uint32_t memSize; ++ t_WrpFmMacDevSettings settings; ++ t_Handle h_Dev; ++ t_Handle h_LnxWrpFmDev; ++} t_LnxWrpFmMacDev; ++ ++/* information about all active ports for an FMan. ++ * !Some ports may be disabled by u-boot, thus will not be available */ ++struct fm_active_ports { ++ uint32_t num_oh_ports; ++ uint32_t num_tx_ports; ++ uint32_t num_rx_ports; ++ uint32_t num_tx25_ports; ++ uint32_t num_rx25_ports; ++ uint32_t num_tx10_ports; ++ uint32_t num_rx10_ports; ++}; ++ ++/* FMan resources precalculated at fm probe based ++ * on available FMan port. */ ++struct fm_resource_settings { ++ /* buffers - fifo sizes */ ++ uint32_t tx1g_num_buffers; ++ uint32_t rx1g_num_buffers; ++ uint32_t tx2g5_num_buffers; /* Not supported yet by LLD */ ++ uint32_t rx2g5_num_buffers; /* Not supported yet by LLD */ ++ uint32_t tx10g_num_buffers; ++ uint32_t rx10g_num_buffers; ++ uint32_t oh_num_buffers; ++ uint32_t shared_ext_buffers; ++ ++ /* open DMAs */ ++ uint32_t tx_1g_dmas; ++ uint32_t rx_1g_dmas; ++ uint32_t tx_2g5_dmas; /* Not supported yet by LLD */ ++ uint32_t rx_2g5_dmas; /* Not supported yet by LLD */ ++ uint32_t tx_10g_dmas; ++ uint32_t rx_10g_dmas; ++ uint32_t oh_dmas; ++ uint32_t shared_ext_open_dma; ++ ++ /* Tnums */ ++ uint32_t tx_1g_tnums; ++ uint32_t rx_1g_tnums; ++ uint32_t tx_2g5_tnums; /* Not supported yet by LLD */ ++ uint32_t rx_2g5_tnums; /* Not supported yet by LLD */ ++ uint32_t tx_10g_tnums; ++ uint32_t rx_10g_tnums; ++ uint32_t oh_tnums; ++ uint32_t shared_ext_tnums; ++}; ++ ++typedef struct { ++ uint8_t id; ++ char name[10]; ++ bool active; ++ bool pcdActive; ++ bool prsActive; ++ bool kgActive; ++ bool ccActive; ++ bool plcrActive; ++ e_LnxWrpFmPortPcdDefUseCase defPcd; ++ uint32_t usedSchemes; ++ uint8_t totalNumOfSharedSchemes; ++ uint8_t sharedSchemesBase; ++ uint8_t numOfSchemesUsed; ++ uint8_t defNetEnvId; ++ uint64_t fmPhysBaseAddr; ++ uint64_t fmBaseAddr; ++ uint32_t fmMemSize; ++ uint64_t fmMuramPhysBaseAddr; ++ uint64_t fmMuramBaseAddr; ++ uint32_t fmMuramMemSize; ++ uint64_t fmRtcPhysBaseAddr; ++ uint64_t fmRtcBaseAddr; ++ uint32_t fmRtcMemSize; ++ uint64_t fmVspPhysBaseAddr; ++ uint64_t fmVspBaseAddr; ++ uint32_t fmVspMemSize; ++ int irq; ++ int err_irq; ++ t_WrpFmDevSettings fmDevSettings; ++ t_WrpFmPcdDevSettings fmPcdDevSettings; ++ t_Handle h_Dev; ++ uint16_t hcCh; ++ ++ t_Handle h_MuramDev; ++ t_Handle h_PcdDev; ++ t_Handle h_RtcDev; ++ ++ t_Handle h_DsarRxPort; ++ t_Handle h_DsarTxPort; ++ ++ t_LnxWrpFmPortDev hcPort; ++ t_LnxWrpFmPortDev opPorts[FM_MAX_NUM_OF_OH_PORTS-1]; ++ t_LnxWrpFmPortDev rxPorts[FM_MAX_NUM_OF_RX_PORTS]; ++ t_LnxWrpFmPortDev txPorts[FM_MAX_NUM_OF_TX_PORTS]; ++ t_LnxWrpFmMacDev macs[FM_MAX_NUM_OF_MACS]; ++ struct fm_active_ports fm_active_ports_info; ++ struct fm_resource_settings fm_resource_settings_info; ++ ++ struct device *dev; ++ struct resource *res; ++ int major; ++ struct class *fm_class; ++ struct device_attribute *dev_attr_stats; ++ struct device_attribute *dev_attr_regs; ++ struct device_attribute *dev_attr_risc_load; ++ ++ struct device_attribute *dev_pcd_attr_stats; ++ struct device_attribute *dev_plcr_attr_regs; ++ struct device_attribute *dev_prs_attr_regs; ++ struct device_attribute *dev_fm_fpm_attr_regs; ++ struct device_attribute *dev_fm_kg_attr_regs; ++ struct device_attribute *dev_fm_kg_pe_attr_regs; ++ struct device_attribute *dev_attr_muram_free_size; ++ struct device_attribute *dev_attr_fm_ctrl_code_ver; ++ ++ ++ struct qman_fq *hc_tx_conf_fq, *hc_tx_err_fq, *hc_tx_fq; ++} t_LnxWrpFmDev; ++ ++typedef struct { ++ t_LnxWrpFmDev *p_FmDevs[INTG_MAX_NUM_OF_FM]; ++} t_LnxWrpFm; ++#define LNXWRP_FM_OBJECT(ptr) LIST_OBJECT(ptr, t_LnxWrpFm, fms[((t_LnxWrpFmDev *)ptr)->id]) ++ ++ ++t_Error LnxwrpFmIOCTL(t_LnxWrpFmDev *p_LnxWrpFmDev, unsigned int cmd, unsigned long arg, bool compat); ++t_Error LnxwrpFmPortIOCTL(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev, unsigned int cmd, unsigned long arg, bool compat); ++ ++ ++#if 0 ++static __inline__ t_Error AllocSchemesForPort(t_LnxWrpFmDev *p_LnxWrpFmDev, uint8_t numSchemes, uint8_t *p_BaseSchemeNum) ++{ ++ uint32_t schemeMask; ++ uint8_t i; ++ ++ if (!numSchemes) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); ++ ++ schemeMask = 0x80000000; ++ *p_BaseSchemeNum = 0xff; ++ ++ for (i=0; schemeMask && numSchemes; schemeMask>>=1, i++) ++ if ((p_LnxWrpFmDev->usedSchemes & schemeMask) == 0) ++ { ++ p_LnxWrpFmDev->usedSchemes |= schemeMask; ++ numSchemes--; ++ if (*p_BaseSchemeNum==0xff) ++ *p_BaseSchemeNum = i; ++ } ++ else if (*p_BaseSchemeNum!=0xff) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("Fragmentation on schemes array!!!")); ++ ++ if (numSchemes) ++ RETURN_ERROR(MINOR, E_FULL, ("schemes!!!")); ++ return E_OK; ++} ++#endif ++ ++void LnxWrpPCDIOCTLTypeChecking(void); ++void LnxWrpPCDIOCTLEnumChecking(void); ++ ++#endif /* __LNXWRP_FM_H__ */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c +new file mode 100644 +index 00000000..00ab4bcb +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_fm_port.c +@@ -0,0 +1,1480 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ @File lnxwrp_fm_port.c ++ ++ @Description FMD wrapper - FMan port functions. ++ ++*/ ++ ++#include ++#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) ++#define MODVERSIONS ++#endif ++#ifdef MODVERSIONS ++#include ++#endif /* MODVERSIONS */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifndef CONFIG_FMAN_ARM ++#include ++#endif ++#include ++ ++#include "sprint_ext.h" ++#include "fm_common.h" ++#include "lnxwrp_fsl_fman.h" ++#include "fm_port_ext.h" ++#if (DPAA_VERSION >= 11) ++#include "fm_vsp_ext.h" ++#endif /* DPAA_VERSION >= 11 */ ++#include "fm_ioctls.h" ++#include "lnxwrp_resources.h" ++#include "lnxwrp_sysfs_fm_port.h" ++ ++#define __ERR_MODULE__ MODULE_FM ++ ++extern struct device_node *GetFmAdvArgsDevTreeNode (uint8_t fmIndx); ++ ++/* TODO: duplicated, see lnxwrp_fm.c */ ++#define ADD_ADV_CONFIG_NO_RET(_func, _param)\ ++do {\ ++ if (i < max) {\ ++ p_Entry = &p_Entrys[i];\ ++ p_Entry->p_Function = _func;\ ++ _param\ ++ i++;\ ++ } else {\ ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE,\ ++ ("Number of advanced-configuration entries exceeded"));\ ++ } \ ++} while (0) ++ ++#ifndef CONFIG_FMAN_ARM ++#define IS_T1023_T1024 (SVR_SOC_VER(mfspr(SPRN_SVR)) == SVR_T1024 || \ ++ SVR_SOC_VER(mfspr(SPRN_SVR)) == SVR_T1023) ++#endif ++ ++static volatile int hcFrmRcv/* = 0 */; ++static spinlock_t lock; ++ ++static enum qman_cb_dqrr_result qm_tx_conf_dqrr_cb(struct qman_portal *portal, ++ struct qman_fq *fq, ++ const struct qm_dqrr_entry ++ *dq) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev = ((t_FmTestFq *) fq)->h_Arg; ++ unsigned long flags; ++ ++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ++{ ++ /* extract the HC frame address */ ++ uint32_t *hcf_va = XX_PhysToVirt(qm_fd_addr((struct qm_fd *)&dq->fd)); ++ int hcf_l = ((struct qm_fd *)&dq->fd)->length20; ++ int i; ++ ++ /* 32b byteswap of all data in the HC Frame */ ++ for(i = 0; i < hcf_l / 4; ++i) ++ hcf_va[i] = ++ ___constant_swab32(hcf_va[i]); ++} ++#endif ++ FM_PCD_HcTxConf(p_LnxWrpFmDev->h_PcdDev, (t_DpaaFD *)&dq->fd); ++ spin_lock_irqsave(&lock, flags); ++ hcFrmRcv--; ++ spin_unlock_irqrestore(&lock, flags); ++ ++ return qman_cb_dqrr_consume; ++} ++ ++static enum qman_cb_dqrr_result qm_tx_dqrr_cb(struct qman_portal *portal, ++ struct qman_fq *fq, ++ const struct qm_dqrr_entry *dq) ++{ ++ WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__, ++ __func__); ++ return qman_cb_dqrr_consume; ++} ++ ++static void qm_err_cb(struct qman_portal *portal, ++ struct qman_fq *fq, const struct qm_mr_entry *msg) ++{ ++ WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__, ++ __func__); ++} ++ ++static struct qman_fq *FqAlloc(t_LnxWrpFmDev * p_LnxWrpFmDev, ++ uint32_t fqid, ++ uint32_t flags, uint16_t channel, uint8_t wq) ++{ ++ int _errno; ++ struct qman_fq *fq = NULL; ++ t_FmTestFq *p_FmtFq; ++ struct qm_mcc_initfq initfq; ++ ++ p_FmtFq = (t_FmTestFq *) XX_Malloc(sizeof(t_FmTestFq)); ++ if (!p_FmtFq) { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FQ obj!!!")); ++ return NULL; ++ } ++ ++ p_FmtFq->fq_base.cb.dqrr = ((flags & QMAN_FQ_FLAG_NO_ENQUEUE) ++ ? qm_tx_conf_dqrr_cb ++ : qm_tx_dqrr_cb); ++ p_FmtFq->fq_base.cb.ern = qm_err_cb; ++ /* p_FmtFq->fq_base.cb.fqs = qm_err_cb; */ ++ /* qm_err_cb wrongly called when the FQ is parked */ ++ p_FmtFq->fq_base.cb.fqs = NULL; ++ p_FmtFq->h_Arg = (t_Handle) p_LnxWrpFmDev; ++ if (fqid == 0) { ++ flags |= QMAN_FQ_FLAG_DYNAMIC_FQID; ++ flags &= ~QMAN_FQ_FLAG_NO_MODIFY; ++ } else { ++ flags &= ~QMAN_FQ_FLAG_DYNAMIC_FQID; ++ } ++ ++ if (qman_create_fq(fqid, flags, &p_FmtFq->fq_base)) { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FQ obj - qman_new_fq!!!")); ++ XX_Free(p_FmtFq); ++ return NULL; ++ } ++ fq = &p_FmtFq->fq_base; ++ ++ if (!(flags & QMAN_FQ_FLAG_NO_MODIFY)) { ++ initfq.we_mask = QM_INITFQ_WE_DESTWQ; ++ initfq.fqd.dest.channel = channel; ++ initfq.fqd.dest.wq = wq; ++ ++ _errno = qman_init_fq(fq, QMAN_INITFQ_FLAG_SCHED, &initfq); ++ if (unlikely(_errno < 0)) { ++ REPORT_ERROR(MAJOR, E_NO_MEMORY, ++ ("FQ obj - qman_init_fq!!!")); ++ qman_destroy_fq(fq, 0); ++ XX_Free(p_FmtFq); ++ return NULL; ++ } ++ } ++ ++ DBG(TRACE, ++ ("fqid %d, flags 0x%08x, channel %d, wq %d", qman_fq_fqid(fq), ++ flags, channel, wq)); ++ ++ return fq; ++} ++ ++static void FqFree(struct qman_fq *fq) ++{ ++ int _errno; ++ ++ _errno = qman_retire_fq(fq, NULL); ++ if (unlikely(_errno < 0)) ++ printk(KERN_WARNING "qman_retire_fq(%u) = %d\n", qman_fq_fqid(fq), _errno); ++ ++ _errno = qman_oos_fq(fq); ++ if (unlikely(_errno < 0)) ++ printk(KERN_WARNING "qman_oos_fq(%u) = %d\n", qman_fq_fqid(fq), _errno); ++ ++ qman_destroy_fq(fq, 0); ++ XX_Free((t_FmTestFq *) fq); ++} ++ ++static t_Error QmEnqueueCB(t_Handle h_Arg, void *p_Fd) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *) h_Arg; ++ int _errno, timeout = 1000000; ++ unsigned long flags; ++ ++ ASSERT_COND(p_LnxWrpFmDev); ++ ++ spin_lock_irqsave(&lock, flags); ++ hcFrmRcv++; ++ spin_unlock_irqrestore(&lock, flags); ++ ++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ++{ ++ /* extract the HC frame address */ ++ uint32_t *hcf_va = XX_PhysToVirt(qm_fd_addr((struct qm_fd *) p_Fd)); ++ int hcf_l = ((struct qm_fd *)p_Fd)->length20; ++ int i; ++ ++ /* 32b byteswap of all data in the HC Frame */ ++ for(i = 0; i < hcf_l / 4; ++i) ++ hcf_va[i] = ++ ___constant_swab32(hcf_va[i]); ++} ++#endif ++ ++ _errno = qman_enqueue(p_LnxWrpFmDev->hc_tx_fq, (struct qm_fd *) p_Fd, ++ 0); ++ if (_errno) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ++ ("qman_enqueue() failed")); ++ ++ while (hcFrmRcv && --timeout) { ++ udelay(1); ++ cpu_relax(); ++ } ++ if (timeout == 0) { ++ dump_stack(); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, ++ ("timeout waiting for Tx confirmation")); ++ return E_WRITE_FAILED; ++ } ++ ++ return E_OK; ++} ++ ++static t_LnxWrpFmPortDev *ReadFmPortDevTreeNode(struct platform_device ++ *of_dev) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev; ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; ++ struct device_node *fm_node, *port_node; ++ struct resource res; ++ const uint32_t *uint32_prop; ++ int _errno = 0, lenp; ++ uint32_t tmp_prop; ++ ++#ifdef CONFIG_FMAN_P1023 ++ static unsigned char have_oh_port/* = 0 */; ++#endif ++ ++ port_node = of_node_get(of_dev->dev.of_node); ++ ++ /* Get the FM node */ ++ fm_node = of_get_parent(port_node); ++ if (unlikely(fm_node == NULL)) { ++ REPORT_ERROR(MAJOR, E_NO_DEVICE, ++ ("of_get_parent() = %d", _errno)); ++ return NULL; ++ } ++ ++ p_LnxWrpFmDev = ++ dev_get_drvdata(&of_find_device_by_node(fm_node)->dev); ++ of_node_put(fm_node); ++ ++ /* if fm_probe() failed, no point in going further with port probing */ ++ if (p_LnxWrpFmDev == NULL) ++ return NULL; ++ ++ uint32_prop = ++ (uint32_t *) of_get_property(port_node, "cell-index", &lenp); ++ if (unlikely(uint32_prop == NULL)) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ++ ("of_get_property(%s, cell-index) failed", ++ port_node->full_name)); ++ return NULL; ++ } ++ tmp_prop = be32_to_cpu(*uint32_prop); ++ if (WARN_ON(lenp != sizeof(uint32_t))) ++ return NULL; ++ if (of_device_is_compatible(port_node, "fsl,fman-port-oh")) { ++ if (unlikely(tmp_prop >= FM_MAX_NUM_OF_OH_PORTS)) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ++ ("of_get_property(%s, cell-index) failed", ++ port_node->full_name)); ++ return NULL; ++ } ++ ++#ifdef CONFIG_FMAN_P1023 ++ /* Beware, this can be done when there is only ++ one FMan to be initialized */ ++ if (!have_oh_port) { ++ have_oh_port = 1; /* first OP/HC port ++ is used for host command */ ++#else ++ /* Here it is hardcoded the use of the OH port 1 ++ (with cell-index 0) */ ++ if (tmp_prop == 0) { ++#endif ++ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->hcPort; ++ p_LnxWrpFmPortDev->id = 0; ++ /* ++ p_LnxWrpFmPortDev->id = *uint32_prop-1; ++ p_LnxWrpFmPortDev->id = *uint32_prop; ++ */ ++ p_LnxWrpFmPortDev->settings.param.portType = ++ e_FM_PORT_TYPE_OH_HOST_COMMAND; ++ } else { ++ p_LnxWrpFmPortDev = ++ &p_LnxWrpFmDev->opPorts[tmp_prop - 1]; ++ p_LnxWrpFmPortDev->id = tmp_prop- 1; ++ p_LnxWrpFmPortDev->settings.param.portType = ++ e_FM_PORT_TYPE_OH_OFFLINE_PARSING; ++ } ++ p_LnxWrpFmPortDev->settings.param.portId = tmp_prop; ++ ++ uint32_prop = ++ (uint32_t *) of_get_property(port_node, ++ "fsl,qman-channel-id", ++ &lenp); ++ if (uint32_prop == NULL) { ++ /* ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("missing fsl,qman-channel-id")); ++ */ ++ XX_Print("FM warning: missing fsl,qman-channel-id" ++ " for OH port.\n"); ++ return NULL; ++ } ++ tmp_prop = be32_to_cpu(*uint32_prop); ++ if (WARN_ON(lenp != sizeof(uint32_t))) ++ return NULL; ++ p_LnxWrpFmPortDev->txCh = tmp_prop; ++ ++ p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams. ++ qmChannel = p_LnxWrpFmPortDev->txCh; ++ } else if (of_device_is_compatible(port_node, "fsl,fman-port-1g-tx")) { ++ tmp_prop -= 0x28; ++ if (unlikely(tmp_prop >= FM_MAX_NUM_OF_1G_TX_PORTS)) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ++ ("of_get_property(%s, cell-index) failed", ++ port_node->full_name)); ++ return NULL; ++ } ++ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[tmp_prop]; ++ ++ p_LnxWrpFmPortDev->id = tmp_prop; ++ p_LnxWrpFmPortDev->settings.param.portId = ++ p_LnxWrpFmPortDev->id; ++ p_LnxWrpFmPortDev->settings.param.portType = e_FM_PORT_TYPE_TX; ++ ++ uint32_prop = (uint32_t *) of_get_property(port_node, ++ "fsl,qman-channel-id", &lenp); ++ if (uint32_prop == NULL) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ++ ("missing fsl,qman-channel-id")); ++ return NULL; ++ } ++ tmp_prop = be32_to_cpu(*uint32_prop); ++ if (WARN_ON(lenp != sizeof(uint32_t))) ++ return NULL; ++ p_LnxWrpFmPortDev->txCh = tmp_prop; ++ p_LnxWrpFmPortDev-> ++ settings.param.specificParams.nonRxParams.qmChannel = ++ p_LnxWrpFmPortDev->txCh; ++ } else if (of_device_is_compatible(port_node, "fsl,fman-port-10g-tx")) { ++ tmp_prop -= 0x30; ++ if (unlikely(tmp_prop>= FM_MAX_NUM_OF_10G_TX_PORTS)) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ++ ("of_get_property(%s, cell-index) failed", ++ port_node->full_name)); ++ return NULL; ++ } ++ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[tmp_prop + ++ FM_MAX_NUM_OF_1G_TX_PORTS]; ++#ifndef CONFIG_FMAN_ARM ++ if (IS_T1023_T1024) ++ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[*uint32_prop]; ++#endif ++ ++ p_LnxWrpFmPortDev->id = tmp_prop; ++ p_LnxWrpFmPortDev->settings.param.portId = ++ p_LnxWrpFmPortDev->id; ++ p_LnxWrpFmPortDev->settings.param.portType = ++ e_FM_PORT_TYPE_TX_10G; ++ uint32_prop = (uint32_t *) of_get_property(port_node, ++ "fsl,qman-channel-id", &lenp); ++ if (uint32_prop == NULL) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ++ ("missing fsl,qman-channel-id")); ++ return NULL; ++ } ++ tmp_prop = be32_to_cpu(*uint32_prop); ++ if (WARN_ON(lenp != sizeof(uint32_t))) ++ return NULL; ++ p_LnxWrpFmPortDev->txCh = tmp_prop; ++ p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams. ++ qmChannel = p_LnxWrpFmPortDev->txCh; ++ } else if (of_device_is_compatible(port_node, "fsl,fman-port-1g-rx")) { ++ tmp_prop -= 0x08; ++ if (unlikely(tmp_prop >= FM_MAX_NUM_OF_1G_RX_PORTS)) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ++ ("of_get_property(%s, cell-index) failed", ++ port_node->full_name)); ++ return NULL; ++ } ++ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[tmp_prop]; ++ ++ p_LnxWrpFmPortDev->id = tmp_prop; ++ p_LnxWrpFmPortDev->settings.param.portId = ++ p_LnxWrpFmPortDev->id; ++ p_LnxWrpFmPortDev->settings.param.portType = e_FM_PORT_TYPE_RX; ++ if (p_LnxWrpFmDev->pcdActive) ++ p_LnxWrpFmPortDev->defPcd = p_LnxWrpFmDev->defPcd; ++ } else if (of_device_is_compatible(port_node, "fsl,fman-port-10g-rx")) { ++ tmp_prop -= 0x10; ++ if (unlikely(tmp_prop >= FM_MAX_NUM_OF_10G_RX_PORTS)) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ++ ("of_get_property(%s, cell-index) failed", ++ port_node->full_name)); ++ return NULL; ++ } ++ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[tmp_prop + ++ FM_MAX_NUM_OF_1G_RX_PORTS]; ++ ++#ifndef CONFIG_FMAN_ARM ++ if (IS_T1023_T1024) ++ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[*uint32_prop]; ++#endif ++ ++ p_LnxWrpFmPortDev->id = tmp_prop; ++ p_LnxWrpFmPortDev->settings.param.portId = ++ p_LnxWrpFmPortDev->id; ++ p_LnxWrpFmPortDev->settings.param.portType = ++ e_FM_PORT_TYPE_RX_10G; ++ if (p_LnxWrpFmDev->pcdActive) ++ p_LnxWrpFmPortDev->defPcd = p_LnxWrpFmDev->defPcd; ++ } else { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal port type")); ++ return NULL; ++ } ++ ++ _errno = of_address_to_resource(port_node, 0, &res); ++ if (unlikely(_errno < 0)) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ++ ("of_address_to_resource() = %d", _errno)); ++ return NULL; ++ } ++ ++ p_LnxWrpFmPortDev->dev = &of_dev->dev; ++ p_LnxWrpFmPortDev->baseAddr = 0; ++ p_LnxWrpFmPortDev->phys_baseAddr = res.start; ++ p_LnxWrpFmPortDev->memSize = res.end + 1 - res.start; ++ p_LnxWrpFmPortDev->settings.param.h_Fm = p_LnxWrpFmDev->h_Dev; ++ p_LnxWrpFmPortDev->h_LnxWrpFmDev = (t_Handle) p_LnxWrpFmDev; ++ ++ of_node_put(port_node); ++ ++ p_LnxWrpFmPortDev->active = TRUE; ++ ++#if defined(CONFIG_FMAN_DISABLE_OH_TO_REUSE_RESOURCES) ++ /* for performance mode no OH port available. */ ++ if (p_LnxWrpFmPortDev->settings.param.portType == ++ e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ p_LnxWrpFmPortDev->active = FALSE; ++#endif ++ ++ return p_LnxWrpFmPortDev; ++} ++ ++struct device_node * GetFmPortAdvArgsDevTreeNode (struct device_node *fm_node, ++ e_FmPortType portType, ++ uint8_t portId) ++{ ++ struct device_node *port_node; ++ const uint32_t *uint32_prop; ++ int lenp; ++ char *portTypeString; ++ uint32_t tmp_prop; ++ ++ switch(portType) { ++ case e_FM_PORT_TYPE_OH_OFFLINE_PARSING: ++ portTypeString = "fsl,fman-port-op-extended-args"; ++ break; ++ case e_FM_PORT_TYPE_TX: ++ portTypeString = "fsl,fman-port-1g-tx-extended-args"; ++ break; ++ case e_FM_PORT_TYPE_TX_10G: ++ portTypeString = "fsl,fman-port-10g-tx-extended-args"; ++ break; ++ case e_FM_PORT_TYPE_RX: ++ portTypeString = "fsl,fman-port-1g-rx-extended-args"; ++ break; ++ case e_FM_PORT_TYPE_RX_10G: ++ portTypeString = "fsl,fman-port-10g-rx-extended-args"; ++ break; ++ default: ++ return NULL; ++ } ++ ++ for_each_child_of_node(fm_node, port_node) { ++ uint32_prop = (uint32_t *)of_get_property(port_node, "cell-index", &lenp); ++ if (unlikely(uint32_prop == NULL)) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ++ ("of_get_property(%s, cell-index) failed", ++ port_node->full_name)); ++ return NULL; ++ } ++ tmp_prop = be32_to_cpu(*uint32_prop); ++ if (WARN_ON(lenp != sizeof(uint32_t))) ++ return NULL; ++ if ((portId == tmp_prop) && ++ (of_device_is_compatible(port_node, portTypeString))) { ++ return port_node; ++ } ++ } ++ ++ return NULL; ++} ++ ++static t_Error CheckNConfigFmPortAdvArgs (t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) ++{ ++ struct device_node *fm_node, *port_node; ++ t_Error err; ++ t_FmPortRsrc portRsrc; ++ const uint32_t *uint32_prop; ++ /*const char *str_prop;*/ ++ int lenp; ++#ifdef CONFIG_FMAN_PFC ++ uint8_t i, id, num_pools; ++ t_FmBufPoolDepletion poolDepletion; ++ ++ if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX || ++ p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX_10G) { ++ memset(&poolDepletion, 0, sizeof(t_FmBufPoolDepletion)); ++ poolDepletion.singlePoolModeEnable = true; ++ num_pools = p_LnxWrpFmPortDev->settings.param.specificParams.rxParams. ++ extBufPools.numOfPoolsUsed; ++ for (i = 0; i < num_pools; i++) { ++ id = p_LnxWrpFmPortDev->settings.param.specificParams.rxParams. ++ extBufPools.extBufPool[i].id; ++ poolDepletion.poolsToConsiderForSingleMode[id] = true; ++ } ++ ++ for (i = 0; i < CONFIG_FMAN_PFC_COS_COUNT; i++) ++ poolDepletion.pfcPrioritiesEn[i] = true; ++ ++ err = FM_PORT_ConfigPoolDepletion(p_LnxWrpFmPortDev->h_Dev, ++ &poolDepletion); ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, ("FM_PORT_ConfigPoolDepletion() failed")); ++ } ++#endif ++ ++ fm_node = GetFmAdvArgsDevTreeNode(((t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev)->id); ++ if (!fm_node) /* no advance parameters for FMan */ ++ return E_OK; ++ ++ port_node = GetFmPortAdvArgsDevTreeNode(fm_node, ++ p_LnxWrpFmPortDev->settings.param.portType, ++ p_LnxWrpFmPortDev->settings.param.portId); ++ if (!port_node) /* no advance parameters for FMan-Port */ ++ return E_OK; ++ ++ uint32_prop = (uint32_t *)of_get_property(port_node, "num-tnums", &lenp); ++ if (uint32_prop) { ++ if (WARN_ON(lenp != sizeof(uint32_t)*2)) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); ++ ++ portRsrc.num = be32_to_cpu(uint32_prop[0]); ++ portRsrc.extra = be32_to_cpu(uint32_prop[1]); ++ ++ if ((err = FM_PORT_ConfigNumOfTasks(p_LnxWrpFmPortDev->h_Dev, ++ &portRsrc)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ uint32_prop = (uint32_t *)of_get_property(port_node, "num-dmas", &lenp); ++ if (uint32_prop) { ++ if (WARN_ON(lenp != sizeof(uint32_t)*2)) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); ++ ++ portRsrc.num = be32_to_cpu(uint32_prop[0]); ++ portRsrc.extra = be32_to_cpu(uint32_prop[1]); ++ ++ if ((err = FM_PORT_ConfigNumOfOpenDmas(p_LnxWrpFmPortDev->h_Dev, ++ &portRsrc)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ uint32_prop = (uint32_t *)of_get_property(port_node, "fifo-size", &lenp); ++ if (uint32_prop) { ++ if (WARN_ON(lenp != sizeof(uint32_t)*2)) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); ++ ++ portRsrc.num = be32_to_cpu(uint32_prop[0]); ++ portRsrc.extra = be32_to_cpu(uint32_prop[1]); ++ ++ if ((err = FM_PORT_ConfigSizeOfFifo(p_LnxWrpFmPortDev->h_Dev, ++ &portRsrc)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ uint32_prop = (uint32_t *)of_get_property(port_node, "errors-to-discard", &lenp); ++ if (uint32_prop) { ++ if (WARN_ON(lenp != sizeof(uint32_t))) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); ++ if ((err = FM_PORT_ConfigErrorsToDiscard(p_LnxWrpFmPortDev->h_Dev, ++ be32_to_cpu(uint32_prop[0]))) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ uint32_prop = (uint32_t *)of_get_property(port_node, "ar-tables-sizes", ++ &lenp); ++ if (uint32_prop) { ++ ++ if (WARN_ON(lenp != sizeof(uint32_t)*8)) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); ++ if (WARN_ON(p_LnxWrpFmPortDev->settings.param.portType != ++ e_FM_PORT_TYPE_RX) && ++ (p_LnxWrpFmPortDev->settings.param.portType != ++ e_FM_PORT_TYPE_RX_10G)) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, ++ ("Auto Response is an Rx port atribute.")); ++ ++ memset(&p_LnxWrpFmPortDev->dsar_table_sizes, 0, sizeof(struct auto_res_tables_sizes)); ++ ++ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_arp_entries = ++ (uint16_t)be32_to_cpu(uint32_prop[0]); ++ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_echo_ipv4_entries = ++ (uint16_t)be32_to_cpu(uint32_prop[1]); ++ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_ndp_entries = ++ (uint16_t)be32_to_cpu(uint32_prop[2]); ++ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_echo_ipv6_entries = ++ (uint16_t)be32_to_cpu(uint32_prop[3]); ++ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_snmp_ipv4_entries = ++ (uint16_t)be32_to_cpu(uint32_prop[4]); ++ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_snmp_ipv6_entries = ++ (uint16_t)be32_to_cpu(uint32_prop[5]); ++ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_snmp_oid_entries = ++ (uint16_t)be32_to_cpu(uint32_prop[6]); ++ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_snmp_char = ++ (uint16_t)be32_to_cpu(uint32_prop[7]); ++ ++ uint32_prop = (uint32_t *)of_get_property(port_node, ++ "ar-filters-sizes", &lenp); ++ if (uint32_prop) { ++ if (WARN_ON(lenp != sizeof(uint32_t)*3)) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); ++ ++ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_ip_prot_filtering = ++ (uint16_t)be32_to_cpu(uint32_prop[0]); ++ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_tcp_port_filtering = ++ (uint16_t)be32_to_cpu(uint32_prop[1]); ++ p_LnxWrpFmPortDev->dsar_table_sizes.max_num_of_udp_port_filtering = ++ (uint16_t)be32_to_cpu(uint32_prop[2]); ++ } ++ ++ if ((err = FM_PORT_ConfigDsarSupport(p_LnxWrpFmPortDev->h_Dev, ++ (t_FmPortDsarTablesSizes*)&p_LnxWrpFmPortDev->dsar_table_sizes)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++ ++ of_node_put(port_node); ++ of_node_put(fm_node); ++ ++ return E_OK; ++} ++ ++static t_Error CheckNSetFmPortAdvArgs (t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) ++{ ++ struct device_node *fm_node, *port_node; ++ t_Error err; ++ const uint32_t *uint32_prop; ++ /*const char *str_prop;*/ ++ int lenp; ++ ++ fm_node = GetFmAdvArgsDevTreeNode(((t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev)->id); ++ if (!fm_node) /* no advance parameters for FMan */ ++ return E_OK; ++ ++ port_node = GetFmPortAdvArgsDevTreeNode(fm_node, ++ p_LnxWrpFmPortDev->settings.param.portType, ++ p_LnxWrpFmPortDev->settings.param.portId); ++ if (!port_node) /* no advance parameters for FMan-Port */ ++ return E_OK; ++ ++#if (DPAA_VERSION >= 11) ++ uint32_prop = (uint32_t *)of_get_property(port_node, "vsp-window", &lenp); ++ if (uint32_prop) { ++ t_FmPortVSPAllocParams portVSPAllocParams; ++ t_FmVspParams fmVspParams; ++ t_LnxWrpFmDev *p_LnxWrpFmDev; ++ uint8_t portId; ++ ++ p_LnxWrpFmDev = ((t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev); ++ ++ if (WARN_ON(lenp != sizeof(uint32_t)*2)) ++ RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); ++ ++ if ((p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_TX) || ++ (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_TX_10G) || ++ ((p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) && ++ p_LnxWrpFmPortDev->settings.frag_enabled)) ++ return E_OK; ++ ++ memset(&portVSPAllocParams, 0, sizeof(portVSPAllocParams)); ++ memset(&fmVspParams, 0, sizeof(fmVspParams)); ++ ++ portVSPAllocParams.numOfProfiles = (uint8_t)be32_to_cpu(uint32_prop[0]); ++ portVSPAllocParams.dfltRelativeId = (uint8_t)be32_to_cpu(uint32_prop[1]); ++ fmVspParams.h_Fm = p_LnxWrpFmDev->h_Dev; ++ ++ fmVspParams.portParams.portType = p_LnxWrpFmPortDev->settings.param.portType; ++ fmVspParams.portParams.portId = p_LnxWrpFmPortDev->settings.param.portId; ++ fmVspParams.relativeProfileId = portVSPAllocParams.dfltRelativeId; ++ ++ if (p_LnxWrpFmPortDev->settings.param.portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ++ { ++ portId = fmVspParams.portParams.portId; ++ if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX_10G){ ++#ifndef CONFIG_FMAN_ARM ++ if (!(IS_T1023_T1024)) ++#endif ++ portId += FM_MAX_NUM_OF_1G_RX_PORTS; ++ } ++ portVSPAllocParams.h_FmTxPort = ++ p_LnxWrpFmDev->txPorts[portId].h_Dev; ++ fmVspParams.liodnOffset = ++ p_LnxWrpFmDev->rxPorts[portId].settings.param.specificParams.rxParams.liodnOffset; ++ memcpy(&fmVspParams.extBufPools, ++ &p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.extBufPools, ++ sizeof(t_FmExtPools)); ++ } ++ else ++ { ++ memcpy(&fmVspParams.extBufPools, ++ &p_LnxWrpFmPortDev->opExtPools, ++ sizeof(t_FmExtPools)); ++ } ++ ++ if ((err = FM_PORT_VSPAlloc(p_LnxWrpFmPortDev->h_Dev, ++ &portVSPAllocParams)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ /* We're initializing only the default VSP that are being used by the Linux-Ethernet-driver */ ++ if ((p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) && ++ !p_LnxWrpFmPortDev->opExtPools.numOfPoolsUsed) ++ return E_OK; ++ ++ p_LnxWrpFmPortDev->h_DfltVsp = FM_VSP_Config(&fmVspParams); ++ if (!p_LnxWrpFmPortDev->h_DfltVsp) ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("default-VSP for port!")); ++ ++ if ((err = FM_VSP_ConfigBufferPrefixContent(p_LnxWrpFmPortDev->h_DfltVsp, ++ &p_LnxWrpFmPortDev->buffPrefixContent)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ ++ if ((err = FM_VSP_Init(p_LnxWrpFmPortDev->h_DfltVsp)) != E_OK) ++ RETURN_ERROR(MINOR, err, NO_MSG); ++ } ++#else ++UNUSED(err); UNUSED(uint32_prop); UNUSED(lenp); ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ of_node_put(port_node); ++ of_node_put(fm_node); ++ ++ return E_OK; ++} ++ ++static t_Error ConfigureFmPortDev(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev = ++ (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; ++ struct resource *dev_res; ++ ++ if (!p_LnxWrpFmPortDev->active) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("FM port not configured!!!")); ++ ++ dev_res = ++ __devm_request_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, ++ p_LnxWrpFmPortDev->phys_baseAddr, ++ p_LnxWrpFmPortDev->memSize, ++ "fman-port-hc"); ++ if (unlikely(dev_res == NULL)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, ++ ("__devm_request_region() failed")); ++ p_LnxWrpFmPortDev->baseAddr = ++ PTR_TO_UINT(devm_ioremap ++ (p_LnxWrpFmDev->dev, ++ p_LnxWrpFmPortDev->phys_baseAddr, ++ p_LnxWrpFmPortDev->memSize)); ++ if (unlikely(p_LnxWrpFmPortDev->baseAddr == 0)) ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ++ ("devm_ioremap() failed")); ++ ++ p_LnxWrpFmPortDev->settings.param.baseAddr = ++ p_LnxWrpFmPortDev->baseAddr; ++ ++ return E_OK; ++} ++ ++static t_Error InitFmPortDev(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) ++{ ++#define MY_ADV_CONFIG_CHECK_END \ ++ RETURN_ERROR(MAJOR, E_INVALID_SELECTION,\ ++ ("Advanced configuration routine"));\ ++ if (errCode != E_OK)\ ++ RETURN_ERROR(MAJOR, errCode, NO_MSG);\ ++ } ++ ++ int i = 0; ++ ++ if (!p_LnxWrpFmPortDev->active || p_LnxWrpFmPortDev->h_Dev) ++ return E_INVALID_STATE; ++ ++ p_LnxWrpFmPortDev->h_Dev = ++ FM_PORT_Config(&p_LnxWrpFmPortDev->settings.param); ++ if (p_LnxWrpFmPortDev->h_Dev == NULL) ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-port")); ++ ++#ifndef FM_QMI_NO_DEQ_OPTIONS_SUPPORT ++ if ((p_LnxWrpFmPortDev->settings.param.portType == ++ e_FM_PORT_TYPE_TX_10G) ++ || (p_LnxWrpFmPortDev->settings.param.portType == ++ e_FM_PORT_TYPE_TX)) { ++ t_Error errCode = E_OK; ++ errCode = ++ FM_PORT_ConfigDeqHighPriority(p_LnxWrpFmPortDev->h_Dev, ++ TRUE); ++ if (errCode != E_OK) ++ RETURN_ERROR(MAJOR, errCode, NO_MSG); ++ errCode = ++ FM_PORT_ConfigDeqPrefetchOption(p_LnxWrpFmPortDev->h_Dev, ++ e_FM_PORT_DEQ_FULL_PREFETCH); ++ if (errCode ++ != E_OK) ++ RETURN_ERROR(MAJOR, errCode, NO_MSG); ++ } ++#endif /* !FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ ++ ++#ifndef CONFIG_FMAN_ARM ++#ifdef FM_BCB_ERRATA_BMI_SW001 ++/* Configure BCB workaround on Rx ports, only for B4860 rev1 */ ++#define SVR_SECURITY_MASK 0x00080000 ++#define SVR_PERSONALITY_MASK 0x0000FF00 ++#define SVR_VER_IGNORE_MASK (SVR_SECURITY_MASK | SVR_PERSONALITY_MASK) ++#define SVR_B4860_REV1_VALUE 0x86800010 ++ ++ if ((p_LnxWrpFmPortDev->settings.param.portType == ++ e_FM_PORT_TYPE_RX_10G) || ++ (p_LnxWrpFmPortDev->settings.param.portType == ++ e_FM_PORT_TYPE_RX)) { ++ unsigned int svr; ++ ++ svr = mfspr(SPRN_SVR); ++ ++ if ((svr & ~SVR_VER_IGNORE_MASK) == SVR_B4860_REV1_VALUE) ++ FM_PORT_ConfigBCBWorkaround(p_LnxWrpFmPortDev->h_Dev); ++ } ++#endif /* FM_BCB_ERRATA_BMI_SW001 */ ++#endif /* CONFIG_FMAN_ARM */ ++/* Call the driver's advanced configuration routines, if requested: ++ Compare the function pointer of each entry to the available routines, ++ and invoke the matching routine with proper casting of arguments. */ ++ while (p_LnxWrpFmPortDev->settings.advConfig[i].p_Function ++ && (i < FM_MAX_NUM_OF_ADV_SETTINGS)) { ++ ++/* TODO: Change this MACRO */ ++ ADV_CONFIG_CHECK_START( ++ &(p_LnxWrpFmPortDev->settings.advConfig[i])) ++ ++ ADV_CONFIG_CHECK(p_LnxWrpFmPortDev->h_Dev, ++ FM_PORT_ConfigBufferPrefixContent, ++ NCSW_PARAMS(1, ++ (t_FmBufferPrefixContent *))) ++ ++ if ((p_LnxWrpFmPortDev->settings.param.portType == ++ e_FM_PORT_TYPE_OH_OFFLINE_PARSING) && ++ (p_LnxWrpFmPortDev->settings.frag_enabled == TRUE)) { ++ ++ ADV_CONFIG_CHECK(p_LnxWrpFmPortDev->h_Dev, ++ FM_PORT_ConfigExtBufPools, ++ NCSW_PARAMS(1, (t_FmExtPools *))) ++ ++ /* this define contains an else */ ++ MY_ADV_CONFIG_CHECK_END ++ } ++ ++ /* Advance to next advanced configuration entry */ ++ i++; ++ } ++ ++ ++ if ((p_LnxWrpFmPortDev->settings.param.portType != e_FM_PORT_TYPE_TX) && ++ (p_LnxWrpFmPortDev->settings.param.portType != e_FM_PORT_TYPE_TX_10G)) { ++ if (FM_PORT_ConfigErrorsToDiscard(p_LnxWrpFmPortDev->h_Dev, (FM_PORT_FRM_ERR_IPRE | ++ FM_PORT_FRM_ERR_IPR_NCSP | ++ FM_PORT_FRM_ERR_CLS_DISCARD)) !=E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ } ++ ++ if (CheckNConfigFmPortAdvArgs(p_LnxWrpFmPortDev) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ ++ if (FM_PORT_Init(p_LnxWrpFmPortDev->h_Dev) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ ++ if (CheckNSetFmPortAdvArgs(p_LnxWrpFmPortDev) != E_OK) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++ ++/* FMan Fifo sizes behind the scene": ++ * Using the following formulae (*), under a set of simplifying assumptions (.): ++ * . all ports are configured in Normal Mode (rather than Independent Mode) ++ * . the DPAA Eth driver allocates buffers of size: ++ * . MAXFRM + NET_IP_ALIGN + DPA_PRIV_DATA_SIZE + DPA_PARSE_RESULTS_SIZE ++ * + DPA_HASH_RESULTS_SIZE, i.e.: ++ * MAXFRM + 2 + 16 + sizeof(t_FmPrsResult) + 16, i.e.: ++ * MAXFRM + 66 ++ * . excessive buffer pools not accounted for ++ * ++ * * for Rx ports on P4080: ++ * . IFSZ = ceil(max(FMBM_EBMPI[PBS]) / 256) * 256 + 7 * 256 ++ * . no internal frame offset (FMBM_RIM[FOF] == 0) - otherwise, ++ * add up to 256 to the above ++ * ++ * * for Rx ports on P1023: ++ * . IFSZ = ceil(second_largest(FMBM_EBMPI[PBS] / 256)) * 256 + 7 * 256, ++ * if at least 2 bpools are configured ++ * . IFSZ = 8 * 256, if only a single bpool is configured ++ * ++ * * for Tx ports: ++ * . IFSZ = ceil(frame_size / 256) * 256 + 3 * 256 ++ * + FMBM_TFP[DPDE] * 256, i.e.: ++ * IFSZ = ceil(MAXFRM / 256) * 256 + 3 x 256 + FMBM_TFP[DPDE] * 256 ++ * ++ * * for OH ports on P4080: ++ * . IFSZ = ceil(frame_size / 256) * 256 + 1 * 256 + FMBM_PP[MXT] * 256 ++ * * for OH ports on P1023: ++ * . IFSZ = ceil(frame_size / 256) * 256 + 3 * 256 + FMBM_TFP[DPDE] * 256 ++ * * for both P4080 and P1023: ++ * . (conservative decisions, assuming that BMI must bring the entire ++ * frame, not only the frame header) ++ * . no internal frame offset (FMBM_OIM[FOF] == 0) - otherwise, ++ * add up to 256 to the above ++ * ++ * . for P4080/P5020/P3041/P2040, DPDE is: ++ * > 0 or 1, for 1Gb ports, HW default: 0 ++ * > 2..7 (recommended: 3..7) for 10Gb ports, HW default: 3 ++ * . for P1023, DPDE should be 1 ++ * ++ * . for P1023, MXT is in range (0..31) ++ * . for P4080, MXT is in range (0..63) ++ * ++ */ ++#if 0 ++ if ((p_LnxWrpFmPortDev->defPcd != e_NO_PCD) && ++ (InitFmPort3TupleDefPcd(p_LnxWrpFmPortDev) != E_OK)) ++ RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); ++#endif ++ return E_OK; ++} ++ ++void fm_set_rx_port_params(struct fm_port *port, ++ struct fm_port_params *params) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) port; ++ int i; ++ ++ p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.errFqid = ++ params->errq; ++ p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.dfltFqid = ++ params->defq; ++ p_LnxWrpFmPortDev->settings.param.specificParams.rxParams.extBufPools. ++ numOfPoolsUsed = params->num_pools; ++ for (i = 0; i < params->num_pools; i++) { ++ p_LnxWrpFmPortDev->settings.param.specificParams.rxParams. ++ extBufPools.extBufPool[i].id = ++ params->pool_param[i].id; ++ p_LnxWrpFmPortDev->settings.param.specificParams.rxParams. ++ extBufPools.extBufPool[i].size = ++ params->pool_param[i].size; ++ } ++ ++ p_LnxWrpFmPortDev->buffPrefixContent.privDataSize = ++ params->priv_data_size; ++ p_LnxWrpFmPortDev->buffPrefixContent.passPrsResult = ++ params->parse_results; ++ p_LnxWrpFmPortDev->buffPrefixContent.passHashResult = ++ params->hash_results; ++ p_LnxWrpFmPortDev->buffPrefixContent.passTimeStamp = ++ params->time_stamp; ++ p_LnxWrpFmPortDev->buffPrefixContent.dataAlign = ++ params->data_align; ++ p_LnxWrpFmPortDev->buffPrefixContent.manipExtraSpace = ++ params->manip_extra_space; ++ ++ ADD_ADV_CONFIG_START(p_LnxWrpFmPortDev->settings.advConfig, ++ FM_MAX_NUM_OF_ADV_SETTINGS) ++ ++ ADD_ADV_CONFIG_NO_RET(FM_PORT_ConfigBufferPrefixContent, ++ ARGS(1, ++ (&p_LnxWrpFmPortDev-> ++ buffPrefixContent))); ++ ++ ADD_ADV_CONFIG_END InitFmPortDev(p_LnxWrpFmPortDev); ++} ++EXPORT_SYMBOL(fm_set_rx_port_params); ++ ++/* this function is called from oh_probe as well, thus it contains oh port ++ * specific parameters (make sure everything is checked) */ ++void fm_set_tx_port_params(struct fm_port *port, ++ struct fm_port_params *params) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) port; ++ ++ p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams.errFqid = ++ params->errq; ++ p_LnxWrpFmPortDev->settings.param.specificParams.nonRxParams. ++ dfltFqid = params->defq; ++ ++ p_LnxWrpFmPortDev->buffPrefixContent.privDataSize = ++ params->priv_data_size; ++ p_LnxWrpFmPortDev->buffPrefixContent.passPrsResult = ++ params->parse_results; ++ p_LnxWrpFmPortDev->buffPrefixContent.passHashResult = ++ params->hash_results; ++ p_LnxWrpFmPortDev->buffPrefixContent.passTimeStamp = ++ params->time_stamp; ++ p_LnxWrpFmPortDev->settings.frag_enabled = ++ params->frag_enable; ++ p_LnxWrpFmPortDev->buffPrefixContent.dataAlign = ++ params->data_align; ++ p_LnxWrpFmPortDev->buffPrefixContent.manipExtraSpace = ++ params->manip_extra_space; ++ ++ ADD_ADV_CONFIG_START(p_LnxWrpFmPortDev->settings.advConfig, ++ FM_MAX_NUM_OF_ADV_SETTINGS) ++ ++ ADD_ADV_CONFIG_NO_RET(FM_PORT_ConfigBufferPrefixContent, ++ ARGS(1, ++ (&p_LnxWrpFmPortDev-> ++ buffPrefixContent))); ++ ++ /* oh port specific parameter (for fragmentation only) */ ++ if ((p_LnxWrpFmPortDev->settings.param.portType == ++ e_FM_PORT_TYPE_OH_OFFLINE_PARSING) && ++ params->num_pools) { ++ int i; ++ ++ p_LnxWrpFmPortDev->opExtPools.numOfPoolsUsed = params->num_pools; ++ for (i = 0; i < params->num_pools; i++) { ++ p_LnxWrpFmPortDev->opExtPools.extBufPool[i].id = params->pool_param[i].id; ++ p_LnxWrpFmPortDev->opExtPools.extBufPool[i].size = params->pool_param[i].size; ++ } ++ ++ if (p_LnxWrpFmPortDev->settings.frag_enabled) ++ ADD_ADV_CONFIG_NO_RET(FM_PORT_ConfigExtBufPools, ++ ARGS(1, (&p_LnxWrpFmPortDev->opExtPools))); ++ } ++ ++ ADD_ADV_CONFIG_END InitFmPortDev(p_LnxWrpFmPortDev); ++} ++EXPORT_SYMBOL(fm_set_tx_port_params); ++ ++void fm_mac_set_handle(t_Handle h_lnx_wrp_fm_dev, ++ t_Handle h_fm_mac, ++ int mac_id) ++{ ++ t_LnxWrpFmDev *p_lnx_wrp_fm_dev = (t_LnxWrpFmDev *)h_lnx_wrp_fm_dev; ++ ++ p_lnx_wrp_fm_dev->macs[mac_id].h_Dev = h_fm_mac; ++ p_lnx_wrp_fm_dev->macs[mac_id].h_LnxWrpFmDev = h_lnx_wrp_fm_dev; ++} ++EXPORT_SYMBOL(fm_mac_set_handle); ++ ++static void LnxwrpFmPcdDevExceptionsCb(t_Handle h_App, ++ e_FmPcdExceptions exception) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *) h_App; ++ ++ ASSERT_COND(p_LnxWrpFmDev); ++ ++ DBG(INFO, ("got fm-pcd exception %d", exception)); ++ ++ /* do nothing */ ++ UNUSED(exception); ++} ++ ++static void LnxwrpFmPcdDevIndexedExceptionsCb(t_Handle h_App, ++ e_FmPcdExceptions exception, ++ uint16_t index) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev = (t_LnxWrpFmDev *) h_App; ++ ++ ASSERT_COND(p_LnxWrpFmDev); ++ ++ DBG(INFO, ++ ("got fm-pcd-indexed exception %d, indx %d", exception, index)); ++ ++ /* do nothing */ ++ UNUSED(exception); ++ UNUSED(index); ++} ++ ++static t_Error InitFmPcdDev(t_LnxWrpFmDev *p_LnxWrpFmDev) ++{ ++ spin_lock_init(&lock); ++ ++ if (p_LnxWrpFmDev->pcdActive) { ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = &p_LnxWrpFmDev->hcPort; ++ t_FmPcdParams fmPcdParams; ++ t_Error err; ++ ++ memset(&fmPcdParams, 0, sizeof(fmPcdParams)); ++ fmPcdParams.h_Fm = p_LnxWrpFmDev->h_Dev; ++ fmPcdParams.prsSupport = p_LnxWrpFmDev->prsActive; ++ fmPcdParams.kgSupport = p_LnxWrpFmDev->kgActive; ++ fmPcdParams.plcrSupport = p_LnxWrpFmDev->plcrActive; ++ fmPcdParams.ccSupport = p_LnxWrpFmDev->ccActive; ++ fmPcdParams.numOfSchemes = FM_PCD_KG_NUM_OF_SCHEMES; ++ ++#ifndef CONFIG_GUEST_PARTITION ++ fmPcdParams.f_Exception = LnxwrpFmPcdDevExceptionsCb; ++ if (fmPcdParams.kgSupport) ++ fmPcdParams.f_ExceptionId = ++ LnxwrpFmPcdDevIndexedExceptionsCb; ++ fmPcdParams.h_App = p_LnxWrpFmDev; ++#endif /* !CONFIG_GUEST_PARTITION */ ++ ++#ifdef CONFIG_MULTI_PARTITION_SUPPORT ++ fmPcdParams.numOfSchemes = 0; ++ fmPcdParams.numOfClsPlanEntries = 0; ++ fmPcdParams.partitionId = 0; ++#endif /* CONFIG_MULTI_PARTITION_SUPPORT */ ++ fmPcdParams.useHostCommand = TRUE; ++ ++ p_LnxWrpFmDev->hc_tx_fq = ++ FqAlloc(p_LnxWrpFmDev, ++ 0, ++ QMAN_FQ_FLAG_TO_DCPORTAL, ++ p_LnxWrpFmPortDev->txCh, 0); ++ if (!p_LnxWrpFmDev->hc_tx_fq) ++ RETURN_ERROR(MAJOR, E_NULL_POINTER, ++ ("Frame queue allocation failed...")); ++ ++ p_LnxWrpFmDev->hc_tx_conf_fq = ++ FqAlloc(p_LnxWrpFmDev, ++ 0, ++ QMAN_FQ_FLAG_NO_ENQUEUE, ++ p_LnxWrpFmDev->hcCh, 1); ++ if (!p_LnxWrpFmDev->hc_tx_conf_fq) ++ RETURN_ERROR(MAJOR, E_NULL_POINTER, ++ ("Frame queue allocation failed...")); ++ ++ p_LnxWrpFmDev->hc_tx_err_fq = ++ FqAlloc(p_LnxWrpFmDev, ++ 0, ++ QMAN_FQ_FLAG_NO_ENQUEUE, ++ p_LnxWrpFmDev->hcCh, 2); ++ if (!p_LnxWrpFmDev->hc_tx_err_fq) ++ RETURN_ERROR(MAJOR, E_NULL_POINTER, ++ ("Frame queue allocation failed...")); ++ ++ fmPcdParams.hc.portBaseAddr = p_LnxWrpFmPortDev->baseAddr; ++ fmPcdParams.hc.portId = ++ p_LnxWrpFmPortDev->settings.param.portId; ++ fmPcdParams.hc.liodnBase = ++ p_LnxWrpFmPortDev->settings.param.liodnBase; ++ fmPcdParams.hc.errFqid = ++ qman_fq_fqid(p_LnxWrpFmDev->hc_tx_err_fq); ++ fmPcdParams.hc.confFqid = ++ qman_fq_fqid(p_LnxWrpFmDev->hc_tx_conf_fq); ++ fmPcdParams.hc.qmChannel = p_LnxWrpFmPortDev->txCh; ++ fmPcdParams.hc.f_QmEnqueue = QmEnqueueCB; ++ fmPcdParams.hc.h_QmArg = (t_Handle) p_LnxWrpFmDev; ++ ++ p_LnxWrpFmDev->h_PcdDev = FM_PCD_Config(&fmPcdParams); ++ if (!p_LnxWrpFmDev->h_PcdDev) ++ RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM PCD!")); ++ ++ err = ++ FM_PCD_ConfigPlcrNumOfSharedProfiles(p_LnxWrpFmDev->h_PcdDev, ++ LNXWRP_FM_NUM_OF_SHARED_PROFILES); ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ err = FM_PCD_Init(p_LnxWrpFmDev->h_PcdDev); ++ if (err != E_OK) ++ RETURN_ERROR(MAJOR, err, NO_MSG); ++ ++ if (p_LnxWrpFmDev->err_irq == 0) { ++ FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, ++ e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC, ++ FALSE); ++ FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, ++ e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW, ++ FALSE); ++ FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, ++ e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR, ++ FALSE); ++ FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, ++ e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC, ++ FALSE); ++ FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, ++ e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC, ++ FALSE); ++ FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, ++ e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE, ++ FALSE); ++ FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, ++ e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE, ++ FALSE); ++ FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, ++ e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC, ++ FALSE); ++ } ++ } ++ ++ return E_OK; ++} ++ ++void FreeFmPcdDev(t_LnxWrpFmDev *p_LnxWrpFmDev) ++{ ++ ++ if (p_LnxWrpFmDev->h_PcdDev) ++ FM_PCD_Free(p_LnxWrpFmDev->h_PcdDev); ++ ++ if (p_LnxWrpFmDev->hc_tx_err_fq) ++ FqFree(p_LnxWrpFmDev->hc_tx_err_fq); ++ ++ if (p_LnxWrpFmDev->hc_tx_conf_fq) ++ FqFree(p_LnxWrpFmDev->hc_tx_conf_fq); ++ ++ if (p_LnxWrpFmDev->hc_tx_fq) ++ FqFree(p_LnxWrpFmDev->hc_tx_fq); ++} ++ ++static void FreeFmPortDev(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev = ++ (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; ++ ++ if (!p_LnxWrpFmPortDev->active) ++ return; ++ ++ if (p_LnxWrpFmPortDev->h_Dev) ++ FM_PORT_Free(p_LnxWrpFmPortDev->h_Dev); ++ ++ devm_iounmap(p_LnxWrpFmDev->dev, ++ UINT_TO_PTR(p_LnxWrpFmPortDev->baseAddr)); ++ __devm_release_region(p_LnxWrpFmDev->dev, p_LnxWrpFmDev->res, ++ p_LnxWrpFmPortDev->phys_baseAddr, ++ p_LnxWrpFmPortDev->memSize); ++} ++ ++static int /*__devinit*/ fm_port_probe(struct platform_device *of_dev) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; ++ t_LnxWrpFmDev *p_LnxWrpFmDev; ++ struct device *dev; ++ ++ dev = &of_dev->dev; ++ ++ p_LnxWrpFmPortDev = ReadFmPortDevTreeNode(of_dev); ++ if (p_LnxWrpFmPortDev == NULL) ++ return -EIO; ++ /* Port can be inactive, thus will not be probed: ++ - in performance mode, OH ports are disabled ++ ... ++ */ ++ if (!p_LnxWrpFmPortDev->active) ++ return 0; ++ ++ if (ConfigureFmPortDev(p_LnxWrpFmPortDev) != E_OK) ++ return -EIO; ++ ++ dev_set_drvdata(dev, p_LnxWrpFmPortDev); ++ ++ if (p_LnxWrpFmPortDev->settings.param.portType == ++ e_FM_PORT_TYPE_OH_HOST_COMMAND) ++ InitFmPcdDev((t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev); ++ ++ p_LnxWrpFmDev = (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; ++ ++ if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX) { ++ Sprint(p_LnxWrpFmPortDev->name, "%s-port-rx%d", ++ p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id); ++ p_LnxWrpFmPortDev->minor = ++ p_LnxWrpFmPortDev->id + DEV_FM_RX_PORTS_MINOR_BASE; ++ } else if (p_LnxWrpFmPortDev->settings.param.portType == ++ e_FM_PORT_TYPE_RX_10G) { ++ Sprint(p_LnxWrpFmPortDev->name, "%s-port-rx%d", ++ p_LnxWrpFmDev->name, ++ p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_RX_PORTS); ++ p_LnxWrpFmPortDev->minor = ++ p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_RX_PORTS + ++ DEV_FM_RX_PORTS_MINOR_BASE; ++#ifndef CONFIG_FMAN_ARM ++ if (IS_T1023_T1024) { ++ Sprint(p_LnxWrpFmPortDev->name, "%s-port-rx%d", ++ p_LnxWrpFmDev->name, ++ p_LnxWrpFmPortDev->id); ++ p_LnxWrpFmPortDev->minor = ++ p_LnxWrpFmPortDev->id + ++ DEV_FM_RX_PORTS_MINOR_BASE; ++ } ++#endif ++ } else if (p_LnxWrpFmPortDev->settings.param.portType == ++ e_FM_PORT_TYPE_TX) { ++ Sprint(p_LnxWrpFmPortDev->name, "%s-port-tx%d", ++ p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id); ++ p_LnxWrpFmPortDev->minor = ++ p_LnxWrpFmPortDev->id + DEV_FM_TX_PORTS_MINOR_BASE; ++ } else if (p_LnxWrpFmPortDev->settings.param.portType == ++ e_FM_PORT_TYPE_TX_10G) { ++ Sprint(p_LnxWrpFmPortDev->name, "%s-port-tx%d", ++ p_LnxWrpFmDev->name, ++ p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_TX_PORTS); ++ p_LnxWrpFmPortDev->minor = ++ p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_TX_PORTS + ++ DEV_FM_TX_PORTS_MINOR_BASE; ++#ifndef CONFIG_FMAN_ARM ++ if (IS_T1023_T1024) { ++ Sprint(p_LnxWrpFmPortDev->name, "%s-port-tx%d", ++ p_LnxWrpFmDev->name, ++ p_LnxWrpFmPortDev->id); ++ p_LnxWrpFmPortDev->minor = ++ p_LnxWrpFmPortDev->id + ++ DEV_FM_TX_PORTS_MINOR_BASE; ++ } ++#endif ++ } else if (p_LnxWrpFmPortDev->settings.param.portType == ++ e_FM_PORT_TYPE_OH_HOST_COMMAND) { ++ Sprint(p_LnxWrpFmPortDev->name, "%s-port-oh%d", ++ p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id); ++ p_LnxWrpFmPortDev->minor = ++ p_LnxWrpFmPortDev->id + DEV_FM_OH_PORTS_MINOR_BASE; ++ } else if (p_LnxWrpFmPortDev->settings.param.portType == ++ e_FM_PORT_TYPE_OH_OFFLINE_PARSING) { ++ Sprint(p_LnxWrpFmPortDev->name, "%s-port-oh%d", ++ p_LnxWrpFmDev->name, p_LnxWrpFmPortDev->id + 1); ++ p_LnxWrpFmPortDev->minor = ++ p_LnxWrpFmPortDev->id + 1 + ++ DEV_FM_OH_PORTS_MINOR_BASE; ++ } ++ ++ device_create(p_LnxWrpFmDev->fm_class, NULL, ++ MKDEV(p_LnxWrpFmDev->major, p_LnxWrpFmPortDev->minor), ++ NULL, p_LnxWrpFmPortDev->name); ++ ++ /* create sysfs entries for stats and regs */ ++ ++ if (fm_port_sysfs_create(dev) != 0) { ++ FreeFmPortDev(p_LnxWrpFmPortDev); ++ REPORT_ERROR(MAJOR, E_INVALID_STATE, ++ ("Unable to create sys entry - fm port!!!")); ++ return -EIO; ++ } ++ ++#ifdef FM_TX_INVALID_ECC_ERRATA_10GMAC_A009 ++ FM_DisableRamsEcc(p_LnxWrpFmDev->h_Dev); ++#endif /* FM_TX_INVALID_ECC_ERRATA_10GMAC_A009 */ ++ ++ DBG(TRACE, ("%s probed", p_LnxWrpFmPortDev->name)); ++ ++ return 0; ++} ++ ++static int fm_port_remove(struct platform_device *of_dev) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; ++ t_LnxWrpFmDev *p_LnxWrpFmDev; ++ struct device *dev; ++ ++ dev = &of_dev->dev; ++ p_LnxWrpFmPortDev = dev_get_drvdata(dev); ++ ++ fm_port_sysfs_destroy(dev); ++ ++ p_LnxWrpFmDev = (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; ++ device_destroy(p_LnxWrpFmDev->fm_class, ++ MKDEV(p_LnxWrpFmDev->major, p_LnxWrpFmPortDev->minor)); ++ ++ FreeFmPortDev(p_LnxWrpFmPortDev); ++ ++ dev_set_drvdata(dev, NULL); ++ ++ return 0; ++} ++ ++static const struct of_device_id fm_port_match[] = { ++ { ++ .compatible = "fsl,fman-port-oh"}, ++ { ++ .compatible = "fsl,fman-port-1g-rx"}, ++ { ++ .compatible = "fsl,fman-port-10g-rx"}, ++ { ++ .compatible = "fsl,fman-port-1g-tx"}, ++ { ++ .compatible = "fsl,fman-port-10g-tx"}, ++ {} ++}; ++ ++#ifndef MODULE ++MODULE_DEVICE_TABLE(of, fm_port_match); ++#endif /* !MODULE */ ++ ++static struct platform_driver fm_port_driver = { ++ ++ .driver = { ++ .name = "fsl-fman-port", ++ .of_match_table = fm_port_match, ++ .owner = THIS_MODULE, ++ }, ++ .probe = fm_port_probe, ++ .remove = fm_port_remove ++}; ++ ++ ++t_Error LNXWRP_FM_Port_Init(void) ++{ ++ /* Register to the DTB for basic FM port API */ ++ if (platform_driver_register(&fm_port_driver)) ++ return E_NO_DEVICE; ++ ++ return E_OK; ++} ++ ++void LNXWRP_FM_Port_Free(void) ++{ ++ platform_driver_unregister(&fm_port_driver); ++} ++ ++static int __init __cold fm_port_load(void) ++{ ++ if (LNXWRP_FM_Port_Init() != E_OK) { ++ printk(KERN_CRIT "Failed to init FM Ports wrapper!\n"); ++ return -ENODEV; ++ } ++ ++ printk(KERN_CRIT "Freescale FM Ports module\n"); ++ ++ return 0; ++} ++ ++static void __exit __cold fm_port_unload(void) ++{ ++ LNXWRP_FM_Port_Free(); ++} ++ ++module_init(fm_port_load); ++module_exit(fm_port_unload); +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm.c +new file mode 100644 +index 00000000..1ddde856 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm.c +@@ -0,0 +1,4813 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ @File lnxwrp_ioctls_fm.c ++ @Author Shlomi Gridish ++ @Description FM Linux wrapper functions. ++*/ ++ ++/* Linux Headers ------------------- */ ++#include ++ ++#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) ++#define MODVERSIONS ++#endif ++#ifdef MODVERSIONS ++#include ++#endif /* MODVERSIONS */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifndef CONFIG_FMAN_ARM ++#include ++#include ++#endif ++ ++#if defined(CONFIG_COMPAT) ++#include ++#endif ++ ++#include "part_ext.h" ++#include "fm_ioctls.h" ++#include "fm_pcd_ioctls.h" ++#include "fm_port_ioctls.h" ++#include "fm_vsp_ext.h" ++ ++#ifndef CONFIG_FMAN_ARM ++#define IS_T1023_T1024 (SVR_SOC_VER(mfspr(SPRN_SVR)) == SVR_T1024 || \ ++ SVR_SOC_VER(mfspr(SPRN_SVR)) == SVR_T1023) ++#endif ++ ++#define __ERR_MODULE__ MODULE_FM ++ ++#if defined(CONFIG_COMPAT) ++#include "lnxwrp_ioctls_fm_compat.h" ++#endif ++ ++#include "lnxwrp_fm.h" ++ ++#define CMP_IOC_DEFINE(def) (IOC_##def != def) ++ ++/* fm_pcd_ioctls.h === fm_pcd_ext.h assertions */ ++#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_PRIVATE_HDRS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(FM_PCD_PRS_NUM_OF_HDRS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(FM_PCD_KG_NUM_OF_GENERIC_REGS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(FM_PCD_KG_NUM_OF_EXTRACT_MASKS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(FM_PCD_KG_NUM_OF_DEFAULT_GROUPS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(FM_PCD_PRS_NUM_OF_LABELS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(FM_PCD_SW_PRS_SIZE) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(FM_PCD_MAX_MANIP_INSRT_TEMPLATE_SIZE) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if DPAA_VERSION >= 11 ++#if CMP_IOC_DEFINE(FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES) ++#error Error: please synchronize IOC_ defines! ++#endif ++#endif ++ ++#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_TREES) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_GROUPS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_UNITS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_KEYS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(FM_PCD_MAX_SIZE_OF_KEY) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(FM_PCD_LAST_KEY_INDEX) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++/* net_ioctls.h === net_ext.h assertions */ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPP_PID) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPP_COMPRESSED) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPP_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPPoE_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPPMUX_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PPPMUX_SUBFRAME_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_ETH_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPv4_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPv6_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_ICMP_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IGMP_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_TCP_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_SCTP_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_DCCP_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_UDP_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_UDP_ENCAP_ESP_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPHC_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_SCTP_CHUNK_DATA_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_L2TPv2_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_L2TPv3_CTRL_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_L2TPv3_SESS_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_VLAN_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_LLC_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_NLPID_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_SNAP_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_LLC_SNAP_ALL_FIELDS) ++#warning Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_ARP_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_RFC2684_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_USER_DEFINED_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_PAYLOAD_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_GRE_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_MINENCAP_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPSEC_AH_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_IPSEC_ESP_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_MPLS_LABEL_STACK_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++#if CMP_IOC_DEFINE(NET_HEADER_FIELD_MACSEC_ALL_FIELDS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++/* fm_ioctls.h === fm_ext.h assertions */ ++#if CMP_IOC_DEFINE(FM_MAX_NUM_OF_VALID_PORTS) ++#error Error: please synchronize IOC_ defines! ++#endif ++ ++void LnxWrpPCDIOCTLTypeChecking(void) ++{ ++ /* fm_ext.h == fm_ioctls.h */ ++ ASSERT_COND(sizeof(ioc_fm_port_bandwidth_params) == sizeof(t_FmPortsBandwidthParams)); ++ ASSERT_COND(sizeof(ioc_fm_revision_info_t) == sizeof(t_FmRevisionInfo)); ++ ++ /* fm_pcd_ext.h == fm_pcd_ioctls.h */ ++ /*ioc_fm_pcd_counters_params_t : NOT USED */ ++ /*ioc_fm_pcd_exception_params_t : private */ ++#if (DPAA_VERSION >= 11) ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_capwap_params_t) == sizeof(t_FmPcdManipFragCapwapParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_capwap_params_t) == sizeof(t_FmPcdManipReassemCapwapParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_insrt_by_hdr_params_t) == sizeof(t_FmPcdManipHdrInsrtByHdrParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_insrt_ip_params_t) == sizeof(t_FmPcdManipHdrInsrtIpParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_insrt_t) == sizeof(t_FmPcdManipHdrInsrt)); ++ ASSERT_COND(sizeof(ioc_fm_manip_hdr_info_t) == sizeof(t_FmManipHdrInfo)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_rmv_by_hdr_params_t) == sizeof(t_FmPcdManipHdrRmvByHdrParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_special_offload_capwap_params_t) == sizeof(t_FmPcdManipSpecialOffloadCapwapParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_capwap_stats_t) == sizeof(t_FmPcdManipFragCapwapStats)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_capwap_stats_t) == sizeof(t_FmPcdManipReassemCapwapStats)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_params_t) == sizeof(t_FmPcdManipFragParams)); ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ ASSERT_COND(sizeof(ioc_fm_pcd_prs_label_params_t) == sizeof(t_FmPcdPrsLabelParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_prs_sw_params_t) == sizeof(t_FmPcdPrsSwParams)); ++ /*ioc_fm_pcd_kg_dflt_value_params_t : private */ ++ ASSERT_COND(sizeof(ioc_fm_pcd_hdr_protocol_opt_u) == sizeof(u_FmPcdHdrProtocolOpt)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_fields_u) == sizeof(t_FmPcdFields)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_from_hdr_t) == sizeof(t_FmPcdFromHdr)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_from_field_t) == sizeof(t_FmPcdFromField)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_distinction_unit_t) == sizeof(t_FmPcdDistinctionUnit)); ++ ++#if defined(CONFIG_ARM64) ++ /* different alignment */ ++ ASSERT_COND(sizeof(ioc_fm_pcd_net_env_params_t) == sizeof(t_FmPcdNetEnvParams) + sizeof(void *) + 4); ++#else ++#if !defined(CONFIG_COMPAT) ++ /* different alignment */ ++ ASSERT_COND(sizeof(ioc_fm_pcd_net_env_params_t) == sizeof(t_FmPcdNetEnvParams) + sizeof(void *)); ++#endif ++#endif ++ ASSERT_COND(sizeof(ioc_fm_pcd_extract_entry_t) == sizeof(t_FmPcdExtractEntry)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_kg_extract_mask_t) == sizeof(t_FmPcdKgExtractMask)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_kg_extract_dflt_t) == sizeof(t_FmPcdKgExtractDflt)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_kg_key_extract_and_hash_params_t) == sizeof(t_FmPcdKgKeyExtractAndHashParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_kg_extracted_or_params_t) == sizeof(t_FmPcdKgExtractedOrParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_kg_scheme_counter_t) == sizeof(t_FmPcdKgSchemeCounter)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_kg_plcr_profile_t) == sizeof(t_FmPcdKgPlcrProfile)); ++#if (DPAA_VERSION >= 11) ++ ASSERT_COND(sizeof(ioc_fm_pcd_kg_storage_profile_t) == sizeof(t_FmPcdKgStorageProfile)); ++#endif ++ ASSERT_COND(sizeof(ioc_fm_pcd_kg_cc_t) == sizeof(t_FmPcdKgCc)); ++#if !defined(CONFIG_COMPAT) ++ /* different alignment */ ++ ASSERT_COND(sizeof(ioc_fm_pcd_kg_scheme_params_t) == sizeof(t_FmPcdKgSchemeParams) + sizeof(void *)); ++#endif ++ ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_cc_params_t) == sizeof(t_FmPcdCcNextCcParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_plcr_params_t) == sizeof(t_FmPcdCcNextPlcrParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_enqueue_params_t) == sizeof(t_FmPcdCcNextEnqueueParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_kg_params_t) == sizeof(t_FmPcdCcNextKgParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_cc_next_engine_params_t) == sizeof(t_FmPcdCcNextEngineParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_cc_key_params_t) == sizeof(t_FmPcdCcKeyParams)); ++ ASSERT_COND(sizeof(ioc_keys_params_t) == sizeof(t_KeysParams)); ++#if !defined(CONFIG_COMPAT) ++ /* different alignment */ ++ ASSERT_COND(sizeof(ioc_fm_pcd_cc_node_params_t) == sizeof(t_FmPcdCcNodeParams) + sizeof(void *)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_hash_table_params_t) == sizeof(t_FmPcdHashTableParams) + sizeof(void *)); ++#endif ++ ASSERT_COND(sizeof(ioc_fm_pcd_cc_grp_params_t) == sizeof(t_FmPcdCcGrpParams)); ++#if !defined(CONFIG_COMPAT) ++ /* different alignment */ ++ ASSERT_COND(sizeof(ioc_fm_pcd_cc_tree_params_t) == sizeof(t_FmPcdCcTreeParams) + sizeof(void *)); ++#endif ++ ASSERT_COND(sizeof(ioc_fm_pcd_plcr_byte_rate_mode_param_t) == sizeof(t_FmPcdPlcrByteRateModeParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_plcr_non_passthrough_alg_param_t) == sizeof(t_FmPcdPlcrNonPassthroughAlgParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_plcr_next_engine_params_u) == sizeof(u_FmPcdPlcrNextEngineParams)); ++ /*ioc_fm_pcd_port_params_t : private */ ++ ASSERT_COND(sizeof(ioc_fm_pcd_plcr_profile_params_t) == sizeof(t_FmPcdPlcrProfileParams) + sizeof(void *)); ++ /*ioc_fm_pcd_cc_tree_modify_next_engine_params_t : private */ ++ ++#ifdef FM_CAPWAP_SUPPORT ++#error TODO: unsupported feature ++/* ++ ASSERT_COND(sizeof(TODO) == sizeof(t_FmPcdManipHdrInsrtByTemplateParams)); ++ ASSERT_COND(sizeof(TODO) == sizeof(t_CapwapFragmentationParams)); ++ ASSERT_COND(sizeof(TODO) == sizeof(t_CapwapReassemblyParams)); ++*/ ++#endif ++ ++ /*ioc_fm_pcd_cc_node_modify_next_engine_params_t : private */ ++ /*ioc_fm_pcd_cc_node_remove_key_params_t : private */ ++ /*ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t : private */ ++ /*ioc_fm_pcd_cc_node_modify_key_params_t : private */ ++ /*ioc_fm_manip_hdr_info_t : private */ ++ /*ioc_fm_pcd_hash_table_set_t : private */ ++ ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_ip_params_t) == sizeof(t_FmPcdManipFragIpParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_ip_params_t) == sizeof(t_FmPcdManipReassemIpParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_special_offload_ipsec_params_t) == sizeof(t_FmPcdManipSpecialOffloadIPSecParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_special_offload_params_t) == sizeof(t_FmPcdManipSpecialOffloadParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_rmv_generic_params_t) == sizeof(t_FmPcdManipHdrRmvGenericParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_insrt_generic_params_t) == sizeof(t_FmPcdManipHdrInsrtGenericParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_insrt_params_t) == sizeof(t_FmPcdManipHdrInsrtParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_rmv_params_t) == sizeof(t_FmPcdManipHdrRmvParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_hdr_params_t) == sizeof(t_FmPcdManipHdrParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_params_t) == sizeof(t_FmPcdManipFragParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_params_t) == sizeof(t_FmPcdManipReassemParams)); ++#if !defined(CONFIG_COMPAT) ++ /* different alignment */ ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_params_t) == sizeof(t_FmPcdManipParams) + sizeof(void *)); ++#endif ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_ip_stats_t) == sizeof(t_FmPcdManipReassemIpStats)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_ip_stats_t) == sizeof(t_FmPcdManipFragIpStats)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_reassem_stats_t) == sizeof(t_FmPcdManipReassemStats)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_frag_stats_t) == sizeof(t_FmPcdManipFragStats)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_manip_stats_t) == sizeof(t_FmPcdManipStats)); ++#if DPAA_VERSION >= 11 ++ ASSERT_COND(sizeof(ioc_fm_pcd_frm_replic_group_params_t) == sizeof(t_FmPcdFrmReplicGroupParams) + sizeof(void *)); ++#endif ++ ++ /* fm_port_ext.h == fm_port_ioctls.h */ ++ ASSERT_COND(sizeof(ioc_fm_port_rate_limit_t) == sizeof(t_FmPortRateLimit)); ++ ASSERT_COND(sizeof(ioc_fm_port_pcd_params_t) == sizeof(t_FmPortPcdParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_kg_scheme_select_t) == sizeof(t_FmPcdKgSchemeSelect)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_port_schemes_params_t) == sizeof(t_FmPcdPortSchemesParams)); ++ ASSERT_COND(sizeof(ioc_fm_pcd_prs_start_t) == sizeof(t_FmPcdPrsStart)); ++ ++ return; ++} ++ ++#define ASSERT_IOC_NET_ENUM(def) ASSERT_COND((unsigned long)e_IOC_NET_##def == (unsigned long)def) ++ ++void LnxWrpPCDIOCTLEnumChecking(void) ++{ ++ /* net_ext.h == net_ioctls.h : sampling checks */ ++ ASSERT_IOC_NET_ENUM(HEADER_TYPE_MACSEC); ++ ASSERT_IOC_NET_ENUM(HEADER_TYPE_PPP); ++ ASSERT_IOC_NET_ENUM(MAX_HEADER_TYPE_COUNT); ++ ++ /* fm_ext.h == fm_ioctls.h */ ++ ASSERT_COND((unsigned long)e_IOC_FM_PORT_TYPE_DUMMY == (unsigned long)e_FM_PORT_TYPE_DUMMY); ++ ASSERT_COND((unsigned long)e_IOC_EX_MURAM_ECC == (unsigned long)e_FM_EX_MURAM_ECC); ++ ASSERT_COND((unsigned long)e_IOC_FM_COUNTERS_DEQ_CONFIRM == (unsigned long)e_FM_COUNTERS_DEQ_CONFIRM); ++ ++ /* fm_pcd_ext.h == fm_pcd_ioctls.h */ ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES == (unsigned long)e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PRS_EXCEPTION_SINGLE_ECC == (unsigned long)e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PRS == (unsigned long)e_FM_PCD_PRS); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_EXTRACT_FULL_FIELD == (unsigned long)e_FM_PCD_EXTRACT_FULL_FIELD); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_EXTRACT_FROM_FLOW_ID == (unsigned long)e_FM_PCD_EXTRACT_FROM_FLOW_ID); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO == (unsigned long)e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_KG_DFLT_ILLEGAL == (unsigned long)e_FM_PCD_KG_DFLT_ILLEGAL); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_KG_GENERIC_NOT_FROM_DATA == (unsigned long)e_FM_PCD_KG_GENERIC_NOT_FROM_DATA); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_HDR_INDEX_LAST == (unsigned long)e_FM_PCD_HDR_INDEX_LAST); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_SHARED == (unsigned long)e_FM_PCD_PLCR_SHARED); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_RFC_4115 == (unsigned long)e_FM_PCD_PLCR_RFC_4115); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_COLOR_AWARE == (unsigned long)e_FM_PCD_PLCR_COLOR_AWARE); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_OVERRIDE == (unsigned long)e_FM_PCD_PLCR_OVERRIDE); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_FULL_FRM_LEN == (unsigned long)e_FM_PCD_PLCR_FULL_FRM_LEN); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN == (unsigned long)e_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_PACKET_MODE == (unsigned long)e_FM_PCD_PLCR_PACKET_MODE); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_DROP_FRAME == (unsigned long)e_FM_PCD_DROP_FRAME); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER == (unsigned long)e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP == (unsigned long)e_FM_PCD_ACTION_INDEXED_LOOKUP); ++ ASSERT_COND((unsigned long)e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR == (unsigned long)e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR); ++#if !defined(FM_CAPWAP_SUPPORT) ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_INSRT_GENERIC == (unsigned long)e_FM_PCD_MANIP_INSRT_GENERIC); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_RMV_GENERIC == (unsigned long)e_FM_PCD_MANIP_RMV_GENERIC); ++#else ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_INSRT_BY_TEMPLATE == (unsigned long)e_FM_PCD_MANIP_INSRT_BY_TEMPLATE); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_RMV_BY_HDR == (unsigned long)e_FM_PCD_MANIP_RMV_BY_HDR); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_RMV_BY_HDR_FROM_START == (unsigned long)e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START); ++#endif ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAG == (unsigned long)e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAG); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_EIGHT_WAYS_HASH == (unsigned long)e_FM_PCD_MANIP_EIGHT_WAYS_HASH); ++ ++#ifdef FM_CAPWAP_SUPPORT ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_STATS_PER_FLOWID == (unsigned long)e_FM_PCD_STATS_PER_FLOWID); ++#endif ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD == (unsigned long)e_FM_PCD_MANIP_SPECIAL_OFFLOAD); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_CC_STATS_MODE_FRAME == (unsigned long)e_FM_PCD_CC_STATS_MODE_FRAME); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_CONTINUE_WITHOUT_FRAG == (unsigned long)e_FM_PCD_MANIP_CONTINUE_WITHOUT_FRAG); ++ ASSERT_COND((unsigned long)e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC == (unsigned long)e_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC); ++ ++ /* fm_port_ext.h == fm_port_ioctls.h */ ++#if !defined(FM_CAPWAP_SUPPORT) ++ ASSERT_COND((unsigned long)e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR == (unsigned long)e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR); ++#else ++ ASSERT_COND((unsigned long)e_IOC_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR == (unsigned long)e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR); ++#endif ++ ASSERT_COND((unsigned long)e_IOC_FM_PORT_COUNTERS_DEQ_CONFIRM == (unsigned long)e_FM_PORT_COUNTERS_DEQ_CONFIRM); ++ ASSERT_COND((unsigned long)e_IOC_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8 == (unsigned long)e_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8); ++ ++ return; ++} ++ ++static t_Error LnxwrpFmPcdIOCTL(t_LnxWrpFmDev *p_LnxWrpFmDev, unsigned int cmd, unsigned long arg, bool compat) ++{ ++ t_Error err = E_OK; ++ ++/* ++Status: PCD API to fmlib (file: drivers/net/dpa/NetCommSw/inc/Peripherals/fm_pcd_ext.h): ++ ++ FM_PCD_PrsLoadSw ++ FM_PCD_SetAdvancedOffloadSupport ++ FM_PCD_Enable ++ FM_PCD_Disable ++ FM_PCD_ForceIntr ++ FM_PCD_SetException ++ FM_PCD_KgSetAdditionalDataAfterParsing ++ FM_PCD_KgSetDfltValue ++ FM_PCD_NetEnvCharacteristicsSet ++ FM_PCD_NetEnvCharacteristicsDelete ++ FM_PCD_KgSchemeSet ++ FM_PCD_KgSchemeDelete ++ FM_PCD_MatchTableSet ++ FM_PCD_MatchTableDelete ++ FM_PCD_CcRootBuild ++ FM_PCD_CcRootDelete ++ FM_PCD_PlcrProfileSet ++ FM_PCD_PlcrProfileDelete ++ FM_PCD_CcRootModifyNextEngine ++ FM_PCD_MatchTableModifyNextEngine ++ FM_PCD_MatchTableModifyMissNextEngine ++ FM_PCD_MatchTableRemoveKey ++ FM_PCD_MatchTableAddKey ++ FM_PCD_MatchTableModifyKeyAndNextEngine ++ FM_PCD_HashTableSet ++ FM_PCD_HashTableDelete ++ FM_PCD_HashTableAddKey ++ FM_PCD_HashTableRemoveKey ++ FM_PCD_MatchTableModifyKey ++ FM_PCD_ManipNodeReplace ++ FM_PCD_ManipNodeSet ++ FM_PCD_ManipNodeDelete ++ ++Status: not exported, should be thru sysfs ++ FM_PCD_KgSchemeGetCounter ++ FM_PCD_KgSchemeSetCounter ++ FM_PCD_PlcrProfileGetCounter ++ FM_PCD_PlcrProfileSetCounter ++ ++Status: not exported ++ FM_PCD_MatchTableFindNRemoveKey ++ FM_PCD_MatchTableFindNModifyNextEngine ++ FM_PCD_MatchTableFindNModifyKeyAndNextEngine ++ FM_PCD_MatchTableFindNModifyKey ++ FM_PCD_MatchTableGetIndexedHashBucket ++ FM_PCD_MatchTableGetNextEngine ++ FM_PCD_MatchTableGetKeyCounter ++ ++Status: not exported, would be nice to have ++ FM_PCD_HashTableModifyNextEngine ++ FM_PCD_HashTableModifyMissNextEngine ++ FM_PCD_HashTableGetMissNextEngine ++ FM_PCD_ManipGetStatistics ++ ++Status: not exported ++#if DPAA_VERSION >= 11 ++ ++ FM_VSP_GetStatistics -- it's not available yet ++#endif ++ ++Status: feature not supported ++#ifdef FM_CAPWAP_SUPPORT ++#error unsupported feature ++ FM_PCD_StatisticsSetNode ++#endif ++ ++ */ ++ _fm_ioctl_dbg("cmd:0x%08x(type:0x%02x, nr:%u).\n", ++ cmd, _IOC_TYPE(cmd), _IOC_NR(cmd) - 20); ++ ++ switch (cmd) ++ { ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_PRS_LOAD_SW_COMPAT: ++#endif ++ case FM_PCD_IOC_PRS_LOAD_SW: ++ { ++ ioc_fm_pcd_prs_sw_params_t *param; ++ uint8_t *p_code; ++ ++ param = (ioc_fm_pcd_prs_sw_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_prs_sw_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_prs_sw_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_prs_sw_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_prs_sw_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_prs_sw_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_prs_sw_params_t)); ++ if (copy_from_user(compat_param, ++ (ioc_compat_fm_pcd_prs_sw_params_t *) compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_prs_sw_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_fm_pcd_prs_sw(compat_param, param, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_prs_sw_params_t *)arg, ++ sizeof(ioc_fm_pcd_prs_sw_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ if (!param->p_code || !param->size) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ p_code = (uint8_t *) XX_Malloc(param->size); ++ if (!p_code) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(p_code, 0, param->size); ++ if (copy_from_user(p_code, param->p_code, param->size)) ++ { ++ XX_Free(p_code); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ param->p_code = p_code; ++ ++ err = FM_PCD_PrsLoadSw(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdPrsSwParams*)param); ++ ++ XX_Free(p_code); ++ XX_Free(param); ++ break; ++ } ++ ++ case FM_PCD_IOC_SET_ADVANCED_OFFLOAD_SUPPORT: ++ err = FM_PCD_SetAdvancedOffloadSupport(p_LnxWrpFmDev->h_PcdDev); ++ break; ++ ++ case FM_PCD_IOC_ENABLE: ++ err = FM_PCD_Enable(p_LnxWrpFmDev->h_PcdDev); ++ break; ++ ++ case FM_PCD_IOC_DISABLE: ++ err = FM_PCD_Disable(p_LnxWrpFmDev->h_PcdDev); ++ break; ++ ++ case FM_PCD_IOC_FORCE_INTR: ++ { ++ int exception; ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (get_user(exception, (int *) compat_ptr(arg))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ else ++#endif ++ { ++ if (get_user(exception, (int *)arg)) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ err = FM_PCD_ForceIntr(p_LnxWrpFmDev->h_PcdDev, (e_FmPcdExceptions)exception); ++ break; ++ } ++ ++ case FM_PCD_IOC_SET_EXCEPTION: ++ { ++ ioc_fm_pcd_exception_params_t *param; ++ ++ param = (ioc_fm_pcd_exception_params_t *) XX_Malloc( ++ sizeof(ioc_fm_pcd_exception_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_exception_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_exception_params_t *)compat_ptr(arg), ++ sizeof(ioc_fm_pcd_exception_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_exception_params_t *)arg, ++ sizeof(ioc_fm_pcd_exception_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ err = FM_PCD_SetException(p_LnxWrpFmDev->h_PcdDev, param->exception, param->enable); ++ ++ XX_Free(param); ++ break; ++ } ++ ++ case FM_PCD_IOC_KG_SET_ADDITIONAL_DATA_AFTER_PARSING: ++ { ++ uint8_t payloadOffset; ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (get_user(payloadOffset, (uint8_t*) compat_ptr(arg))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ else ++#endif ++ { ++ if (get_user(payloadOffset, (uint8_t*) arg)) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ err = FM_PCD_KgSetAdditionalDataAfterParsing(p_LnxWrpFmDev->h_PcdDev, payloadOffset); ++ break; ++ } ++ ++ case FM_PCD_IOC_KG_SET_DFLT_VALUE: ++ { ++ ioc_fm_pcd_kg_dflt_value_params_t *param; ++ ++ param = (ioc_fm_pcd_kg_dflt_value_params_t *) XX_Malloc( ++ sizeof(ioc_fm_pcd_kg_dflt_value_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_kg_dflt_value_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_kg_dflt_value_params_t *)compat_ptr(arg), ++ sizeof(ioc_fm_pcd_kg_dflt_value_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_kg_dflt_value_params_t *)arg, ++ sizeof(ioc_fm_pcd_kg_dflt_value_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ err = FM_PCD_KgSetDfltValue(p_LnxWrpFmDev->h_PcdDev, param->valueId, param->value); ++ ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_NET_ENV_CHARACTERISTICS_SET_COMPAT: ++#endif ++ case FM_PCD_IOC_NET_ENV_CHARACTERISTICS_SET: ++ { ++ ioc_fm_pcd_net_env_params_t *param; ++ ++ param = (ioc_fm_pcd_net_env_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_net_env_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_net_env_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_net_env_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_net_env_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_net_env_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_net_env_params_t)); ++ if (copy_from_user(compat_param, (ioc_compat_fm_pcd_net_env_params_t *) compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_net_env_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_net_env(compat_param, param, COMPAT_US_TO_K); ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_net_env_params_t *) arg, ++ sizeof(ioc_fm_pcd_net_env_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ param->id = FM_PCD_NetEnvCharacteristicsSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdNetEnvParams*)param); ++ ++ if (!param->id) ++ { ++ XX_Free(param); ++ err = E_INVALID_VALUE; ++ /* Since the LLD has no errno-style error reporting, ++ we're left here with no other option than to report ++ a generic E_INVALID_VALUE */ ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_net_env_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_net_env_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_net_env_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_net_env_params_t)); ++ compat_copy_fm_pcd_net_env(compat_param, param, COMPAT_K_TO_US); ++ ++ if (copy_to_user((ioc_compat_fm_pcd_net_env_params_t *) compat_ptr(arg), ++ compat_param, ++ sizeof(ioc_compat_fm_pcd_net_env_params_t))) ++ err = E_READ_FAILED; ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_to_user((ioc_fm_pcd_net_env_params_t *)arg, ++ param, ++ sizeof(ioc_fm_pcd_net_env_params_t))) ++ err = E_READ_FAILED; ++ } ++ ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_NET_ENV_CHARACTERISTICS_DELETE_COMPAT: ++#endif ++ case FM_PCD_IOC_NET_ENV_CHARACTERISTICS_DELETE: ++ { ++ ioc_fm_obj_t id; ++ ++ memset(&id, 0 , sizeof(ioc_fm_obj_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_obj_t compat_id; ++ ++ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ compat_obj_delete(&compat_id, &id); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ err = FM_PCD_NetEnvCharacteristicsDelete(id.obj); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_KG_SCHEME_SET_COMPAT: ++#endif ++ case FM_PCD_IOC_KG_SCHEME_SET: ++ { ++ ioc_fm_pcd_kg_scheme_params_t *param; ++ ++ param = (ioc_fm_pcd_kg_scheme_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_kg_scheme_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_kg_scheme_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_kg_scheme_params_t *compat_param = NULL; ++ ++ compat_param = (ioc_compat_fm_pcd_kg_scheme_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_kg_scheme_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_params_t)); ++ ++ if (copy_from_user(compat_param, (ioc_compat_fm_pcd_kg_scheme_params_t *) compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_kg_scheme_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_kg_scheme(compat_param, param, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_kg_scheme_params_t *)arg, ++ sizeof(ioc_fm_pcd_kg_scheme_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ param->id = FM_PCD_KgSchemeSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdKgSchemeParams*)param); ++ ++ if (!param->id) ++ { ++ XX_Free(param); ++ err = E_INVALID_VALUE; ++ /* Since the LLD has no errno-style error reporting, ++ we're left here with no other option than to report ++ a generic E_INVALID_VALUE */ ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_kg_scheme_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_kg_scheme_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_kg_scheme_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_params_t)); ++ compat_copy_fm_pcd_kg_scheme(compat_param, param, COMPAT_K_TO_US); ++ if (copy_to_user((ioc_compat_fm_pcd_kg_scheme_params_t *)compat_ptr(arg), ++ compat_param, ++ sizeof(ioc_compat_fm_pcd_kg_scheme_params_t))) ++ err = E_READ_FAILED; ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_to_user((ioc_fm_pcd_kg_scheme_params_t *)arg, ++ param, ++ sizeof(ioc_fm_pcd_kg_scheme_params_t))) ++ err = E_READ_FAILED; ++ } ++ ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_KG_SCHEME_GET_CNTR_COMPAT: ++#endif ++ case FM_PCD_IOC_KG_SCHEME_GET_CNTR: ++ { ++ ioc_fm_pcd_kg_scheme_spc_t *param; ++ ++ param = (ioc_fm_pcd_kg_scheme_spc_t *) XX_Malloc(sizeof(ioc_fm_pcd_kg_scheme_spc_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_kg_scheme_spc_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_kg_scheme_spc_t *compat_param = NULL; ++ ++ compat_param = (ioc_compat_fm_pcd_kg_scheme_spc_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t)); ++ ++ if (copy_from_user(compat_param, (ioc_compat_fm_pcd_kg_scheme_spc_t *) compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_kg_scheme_spc(compat_param, param, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_kg_scheme_spc_t *)arg, ++ sizeof(ioc_fm_pcd_kg_scheme_spc_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ param->val = FM_PCD_KgSchemeGetCounter((t_Handle)param->id); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_kg_scheme_spc_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_kg_scheme_spc_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t)); ++ compat_copy_fm_pcd_kg_scheme_spc(compat_param, param, COMPAT_K_TO_US); ++ if (copy_to_user((ioc_compat_fm_pcd_kg_scheme_spc_t *)compat_ptr(arg), ++ compat_param, ++ sizeof(ioc_compat_fm_pcd_kg_scheme_spc_t))) ++ err = E_READ_FAILED; ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_to_user((ioc_fm_pcd_kg_scheme_spc_t *)arg, ++ param, ++ sizeof(ioc_fm_pcd_kg_scheme_spc_t))) ++ err = E_READ_FAILED; ++ } ++ ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_KG_SCHEME_DELETE_COMPAT: ++#endif ++ case FM_PCD_IOC_KG_SCHEME_DELETE: ++ { ++ ioc_fm_obj_t id; ++ ++ memset(&id, 0 , sizeof(ioc_fm_obj_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_obj_t compat_id; ++ ++ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ compat_obj_delete(&compat_id, &id); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ err = FM_PCD_KgSchemeDelete(id.obj); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_MATCH_TABLE_SET_COMPAT: ++#endif ++ case FM_PCD_IOC_MATCH_TABLE_SET: ++ { ++ ioc_fm_pcd_cc_node_params_t *param; ++ uint8_t *keys; ++ uint8_t *masks; ++ int i,k; ++ ++ param = (ioc_fm_pcd_cc_node_params_t *) XX_Malloc( ++ sizeof(ioc_fm_pcd_cc_node_params_t) + ++ 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_cc_node_params_t) + ++ 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); ++ ++ keys = (uint8_t *) (param + 1); ++ masks = keys + IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY; ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_cc_node_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_cc_node_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_cc_node_params_t) + ++ 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_params_t) + ++ 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); ++ ++ if (copy_from_user(compat_param, ++ (ioc_compat_fm_pcd_cc_node_params_t *)compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_cc_node_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_cc_node(compat_param, param, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_cc_node_params_t *)arg, sizeof(ioc_fm_pcd_cc_node_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ ASSERT_COND(param->keys_params.num_of_keys <= IOC_FM_PCD_MAX_NUM_OF_KEYS); ++ ASSERT_COND(param->keys_params.key_size <= IOC_FM_PCD_MAX_SIZE_OF_KEY); ++ ++ /* support for indexed lookup */ ++ if( !(param->extract_cc_params.type == e_IOC_FM_PCD_EXTRACT_NON_HDR && ++ param->extract_cc_params.extract_params.extract_non_hdr.src == e_IOC_FM_PCD_EXTRACT_FROM_HASH && ++ param->extract_cc_params.extract_params.extract_non_hdr.action == e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP)) ++ { ++ for (i=0, k=0; ++ i < param->keys_params.num_of_keys; ++ i++, k += IOC_FM_PCD_MAX_SIZE_OF_KEY) ++ { ++ if (param->keys_params.key_params[i].p_key && ++ param->keys_params.key_size) ++ { ++ if (copy_from_user(&keys[k], ++ param->keys_params.key_params[i].p_key, ++ param->keys_params.key_size)) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ param->keys_params.key_params[i].p_key = &keys[k]; ++ } ++ ++ if (param->keys_params.key_params[i].p_mask) ++ { ++ if (copy_from_user(&masks[k], ++ param->keys_params.key_params[i].p_mask, ++ param->keys_params.key_size)) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ param->keys_params.key_params[i].p_mask = &masks[k]; ++ } ++ } ++ } ++ ++ param->id = FM_PCD_MatchTableSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdCcNodeParams*)param); ++ ++ if (!param->id) { ++ XX_Free(param); ++ err = E_INVALID_VALUE; ++ /* Since the LLD has no errno-style error reporting, ++ we're left here with no other option than to report ++ a generic E_INVALID_VALUE */ ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_cc_node_params_t *compat_param; ++ compat_param = (ioc_compat_fm_pcd_cc_node_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_cc_node_params_t) + ++ 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_params_t) + ++ 2 * IOC_FM_PCD_MAX_NUM_OF_KEYS * IOC_FM_PCD_MAX_SIZE_OF_KEY); ++ compat_copy_fm_pcd_cc_node(compat_param, param, COMPAT_K_TO_US); ++ ++ if (copy_to_user((ioc_compat_fm_pcd_cc_node_params_t *)compat_ptr(arg), ++ compat_param, ++ sizeof(ioc_compat_fm_pcd_cc_node_params_t))) ++ err = E_READ_FAILED; ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_to_user((ioc_fm_pcd_cc_node_params_t *)arg, ++ param, ++ sizeof(ioc_fm_pcd_cc_node_params_t))) ++ err = E_READ_FAILED; ++ } ++ ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_MATCH_TABLE_DELETE_COMPAT: ++#endif ++ case FM_PCD_IOC_MATCH_TABLE_DELETE: ++ { ++ ioc_fm_obj_t id; ++ ++ memset(&id, 0 , sizeof(ioc_fm_obj_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_obj_t compat_id; ++ ++ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ compat_obj_delete(&compat_id, &id); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ err = FM_PCD_MatchTableDelete(id.obj); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_CC_ROOT_BUILD_COMPAT: ++#endif ++ case FM_PCD_IOC_CC_ROOT_BUILD: ++ { ++ ioc_fm_pcd_cc_tree_params_t *param; ++ ++ param = (ioc_fm_pcd_cc_tree_params_t *) XX_Malloc(sizeof(ioc_fm_pcd_cc_tree_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_cc_tree_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_cc_tree_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_cc_tree_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_cc_tree_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tree_params_t)); ++ if (copy_from_user(compat_param, ++ (ioc_compat_fm_pcd_cc_tree_params_t *)compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_cc_tree_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_cc_tree(compat_param, param, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_cc_tree_params_t *)arg, ++ sizeof(ioc_fm_pcd_cc_tree_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ param->id = FM_PCD_CcRootBuild(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdCcTreeParams*)param); ++ ++ if (!param->id) { ++ XX_Free(param); ++ err = E_INVALID_VALUE; ++ /* Since the LLD has no errno-style error reporting, ++ we're left here with no other option than to report ++ a generic E_INVALID_VALUE */ ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_cc_tree_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_cc_tree_params_t *) XX_Malloc(sizeof(ioc_compat_fm_pcd_cc_tree_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tree_params_t)); ++ ++ compat_copy_fm_pcd_cc_tree(compat_param, param, COMPAT_K_TO_US); ++ ++ if (copy_to_user((ioc_compat_fm_pcd_cc_tree_params_t *)compat_ptr(arg), ++ compat_param, ++ sizeof(ioc_compat_fm_pcd_cc_tree_params_t))) ++ err = E_READ_FAILED; ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_to_user((ioc_fm_pcd_cc_tree_params_t *)arg, ++ param, ++ sizeof(ioc_fm_pcd_cc_tree_params_t))) ++ err = E_READ_FAILED; ++ } ++ ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_CC_ROOT_DELETE_COMPAT: ++#endif ++ case FM_PCD_IOC_CC_ROOT_DELETE: ++ { ++ ioc_fm_obj_t id; ++ ++ memset(&id, 0 , sizeof(ioc_fm_obj_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_obj_t compat_id; ++ ++ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ compat_obj_delete(&compat_id, &id); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ err = FM_PCD_CcRootDelete(id.obj); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_PLCR_PROFILE_SET_COMPAT: ++#endif ++ case FM_PCD_IOC_PLCR_PROFILE_SET: ++ { ++ ioc_fm_pcd_plcr_profile_params_t *param; ++ ++ param = (ioc_fm_pcd_plcr_profile_params_t *) XX_Malloc( ++ sizeof(ioc_fm_pcd_plcr_profile_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_plcr_profile_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_plcr_profile_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_plcr_profile_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_plcr_profile_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_plcr_profile_params_t)); ++ if (copy_from_user(compat_param, ( ++ ioc_compat_fm_pcd_plcr_profile_params_t *)compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_plcr_profile_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_plcr_profile(compat_param, param, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_plcr_profile_params_t *)arg, ++ sizeof(ioc_fm_pcd_plcr_profile_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ if (!param->modify && ++ (((t_FmPcdPlcrProfileParams*)param)->id.newParams.profileType != e_FM_PCD_PLCR_SHARED)) ++ { ++ t_Handle h_Port; ++ ioc_fm_pcd_port_params_t *port_params; ++ ++ port_params = (ioc_fm_pcd_port_params_t*) XX_Malloc(sizeof(ioc_fm_pcd_port_params_t)); ++ if (!port_params) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(port_params, 0, sizeof(ioc_fm_pcd_port_params_t)); ++ if (copy_from_user(port_params, (ioc_fm_pcd_port_params_t*)((t_FmPcdPlcrProfileParams*)param)->id.newParams.h_FmPort, ++ sizeof(ioc_fm_pcd_port_params_t))) ++ { ++ XX_Free(port_params); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ switch(port_params->port_type) ++ { ++ case (e_IOC_FM_PORT_TYPE_RX): ++ if (port_params->port_id < FM_MAX_NUM_OF_1G_RX_PORTS) { ++ h_Port = p_LnxWrpFmDev->rxPorts[port_params->port_id].h_Dev; ++ break; ++ } ++ goto invalid_port_id; ++ ++ case (e_IOC_FM_PORT_TYPE_RX_10G): ++ if (port_params->port_id < FM_MAX_NUM_OF_10G_RX_PORTS) { ++#ifndef CONFIG_FMAN_ARM ++ if (IS_T1023_T1024) { ++ h_Port = p_LnxWrpFmDev->rxPorts[port_params->port_id].h_Dev; ++ } else { ++#else ++ { ++#endif ++ h_Port = p_LnxWrpFmDev->rxPorts[port_params->port_id + FM_MAX_NUM_OF_1G_RX_PORTS].h_Dev; ++ } ++ break; ++ } ++ goto invalid_port_id; ++ ++ case (e_IOC_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ if (port_params->port_id && port_params->port_id < FM_MAX_NUM_OF_OH_PORTS) { ++ h_Port = p_LnxWrpFmDev->opPorts[port_params->port_id - 1].h_Dev; ++ break; ++ } ++ goto invalid_port_id; ++ ++ default: ++invalid_port_id: ++ XX_Free(port_params); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_INVALID_SELECTION, NO_MSG); ++ } ++ ++ ((t_FmPcdPlcrProfileParams*)param)->id.newParams.h_FmPort = h_Port; ++ XX_Free(port_params); ++ } ++ ++ param->id = FM_PCD_PlcrProfileSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdPlcrProfileParams*)param); ++ ++ if (!param->id) { ++ XX_Free(param); ++ err = E_INVALID_VALUE; ++ /* Since the LLD has no errno-style error reporting, ++ we're left here with no other option than to report ++ a generic E_INVALID_VALUE */ ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_plcr_profile_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_plcr_profile_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_plcr_profile_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_plcr_profile_params_t)); ++ compat_copy_fm_pcd_plcr_profile(compat_param, param, COMPAT_K_TO_US); ++ if (copy_to_user((ioc_compat_fm_pcd_plcr_profile_params_t *) compat_ptr(arg), ++ compat_param, ++ sizeof(ioc_compat_fm_pcd_plcr_profile_params_t))) ++ err = E_READ_FAILED; ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_to_user((ioc_fm_pcd_plcr_profile_params_t *)arg, ++ param, ++ sizeof(ioc_fm_pcd_plcr_profile_params_t))) ++ err = E_READ_FAILED; ++ } ++ ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_PLCR_PROFILE_DELETE_COMPAT: ++#endif ++ case FM_PCD_IOC_PLCR_PROFILE_DELETE: ++ { ++ ioc_fm_obj_t id; ++ ++ memset(&id, 0 , sizeof(ioc_fm_obj_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_obj_t compat_id; ++ ++ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ compat_obj_delete(&compat_id, &id); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ err = FM_PCD_PlcrProfileDelete(id.obj); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_CC_ROOT_MODIFY_NEXT_ENGINE_COMPAT: ++#endif ++ case FM_PCD_IOC_CC_ROOT_MODIFY_NEXT_ENGINE: ++ { ++ ioc_fm_pcd_cc_tree_modify_next_engine_params_t *param; ++ ++ param = (ioc_fm_pcd_cc_tree_modify_next_engine_params_t *) XX_Malloc( ++ sizeof(ioc_fm_pcd_cc_tree_modify_next_engine_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_cc_tree_modify_next_engine_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t)); ++ if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *) compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_fm_pcd_cc_tree_modify_next_engine(compat_param, param, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_cc_tree_modify_next_engine_params_t *)arg, ++ sizeof(ioc_fm_pcd_cc_tree_modify_next_engine_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ err = FM_PCD_CcRootModifyNextEngine(param->id, ++ param->grp_indx, ++ param->indx, ++ (t_FmPcdCcNextEngineParams*)(¶m->cc_next_engine_params)); ++ ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_MATCH_TABLE_MODIFY_NEXT_ENGINE_COMPAT: ++#endif ++ case FM_PCD_IOC_MATCH_TABLE_MODIFY_NEXT_ENGINE: ++ { ++ ioc_fm_pcd_cc_node_modify_next_engine_params_t *param; ++ ++ param = (ioc_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc( ++ sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t)); ++ if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_cc_node_modify_next_engine(compat_param, param, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_next_engine_params_t *)arg, ++ sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ err = FM_PCD_MatchTableModifyNextEngine(param->id, ++ param->key_indx, ++ (t_FmPcdCcNextEngineParams*)(¶m->cc_next_engine_params)); ++ ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_MATCH_TABLE_MODIFY_MISS_NEXT_ENGINE_COMPAT: ++#endif ++ case FM_PCD_IOC_MATCH_TABLE_MODIFY_MISS_NEXT_ENGINE: ++ { ++ ioc_fm_pcd_cc_node_modify_next_engine_params_t *param; ++ ++ param = (ioc_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc( ++ sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t)); ++ if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *) compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_cc_node_modify_next_engine(compat_param, param, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_next_engine_params_t *) arg, ++ sizeof(ioc_fm_pcd_cc_node_modify_next_engine_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ err = FM_PCD_MatchTableModifyMissNextEngine(param->id, ++ (t_FmPcdCcNextEngineParams*)(¶m->cc_next_engine_params)); ++ ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_MATCH_TABLE_REMOVE_KEY_COMPAT: ++#endif ++ case FM_PCD_IOC_MATCH_TABLE_REMOVE_KEY: ++ { ++ ioc_fm_pcd_cc_node_remove_key_params_t *param; ++ ++ param = (ioc_fm_pcd_cc_node_remove_key_params_t *) XX_Malloc( ++ sizeof(ioc_fm_pcd_cc_node_remove_key_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_cc_node_remove_key_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_cc_node_remove_key_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_cc_node_remove_key_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_cc_node_remove_key_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_remove_key_params_t)); ++ if (copy_from_user(compat_param, ++ (ioc_compat_fm_pcd_cc_node_remove_key_params_t *)compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_cc_node_remove_key_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ param->id = compat_ptr(compat_param->id); ++ param->key_indx = compat_param->key_indx; ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_cc_node_remove_key_params_t *) arg, ++ sizeof(ioc_fm_pcd_cc_node_remove_key_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ err = FM_PCD_MatchTableRemoveKey(param->id, param->key_indx); ++ ++ XX_Free(param); ++ break; ++ } ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_MATCH_TABLE_ADD_KEY_COMPAT: ++#endif ++ case FM_PCD_IOC_MATCH_TABLE_ADD_KEY: ++ { ++ ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param; ++ ++ param = (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc( ++ sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); ++ if (copy_from_user(compat_param, ++ (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_cc_node_modify_key_and_next_engine(compat_param, param, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)arg, ++ sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ if (param->key_size) ++ { ++ int size = 0; ++ ++ if (param->key_params.p_key) size += param->key_size; ++ if (param->key_params.p_mask) size += param->key_size; ++ ++ if (size) ++ { ++ uint8_t *p_tmp; ++ ++ p_tmp = (uint8_t*) XX_Malloc(size); ++ if (!p_tmp) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD key/mask")); ++ } ++ ++ if (param->key_params.p_key) ++ { ++ if (copy_from_user(p_tmp, param->key_params.p_key, param->key_size)) ++ { ++ XX_Free(p_tmp); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ param->key_params.p_key = p_tmp; ++ } ++ ++ if (param->key_params.p_mask) ++ { ++ p_tmp += param->key_size; ++ if (copy_from_user(p_tmp, param->key_params.p_mask, param->key_size)) ++ { ++ XX_Free(p_tmp - param->key_size); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ param->key_params.p_mask = p_tmp; ++ } ++ } ++ } ++ ++ err = FM_PCD_MatchTableAddKey( ++ param->id, ++ param->key_indx, ++ param->key_size, ++ (t_FmPcdCcKeyParams*)¶m->key_params); ++ ++ if (param->key_params.p_key) ++ XX_Free(param->key_params.p_key); ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_AND_NEXT_ENGINE_COMPAT: ++#endif ++ case FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_AND_NEXT_ENGINE: ++ { ++ ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param; ++ ++ param = (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc( ++ sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t)); ++ if (copy_from_user(compat_param, ++ (ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_cc_node_modify_key_and_next_engine(compat_param, param, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *)arg, ++ sizeof(ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ err = FM_PCD_MatchTableModifyKeyAndNextEngine(param->id, ++ param->key_indx, ++ param->key_size, ++ (t_FmPcdCcKeyParams*)(¶m->key_params)); ++ ++ XX_Free(param); ++ break; ++ } ++ ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_MATCH_TABLE_GET_KEY_STAT_COMPAT: ++#endif ++ case FM_PCD_IOC_MATCH_TABLE_GET_KEY_STAT: ++ { ++ ioc_fm_pcd_cc_tbl_get_stats_t param; ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)); ++ if (!compat_param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)); ++ if (copy_from_user(compat_param, ++ (ioc_compat_fm_pcd_cc_tbl_get_stats_t *)compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t))) ++ { ++ XX_Free(compat_param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, ¶m, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(¶m, (ioc_fm_pcd_cc_tbl_get_stats_t *)arg, ++ sizeof(ioc_fm_pcd_cc_tbl_get_stats_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ ++ err = FM_PCD_MatchTableGetKeyStatistics((t_Handle) param.id, ++ param.key_index, ++ (t_FmPcdCcKeyStatistics *) ¶m.statistics); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t*) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)); ++ if (!compat_param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)); ++ compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, ¶m, COMPAT_K_TO_US); ++ if (copy_to_user((ioc_compat_fm_pcd_cc_tbl_get_stats_t*) compat_ptr(arg), ++ compat_param, ++ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t))){ ++ XX_Free(compat_param); ++ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG); ++ } ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_to_user((ioc_fm_pcd_cc_tbl_get_stats_t *)arg, ++ ¶m, ++ sizeof(ioc_fm_pcd_cc_tbl_get_stats_t))) ++ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG); ++ } ++ ++ break; ++ } ++ ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_MATCH_TABLE_GET_MISS_STAT_COMPAT: ++#endif ++ case FM_PCD_IOC_MATCH_TABLE_GET_MISS_STAT: ++ { ++ ioc_fm_pcd_cc_tbl_get_stats_t param; ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)); ++ if (!compat_param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)); ++ if (copy_from_user(compat_param, ++ (ioc_compat_fm_pcd_cc_tbl_get_stats_t *)compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t))) ++ { ++ XX_Free(compat_param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, ¶m, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(¶m, (ioc_fm_pcd_cc_tbl_get_stats_t *)arg, ++ sizeof(ioc_fm_pcd_cc_tbl_get_stats_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ ++ err = FM_PCD_MatchTableGetMissStatistics((t_Handle) param.id, ++ (t_FmPcdCcKeyStatistics *) ¶m.statistics); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t*) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)); ++ if (!compat_param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)); ++ compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, ¶m, COMPAT_K_TO_US); ++ if (copy_to_user((ioc_compat_fm_pcd_cc_tbl_get_stats_t*) compat_ptr(arg), ++ compat_param, ++ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t))){ ++ XX_Free(compat_param); ++ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG); ++ } ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_to_user((ioc_fm_pcd_cc_tbl_get_stats_t *)arg, ++ ¶m, ++ sizeof(ioc_fm_pcd_cc_tbl_get_stats_t))) ++ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG); ++ } ++ ++ break; ++ } ++ ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_HASH_TABLE_GET_MISS_STAT_COMPAT: ++#endif ++ case FM_PCD_IOC_HASH_TABLE_GET_MISS_STAT: ++ { ++ ioc_fm_pcd_cc_tbl_get_stats_t param; ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)); ++ if (!compat_param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)); ++ if (copy_from_user(compat_param, ++ (ioc_compat_fm_pcd_cc_tbl_get_stats_t *)compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t))) ++ { ++ XX_Free(compat_param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, ¶m, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(¶m, (ioc_fm_pcd_cc_tbl_get_stats_t *)arg, ++ sizeof(ioc_fm_pcd_cc_tbl_get_stats_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ ++ err = FM_PCD_HashTableGetMissStatistics((t_Handle) param.id, ++ (t_FmPcdCcKeyStatistics *) ¶m.statistics); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_cc_tbl_get_stats_t*) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)); ++ if (!compat_param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t)); ++ compat_copy_fm_pcd_cc_tbl_get_stats(compat_param, ¶m, COMPAT_K_TO_US); ++ if (copy_to_user((ioc_compat_fm_pcd_cc_tbl_get_stats_t*) compat_ptr(arg), ++ compat_param, ++ sizeof(ioc_compat_fm_pcd_cc_tbl_get_stats_t))){ ++ XX_Free(compat_param); ++ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG); ++ } ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_to_user((ioc_fm_pcd_cc_tbl_get_stats_t *)arg, ++ ¶m, ++ sizeof(ioc_fm_pcd_cc_tbl_get_stats_t))) ++ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG); ++ } ++ ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_HASH_TABLE_SET_COMPAT: ++#endif ++ case FM_PCD_IOC_HASH_TABLE_SET: ++ { ++ ioc_fm_pcd_hash_table_params_t *param; ++ ++ param = (ioc_fm_pcd_hash_table_params_t*) XX_Malloc( ++ sizeof(ioc_fm_pcd_hash_table_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_hash_table_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_hash_table_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_hash_table_params_t*) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_hash_table_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_hash_table_params_t)); ++ if (copy_from_user(compat_param, ++ (ioc_compat_fm_pcd_hash_table_params_t*)compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_hash_table_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_hash_table(compat_param, param, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_hash_table_params_t *)arg, ++ sizeof(ioc_fm_pcd_hash_table_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ param->id = FM_PCD_HashTableSet(p_LnxWrpFmDev->h_PcdDev, (t_FmPcdHashTableParams *) param); ++ ++ if (!param->id) ++ { ++ XX_Free(param); ++ err = E_INVALID_VALUE; ++ /* Since the LLD has no errno-style error reporting, ++ we're left here with no other option than to report ++ a generic E_INVALID_VALUE */ ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_hash_table_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_hash_table_params_t*) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_hash_table_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_hash_table_params_t)); ++ compat_copy_fm_pcd_hash_table(compat_param, param, COMPAT_K_TO_US); ++ if (copy_to_user((ioc_compat_fm_pcd_hash_table_params_t*) compat_ptr(arg), ++ compat_param, ++ sizeof(ioc_compat_fm_pcd_hash_table_params_t))) ++ err = E_READ_FAILED; ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_to_user((ioc_fm_pcd_hash_table_params_t *)arg, ++ param, ++ sizeof(ioc_fm_pcd_hash_table_params_t))) ++ err = E_READ_FAILED; ++ } ++ ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_HASH_TABLE_DELETE_COMPAT: ++#endif ++ case FM_PCD_IOC_HASH_TABLE_DELETE: ++ { ++ ioc_fm_obj_t id; ++ ++ memset(&id, 0, sizeof(ioc_fm_obj_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_obj_t compat_id; ++ ++ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ id.obj = compat_pcd_id2ptr(compat_id.obj); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ err = FM_PCD_HashTableDelete(id.obj); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_HASH_TABLE_ADD_KEY_COMPAT: ++#endif ++ case FM_PCD_IOC_HASH_TABLE_ADD_KEY: ++ { ++ ioc_fm_pcd_hash_table_add_key_params_t *param = NULL; ++ ++ param = (ioc_fm_pcd_hash_table_add_key_params_t*) XX_Malloc( ++ sizeof(ioc_fm_pcd_hash_table_add_key_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_hash_table_add_key_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_hash_table_add_key_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_hash_table_add_key_params_t*) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_hash_table_add_key_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_hash_table_add_key_params_t)); ++ if (copy_from_user(compat_param, ++ (ioc_compat_fm_pcd_hash_table_add_key_params_t*) compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_hash_table_add_key_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ if (compat_param->key_size) ++ { ++ param->p_hash_tbl = compat_pcd_id2ptr(compat_param->p_hash_tbl); ++ param->key_size = compat_param->key_size; ++ ++ compat_copy_fm_pcd_cc_key(&compat_param->key_params, ¶m->key_params, COMPAT_US_TO_K); ++ } ++ else ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ err = E_INVALID_VALUE; ++ break; ++ } ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_hash_table_add_key_params_t*) arg, ++ sizeof(ioc_fm_pcd_hash_table_add_key_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ if (param->key_size) ++ { ++ int size = 0; ++ ++ if (param->key_params.p_key) size += param->key_size; ++ if (param->key_params.p_mask) size += param->key_size; ++ ++ if (size) ++ { ++ uint8_t *p_tmp; ++ ++ p_tmp = (uint8_t*) XX_Malloc(size); ++ if (!p_tmp) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD key/mask")); ++ } ++ ++ if (param->key_params.p_key) ++ { ++ if (copy_from_user(p_tmp, param->key_params.p_key, param->key_size)) ++ { ++ XX_Free(p_tmp); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ param->key_params.p_key = p_tmp; ++ } ++ ++ if (param->key_params.p_mask) ++ { ++ p_tmp += param->key_size; ++ if (copy_from_user(p_tmp, param->key_params.p_mask, param->key_size)) ++ { ++ XX_Free(p_tmp - param->key_size); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ param->key_params.p_mask = p_tmp; ++ } ++ } ++ } ++ ++ err = FM_PCD_HashTableAddKey( ++ param->p_hash_tbl, ++ param->key_size, ++ (t_FmPcdCcKeyParams*)¶m->key_params); ++ ++ if (param->key_params.p_key) ++ XX_Free(param->key_params.p_key); ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_HASH_TABLE_REMOVE_KEY_COMPAT: ++#endif ++ case FM_PCD_IOC_HASH_TABLE_REMOVE_KEY: ++ { ++ ioc_fm_pcd_hash_table_remove_key_params_t *param = NULL; ++ ++ param = (ioc_fm_pcd_hash_table_remove_key_params_t*) XX_Malloc( ++ sizeof(ioc_fm_pcd_hash_table_remove_key_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_hash_table_remove_key_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_hash_table_remove_key_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_hash_table_remove_key_params_t*) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_hash_table_remove_key_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_hash_table_remove_key_params_t)); ++ if (copy_from_user(compat_param, ++ (ioc_compat_fm_pcd_hash_table_remove_key_params_t*) compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_hash_table_remove_key_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ param->p_hash_tbl = compat_pcd_id2ptr(compat_param->p_hash_tbl); ++ param->key_size = compat_param->key_size; ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_hash_table_remove_key_params_t*)arg, ++ sizeof(ioc_fm_pcd_hash_table_remove_key_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ if (param->key_size) ++ { ++ uint8_t *p_key; ++ ++ p_key = (uint8_t*) XX_Malloc(param->key_size); ++ if (!p_key) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ if (param->p_key && copy_from_user(p_key, param->p_key, param->key_size)) ++ { ++ XX_Free(p_key); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ param->p_key = p_key; ++ } ++ ++ err = FM_PCD_HashTableRemoveKey( ++ param->p_hash_tbl, ++ param->key_size, ++ param->p_key); ++ ++ if (param->p_key) ++ XX_Free(param->p_key); ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_COMPAT: ++#endif ++ case FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY: ++ { ++ ioc_fm_pcd_cc_node_modify_key_params_t *param; ++ ++ param = (ioc_fm_pcd_cc_node_modify_key_params_t *) XX_Malloc( ++ sizeof(ioc_fm_pcd_cc_node_modify_key_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_cc_node_modify_key_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_cc_node_modify_key_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_cc_node_modify_key_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_cc_node_modify_key_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_cc_node_modify_key_params_t)); ++ if (copy_from_user(compat_param, (ioc_compat_fm_pcd_cc_node_modify_key_params_t *)compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_cc_node_modify_key_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_cc_node_modify_key(compat_param, param, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_cc_node_modify_key_params_t *)arg, ++ sizeof(ioc_fm_pcd_cc_node_modify_key_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ if (param->key_size) ++ { ++ int size = 0; ++ ++ if (param->p_key) size += param->key_size; ++ if (param->p_mask) size += param->key_size; ++ ++ if (size) ++ { ++ uint8_t *p_tmp; ++ ++ p_tmp = (uint8_t*) XX_Malloc(size); ++ if (!p_tmp) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD key/mask")); ++ } ++ ++ if (param->p_key) ++ { ++ if (copy_from_user(p_tmp, param->p_key, param->key_size)) ++ { ++ XX_Free(p_tmp); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ param->p_key = p_tmp; ++ } ++ ++ if (param->p_mask) ++ { ++ p_tmp += param->key_size; ++ if (copy_from_user(p_tmp, param->p_mask, param->key_size)) ++ { ++ XX_Free(p_tmp - param->key_size); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ param->p_mask = p_tmp; ++ } ++ } ++ } ++ ++ err = FM_PCD_MatchTableModifyKey(param->id, ++ param->key_indx, ++ param->key_size, ++ param->p_key, ++ param->p_mask); ++ ++ if (param->p_key) ++ XX_Free(param->p_key); ++ else if (param->p_mask) ++ XX_Free(param->p_mask); ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_MANIP_NODE_SET_COMPAT: ++#endif ++ case FM_PCD_IOC_MANIP_NODE_SET: ++ { ++ ioc_fm_pcd_manip_params_t *param; ++ uint8_t *p_data = NULL; ++ uint8_t size; ++ ++ param = (ioc_fm_pcd_manip_params_t *) XX_Malloc( ++ sizeof(ioc_fm_pcd_manip_params_t)); ++ ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_manip_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_manip_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_manip_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_manip_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_manip_params_t)); ++ if (copy_from_user(compat_param, ++ (ioc_compat_fm_pcd_manip_params_t *) compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_manip_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_fm_pcd_manip_set_node(compat_param, param, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_manip_params_t *)arg, ++ sizeof(ioc_fm_pcd_manip_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ if (param->type == e_IOC_FM_PCD_MANIP_HDR) ++ { ++ size = param->u.hdr.insrt_params.u.generic.size; ++ p_data = (uint8_t *) XX_Malloc(size); ++ if (!p_data ) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, NO_MSG); ++ } ++ ++ if (param->u.hdr.insrt_params.u.generic.p_data && ++ copy_from_user(p_data, ++ param->u.hdr.insrt_params.u.generic.p_data, size)) ++ { ++ XX_Free(p_data); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ param->u.hdr.insrt_params.u.generic.p_data = p_data; ++ } ++ ++ if (param->id) ++ { ++ /* Security Hole: the user can pass any piece of garbage ++ in 'param->id', and that will go straight through to the LLD, ++ no checks being done by the wrapper! */ ++ err = FM_PCD_ManipNodeReplace( ++ (t_Handle) param->id, ++ (t_FmPcdManipParams*) param); ++ if (err) ++ { ++ if (p_data) ++ XX_Free(p_data); ++ XX_Free(param); ++ break; ++ } ++ } ++ else ++ { ++ param->id = FM_PCD_ManipNodeSet( ++ p_LnxWrpFmDev->h_PcdDev, ++ (t_FmPcdManipParams*) param); ++ if (!param->id) ++ { ++ if (p_data) ++ XX_Free(p_data); ++ XX_Free(param); ++ err = E_INVALID_VALUE; ++ /* Since the LLD has no errno-style error reporting, ++ we're left here with no other option than to report ++ a generic E_INVALID_VALUE */ ++ break; ++ } ++ } ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_manip_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_manip_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_manip_params_t)); ++ if (!compat_param) ++ { ++ if (p_data) ++ XX_Free(p_data); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_manip_params_t)); ++ ++ compat_fm_pcd_manip_set_node(compat_param, param, COMPAT_K_TO_US); ++ ++ if (copy_to_user((ioc_compat_fm_pcd_manip_params_t *) compat_ptr(arg), ++ compat_param, ++ sizeof(ioc_compat_fm_pcd_manip_params_t))) ++ err = E_READ_FAILED; ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_to_user((ioc_fm_pcd_manip_params_t *)arg, ++ param, sizeof(ioc_fm_pcd_manip_params_t))) ++ err = E_READ_FAILED; ++ } ++ ++ if (p_data) ++ XX_Free(p_data); ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_MANIP_NODE_DELETE_COMPAT: ++#endif ++ case FM_PCD_IOC_MANIP_NODE_DELETE: ++ { ++ ioc_fm_obj_t id; ++ ++ memset(&id, 0, sizeof(ioc_fm_obj_t)); ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_obj_t compat_id; ++ ++ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ compat_obj_delete(&compat_id, &id); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ err = FM_PCD_ManipNodeDelete(id.obj); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_MANIP_GET_STATS_COMPAT: ++#endif ++ case FM_PCD_IOC_MANIP_GET_STATS: ++ { ++ ioc_fm_pcd_manip_get_stats_t param; ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_manip_get_stats_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_manip_get_stats_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_manip_get_stats_t)); ++ if (!compat_param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_manip_get_stats_t)); ++ if (copy_from_user(compat_param, ++ (ioc_compat_fm_pcd_manip_get_stats_t *)compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_manip_get_stats_t))) ++ { ++ XX_Free(compat_param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_manip_get_stats(compat_param, ¶m, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(¶m, (ioc_fm_pcd_manip_get_stats_t *)arg, ++ sizeof(ioc_fm_pcd_manip_get_stats_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ err = FM_PCD_ManipGetStatistics((t_Handle) param.id, ++ (t_FmPcdManipStats*) ¶m.stats); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_manip_get_stats_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_manip_get_stats_t*) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_manip_get_stats_t)); ++ if (!compat_param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_manip_get_stats_t)); ++ compat_copy_fm_pcd_manip_get_stats(compat_param, ¶m, COMPAT_K_TO_US); ++ if (copy_to_user((ioc_compat_fm_pcd_manip_get_stats_t*) compat_ptr(arg), ++ compat_param, ++ sizeof(ioc_compat_fm_pcd_manip_get_stats_t))){ ++ XX_Free(compat_param); ++ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG); ++ } ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ if (copy_to_user((ioc_fm_pcd_manip_get_stats_t *)arg, ++ ¶m, ++ sizeof(ioc_fm_pcd_manip_get_stats_t))) ++ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG); ++ ++ break; ++ } ++ ++#if (DPAA_VERSION >= 11) ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_FRM_REPLIC_GROUP_SET_COMPAT: ++#endif ++ case FM_PCD_IOC_FRM_REPLIC_GROUP_SET: ++ { ++ ioc_fm_pcd_frm_replic_group_params_t *param; ++ ++ param = (ioc_fm_pcd_frm_replic_group_params_t *) XX_Malloc( ++ sizeof(ioc_fm_pcd_frm_replic_group_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_frm_replic_group_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_frm_replic_group_params_t ++ *compat_param; ++ ++ compat_param = ++ (ioc_compat_fm_pcd_frm_replic_group_params_t *) ++ XX_Malloc(sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ++ ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t)); ++ if (copy_from_user(compat_param, ++ (ioc_compat_fm_pcd_frm_replic_group_params_t *) ++ compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t))) { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_frm_replic_group_params(compat_param, ++ param, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, ++ (ioc_fm_pcd_frm_replic_group_params_t *)arg, ++ sizeof(ioc_fm_pcd_frm_replic_group_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG); ++ } ++ } ++ ++ param->id = FM_PCD_FrmReplicSetGroup(p_LnxWrpFmDev->h_PcdDev, ++ (t_FmPcdFrmReplicGroupParams*)param); ++ ++ if (!param->id) { ++ XX_Free(param); ++ err = E_INVALID_VALUE; ++ /* ++ * Since the LLD has no errno-style error reporting, ++ * we're left here with no other option than to report ++ * a generic E_INVALID_VALUE ++ */ ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_frm_replic_group_params_t ++ *compat_param; ++ ++ compat_param = ++ (ioc_compat_fm_pcd_frm_replic_group_params_t *) ++ XX_Malloc(sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ++ ("IOCTL FM PCD")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t)); ++ compat_copy_fm_pcd_frm_replic_group_params(compat_param, ++ param, COMPAT_K_TO_US); ++ if (copy_to_user( ++ (ioc_compat_fm_pcd_frm_replic_group_params_t *) ++ compat_ptr(arg), ++ compat_param, ++ sizeof(ioc_compat_fm_pcd_frm_replic_group_params_t))) ++ err = E_WRITE_FAILED; ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_to_user( ++ (ioc_fm_pcd_frm_replic_group_params_t *)arg, ++ param, ++ sizeof(ioc_fm_pcd_frm_replic_group_params_t))) ++ err = E_WRITE_FAILED; ++ } ++ ++ XX_Free(param); ++ break; ++ } ++ break; ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_FRM_REPLIC_GROUP_DELETE_COMPAT: ++#endif ++ case FM_PCD_IOC_FRM_REPLIC_GROUP_DELETE: ++ { ++ ioc_fm_obj_t id; ++ ++ memset(&id, 0, sizeof(ioc_fm_obj_t)); ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_obj_t compat_id; ++ ++ if (copy_from_user(&compat_id, ++ (ioc_compat_fm_obj_t *) compat_ptr(arg), ++ sizeof(ioc_compat_fm_obj_t))) ++ break; ++ compat_obj_delete(&compat_id, &id); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, ++ sizeof(ioc_fm_obj_t))) ++ break; ++ } ++ ++ return FM_PCD_FrmReplicDeleteGroup(id.obj); ++ } ++ break; ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_FRM_REPLIC_MEMBER_ADD_COMPAT: ++#endif ++ case FM_PCD_IOC_FRM_REPLIC_MEMBER_ADD: ++ { ++ ioc_fm_pcd_frm_replic_member_params_t param; ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_frm_replic_member_params_t compat_param; ++ ++ if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ compat_copy_fm_pcd_frm_replic_member_params(&compat_param, ¶m, COMPAT_US_TO_K); ++ } ++ else ++#endif ++ if (copy_from_user(¶m, (void *)arg, sizeof(param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ return FM_PCD_FrmReplicAddMember(param.member.h_replic_group, ++ param.member.member_index, ++ (t_FmPcdCcNextEngineParams*)¶m.next_engine_params); ++ } ++ break; ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_FRM_REPLIC_MEMBER_REMOVE_COMPAT: ++#endif ++ case FM_PCD_IOC_FRM_REPLIC_MEMBER_REMOVE: ++ { ++ ioc_fm_pcd_frm_replic_member_t param; ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_frm_replic_member_t compat_param; ++ ++ if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ compat_copy_fm_pcd_frm_replic_member(&compat_param, ¶m, COMPAT_US_TO_K); ++ } ++ else ++#endif ++ if (copy_from_user(¶m, (void *)arg, sizeof(param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ return FM_PCD_FrmReplicRemoveMember(param.h_replic_group, param.member_index); ++ } ++ break; ++ ++#if defined(CONFIG_COMPAT) ++ case FM_IOC_VSP_CONFIG_COMPAT: ++#endif ++ case FM_IOC_VSP_CONFIG: ++ { ++ ioc_fm_vsp_params_t param; ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_vsp_params_t compat_param; ++ ++ if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ compat_copy_fm_vsp_params(&compat_param, ¶m, COMPAT_US_TO_K); ++ } ++ else ++#endif ++ if (copy_from_user(¶m, (void *)arg, sizeof(param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ { ++ uint8_t portId = param.port_params.port_id; ++ param.liodn_offset = ++ p_LnxWrpFmDev->rxPorts[portId].settings.param.specificParams.rxParams.liodnOffset; ++ } ++ param.p_fm = p_LnxWrpFmDev->h_Dev; ++ param.id = FM_VSP_Config((t_FmVspParams *)¶m); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_vsp_params_t compat_param; ++ ++ memset(&compat_param, 0, sizeof(compat_param)); ++ compat_copy_fm_vsp_params(&compat_param, ¶m, COMPAT_K_TO_US); ++ ++ if (copy_to_user(compat_ptr(arg), &compat_param, sizeof(compat_param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ else ++#endif ++ if (copy_to_user((void *)arg, ¶m, sizeof(param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_IOC_VSP_INIT_COMPAT: ++#endif ++ case FM_IOC_VSP_INIT: ++ { ++ ioc_fm_obj_t id; ++ ++ memset(&id, 0, sizeof(ioc_fm_obj_t)); ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_obj_t compat_id; ++ ++ if (copy_from_user(&compat_id, ++ (ioc_compat_fm_obj_t *) compat_ptr(arg), ++ sizeof(ioc_compat_fm_obj_t))) ++ break; ++ id.obj = compat_pcd_id2ptr(compat_id.obj); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, ++ sizeof(ioc_fm_obj_t))) ++ break; ++ } ++ ++ return FM_VSP_Init(id.obj); ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_IOC_VSP_FREE_COMPAT: ++#endif ++ case FM_IOC_VSP_FREE: ++ { ++ ioc_fm_obj_t id; ++ ++ memset(&id, 0, sizeof(ioc_fm_obj_t)); ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_obj_t compat_id; ++ ++ if (copy_from_user(&compat_id, ++ (ioc_compat_fm_obj_t *) compat_ptr(arg), ++ sizeof(ioc_compat_fm_obj_t))) ++ break; ++ compat_obj_delete(&compat_id, &id); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, ++ sizeof(ioc_fm_obj_t))) ++ break; ++ } ++ ++ return FM_VSP_Free(id.obj); ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_IOC_VSP_CONFIG_POOL_DEPLETION_COMPAT: ++#endif ++ case FM_IOC_VSP_CONFIG_POOL_DEPLETION: ++ { ++ ioc_fm_buf_pool_depletion_params_t param; ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_buf_pool_depletion_params_t compat_param; ++ ++ if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ compat_copy_fm_buf_pool_depletion_params(&compat_param, ¶m, COMPAT_US_TO_K); ++ } ++ else ++#endif ++ if (copy_from_user(¶m, (void *)arg, sizeof(param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ if (FM_VSP_ConfigPoolDepletion(param.p_fm_vsp, ++ (t_FmBufPoolDepletion *)¶m.fm_buf_pool_depletion)) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ break; ++ } ++ ++ ++#if defined(CONFIG_COMPAT) ++ case FM_IOC_VSP_CONFIG_BUFFER_PREFIX_CONTENT_COMPAT: ++#endif ++ case FM_IOC_VSP_CONFIG_BUFFER_PREFIX_CONTENT: ++ { ++ ioc_fm_buffer_prefix_content_params_t param; ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_buffer_prefix_content_params_t compat_param; ++ ++ if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ compat_copy_fm_buffer_prefix_content_params(&compat_param, ¶m, COMPAT_US_TO_K); ++ } ++ else ++#endif ++ if (copy_from_user(¶m, (void *)arg, sizeof(param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ if (FM_VSP_ConfigBufferPrefixContent(param.p_fm_vsp, ++ (t_FmBufferPrefixContent *)¶m.fm_buffer_prefix_content)) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_IOC_VSP_CONFIG_NO_SG_COMPAT: ++#endif ++ case FM_IOC_VSP_CONFIG_NO_SG: ++ { ++ ioc_fm_vsp_config_no_sg_params_t param; ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_vsp_config_no_sg_params_t compat_param; ++ ++ if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ compat_copy_fm_vsp_config_no_sg_params(&compat_param, ¶m, COMPAT_US_TO_K); ++ } ++ else ++#endif ++ if (copy_from_user(¶m, (void *)arg, sizeof(param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ if (FM_VSP_ConfigNoScatherGather(param.p_fm_vsp, param.no_sg)) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_IOC_VSP_GET_BUFFER_PRS_RESULT_COMPAT: ++#endif ++ case FM_IOC_VSP_GET_BUFFER_PRS_RESULT: ++ { ++ ioc_fm_vsp_prs_result_params_t param; ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_vsp_prs_result_params_t compat_param; ++ ++ if (copy_from_user(&compat_param, compat_ptr(arg), sizeof(compat_param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ compat_copy_fm_vsp_prs_result_params(&compat_param, ¶m, COMPAT_US_TO_K); ++ } ++ else ++#endif ++ if (copy_from_user(¶m, (void *)arg, sizeof(param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ /* this call just adds the parse results offset to p_data */ ++ param.p_data = FM_VSP_GetBufferPrsResult(param.p_fm_vsp, param.p_data); ++ ++ if (!param.p_data) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_vsp_prs_result_params_t compat_param; ++ ++ memset(&compat_param, 0, sizeof(compat_param)); ++ compat_copy_fm_vsp_prs_result_params(&compat_param, ¶m, COMPAT_K_TO_US); ++ ++ if (copy_to_user(compat_ptr(arg), &compat_param, sizeof(compat_param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ else ++#endif ++ if (copy_to_user((void *)arg, ¶m, sizeof(param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ break; ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ ++#ifdef FM_CAPWAP_SUPPORT ++#warning "feature not supported!" ++#if defined(CONFIG_COMPAT) ++ case FM_PCD_IOC_STATISTICS_SET_NODE_COMPAT: ++#endif ++ case FM_PCD_IOC_STATISTICS_SET_NODE: ++ { ++/* ioc_fm_pcd_stats_params_t param; ++ ... ++ param->id = FM_PCD_StatisticsSetNode(p_LnxWrpFmDev->h_PcdDev, ++ (t_FmPcdStatsParams *)¶m); ++*/ ++ err = E_NOT_SUPPORTED; ++ break; ++ } ++#endif /* FM_CAPWAP_SUPPORT */ ++ ++ default: ++ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ++ ("invalid ioctl: cmd:0x%08x(type:0x%02x, nr: %d.\n", ++ cmd, _IOC_TYPE(cmd), _IOC_NR(cmd))); ++ } ++ ++ if (err) ++ RETURN_ERROR(MINOR, err, ("IOCTL FM PCD")); ++ ++ return E_OK; ++} ++ ++void FM_Get_Api_Version(ioc_fm_api_version_t *p_version) ++{ ++ p_version->version.major = FMD_API_VERSION_MAJOR; ++ p_version->version.minor = FMD_API_VERSION_MINOR; ++ p_version->version.respin = FMD_API_VERSION_RESPIN; ++ p_version->version.reserved = 0; ++} ++ ++t_Error LnxwrpFmIOCTL(t_LnxWrpFmDev *p_LnxWrpFmDev, unsigned int cmd, unsigned long arg, bool compat) ++{ ++ t_Error err = E_OK; ++ ++ switch (cmd) ++ { ++ case FM_IOC_SET_PORTS_BANDWIDTH: ++ { ++ ioc_fm_port_bandwidth_params *param; ++ ++ param = (ioc_fm_port_bandwidth_params*) XX_Malloc(sizeof(ioc_fm_port_bandwidth_params)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_port_bandwidth_params)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (copy_from_user(param, (ioc_fm_port_bandwidth_params*)compat_ptr(arg), sizeof(ioc_fm_port_bandwidth_params))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_port_bandwidth_params*)arg, sizeof(ioc_fm_port_bandwidth_params))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ err = FM_SetPortsBandwidth(p_LnxWrpFmDev->h_Dev, (t_FmPortsBandwidthParams*) param); ++ ++ XX_Free(param); ++ break; ++ } ++ ++ case FM_IOC_GET_REVISION: ++ { ++ ioc_fm_revision_info_t *param; ++ ++ param = (ioc_fm_revision_info_t *) XX_Malloc(sizeof(ioc_fm_revision_info_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ FM_GetRevision(p_LnxWrpFmDev->h_Dev, (t_FmRevisionInfo*)param); ++ /* This one never returns anything other than E_OK */ ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (copy_to_user((ioc_fm_revision_info_t *)compat_ptr(arg), ++ param, ++ sizeof(ioc_fm_revision_info_t))){ ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG); ++ } ++ } ++ else ++#endif ++ { ++ if (copy_to_user((ioc_fm_revision_info_t *)arg, ++ param, ++ sizeof(ioc_fm_revision_info_t))){ ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_READ_FAILED, NO_MSG); ++ } ++ } ++ XX_Free(param); ++ break; ++ } ++ ++ case FM_IOC_SET_COUNTER: ++ { ++ ioc_fm_counters_params_t *param; ++ ++ param = (ioc_fm_counters_params_t *) XX_Malloc(sizeof(ioc_fm_counters_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_counters_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (copy_from_user(param, (ioc_fm_counters_params_t *)compat_ptr(arg), sizeof(ioc_fm_counters_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_counters_params_t *)arg, sizeof(ioc_fm_counters_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ err = FM_ModifyCounter(p_LnxWrpFmDev->h_Dev, param->cnt, param->val); ++ ++ XX_Free(param); ++ break; ++ } ++ ++ case FM_IOC_GET_COUNTER: ++ { ++ ioc_fm_counters_params_t *param; ++ ++ param = (ioc_fm_counters_params_t *) XX_Malloc(sizeof(ioc_fm_counters_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PCD")); ++ ++ memset(param, 0, sizeof(ioc_fm_counters_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (copy_from_user(param, (ioc_fm_counters_params_t *)compat_ptr(arg), sizeof(ioc_fm_counters_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_counters_params_t *)arg, sizeof(ioc_fm_counters_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ param->val = FM_GetCounter(p_LnxWrpFmDev->h_Dev, param->cnt); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (copy_to_user((ioc_fm_counters_params_t *)compat_ptr(arg), param, sizeof(ioc_fm_counters_params_t))) ++ err = E_READ_FAILED; ++ } ++ else ++#endif ++ { ++ if (copy_to_user((ioc_fm_counters_params_t *)arg, param, sizeof(ioc_fm_counters_params_t))) ++ err = E_READ_FAILED; ++ } ++ ++ XX_Free(param); ++ break; ++ } ++ ++ case FM_IOC_FORCE_INTR: ++ { ++ ioc_fm_exceptions param; ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (get_user(param, (ioc_fm_exceptions*) compat_ptr(arg))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ else ++#endif ++ { ++ if (get_user(param, (ioc_fm_exceptions*)arg)) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ err = FM_ForceIntr(p_LnxWrpFmDev->h_Dev, (e_FmExceptions)param); ++ break; ++ } ++ ++ case FM_IOC_GET_API_VERSION: ++ { ++ ioc_fm_api_version_t version; ++ ++ FM_Get_Api_Version(&version); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (copy_to_user( ++ (ioc_fm_api_version_t *)compat_ptr(arg), ++ &version, sizeof(version))) ++ err = E_READ_FAILED; ++ } ++ else ++#endif ++ { ++ if (copy_to_user((ioc_fm_api_version_t *)arg, ++ &version, sizeof(version))) ++ err = E_READ_FAILED; ++ } ++ } ++ break; ++ ++ case FM_IOC_CTRL_MON_START: ++ { ++ FM_CtrlMonStart(p_LnxWrpFmDev->h_Dev); ++ } ++ break; ++ ++ case FM_IOC_CTRL_MON_STOP: ++ { ++ FM_CtrlMonStop(p_LnxWrpFmDev->h_Dev); ++ } ++ break; ++ ++#if defined(CONFIG_COMPAT) ++ case FM_IOC_CTRL_MON_GET_COUNTERS_COMPAT: ++#endif ++ case FM_IOC_CTRL_MON_GET_COUNTERS: ++ { ++ ioc_fm_ctrl_mon_counters_params_t param; ++ t_FmCtrlMon mon; ++ ++#if defined(CONFIG_COMPAT) ++ ioc_compat_fm_ctrl_mon_counters_params_t compat_param; ++ ++ if (compat) ++ { ++ if (copy_from_user(&compat_param, (void *)compat_ptr(arg), ++ sizeof(compat_param))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ param.fm_ctrl_index = compat_param.fm_ctrl_index; ++ param.p_mon = (fm_ctrl_mon_t *)compat_ptr(compat_param.p_mon); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(¶m, (void *)arg, sizeof(ioc_fm_ctrl_mon_counters_params_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ if (FM_CtrlMonGetCounters(p_LnxWrpFmDev->h_Dev, param.fm_ctrl_index, &mon)) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ if (copy_to_user(param.p_mon, &mon, sizeof(t_FmCtrlMon))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ break; ++ ++ default: ++ return LnxwrpFmPcdIOCTL(p_LnxWrpFmDev, cmd, arg, compat); ++ } ++ ++ if (err) ++ RETURN_ERROR(MINOR, E_INVALID_OPERATION, ("IOCTL FM")); ++ ++ return E_OK; ++} ++ ++t_Error LnxwrpFmPortIOCTL(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev, unsigned int cmd, unsigned long arg, bool compat) ++{ ++ t_Error err = E_OK; ++ ++ _fm_ioctl_dbg("cmd:0x%08x(type:0x%02x, nr:%u).\n", ++ cmd, _IOC_TYPE(cmd), _IOC_NR(cmd) - 70); ++ ++ switch (cmd) ++ { ++ case FM_PORT_IOC_DISABLE: ++ FM_PORT_Disable(p_LnxWrpFmPortDev->h_Dev); ++ /* deliberately ignoring error codes here */ ++ return E_OK; ++ ++ case FM_PORT_IOC_ENABLE: ++ FM_PORT_Enable(p_LnxWrpFmPortDev->h_Dev); ++ /* deliberately ignoring error codes here */ ++ return E_OK; ++ ++ case FM_PORT_IOC_SET_ERRORS_ROUTE: ++ { ++ ioc_fm_port_frame_err_select_t errs; ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (get_user(errs, (ioc_fm_port_frame_err_select_t*)compat_ptr(arg))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ else ++#endif ++ { ++ if (get_user(errs, (ioc_fm_port_frame_err_select_t*)arg)) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ err = FM_PORT_SetErrorsRoute(p_LnxWrpFmPortDev->h_Dev, (fmPortFrameErrSelect_t)errs); ++ break; ++ } ++ ++ case FM_PORT_IOC_SET_RATE_LIMIT: ++ { ++ ioc_fm_port_rate_limit_t *param; ++ ++ param = (ioc_fm_port_rate_limit_t *) XX_Malloc(sizeof(ioc_fm_port_rate_limit_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); ++ ++ memset(param, 0, sizeof(ioc_fm_port_rate_limit_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (copy_from_user(param, (ioc_fm_port_rate_limit_t *)compat_ptr(arg), sizeof(ioc_fm_port_rate_limit_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_port_rate_limit_t *)arg, sizeof(ioc_fm_port_rate_limit_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ err = FM_PORT_SetRateLimit(p_LnxWrpFmPortDev->h_Dev, (t_FmPortRateLimit *)param); ++ ++ XX_Free(param); ++ break; ++ } ++ ++ case FM_PORT_IOC_REMOVE_RATE_LIMIT: ++ FM_PORT_DeleteRateLimit(p_LnxWrpFmPortDev->h_Dev); ++ /* deliberately ignoring error codes here */ ++ return E_OK; ++ ++ case FM_PORT_IOC_ALLOC_PCD_FQIDS: ++ { ++ ioc_fm_port_pcd_fqids_params_t *param; ++ ++ if (!p_LnxWrpFmPortDev->pcd_owner_params.cba) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("No one to listen on this PCD!!!")); ++ ++ param = (ioc_fm_port_pcd_fqids_params_t *) XX_Malloc(sizeof(ioc_fm_port_pcd_fqids_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); ++ ++ memset(param, 0, sizeof(ioc_fm_port_pcd_fqids_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (copy_from_user(param, (ioc_fm_port_pcd_fqids_params_t *)compat_ptr(arg), ++ sizeof(ioc_fm_port_pcd_fqids_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_port_pcd_fqids_params_t *)arg, ++ sizeof(ioc_fm_port_pcd_fqids_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ if (p_LnxWrpFmPortDev->pcd_owner_params.cba(p_LnxWrpFmPortDev->pcd_owner_params.dev, ++ param->num_fqids, ++ param->alignment, ++ ¶m->base_fqid)) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("can't allocate fqids for PCD!!!")); ++ } ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (copy_to_user((ioc_fm_port_pcd_fqids_params_t *)compat_ptr(arg), ++ param, sizeof(ioc_fm_port_pcd_fqids_params_t))) ++ err = E_READ_FAILED; ++ } ++ else ++#endif ++ { ++ if (copy_to_user((ioc_fm_port_pcd_fqids_params_t *)arg, ++ param, sizeof(ioc_fm_port_pcd_fqids_params_t))) ++ err = E_READ_FAILED; ++ } ++ ++ XX_Free(param); ++ break; ++ } ++ ++ case FM_PORT_IOC_FREE_PCD_FQIDS: ++ { ++ uint32_t base_fqid; ++ ++ if (!p_LnxWrpFmPortDev->pcd_owner_params.cbf) ++ RETURN_ERROR(MINOR, E_INVALID_STATE, ("No one to listen on this PCD!!!")); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (get_user(base_fqid, (uint32_t*) compat_ptr(arg))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ else ++#endif ++ { ++ if (get_user(base_fqid, (uint32_t*)arg)) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ if (p_LnxWrpFmPortDev->pcd_owner_params.cbf(p_LnxWrpFmPortDev->pcd_owner_params.dev, base_fqid)) ++ err = E_WRITE_FAILED; ++ ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PORT_IOC_SET_PCD_COMPAT: ++#endif ++ case FM_PORT_IOC_SET_PCD: ++ { ++ ioc_fm_port_pcd_params_t *port_pcd_params; ++ ioc_fm_port_pcd_prs_params_t *port_pcd_prs_params; ++ ioc_fm_port_pcd_cc_params_t *port_pcd_cc_params; ++ ioc_fm_port_pcd_kg_params_t *port_pcd_kg_params; ++ ioc_fm_port_pcd_plcr_params_t *port_pcd_plcr_params; ++ ++ port_pcd_params = (ioc_fm_port_pcd_params_t *) XX_Malloc( ++ sizeof(ioc_fm_port_pcd_params_t) + ++ sizeof(ioc_fm_port_pcd_prs_params_t) + ++ sizeof(ioc_fm_port_pcd_cc_params_t) + ++ sizeof(ioc_fm_port_pcd_kg_params_t) + ++ sizeof(ioc_fm_port_pcd_plcr_params_t)); ++ if (!port_pcd_params) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); ++ ++ memset(port_pcd_params, 0, ++ sizeof(ioc_fm_port_pcd_params_t) + ++ sizeof(ioc_fm_port_pcd_prs_params_t) + ++ sizeof(ioc_fm_port_pcd_cc_params_t) + ++ sizeof(ioc_fm_port_pcd_kg_params_t) + ++ sizeof(ioc_fm_port_pcd_plcr_params_t)); ++ ++ port_pcd_prs_params = (ioc_fm_port_pcd_prs_params_t *) (port_pcd_params + 1); ++ port_pcd_cc_params = (ioc_fm_port_pcd_cc_params_t *) (port_pcd_prs_params + 1); ++ port_pcd_kg_params = (ioc_fm_port_pcd_kg_params_t *) (port_pcd_cc_params + 1); ++ port_pcd_plcr_params = (ioc_fm_port_pcd_plcr_params_t *) (port_pcd_kg_params + 1); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_port_pcd_params_t *compat_port_pcd_params; ++ ioc_fm_port_pcd_prs_params_t *same_port_pcd_prs_params; ++ ioc_compat_fm_port_pcd_cc_params_t *compat_port_pcd_cc_params; ++ ioc_compat_fm_port_pcd_kg_params_t *compat_port_pcd_kg_params; ++ ioc_compat_fm_port_pcd_plcr_params_t *compat_port_pcd_plcr_params; ++ ++ compat_port_pcd_params = (ioc_compat_fm_port_pcd_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_port_pcd_params_t) + ++ sizeof(ioc_fm_port_pcd_prs_params_t) + ++ sizeof(ioc_compat_fm_port_pcd_cc_params_t) + ++ sizeof(ioc_compat_fm_port_pcd_kg_params_t) + ++ sizeof(ioc_compat_fm_port_pcd_plcr_params_t)); ++ if (!compat_port_pcd_params) ++ { ++ XX_Free(port_pcd_params); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); ++ } ++ ++ memset(compat_port_pcd_params, 0, ++ sizeof(ioc_compat_fm_port_pcd_params_t) + ++ sizeof(ioc_fm_port_pcd_prs_params_t) + ++ sizeof(ioc_compat_fm_port_pcd_cc_params_t) + ++ sizeof(ioc_compat_fm_port_pcd_kg_params_t) + ++ sizeof(ioc_compat_fm_port_pcd_plcr_params_t)); ++ same_port_pcd_prs_params = (ioc_fm_port_pcd_prs_params_t *) (compat_port_pcd_params + 1); ++ compat_port_pcd_cc_params = (ioc_compat_fm_port_pcd_cc_params_t *) (same_port_pcd_prs_params + 1); ++ compat_port_pcd_kg_params = (ioc_compat_fm_port_pcd_kg_params_t *) (compat_port_pcd_cc_params + 1); ++ compat_port_pcd_plcr_params = (ioc_compat_fm_port_pcd_plcr_params_t *) (compat_port_pcd_kg_params + 1); ++ ++ if (copy_from_user(compat_port_pcd_params, ++ (ioc_compat_fm_port_pcd_params_t*) compat_ptr(arg), ++ sizeof(ioc_compat_fm_port_pcd_params_t))) ++ err = E_WRITE_FAILED; ++ ++ while (!err) /* pseudo-while */ ++ { ++ /* set pointers from where to copy from: */ ++ port_pcd_params->p_prs_params = compat_ptr(compat_port_pcd_params->p_prs_params); /* same structure */ ++ port_pcd_params->p_cc_params = compat_ptr(compat_port_pcd_params->p_cc_params); ++ port_pcd_params->p_kg_params = compat_ptr(compat_port_pcd_params->p_kg_params); ++ port_pcd_params->p_plcr_params = compat_ptr(compat_port_pcd_params->p_plcr_params); ++ port_pcd_params->p_ip_reassembly_manip = compat_ptr(compat_port_pcd_params->p_ip_reassembly_manip); ++#if (DPAA_VERSION >= 11) ++ port_pcd_params->p_capwap_reassembly_manip = compat_ptr(compat_port_pcd_params->p_capwap_reassembly_manip); ++#endif ++ /* the prs member is the same, no compat structure...memcpy only */ ++ if (port_pcd_params->p_prs_params) ++ { ++ if (copy_from_user(same_port_pcd_prs_params, ++ port_pcd_params->p_prs_params, ++ sizeof(ioc_fm_port_pcd_prs_params_t))) ++ { ++ err = E_WRITE_FAILED; ++ break; /* from pseudo-while */ ++ } ++ ++ memcpy(port_pcd_prs_params, same_port_pcd_prs_params, sizeof(ioc_fm_port_pcd_prs_params_t)); ++ port_pcd_params->p_prs_params = port_pcd_prs_params; ++ } ++ ++ if (port_pcd_params->p_cc_params) ++ { ++ if (copy_from_user(compat_port_pcd_cc_params, ++ port_pcd_params->p_cc_params, ++ sizeof(ioc_compat_fm_port_pcd_cc_params_t))) ++ { ++ err = E_WRITE_FAILED; ++ break; /* from pseudo-while */ ++ } ++ ++ port_pcd_params->p_cc_params = port_pcd_cc_params; ++ } ++ ++ if (port_pcd_params->p_kg_params) ++ { ++ if (copy_from_user(compat_port_pcd_kg_params, ++ port_pcd_params->p_kg_params, ++ sizeof(ioc_compat_fm_port_pcd_kg_params_t))) ++ { ++ err = E_WRITE_FAILED; ++ break; /* from pseudo-while */ ++ } ++ ++ port_pcd_params->p_kg_params = port_pcd_kg_params; ++ } ++ ++ if (port_pcd_params->p_plcr_params) ++ { ++ if (copy_from_user(compat_port_pcd_plcr_params, ++ port_pcd_params->p_plcr_params, ++ sizeof(ioc_compat_fm_port_pcd_plcr_params_t))) ++ { ++ err = E_WRITE_FAILED; ++ break; /* from pseudo-while */ ++ } ++ ++ port_pcd_params->p_plcr_params = port_pcd_plcr_params; ++ } ++ ++ break; /* pseudo-while: always run once! */ ++ } ++ ++ if (!err) ++ compat_copy_fm_port_pcd(compat_port_pcd_params, port_pcd_params, COMPAT_US_TO_K); ++ ++ XX_Free(compat_port_pcd_params); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(port_pcd_params, ++ (ioc_fm_port_pcd_params_t*) arg, ++ sizeof(ioc_fm_port_pcd_params_t))) ++ err = E_WRITE_FAILED; ++ ++ while (!err) /* pseudo-while */ ++ { ++ if (port_pcd_params->p_prs_params) ++ { ++ if (copy_from_user(port_pcd_prs_params, ++ port_pcd_params->p_prs_params, ++ sizeof(ioc_fm_port_pcd_prs_params_t))) ++ { ++ err = E_WRITE_FAILED; ++ break; /* from pseudo-while */ ++ } ++ ++ port_pcd_params->p_prs_params = port_pcd_prs_params; ++ } ++ ++ if (port_pcd_params->p_cc_params) ++ { ++ if (copy_from_user(port_pcd_cc_params, ++ port_pcd_params->p_cc_params, ++ sizeof(ioc_fm_port_pcd_cc_params_t))) ++ { ++ err = E_WRITE_FAILED; ++ break; /* from pseudo-while */ ++ } ++ ++ port_pcd_params->p_cc_params = port_pcd_cc_params; ++ } ++ ++ if (port_pcd_params->p_kg_params) ++ { ++ if (copy_from_user(port_pcd_kg_params, ++ port_pcd_params->p_kg_params, ++ sizeof(ioc_fm_port_pcd_kg_params_t))) ++ { ++ err = E_WRITE_FAILED; ++ break; /* from pseudo-while */ ++ } ++ ++ port_pcd_params->p_kg_params = port_pcd_kg_params; ++ } ++ ++ if (port_pcd_params->p_plcr_params) ++ { ++ if (copy_from_user(port_pcd_plcr_params, ++ port_pcd_params->p_plcr_params, ++ sizeof(ioc_fm_port_pcd_plcr_params_t))) ++ { ++ err = E_WRITE_FAILED; ++ break; /* from pseudo-while */ ++ } ++ ++ port_pcd_params->p_plcr_params = port_pcd_plcr_params; ++ } ++ ++ break; /* pseudo-while: always run once! */ ++ } ++ } ++ ++ if (!err) ++ err = FM_PORT_SetPCD(p_LnxWrpFmPortDev->h_Dev, (t_FmPortPcdParams*) port_pcd_params); ++ ++ XX_Free(port_pcd_params); ++ break; ++ } ++ ++ case FM_PORT_IOC_DELETE_PCD: ++ err = FM_PORT_DeletePCD(p_LnxWrpFmPortDev->h_Dev); ++ break; ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PORT_IOC_PCD_KG_MODIFY_INITIAL_SCHEME_COMPAT: ++#endif ++ case FM_PORT_IOC_PCD_KG_MODIFY_INITIAL_SCHEME: ++ { ++ ioc_fm_pcd_kg_scheme_select_t *param; ++ ++ param = (ioc_fm_pcd_kg_scheme_select_t *) XX_Malloc( ++ sizeof(ioc_fm_pcd_kg_scheme_select_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); ++ ++ memset(param, 0, sizeof(ioc_fm_pcd_kg_scheme_select_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_kg_scheme_select_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_pcd_kg_scheme_select_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_pcd_kg_scheme_select_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_pcd_kg_scheme_select_t)); ++ if (copy_from_user(compat_param, ++ (ioc_compat_fm_pcd_kg_scheme_select_t *) compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_kg_scheme_select_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_kg_scheme_select(compat_param, param, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_kg_scheme_select_t *)arg, ++ sizeof(ioc_fm_pcd_kg_scheme_select_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ err = FM_PORT_PcdKgModifyInitialScheme(p_LnxWrpFmPortDev->h_Dev, (t_FmPcdKgSchemeSelect *)param); ++ ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PORT_IOC_PCD_PLCR_MODIFY_INITIAL_PROFILE_COMPAT: ++#endif ++ case FM_PORT_IOC_PCD_PLCR_MODIFY_INITIAL_PROFILE: ++ { ++ ioc_fm_obj_t id; ++ ++ memset(&id, 0 , sizeof(ioc_fm_obj_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_obj_t compat_id; ++ ++ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ id.obj = compat_ptr(compat_id.obj); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ err = FM_PORT_PcdPlcrModifyInitialProfile(p_LnxWrpFmPortDev->h_Dev, id.obj); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PORT_IOC_PCD_KG_BIND_SCHEMES_COMPAT: ++#endif ++ case FM_PORT_IOC_PCD_KG_BIND_SCHEMES: ++ { ++ ioc_fm_pcd_port_schemes_params_t *param; ++ ++ param = (ioc_fm_pcd_port_schemes_params_t *) XX_Malloc( ++ sizeof(ioc_fm_pcd_port_schemes_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); ++ ++ memset(param, 0 , sizeof(ioc_fm_pcd_port_schemes_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_port_schemes_params_t compat_param; ++ ++ if (copy_from_user(&compat_param, ++ (ioc_compat_fm_pcd_port_schemes_params_t *) compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_port_schemes_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_kg_schemes_params(&compat_param, param, COMPAT_US_TO_K); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_port_schemes_params_t *) arg, ++ sizeof(ioc_fm_pcd_port_schemes_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ err = FM_PORT_PcdKgBindSchemes(p_LnxWrpFmPortDev->h_Dev, (t_FmPcdPortSchemesParams *)param); ++ ++ XX_Free(param); ++ break; ++ } ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PORT_IOC_PCD_KG_UNBIND_SCHEMES_COMPAT: ++#endif ++ case FM_PORT_IOC_PCD_KG_UNBIND_SCHEMES: ++ { ++ ioc_fm_pcd_port_schemes_params_t *param; ++ ++ param = (ioc_fm_pcd_port_schemes_params_t *) XX_Malloc( ++ sizeof(ioc_fm_pcd_port_schemes_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); ++ ++ memset(param, 0 , sizeof(ioc_fm_pcd_port_schemes_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_pcd_port_schemes_params_t compat_param; ++ ++ if (copy_from_user(&compat_param, ++ (ioc_compat_fm_pcd_port_schemes_params_t *) compat_ptr(arg), ++ sizeof(ioc_compat_fm_pcd_port_schemes_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_pcd_kg_schemes_params(&compat_param, param, COMPAT_US_TO_K); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_pcd_port_schemes_params_t *) arg, ++ sizeof(ioc_fm_pcd_port_schemes_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ err = FM_PORT_PcdKgUnbindSchemes(p_LnxWrpFmPortDev->h_Dev, (t_FmPcdPortSchemesParams *)param); ++ ++ XX_Free(param); ++ break; ++ } ++ ++ case FM_PORT_IOC_PCD_PLCR_ALLOC_PROFILES: ++ { ++ uint16_t num; ++ if (get_user(num, (uint16_t*) arg)) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ err = FM_PORT_PcdPlcrAllocProfiles(p_LnxWrpFmPortDev->h_Dev, num); ++ break; ++ } ++ ++ case FM_PORT_IOC_PCD_PLCR_FREE_PROFILES: ++ err = FM_PORT_PcdPlcrFreeProfiles(p_LnxWrpFmPortDev->h_Dev); ++ break; ++ ++ case FM_PORT_IOC_DETACH_PCD: ++ err = FM_PORT_DetachPCD(p_LnxWrpFmPortDev->h_Dev); ++ break; ++ ++ case FM_PORT_IOC_ATTACH_PCD: ++ err = FM_PORT_AttachPCD(p_LnxWrpFmPortDev->h_Dev); ++ break; ++ ++#if defined(CONFIG_COMPAT) ++ case FM_PORT_IOC_PCD_CC_MODIFY_TREE_COMPAT: ++#endif ++ case FM_PORT_IOC_PCD_CC_MODIFY_TREE: ++ { ++ ioc_fm_obj_t id; ++ ++ memset(&id, 0 , sizeof(ioc_fm_obj_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_obj_t compat_id; ++ ++ if (copy_from_user(&compat_id, (ioc_compat_fm_obj_t *) compat_ptr(arg), sizeof(ioc_compat_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ compat_copy_fm_port_pcd_modify_tree(&compat_id, &id, COMPAT_US_TO_K); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(&id, (ioc_fm_obj_t *) arg, sizeof(ioc_fm_obj_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ err = FM_PORT_PcdCcModifyTree(p_LnxWrpFmPortDev->h_Dev, id.obj); ++ break; ++ } ++ ++ case FM_PORT_IOC_ADD_CONGESTION_GRPS: ++ case FM_PORT_IOC_REMOVE_CONGESTION_GRPS: ++ { ++ ioc_fm_port_congestion_groups_t *param; ++ ++ param = (ioc_fm_port_congestion_groups_t*) XX_Malloc(sizeof(ioc_fm_port_congestion_groups_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); ++ ++ memset(param, 0, sizeof(ioc_fm_port_congestion_groups_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (copy_from_user(param, (t_FmPortCongestionGrps*) compat_ptr(arg), ++ sizeof(t_FmPortCongestionGrps))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ else ++#endif /* CONFIG_COMPAT */ ++ { ++ if (copy_from_user(param, (t_FmPortCongestionGrps*) arg, ++ sizeof(t_FmPortCongestionGrps))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ err = (cmd == FM_PORT_IOC_ADD_CONGESTION_GRPS) ++ ? FM_PORT_AddCongestionGrps(p_LnxWrpFmPortDev->h_Dev, (t_FmPortCongestionGrps*) param) ++ : FM_PORT_RemoveCongestionGrps(p_LnxWrpFmPortDev->h_Dev, (t_FmPortCongestionGrps*) param) ++ ; ++ ++ XX_Free(param); ++ break; ++ } ++ ++ case FM_PORT_IOC_ADD_RX_HASH_MAC_ADDR: ++ case FM_PORT_IOC_REMOVE_RX_HASH_MAC_ADDR: ++ { ++ ioc_fm_port_mac_addr_params_t *param; ++ ++ param = (ioc_fm_port_mac_addr_params_t*) XX_Malloc( ++ sizeof(ioc_fm_port_mac_addr_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); ++ ++ memset(param, 0, sizeof(ioc_fm_port_mac_addr_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ if (copy_from_user(param, (ioc_fm_port_mac_addr_params_t*) compat_ptr(arg), ++ sizeof(ioc_fm_port_mac_addr_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ else ++#endif /* CONFIG_COMPAT */ ++ { ++ if (copy_from_user(param, (ioc_fm_port_mac_addr_params_t*) arg, ++ sizeof(ioc_fm_port_mac_addr_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ if (p_LnxWrpFmPortDev->pcd_owner_params.dev) ++ { ++ int id = -1; ++ ++ switch(p_LnxWrpFmPortDev->settings.param.portType) ++ { ++ case e_FM_PORT_TYPE_RX: ++ case e_FM_PORT_TYPE_TX: ++ id = p_LnxWrpFmPortDev->id; ++ break; ++ case e_FM_PORT_TYPE_RX_10G: ++ case e_FM_PORT_TYPE_TX_10G: ++ id = p_LnxWrpFmPortDev->id + FM_MAX_NUM_OF_1G_MACS; ++ break; ++ default: ++ err = E_NOT_AVAILABLE; ++ REPORT_ERROR(MINOR, err, ("Attempt to add/remove hash MAC addr. to/from MAC-less port!")); ++ } ++ if (id >= 0) ++ { ++ t_LnxWrpFmDev *fm = (t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev; ++ t_Handle mac_handle = fm->macs[id].h_Dev; ++ ++ err = (cmd == FM_PORT_IOC_ADD_RX_HASH_MAC_ADDR) ++ ? FM_MAC_AddHashMacAddr(mac_handle, (t_EnetAddr*) param) ++ : FM_MAC_RemoveHashMacAddr(mac_handle, (t_EnetAddr*) param); ++ } ++ } ++ else ++ { ++ err = E_NOT_AVAILABLE; ++ REPORT_ERROR(MINOR, err, ("Port not initialized or other error!?!?")); ++ } ++ ++ XX_Free(param); ++ break; ++ } ++ ++ case FM_PORT_IOC_SET_TX_PAUSE_FRAMES: ++ { ++ t_LnxWrpFmDev *p_LnxWrpFmDev = ++ (t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev; ++ ioc_fm_port_tx_pause_frames_params_t param; ++ int mac_id = p_LnxWrpFmPortDev->id; ++ ++ if(&p_LnxWrpFmDev->txPorts[mac_id] != p_LnxWrpFmPortDev) ++ mac_id += FM_MAX_NUM_OF_1G_MACS; /* 10G port */ ++ ++ if (copy_from_user(¶m, (ioc_fm_port_tx_pause_frames_params_t *)arg, ++ sizeof(ioc_fm_port_tx_pause_frames_params_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ if (p_LnxWrpFmDev && p_LnxWrpFmDev->macs[mac_id].h_Dev) ++ { ++ FM_MAC_SetTxPauseFrames(p_LnxWrpFmDev->macs[mac_id].h_Dev, ++ param.priority, ++ param.pause_time, ++ param.thresh_time); ++ } ++ else ++ { ++ err = E_NOT_AVAILABLE; ++ REPORT_ERROR(MINOR, err, ("Port not initialized or other error!")); ++ } ++ ++ break; ++ } ++ ++ case FM_PORT_IOC_CONFIG_BUFFER_PREFIX_CONTENT: ++ { ++ ioc_fm_buffer_prefix_content_t *param; ++ ++ param = (ioc_fm_buffer_prefix_content_t*) XX_Malloc(sizeof(ioc_fm_buffer_prefix_content_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); ++ ++ memset(param, 0, sizeof(ioc_fm_buffer_prefix_content_t)); ++ ++ if (copy_from_user(param, (ioc_fm_buffer_prefix_content_t*) arg, ++ sizeof(ioc_fm_buffer_prefix_content_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ if (FM_PORT_ConfigBufferPrefixContent(p_LnxWrpFmPortDev->h_Dev, ++ (t_FmBufferPrefixContent *)param)) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ XX_Free(param); ++ break; ++ } ++ ++#if (DPAA_VERSION >= 11) ++#if defined(CONFIG_COMPAT) ++ case FM_PORT_IOC_VSP_ALLOC_COMPAT: ++#endif ++ case FM_PORT_IOC_VSP_ALLOC: ++ { ++ ioc_fm_port_vsp_alloc_params_t *param; ++ t_LnxWrpFmDev *p_LnxWrpFmDev; ++ t_LnxWrpFmPortDev *p_LnxWrpFmTxPortDev; ++ ++ param = (ioc_fm_port_vsp_alloc_params_t *) XX_Malloc( ++ sizeof(ioc_fm_port_vsp_alloc_params_t)); ++ if (!param) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); ++ ++ memset(param, 0, sizeof(ioc_fm_port_vsp_alloc_params_t)); ++ ++#if defined(CONFIG_COMPAT) ++ if (compat) ++ { ++ ioc_compat_fm_port_vsp_alloc_params_t *compat_param; ++ ++ compat_param = (ioc_compat_fm_port_vsp_alloc_params_t *) XX_Malloc( ++ sizeof(ioc_compat_fm_port_vsp_alloc_params_t)); ++ if (!compat_param) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("IOCTL FM PORT")); ++ } ++ ++ memset(compat_param, 0, sizeof(ioc_compat_fm_port_vsp_alloc_params_t)); ++ if (copy_from_user(compat_param, ++ (ioc_compat_fm_port_vsp_alloc_params_t *) compat_ptr(arg), ++ sizeof(ioc_compat_fm_port_vsp_alloc_params_t))) ++ { ++ XX_Free(compat_param); ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ compat_copy_fm_port_vsp_alloc_params(compat_param, param, COMPAT_US_TO_K); ++ ++ XX_Free(compat_param); ++ } ++ else ++#endif ++ { ++ if (copy_from_user(param, (ioc_fm_port_vsp_alloc_params_t *)arg, ++ sizeof(ioc_fm_port_vsp_alloc_params_t))) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ } ++ ++ /* Userspace may not have the Tx port t_handle when issuing the IOCTL */ ++ if (p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX || ++ p_LnxWrpFmPortDev->settings.param.portType == e_FM_PORT_TYPE_RX_10G) ++ { ++ /* Determine the Tx port t_Handle from the Rx port id */ ++ p_LnxWrpFmDev = p_LnxWrpFmPortDev->h_LnxWrpFmDev; ++ p_LnxWrpFmTxPortDev = &p_LnxWrpFmDev->txPorts[p_LnxWrpFmPortDev->id]; ++ param->p_fm_tx_port = p_LnxWrpFmTxPortDev->h_Dev; ++ } ++ ++ if (FM_PORT_VSPAlloc(p_LnxWrpFmPortDev->h_Dev, (t_FmPortVSPAllocParams *)param)) ++ { ++ XX_Free(param); ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ } ++ ++ XX_Free(param); ++ break; ++ } ++#endif /* (DPAA_VERSION >= 11) */ ++ ++ case FM_PORT_IOC_GET_MAC_STATISTICS: ++ { ++ t_LnxWrpFmDev *p_LnxWrpFmDev = ++ (t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev; ++ ioc_fm_port_mac_statistics_t param; ++ int mac_id = p_LnxWrpFmPortDev->id; ++ ++ if (!p_LnxWrpFmDev) ++ RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Port not initialized or other error!")); ++ ++ if (&p_LnxWrpFmDev->txPorts[mac_id] != p_LnxWrpFmPortDev && ++ &p_LnxWrpFmDev->rxPorts[mac_id] != p_LnxWrpFmPortDev) ++ mac_id += FM_MAX_NUM_OF_1G_MACS; /* 10G port */ ++ ++ if (!p_LnxWrpFmDev->macs[mac_id].h_Dev) ++ RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Port not initialized or other error!")); ++ ++ if (FM_MAC_GetStatistics(p_LnxWrpFmDev->macs[mac_id].h_Dev, ++ (t_FmMacStatistics *)¶m)) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ if (copy_to_user((ioc_fm_port_mac_statistics_t *)arg, ¶m, ++ sizeof(ioc_fm_port_mac_statistics_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ break; ++ } ++ ++ case FM_PORT_IOC_GET_BMI_COUNTERS: ++ { ++ t_LnxWrpFmDev *p_LnxWrpFmDev = ++ (t_LnxWrpFmDev *)p_LnxWrpFmPortDev->h_LnxWrpFmDev; ++ ioc_fm_port_bmi_stats_t param; ++ ++ if (!p_LnxWrpFmDev) ++ RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Port not initialized or other error!")); ++ ++ if (FM_PORT_GetBmiCounters(p_LnxWrpFmPortDev->h_Dev, ++ (t_FmPortBmiStats *)¶m)) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ if (copy_to_user((ioc_fm_port_bmi_stats_t *)arg, ¶m, ++ sizeof(ioc_fm_port_bmi_stats_t))) ++ RETURN_ERROR(MINOR, E_WRITE_FAILED, NO_MSG); ++ ++ break; ++ } ++ ++ default: ++ RETURN_ERROR(MINOR, E_INVALID_SELECTION, ++ ("invalid ioctl: cmd:0x%08x(type:0x%02x, nr:0x%02x.\n", ++ cmd, _IOC_TYPE(cmd), _IOC_NR(cmd))); ++ } ++ ++ if (err) ++ RETURN_ERROR(MINOR, E_INVALID_OPERATION, ("IOCTL FM PORT")); ++ ++ return E_OK; ++} ++ ++/*****************************************************************************/ ++/* API routines for the FM Linux Device */ ++/*****************************************************************************/ ++ ++static int fm_open(struct inode *inode, struct file *file) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev = NULL; ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = NULL; ++ unsigned int major = imajor(inode); ++ unsigned int minor = iminor(inode); ++ struct device_node *fm_node; ++ static struct of_device_id fm_node_of_match[] = { ++ { .compatible = "fsl,fman", }, ++ { /* end of list */ }, ++ }; ++ ++ DBG(TRACE, ("Opening minor - %d - ", minor)); ++ ++ if (file->private_data != NULL) ++ return 0; ++ ++ /* Get all the FM nodes */ ++ for_each_matching_node(fm_node, fm_node_of_match) { ++ struct platform_device *of_dev; ++ ++ of_dev = of_find_device_by_node(fm_node); ++ if (unlikely(of_dev == NULL)) { ++ REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("fm id!")); ++ return -ENXIO; ++ } ++ ++ p_LnxWrpFmDev = (t_LnxWrpFmDev *)fm_bind(&of_dev->dev); ++ if (p_LnxWrpFmDev->major == major) ++ break; ++ fm_unbind((struct fm *)p_LnxWrpFmDev); ++ p_LnxWrpFmDev = NULL; ++ } ++ ++ if (!p_LnxWrpFmDev) ++ return -ENODEV; ++ ++ if (minor == DEV_FM_MINOR_BASE) ++ file->private_data = p_LnxWrpFmDev; ++ else if (minor == DEV_FM_PCD_MINOR_BASE) ++ file->private_data = p_LnxWrpFmDev; ++ else { ++ if (minor == DEV_FM_OH_PORTS_MINOR_BASE) ++ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->hcPort; ++ else if ((minor > DEV_FM_OH_PORTS_MINOR_BASE) && (minor < DEV_FM_RX_PORTS_MINOR_BASE)) ++ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->opPorts[minor-DEV_FM_OH_PORTS_MINOR_BASE-1]; ++ else if ((minor >= DEV_FM_RX_PORTS_MINOR_BASE) && (minor < DEV_FM_TX_PORTS_MINOR_BASE)) ++ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->rxPorts[minor-DEV_FM_RX_PORTS_MINOR_BASE]; ++ else if ((minor >= DEV_FM_TX_PORTS_MINOR_BASE) && (minor < DEV_FM_MAX_MINORS)) ++ p_LnxWrpFmPortDev = &p_LnxWrpFmDev->txPorts[minor-DEV_FM_TX_PORTS_MINOR_BASE]; ++ else ++ return -EINVAL; ++ ++ /* if trying to open port, check if it initialized */ ++ if (!p_LnxWrpFmPortDev->h_Dev) ++ return -ENODEV; ++ ++ p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *)fm_port_bind(p_LnxWrpFmPortDev->dev); ++ file->private_data = p_LnxWrpFmPortDev; ++ fm_unbind((struct fm *)p_LnxWrpFmDev); ++ } ++ ++ if (file->private_data == NULL) ++ return -ENXIO; ++ ++ return 0; ++} ++ ++static int fm_close(struct inode *inode, struct file *file) ++{ ++ t_LnxWrpFmDev *p_LnxWrpFmDev; ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; ++ unsigned int minor = iminor(inode); ++ int err = 0; ++ ++ DBG(TRACE, ("Closing minor - %d - ", minor)); ++ ++ if ((minor == DEV_FM_MINOR_BASE) || ++ (minor == DEV_FM_PCD_MINOR_BASE)) ++ { ++ p_LnxWrpFmDev = (t_LnxWrpFmDev*)file->private_data; ++ if (!p_LnxWrpFmDev) ++ return -ENODEV; ++ fm_unbind((struct fm *)p_LnxWrpFmDev); ++ } ++ else if (((minor >= DEV_FM_OH_PORTS_MINOR_BASE) && (minor < DEV_FM_RX_PORTS_MINOR_BASE)) || ++ ((minor >= DEV_FM_RX_PORTS_MINOR_BASE) && (minor < DEV_FM_TX_PORTS_MINOR_BASE)) || ++ ((minor >= DEV_FM_TX_PORTS_MINOR_BASE) && (minor < DEV_FM_MAX_MINORS))) ++ { ++ p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev*)file->private_data; ++ if (!p_LnxWrpFmPortDev) ++ return -ENODEV; ++ fm_port_unbind((struct fm_port *)p_LnxWrpFmPortDev); ++ } ++ ++ return err; ++} ++ ++static int fm_ioctls(unsigned int minor, struct file *file, unsigned int cmd, unsigned long arg, bool compat) ++{ ++ DBG(TRACE, ("IOCTL minor - %u, cmd - 0x%08x, arg - 0x%08lx \n", minor, cmd, arg)); ++ ++ if ((minor == DEV_FM_MINOR_BASE) || ++ (minor == DEV_FM_PCD_MINOR_BASE)) ++ { ++ t_LnxWrpFmDev *p_LnxWrpFmDev = ((t_LnxWrpFmDev*)file->private_data); ++ if (!p_LnxWrpFmDev) ++ return -ENODEV; ++ if (LnxwrpFmIOCTL(p_LnxWrpFmDev, cmd, arg, compat)) ++ return -EFAULT; ++ } ++ else if (((minor >= DEV_FM_OH_PORTS_MINOR_BASE) && (minor < DEV_FM_RX_PORTS_MINOR_BASE)) || ++ ((minor >= DEV_FM_RX_PORTS_MINOR_BASE) && (minor < DEV_FM_TX_PORTS_MINOR_BASE)) || ++ ((minor >= DEV_FM_TX_PORTS_MINOR_BASE) && (minor < DEV_FM_MAX_MINORS))) ++ { ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = ((t_LnxWrpFmPortDev*)file->private_data); ++ if (!p_LnxWrpFmPortDev) ++ return -ENODEV; ++ if (LnxwrpFmPortIOCTL(p_LnxWrpFmPortDev, cmd, arg, compat)) ++ return -EFAULT; ++ } ++ else ++ { ++ REPORT_ERROR(MINOR, E_INVALID_VALUE, ("minor")); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_COMPAT ++static long fm_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ unsigned int minor = iminor(file->f_path.dentry->d_inode); ++ long res; ++ ++ fm_mutex_lock(); ++ res = fm_ioctls(minor, file, cmd, arg, true); ++ fm_mutex_unlock(); ++ ++ return res; ++} ++#endif ++ ++static long fm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ unsigned int minor = iminor(file->f_path.dentry->d_inode); ++ long res; ++ ++ fm_mutex_lock(); ++ res = fm_ioctls(minor, file, cmd, arg, false); ++ fm_mutex_unlock(); ++ ++ return res; ++} ++ ++/* Globals for FM character device */ ++struct file_operations fm_fops = ++{ ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = fm_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = fm_compat_ioctl, ++#endif ++ .open = fm_open, ++ .release = fm_close, ++}; +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c +new file mode 100644 +index 00000000..322ae9ef +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.c +@@ -0,0 +1,1297 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ @File lnxwrp_fm_compat_ioctls.c ++ ++ @Description FM PCD compat functions ++ ++*/ ++ ++#if !defined(CONFIG_COMPAT) ++#error "missing COMPAT layer..." ++#endif ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifndef CONFIG_FMAN_ARM ++#include ++#endif ++ ++#include "part_ext.h" ++#include "fm_ioctls.h" ++#include "fm_pcd_ioctls.h" ++#include "fm_port_ioctls.h" ++#include "lnxwrp_ioctls_fm_compat.h" ++ ++#if defined(FM_COMPAT_DBG) ++static void hex_dump(void * p_addr, unsigned int size) ++{ ++ int i; ++ ++ for(i=0; i\n", p); ++ ++ if(!p) ++ return 0; ++ ++ for(k=1; k < COMPAT_PTR2ID_ARRAY_MAX; k++) ++ if(compat_ptr2id_array[k].ptr == NULL) ++ { ++ compat_ptr2id_array[k].ptr = p; ++ compat_ptr2id_array[k].node_type = node_type; ++ _fm_cpt_dbg(COMPAT_GENERIC, "0x%08x \n", k | COMPAT_PTR2ID_WATERMARK); ++ return k | COMPAT_PTR2ID_WATERMARK; ++ } ++ ++ printk(KERN_WARNING "FMan map list full! No more PCD space on kernel!\n"); ++ return 0; ++} ++EXPORT_SYMBOL(compat_add_ptr2id); ++ ++compat_uptr_t compat_get_ptr2id(void *p, enum fm_map_node_type node_type) ++{ ++ compat_uptr_t k; ++ ++ _fm_cpt_dbg(COMPAT_GENERIC, " (%p) get -> \n", p); ++ ++ for(k=1; k < COMPAT_PTR2ID_ARRAY_MAX; k++) ++ if(compat_ptr2id_array[k].ptr == p && ++ compat_ptr2id_array[k].node_type == node_type) { ++ ++ _fm_cpt_dbg(COMPAT_GENERIC, "0x%08x\n", k | COMPAT_PTR2ID_WATERMARK); ++ return k | COMPAT_PTR2ID_WATERMARK; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(compat_get_ptr2id); ++ ++void *compat_get_id2ptr(compat_uptr_t comp, enum fm_map_node_type node_type) ++{ ++ ++ _fm_cpt_dbg(COMPAT_GENERIC, " (0x%08x) get -> \n", comp); ++ ++ if((COMPAT_PTR2ID_WM_MASK & comp) != COMPAT_PTR2ID_WATERMARK) { ++ _fm_cpt_dbg(COMPAT_GENERIC, "Error, invalid watermark (0x%08x)!\n\n", comp); ++ dump_stack(); ++ return compat_ptr(comp); ++ } ++ ++ comp &= ~COMPAT_PTR2ID_WM_MASK; ++ ++ if(((0 < comp) && (comp < COMPAT_PTR2ID_ARRAY_MAX) && (compat_ptr2id_array[comp].ptr != NULL) ++ && compat_ptr2id_array[comp].node_type == node_type)) { ++ _fm_cpt_dbg(COMPAT_GENERIC, "%p\n", compat_ptr2id_array[comp].ptr); ++ return compat_ptr2id_array[comp].ptr; ++ } ++ return NULL; ++} ++EXPORT_SYMBOL(compat_get_id2ptr); ++/* } maping kernel pointers w/ UserSpace id's */ ++ ++void compat_obj_delete( ++ ioc_compat_fm_obj_t *compat_id, ++ ioc_fm_obj_t *id) ++{ ++ id->obj = compat_pcd_id2ptr(compat_id->obj); ++ compat_del_ptr2id(id->obj, FM_MAP_TYPE_PCD_NODE); ++} ++ ++static inline void compat_copy_fm_pcd_plcr_next_engine( ++ ioc_compat_fm_pcd_plcr_next_engine_params_u *compat_param, ++ ioc_fm_pcd_plcr_next_engine_params_u *param, ++ ioc_fm_pcd_engine next_engine, ++ uint8_t compat) ++{ ++ _fm_cpt_dbg (compat, " {->...\n"); ++ ++ switch (next_engine) ++ { ++ case e_IOC_FM_PCD_PLCR: ++ if (compat == COMPAT_US_TO_K) ++ param->p_profile = compat_pcd_id2ptr(compat_param->p_profile); ++ else ++ compat_param->p_profile = compat_pcd_ptr2id(param->p_profile); ++ break; ++ case e_IOC_FM_PCD_KG: ++ if (compat == COMPAT_US_TO_K) ++ param->p_direct_scheme = compat_pcd_id2ptr(compat_param->p_direct_scheme); ++ else ++ compat_param->p_direct_scheme = compat_pcd_ptr2id(param->p_direct_scheme); ++ break; ++ default: ++ if (compat == COMPAT_US_TO_K) ++ param->action = compat_param->action; ++ else ++ compat_param->action = param->action; ++ break; ++ } ++ ++ _fm_cpt_dbg (compat, " ...->}\n"); ++} ++ ++void compat_copy_fm_pcd_plcr_profile( ++ ioc_compat_fm_pcd_plcr_profile_params_t *compat_param, ++ ioc_fm_pcd_plcr_profile_params_t *param, ++ uint8_t compat) ++{ ++ _fm_cpt_dbg (compat, " {->...\n"); ++ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->modify = compat_param->modify; ++ ++ /* profile_select */ ++ if (!compat_param->modify) ++ { ++ param->profile_select.new_params.profile_type = ++ compat_param->profile_select.new_params.profile_type; ++ param->profile_select.new_params.p_fm_port = ++ compat_ptr(compat_param->profile_select.new_params.p_fm_port); ++ param->profile_select.new_params.relative_profile_id = ++ compat_param->profile_select.new_params.relative_profile_id; ++ } ++ else ++ param->profile_select.p_profile = ++ compat_pcd_id2ptr(compat_param->profile_select.p_profile); ++ ++ param->alg_selection = compat_param->alg_selection; ++ param->color_mode = compat_param->color_mode; ++ ++ /* both parameters in the union has the same size, so memcpy works */ ++ memcpy(¶m->color, &compat_param->color, sizeof(param->color)); ++ ++ memcpy(¶m->non_passthrough_alg_param, ++ &compat_param->non_passthrough_alg_param, ++ sizeof(ioc_fm_pcd_plcr_non_passthrough_alg_param_t)); ++ ++ param->next_engine_on_green = compat_param->next_engine_on_green; ++ param->next_engine_on_yellow = compat_param->next_engine_on_yellow; ++ param->next_engine_on_red = compat_param->next_engine_on_red; ++ ++ param->trap_profile_on_flow_A = compat_param->trap_profile_on_flow_A; ++ param->trap_profile_on_flow_B = compat_param->trap_profile_on_flow_B; ++ param->trap_profile_on_flow_C = compat_param->trap_profile_on_flow_C; ++ } ++ else ++ { ++ compat_param->modify = param->modify; ++ ++ /* profile_select */ ++ if (!param->modify) ++ { ++ compat_param->profile_select.new_params.profile_type = ++ param->profile_select.new_params.profile_type; ++ compat_param->profile_select.new_params.p_fm_port = ++ ptr_to_compat(param->profile_select.new_params.p_fm_port); ++ compat_param->profile_select.new_params.relative_profile_id = ++ param->profile_select.new_params.relative_profile_id; ++ } ++ else ++ compat_param->profile_select.p_profile = ++ compat_pcd_ptr2id(param->profile_select.p_profile); ++ ++ compat_param->alg_selection = param->alg_selection; ++ compat_param->color_mode = param->color_mode; ++ ++ /* both parameters in the union has the same size, so memcpy works */ ++ memcpy(&compat_param->color, ¶m->color, sizeof(compat_param->color)); ++ ++ memcpy(&compat_param->non_passthrough_alg_param, ++ ¶m->non_passthrough_alg_param, ++ sizeof(ioc_fm_pcd_plcr_non_passthrough_alg_param_t)); ++ ++ compat_param->next_engine_on_green = param->next_engine_on_green; ++ compat_param->next_engine_on_yellow = param->next_engine_on_yellow; ++ compat_param->next_engine_on_red = param->next_engine_on_red; ++ ++ compat_param->trap_profile_on_flow_A = param->trap_profile_on_flow_A; ++ compat_param->trap_profile_on_flow_B = param->trap_profile_on_flow_B; ++ compat_param->trap_profile_on_flow_C = param->trap_profile_on_flow_C; ++ ++ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); ++ } ++ ++ compat_copy_fm_pcd_plcr_next_engine(&compat_param->params_on_green, ++ ¶m->params_on_green, param->next_engine_on_green, compat); ++ ++ compat_copy_fm_pcd_plcr_next_engine(&compat_param->params_on_yellow, ++ ¶m->params_on_yellow, param->next_engine_on_yellow, compat); ++ ++ compat_copy_fm_pcd_plcr_next_engine(&compat_param->params_on_red, ++ ¶m->params_on_red, param->next_engine_on_red, compat); ++ ++ _fm_cpt_dbg (compat, " ...->}\n"); ++} ++ ++static inline void compat_copy_fm_pcd_cc_next_kg( ++ ioc_compat_fm_pcd_cc_next_kg_params_t *compat_param, ++ ioc_fm_pcd_cc_next_kg_params_t *param, ++ uint8_t compat) ++{ ++ _fm_cpt_dbg (compat, " {->...\n"); ++ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->new_fqid = compat_param->new_fqid; ++ param->override_fqid = compat_param->override_fqid; ++#if DPAA_VERSION >= 11 ++ param->new_relative_storage_profile_id = compat_param->new_relative_storage_profile_id; ++#endif ++ param->p_direct_scheme = compat_pcd_id2ptr(compat_param->p_direct_scheme); ++ } ++ else ++ { ++ compat_param->new_fqid = param->new_fqid; ++ compat_param->override_fqid = param->override_fqid; ++#if DPAA_VERSION >= 11 ++ compat_param->new_relative_storage_profile_id = param->new_relative_storage_profile_id; ++#endif ++ compat_param->p_direct_scheme = compat_pcd_ptr2id(param->p_direct_scheme); ++ } ++ ++ _fm_cpt_dbg (compat, " ...->}\n"); ++} ++ ++static inline void compat_copy_fm_pcd_cc_next_cc( ++ ioc_compat_fm_pcd_cc_next_cc_params_t *compat_param, ++ ioc_fm_pcd_cc_next_cc_params_t *param, ++ uint8_t compat) ++{ ++ _fm_cpt_dbg (compat, " {->...\n"); ++ ++ if (compat == COMPAT_US_TO_K) ++ param->cc_node_id = compat_pcd_id2ptr(compat_param->cc_node_id); ++ else ++ compat_param->cc_node_id = compat_pcd_ptr2id(param->cc_node_id); ++ ++ _fm_cpt_dbg (compat, " ...->}\n"); ++} ++ ++static inline void compat_copy_fm_pcd_cc_next_engine( ++ ioc_compat_fm_pcd_cc_next_engine_params_t *compat_param, ++ ioc_fm_pcd_cc_next_engine_params_t *param, ++ uint8_t compat) ++{ ++ _fm_cpt_dbg (compat, " {->...\n"); ++ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->next_engine = compat_param->next_engine; ++ if (param->next_engine != e_IOC_FM_PCD_INVALID ) ++ _fm_cpt_dbg(compat, " param->next_engine = %i \n", param->next_engine); ++ ++ switch (param->next_engine) ++ { ++#if DPAA_VERSION >= 11 ++ case e_IOC_FM_PCD_FR: ++ param->params.fr_params.frm_replic_id = compat_pcd_id2ptr(compat_param->params.fr_params.frm_replic_id); ++ break; ++#endif /* DPAA_VERSION >= 11 */ ++ case e_IOC_FM_PCD_CC: ++ param->manip_id = compat_pcd_id2ptr(compat_param->manip_id); ++ compat_copy_fm_pcd_cc_next_cc(&compat_param->params.cc_params, ¶m->params.cc_params, compat); ++ break; ++ case e_IOC_FM_PCD_KG: ++ param->manip_id = compat_pcd_id2ptr(compat_param->manip_id); ++ compat_copy_fm_pcd_cc_next_kg(&compat_param->params.kg_params, ¶m->params.kg_params, compat); ++ break; ++ case e_IOC_FM_PCD_DONE: ++ case e_IOC_FM_PCD_PLCR: ++ param->manip_id = compat_pcd_id2ptr(compat_param->manip_id); ++ default: ++ memcpy(¶m->params, &compat_param->params, sizeof(param->params)); ++ } ++ param->statistics_en = compat_param->statistics_en; ++ } ++ else ++ { ++ compat_param->next_engine = param->next_engine; ++ ++ switch (compat_param->next_engine) ++ { ++#if DPAA_VERSION >= 11 ++ case e_IOC_FM_PCD_FR: ++ compat_param->params.fr_params.frm_replic_id = compat_pcd_ptr2id(param->params.fr_params.frm_replic_id); ++ break; ++#endif /* DPAA_VERSION >= 11 */ ++ case e_IOC_FM_PCD_CC: ++ compat_param->manip_id = compat_pcd_ptr2id(param->manip_id); ++ compat_copy_fm_pcd_cc_next_cc(&compat_param->params.cc_params, ¶m->params.cc_params, compat); ++ break; ++ case e_IOC_FM_PCD_KG: ++ compat_param->manip_id = compat_pcd_ptr2id(param->manip_id); ++ compat_copy_fm_pcd_cc_next_kg(&compat_param->params.kg_params, ¶m->params.kg_params, compat); ++ break; ++ case e_IOC_FM_PCD_DONE: ++ case e_IOC_FM_PCD_PLCR: ++ compat_param->manip_id = compat_pcd_ptr2id(param->manip_id); ++ default: ++ memcpy(&compat_param->params, ¶m->params, sizeof(compat_param->params)); ++ } ++ compat_param->statistics_en = param->statistics_en; ++ } ++ ++ _fm_cpt_dbg (compat, " ...->}\n"); ++} ++ ++void compat_copy_fm_pcd_cc_key( ++ ioc_compat_fm_pcd_cc_key_params_t *compat_param, ++ ioc_fm_pcd_cc_key_params_t *param, ++ uint8_t compat) ++{ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->p_key = compat_ptr(compat_param->p_key); ++ param->p_mask = compat_ptr(compat_param->p_mask); ++ } ++ else ++ { ++ compat_param->p_key = ptr_to_compat(param->p_key); ++ compat_param->p_mask = ptr_to_compat(param->p_mask); ++ } ++ ++ compat_copy_fm_pcd_cc_next_engine( ++ &compat_param->cc_next_engine_params, ++ ¶m->cc_next_engine_params, ++ compat); ++} ++ ++void compat_copy_fm_pcd_cc_node_modify_key_and_next_engine( ++ ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param, ++ ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param, ++ uint8_t compat) ++{ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->id = compat_pcd_id2ptr(compat_param->id); ++ param->key_indx = compat_param->key_indx; ++ param->key_size = compat_param->key_size; ++ compat_copy_fm_pcd_cc_key( ++ &compat_param->key_params, ++ ¶m->key_params, ++ compat); ++ } ++ else ++ { ++ compat_param->id = compat_pcd_ptr2id(param->id); ++ compat_param->key_indx = param->key_indx; ++ compat_param->key_size = param->key_size; ++ compat_copy_fm_pcd_cc_key( ++ &compat_param->key_params, ++ ¶m->key_params, ++ compat); ++ } ++} ++ ++void compat_copy_fm_pcd_cc_node_modify_next_engine( ++ ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param, ++ ioc_fm_pcd_cc_node_modify_next_engine_params_t *param, ++ uint8_t compat) ++{ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->id = compat_pcd_id2ptr(compat_param->id); ++ param->key_indx = compat_param->key_indx; ++ param->key_size = compat_param->key_size; ++ } ++ else ++ { ++ compat_param->id = compat_pcd_ptr2id(param->id); ++ compat_param->key_indx = param->key_indx; ++ compat_param->key_size = param->key_size; ++ } ++ ++ compat_copy_fm_pcd_cc_next_engine( ++ &compat_param->cc_next_engine_params, ++ ¶m->cc_next_engine_params, ++ compat); ++} ++ ++void compat_fm_pcd_cc_tree_modify_next_engine( ++ ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *compat_param, ++ ioc_fm_pcd_cc_tree_modify_next_engine_params_t *param, ++ uint8_t compat) ++{ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->id = compat_pcd_id2ptr(compat_param->id); ++ param->grp_indx = compat_param->grp_indx; ++ param->indx = compat_param->indx; ++ } ++ else ++ { ++ compat_param->id = compat_pcd_ptr2id(param->id); ++ compat_param->grp_indx = param->grp_indx; ++ compat_param->indx = param->indx; ++ } ++ ++ compat_copy_fm_pcd_cc_next_engine( ++ &compat_param->cc_next_engine_params, ++ ¶m->cc_next_engine_params, ++ compat); ++} ++ ++void compat_copy_fm_pcd_hash_table( ++ ioc_compat_fm_pcd_hash_table_params_t *compat_param, ++ ioc_fm_pcd_hash_table_params_t *param, ++ uint8_t compat) ++{ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->max_num_of_keys = compat_param->max_num_of_keys; ++ param->statistics_mode = compat_param->statistics_mode; ++ param->kg_hash_shift = compat_param->kg_hash_shift; ++ param->hash_res_mask = compat_param->hash_res_mask; ++ param->hash_shift = compat_param->hash_shift; ++ param->match_key_size = compat_param->match_key_size; ++ param->id = compat_pcd_id2ptr(compat_param->id); ++ } ++ else ++ { ++ compat_param->max_num_of_keys = param->max_num_of_keys; ++ compat_param->statistics_mode = param->statistics_mode; ++ compat_param->kg_hash_shift = param->kg_hash_shift; ++ compat_param->hash_res_mask = param->hash_res_mask; ++ compat_param->hash_shift = param->hash_shift; ++ compat_param->match_key_size = param->match_key_size; ++ ++ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); ++ } ++ ++ compat_copy_fm_pcd_cc_next_engine( ++ &compat_param->cc_next_engine_params_for_miss, ++ ¶m->cc_next_engine_params_for_miss, ++ compat); ++} ++ ++void compat_copy_fm_pcd_cc_grp( ++ ioc_compat_fm_pcd_cc_grp_params_t *compat_param, ++ ioc_fm_pcd_cc_grp_params_t *param, ++ uint8_t compat) ++{ ++ int k; ++ ++ _fm_cpt_dbg (compat, " {->...\n"); ++ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->num_of_distinction_units = compat_param->num_of_distinction_units; ++ memcpy(param->unit_ids, compat_param->unit_ids, IOC_FM_PCD_MAX_NUM_OF_CC_UNITS); ++ } ++ else ++ { ++ compat_param->num_of_distinction_units = param->num_of_distinction_units; ++ memcpy(compat_param->unit_ids, param->unit_ids, IOC_FM_PCD_MAX_NUM_OF_CC_UNITS); ++ } ++ ++ for (k=0; k < IOC_FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP; k++) ++ compat_copy_fm_pcd_cc_next_engine( ++ &compat_param->next_engine_per_entries_in_grp[k], ++ ¶m->next_engine_per_entries_in_grp[k], ++ compat); ++ ++ _fm_cpt_dbg (compat, " ...->}\n"); ++} ++ ++void compat_copy_fm_pcd_cc_tree( ++ ioc_compat_fm_pcd_cc_tree_params_t *compat_param, ++ ioc_fm_pcd_cc_tree_params_t *param, ++ uint8_t compat) ++{ ++ int k; ++ _fm_cpt_dbg (compat, " {->...\n"); ++ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->net_env_id = compat_pcd_id2ptr(compat_param->net_env_id); ++ param->num_of_groups = compat_param->num_of_groups; ++ } ++ else ++ { ++ compat_param->net_env_id = compat_pcd_ptr2id(param->net_env_id); ++ compat_param->num_of_groups = param->num_of_groups; ++ ++ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); ++ } ++ ++ for (k=0; k < IOC_FM_PCD_MAX_NUM_OF_CC_GROUPS; k++) ++ compat_copy_fm_pcd_cc_grp( ++ &compat_param->fm_pcd_cc_group_params[k], ++ ¶m->fm_pcd_cc_group_params[k], ++ compat); ++ ++ _fm_cpt_dbg (compat, " ...->}\n"); ++} ++ ++void compat_fm_pcd_prs_sw( ++ ioc_compat_fm_pcd_prs_sw_params_t *compat_param, ++ ioc_fm_pcd_prs_sw_params_t *param, ++ uint8_t compat) ++{ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->override = compat_param->override; ++ param->size = compat_param->size; ++ param->base = compat_param->base; ++ param->p_code = compat_ptr(compat_param->p_code); ++ memcpy(param->sw_prs_data_params,compat_param->sw_prs_data_params,IOC_FM_PCD_PRS_NUM_OF_HDRS*sizeof(uint32_t)); ++ param->num_of_labels = compat_param->num_of_labels; ++ memcpy(param->labels_table,compat_param->labels_table,IOC_FM_PCD_PRS_NUM_OF_LABELS*sizeof(ioc_fm_pcd_prs_label_params_t)); ++ } ++} ++ ++void compat_copy_fm_pcd_kg_scheme( ++ ioc_compat_fm_pcd_kg_scheme_params_t *compat_param, ++ ioc_fm_pcd_kg_scheme_params_t *param, ++ uint8_t compat) ++{ ++ _fm_cpt_dbg(compat," {->...\n"); ++ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->modify = compat_param->modify; ++ ++ /* scm_id */ ++ if (compat_param->modify) ++ { ++ param->scm_id.scheme_id = compat_pcd_id2ptr(compat_param->scm_id.scheme_id); ++ _fm_cpt_dbg(compat," param->scm_id.scheme_id = %p \n", param->scm_id.scheme_id); ++ } ++ else ++ param->scm_id.relative_scheme_id = compat_param->scm_id.relative_scheme_id; ++ ++ param->always_direct = compat_param->always_direct; ++ /* net_env_params */ ++ param->net_env_params.net_env_id = compat_pcd_id2ptr(compat_param->net_env_params.net_env_id); ++ param->net_env_params.num_of_distinction_units = compat_param->net_env_params.num_of_distinction_units; ++ memcpy(param->net_env_params.unit_ids, ++ compat_param->net_env_params.unit_ids, ++ IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); ++ ++ param->use_hash = compat_param->use_hash; ++ memcpy(¶m->key_extract_and_hash_params, ++ &compat_param->key_extract_and_hash_params, ++ sizeof(ioc_fm_pcd_kg_key_extract_and_hash_params_t)); ++ param->bypass_fqid_generation = compat_param->bypass_fqid_generation; ++ param->base_fqid = compat_param->base_fqid; ++#if DPAA_VERSION >= 11 ++ param->override_storage_profile = ++ compat_param->override_storage_profile; ++ param->storage_profile = compat_param->storage_profile; ++#endif ++ param->num_of_used_extracted_ors = compat_param->num_of_used_extracted_ors; ++ memcpy(param->extracted_ors, ++ compat_param->extracted_ors, ++ IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS * sizeof(ioc_fm_pcd_kg_extracted_or_params_t)); ++ param->next_engine = compat_param->next_engine; ++ ++ /* kg_next_engine_params */ ++ if (param->next_engine == e_IOC_FM_PCD_CC) ++ { ++ param->kg_next_engine_params.cc.tree_id = compat_pcd_id2ptr(compat_param->kg_next_engine_params.cc.tree_id); ++ param->kg_next_engine_params.cc.grp_id = compat_param->kg_next_engine_params.cc.grp_id; ++ param->kg_next_engine_params.cc.plcr_next = compat_param->kg_next_engine_params.cc.plcr_next; ++ param->kg_next_engine_params.cc.bypass_plcr_profile_generation ++ = compat_param->kg_next_engine_params.cc.bypass_plcr_profile_generation; ++ memcpy(¶m->kg_next_engine_params.cc.plcr_profile, ++ &compat_param->kg_next_engine_params.cc.plcr_profile, ++ sizeof(ioc_fm_pcd_kg_plcr_profile_t)); ++ } ++ else ++ memcpy(¶m->kg_next_engine_params, ++ &compat_param->kg_next_engine_params, ++ sizeof(param->kg_next_engine_params)); ++ ++ memcpy(¶m->scheme_counter, ++ &compat_param->scheme_counter, ++ sizeof(ioc_fm_pcd_kg_scheme_counter_t)); ++ } ++ else ++ { ++ compat_param->modify = param->modify; ++ ++ /* scm_id */ ++ if (param->modify) ++ compat_param->scm_id.scheme_id = compat_pcd_ptr2id(param->scm_id.scheme_id); ++ else ++ compat_param->scm_id.relative_scheme_id = param->scm_id.relative_scheme_id; ++ ++ compat_param->always_direct = param->always_direct; ++ ++ /* net_env_params */ ++ compat_param->net_env_params.net_env_id = compat_pcd_ptr2id(param->net_env_params.net_env_id); ++ compat_param->net_env_params.num_of_distinction_units = param->net_env_params.num_of_distinction_units; ++ memcpy(compat_param->net_env_params.unit_ids, param->net_env_params.unit_ids, IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); ++ ++ compat_param->use_hash = param->use_hash; ++ memcpy(&compat_param->key_extract_and_hash_params, ¶m->key_extract_and_hash_params, sizeof(ioc_fm_pcd_kg_key_extract_and_hash_params_t)); ++ compat_param->bypass_fqid_generation = param->bypass_fqid_generation; ++ compat_param->base_fqid = param->base_fqid; ++#if DPAA_VERSION >= 11 ++ compat_param->override_storage_profile = ++ param->override_storage_profile; ++ compat_param->storage_profile = param->storage_profile; ++#endif ++ compat_param->num_of_used_extracted_ors = param->num_of_used_extracted_ors; ++ memcpy(compat_param->extracted_ors, param->extracted_ors, IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS * sizeof(ioc_fm_pcd_kg_extracted_or_params_t)); ++ compat_param->next_engine = param->next_engine; ++ ++ /* kg_next_engine_params */ ++ if (compat_param->next_engine == e_IOC_FM_PCD_CC) ++ { ++ compat_param->kg_next_engine_params.cc.tree_id = compat_pcd_ptr2id(param->kg_next_engine_params.cc.tree_id); ++ compat_param->kg_next_engine_params.cc.grp_id = param->kg_next_engine_params.cc.grp_id; ++ compat_param->kg_next_engine_params.cc.plcr_next = param->kg_next_engine_params.cc.plcr_next; ++ compat_param->kg_next_engine_params.cc.bypass_plcr_profile_generation ++ = param->kg_next_engine_params.cc.bypass_plcr_profile_generation; ++ memcpy(&compat_param->kg_next_engine_params.cc.plcr_profile, ++ ¶m->kg_next_engine_params.cc.plcr_profile, ++ sizeof(ioc_fm_pcd_kg_plcr_profile_t)); ++ } ++ else ++ memcpy(¶m->kg_next_engine_params, &compat_param->kg_next_engine_params, sizeof(compat_param->kg_next_engine_params)); ++ ++ memcpy(&compat_param->scheme_counter, ¶m->scheme_counter, sizeof(ioc_fm_pcd_kg_scheme_counter_t)); ++ ++ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); ++ } ++ ++ _fm_cpt_dbg(compat," ...->}\n"); ++} ++ ++void compat_copy_fm_pcd_kg_scheme_spc( ++ ioc_compat_fm_pcd_kg_scheme_spc_t *compat_param, ++ ioc_fm_pcd_kg_scheme_spc_t *param, ++ uint8_t compat) ++{ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->id = compat_pcd_id2ptr(compat_param->id); ++ param->val = compat_param->val; ++ } else { ++ compat_param->id = compat_pcd_ptr2id(param->id); ++ compat_param->val = param->val; ++ } ++} ++ ++ ++void compat_copy_fm_pcd_kg_scheme_select( ++ ioc_compat_fm_pcd_kg_scheme_select_t *compat_param, ++ ioc_fm_pcd_kg_scheme_select_t *param, ++ uint8_t compat) ++{ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->direct = compat_param->direct; ++ if (param->direct) ++ param->scheme_id = compat_pcd_id2ptr(compat_param->scheme_id); ++ } ++} ++ ++void compat_copy_fm_pcd_kg_schemes_params( ++ ioc_compat_fm_pcd_port_schemes_params_t *compat_param, ++ ioc_fm_pcd_port_schemes_params_t *param, ++ uint8_t compat) ++{ ++ int k; ++ ++ if (compat == COMPAT_US_TO_K) { ++ param->num_of_schemes = compat_param->num_of_schemes; ++ for(k=0; k < compat_param->num_of_schemes; k++) ++ param->scheme_ids[k] = compat_pcd_id2ptr(compat_param->scheme_ids[k]); ++ } ++} ++ ++void compat_copy_fm_port_pcd_cc( ++ ioc_compat_fm_port_pcd_cc_params_t *compat_cc_params , ++ ioc_fm_port_pcd_cc_params_t *p_cc_params, ++ uint8_t compat) ++{ ++ if (compat == COMPAT_US_TO_K){ ++ p_cc_params->cc_tree_id = compat_pcd_id2ptr(compat_cc_params->cc_tree_id); ++ } ++} ++ ++void compat_copy_fm_port_pcd_kg( ++ ioc_compat_fm_port_pcd_kg_params_t *compat_param, ++ ioc_fm_port_pcd_kg_params_t *param, ++ uint8_t compat) ++{ ++ if (compat == COMPAT_US_TO_K){ ++ uint8_t k; ++ ++ param->num_of_schemes = compat_param->num_of_schemes; ++ for(k=0; knum_of_schemes; k++) ++ param->scheme_ids[k] = compat_pcd_id2ptr(compat_param->scheme_ids[k]); ++ ++ param->direct_scheme = compat_param->direct_scheme; ++ if (param->direct_scheme) ++ param->direct_scheme_id = compat_pcd_id2ptr(compat_param->direct_scheme_id); ++ } ++} ++ ++void compat_copy_fm_port_pcd( ++ ioc_compat_fm_port_pcd_params_t *compat_param, ++ ioc_fm_port_pcd_params_t *param, ++ uint8_t compat) ++{ ++ if (compat == COMPAT_US_TO_K) ++ { ++ ioc_fm_port_pcd_prs_params_t *same_port_pcd_prs_params; ++ ioc_compat_fm_port_pcd_cc_params_t *compat_port_pcd_cc_params; ++ ioc_compat_fm_port_pcd_kg_params_t *compat_port_pcd_kg_params; ++ ioc_compat_fm_port_pcd_plcr_params_t *compat_port_pcd_plcr_params; ++ ++ same_port_pcd_prs_params = (ioc_fm_port_pcd_prs_params_t *) (compat_param + 1); ++ compat_port_pcd_cc_params = (ioc_compat_fm_port_pcd_cc_params_t *) (same_port_pcd_prs_params + 1); ++ compat_port_pcd_kg_params = (ioc_compat_fm_port_pcd_kg_params_t *) (compat_port_pcd_cc_params + 1); ++ compat_port_pcd_plcr_params = (ioc_compat_fm_port_pcd_plcr_params_t *) (compat_port_pcd_kg_params + 1); ++ ++ _fm_cpt_dbg(compat,"\n param->p_prs_params=%p \n", param->p_prs_params); ++ _fm_cpt_dbg(compat," param->p_cc_params=%p \n", param->p_cc_params); ++ _fm_cpt_dbg(compat," param->p_kg_params=%p \n", param->p_kg_params); ++ _fm_cpt_dbg(compat," param->p_plcr_params=%p \n", param->p_plcr_params); ++ _fm_cpt_dbg(compat," param->p_ip_reassembly_manip=%p \n", param->p_ip_reassembly_manip); ++#if (DPAA_VERSION >= 11) ++ _fm_cpt_dbg(compat," param->p_capwap_reassembly_manip=%p \n", param->p_capwap_reassembly_manip); ++#endif ++ param->pcd_support = compat_param->pcd_support; ++ param->net_env_id = compat_pcd_id2ptr(compat_param->net_env_id); ++ ++ if (param->p_cc_params) ++ compat_copy_fm_port_pcd_cc(compat_port_pcd_cc_params, param->p_cc_params, COMPAT_US_TO_K); ++ if (param->p_kg_params) ++ compat_copy_fm_port_pcd_kg(compat_port_pcd_kg_params, param->p_kg_params, COMPAT_US_TO_K); ++ if (param->p_plcr_params) ++ param->p_plcr_params->plcr_profile_id = compat_pcd_id2ptr(compat_port_pcd_plcr_params->plcr_profile_id); ++ param->p_ip_reassembly_manip = compat_pcd_id2ptr(compat_param->p_ip_reassembly_manip); ++#if (DPAA_VERSION >= 11) ++ param->p_capwap_reassembly_manip = compat_pcd_id2ptr(compat_param->p_capwap_reassembly_manip); ++#endif ++ } ++} ++ ++void compat_copy_fm_port_pcd_modify_tree( ++ ioc_compat_fm_obj_t *compat_id, ++ ioc_fm_obj_t *id, ++ uint8_t compat) ++{ ++ if (compat == COMPAT_US_TO_K) ++ id->obj = compat_pcd_id2ptr(compat_id->obj); ++} ++ ++#if (DPAA_VERSION >= 11) ++void compat_copy_fm_port_vsp_alloc_params( ++ ioc_compat_fm_port_vsp_alloc_params_t *compat_param, ++ ioc_fm_port_vsp_alloc_params_t *param, ++ uint8_t compat) ++{ ++ if (compat == COMPAT_US_TO_K) ++ { ++ _fm_cpt_dbg(compat," param->p_fm_tx_port=%p \n", param->p_fm_tx_port); ++ ++ param->dflt_relative_id = compat_param->dflt_relative_id; ++ param->num_of_profiles = compat_param->num_of_profiles; ++ param->p_fm_tx_port = compat_pcd_id2ptr(compat_param->p_fm_tx_port); ++ } ++} ++#endif /* (DPAA_VERSION >= 11) */ ++ ++void compat_copy_fm_pcd_cc_tbl_get_stats( ++ ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param, ++ ioc_fm_pcd_cc_tbl_get_stats_t *param, ++ uint8_t compat) ++{ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->id = compat_pcd_id2ptr(compat_param->id); ++ param->key_index = compat_param->key_index; ++ memcpy(¶m->statistics, &compat_param->statistics, sizeof(ioc_fm_pcd_cc_key_statistics_t)); ++ } else { ++ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); ++ compat_param->key_index = param->key_index; ++ memcpy(&compat_param->statistics, ¶m->statistics, sizeof(ioc_fm_pcd_cc_key_statistics_t)); ++ } ++} ++ ++ ++void compat_copy_fm_pcd_net_env( ++ ioc_compat_fm_pcd_net_env_params_t *compat_param, ++ ioc_fm_pcd_net_env_params_t *param, ++ uint8_t compat) ++{ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->num_of_distinction_units = compat_param->num_of_distinction_units; ++ memcpy(param->units, compat_param->units, sizeof(ioc_fm_pcd_distinction_unit_t)*IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); ++ param->id = NULL; /* to avoid passing garbage to the kernel */ ++ } ++ else ++ { ++ compat_param->num_of_distinction_units = param->num_of_distinction_units; ++ memcpy(compat_param->units, param->units, sizeof(ioc_fm_pcd_distinction_unit_t)*IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); ++ ++ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); ++ } ++} ++ ++void compat_copy_fm_pcd_cc_node_modify_key( ++ ioc_compat_fm_pcd_cc_node_modify_key_params_t *compat_param, ++ ioc_fm_pcd_cc_node_modify_key_params_t *param, ++ uint8_t compat) ++{ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->key_indx = compat_param->key_indx; ++ param->key_size = compat_param->key_size; ++ param->p_key = (uint8_t *)compat_ptr(compat_param->p_key); ++ _fm_cpt_dbg(compat," param->p_key = %p \n", param->p_key); ++ param->p_mask = (uint8_t *)compat_ptr(compat_param->p_mask); ++ _fm_cpt_dbg(compat," param->p_mask = %p\n", param->p_mask); ++ param->id = compat_pcd_id2ptr(compat_param->id); ++ _fm_cpt_dbg(compat," param->id = %p \n", param->id); ++ } ++ else ++ { ++ compat_param->key_indx = param->key_indx; ++ compat_param->key_size = param->key_size; ++ compat_param->p_key = ptr_to_compat((void *)param->p_key); ++ compat_param->p_mask = ptr_to_compat((void *)param->p_mask); ++ ++ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); ++ } ++} ++ ++void compat_copy_keys( ++ ioc_compat_keys_params_t *compat_param, ++ ioc_keys_params_t *param, ++ uint8_t compat) ++{ ++ int k = 0; ++ ++ _fm_cpt_dbg(compat," {->...\n"); ++ ++ if (compat == COMPAT_US_TO_K) { ++ param->max_num_of_keys = compat_param->max_num_of_keys; ++ param->mask_support = compat_param->mask_support; ++ param->statistics_mode = compat_param->statistics_mode; ++ param->num_of_keys = compat_param->num_of_keys; ++ param->key_size = compat_param->key_size; ++#if (DPAA_VERSION >= 11) ++ memcpy(¶m->frame_length_ranges, ++ &compat_param->frame_length_ranges, ++ sizeof(param->frame_length_ranges[0]) * ++ IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR); ++#endif /* (DPAA_VERSION >= 11) */ ++ } ++ else { ++ compat_param->max_num_of_keys = param->max_num_of_keys; ++ compat_param->mask_support = param->mask_support; ++ compat_param->statistics_mode = param->statistics_mode; ++ compat_param->num_of_keys = param->num_of_keys; ++ compat_param->key_size = param->key_size; ++#if (DPAA_VERSION >= 11) ++ memcpy(&compat_param->frame_length_ranges, ++ ¶m->frame_length_ranges, ++ sizeof(compat_param->frame_length_ranges[0]) * ++ IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR); ++#endif /* (DPAA_VERSION >= 11) */ ++ } ++ ++ for (k=0; k < IOC_FM_PCD_MAX_NUM_OF_KEYS; k++) ++ compat_copy_fm_pcd_cc_key( ++ &compat_param->key_params[k], ++ ¶m->key_params[k], ++ compat); ++ ++ compat_copy_fm_pcd_cc_next_engine( ++ &compat_param->cc_next_engine_params_for_miss, ++ ¶m->cc_next_engine_params_for_miss, ++ compat); ++ ++ _fm_cpt_dbg(compat," ...->}\n"); ++} ++ ++void compat_copy_fm_pcd_cc_node( ++ ioc_compat_fm_pcd_cc_node_params_t *compat_param, ++ ioc_fm_pcd_cc_node_params_t *param, ++ uint8_t compat) ++{ ++ _fm_cpt_dbg(compat," {->...\n"); ++ ++ if (compat == COMPAT_US_TO_K) ++ memcpy(¶m->extract_cc_params, &compat_param->extract_cc_params, sizeof(ioc_fm_pcd_extract_entry_t)); ++ ++ else ++ { ++ compat_copy_keys(&compat_param->keys_params, ¶m->keys_params, compat); ++ ++ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); ++ _fm_cpt_dbg(compat," param->id = %p \n", param->id); ++ } ++ ++ compat_copy_keys(&compat_param->keys_params, ¶m->keys_params, compat); ++ ++ _fm_cpt_dbg(compat," ...->}\n"); ++} ++ ++void compat_fm_pcd_manip_set_node( ++ ioc_compat_fm_pcd_manip_params_t *compat_param, ++ ioc_fm_pcd_manip_params_t *param, ++ uint8_t compat) ++{ ++ if (compat == COMPAT_US_TO_K) { ++ param->type = compat_param->type; ++ switch (param->type) { ++ case e_IOC_FM_PCD_MANIP_HDR: ++ param->u.hdr.rmv = compat_param->u.hdr.rmv; ++ memcpy(¶m->u.hdr.rmv_params, ++ &compat_param->u.hdr.rmv_params, ++ sizeof(param->u.hdr.rmv_params)); ++ ++ param->u.hdr.insrt = compat_param->u.hdr.insrt; ++ param->u.hdr.insrt_params.type = ++ compat_param->u.hdr.insrt_params.type; ++ switch (compat_param->u.hdr.insrt_params.type) ++ { ++ case e_IOC_FM_PCD_MANIP_INSRT_GENERIC: ++ param->u.hdr.insrt_params.u.generic.offset = ++ compat_param->u.hdr.insrt_params.u.generic.offset; ++ param->u.hdr.insrt_params.u.generic.size = ++ compat_param->u.hdr.insrt_params.u.generic.size; ++ param->u.hdr.insrt_params.u.generic.replace = ++ compat_param->u.hdr.insrt_params.u.generic.replace; ++ param->u.hdr.insrt_params.u.generic.p_data = ++ compat_ptr(compat_param->u.hdr.insrt_params.u.generic.p_data); ++ break; ++ case e_IOC_FM_PCD_MANIP_INSRT_BY_HDR: ++ param->u.hdr.insrt_params.u.by_hdr.type = ++ compat_param->u.hdr.insrt_params.u.by_hdr.type; ++ param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.specific_l2 = ++ compat_param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.specific_l2; ++ param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.update = ++ compat_param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.update; ++ param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.size = ++ compat_param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.size; ++ param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.p_data = ++ compat_ptr(compat_param->u.hdr.insrt_params.u.by_hdr.u.specific_l2_params.p_data); ++ break; ++ default: ++ _fm_cpt_err("Unsupported type: %d", compat_param->u.hdr.insrt_params.type); ++ } ++ ++ param->u.hdr.field_update = compat_param->u.hdr.field_update; ++ memcpy(¶m->u.hdr.field_update_params, ++ &compat_param->u.hdr.field_update_params, ++ sizeof(param->u.hdr.field_update_params)); ++ ++ param->u.hdr.custom = compat_param->u.hdr.custom; ++ memcpy(¶m->u.hdr.custom_params, ++ &compat_param->u.hdr.custom_params, ++ sizeof(param->u.hdr.custom_params)); ++ ++ param->u.hdr.dont_parse_after_manip = ++ compat_param->u.hdr.dont_parse_after_manip; ++ break; ++ case e_IOC_FM_PCD_MANIP_REASSEM: ++ memcpy(¶m->u.reassem, &compat_param->u.reassem, sizeof(param->u.reassem)); ++ break; ++ case e_IOC_FM_PCD_MANIP_FRAG: ++ memcpy(¶m->u.frag, &compat_param->u.frag, sizeof(param->u.frag)); ++ break; ++ case e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD: ++ memcpy(¶m->u.special_offload, ++ &compat_param->u.special_offload, ++ sizeof(param->u.special_offload)); ++ break; ++ } ++ ++ param->p_next_manip = compat_pcd_id2ptr(compat_param->p_next_manip); ++ param->id = compat_pcd_id2ptr(compat_param->id); ++ } ++ else { ++ compat_param->type = param->type; ++ memcpy(&compat_param->u, ¶m->u, sizeof(compat_param->u)); ++ ++ if (param->type == e_IOC_FM_PCD_MANIP_HDR && ++ param->u.hdr.insrt_params.type == e_IOC_FM_PCD_MANIP_INSRT_GENERIC) ++ compat_param->u.hdr.insrt_params.u.generic.p_data = ++ ptr_to_compat(param->u.hdr.insrt_params.u.generic.p_data); ++ ++ compat_param->p_next_manip = compat_pcd_ptr2id(param->id); ++ /* ... should be one that was added previously by the very call to ++ compat_add_ptr2id() below: */ ++ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); ++ } ++} ++ ++void compat_copy_fm_pcd_manip_get_stats( ++ ioc_compat_fm_pcd_manip_get_stats_t *compat_param, ++ ioc_fm_pcd_manip_get_stats_t *param, ++ uint8_t compat) ++{ ++ _fm_cpt_dbg (compat, " {->...\n"); ++ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->id = compat_pcd_id2ptr(compat_param->id); ++ memcpy(¶m->stats, &compat_param->stats, ++ sizeof(ioc_fm_pcd_manip_stats_t)); ++ } ++ else ++ { ++ compat_param->id = compat_add_ptr2id(param->id, ++ FM_MAP_TYPE_PCD_NODE); ++ memcpy(&compat_param->stats, ¶m->stats, ++ sizeof(ioc_fm_pcd_manip_stats_t)); ++ } ++ ++ _fm_cpt_dbg (compat, " ...->}\n"); ++} ++ ++#if (DPAA_VERSION >= 11) ++void compat_copy_fm_pcd_frm_replic_group_params( ++ ioc_compat_fm_pcd_frm_replic_group_params_t *compat_param, ++ ioc_fm_pcd_frm_replic_group_params_t *param, ++ uint8_t compat) ++{ ++ int k; ++ ++ _fm_cpt_dbg (compat, " {->...\n"); ++ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->max_num_of_entries = compat_param->max_num_of_entries; ++ param->num_of_entries = compat_param->num_of_entries; ++ param->id = compat_pcd_id2ptr(compat_param->id); ++ } ++ else ++ { ++ compat_param->max_num_of_entries = param->max_num_of_entries; ++ compat_param->num_of_entries = param->num_of_entries; ++ compat_param->id = compat_add_ptr2id(param->id, ++ FM_MAP_TYPE_PCD_NODE); ++ } ++ ++ for (k=0; k < IOC_FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES; k++) ++ compat_copy_fm_pcd_cc_next_engine( ++ &compat_param->next_engine_params[k], ++ ¶m->next_engine_params[k], ++ compat); ++ ++ _fm_cpt_dbg (compat, " ...->}\n"); ++} ++ ++void compat_copy_fm_pcd_frm_replic_member( ++ ioc_compat_fm_pcd_frm_replic_member_t *compat_param, ++ ioc_fm_pcd_frm_replic_member_t *param, ++ uint8_t compat) ++{ ++ _fm_cpt_dbg (compat, " {->...\n"); ++ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->h_replic_group = compat_pcd_id2ptr(compat_param->h_replic_group); ++ param->member_index = compat_param->member_index; ++ } ++ ++ _fm_cpt_dbg (compat, " ...->}\n"); ++} ++ ++void compat_copy_fm_pcd_frm_replic_member_params( ++ ioc_compat_fm_pcd_frm_replic_member_params_t *compat_param, ++ ioc_fm_pcd_frm_replic_member_params_t *param, ++ uint8_t compat) ++{ ++ _fm_cpt_dbg (compat, " {->...\n"); ++ ++ compat_copy_fm_pcd_frm_replic_member(&compat_param->member, ++ ¶m->member, compat); ++ ++ compat_copy_fm_pcd_cc_next_engine(&compat_param->next_engine_params, ++ ¶m->next_engine_params, compat); ++ ++ _fm_cpt_dbg (compat, " ...->}\n"); ++} ++ ++void compat_copy_fm_vsp_params( ++ ioc_compat_fm_vsp_params_t *compat_param, ++ ioc_fm_vsp_params_t *param, ++ uint8_t compat) ++{ ++ _fm_cpt_dbg (compat, " {->...\n"); ++ ++ if (compat == COMPAT_US_TO_K) ++ { ++ memcpy(¶m->ext_buf_pools, &compat_param->ext_buf_pools, sizeof(ioc_fm_ext_pools)); ++ param->liodn_offset = compat_param->liodn_offset; ++ param->port_params.port_id = compat_param->port_params.port_id; ++ param->port_params.port_type = compat_param->port_params.port_type; ++ param->relative_profile_id = compat_param->relative_profile_id; ++ } ++ else ++ { ++ memcpy(&compat_param->ext_buf_pools, ¶m->ext_buf_pools, sizeof(ioc_fm_ext_pools)); ++ compat_param->liodn_offset = param->liodn_offset; ++ compat_param->port_params.port_id = param->port_params.port_id; ++ compat_param->port_params.port_type = param->port_params.port_type; ++ compat_param->relative_profile_id = param->relative_profile_id; ++ compat_param->id = compat_add_ptr2id(param->id, FM_MAP_TYPE_PCD_NODE); ++ } ++ ++ _fm_cpt_dbg (compat, " ...->}\n"); ++} ++ ++void compat_copy_fm_buf_pool_depletion_params( ++ ioc_compat_fm_buf_pool_depletion_params_t *compat_param, ++ ioc_fm_buf_pool_depletion_params_t *param, ++ uint8_t compat) ++{ ++ _fm_cpt_dbg (compat, " {->...\n"); ++ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->p_fm_vsp = compat_pcd_id2ptr(compat_param->p_fm_vsp); ++ memcpy(¶m->fm_buf_pool_depletion, ++ &compat_param->fm_buf_pool_depletion, ++ sizeof(ioc_fm_buf_pool_depletion_t)); ++ } ++ ++ _fm_cpt_dbg (compat, " ...->}\n"); ++} ++ ++void compat_copy_fm_buffer_prefix_content_params( ++ ioc_compat_fm_buffer_prefix_content_params_t *compat_param, ++ ioc_fm_buffer_prefix_content_params_t *param, ++ uint8_t compat) ++{ ++ _fm_cpt_dbg (compat, " {->...\n"); ++ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->p_fm_vsp = compat_pcd_id2ptr(compat_param->p_fm_vsp); ++ memcpy(¶m->fm_buffer_prefix_content, ++ &compat_param->fm_buffer_prefix_content, ++ sizeof(ioc_fm_buffer_prefix_content_t)); ++ } ++ ++ _fm_cpt_dbg (compat, " ...->}\n"); ++} ++ ++void compat_copy_fm_vsp_config_no_sg_params( ++ ioc_compat_fm_vsp_config_no_sg_params_t *compat_param, ++ ioc_fm_vsp_config_no_sg_params_t *param, ++ uint8_t compat) ++{ ++ _fm_cpt_dbg (compat, " {->...\n"); ++ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->p_fm_vsp = compat_pcd_id2ptr(compat_param->p_fm_vsp); ++ param->no_sg = compat_param->no_sg; ++ } ++ ++ _fm_cpt_dbg (compat, " ...->}\n"); ++} ++ ++void compat_copy_fm_vsp_prs_result_params( ++ ioc_compat_fm_vsp_prs_result_params_t *compat_param, ++ ioc_fm_vsp_prs_result_params_t *param, ++ uint8_t compat) ++{ ++ _fm_cpt_dbg (compat, " {->...\n"); ++ ++ if (compat == COMPAT_US_TO_K) ++ { ++ param->p_fm_vsp = compat_pcd_id2ptr(compat_param->p_fm_vsp); ++ /* p_data is an user-space pointer that needs to remain unmodified */ ++ param->p_data = (void *)(unsigned long long)compat_param->p_data; ++ } ++ else ++ { ++ compat_param->p_fm_vsp = compat_pcd_ptr2id(param->p_fm_vsp); ++ /* p_data is an user-space pointer that needs to remain unmodified */ ++ compat_param->p_data = (compat_uptr_t)((unsigned long long)param->p_data & 0xFFFFFFFF); ++ } ++ ++ _fm_cpt_dbg (compat, " ...->}\n"); ++} ++#endif /* (DPAA_VERSION >= 11) */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.h b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.h +new file mode 100644 +index 00000000..187011f7 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_ioctls_fm_compat.h +@@ -0,0 +1,755 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ @File lnxwrp_ioctls_fm_compat.h ++ ++ @Description FM PCD compat structures definition. ++ ++*/ ++ ++#ifndef __FM_COMPAT_IOCTLS_H ++#define __FM_COMPAT_IOCTLS_H ++ ++#include ++ ++#define COMPAT_K_TO_US 0 /* copy from Kernel to User */ ++#define COMPAT_US_TO_K 1 /* copy from User to Kernel */ ++#define COMPAT_GENERIC 2 ++ ++#define COMPAT_COPY_K2US(dest, src, type) compat_copy_##type(src, dest, 0) ++#define COMPAT_COPY_US2K(dest, src, type) compat_copy_##type(dest, src, 1) ++ ++/* mapping kernel pointers w/ UserSpace id's { */ ++/* Because compat_ptr(ptr_to_compat(X)) != X, this way we cannot exchange pointers ++ back and forth (US - KS). compat_ptr is a cast and pointers are broken. */ ++#define COMPAT_PTR2ID_ARRAY_MAX (512+1) /* first location is not used */ ++#define COMPAT_PTR2ID_WATERMARK 0xface0000 ++#define COMPAT_PTR2ID_WM_MASK 0xffff0000 ++ ++/* define it for debug trace */ ++/*#define FM_COMPAT_DBG*/ ++ ++#define _fm_cpt_prk(stage, format, arg...) \ ++ printk(stage "fm_cpt (cpu:%u): " format, raw_smp_processor_id(), ##arg) ++ ++#define _fm_cpt_inf(format, arg...) _fm_cpt_prk(KERN_INFO, format, ##arg) ++#define _fm_cpt_wrn(format, arg...) _fm_cpt_prk(KERN_WARNING, format, ##arg) ++#define _fm_cpt_err(format, arg...) _fm_cpt_prk(KERN_ERR, format, ##arg) ++ ++/* used for compat IOCTL debugging */ ++#if defined(FM_COMPAT_DBG) ++ #define _fm_cpt_dbg(from, format, arg...) \ ++ do{ \ ++ if (from == COMPAT_US_TO_K) \ ++ printk("fm_cpt to KS [%s:%u](cpu:%u) - " format, \ ++ __func__, __LINE__, raw_smp_processor_id(), ##arg); \ ++ else if (from == COMPAT_K_TO_US) \ ++ printk("fm_cpt to US [%s:%u](cpu:%u) - " format, \ ++ __func__, __LINE__, raw_smp_processor_id(), ##arg); \ ++ else \ ++ printk("fm_cpt [%s:%u](cpu:%u) - " format, \ ++ __func__, __LINE__, raw_smp_processor_id(), ##arg); \ ++ }while(0) ++#else ++# define _fm_cpt_dbg(arg...) ++#endif ++ ++/*TODO: per FMan module: ++ * ++ * Parser: FM_MAP_TYPE_PARSER_NODE, ++ * Kg: FM_MAP_TYPE_KG_NODE, ++ * Policer: FM_MAP_TYPE_POLICER_NODE ++ * Manip: FM_MAP_TYPE_MANIP_NODE ++ **/ ++enum fm_map_node_type { ++ FM_MAP_TYPE_UNSPEC = 0, ++ FM_MAP_TYPE_PCD_NODE, ++ ++ /* add types here, update the policy */ ++ ++ __FM_MAP_TYPE_AFTER_LAST, ++ FM_MAP_TYPE_MAX = __FM_MAP_TYPE_AFTER_LAST - 1 ++}; ++ ++void compat_del_ptr2id(void *p, enum fm_map_node_type); ++compat_uptr_t compat_add_ptr2id(void *p, enum fm_map_node_type); ++compat_uptr_t compat_get_ptr2id(void *p, enum fm_map_node_type); ++void *compat_get_id2ptr(compat_uptr_t comp, enum fm_map_node_type); ++ ++static inline compat_uptr_t compat_pcd_ptr2id(void *ptr) { ++ return (ptr)? compat_get_ptr2id(ptr, FM_MAP_TYPE_PCD_NODE) ++ : (compat_uptr_t) 0; ++} ++ ++static inline void *compat_pcd_id2ptr(compat_uptr_t id) { ++ return (id) ? compat_get_id2ptr(id, FM_MAP_TYPE_PCD_NODE) ++ : NULL; ++} ++ ++/* other similar inlines may be added as new nodes are added ++ to enum fm_map_node_type above... */ ++/* } mapping kernel pointers w/ UserSpace id's */ ++ ++/* pcd compat structures { */ ++typedef struct ioc_compat_fm_pcd_cc_node_remove_key_params_t { ++ compat_uptr_t id; ++ uint16_t key_indx; ++} ioc_compat_fm_pcd_cc_node_remove_key_params_t; ++ ++typedef union ioc_compat_fm_pcd_plcr_next_engine_params_u { ++ ioc_fm_pcd_done_action action; ++ compat_uptr_t p_profile; ++ compat_uptr_t p_direct_scheme; ++} ioc_compat_fm_pcd_plcr_next_engine_params_u; ++ ++typedef struct ioc_compat_fm_pcd_plcr_profile_params_t { ++ bool modify; ++ union { ++ struct { ++ ioc_fm_pcd_profile_type_selection profile_type; ++ compat_uptr_t p_fm_port; ++ uint16_t relative_profile_id; ++ } new_params; ++ compat_uptr_t p_profile; ++ } profile_select; ++ ioc_fm_pcd_plcr_algorithm_selection alg_selection; ++ ioc_fm_pcd_plcr_color_mode color_mode; ++ ++ union { ++ ioc_fm_pcd_plcr_color dflt_color; ++ ioc_fm_pcd_plcr_color override; ++ } color; ++ ++ ioc_fm_pcd_plcr_non_passthrough_alg_param_t non_passthrough_alg_param; ++ ++ ioc_fm_pcd_engine next_engine_on_green; ++ ioc_compat_fm_pcd_plcr_next_engine_params_u params_on_green; ++ ++ ioc_fm_pcd_engine next_engine_on_yellow; ++ ioc_compat_fm_pcd_plcr_next_engine_params_u params_on_yellow; ++ ++ ioc_fm_pcd_engine next_engine_on_red; ++ ioc_compat_fm_pcd_plcr_next_engine_params_u params_on_red; ++ ++ bool trap_profile_on_flow_A; ++ bool trap_profile_on_flow_B; ++ bool trap_profile_on_flow_C; ++ compat_uptr_t id; ++} ioc_compat_fm_pcd_plcr_profile_params_t; ++ ++typedef struct ioc_compat_fm_obj_t { ++ compat_uptr_t obj; ++} ioc_compat_fm_obj_t; ++ ++typedef struct ioc_compat_fm_pcd_kg_scheme_select_t { ++ bool direct; ++ compat_uptr_t scheme_id; ++} ioc_compat_fm_pcd_kg_scheme_select_t; ++ ++typedef struct ioc_compat_fm_pcd_port_schemes_params_t { ++ uint8_t num_of_schemes; ++ compat_uptr_t scheme_ids[FM_PCD_KG_NUM_OF_SCHEMES]; ++} ioc_compat_fm_pcd_port_schemes_params_t; ++ ++#if (DPAA_VERSION >= 11) ++typedef struct ioc_compat_fm_port_vsp_alloc_params_t { ++ uint8_t num_of_profiles; /**< Number of Virtual Storage Profiles */ ++ uint8_t dflt_relative_id; /**< The default Virtual-Storage-Profile-id dedicated to Rx/OP port ++ The same default Virtual-Storage-Profile-id will be for coupled Tx port ++ if relevant function called for Rx port */ ++ compat_uptr_t p_fm_tx_port; /**< Handle to coupled Tx Port; not relevant for OP port. */ ++}ioc_compat_fm_port_vsp_alloc_params_t; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++typedef struct ioc_compat_fm_pcd_net_env_params_t { ++ uint8_t num_of_distinction_units; ++ ioc_fm_pcd_distinction_unit_t units[IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; /* same structure*/ ++ compat_uptr_t id; ++} ioc_compat_fm_pcd_net_env_params_t; ++ ++typedef struct ioc_compat_fm_pcd_prs_sw_params_t { ++ bool override; ++ uint32_t size; ++ uint16_t base; ++ compat_uptr_t p_code; ++ uint32_t sw_prs_data_params[IOC_FM_PCD_PRS_NUM_OF_HDRS]; ++ uint8_t num_of_labels; ++ ioc_fm_pcd_prs_label_params_t labels_table[IOC_FM_PCD_PRS_NUM_OF_LABELS]; ++} ioc_compat_fm_pcd_prs_sw_params_t; ++ ++typedef struct ioc_compat_fm_pcd_cc_next_kg_params_t { ++ bool override_fqid; ++ uint32_t new_fqid; ++#if DPAA_VERSION >= 11 ++ uint8_t new_relative_storage_profile_id; ++#endif ++ compat_uptr_t p_direct_scheme; ++} ioc_compat_fm_pcd_cc_next_kg_params_t; ++ ++typedef struct ioc_compat_fm_pcd_cc_next_cc_params_t { ++ compat_uptr_t cc_node_id; ++} ioc_compat_fm_pcd_cc_next_cc_params_t; ++ ++#if DPAA_VERSION >= 11 ++typedef struct ioc_compat_fm_pcd_cc_next_fr_params_t { ++ compat_uptr_t frm_replic_id; ++} ioc_compat_fm_pcd_cc_next_fr_params_t; ++#endif /* DPAA_VERSION >= 11 */ ++ ++typedef struct ioc_compat_fm_pcd_cc_next_engine_params_t { ++ ioc_fm_pcd_engine next_engine; ++ union { ++ ioc_compat_fm_pcd_cc_next_cc_params_t cc_params; /**< compat structure*/ ++ ioc_fm_pcd_cc_next_plcr_params_t plcr_params; /**< same structure*/ ++ ioc_fm_pcd_cc_next_enqueue_params_t enqueue_params; /**< same structure*/ ++ ioc_compat_fm_pcd_cc_next_kg_params_t kg_params; /**< compat structure*/ ++#if DPAA_VERSION >= 11 ++ ioc_compat_fm_pcd_cc_next_fr_params_t fr_params; /**< compat structure*/ ++#endif /* DPAA_VERSION >= 11 */ ++ } params; ++ compat_uptr_t manip_id; ++ bool statistics_en; ++} ioc_compat_fm_pcd_cc_next_engine_params_t; ++ ++typedef struct ioc_compat_fm_pcd_cc_grp_params_t { ++ uint8_t num_of_distinction_units; ++ uint8_t unit_ids [IOC_FM_PCD_MAX_NUM_OF_CC_UNITS]; ++ ioc_compat_fm_pcd_cc_next_engine_params_t next_engine_per_entries_in_grp[IOC_FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP]; ++} ioc_compat_fm_pcd_cc_grp_params_t; ++ ++typedef struct ioc_compat_fm_pcd_cc_tree_params_t { ++ compat_uptr_t net_env_id; ++ uint8_t num_of_groups; ++ ioc_compat_fm_pcd_cc_grp_params_t fm_pcd_cc_group_params [IOC_FM_PCD_MAX_NUM_OF_CC_GROUPS]; ++ compat_uptr_t id; ++} ioc_compat_fm_pcd_cc_tree_params_t; ++ ++typedef struct ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t { ++ compat_uptr_t id; ++ uint8_t grp_indx; ++ uint8_t indx; ++ ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params; ++} ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t; ++ ++typedef struct ioc_compat_fm_pcd_cc_key_params_t { ++ compat_uptr_t p_key; ++ compat_uptr_t p_mask; ++ ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params; /**< compat structure*/ ++} ioc_compat_fm_pcd_cc_key_params_t; ++ ++typedef struct ioc_compat_keys_params_t { ++ uint16_t max_num_of_keys; ++ bool mask_support; ++ ioc_fm_pcd_cc_stats_mode statistics_mode; ++#if (DPAA_VERSION >= 11) ++ uint16_t frame_length_ranges[IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR]; ++#endif /* (DPAA_VERSION >= 11) */ ++ uint16_t num_of_keys; ++ uint8_t key_size; ++ ioc_compat_fm_pcd_cc_key_params_t key_params[IOC_FM_PCD_MAX_NUM_OF_KEYS]; /**< compat structure*/ ++ ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params_for_miss; /**< compat structure*/ ++} ioc_compat_keys_params_t; ++ ++typedef struct ioc_compat_fm_pcd_cc_node_params_t { ++ ioc_fm_pcd_extract_entry_t extract_cc_params; /**< same structure*/ ++ ioc_compat_keys_params_t keys_params; /**< compat structure*/ ++ compat_uptr_t id; ++} ioc_compat_fm_pcd_cc_node_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining a hash table ++*//***************************************************************************/ ++typedef struct ioc_compat_fm_pcd_hash_table_params_t { ++ uint16_t max_num_of_keys; ++ ioc_fm_pcd_cc_stats_mode statistics_mode; ++ uint8_t kg_hash_shift; ++ uint16_t hash_res_mask; ++ uint8_t hash_shift; ++ uint8_t match_key_size; ++ ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params_for_miss; ++ compat_uptr_t id; ++} ioc_compat_fm_pcd_hash_table_params_t; ++ ++typedef struct ioc_compat_fm_pcd_hash_table_add_key_params_t { ++ compat_uptr_t p_hash_tbl; ++ uint8_t key_size; ++ ioc_compat_fm_pcd_cc_key_params_t key_params; ++} ioc_compat_fm_pcd_hash_table_add_key_params_t; ++ ++typedef struct ioc_compat_fm_pcd_cc_node_modify_key_params_t { ++ compat_uptr_t id; ++ uint16_t key_indx; ++ uint8_t key_size; ++ compat_uptr_t p_key; ++ compat_uptr_t p_mask; ++} ioc_compat_fm_pcd_cc_node_modify_key_params_t; ++ ++typedef struct ioc_compat_fm_pcd_hash_table_remove_key_params_t { ++ compat_uptr_t p_hash_tbl; ++ uint8_t key_size; ++ compat_uptr_t p_key; ++} ioc_compat_fm_pcd_hash_table_remove_key_params_t; ++ ++typedef struct ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t { ++ compat_uptr_t id; ++ uint16_t key_indx; ++ uint8_t key_size; ++ ioc_compat_fm_pcd_cc_key_params_t key_params; ++} ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t; ++ ++typedef struct ioc_compat_fm_port_pcd_plcr_params_t { ++ compat_uptr_t plcr_profile_id; ++} ioc_compat_fm_port_pcd_plcr_params_t; ++ ++typedef struct ioc_compat_fm_port_pcd_cc_params_t { ++ compat_uptr_t cc_tree_id; ++} ioc_compat_fm_port_pcd_cc_params_t; ++ ++typedef struct ioc_compat_fm_port_pcd_kg_params_t { ++ uint8_t num_of_schemes; ++ compat_uptr_t scheme_ids[FM_PCD_KG_NUM_OF_SCHEMES]; ++ bool direct_scheme; ++ compat_uptr_t direct_scheme_id; ++} ioc_compat_fm_port_pcd_kg_params_t; ++ ++typedef struct ioc_compat_fm_port_pcd_params_t { ++ ioc_fm_port_pcd_support pcd_support; ++ compat_uptr_t net_env_id; ++ compat_uptr_t p_prs_params; ++ compat_uptr_t p_cc_params; ++ compat_uptr_t p_kg_params; ++ compat_uptr_t p_plcr_params; ++ compat_uptr_t p_ip_reassembly_manip; ++#if DPAA_VERSION >= 11 ++ compat_uptr_t p_capwap_reassembly_manip; ++#endif ++} ioc_compat_fm_port_pcd_params_t; ++ ++typedef struct ioc_compat_fm_pcd_kg_cc_t { ++ compat_uptr_t tree_id; ++ uint8_t grp_id; ++ bool plcr_next; ++ bool bypass_plcr_profile_generation; ++ ioc_fm_pcd_kg_plcr_profile_t plcr_profile; ++} ioc_compat_fm_pcd_kg_cc_t; ++ ++typedef struct ioc_compat_fm_pcd_kg_scheme_params_t { ++ bool modify; ++ union { ++ uint8_t relative_scheme_id; ++ compat_uptr_t scheme_id; ++ } scm_id; ++ bool always_direct; ++ struct { ++ compat_uptr_t net_env_id; ++ uint8_t num_of_distinction_units; ++ uint8_t unit_ids[IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; ++ } net_env_params; ++ bool use_hash; ++ ioc_fm_pcd_kg_key_extract_and_hash_params_t key_extract_and_hash_params; ++ bool bypass_fqid_generation; ++ uint32_t base_fqid; ++ uint8_t num_of_used_extracted_ors; ++ ioc_fm_pcd_kg_extracted_or_params_t extracted_ors[IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS]; ++#if DPAA_VERSION >= 11 ++ bool override_storage_profile; ++ ioc_fm_pcd_kg_storage_profile_t storage_profile; ++#endif /* DPAA_VERSION >= 11 */ ++ ioc_fm_pcd_engine next_engine; ++ union{ ++ ioc_fm_pcd_done_action done_action; ++ ioc_fm_pcd_kg_plcr_profile_t plcr_profile; ++ ioc_compat_fm_pcd_kg_cc_t cc; ++ } kg_next_engine_params; ++ ioc_fm_pcd_kg_scheme_counter_t scheme_counter; ++ compat_uptr_t id; ++} ioc_compat_fm_pcd_kg_scheme_params_t; ++ ++typedef struct ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t { ++ compat_uptr_t id; ++ uint16_t key_indx; ++ uint8_t key_size; ++ ioc_compat_fm_pcd_cc_next_engine_params_t cc_next_engine_params; ++} ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t; ++ ++typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_generic_params_t { ++ uint8_t offset; ++ uint8_t size; ++ bool replace; ++ compat_uptr_t p_data; ++} ioc_compat_fm_pcd_manip_hdr_insrt_generic_params_t; ++ ++typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_specific_l2_params_t { ++ ioc_fm_pcd_manip_hdr_insrt_specific_l2 specific_l2; ++ bool update; ++ uint8_t size; ++ compat_uptr_t p_data; ++} ioc_compat_fm_pcd_manip_hdr_insrt_specific_l2_params_t; ++ ++typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_t { ++ uint8_t size; /**< size of inserted section */ ++ compat_uptr_t p_data; /**< data to be inserted */ ++} ioc_compat_fm_pcd_manip_hdr_insrt_t; ++ ++#if (DPAA_VERSION >= 11) ++typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_ip_params_t { ++ bool calc_l4_checksum; /**< Calculate L4 checksum. */ ++ ioc_fm_pcd_manip_hdr_qos_mapping_mode mapping_mode; /**< TODO */ ++ uint8_t last_pid_offset; /**< the offset of the last Protocol within ++ the inserted header */ ++ uint16_t id; /**< 16 bit New IP ID */ ++ bool dont_frag_overwrite; ++ /**< IPv4 only. DF is overwritten with the hash-result next-to-last byte. ++ * This byte is configured to be overwritten when RPD is set. */ ++ uint8_t last_dst_offset; ++ /**< IPv6 only. if routing extension exist, user should set the offset of the destination address ++ * in order to calculate UDP checksum pseudo header; ++ * Otherwise set it to '0'. */ ++ ioc_compat_fm_pcd_manip_hdr_insrt_t insrt; /**< size and data to be inserted. */ ++} ioc_compat_fm_pcd_manip_hdr_insrt_ip_params_t; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_by_hdr_params_t { ++ ioc_fm_pcd_manip_hdr_insrt_by_hdr_type type; ++ union { ++ ioc_compat_fm_pcd_manip_hdr_insrt_specific_l2_params_t specific_l2_params; ++#if (DPAA_VERSION >= 11) ++ ioc_compat_fm_pcd_manip_hdr_insrt_ip_params_t ip_params; ++ ioc_compat_fm_pcd_manip_hdr_insrt_t insrt; ++#endif /* (DPAA_VERSION >= 11) */ ++ } u; ++} ioc_compat_fm_pcd_manip_hdr_insrt_by_hdr_params_t; ++ ++typedef struct ioc_compat_fm_pcd_manip_hdr_insrt_params_t { ++ ioc_fm_pcd_manip_hdr_insrt_type type; ++ union { ++ ioc_compat_fm_pcd_manip_hdr_insrt_by_hdr_params_t by_hdr; ++ ioc_compat_fm_pcd_manip_hdr_insrt_generic_params_t generic; ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++#error "FM_CAPWAP_SUPPORT feature not supported!" ++ ioc_fm_pcd_manip_hdr_insrt_by_template_params_t by_template; ++#endif /* FM_CAPWAP_SUPPORT */ ++ } u; ++} ioc_compat_fm_pcd_manip_hdr_insrt_params_t; ++ ++typedef struct ioc_compat_fm_pcd_manip_hdr_params_t { ++ bool rmv; ++ ioc_fm_pcd_manip_hdr_rmv_params_t rmv_params; ++ bool insrt; ++ ioc_compat_fm_pcd_manip_hdr_insrt_params_t insrt_params; ++ bool field_update; ++ ioc_fm_pcd_manip_hdr_field_update_params_t field_update_params; ++ bool custom; ++ ioc_fm_pcd_manip_hdr_custom_params_t custom_params; ++ bool dont_parse_after_manip; ++} ioc_compat_fm_pcd_manip_hdr_params_t; ++ ++typedef struct ioc_compat_fm_pcd_manip_special_offload_params_t { ++ bool decryption; ++ bool ecn_copy; ++ bool dscp_copy; ++ bool variable_ip_hdr_len; ++ bool variable_ip_version; ++ uint8_t outer_ip_hdr_len; ++ uint16_t arw_size; ++ compat_uptr_t arw_addr; ++} ioc_compat_fm_pcd_manip_special_offload_params_t; ++ ++typedef struct ioc_compat_fm_pcd_manip_params_t { ++ ioc_fm_pcd_manip_type type; ++ union { ++ ioc_compat_fm_pcd_manip_hdr_params_t hdr; ++ ioc_fm_pcd_manip_reassem_params_t reassem; ++ ioc_fm_pcd_manip_frag_params_t frag; ++ ioc_compat_fm_pcd_manip_special_offload_params_t special_offload; ++ } u; ++ compat_uptr_t p_next_manip; ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++#error "FM_CAPWAP_SUPPORT feature not supported!" ++ bool frag_or_reasm; ++ ioc_fm_pcd_manip_frag_or_reasm_params_t frag_or_reasm_params; ++#endif /* FM_CAPWAP_SUPPORT */ ++ compat_uptr_t id; ++} ioc_compat_fm_pcd_manip_params_t; ++ ++typedef struct ioc_compat_fm_pcd_manip_get_stats_t { ++ compat_uptr_t id; ++ ioc_fm_pcd_manip_stats_t stats; ++} ioc_compat_fm_pcd_manip_get_stats_t; ++ ++#if (DPAA_VERSION >= 11) ++typedef struct ioc_compat_fm_pcd_frm_replic_group_params_t { ++ uint8_t max_num_of_entries; ++ uint8_t num_of_entries; ++ ioc_compat_fm_pcd_cc_next_engine_params_t ++ next_engine_params[IOC_FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES]; ++ compat_uptr_t id; ++} ioc_compat_fm_pcd_frm_replic_group_params_t; ++ ++typedef struct ioc_compat_fm_pcd_frm_replic_member_t { ++ compat_uptr_t h_replic_group; ++ uint16_t member_index; ++} ioc_compat_fm_pcd_frm_replic_member_t; ++ ++typedef struct ioc_compat_fm_pcd_frm_replic_member_params_t { ++ ioc_compat_fm_pcd_frm_replic_member_t member; ++ ioc_compat_fm_pcd_cc_next_engine_params_t next_engine_params; ++} ioc_compat_fm_pcd_frm_replic_member_params_t; ++ ++typedef struct ioc_compat_fm_vsp_params_t { ++ compat_uptr_t p_fm; /**< A handle to the FM object this VSP related to */ ++ ioc_fm_ext_pools ext_buf_pools; /**< Which external buffer pools are used ++ (up to FM_PORT_MAX_NUM_OF_EXT_POOLS), and their sizes. ++ parameter associated with Rx / OP port */ ++ uint16_t liodn_offset; /**< VSP's LIODN offset */ ++ struct { ++ ioc_fm_port_type port_type; /**< Port type */ ++ uint8_t port_id; /**< Port Id - relative to type */ ++ } port_params; ++ uint8_t relative_profile_id; /**< VSP Id - relative to VSP's range ++ defined in relevant FM object */ ++ compat_uptr_t id; /**< return value */ ++} ioc_compat_fm_vsp_params_t; ++ ++typedef struct ioc_compat_fm_buf_pool_depletion_params_t { ++ compat_uptr_t p_fm_vsp; ++ ioc_fm_buf_pool_depletion_t fm_buf_pool_depletion; ++} ioc_compat_fm_buf_pool_depletion_params_t; ++ ++typedef struct ioc_compat_fm_buffer_prefix_content_params_t { ++ compat_uptr_t p_fm_vsp; ++ ioc_fm_buffer_prefix_content_t fm_buffer_prefix_content; ++} ioc_compat_fm_buffer_prefix_content_params_t; ++ ++typedef struct ioc_compat_fm_vsp_config_no_sg_params_t { ++ compat_uptr_t p_fm_vsp; ++ bool no_sg; ++} ioc_compat_fm_vsp_config_no_sg_params_t; ++ ++typedef struct ioc_compat_fm_vsp_prs_result_params_t { ++ compat_uptr_t p_fm_vsp; ++ compat_uptr_t p_data; ++} ioc_compat_fm_vsp_prs_result_params_t; ++ ++#endif /* (DPAA_VERSION >= 11) */ ++typedef struct ioc_compat_fm_pcd_kg_scheme_spc_t { ++ uint32_t val; ++ compat_uptr_t id; ++} ioc_compat_fm_pcd_kg_scheme_spc_t; ++ ++typedef struct ioc_compat_fm_ctrl_mon_counters_params_t { ++ uint8_t fm_ctrl_index; ++ compat_uptr_t p_mon; ++} ioc_compat_fm_ctrl_mon_counters_params_t; ++ ++typedef struct ioc_compat_fm_pcd_cc_tbl_get_stats_t { ++ compat_uptr_t id; ++ uint16_t key_index; ++ ioc_fm_pcd_cc_key_statistics_t statistics; ++} ioc_compat_fm_pcd_cc_tbl_get_stats_t; ++ ++ ++/* } pcd compat structures */ ++ ++void compat_obj_delete( ++ ioc_compat_fm_obj_t *compat_id, ++ ioc_fm_obj_t *id); ++ ++/* pcd compat functions { */ ++void compat_copy_fm_pcd_plcr_profile( ++ ioc_compat_fm_pcd_plcr_profile_params_t *compat_param, ++ ioc_fm_pcd_plcr_profile_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_pcd_cc_key( ++ ioc_compat_fm_pcd_cc_key_params_t *compat_param, ++ ioc_fm_pcd_cc_key_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_pcd_cc_node_modify_key_and_next_engine( ++ ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t *compat_param, ++ ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_pcd_cc_node_modify_next_engine( ++ ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t *compat_param, ++ ioc_fm_pcd_cc_node_modify_next_engine_params_t *param, ++ uint8_t compat); ++ ++void compat_fm_pcd_cc_tree_modify_next_engine( ++ ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t *compat_param, ++ ioc_fm_pcd_cc_tree_modify_next_engine_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_pcd_hash_table( ++ ioc_compat_fm_pcd_hash_table_params_t *compat_param, ++ ioc_fm_pcd_hash_table_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_pcd_cc_grp( ++ ioc_compat_fm_pcd_cc_grp_params_t *compat_param, ++ ioc_fm_pcd_cc_grp_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_pcd_cc_tree( ++ ioc_compat_fm_pcd_cc_tree_params_t *compat_param, ++ ioc_fm_pcd_cc_tree_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_pcd_cc_tbl_get_stats( ++ ioc_compat_fm_pcd_cc_tbl_get_stats_t *compat_param, ++ ioc_fm_pcd_cc_tbl_get_stats_t *param, ++ uint8_t compat); ++ ++void compat_fm_pcd_prs_sw( ++ ioc_compat_fm_pcd_prs_sw_params_t *compat_param, ++ ioc_fm_pcd_prs_sw_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_pcd_kg_scheme( ++ ioc_compat_fm_pcd_kg_scheme_params_t *compat_param, ++ ioc_fm_pcd_kg_scheme_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_pcd_kg_scheme_select( ++ ioc_compat_fm_pcd_kg_scheme_select_t *compat_param, ++ ioc_fm_pcd_kg_scheme_select_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_pcd_kg_schemes_params( ++ ioc_compat_fm_pcd_port_schemes_params_t *compat_param, ++ ioc_fm_pcd_port_schemes_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_port_pcd_kg( ++ ioc_compat_fm_port_pcd_kg_params_t *compat_param, ++ ioc_fm_port_pcd_kg_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_port_pcd( ++ ioc_compat_fm_port_pcd_params_t *compat_param, ++ ioc_fm_port_pcd_params_t *param, ++ uint8_t compat); ++ ++#if (DPAA_VERSION >= 11) ++void compat_copy_fm_port_vsp_alloc_params( ++ ioc_compat_fm_port_vsp_alloc_params_t *compat_param, ++ ioc_fm_port_vsp_alloc_params_t *param, ++ uint8_t compat); ++#endif /* (DPAA_VERSION >= 11) */ ++ ++void compat_copy_fm_pcd_net_env( ++ ioc_compat_fm_pcd_net_env_params_t *compat_param, ++ ioc_fm_pcd_net_env_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_pcd_cc_node_modify_key( ++ ioc_compat_fm_pcd_cc_node_modify_key_params_t *compat_param, ++ ioc_fm_pcd_cc_node_modify_key_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_keys( ++ ioc_compat_keys_params_t *compat_param, ++ ioc_keys_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_pcd_cc_node( ++ ioc_compat_fm_pcd_cc_node_params_t *compat_param, ++ ioc_fm_pcd_cc_node_params_t *param, ++ uint8_t compat); ++ ++void compat_fm_pcd_manip_set_node( ++ ioc_compat_fm_pcd_manip_params_t *compat_param, ++ ioc_fm_pcd_manip_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_pcd_manip_get_stats( ++ ioc_compat_fm_pcd_manip_get_stats_t *compat_param, ++ ioc_fm_pcd_manip_get_stats_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_port_pcd_modify_tree( ++ ioc_compat_fm_obj_t *compat_id, ++ ioc_fm_obj_t *id, ++ uint8_t compat); ++ ++#if (DPAA_VERSION >= 11) ++void compat_copy_fm_pcd_frm_replic_group_params( ++ ioc_compat_fm_pcd_frm_replic_group_params_t *compat_param, ++ ioc_fm_pcd_frm_replic_group_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_pcd_frm_replic_member( ++ ioc_compat_fm_pcd_frm_replic_member_t *compat_param, ++ ioc_fm_pcd_frm_replic_member_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_pcd_frm_replic_member_params( ++ ioc_compat_fm_pcd_frm_replic_member_params_t *compat_param, ++ ioc_fm_pcd_frm_replic_member_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_vsp_params( ++ ioc_compat_fm_vsp_params_t *compat_param, ++ ioc_fm_vsp_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_buf_pool_depletion_params( ++ ioc_compat_fm_buf_pool_depletion_params_t *compat_param, ++ ioc_fm_buf_pool_depletion_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_buffer_prefix_content_params( ++ ioc_compat_fm_buffer_prefix_content_params_t *compat_param, ++ ioc_fm_buffer_prefix_content_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_vsp_config_no_sg_params( ++ ioc_compat_fm_vsp_config_no_sg_params_t *compat_param, ++ ioc_fm_vsp_config_no_sg_params_t *param, ++ uint8_t compat); ++ ++void compat_copy_fm_vsp_prs_result_params( ++ ioc_compat_fm_vsp_prs_result_params_t *compat_param, ++ ioc_fm_vsp_prs_result_params_t *param, ++ uint8_t compat); ++ ++#endif /* (DPAA_VERSION >= 11) */ ++ ++void compat_copy_fm_pcd_kg_scheme_spc( ++ ioc_compat_fm_pcd_kg_scheme_spc_t *compat_param, ++ ioc_fm_pcd_kg_scheme_spc_t *param, ++ uint8_t compat); ++ ++/* } pcd compat functions */ ++#endif +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources.h b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources.h +new file mode 100644 +index 00000000..1b72e1d5 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources.h +@@ -0,0 +1,121 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ @File lnxwrp_resources.h ++ ++ @Description FMD wrapper resource allocation functions. ++ ++*/ ++ ++#ifndef LNXWRP_RESOURCES_H_ ++#define LNXWRP_RESOURCES_H_ ++ ++#if !defined(FMAN_RESOURCES_UNIT_TEST) ++#include "lnxwrp_fm.h" ++#else ++#include "lnxwrp_resources_ut.h" ++#endif ++ ++#define ROUND(X) ((2*(X)+1)/2) ++#define CEIL(X) ((X)+1) ++/* #define ROUND_DIV(X, Y) (((X)+(Y)/2)/(Y)) */ ++#define ROUND_DIV(X, Y) ((2*(X)+(Y))/(2*(Y))) ++#define CEIL_DIV(X, Y) (((X)+(Y)-1)/(Y)) ++ ++/* used for resource calculus */ ++#define DPDE_1G 2 /* DQDP 1g - from LLD: ++ DEFAULT_PORT_txFifoDeqPipelineDepth_1G */ ++#define DPDE_10G 8 /* DQDP 10g - from LLD: ++ DEFAULT_PORT_txFifoDeqPipelineDepth_10G */ ++ ++int fm_set_active_fman_ports(struct platform_device *of_dev, ++ t_LnxWrpFmDev *p_LnxWrpFmDev); ++ ++/* Calculate the fifosize based on MURAM allocation, number of ports, dpde ++ * value and s/g software support (! Kernel does not suport s/g). ++ * ++ * Algorithm summary: ++ * - Calculate the the minimum fifosize required for every type of port ++ * (TX,RX for 1G, 2.5G and 10G). ++ * - Set TX the minimum fifosize required. ++ * - Distribute the remaining buffers (after all TX were set) to RX ports ++ * based on: ++ * 1G RX = Remaining_buffers * 1/(1+2.5+10) ++ * 2.5G RX = Remaining_buffers * 2.5/(1+2.5+10) ++ * 10G RX = Remaining_buffers * 10/(1+2.5+10) ++ * - if the RX is smaller than the minimum required, then set the minimum ++ * required ++ * - In the end distribuite the leftovers if there are any (due to ++ * unprecise calculus) or if over allocation cat some buffers from all RX ++ * ports w/o pass over minimum required treshold, but if there must be ++ * pass the treshold in order to cat the over allocation ,then this ++ * configuration can not be set - KERN_ALERT. ++*/ ++int fm_precalculate_fifosizes(t_LnxWrpFmDev *p_LnxWrpFmDev, ++ int muram_fifo_size); ++ ++#if !defined(FMAN_RESOURCES_UNIT_TEST) ++int fm_config_precalculate_fifosize(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev); ++#endif ++ ++/* Compute FMan open DMA based on total number of open DMAs and ++ * number of available fman ports. ++ * ++ * By default 10g ports are set to input parameters. The other ports ++ * tries to keep the proportion rx=2tx open dmas or tresholds. ++ * ++ * If leftovers, then those will be set as shared. ++ * ++ * If after computing overflow appears, then it decrements open dma ++ * for all ports w/o cross the tresholds. If the tresholds are meet ++ * and is still overflow, then it returns error. ++*/ ++int fm_precalculate_open_dma(t_LnxWrpFmDev *p_LnxWrpFmDev, ++ int max_fm_open_dma, ++ int default_tx_10g_dmas, ++ int default_rx_10g_dmas, ++ int min_tx_10g_treshold, int min_rx_10g_treshold); ++ ++#if !defined(FMAN_RESOURCES_UNIT_TEST) ++int fm_config_precalculate_open_dma(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev); ++#endif ++ ++/* Compute FMan tnums based on available tnums and number of ports. ++ * Set defaults (minim tresholds) and then distribute leftovers.*/ ++int fm_precalculate_tnums(t_LnxWrpFmDev *p_LnxWrpFmDev, int max_fm_tnums); ++ ++#if !defined(FMAN_RESOURCES_UNIT_TEST) ++int fm_config_precalculate_tnums(t_LnxWrpFmPortDev *p_LnxWrpFmPortDev); ++#endif ++ ++#endif /* LNXWRP_RESOURCES_H_ */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.c +new file mode 100644 +index 00000000..6c06a5a6 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.c +@@ -0,0 +1,191 @@ ++/* Copyright (c) 2012 Freescale Semiconductor, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "lnxwrp_resources.h" ++#include "lnxwrp_resources_ut.h" ++ ++#define KILOBYTE 0x400 /* 1024 */ ++ ++typedef enum e_board_type { ++ e_p3041, ++ e_p4080, ++ e_p5020, ++ e_p1023 ++} e_board_type; ++ ++uint8_t board_type; ++uint32_t muram_size = 0; ++uint32_t dmas_num = 0; ++uint32_t task_num = 0; ++uint32_t frame_size = 0; ++uint32_t oh_num = 0; ++uint32_t num_ports_1g = 0; ++uint32_t num_ports_10g = 0; ++uint32_t num_ports_2g5 = 0; ++uint32_t fsl_fman_phy_maxfrm = 0; ++uint32_t dpa_rx_extra_headroom = 0; ++ ++void show_help(void){ ++ printf(" help: \n"); ++ printf(" -b -f -o -g1" ++ " -g10 -g25 \n"); ++ printf(" Maxim num of DMAS availbale: P3/P4/P5:32 , P1023:16 \n"); ++ printf(" Maxim num of TNUMs availbale: P3/P4/P5:128, P1023:32 \n"); ++ printf(" Muram size: P3/P4/P5:160K, P1023:64K \n"); ++ printf(" Number of ports:\n"); ++ printf(" P3/P5: 5p 1g, 1p 10g, 7p oh \n"); ++ printf(" P4 : 4p 1g, 1p 10g, 7p oh \n"); ++ printf(" P1 : 2p 1g, 0p 10g, 4p oh \n"); ++ printf(" MTU: Default:1522, Jumbo:9600 \n"); ++} ++ ++int fm_set_param(t_LnxWrpFmDev *p_LnxWrpFmDev) { ++ struct fm_active_ports *fm_active_ports_info = NULL; ++ fm_active_ports_info = &p_LnxWrpFmDev->fm_active_ports_info; ++ ++ switch(board_type){ ++ case e_p3041: ++ case e_p5020: ++ muram_size = 160*KILOBYTE; ++ dmas_num = 32; ++ task_num = 128; ++ if ((num_ports_1g+num_ports_2g5) > 5 || num_ports_10g > 1 || oh_num > 7) ++ goto err_fm_set_param; ++ break; ++ case e_p4080: ++ muram_size = 160*KILOBYTE; ++ dmas_num = 32; ++ task_num = 128; ++ if ((num_ports_1g+num_ports_2g5) > 4 || num_ports_10g > 1 || oh_num > 7) ++ goto err_fm_set_param; ++ break; ++ case e_p1023: ++ muram_size = 64*KILOBYTE; ++ dmas_num = 16; ++ task_num = 128; ++ if ((num_ports_1g+num_ports_2g5) > 2 || oh_num > 4) ++ goto err_fm_set_param; ++ break; ++ default: ++ goto err_fm_set_param; ++ break; ++ } ++ ++ p_LnxWrpFmDev->id = 0; ++ fsl_fman_phy_maxfrm = frame_size; ++ dpa_rx_extra_headroom = 0; /* ATTENTION: can be != 0 */ ++ fm_active_ports_info->num_oh_ports = oh_num; ++ fm_active_ports_info->num_tx_ports = num_ports_1g; ++ fm_active_ports_info->num_rx_ports = num_ports_1g; ++ fm_active_ports_info->num_tx25_ports = num_ports_2g5; ++ fm_active_ports_info->num_rx25_ports = num_ports_2g5; ++ fm_active_ports_info->num_tx10_ports = num_ports_10g; ++ fm_active_ports_info->num_rx10_ports = num_ports_10g; ++ ++ return 0; ++ ++err_fm_set_param: ++ printf(" ERR: To many ports!!! \n"); ++ return -1; ++} ++ ++int main (int argc, char *argv[]){ ++ t_LnxWrpFmDev LnxWrpFmDev; ++ t_LnxWrpFmDev *p_LnxWrpFmDev = &LnxWrpFmDev; ++ int tokens_cnt = 1; ++ ++ char *token = NULL; ++ ++ while(tokens_cnt < argc) ++ { ++ token = argv[tokens_cnt++]; ++ if (strcmp(token, "-b") == 0){ ++ if(strcmp(argv[tokens_cnt],"p3") == 0) ++ board_type = e_p3041; ++ else if(strcmp(argv[tokens_cnt],"p4") == 0) ++ board_type = e_p4080; ++ else if(strcmp(argv[tokens_cnt],"p5") == 0) ++ board_type = e_p5020; ++ else if(strcmp(argv[tokens_cnt],"p1") == 0) ++ board_type = e_p1023; ++ else ++ show_help(); ++ tokens_cnt++; ++ } ++ else if(strcmp(token, "-d") == 0){ ++ dmas_num = atoi(argv[tokens_cnt++]); ++ } ++ else if(strcmp(token, "-t") == 0) ++ task_num = atoi(argv[tokens_cnt++]); ++ else if(strcmp(token, "-f") == 0) ++ frame_size = atoi(argv[tokens_cnt++]); ++ else if(strcmp(token, "-o") == 0) ++ oh_num = atoi(argv[tokens_cnt++]); ++ else if(strcmp(token, "-g1") == 0) ++ num_ports_1g = atoi(argv[tokens_cnt++]); ++ else if(strcmp(token, "-g10") == 0) ++ num_ports_10g = atoi(argv[tokens_cnt++]); ++ else if(strcmp(token, "-g25") == 0) ++ num_ports_2g5 = atoi(argv[tokens_cnt++]); ++ else { ++ show_help(); ++ return -1; ++ } ++ } ++ ++ if(fm_set_param(p_LnxWrpFmDev) < 0){ ++ show_help(); ++ return -1; ++ } ++ ++ if(fm_precalculate_fifosizes( ++ p_LnxWrpFmDev, ++ 128*KILOBYTE) ++ != 0) ++ return -1; ++ if(fm_precalculate_open_dma( ++ p_LnxWrpFmDev, ++ dmas_num, /* max open dmas:dpaa_integration_ext.h */ ++ FM_DEFAULT_TX10G_OPENDMA, /* default TX 10g open dmas */ ++ FM_DEFAULT_RX10G_OPENDMA, /* default RX 10g open dmas */ ++ FM_10G_OPENDMA_MIN_TRESHOLD,/* TX 10g minimum treshold */ ++ FM_10G_OPENDMA_MIN_TRESHOLD)/* RX 10g minimum treshold */ ++ != 0) ++ return -1; ++ if(fm_precalculate_tnums( ++ p_LnxWrpFmDev, ++ task_num) /* max TNUMS: dpa integration file. */ ++ != 0) ++ return -1; ++ ++ return 0; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.h b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.h +new file mode 100644 +index 00000000..063946eb +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.h +@@ -0,0 +1,144 @@ ++/* Copyright (c) 2012 Freescale Semiconductor, Inc ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef FM_RESS_TEST_H_ ++#define FM_RESS_TEST_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define _Packed ++#define _PackedType __attribute__ ((packed)) ++#define MAX(x, y) (((x) > (y)) ? (x) : (y)) ++#define MIN(x, y) (((x) < (y)) ? (x) : (y)) ++#define KERN_ALERT "" ++#define KERN_INFO "" ++#define ASSERT_COND assert ++#define printk printf ++#define NET_IP_ALIGN 0 ++#define FM_FIFO_ALLOCATION_OLD_ALG ++ ++#if defined(CONFIG_FMAN_DISABLE_OH_AND_DISTRIBUTE_RESOURCES) ++#define FM_10G_OPENDMA_MIN_TRESHOLD 8 /* 10g minimum treshold if only HC is enabled and no OH port enabled */ ++#define FM_OPENDMA_RX_TX_RAPORT 2 /* RX = 2*TX */ ++#else ++#define FM_10G_OPENDMA_MIN_TRESHOLD 7 /* 10g minimum treshold if 7 OH ports are enabled */ ++#define FM_OPENDMA_RX_TX_RAPORT 1 /* RX = TX */ ++#endif ++#define FM_DEFAULT_TX10G_OPENDMA 8 /* default TX 10g open dmas */ ++#define FM_DEFAULT_RX10G_OPENDMA 8 /* default RX 10g open dmas */ ++ ++/* information about all active ports for an FMan. ++ * !Some ports may be disabled by u-boot, thus will not be available */ ++struct fm_active_ports { ++ uint32_t num_oh_ports; ++ uint32_t num_tx_ports; ++ uint32_t num_rx_ports; ++ uint32_t num_tx25_ports; ++ uint32_t num_rx25_ports; ++ uint32_t num_tx10_ports; ++ uint32_t num_rx10_ports; ++}; ++ ++/* FMan resources precalculated at fm probe based ++ * on available FMan port. */ ++struct fm_resource_settings { ++ /* buffers - fifo sizes */ ++ uint32_t tx1g_num_buffers; ++ uint32_t rx1g_num_buffers; ++ uint32_t tx2g5_num_buffers; /* Not supported yet by LLD */ ++ uint32_t rx2g5_num_buffers; /* Not supported yet by LLD */ ++ uint32_t tx10g_num_buffers; ++ uint32_t rx10g_num_buffers; ++ uint32_t oh_num_buffers; ++ uint32_t shared_ext_buffers; ++ ++ ++ /* open DMAs */ ++ uint32_t tx_1g_dmas; ++ uint32_t rx_1g_dmas; ++ uint32_t tx_2g5_dmas; /* Not supported yet by LLD */ ++ uint32_t rx_2g5_dmas; /* Not supported yet by LLD */ ++ uint32_t tx_10g_dmas; ++ uint32_t rx_10g_dmas; ++ uint32_t oh_dmas; ++ uint32_t shared_ext_open_dma; ++ ++ /* Tnums */ ++ uint32_t tx_1g_tnums; ++ uint32_t rx_1g_tnums; ++ uint32_t tx_2g5_tnums; /* Not supported yet by LLD */ ++ uint32_t rx_2g5_tnums; /* Not supported yet by LLD */ ++ uint32_t tx_10g_tnums; ++ uint32_t rx_10g_tnums; ++ uint32_t oh_tnums; ++ uint32_t shared_ext_tnums; ++}; ++ ++typedef struct { ++ uint8_t id; ++ struct fm_active_ports fm_active_ports_info; ++ struct fm_resource_settings fm_resource_settings_info; ++} t_LnxWrpFmDev; ++ ++typedef struct { ++ uint8_t id; ++} t_LnxWrpFmPortDev; ++ ++typedef _Packed struct t_FmPrsResult { ++ volatile uint8_t lpid; /**< Logical port id */ ++ volatile uint8_t shimr; /**< Shim header result */ ++ volatile uint16_t l2r; /**< Layer 2 result */ ++ volatile uint16_t l3r; /**< Layer 3 result */ ++ volatile uint8_t l4r; /**< Layer 4 result */ ++ volatile uint8_t cplan; /**< Classification plan id */ ++ volatile uint16_t nxthdr; /**< Next Header */ ++ volatile uint16_t cksum; /**< Checksum */ ++ volatile uint32_t lcv; /**< LCV */ ++ volatile uint8_t shim_off[3]; /**< Shim offset */ ++ volatile uint8_t eth_off; /**< ETH offset */ ++ volatile uint8_t llc_snap_off; /**< LLC_SNAP offset */ ++ volatile uint8_t vlan_off[2]; /**< VLAN offset */ ++ volatile uint8_t etype_off; /**< ETYPE offset */ ++ volatile uint8_t pppoe_off; /**< PPP offset */ ++ volatile uint8_t mpls_off[2]; /**< MPLS offset */ ++ volatile uint8_t ip_off[2]; /**< IP offset */ ++ volatile uint8_t gre_off; /**< GRE offset */ ++ volatile uint8_t l4_off; /**< Layer 4 offset */ ++ volatile uint8_t nxthdr_off; /**< Parser end point */ ++} _PackedType t_FmPrsResult; ++ ++#endif +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.make b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.make +new file mode 100644 +index 00000000..58009cd8 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_resources_ut.make +@@ -0,0 +1,28 @@ ++CC=gcc ++ ++LNXWRP_RESS_UT=lnxwrp_resources_ut ++OBJ=lnxwrp_resources ++ ++INC_PATH= ++LIB_PATH= ++ ++INC=$(addprefix -I,$(INC_PATH)) ++LIB=$(addprefix -L,$(LIB_PATH)) ++ ++CFLAGS= -gdwarf-2 -g -O0 -Wall ++XFLAGS= -DFMAN_RESOURCES_UNIT_TEST ++ ++all: $(LNXWRP_RESS_UT) ++ ++$(LNXWRP_RESS_UT):$(addsuffix .o,$(OBJ)) $(LNXWRP_RESS_UT).o ++ $(CC) -o $(LNXWRP_RESS_UT) $(LNXWRP_RESS_UT).o $(addsuffix .o,$(OBJ)) ++ ++%.o: %.c ++ @(echo " (CC) $@") ++ @($(CC) $(INC) $(CFLAGS) $(XFLAGS) -o $(@) -c $<) ++ ++.PHONY: clean ++ ++clean: ++ rm -f *.o ++ rm -f $(LNXWRP_RESS_UT) +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.c +new file mode 100644 +index 00000000..813771bf +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.c +@@ -0,0 +1,60 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ @File lnxwrp_sysfs.c ++ ++ @Description FM wrapper sysfs related functions. ++ ++*/ ++ ++#include ++#include "lnxwrp_sysfs.h" ++ ++uint8_t fm_find_statistic_counter_by_name(const char *attr_name, ++ const struct sysfs_stats_t *sysfs_stats, ++ uint8_t *offset) ++{ ++ int i = 0; ++ ++ while (sysfs_stats[i].stat_name != NULL) { ++ if (strcmp(sysfs_stats[i].stat_name, attr_name) == 0) { ++ if (offset != NULL) ++ *offset = i; ++ return sysfs_stats[i].stat_counter; ++ } ++ ++ i++; ++ } ++ WARN(1, "FMD: Should never get here!"); ++ return 0; ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.h b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.h +new file mode 100644 +index 00000000..2098b244 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs.h +@@ -0,0 +1,60 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef LNXWRP_SYSFS_H_ ++#define LNXWRP_SYSFS_H_ ++ ++/* Linux Headers ------------------- */ ++#include ++ ++#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) ++#define MODVERSIONS ++#endif ++#ifdef MODVERSIONS ++#include ++#endif /* MODVERSIONS */ ++ ++#include ++#include ++#include ++#include ++ ++struct sysfs_stats_t { ++ const char *stat_name; ++ uint8_t stat_counter; ++}; ++ ++uint8_t fm_find_statistic_counter_by_name(const char *attr_name, ++ const struct sysfs_stats_t *sysfs_stats, ++ uint8_t *offset); ++ ++#endif /* LNXWRP_SYSFS_H_ */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c +new file mode 100644 +index 00000000..1badbf98 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.c +@@ -0,0 +1,1855 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "lnxwrp_sysfs.h" ++#include "lnxwrp_sysfs_fm.h" ++#include "lnxwrp_fm.h" ++ ++#include "../../sdk_fman/Peripherals/FM/inc/fm_common.h" ++#include "../../sdk_fman/Peripherals/FM/Pcd/fm_pcd.h" ++#include "../../sdk_fman/Peripherals/FM/Pcd/fm_kg.h" ++#include "../../sdk_fman/Peripherals/FM/Pcd/fm_plcr.h" ++ ++#if defined(__ERR_MODULE__) ++#undef __ERR_MODULE__ ++#endif ++ ++#include "../../sdk_fman/Peripherals/FM/fm.h" ++#include ++ ++ ++static int fm_get_counter(void *h_fm, e_FmCounters cnt_e, uint32_t *cnt_val); ++ ++enum fm_dma_match_stats { ++ FM_DMA_COUNTERS_CMQ_NOT_EMPTY, ++ FM_DMA_COUNTERS_BUS_ERROR, ++ FM_DMA_COUNTERS_READ_BUF_ECC_ERROR, ++ FM_DMA_COUNTERS_WRITE_BUF_ECC_SYS_ERROR, ++ FM_DMA_COUNTERS_WRITE_BUF_ECC_FM_ERROR ++}; ++ ++static const struct sysfs_stats_t fm_sysfs_stats[] = { ++ /* FM statistics */ ++ { ++ .stat_name = "enq_total_frame", ++ .stat_counter = e_FM_COUNTERS_ENQ_TOTAL_FRAME, ++ }, ++ { ++ .stat_name = "deq_total_frame", ++ .stat_counter = e_FM_COUNTERS_DEQ_TOTAL_FRAME, ++ }, ++ { ++ .stat_name = "deq_0", ++ .stat_counter = e_FM_COUNTERS_DEQ_0, ++ }, ++ { ++ .stat_name = "deq_1", ++ .stat_counter = e_FM_COUNTERS_DEQ_1, ++ }, ++ { ++ .stat_name = "deq_2", ++ .stat_counter = e_FM_COUNTERS_DEQ_2, ++ }, ++ { ++ .stat_name = "deq_3", ++ .stat_counter = e_FM_COUNTERS_DEQ_3, ++ }, ++ { ++ .stat_name = "deq_from_default", ++ .stat_counter = e_FM_COUNTERS_DEQ_FROM_DEFAULT, ++ }, ++ { ++ .stat_name = "deq_from_context", ++ .stat_counter = e_FM_COUNTERS_DEQ_FROM_CONTEXT, ++ }, ++ { ++ .stat_name = "deq_from_fd", ++ .stat_counter = e_FM_COUNTERS_DEQ_FROM_FD, ++ }, ++ { ++ .stat_name = "deq_confirm", ++ .stat_counter = e_FM_COUNTERS_DEQ_CONFIRM, ++ }, ++ /* FM:DMA statistics */ ++ { ++ .stat_name = "cmq_not_empty", ++ .stat_counter = FM_DMA_COUNTERS_CMQ_NOT_EMPTY, ++ }, ++ { ++ .stat_name = "bus_error", ++ .stat_counter = FM_DMA_COUNTERS_BUS_ERROR, ++ }, ++ { ++ .stat_name = "read_buf_ecc_error", ++ .stat_counter = FM_DMA_COUNTERS_READ_BUF_ECC_ERROR, ++ }, ++ { ++ .stat_name = "write_buf_ecc_sys_error", ++ .stat_counter = FM_DMA_COUNTERS_WRITE_BUF_ECC_SYS_ERROR, ++ }, ++ { ++ .stat_name = "write_buf_ecc_fm_error", ++ .stat_counter = FM_DMA_COUNTERS_WRITE_BUF_ECC_FM_ERROR, ++ }, ++ /* FM:PCD statistics */ ++ { ++ .stat_name = "pcd_kg_total", ++ .stat_counter = e_FM_PCD_KG_COUNTERS_TOTAL, ++ }, ++ { ++ .stat_name = "pcd_plcr_yellow", ++ .stat_counter = e_FM_PCD_PLCR_COUNTERS_YELLOW, ++ }, ++ { ++ .stat_name = "pcd_plcr_red", ++ .stat_counter = e_FM_PCD_PLCR_COUNTERS_RED, ++ }, ++ { ++ .stat_name = "pcd_plcr_recolored_to_red", ++ .stat_counter = e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED, ++ }, ++ { ++ .stat_name = "pcd_plcr_recolored_to_yellow", ++ .stat_counter = e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW, ++ }, ++ { ++ .stat_name = "pcd_plcr_total", ++ .stat_counter = e_FM_PCD_PLCR_COUNTERS_TOTAL, ++ }, ++ { ++ .stat_name = "pcd_plcr_length_mismatch", ++ .stat_counter = e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH, ++ }, ++ { ++ .stat_name = "pcd_prs_parse_dispatch", ++ .stat_counter = e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH, ++ }, ++ { ++ .stat_name = "pcd_prs_l2_parse_result_returned", ++ .stat_counter = e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED, ++ }, ++ { ++ .stat_name = "pcd_prs_l3_parse_result_returned", ++ .stat_counter = e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED, ++ }, ++ { ++ .stat_name = "pcd_prs_l4_parse_result_returned", ++ .stat_counter = e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED, ++ }, ++ { ++ .stat_name = "pcd_prs_shim_parse_result_returned", ++ .stat_counter = e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED, ++ }, ++ { ++ .stat_name = "pcd_prs_l2_parse_result_returned_with_err", ++ .stat_counter = ++ e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR, ++ }, ++ { ++ .stat_name = "pcd_prs_l3_parse_result_returned_with_err", ++ .stat_counter = ++ e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR, ++ }, ++ { ++ .stat_name = "pcd_prs_l4_parse_result_returned_with_err", ++ .stat_counter = ++ e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR, ++ }, ++ { ++ .stat_name = "pcd_prs_shim_parse_result_returned_with_err", ++ .stat_counter = ++ e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR, ++ }, ++ { ++ .stat_name = "pcd_prs_soft_prs_cycles", ++ .stat_counter = e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES, ++ }, ++ { ++ .stat_name = "pcd_prs_soft_prs_stall_cycles", ++ .stat_counter = e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES, ++ }, ++ { ++ .stat_name = "pcd_prs_hard_prs_cycle_incl_stall_cycles", ++ .stat_counter = ++ e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES, ++ }, ++ { ++ .stat_name = "pcd_prs_muram_read_cycles", ++ .stat_counter = e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES, ++ }, ++ { ++ .stat_name = "pcd_prs_muram_read_stall_cycles", ++ .stat_counter = e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES, ++ }, ++ { ++ .stat_name = "pcd_prs_muram_write_cycles", ++ .stat_counter = e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES, ++ }, ++ { ++ .stat_name = "pcd_prs_muram_write_stall_cycles", ++ .stat_counter = e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES, ++ }, ++ { ++ .stat_name = "pcd_prs_fpm_command_stall_cycles", ++ .stat_counter = e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES, ++ }, ++ {} ++}; ++ ++ ++static ssize_t show_fm_risc_load(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++ unsigned long flags; ++ int m =0; ++ int err =0; ++ unsigned n = 0; ++ t_FmCtrlMon util; ++ uint8_t i =0 ; ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_wrp_fm_dev == NULL)) ++ return -EINVAL; ++ ++ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev) ++ return -EIO; ++ ++ local_irq_save(flags); ++ ++ /* Calculate risc load */ ++ FM_CtrlMonStart(p_wrp_fm_dev->h_Dev); ++ msleep(1000); ++ FM_CtrlMonStop(p_wrp_fm_dev->h_Dev); ++ ++ for (i = 0; i < FM_NUM_OF_CTRL; i++) { ++ err |= FM_CtrlMonGetCounters(p_wrp_fm_dev->h_Dev, i, &util); ++ m = snprintf(&buf[n],PAGE_SIZE,"\tRisc%u: util-%u%%, efficiency-%u%%\n", ++ i, util.percentCnt[0], util.percentCnt[1]); ++ n=m+n; ++ } ++ ++ local_irq_restore(flags); ++ ++ return n; ++} ++ ++/* Fm stats and regs dumps via sysfs */ ++static ssize_t show_fm_dma_stats(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++ t_FmDmaStatus dma_status; ++ unsigned long flags = 0; ++ unsigned n = 0; ++ uint8_t counter_value = 0, counter = 0; ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_wrp_fm_dev == NULL)) ++ return -EINVAL; ++ ++ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev) ++ return -EIO; ++ ++ counter = fm_find_statistic_counter_by_name( ++ attr->attr.name, ++ fm_sysfs_stats, NULL); ++ ++ local_irq_save(flags); ++ ++ memset(&dma_status, 0, sizeof(dma_status)); ++ FM_GetDmaStatus(p_wrp_fm_dev->h_Dev, &dma_status); ++ ++ switch (counter) { ++ case FM_DMA_COUNTERS_CMQ_NOT_EMPTY: ++ counter_value = dma_status.cmqNotEmpty; ++ break; ++ case FM_DMA_COUNTERS_BUS_ERROR: ++ counter_value = dma_status.busError; ++ break; ++ case FM_DMA_COUNTERS_READ_BUF_ECC_ERROR: ++ counter_value = dma_status.readBufEccError; ++ break; ++ case FM_DMA_COUNTERS_WRITE_BUF_ECC_SYS_ERROR: ++ counter_value = dma_status.writeBufEccSysError; ++ break; ++ case FM_DMA_COUNTERS_WRITE_BUF_ECC_FM_ERROR: ++ counter_value = dma_status.writeBufEccFmError; ++ break; ++ default: ++ WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__, ++ __func__); ++ break; ++ }; ++ ++ n = snprintf(buf, PAGE_SIZE, "\tFM %u counter: %c\n", ++ p_wrp_fm_dev->id, counter_value ? 'T' : 'F'); ++ ++ local_irq_restore(flags); ++ ++ return n; ++} ++ ++static ssize_t show_fm_stats(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++ unsigned long flags = 0; ++ unsigned n = 0, cnt_e = 0; ++ uint32_t cnt_val; ++ int err; ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_wrp_fm_dev == NULL)) ++ return -EINVAL; ++ ++ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev) ++ return -EIO; ++ ++ cnt_e = fm_find_statistic_counter_by_name( ++ attr->attr.name, ++ fm_sysfs_stats, NULL); ++ ++ err = fm_get_counter(p_wrp_fm_dev->h_Dev, ++ (e_FmCounters) cnt_e, &cnt_val); ++ ++ if (err) ++ return err; ++ ++ local_irq_save(flags); ++ ++ n = snprintf(buf, PAGE_SIZE, "\tFM %d counter: %d\n", ++ p_wrp_fm_dev->id, cnt_val); ++ ++ local_irq_restore(flags); ++ ++ return n; ++} ++ ++static ssize_t show_fm_muram_free_sz(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++ unsigned long flags = 0; ++ unsigned n = 0; ++ uint64_t muram_free_size = 0; ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_wrp_fm_dev == NULL)) ++ return -EINVAL; ++ ++ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev) ++ return -EIO; ++ ++ muram_free_size = FM_MURAM_GetFreeMemSize(p_wrp_fm_dev->h_MuramDev); ++ ++ local_irq_save(flags); ++ ++ n = snprintf(buf, PAGE_SIZE, "\tFM %d muram_free_size: %lld\n", ++ p_wrp_fm_dev->id, muram_free_size); ++ ++ local_irq_restore(flags); ++ ++ return n; ++} ++ ++static ssize_t show_fm_ctrl_code_ver(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++ unsigned long flags = 0; ++ unsigned n = 0; ++ t_FmCtrlCodeRevisionInfo rv_info; ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_wrp_fm_dev == NULL)) ++ return -EINVAL; ++ ++ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev) ++ return -EIO; ++ ++ FM_GetFmanCtrlCodeRevision((t_Fm *)p_wrp_fm_dev->h_Dev, &rv_info); ++ ++ local_irq_save(flags); ++ ++ FM_DMP_LN(buf, n, "- FM %d ctrl code pkg info:\n", p_wrp_fm_dev->id); ++ FM_DMP_LN(buf, n, "Package rev: %d\n", rv_info.packageRev); ++ FM_DMP_LN(buf, n, "major rev: %d\n", rv_info.majorRev); ++ FM_DMP_LN(buf, n, "minor rev: %d\n", rv_info.minorRev); ++ ++ local_irq_restore(flags); ++ ++ return n; ++} ++ ++static ssize_t show_fm_pcd_stats(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++ unsigned long flags = 0; ++ unsigned n = 0, counter = 0; ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_wrp_fm_dev == NULL)) ++ return -EINVAL; ++ ++ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev || ++ !p_wrp_fm_dev->h_PcdDev) ++ return -EIO; ++ ++ counter = fm_find_statistic_counter_by_name( ++ attr->attr.name, ++ fm_sysfs_stats, NULL); ++ ++ local_irq_save(flags); ++ ++ n = snprintf(buf, PAGE_SIZE, "\tFM %d counter: %d\n", ++ p_wrp_fm_dev->id, ++ FM_PCD_GetCounter(p_wrp_fm_dev->h_PcdDev, ++ (e_FmPcdCounters) counter)); ++ ++ local_irq_restore(flags); ++ ++ return n; ++} ++ ++static ssize_t show_fm_tnum_dbg(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ unsigned long flags; ++ unsigned n = 0; ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++#endif ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_wrp_fm_dev == NULL)) ++ return -EINVAL; ++ ++ local_irq_save(flags); ++ ++ if (!p_wrp_fm_dev->active) ++ return -EIO; ++ else { ++ int tn_s; ++ ++ if (!sscanf(attr->attr.name, "tnum_dbg_%d", &tn_s)) ++ return -EINVAL; ++ ++ n = fm_dump_tnum_dbg(p_wrp_fm_dev->h_Dev, ++ tn_s, tn_s + 15, buf, n); ++ } ++ local_irq_restore(flags); ++#else ++ ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, ++ "Debug level is too low to dump registers!!!\n"); ++ local_irq_restore(flags); ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++ return n; ++} ++ ++static ssize_t show_fm_cls_plan(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ unsigned long flags; ++ unsigned n = 0; ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++#endif ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_wrp_fm_dev == NULL)) ++ return -EINVAL; ++ ++ local_irq_save(flags); ++ ++ n = snprintf(buf, PAGE_SIZE, "\n FM-KG classification plan dump.\n"); ++ ++ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev) ++ return -EIO; ++ else { ++ int cpn; ++ ++ if (!sscanf(attr->attr.name, "cls_plan_%d", &cpn)) ++ return -EINVAL; ++ ++ n = fm_dump_cls_plan(p_wrp_fm_dev->h_PcdDev, cpn, buf, n); ++ } ++ local_irq_restore(flags); ++#else ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, ++ "Debug level is too low to dump registers!!!\n"); ++ local_irq_restore(flags); ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++ return n; ++} ++ ++static ssize_t show_fm_profiles(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ unsigned long flags; ++ unsigned n = 0; ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++#endif ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_wrp_fm_dev == NULL)) ++ return -EINVAL; ++ ++ local_irq_save(flags); ++ ++ n = snprintf(buf, PAGE_SIZE, "FM policer profile dump.\n"); ++ ++ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev) ++ return -EIO; ++ else { ++ int pn; ++ ++ if (!sscanf(attr->attr.name, "profile_%d", &pn)) ++ return -EINVAL; ++ ++ n = fm_profile_dump_regs(p_wrp_fm_dev->h_PcdDev, pn, buf, n); ++ } ++ local_irq_restore(flags); ++#else ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, ++ "Debug level is too low to dump registers!!!\n"); ++ local_irq_restore(flags); ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++ return n; ++} ++ ++static ssize_t show_fm_schemes(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ unsigned long flags; ++ unsigned n = 0; ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++#endif ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_wrp_fm_dev == NULL)) ++ return -EINVAL; ++ ++ local_irq_save(flags); ++ ++ n = snprintf(buf, PAGE_SIZE, "FM-KG driver schemes dump.\n"); ++ ++ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev) ++ return -EIO; ++ else { ++ int sn; ++ ++ if (!sscanf(attr->attr.name, "scheme_%d", &sn)) ++ return -EINVAL; ++ ++ n = fm_dump_scheme(p_wrp_fm_dev->h_PcdDev, sn, buf, n); ++ } ++ local_irq_restore(flags); ++#else ++ ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, ++ "Debug level is too low to dump registers!!!\n"); ++ local_irq_restore(flags); ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++ return n; ++} ++ ++/* FM */ ++static DEVICE_ATTR(enq_total_frame, S_IRUGO, show_fm_stats, NULL); ++static DEVICE_ATTR(deq_total_frame, S_IRUGO, show_fm_stats, NULL); ++static DEVICE_ATTR(fm_risc_load_val, S_IRUGO, show_fm_risc_load, NULL); ++static DEVICE_ATTR(deq_0, S_IRUGO, show_fm_stats, NULL); ++static DEVICE_ATTR(deq_1, S_IRUGO, show_fm_stats, NULL); ++static DEVICE_ATTR(deq_2, S_IRUGO, show_fm_stats, NULL); ++static DEVICE_ATTR(deq_3, S_IRUGO, show_fm_stats, NULL); ++static DEVICE_ATTR(deq_from_default, S_IRUGO, show_fm_stats, NULL); ++static DEVICE_ATTR(deq_from_context, S_IRUGO, show_fm_stats, NULL); ++static DEVICE_ATTR(deq_from_fd, S_IRUGO, show_fm_stats, NULL); ++static DEVICE_ATTR(deq_confirm, S_IRUGO, show_fm_stats, NULL); ++/* FM:DMA */ ++static DEVICE_ATTR(cmq_not_empty, S_IRUGO, show_fm_dma_stats, NULL); ++static DEVICE_ATTR(bus_error, S_IRUGO, show_fm_dma_stats, NULL); ++static DEVICE_ATTR(read_buf_ecc_error, S_IRUGO, show_fm_dma_stats, NULL); ++static DEVICE_ATTR(write_buf_ecc_sys_error, S_IRUGO, show_fm_dma_stats, NULL); ++static DEVICE_ATTR(write_buf_ecc_fm_error, S_IRUGO, show_fm_dma_stats, NULL); ++/* FM:PCD */ ++static DEVICE_ATTR(pcd_kg_total, S_IRUGO, show_fm_pcd_stats, NULL); ++static DEVICE_ATTR(pcd_plcr_yellow, S_IRUGO, show_fm_pcd_stats, NULL); ++static DEVICE_ATTR(pcd_plcr_red, S_IRUGO, show_fm_pcd_stats, NULL); ++static DEVICE_ATTR(pcd_plcr_recolored_to_red, S_IRUGO, show_fm_pcd_stats, ++ NULL); ++static DEVICE_ATTR(pcd_plcr_recolored_to_yellow, S_IRUGO, show_fm_pcd_stats, ++ NULL); ++static DEVICE_ATTR(pcd_plcr_total, S_IRUGO, show_fm_pcd_stats, NULL); ++static DEVICE_ATTR(pcd_plcr_length_mismatch, S_IRUGO, show_fm_pcd_stats, ++ NULL); ++static DEVICE_ATTR(pcd_prs_parse_dispatch, S_IRUGO, show_fm_pcd_stats, NULL); ++static DEVICE_ATTR(pcd_prs_l2_parse_result_returned, S_IRUGO, ++ show_fm_pcd_stats, NULL); ++static DEVICE_ATTR(pcd_prs_l3_parse_result_returned, S_IRUGO, ++ show_fm_pcd_stats, NULL); ++static DEVICE_ATTR(pcd_prs_l4_parse_result_returned, S_IRUGO, ++ show_fm_pcd_stats, NULL); ++static DEVICE_ATTR(pcd_prs_shim_parse_result_returned, S_IRUGO, ++ show_fm_pcd_stats, NULL); ++static DEVICE_ATTR(pcd_prs_l2_parse_result_returned_with_err, S_IRUGO, ++ show_fm_pcd_stats, NULL); ++static DEVICE_ATTR(pcd_prs_l3_parse_result_returned_with_err, S_IRUGO, ++ show_fm_pcd_stats, NULL); ++static DEVICE_ATTR(pcd_prs_l4_parse_result_returned_with_err, S_IRUGO, ++ show_fm_pcd_stats, NULL); ++static DEVICE_ATTR(pcd_prs_shim_parse_result_returned_with_err, S_IRUGO, ++ show_fm_pcd_stats, NULL); ++static DEVICE_ATTR(pcd_prs_soft_prs_cycles, S_IRUGO, show_fm_pcd_stats, NULL); ++static DEVICE_ATTR(pcd_prs_soft_prs_stall_cycles, S_IRUGO, show_fm_pcd_stats, ++ NULL); ++static DEVICE_ATTR(pcd_prs_hard_prs_cycle_incl_stall_cycles, S_IRUGO, ++ show_fm_pcd_stats, NULL); ++static DEVICE_ATTR(pcd_prs_muram_read_cycles, S_IRUGO, show_fm_pcd_stats, ++ NULL); ++static DEVICE_ATTR(pcd_prs_muram_read_stall_cycles, S_IRUGO, ++ show_fm_pcd_stats, NULL); ++static DEVICE_ATTR(pcd_prs_muram_write_cycles, S_IRUGO, show_fm_pcd_stats, ++ NULL); ++static DEVICE_ATTR(pcd_prs_muram_write_stall_cycles, S_IRUGO, ++ show_fm_pcd_stats, NULL); ++static DEVICE_ATTR(pcd_prs_fpm_command_stall_cycles, S_IRUGO, ++ show_fm_pcd_stats, NULL); ++ ++static DEVICE_ATTR(tnum_dbg_0, S_IRUGO, show_fm_tnum_dbg, NULL); ++static DEVICE_ATTR(tnum_dbg_16, S_IRUGO, show_fm_tnum_dbg, NULL); ++static DEVICE_ATTR(tnum_dbg_32, S_IRUGO, show_fm_tnum_dbg, NULL); ++static DEVICE_ATTR(tnum_dbg_48, S_IRUGO, show_fm_tnum_dbg, NULL); ++static DEVICE_ATTR(tnum_dbg_64, S_IRUGO, show_fm_tnum_dbg, NULL); ++static DEVICE_ATTR(tnum_dbg_80, S_IRUGO, show_fm_tnum_dbg, NULL); ++static DEVICE_ATTR(tnum_dbg_96, S_IRUGO, show_fm_tnum_dbg, NULL); ++static DEVICE_ATTR(tnum_dbg_112, S_IRUGO, show_fm_tnum_dbg, NULL); ++ ++static DEVICE_ATTR(cls_plan_0, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_1, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_2, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_3, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_4, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_5, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_6, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_7, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_8, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_9, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_10, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_11, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_12, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_13, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_14, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_15, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_16, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_17, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_18, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_19, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_20, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_21, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_22, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_23, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_24, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_25, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_26, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_27, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_28, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_29, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_30, S_IRUGO, show_fm_cls_plan, NULL); ++static DEVICE_ATTR(cls_plan_31, S_IRUGO, show_fm_cls_plan, NULL); ++ ++static DEVICE_ATTR(profile_0, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_1, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_2, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_3, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_4, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_5, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_6, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_7, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_8, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_9, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_10, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_11, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_12, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_13, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_14, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_15, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_16, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_17, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_18, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_19, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_20, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_21, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_22, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_23, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_24, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_25, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_26, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_27, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_28, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_29, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_30, S_IRUGO, show_fm_profiles, NULL); ++static DEVICE_ATTR(profile_31, S_IRUGO, show_fm_profiles, NULL); ++ ++static DEVICE_ATTR(scheme_0, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_1, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_2, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_3, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_4, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_5, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_6, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_7, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_8, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_9, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_10, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_11, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_12, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_13, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_14, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_15, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_16, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_17, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_18, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_19, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_20, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_21, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_22, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_23, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_24, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_25, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_26, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_27, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_28, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_29, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_30, S_IRUGO, show_fm_schemes, NULL); ++static DEVICE_ATTR(scheme_31, S_IRUGO, show_fm_schemes, NULL); ++ ++ ++static struct attribute *fm_dev_stats_attributes[] = { ++ &dev_attr_enq_total_frame.attr, ++ &dev_attr_deq_total_frame.attr, ++ &dev_attr_deq_0.attr, ++ &dev_attr_deq_1.attr, ++ &dev_attr_deq_2.attr, ++ &dev_attr_deq_3.attr, ++ &dev_attr_deq_from_default.attr, ++ &dev_attr_deq_from_context.attr, ++ &dev_attr_deq_from_fd.attr, ++ &dev_attr_deq_confirm.attr, ++ &dev_attr_cmq_not_empty.attr, ++ &dev_attr_bus_error.attr, ++ &dev_attr_read_buf_ecc_error.attr, ++ &dev_attr_write_buf_ecc_sys_error.attr, ++ &dev_attr_write_buf_ecc_fm_error.attr, ++ &dev_attr_pcd_kg_total.attr, ++ &dev_attr_pcd_plcr_yellow.attr, ++ &dev_attr_pcd_plcr_red.attr, ++ &dev_attr_pcd_plcr_recolored_to_red.attr, ++ &dev_attr_pcd_plcr_recolored_to_yellow.attr, ++ &dev_attr_pcd_plcr_total.attr, ++ &dev_attr_pcd_plcr_length_mismatch.attr, ++ &dev_attr_pcd_prs_parse_dispatch.attr, ++ &dev_attr_pcd_prs_l2_parse_result_returned.attr, ++ &dev_attr_pcd_prs_l3_parse_result_returned.attr, ++ &dev_attr_pcd_prs_l4_parse_result_returned.attr, ++ &dev_attr_pcd_prs_shim_parse_result_returned.attr, ++ &dev_attr_pcd_prs_l2_parse_result_returned_with_err.attr, ++ &dev_attr_pcd_prs_l3_parse_result_returned_with_err.attr, ++ &dev_attr_pcd_prs_l4_parse_result_returned_with_err.attr, ++ &dev_attr_pcd_prs_shim_parse_result_returned_with_err.attr, ++ &dev_attr_pcd_prs_soft_prs_cycles.attr, ++ &dev_attr_pcd_prs_soft_prs_stall_cycles.attr, ++ &dev_attr_pcd_prs_hard_prs_cycle_incl_stall_cycles.attr, ++ &dev_attr_pcd_prs_muram_read_cycles.attr, ++ &dev_attr_pcd_prs_muram_read_stall_cycles.attr, ++ &dev_attr_pcd_prs_muram_write_cycles.attr, ++ &dev_attr_pcd_prs_muram_write_stall_cycles.attr, ++ &dev_attr_pcd_prs_fpm_command_stall_cycles.attr, ++ NULL ++}; ++ ++static struct attribute *fm_dev_tnums_dbg_attributes[] = { ++ &dev_attr_tnum_dbg_0.attr, ++ &dev_attr_tnum_dbg_16.attr, ++ &dev_attr_tnum_dbg_32.attr, ++ &dev_attr_tnum_dbg_48.attr, ++ &dev_attr_tnum_dbg_64.attr, ++ &dev_attr_tnum_dbg_80.attr, ++ &dev_attr_tnum_dbg_96.attr, ++ &dev_attr_tnum_dbg_112.attr, ++ NULL ++}; ++ ++static struct attribute *fm_dev_cls_plans_attributes[] = { ++ &dev_attr_cls_plan_0.attr, ++ &dev_attr_cls_plan_1.attr, ++ &dev_attr_cls_plan_2.attr, ++ &dev_attr_cls_plan_3.attr, ++ &dev_attr_cls_plan_4.attr, ++ &dev_attr_cls_plan_5.attr, ++ &dev_attr_cls_plan_6.attr, ++ &dev_attr_cls_plan_7.attr, ++ &dev_attr_cls_plan_8.attr, ++ &dev_attr_cls_plan_9.attr, ++ &dev_attr_cls_plan_10.attr, ++ &dev_attr_cls_plan_11.attr, ++ &dev_attr_cls_plan_12.attr, ++ &dev_attr_cls_plan_13.attr, ++ &dev_attr_cls_plan_14.attr, ++ &dev_attr_cls_plan_15.attr, ++ &dev_attr_cls_plan_16.attr, ++ &dev_attr_cls_plan_17.attr, ++ &dev_attr_cls_plan_18.attr, ++ &dev_attr_cls_plan_19.attr, ++ &dev_attr_cls_plan_20.attr, ++ &dev_attr_cls_plan_21.attr, ++ &dev_attr_cls_plan_22.attr, ++ &dev_attr_cls_plan_23.attr, ++ &dev_attr_cls_plan_24.attr, ++ &dev_attr_cls_plan_25.attr, ++ &dev_attr_cls_plan_26.attr, ++ &dev_attr_cls_plan_27.attr, ++ &dev_attr_cls_plan_28.attr, ++ &dev_attr_cls_plan_29.attr, ++ &dev_attr_cls_plan_30.attr, ++ &dev_attr_cls_plan_31.attr, ++ NULL ++}; ++ ++static struct attribute *fm_dev_profiles_attributes[] = { ++ &dev_attr_profile_0.attr, ++ &dev_attr_profile_1.attr, ++ &dev_attr_profile_2.attr, ++ &dev_attr_profile_3.attr, ++ &dev_attr_profile_4.attr, ++ &dev_attr_profile_5.attr, ++ &dev_attr_profile_6.attr, ++ &dev_attr_profile_7.attr, ++ &dev_attr_profile_8.attr, ++ &dev_attr_profile_9.attr, ++ &dev_attr_profile_10.attr, ++ &dev_attr_profile_11.attr, ++ &dev_attr_profile_12.attr, ++ &dev_attr_profile_13.attr, ++ &dev_attr_profile_14.attr, ++ &dev_attr_profile_15.attr, ++ &dev_attr_profile_16.attr, ++ &dev_attr_profile_17.attr, ++ &dev_attr_profile_18.attr, ++ &dev_attr_profile_19.attr, ++ &dev_attr_profile_20.attr, ++ &dev_attr_profile_21.attr, ++ &dev_attr_profile_22.attr, ++ &dev_attr_profile_23.attr, ++ &dev_attr_profile_24.attr, ++ &dev_attr_profile_25.attr, ++ &dev_attr_profile_26.attr, ++ &dev_attr_profile_27.attr, ++ &dev_attr_profile_28.attr, ++ &dev_attr_profile_29.attr, ++ &dev_attr_profile_30.attr, ++ &dev_attr_profile_31.attr, ++ NULL ++}; ++ ++static struct attribute *fm_dev_schemes_attributes[] = { ++ &dev_attr_scheme_0.attr, ++ &dev_attr_scheme_1.attr, ++ &dev_attr_scheme_2.attr, ++ &dev_attr_scheme_3.attr, ++ &dev_attr_scheme_4.attr, ++ &dev_attr_scheme_5.attr, ++ &dev_attr_scheme_6.attr, ++ &dev_attr_scheme_7.attr, ++ &dev_attr_scheme_8.attr, ++ &dev_attr_scheme_9.attr, ++ &dev_attr_scheme_10.attr, ++ &dev_attr_scheme_11.attr, ++ &dev_attr_scheme_12.attr, ++ &dev_attr_scheme_13.attr, ++ &dev_attr_scheme_14.attr, ++ &dev_attr_scheme_15.attr, ++ &dev_attr_scheme_16.attr, ++ &dev_attr_scheme_17.attr, ++ &dev_attr_scheme_18.attr, ++ &dev_attr_scheme_19.attr, ++ &dev_attr_scheme_20.attr, ++ &dev_attr_scheme_21.attr, ++ &dev_attr_scheme_22.attr, ++ &dev_attr_scheme_23.attr, ++ &dev_attr_scheme_24.attr, ++ &dev_attr_scheme_25.attr, ++ &dev_attr_scheme_26.attr, ++ &dev_attr_scheme_27.attr, ++ &dev_attr_scheme_28.attr, ++ &dev_attr_scheme_29.attr, ++ &dev_attr_scheme_30.attr, ++ &dev_attr_scheme_31.attr, ++ NULL ++}; ++ ++static const struct attribute_group fm_dev_stats_attr_grp = { ++ .name = "statistics", ++ .attrs = fm_dev_stats_attributes ++}; ++ ++static const struct attribute_group fm_dev_tnums_dbg_attr_grp = { ++ .name = "tnums_dbg", ++ .attrs = fm_dev_tnums_dbg_attributes ++}; ++ ++static const struct attribute_group fm_dev_cls_plans_attr_grp = { ++ .name = "cls_plans", ++ .attrs = fm_dev_cls_plans_attributes ++}; ++ ++static const struct attribute_group fm_dev_schemes_attr_grp = { ++ .name = "schemes", ++ .attrs = fm_dev_schemes_attributes ++}; ++ ++static const struct attribute_group fm_dev_profiles_attr_grp = { ++ .name = "profiles", ++ .attrs = fm_dev_profiles_attributes ++}; ++ ++static ssize_t show_fm_regs(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ unsigned long flags; ++ unsigned n = 0; ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++#endif ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_wrp_fm_dev == NULL)) ++ return -EINVAL; ++ ++ local_irq_save(flags); ++ ++ n = snprintf(buf, PAGE_SIZE, "FM driver registers dump.\n"); ++ ++ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev) ++ return -EIO; ++ else ++ n = fm_dump_regs(p_wrp_fm_dev->h_Dev, buf, n); ++ ++ local_irq_restore(flags); ++#else ++ ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, ++ "Debug level is too low to dump registers!!!\n"); ++ local_irq_restore(flags); ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++ return n; ++} ++ ++static ssize_t show_fm_kg_pe_regs(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ unsigned long flags; ++ unsigned n = 0; ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++#endif ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_wrp_fm_dev == NULL)) ++ return -EINVAL; ++ ++ local_irq_save(flags); ++ ++ n = snprintf(buf, PAGE_SIZE, ++ "\n FM-KG Port Partition Config registers dump.\n"); ++ ++ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev) ++ return -EIO; ++ else ++ n = fm_kg_pe_dump_regs(p_wrp_fm_dev->h_PcdDev, buf, n); ++ ++ local_irq_restore(flags); ++#else ++ ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, ++ "Debug level is too low to dump registers!!!\n"); ++ local_irq_restore(flags); ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++ return n; ++} ++ ++static ssize_t show_fm_kg_regs(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ unsigned long flags; ++ unsigned n = 0; ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++#endif ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_wrp_fm_dev == NULL)) ++ return -EINVAL; ++ ++ local_irq_save(flags); ++ ++ n = snprintf(buf, PAGE_SIZE, "FM-KG registers dump.\n"); ++ ++ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev) ++ return -EIO; ++ else ++ n = fm_kg_dump_regs(p_wrp_fm_dev->h_PcdDev, buf, n); ++ ++ local_irq_restore(flags); ++#else ++ ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, ++ "Debug level is too low to dump registers!!!\n"); ++ local_irq_restore(flags); ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++ return n; ++} ++ ++ ++static ssize_t show_fm_fpm_regs(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ unsigned long flags; ++ unsigned n = 0; ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++#endif ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_wrp_fm_dev == NULL)) ++ return -EINVAL; ++ ++ local_irq_save(flags); ++ ++ n = snprintf(buf, PAGE_SIZE, "FM-FPM registers dump.\n"); ++ ++ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_Dev) ++ return -EIO; ++ else ++ n = fm_fpm_dump_regs(p_wrp_fm_dev->h_Dev, buf, n); ++ ++ local_irq_restore(flags); ++#else ++ ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, ++ "Debug level is too low to dump registers!!!\n"); ++ local_irq_restore(flags); ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++ return n; ++} ++ ++static ssize_t show_prs_regs(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ unsigned long flags; ++ unsigned n = 0; ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++#endif ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_wrp_fm_dev == NULL)) ++ return -EINVAL; ++ ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, "FM Policer registers dump.\n"); ++ ++ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev) ++ return -EIO; ++ else ++ n = fm_prs_dump_regs(p_wrp_fm_dev->h_PcdDev, buf, n); ++ ++ local_irq_restore(flags); ++#else ++ ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, ++ "Debug level is too low to dump registers!!!\n"); ++ local_irq_restore(flags); ++ ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++ return n; ++} ++ ++static ssize_t show_plcr_regs(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ unsigned long flags; ++ unsigned n = 0; ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++#endif ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_wrp_fm_dev == NULL)) ++ return -EINVAL; ++ ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, "FM Policer registers dump.\n"); ++ ++ if (!p_wrp_fm_dev->active || !p_wrp_fm_dev->h_PcdDev) ++ return -EIO; ++ else ++ n = fm_plcr_dump_regs(p_wrp_fm_dev->h_PcdDev, buf, n); ++ ++ local_irq_restore(flags); ++#else ++ ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, ++ "Debug level is too low to dump registers!!!\n"); ++ local_irq_restore(flags); ++ ++#endif /* (defined(DEBUG_ERRORS) && ... */ ++ ++ return n; ++} ++ ++static DEVICE_ATTR(fm_regs, S_IRUGO, show_fm_regs, NULL); ++static DEVICE_ATTR(fm_fpm_regs, S_IRUGO, show_fm_fpm_regs, NULL); ++static DEVICE_ATTR(fm_kg_regs, S_IRUGO, show_fm_kg_regs, NULL); ++static DEVICE_ATTR(fm_kg_pe_regs, S_IRUGO, show_fm_kg_pe_regs, NULL); ++static DEVICE_ATTR(fm_plcr_regs, S_IRUGO, show_plcr_regs, NULL); ++static DEVICE_ATTR(fm_prs_regs, S_IRUGO, show_prs_regs, NULL); ++static DEVICE_ATTR(fm_muram_free_size, S_IRUGO, show_fm_muram_free_sz, NULL); ++static DEVICE_ATTR(fm_ctrl_code_ver, S_IRUGO, show_fm_ctrl_code_ver, NULL); ++ ++int fm_sysfs_create(struct device *dev) ++{ ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++ ++ if (dev == NULL) ++ return -EIO; ++ ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ ++ /* store to remove them when module is disabled */ ++ p_wrp_fm_dev->dev_attr_regs = &dev_attr_fm_regs; ++ p_wrp_fm_dev->dev_attr_risc_load = &dev_attr_fm_risc_load_val; ++ p_wrp_fm_dev->dev_fm_fpm_attr_regs = &dev_attr_fm_fpm_regs; ++ p_wrp_fm_dev->dev_fm_kg_attr_regs = &dev_attr_fm_kg_regs; ++ p_wrp_fm_dev->dev_fm_kg_pe_attr_regs = &dev_attr_fm_kg_pe_regs; ++ p_wrp_fm_dev->dev_plcr_attr_regs = &dev_attr_fm_plcr_regs; ++ p_wrp_fm_dev->dev_prs_attr_regs = &dev_attr_fm_prs_regs; ++ p_wrp_fm_dev->dev_attr_muram_free_size = &dev_attr_fm_muram_free_size; ++ p_wrp_fm_dev->dev_attr_fm_ctrl_code_ver = &dev_attr_fm_ctrl_code_ver; ++ ++ /* Create sysfs statistics group for FM module */ ++ if (sysfs_create_group(&dev->kobj, &fm_dev_stats_attr_grp) != 0) ++ return -EIO; ++ ++ if (sysfs_create_group(&dev->kobj, &fm_dev_schemes_attr_grp) != 0) ++ return -EIO; ++ ++ if (sysfs_create_group(&dev->kobj, &fm_dev_profiles_attr_grp) != 0) ++ return -EIO; ++ ++ if (sysfs_create_group(&dev->kobj, &fm_dev_tnums_dbg_attr_grp) != 0) ++ return -EIO; ++ ++ if (sysfs_create_group(&dev->kobj, &fm_dev_cls_plans_attr_grp) != 0) ++ return -EIO; ++ ++ /* Registers dump entry - in future will be moved to debugfs */ ++ if (device_create_file(dev, &dev_attr_fm_regs) != 0) ++ return -EIO; ++ ++ if (device_create_file(dev, &dev_attr_fm_risc_load_val) != 0) ++ return -EIO; ++ ++ if (device_create_file(dev, &dev_attr_fm_fpm_regs) != 0) ++ return -EIO; ++ ++ if (device_create_file(dev, &dev_attr_fm_kg_regs) != 0) ++ return -EIO; ++ ++ if (device_create_file(dev, &dev_attr_fm_kg_pe_regs) != 0) ++ return -EIO; ++ ++ if (device_create_file(dev, &dev_attr_fm_plcr_regs) != 0) ++ return -EIO; ++ ++ if (device_create_file(dev, &dev_attr_fm_prs_regs) != 0) ++ return -EIO; ++ ++ /* muram free size */ ++ if (device_create_file(dev, &dev_attr_fm_muram_free_size) != 0) ++ return -EIO; ++ ++ /* fm ctrl code version */ ++ if (device_create_file(dev, &dev_attr_fm_ctrl_code_ver) != 0) ++ return -EIO; ++ ++ return 0; ++} ++ ++void fm_sysfs_destroy(struct device *dev) ++{ ++ t_LnxWrpFmDev *p_wrp_fm_dev = NULL; ++ ++ if (WARN_ON(dev == NULL)) ++ return; ++ ++ p_wrp_fm_dev = (t_LnxWrpFmDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_wrp_fm_dev == NULL)) ++ return; ++ ++ sysfs_remove_group(&dev->kobj, &fm_dev_stats_attr_grp); ++ sysfs_remove_group(&dev->kobj, &fm_dev_schemes_attr_grp); ++ sysfs_remove_group(&dev->kobj, &fm_dev_profiles_attr_grp); ++ sysfs_remove_group(&dev->kobj, &fm_dev_cls_plans_attr_grp); ++ sysfs_remove_group(&dev->kobj, &fm_dev_tnums_dbg_attr_grp); ++ device_remove_file(dev, p_wrp_fm_dev->dev_attr_regs); ++ device_remove_file(dev, p_wrp_fm_dev->dev_fm_fpm_attr_regs); ++ device_remove_file(dev, p_wrp_fm_dev->dev_fm_kg_attr_regs); ++ device_remove_file(dev, p_wrp_fm_dev->dev_fm_kg_pe_attr_regs); ++ device_remove_file(dev, p_wrp_fm_dev->dev_plcr_attr_regs); ++ device_remove_file(dev, p_wrp_fm_dev->dev_prs_attr_regs); ++ device_remove_file(dev, p_wrp_fm_dev->dev_attr_muram_free_size); ++ device_remove_file(dev, p_wrp_fm_dev->dev_attr_fm_ctrl_code_ver); ++} ++ ++int fm_dump_regs(void *h_fm, char *buf, int nn) ++{ ++ t_Fm *p_Fm = (t_Fm *)h_fm; ++ uint8_t i = 0; ++ int n = nn; ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ ++ FM_DMP_TITLE(buf, n, p_Fm->p_FmDmaRegs, "FM-DMA Regs"); ++ ++ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmsr); ++ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmemsr); ++ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmmr); ++ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmtr); ++ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmhy); ++ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmsetr); ++ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmtah); ++ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmtal); ++ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmtcid); ++ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmra); ++ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmrd); ++ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmwcr); ++ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmebcr); ++ FM_DMP_V32(buf, n, p_Fm->p_FmDmaRegs, fmdmdcr); ++ ++ FM_DMP_TITLE(buf, n, &p_Fm->p_FmDmaRegs->fmdmplr, "fmdmplr"); ++ ++ for (i = 0; i < FM_MAX_NUM_OF_HW_PORT_IDS / 2 ; ++i) ++ FM_DMP_MEM_32(buf, n, &p_Fm->p_FmDmaRegs->fmdmplr[i]); ++ ++ FM_DMP_TITLE(buf, n, p_Fm->p_FmBmiRegs, "FM-BMI COMMON Regs"); ++ FM_DMP_V32(buf, n, p_Fm->p_FmBmiRegs, fmbm_init); ++ FM_DMP_V32(buf, n, p_Fm->p_FmBmiRegs, fmbm_cfg1); ++ FM_DMP_V32(buf, n, p_Fm->p_FmBmiRegs, fmbm_cfg2); ++ FM_DMP_V32(buf, n, p_Fm->p_FmBmiRegs, fmbm_ievr); ++ FM_DMP_V32(buf, n, p_Fm->p_FmBmiRegs, fmbm_ier); ++ ++ FM_DMP_TITLE(buf, n, &p_Fm->p_FmBmiRegs->fmbm_arb, "fmbm_arb"); ++ for (i = 0; i < 8 ; ++i) ++ FM_DMP_MEM_32(buf, n, &p_Fm->p_FmBmiRegs->fmbm_arb[i]); ++ ++ FM_DMP_TITLE(buf, n, p_Fm->p_FmQmiRegs, "FM-QMI COMMON Regs"); ++ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_gc); ++ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_eie); ++ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_eien); ++ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_eif); ++ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_ie); ++ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_ien); ++ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_if); ++ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_gs); ++ FM_DMP_V32(buf, n, p_Fm->p_FmQmiRegs, fmqm_etfc); ++ ++ return n; ++} ++ ++int fm_dump_tnum_dbg(void *h_fm, int tn_s, int tn_e, char *buf, int nn) ++{ ++ t_Fm *p_Fm = (t_Fm *)h_fm; ++ uint8_t i, j = 0; ++ int n = nn; ++ ++ FM_DMP_TITLE(buf, n, NULL, "Tnums and Tnum dbg regs %d - %d", ++ tn_s, tn_e); ++ ++ iowrite32be(tn_s << 24, &p_Fm->p_FmFpmRegs->fmfp_dra); ++ ++ mb(); ++ ++ for (j = tn_s; j <= tn_e; j++) { ++ FM_DMP_LN(buf, n, "> fmfp_ts[%d]\n", j); ++ FM_DMP_MEM_32(buf, n, &p_Fm->p_FmFpmRegs->fmfp_ts[j]); ++ FM_DMP_V32(buf, n, p_Fm->p_FmFpmRegs, fmfp_dra); ++ FM_DMP_LN(buf, n, "> fmfp_drd[0-3]\n"); ++ ++ for (i = 0; i < 4 ; ++i) ++ FM_DMP_MEM_32(buf, n, &p_Fm->p_FmFpmRegs->fmfp_drd[i]); ++ ++ FM_DMP_LN(buf, n, "\n"); ++ ++ } ++ ++ return n; ++} ++ ++int fm_dump_cls_plan(void *h_fm_pcd, int cpn, char *buf, int nn) ++{ ++ t_FmPcd *p_pcd = (t_FmPcd *)h_fm_pcd; ++ int i = 0; ++ uint32_t tmp; ++ unsigned long i_flg; ++ int n = nn; ++ u_FmPcdKgIndirectAccessRegs *idac; ++ spinlock_t *p_lk; ++ ++ p_lk = (spinlock_t *)p_pcd->p_FmPcdKg->h_HwSpinlock; ++ idac = p_pcd->p_FmPcdKg->p_IndirectAccessRegs; ++ ++ spin_lock_irqsave(p_lk, i_flg); ++ ++ /* Read ClsPlan Block Action Regs */ ++ tmp = (uint32_t)(FM_KG_KGAR_GO | ++ FM_KG_KGAR_READ | ++ FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY | ++ DUMMY_PORT_ID | ++ ((uint32_t)cpn << FM_PCD_KG_KGAR_NUM_SHIFT) | ++ FM_PCD_KG_KGAR_WSEL_MASK); ++ ++ if (fman_kg_write_ar_wait(p_pcd->p_FmPcdKg->p_FmPcdKgRegs, tmp)) { ++ FM_DMP_LN(buf, nn, "Keygen scheme access violation"); ++ spin_unlock_irqrestore(p_lk, i_flg); ++ return nn; ++ } ++ FM_DMP_TITLE(buf, n, &idac->clsPlanRegs, ++ "ClsPlan %d Indirect Access Regs", cpn); ++ ++ for (i = 0; i < 8; i++) ++ FM_DMP_MEM_32(buf, n, &idac->clsPlanRegs.kgcpe[i]); ++ ++ spin_unlock_irqrestore(p_lk, i_flg); ++ ++ return n; ++} ++ ++int fm_profile_dump_regs(void *h_fm_pcd, int ppn, char *buf, int nn) ++{ ++ t_FmPcd *p_pcd = (t_FmPcd *)h_fm_pcd; ++ t_FmPcdPlcrProfileRegs *p_prof_regs; ++ t_FmPcdPlcrRegs *p_plcr_regs; ++ t_FmPcdPlcr *p_plcr; ++ uint32_t tmp; ++ unsigned long i_flg; ++ int n = nn; ++ int toc = 10; ++ spinlock_t *p_lk; ++ ++ p_plcr = p_pcd->p_FmPcdPlcr; ++ p_prof_regs = &p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->profileRegs; ++ p_plcr_regs = p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; ++ ++ p_lk = (spinlock_t *)((t_FmPcdPlcr *)p_plcr)->h_HwSpinlock; ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ FM_DMP_TITLE(buf, n, p_plcr_regs, "FM-PCD policer-profile regs"); ++ ++ tmp = (uint32_t)(FM_PCD_PLCR_PAR_GO | ++ FM_PCD_PLCR_PAR_R | ++ ((uint32_t)ppn << FM_PCD_PLCR_PAR_PNUM_SHIFT) | ++ FM_PCD_PLCR_PAR_PWSEL_MASK); ++ ++ spin_lock_irqsave(p_lk, i_flg); ++ ++ iowrite32be(tmp, &p_plcr_regs->fmpl_par); ++ ++ mb(); ++ ++ /* wait for the porfile regs to be present */ ++ do { ++ --toc; ++ udelay(10); ++ if (!toc) { ++ /* looks like PLCR_PAR_GO refuses to clear */ ++ spin_unlock_irqrestore(p_lk, i_flg); ++ FM_DMP_LN(buf, n, "Profile regs not accessible -"); ++ FM_DMP_LN(buf, n, " check profile init process\n"); ++ return n; ++ } ++ } while ((ioread32be(&p_plcr_regs->fmpl_par) & FM_PCD_PLCR_PAR_GO)); ++ ++ FM_DMP_TITLE(buf, n, p_prof_regs, "Profile %d regs", ppn); ++ ++ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pemode); ++ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pegnia); ++ FM_DMP_V32(buf, n, p_prof_regs, fmpl_peynia); ++ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pernia); ++ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pecir); ++ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pecbs); ++ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pepepir_eir); ++ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pepbs_ebs); ++ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pelts); ++ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pects); ++ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pepts_ets); ++ FM_DMP_V32(buf, n, p_prof_regs, fmpl_pegpc); ++ FM_DMP_V32(buf, n, p_prof_regs, fmpl_peypc); ++ FM_DMP_V32(buf, n, p_prof_regs, fmpl_perpc); ++ FM_DMP_V32(buf, n, p_prof_regs, fmpl_perypc); ++ FM_DMP_V32(buf, n, p_prof_regs, fmpl_perrpc); ++ ++ spin_unlock_irqrestore(p_lk, i_flg); ++ ++ return n; ++} ++ ++int fm_dump_scheme(void *h_fm_pcd, int scnum, char *buf, int nn) ++{ ++ t_FmPcd *p_pcd = (t_FmPcd *)h_fm_pcd; ++ uint32_t tmp_ar; ++ unsigned long i_flg; ++ int i, n = nn; ++ spinlock_t *p_lk; ++ u_FmPcdKgIndirectAccessRegs *idac; ++ ++ idac = p_pcd->p_FmPcdKg->p_IndirectAccessRegs; ++ p_lk = (spinlock_t *)p_pcd->p_FmPcdKg->h_HwSpinlock; ++ ++ spin_lock_irqsave(p_lk, i_flg); ++ ++ tmp_ar = FmPcdKgBuildReadSchemeActionReg((uint8_t)scnum); ++ if (fman_kg_write_ar_wait(p_pcd->p_FmPcdKg->p_FmPcdKgRegs, tmp_ar)) { ++ FM_DMP_LN(buf, nn, ++ "Keygen scheme access violation or no such scheme"); ++ spin_unlock_irqrestore(p_lk, i_flg); ++ return nn; ++ } ++ ++ FM_DMP_TITLE(buf, n, &idac->schemeRegs, ++ "Scheme %d Indirect Access Regs", scnum); ++ ++ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_mode); ++ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_ekfc); ++ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_ekdv); ++ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_bmch); ++ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_bmcl); ++ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_fqb); ++ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_hc); ++ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_ppc); ++ ++ FM_DMP_TITLE(buf, n, &idac->schemeRegs.kgse_gec, "kgse_gec"); ++ ++ for (i = 0; i < FM_KG_NUM_OF_GENERIC_REGS; i++) ++ FM_DMP_MEM_32(buf, n, &idac->schemeRegs.kgse_gec[i]); ++ ++ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_spc); ++ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_dv0); ++ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_dv1); ++ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_ccbs); ++ FM_DMP_V32(buf, n, &idac->schemeRegs, kgse_mv); ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ ++ spin_unlock_irqrestore(p_lk, i_flg); ++ ++ return n; ++} ++ ++int fm_kg_pe_dump_regs(void *h_fm_pcd, char *buf, int nn) ++{ ++ t_FmPcd *p_pcd = (t_FmPcd *)h_fm_pcd; ++ int i = 0; ++ uint8_t prt_id = 0; ++ uint32_t tmp_ar; ++ unsigned long i_flg; ++ int n = nn; ++ u_FmPcdKgIndirectAccessRegs *idac; ++ t_FmPcdKg *p_kg; ++ spinlock_t *p_lk; ++ ++ p_kg = p_pcd->p_FmPcdKg; ++ idac = p_pcd->p_FmPcdKg->p_IndirectAccessRegs; ++ p_lk = (spinlock_t *)p_kg->h_HwSpinlock; ++ ++ spin_lock_irqsave(p_lk, i_flg); ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ ++ for (i = 0; i < FM_MAX_NUM_OF_PORTS; i++) { ++ SW_PORT_INDX_TO_HW_PORT_ID(prt_id, i); ++ ++ tmp_ar = FmPcdKgBuildReadPortSchemeBindActionReg(prt_id); ++ ++ if (fman_kg_write_ar_wait(p_kg->p_FmPcdKgRegs, tmp_ar)) { ++ FM_DMP_LN(buf, nn, "Keygen scheme access violation"); ++ spin_unlock_irqrestore(p_lk, i_flg); ++ return nn; ++ } ++ FM_DMP_TITLE(buf, n, &idac->portRegs, "Port %d regs", prt_id); ++ FM_DMP_V32(buf, n, &idac->portRegs, fmkg_pe_sp); ++ FM_DMP_V32(buf, n, &idac->portRegs, fmkg_pe_cpp); ++ } ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ ++ spin_unlock_irqrestore(p_lk, i_flg); ++ ++ return n; ++} ++ ++int fm_kg_dump_regs(void *h_fm_pcd, char *buf, int nn) ++{ ++ t_FmPcd *p_pcd = (t_FmPcd *)h_fm_pcd; ++ int n = nn; ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ FM_DMP_TITLE(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, ++ "FmPcdKgRegs Regs"); ++ ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_gcr); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_eer); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_eeer); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_seer); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_seeer); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_gsr); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_tpc); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_serc); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_fdor); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_gdv0r); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_gdv1r); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_feer); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdKg->p_FmPcdKgRegs, fmkg_ar); ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ ++ return n; ++} ++ ++ ++int fm_fpm_dump_regs(void *h_fm, char *buf, int nn) ++{ ++ t_Fm *p_fm = (t_Fm *)h_fm; ++ uint8_t i; ++ int n = nn; ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ ++ FM_DMP_TITLE(buf, n, p_fm->p_FmFpmRegs, "FM-FPM Regs"); ++ ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_tnc); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_prc); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_brkc); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_mxd); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_dist1); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_dist2); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_epi); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_rie); ++ ++ FM_DMP_TITLE(buf, n, &p_fm->p_FmFpmRegs->fmfp_fcev, "fmfp_fcev"); ++ for (i = 0; i < 4; ++i) ++ FM_DMP_MEM_32(buf, n, &p_fm->p_FmFpmRegs->fmfp_fcev[i]); ++ ++ FM_DMP_TITLE(buf, n, &p_fm->p_FmFpmRegs->fmfp_cee, "fmfp_cee"); ++ for (i = 0; i < 4; ++i) ++ FM_DMP_MEM_32(buf, n, &p_fm->p_FmFpmRegs->fmfp_cee[i]); ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_tsc1); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_tsc2); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_tsp); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_tsf); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_rcr); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_extc); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_ext1); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_ext2); ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_ip_rev_1); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_ip_rev_2); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_rstc); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_cld); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fm_npi); ++ FM_DMP_V32(buf, n, p_fm->p_FmFpmRegs, fmfp_ee); ++ ++ FM_DMP_TITLE(buf, n, &p_fm->p_FmFpmRegs->fmfp_cev, "fmfp_cev"); ++ for (i = 0; i < 4; ++i) ++ FM_DMP_MEM_32(buf, n, &p_fm->p_FmFpmRegs->fmfp_cev[i]); ++ ++ FM_DMP_TITLE(buf, n, &p_fm->p_FmFpmRegs->fmfp_ps, "fmfp_ps"); ++ for (i = 0; i < 64; ++i) ++ FM_DMP_MEM_32(buf, n, &p_fm->p_FmFpmRegs->fmfp_ps[i]); ++ ++ return n; ++} ++ ++int fm_prs_dump_regs(void *h_fm_pcd, char *buf, int nn) ++{ ++ t_FmPcd *p_pcd = (t_FmPcd *)h_fm_pcd; ++ int n = nn; ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ ++ FM_DMP_TITLE(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, ++ "FM-PCD parser regs"); ++ ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_rpclim); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_rpimac); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, pmeec); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_pevr); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_pever); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_perr); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_perer); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_ppsc); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_pds); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l2rrs); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l3rrs); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l4rrs); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_srrs); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l2rres); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l3rres); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_l4rres); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_srres); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_spcs); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_spscs); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_hxscs); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_mrcs); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_mwcs); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_mrscs); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_mwscs); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPrs->p_FmPcdPrsRegs, fmpr_fcscs); ++ ++ return n; ++} ++ ++int fm_plcr_dump_regs(void *h_fm_pcd, char *buf, int nn) ++{ ++ t_FmPcd *p_pcd = (t_FmPcd *)h_fm_pcd; ++ int i = 0; ++ int n = nn; ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ ++ FM_DMP_TITLE(buf, n, ++ p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, ++ "FM policer regs"); ++ ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_gcr); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_gsr); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_evr); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_ier); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_ifr); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_eevr); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_eier); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_eifr); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_rpcnt); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_ypcnt); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_rrpcnt); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_rypcnt); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_tpcnt); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_flmcnt); ++ ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_serc); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_upcr); ++ FM_DMP_V32(buf, n, p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs, fmpl_dpmr); ++ ++ FM_DMP_TITLE(buf, n, ++ &p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_pmr, ++ "fmpl_pmr"); ++ ++ for (i = 0; i < 63; ++i) ++ FM_DMP_MEM_32(buf, n, ++ &p_pcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_pmr[i]); ++ ++ return n; ++} ++ ++int fm_get_counter(void *h_fm, e_FmCounters cnt_e, uint32_t *cnt_val) ++{ ++ t_Fm *p_fm = (t_Fm *)h_fm; ++ ++ /* When applicable (when there is an "enable counters" bit), ++ check that counters are enabled */ ++ ++ switch (cnt_e) { ++ case (e_FM_COUNTERS_DEQ_1): ++ case (e_FM_COUNTERS_DEQ_2): ++ case (e_FM_COUNTERS_DEQ_3): ++ if (p_fm->p_FmStateStruct->revInfo.majorRev >= 6) ++ return -EINVAL; /* counter not available */ ++ ++ case (e_FM_COUNTERS_ENQ_TOTAL_FRAME): ++ case (e_FM_COUNTERS_DEQ_TOTAL_FRAME): ++ case (e_FM_COUNTERS_DEQ_0): ++ case (e_FM_COUNTERS_DEQ_FROM_DEFAULT): ++ case (e_FM_COUNTERS_DEQ_FROM_CONTEXT): ++ case (e_FM_COUNTERS_DEQ_FROM_FD): ++ case (e_FM_COUNTERS_DEQ_CONFIRM): ++ if (!(ioread32be(&p_fm->p_FmQmiRegs->fmqm_gc) & ++ QMI_CFG_EN_COUNTERS)) ++ return -EINVAL; /* Requested counter not available */ ++ break; ++ default: ++ break; ++ } ++ ++ switch (cnt_e) { ++ case (e_FM_COUNTERS_ENQ_TOTAL_FRAME): ++ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_etfc); ++ return 0; ++ case (e_FM_COUNTERS_DEQ_TOTAL_FRAME): ++ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dtfc); ++ return 0; ++ case (e_FM_COUNTERS_DEQ_0): ++ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dc0); ++ return 0; ++ case (e_FM_COUNTERS_DEQ_1): ++ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dc1); ++ return 0; ++ case (e_FM_COUNTERS_DEQ_2): ++ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dc2); ++ return 0; ++ case (e_FM_COUNTERS_DEQ_3): ++ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dc3); ++ return 0; ++ case (e_FM_COUNTERS_DEQ_FROM_DEFAULT): ++ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dfdc); ++ return 0; ++ case (e_FM_COUNTERS_DEQ_FROM_CONTEXT): ++ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dfcc); ++ return 0; ++ case (e_FM_COUNTERS_DEQ_FROM_FD): ++ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dffc); ++ return 0; ++ case (e_FM_COUNTERS_DEQ_CONFIRM): ++ *cnt_val = ioread32be(&p_fm->p_FmQmiRegs->fmqm_dcc); ++ return 0; ++ } ++ /* should never get here */ ++ return -EINVAL; /* counter not available */ ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.h b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.h +new file mode 100644 +index 00000000..137653e9 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm.h +@@ -0,0 +1,136 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++#ifndef LNXWRP_SYSFS_FM_H_ ++#define LNXWRP_SYSFS_FM_H_ ++ ++#include "lnxwrp_sysfs.h" ++ ++int fm_sysfs_create(struct device *dev); ++void fm_sysfs_destroy(struct device *dev); ++int fm_dump_regs(void *h_dev, char *buf, int nn); ++int fm_fpm_dump_regs(void *h_dev, char *buf, int nn); ++int fm_kg_dump_regs(void *h_pcd, char *buf, int nn); ++int fm_kg_pe_dump_regs(void *h_pcd, char *buf, int nn); ++int fm_dump_scheme(void *h_pcd, int scnum, char *buf, int nn); ++int fm_dump_tnum_dbg(void *h_fm, int tn_s, int tn_e, char *buf, int nn); ++int fm_dump_cls_plan(void *h_pcd, int cpn, char *buf, int nn); ++int fm_plcr_dump_regs(void *h_pcd, char *buf, int nn); ++int fm_prs_dump_regs(void *h_pcd, char *buf, int nn); ++int fm_profile_dump_regs(void *h_pcd, int ppnum, char *buf, int nn); ++ ++#define FM_DMP_PGSZ_ERR { \ ++ snprintf(&buf[PAGE_SIZE - 80], 70, \ ++ "\n Err: current sysfs buffer reached PAGE_SIZE\n");\ ++ n = PAGE_SIZE - 2; \ ++ } ++ ++#define FM_DMP_LN(buf, n, ...) \ ++ do { \ ++ int k, m = n; \ ++ m += k = snprintf(&buf[m], PAGE_SIZE - m, __VA_ARGS__); \ ++ if (k < 0 || m > PAGE_SIZE - 90) \ ++ FM_DMP_PGSZ_ERR \ ++ n = m; \ ++ } while (0) ++ ++#define FM_DMP_TITLE(buf, n, addr, ...) \ ++ do { \ ++ int k, m = n; \ ++ m += k = snprintf(&buf[m], PAGE_SIZE - m, "\n"); \ ++ if (k < 0 || m > PAGE_SIZE - 90) \ ++ FM_DMP_PGSZ_ERR \ ++ m += k = snprintf(&buf[m], PAGE_SIZE - m, __VA_ARGS__); \ ++ if (k < 0 || m > PAGE_SIZE - 90) \ ++ FM_DMP_PGSZ_ERR \ ++ if (addr) { \ ++ phys_addr_t pa; \ ++ pa = virt_to_phys(addr); \ ++ m += k = \ ++ snprintf(&buf[m], PAGE_SIZE - m, " (0x%lX)", \ ++ (long unsigned int)(pa)); \ ++ if (k < 0 || m > PAGE_SIZE - 90) \ ++ FM_DMP_PGSZ_ERR \ ++ } \ ++ m += k = snprintf(&buf[m], PAGE_SIZE - m, \ ++ "\n----------------------------------------\n\n"); \ ++ if (k < 0 || m > PAGE_SIZE - 90) \ ++ FM_DMP_PGSZ_ERR \ ++ n = m; \ ++ } while (0) ++ ++#define FM_DMP_SUBTITLE(buf, n, ...) \ ++ do { \ ++ int k, m = n; \ ++ m += k = snprintf(&buf[m], PAGE_SIZE - m, "------- "); \ ++ if (k < 0 || m > PAGE_SIZE - 90) \ ++ FM_DMP_PGSZ_ERR \ ++ m += k = snprintf(&buf[m], PAGE_SIZE - m, __VA_ARGS__); \ ++ if (k < 0 || m > PAGE_SIZE - 90) \ ++ FM_DMP_PGSZ_ERR \ ++ m += k = snprintf(&buf[m], PAGE_SIZE - m, "\n"); \ ++ if (k < 0 || m > PAGE_SIZE - 90) \ ++ FM_DMP_PGSZ_ERR \ ++ n = m; \ ++ } while (0) ++ ++#define FM_DMP_MEM_32(buf, n, addr) \ ++ { \ ++ uint32_t val; \ ++ phys_addr_t pa; \ ++ int k, m = n; \ ++ pa = virt_to_phys(addr); \ ++ val = ioread32be((addr)); \ ++ do { \ ++ m += k = snprintf(&buf[m], \ ++ PAGE_SIZE - m, "0x%010llX: 0x%08x\n", \ ++ pa, val); \ ++ if (k < 0 || m > PAGE_SIZE - 90) \ ++ FM_DMP_PGSZ_ERR \ ++ n += k; \ ++ } while (0) ;\ ++ } ++ ++#define FM_DMP_V32(buf, n, st, phrase) \ ++ do { \ ++ int k, m = n; \ ++ phys_addr_t pa = virt_to_phys(&((st)->phrase)); \ ++ k = snprintf(&buf[m], PAGE_SIZE - m, \ ++ "0x%010llX: 0x%08x%8s\t%s\n", (unsigned long long) pa, \ ++ ioread32be((uint32_t *)&((st)->phrase)), "", #phrase); \ ++ if (k < 0 || m > PAGE_SIZE - 90) \ ++ FM_DMP_PGSZ_ERR \ ++ n += k; \ ++ } while (0) ++ ++#endif /* LNXWRP_SYSFS_FM_H_ */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.c b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.c +new file mode 100644 +index 00000000..db8e824c +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.c +@@ -0,0 +1,1268 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "lnxwrp_sysfs.h" ++#include "lnxwrp_fm.h" ++#include "debug_ext.h" ++#include "lnxwrp_sysfs_fm_port.h" ++#include "lnxwrp_sysfs_fm.h" ++ ++#include "../../sdk_fman/Peripherals/FM/Port/fm_port.h" ++#include "../../sdk_fman/Peripherals/FM/Port/fm_port_dsar.h" ++ ++#if defined(__ERR_MODULE__) ++#undef __ERR_MODULE__ ++#endif ++ ++#include "../../sdk_fman/Peripherals/FM/fm.h" ++ ++static const struct sysfs_stats_t portSysfsStats[] = { ++ /* RX/TX/OH common statistics */ ++ { ++ .stat_name = "port_frame", ++ .stat_counter = e_FM_PORT_COUNTERS_FRAME, ++ }, ++ { ++ .stat_name = "port_discard_frame", ++ .stat_counter = e_FM_PORT_COUNTERS_DISCARD_FRAME, ++ }, ++ { ++ .stat_name = "port_dealloc_buf", ++ .stat_counter = e_FM_PORT_COUNTERS_DEALLOC_BUF, ++ }, ++ { ++ .stat_name = "port_enq_total", ++ .stat_counter = e_FM_PORT_COUNTERS_ENQ_TOTAL, ++ }, ++ /* TX/OH */ ++ { ++ .stat_name = "port_length_err", ++ .stat_counter = e_FM_PORT_COUNTERS_LENGTH_ERR, ++ }, ++ { ++ .stat_name = "port_unsupprted_format", ++ .stat_counter = e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT, ++ }, ++ { ++ .stat_name = "port_deq_total", ++ .stat_counter = e_FM_PORT_COUNTERS_DEQ_TOTAL, ++ }, ++ { ++ .stat_name = "port_deq_from_default", ++ .stat_counter = e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT, ++ }, ++ { ++ .stat_name = "port_deq_confirm", ++ .stat_counter = e_FM_PORT_COUNTERS_DEQ_CONFIRM, ++ }, ++ /* RX/OH */ ++ { ++ .stat_name = "port_rx_bad_frame", ++ .stat_counter = e_FM_PORT_COUNTERS_RX_BAD_FRAME, ++ }, ++ { ++ .stat_name = "port_rx_large_frame", ++ .stat_counter = e_FM_PORT_COUNTERS_RX_LARGE_FRAME, ++ }, ++ { ++ .stat_name = "port_rx_out_of_buffers_discard", ++ .stat_counter = e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD, ++ }, ++ { ++ .stat_name = "port_rx_filter_frame", ++ .stat_counter = e_FM_PORT_COUNTERS_RX_FILTER_FRAME, ++ }, ++ /* TODO: Particular statistics for OH ports */ ++ {} ++}; ++ ++static ssize_t show_fm_port_stats(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; ++ t_LnxWrpFmDev *p_LnxWrpFmDev; ++ unsigned long flags; ++ int n = 0; ++ uint8_t counter = 0; ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++ p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_LnxWrpFmPortDev == NULL)) ++ return -EINVAL; ++ ++ p_LnxWrpFmDev = (t_LnxWrpFmDev *) p_LnxWrpFmPortDev->h_LnxWrpFmDev; ++ if (WARN_ON(p_LnxWrpFmDev == NULL)) ++ return -EINVAL; ++ ++ if (!p_LnxWrpFmDev->active || !p_LnxWrpFmDev->h_Dev) ++ return -EIO; ++ ++ if (!p_LnxWrpFmPortDev->h_Dev) { ++ n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n"); ++ return n; ++ } ++ ++ counter = fm_find_statistic_counter_by_name( ++ attr->attr.name, ++ portSysfsStats, NULL); ++ ++ if (counter == e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR) { ++ uint32_t fmRev = 0; ++ fmRev = 0xffff & ++ ioread32(UINT_TO_PTR(p_LnxWrpFmDev->fmBaseAddr + ++ 0x000c30c4)); ++ ++ if (fmRev == 0x0100) { ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, ++ "counter not available for revision 1\n"); ++ local_irq_restore(flags); ++ } ++ return n; ++ } ++ ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, "\t%s counter: %u\n", ++ p_LnxWrpFmPortDev->name, ++ FM_PORT_GetCounter(p_LnxWrpFmPortDev->h_Dev, ++ (e_FmPortCounters) counter)); ++ local_irq_restore(flags); ++ ++ return n; ++} ++ ++/* FM PORT RX/TX/OH statistics */ ++static DEVICE_ATTR(port_frame, S_IRUGO, show_fm_port_stats, NULL); ++static DEVICE_ATTR(port_discard_frame, S_IRUGO, show_fm_port_stats, NULL); ++static DEVICE_ATTR(port_dealloc_buf, S_IRUGO, show_fm_port_stats, NULL); ++static DEVICE_ATTR(port_enq_total, S_IRUGO, show_fm_port_stats, NULL); ++/* FM PORT TX/OH statistics */ ++static DEVICE_ATTR(port_length_err, S_IRUGO, show_fm_port_stats, NULL); ++static DEVICE_ATTR(port_unsupprted_format, S_IRUGO, show_fm_port_stats, NULL); ++static DEVICE_ATTR(port_deq_total, S_IRUGO, show_fm_port_stats, NULL); ++static DEVICE_ATTR(port_deq_from_default, S_IRUGO, show_fm_port_stats, NULL); ++static DEVICE_ATTR(port_deq_confirm, S_IRUGO, show_fm_port_stats, NULL); ++/* FM PORT RX/OH statistics */ ++static DEVICE_ATTR(port_rx_bad_frame, S_IRUGO, show_fm_port_stats, NULL); ++static DEVICE_ATTR(port_rx_large_frame, S_IRUGO, show_fm_port_stats, NULL); ++static DEVICE_ATTR(port_rx_out_of_buffers_discard, S_IRUGO, ++ show_fm_port_stats, NULL); ++static DEVICE_ATTR(port_rx_filter_frame, S_IRUGO, show_fm_port_stats, NULL); ++ ++/* FM PORT TX statistics */ ++static struct attribute *fm_tx_port_dev_stats_attributes[] = { ++ &dev_attr_port_frame.attr, ++ &dev_attr_port_discard_frame.attr, ++ &dev_attr_port_dealloc_buf.attr, ++ &dev_attr_port_enq_total.attr, ++ &dev_attr_port_length_err.attr, ++ &dev_attr_port_unsupprted_format.attr, ++ &dev_attr_port_deq_total.attr, ++ &dev_attr_port_deq_from_default.attr, ++ &dev_attr_port_deq_confirm.attr, ++ NULL ++}; ++ ++static const struct attribute_group fm_tx_port_dev_stats_attr_grp = { ++ .name = "statistics", ++ .attrs = fm_tx_port_dev_stats_attributes ++}; ++ ++/* FM PORT RX statistics */ ++static struct attribute *fm_rx_port_dev_stats_attributes[] = { ++ &dev_attr_port_frame.attr, ++ &dev_attr_port_discard_frame.attr, ++ &dev_attr_port_dealloc_buf.attr, ++ &dev_attr_port_enq_total.attr, ++ &dev_attr_port_rx_bad_frame.attr, ++ &dev_attr_port_rx_large_frame.attr, ++ &dev_attr_port_rx_out_of_buffers_discard.attr, ++ &dev_attr_port_rx_filter_frame.attr, ++ NULL ++}; ++ ++static const struct attribute_group fm_rx_port_dev_stats_attr_grp = { ++ .name = "statistics", ++ .attrs = fm_rx_port_dev_stats_attributes ++}; ++ ++/* TODO: add particular OH ports statistics */ ++static struct attribute *fm_oh_port_dev_stats_attributes[] = { ++ &dev_attr_port_frame.attr, ++ &dev_attr_port_discard_frame.attr, ++ &dev_attr_port_dealloc_buf.attr, ++ &dev_attr_port_enq_total.attr, ++ /*TX*/ &dev_attr_port_length_err.attr, ++ &dev_attr_port_unsupprted_format.attr, ++ &dev_attr_port_deq_total.attr, ++ &dev_attr_port_deq_from_default.attr, ++ &dev_attr_port_deq_confirm.attr, ++ /* &dev_attr_port_rx_bad_frame.attr, */ ++ /* &dev_attr_port_rx_large_frame.attr, */ ++ &dev_attr_port_rx_out_of_buffers_discard.attr, ++ /*&dev_attr_port_rx_filter_frame.attr, */ ++ NULL ++}; ++ ++static const struct attribute_group fm_oh_port_dev_stats_attr_grp = { ++ .name = "statistics", ++ .attrs = fm_oh_port_dev_stats_attributes ++}; ++ ++static ssize_t show_fm_port_regs(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ unsigned long flags; ++ unsigned n = 0; ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; ++#endif ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ p_LnxWrpFmPortDev = ++ (t_LnxWrpFmPortDev *) dev_get_drvdata(dev); ++ ++ ++ local_irq_save(flags); ++ ++ if (!p_LnxWrpFmPortDev->h_Dev) { ++ n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n"); ++ return n; ++ } else { ++ n = snprintf(buf, PAGE_SIZE, ++ "FM port driver registers dump.\n"); ++ n = fm_port_dump_regs(p_LnxWrpFmPortDev->h_Dev, buf, n); ++ } ++ ++ local_irq_restore(flags); ++ ++ return n; ++#else ++ ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, ++ "Debug level is too low to dump registers!!!\n"); ++ local_irq_restore(flags); ++ ++ return n; ++#endif ++} ++static int fm_port_dsar_dump_mem(void *h_dev, char *buf, int nn) ++{ ++ t_FmPort *p_FmPort; ++ t_Fm *p_Fm; ++ uint8_t hardwarePortId; ++ uint32_t *param_page; ++ t_ArCommonDesc *ArCommonDescPtr; ++ uint32_t *mem; ++ int i, n = nn; ++ ++ p_FmPort = (t_FmPort *)h_dev; ++ hardwarePortId = p_FmPort->hardwarePortId; ++ p_Fm = (t_Fm *)p_FmPort->h_Fm; ++ ++ if (!FM_PORT_IsInDsar(p_FmPort)) ++ { ++ FM_DMP_LN(buf, n, "port %u is not a DSAR port\n", ++ hardwarePortId); ++ return n; ++ } ++ FM_DMP_LN(buf, n, "port %u DSAR mem\n", hardwarePortId); ++ FM_DMP_LN(buf, n, "========================\n"); ++ ++ /* do I need request_mem_region here? */ ++ param_page = ioremap(p_FmPort->fmMuramPhysBaseAddr + ioread32be(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr), 4); ++ ArCommonDescPtr = (t_ArCommonDesc*)(ioremap(p_FmPort->fmMuramPhysBaseAddr + ioread32be(param_page), 300*4)); /* this should be changed*/ ++ mem = (uint32_t*)ArCommonDescPtr; ++ for (i = 0; i < 300; i+=4) ++ FM_DMP_LN(buf, n, "%08x: %08x %08x %08x %08x\n", i*4, mem[i], mem[i + 1], mem[i + 2], mem[i + 3]); ++ iounmap(ArCommonDescPtr); ++ iounmap(param_page); ++ return n; ++} ++ ++static int fm_port_dsar_dump_regs(void *h_dev, char *buf, int nn) ++{ ++ t_FmPort *p_FmPort; ++ t_Fm *p_Fm; ++ uint8_t hardwarePortId; ++ uint32_t *param_page; ++ t_ArCommonDesc *ArCommonDescPtr; ++ int i, n = nn; ++ ++ p_FmPort = (t_FmPort *)h_dev; ++ hardwarePortId = p_FmPort->hardwarePortId; ++ p_Fm = (t_Fm *)p_FmPort->h_Fm; ++ ++ if (!FM_PORT_IsInDsar(p_FmPort)) ++ { ++ FM_DMP_LN(buf, n, "port %u is not a DSAR port\n", ++ hardwarePortId); ++ return n; ++ } ++ FM_DMP_LN(buf, n, "port %u DSAR information\n", hardwarePortId); ++ FM_DMP_LN(buf, n, "========================\n"); ++ ++ /* do I need request_mem_region here? */ ++ param_page = ioremap(p_FmPort->fmMuramPhysBaseAddr + ioread32be(&p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr), 4); ++ ArCommonDescPtr = (t_ArCommonDesc*)(ioremap(p_FmPort->fmMuramPhysBaseAddr + ioread32be(param_page), sizeof(t_ArCommonDesc))); /* this should be changed*/ ++ FM_DMP_LN(buf, n, "Tx port: 0x%x\n", ArCommonDescPtr->arTxPort); ++ FM_DMP_LN(buf, n, "Active HPNIA: 0x%08x\n", ArCommonDescPtr->activeHPNIA); ++ FM_DMP_LN(buf, n, "Snmp port: 0x%x\n", ArCommonDescPtr->snmpPort); ++ FM_DMP_LN(buf, n, "MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", ArCommonDescPtr->macStationAddr[0], ++ ArCommonDescPtr->macStationAddr[1], ArCommonDescPtr->macStationAddr[2], ++ ArCommonDescPtr->macStationAddr[3], ArCommonDescPtr->macStationAddr[4], ++ ArCommonDescPtr->macStationAddr[5]); ++ FM_DMP_LN(buf, n, "filterControl: 0x%02x\n", ArCommonDescPtr->filterControl); ++ FM_DMP_LN(buf, n, "tcpControlPass: 0x%04x\n", ArCommonDescPtr->tcpControlPass); ++ FM_DMP_LN(buf, n, "ipProtocolTblSize: 0x%x\n", ArCommonDescPtr->ipProtocolTblSize); ++ FM_DMP_LN(buf, n, "udpPortTblSize: 0x%x\n", ArCommonDescPtr->udpPortTblSize); ++ FM_DMP_LN(buf, n, "tcpPortTblSize: 0x%x\n", ArCommonDescPtr->tcpPortTblSize); ++ if (ArCommonDescPtr->p_ArStats) ++ { ++ t_ArStatistics *arStatistics = (t_ArStatistics*) ++ ioremap(ioread32be(&ArCommonDescPtr->p_ArStats) + ++ p_FmPort->fmMuramPhysBaseAddr, ++ sizeof (t_ArStatistics)); ++ FM_DMP_LN(buf, n, "\nDSAR statistics\n"); ++ FM_DMP_LN(buf, n, "DSAR_Discarded: 0x%x\n", arStatistics->dsarDiscarded); ++ FM_DMP_LN(buf, n, "DSAR_Err_Discarded: 0x%x\n", arStatistics->dsarErrDiscarded); ++ FM_DMP_LN(buf, n, "DSAR_Frag_Discarded: 0x%x\n", arStatistics->dsarFragDiscarded); ++ FM_DMP_LN(buf, n, "DSAR_Tunnel_Discarded: 0x%x\n", arStatistics->dsarTunnelDiscarded); ++ FM_DMP_LN(buf, n, "DSAR_ARP_Discarded: 0x%x\n", arStatistics->dsarArpDiscarded); ++ FM_DMP_LN(buf, n, "DSAR_IP_Discarded: 0x%x\n", arStatistics->dsarIpDiscarded); ++ FM_DMP_LN(buf, n, "DSAR_TCP_Discarded: 0x%x\n", arStatistics->dsarTcpDiscarded); ++ FM_DMP_LN(buf, n, "DSAR_UDP_Discarded: 0x%x\n", arStatistics->dsarUdpDiscarded); ++ FM_DMP_LN(buf, n, "DSAR_ICMPv6_Checksum_Err: 0x%x\n", arStatistics->dsarIcmpV6ChecksumErr); ++ FM_DMP_LN(buf, n, "DSAR_ICMPv6_Other_Type: 0x%x\n", arStatistics->dsarIcmpV6OtherType); ++ FM_DMP_LN(buf, n, "DSAR_ICMPv4_Other_Type: 0x%x\n", arStatistics->dsarIcmpV4OtherType); ++ ++ iounmap(arStatistics); ++ } ++ if (ArCommonDescPtr->p_ArpDescriptor) ++ { ++ t_DsarArpDescriptor* ArpDescriptor = (t_DsarArpDescriptor*) ++ ioremap(ioread32be(&ArCommonDescPtr->p_ArpDescriptor) + ++ p_FmPort->fmMuramPhysBaseAddr, ++ sizeof (t_DsarArpDescriptor)); ++ FM_DMP_LN(buf, n, "\nARP\n"); ++ FM_DMP_LN(buf, n, "===\n"); ++ FM_DMP_LN(buf, n, "control bits 0x%04x\n", ArpDescriptor->control); ++ if (ArpDescriptor->numOfBindings) ++ { ++ char ip_str[100]; ++ t_DsarArpBindingEntry* bindings = ioremap( ++ ioread32be(&ArpDescriptor->p_Bindings) + ++ p_FmPort->fmMuramPhysBaseAddr, ++ ArpDescriptor->numOfBindings * ++ sizeof(t_DsarArpBindingEntry)); ++ uint8_t* ip_addr = (uint8_t*)&bindings->ipv4Addr; ++ FM_DMP_LN(buf, n, " ip vlan id\n"); ++ for (i = 0; i < ArpDescriptor->numOfBindings; i++) ++ { ++ n += snprintf(ip_str, 100, "%d.%d.%d.%d", ++ ip_addr[0], ip_addr[1], ++ ip_addr[2], ip_addr[3]); ++ FM_DMP_LN(buf, n, "%-15s 0x%x\n", ++ ip_str, bindings->vlanId); ++ } ++ iounmap(bindings); ++ } ++ if (ArpDescriptor->p_Statistics) ++ { ++ t_DsarArpStatistics* arpStats = ioremap( ++ ioread32be(&ArpDescriptor->p_Statistics) + ++ p_FmPort->fmMuramPhysBaseAddr, ++ sizeof(t_DsarArpStatistics)); ++ FM_DMP_LN(buf, n, "statistics\n"); ++ FM_DMP_LN(buf, n, "INVAL_CNT: 0x%x\n", arpStats->invalCnt); ++ FM_DMP_LN(buf, n, "ECHO_CNT: 0x%x\n", arpStats->echoCnt); ++ FM_DMP_LN(buf, n, "CD_CNT: 0x%x\n", arpStats->cdCnt); ++ FM_DMP_LN(buf, n, "AR_CNT: 0x%x\n", arpStats->arCnt); ++ FM_DMP_LN(buf, n, "RATM_CNT: 0x%x\n", arpStats->ratmCnt); ++ FM_DMP_LN(buf, n, "UKOP_CNT: 0x%x\n", arpStats->ukopCnt); ++ FM_DMP_LN(buf, n, "NMTP_CNT: 0x%x\n", arpStats->nmtpCnt); ++ FM_DMP_LN(buf, n, "NMVLAN_CNT: 0x%x\n", arpStats->nmVlanCnt); ++ iounmap(arpStats); ++ } ++ ++ iounmap(ArpDescriptor); ++ } ++ if (ArCommonDescPtr->p_IcmpV4Descriptor) ++ { ++ t_DsarIcmpV4Descriptor* ICMPV4Descriptor = ++ (t_DsarIcmpV4Descriptor*)ioremap(ioread32be( ++ &ArCommonDescPtr->p_IcmpV4Descriptor) + ++ p_FmPort->fmMuramPhysBaseAddr, ++ sizeof (t_DsarIcmpV4Descriptor)); ++ FM_DMP_LN(buf, n, "\nEcho ICMPv4\n"); ++ FM_DMP_LN(buf, n, "===========\n"); ++ FM_DMP_LN(buf, n, "control bits 0x%04x\n", ICMPV4Descriptor->control); ++ if (ICMPV4Descriptor->numOfBindings) ++ { ++ char ip_str[100]; ++ t_DsarArpBindingEntry* bindings = ioremap( ++ ioread32be(&ICMPV4Descriptor->p_Bindings) + ++ p_FmPort->fmMuramPhysBaseAddr, ++ ICMPV4Descriptor->numOfBindings * ++ sizeof(t_DsarArpBindingEntry)); ++ uint8_t* ip_addr = (uint8_t*)&bindings->ipv4Addr; ++ FM_DMP_LN(buf, n, " ip vlan id\n"); ++ for (i = 0; i < ICMPV4Descriptor->numOfBindings; i++) ++ { ++ n += snprintf(ip_str, 100, "%d.%d.%d.%d", ++ ip_addr[0], ip_addr[1], ++ ip_addr[2], ip_addr[3]); ++ FM_DMP_LN(buf, n, "%-15s 0x%x\n", ++ ip_str, bindings->vlanId); ++ } ++ iounmap(bindings); ++ } ++ if (ICMPV4Descriptor->p_Statistics) ++ { ++ t_DsarIcmpV4Statistics* icmpv4Stats = ioremap( ++ ioread32be(&ICMPV4Descriptor->p_Statistics) + ++ p_FmPort->fmMuramPhysBaseAddr, ++ sizeof(t_DsarIcmpV4Statistics)); ++ FM_DMP_LN(buf, n, "statistics\n"); ++ FM_DMP_LN(buf, n, "INVAL_CNT: 0x%x\n", icmpv4Stats->invalCnt); ++ FM_DMP_LN(buf, n, "NMVLAN_CNT: 0x%x\n", icmpv4Stats->nmVlanCnt); ++ FM_DMP_LN(buf, n, "NMIP_CNT: 0x%x\n", icmpv4Stats->nmIpCnt); ++ FM_DMP_LN(buf, n, "AR_CNT: 0x%x\n", icmpv4Stats->arCnt); ++ FM_DMP_LN(buf, n, "CSERR_CNT: 0x%x\n", icmpv4Stats->cserrCnt); ++ iounmap(icmpv4Stats); ++ } ++ iounmap(ICMPV4Descriptor); ++ } ++ if (ArCommonDescPtr->p_NdDescriptor) ++ { ++ t_DsarNdDescriptor *NDDescriptor = ++ (t_DsarNdDescriptor*)ioremap(ioread32be( ++ &ArCommonDescPtr->p_NdDescriptor) + p_FmPort-> ++ fmMuramPhysBaseAddr, sizeof (t_DsarNdDescriptor)); ++ FM_DMP_LN(buf, n, "\nNDP\n"); ++ FM_DMP_LN(buf, n, "===\n"); ++ FM_DMP_LN(buf, n, "control bits 0x%04x\n", NDDescriptor->control); ++ FM_DMP_LN(buf, n, "solicited address 0x%08x\n", NDDescriptor->solicitedAddr); ++ if (NDDescriptor->numOfBindings) ++ { ++ char ip_str[100]; ++ t_DsarIcmpV6BindingEntry* bindings = ioremap( ++ ioread32be(&NDDescriptor->p_Bindings) + ++ p_FmPort->fmMuramPhysBaseAddr, ++ NDDescriptor->numOfBindings * ++ sizeof(t_DsarIcmpV6BindingEntry)); ++ uint16_t* ip_addr = (uint16_t*)&bindings->ipv6Addr; ++ FM_DMP_LN(buf, n, " ip vlan id\n"); ++ for (i = 0; i < NDDescriptor->numOfBindings; i++) ++ { ++ n += snprintf(ip_str, 100, ++ "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", ++ ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3], ++ ip_addr[4], ip_addr[5], ip_addr[6], ip_addr[7]); ++ FM_DMP_LN(buf, n, "%s 0x%x\n", ip_str, bindings->vlanId); ++ } ++ iounmap(bindings); ++ } ++ if (NDDescriptor->p_Statistics) ++ { ++ t_NdStatistics* ndStats = ioremap( ++ ioread32be(&NDDescriptor->p_Statistics) + ++ p_FmPort->fmMuramPhysBaseAddr, ++ sizeof(t_NdStatistics)); ++ FM_DMP_LN(buf, n, "statistics\n"); ++ FM_DMP_LN(buf, n, "INVAL_CNT: 0x%x\n", ndStats->invalCnt); ++ FM_DMP_LN(buf, n, "NMVLAN_CNT: 0x%x\n", ndStats->nmVlanCnt); ++ FM_DMP_LN(buf, n, "NMIP_CNT: 0x%x\n", ndStats->nmIpCnt); ++ FM_DMP_LN(buf, n, "AR_CNT: 0x%x\n", ndStats->arCnt); ++ FM_DMP_LN(buf, n, "USADVERT_CNT: 0x%x\n", ndStats->usadvertCnt); ++ FM_DMP_LN(buf, n, "NMMCAST_CNT: 0x%x\n", ndStats->nmmcastCnt); ++ FM_DMP_LN(buf, n, "NSLLA_CNT: 0x%x\n", ndStats->nsllaCnt); ++ iounmap(ndStats); ++ } ++ iounmap(NDDescriptor); ++ } ++ if (ArCommonDescPtr->p_IcmpV6Descriptor) ++ { ++ t_DsarIcmpV6Descriptor *ICMPV6Descriptor = ++ (t_DsarIcmpV6Descriptor*)ioremap(ioread32be( ++ &ArCommonDescPtr->p_IcmpV6Descriptor) + p_FmPort-> ++ fmMuramPhysBaseAddr, sizeof (t_DsarIcmpV6Descriptor)); ++ FM_DMP_LN(buf, n, "\nEcho ICMPv6\n"); ++ FM_DMP_LN(buf, n, "===========\n"); ++ FM_DMP_LN(buf, n, "control bits 0x%04x\n", ICMPV6Descriptor->control); ++ if (ICMPV6Descriptor->numOfBindings) ++ { ++ char ip_str[100]; ++ t_DsarIcmpV6BindingEntry* bindings = ioremap( ++ ioread32be(&ICMPV6Descriptor->p_Bindings) + ++ p_FmPort->fmMuramPhysBaseAddr, ++ ICMPV6Descriptor->numOfBindings * ++ sizeof(t_DsarIcmpV6BindingEntry)); ++ uint16_t* ip_addr = (uint16_t*)&bindings->ipv6Addr; ++ FM_DMP_LN(buf, n, " ip vlan id\n"); ++ for (i = 0; i < ICMPV6Descriptor->numOfBindings; i++) ++ { ++ n += snprintf(ip_str, 100, ++ "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", ++ ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3], ++ ip_addr[4], ip_addr[5], ip_addr[6], ip_addr[7]); ++ FM_DMP_LN(buf, n, "%s 0x%x\n", ip_str, bindings->vlanId); ++ } ++ iounmap(bindings); ++ } ++ if (ICMPV6Descriptor->p_Statistics) ++ { ++ t_DsarIcmpV6Statistics* icmpv6Stats = ioremap( ++ ioread32be(&ICMPV6Descriptor->p_Statistics) + ++ p_FmPort->fmMuramPhysBaseAddr, ++ sizeof(t_DsarIcmpV6Statistics)); ++ FM_DMP_LN(buf, n, "statistics\n"); ++ FM_DMP_LN(buf, n, "INVAL_CNT: 0x%x\n", icmpv6Stats->invalCnt); ++ FM_DMP_LN(buf, n, "NMVLAN_CNT: 0x%x\n", icmpv6Stats->nmVlanCnt); ++ FM_DMP_LN(buf, n, "NMIP_CNT: 0x%x\n", icmpv6Stats->nmIpCnt); ++ FM_DMP_LN(buf, n, "AR_CNT: 0x%x\n", icmpv6Stats->arCnt); ++ iounmap(icmpv6Stats); ++ } ++ iounmap(ICMPV6Descriptor); ++ } ++ if (ArCommonDescPtr->p_SnmpDescriptor) ++ { ++ t_DsarSnmpDescriptor *SnmpDescriptor = ++ (t_DsarSnmpDescriptor*)ioremap(ioread32be( ++ &ArCommonDescPtr->p_SnmpDescriptor) + p_FmPort-> ++ fmMuramPhysBaseAddr, sizeof (t_DsarSnmpDescriptor)); ++ FM_DMP_LN(buf, n, "\nSNMP\n"); ++ FM_DMP_LN(buf, n, "===========\n"); ++ FM_DMP_LN(buf, n, "control bits 0x%04x\n", SnmpDescriptor->control); ++ FM_DMP_LN(buf, n, "max message length 0x%04x\n", SnmpDescriptor->maxSnmpMsgLength); ++ if (SnmpDescriptor->numOfIpv4Addresses) ++ { ++ char ip_str[100]; ++ t_DsarSnmpIpv4AddrTblEntry* addrs = ioremap( ++ ioread32be(&SnmpDescriptor->p_Ipv4AddrTbl) + ++ p_FmPort->fmMuramPhysBaseAddr, ++ SnmpDescriptor->numOfIpv4Addresses * ++ sizeof(t_DsarSnmpIpv4AddrTblEntry)); ++ uint8_t* ip_addr = (uint8_t*)&addrs->ipv4Addr; ++ FM_DMP_LN(buf, n, " ip vlan id\n"); ++ for (i = 0; i < SnmpDescriptor->numOfIpv4Addresses; i++) ++ { ++ n += snprintf(ip_str, 100, "%d.%d.%d.%d", ++ ip_addr[0], ip_addr[1], ++ ip_addr[2], ip_addr[3]); ++ FM_DMP_LN(buf, n, "%-15s 0x%x\n", ip_str, addrs->vlanId); ++ } ++ iounmap(addrs); ++ } ++ if (SnmpDescriptor->p_Statistics) ++ { ++ t_DsarSnmpStatistics* snmpStats = ioremap( ++ ioread32be(&SnmpDescriptor->p_Statistics) + ++ p_FmPort->fmMuramPhysBaseAddr, ++ sizeof(t_DsarSnmpStatistics)); ++ FM_DMP_LN(buf, n, "statistics\n"); ++ FM_DMP_LN(buf, n, "snmpErrCnt: 0x%x\n", snmpStats->snmpErrCnt); ++ FM_DMP_LN(buf, n, "snmpCommunityErrCnt: 0x%x\n", snmpStats->snmpCommunityErrCnt); ++ FM_DMP_LN(buf, n, "snmpTotalDiscardCnt: 0x%x\n", snmpStats->snmpTotalDiscardCnt); ++ FM_DMP_LN(buf, n, "snmpGetReqCnt: 0x%x\n", snmpStats->snmpGetReqCnt); ++ FM_DMP_LN(buf, n, "snmpGetNextReqCnt: 0x%x\n", snmpStats->snmpGetNextReqCnt); ++ iounmap(snmpStats); ++ } ++ iounmap(SnmpDescriptor); ++ } ++ iounmap(ArCommonDescPtr); ++ iounmap(param_page); ++ return n; ++} ++ ++static ssize_t show_fm_port_dsar_mem(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ unsigned long flags; ++ unsigned n = 0; ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; ++#endif ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ p_LnxWrpFmPortDev = ++ (t_LnxWrpFmPortDev *) dev_get_drvdata(dev); ++ ++ local_irq_save(flags); ++ ++ if (!p_LnxWrpFmPortDev->h_Dev) { ++ n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n"); ++ return n; ++ } else { ++ n = snprintf(buf, PAGE_SIZE, ++ "FM port driver registers dump.\n"); ++ n = fm_port_dsar_dump_mem(p_LnxWrpFmPortDev->h_Dev, buf, n); ++ } ++ ++ local_irq_restore(flags); ++ ++ return n; ++#else ++ ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, ++ "Debug level is too low to dump registers!!!\n"); ++ local_irq_restore(flags); ++ ++ return n; ++#endif ++} ++ ++static ssize_t show_fm_port_dsar_regs(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ unsigned long flags; ++ unsigned n = 0; ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; ++#endif ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ p_LnxWrpFmPortDev = ++ (t_LnxWrpFmPortDev *) dev_get_drvdata(dev); ++ ++ local_irq_save(flags); ++ ++ if (!p_LnxWrpFmPortDev->h_Dev) { ++ n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n"); ++ return n; ++ } else { ++ n = snprintf(buf, PAGE_SIZE, ++ "FM port driver registers dump.\n"); ++ n = fm_port_dsar_dump_regs(p_LnxWrpFmPortDev->h_Dev, buf, n); ++ } ++ ++ local_irq_restore(flags); ++ ++ return n; ++#else ++ ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, ++ "Debug level is too low to dump registers!!!\n"); ++ local_irq_restore(flags); ++ ++ return n; ++#endif ++} ++ ++#if (DPAA_VERSION >= 11) ++static ssize_t show_fm_port_ipv4_options(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ unsigned long flags; ++ unsigned n = 0; ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; ++#endif ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ p_LnxWrpFmPortDev = ++ (t_LnxWrpFmPortDev *) dev_get_drvdata(dev); ++ ++ local_irq_save(flags); ++ ++ if (!p_LnxWrpFmPortDev->h_Dev) { ++ n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n"); ++ return n; ++ } else if (((t_FmPort *)p_LnxWrpFmPortDev->h_Dev)->p_ParamsPage ++ == NULL) { ++ n = snprintf(buf, PAGE_SIZE, ++ "\tPort: FMan-controller params page not set\n"); ++ return n; ++ } else { ++ n = snprintf(buf, PAGE_SIZE, ++ "Counter for fragmented pkt with IP header options\n"); ++ n = fm_port_dump_ipv4_opt(p_LnxWrpFmPortDev->h_Dev, buf, n); ++ } ++ ++ local_irq_restore(flags); ++ ++ return n; ++#else ++ ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, ++ "Debug level is too low to dump registers!!!\n"); ++ local_irq_restore(flags); ++ ++ return n; ++#endif ++} ++ ++#endif ++ ++static ssize_t show_fm_port_bmi_regs(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ unsigned long flags; ++ unsigned n = 0; ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; ++#endif ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ p_LnxWrpFmPortDev = ++ (t_LnxWrpFmPortDev *) dev_get_drvdata(dev); ++ ++ local_irq_save(flags); ++ ++ if (!p_LnxWrpFmPortDev->h_Dev) { ++ n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n"); ++ return n; ++ } else { ++ n = snprintf(buf, PAGE_SIZE, ++ "FM port driver registers dump.\n"); ++ n = fm_port_dump_regs_bmi(p_LnxWrpFmPortDev->h_Dev, buf, n); ++ } ++ ++ local_irq_restore(flags); ++ ++ return n; ++#else ++ ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, ++ "Debug level is too low to dump registers!!!\n"); ++ local_irq_restore(flags); ++ ++ return n; ++#endif ++} ++ ++static ssize_t show_fm_port_qmi_regs(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ unsigned long flags; ++ unsigned n = 0; ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; ++#endif ++ ++ if (attr == NULL || buf == NULL || dev == NULL) ++ return -EINVAL; ++ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ p_LnxWrpFmPortDev = ++ (t_LnxWrpFmPortDev *) dev_get_drvdata(dev); ++ ++ local_irq_save(flags); ++ ++ if (!p_LnxWrpFmPortDev->h_Dev) { ++ n = snprintf(buf, PAGE_SIZE, "\tFM Port not configured...\n"); ++ return n; ++ } else { ++ n = snprintf(buf, PAGE_SIZE, ++ "FM port driver registers dump.\n"); ++ n = fm_port_dump_regs_qmi(p_LnxWrpFmPortDev->h_Dev, buf, n); ++ } ++ ++ local_irq_restore(flags); ++ ++ return n; ++#else ++ ++ local_irq_save(flags); ++ n = snprintf(buf, PAGE_SIZE, ++ "Debug level is too low to dump registers!!!\n"); ++ local_irq_restore(flags); ++ ++ return n; ++#endif ++} ++ ++static DEVICE_ATTR(fm_port_regs, S_IRUGO | S_IRUSR, show_fm_port_regs, NULL); ++static DEVICE_ATTR(fm_port_qmi_regs, S_IRUGO | S_IRUSR, show_fm_port_qmi_regs, NULL); ++static DEVICE_ATTR(fm_port_bmi_regs, S_IRUGO | S_IRUSR, show_fm_port_bmi_regs, NULL); ++#if (DPAA_VERSION >= 11) ++static DEVICE_ATTR(fm_port_ipv4_opt, S_IRUGO | S_IRUSR, show_fm_port_ipv4_options, NULL); ++#endif ++static DEVICE_ATTR(fm_port_dsar_regs, S_IRUGO | S_IRUSR, show_fm_port_dsar_regs, NULL); ++static DEVICE_ATTR(fm_port_dsar_mem, S_IRUGO | S_IRUSR, show_fm_port_dsar_mem, NULL); ++ ++int fm_port_sysfs_create(struct device *dev) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev; ++ ++ if (dev == NULL) ++ return -EINVAL; ++ ++ p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_LnxWrpFmPortDev == NULL)) ++ return -EINVAL; ++ ++ /* store to remove them when module is disabled */ ++ p_LnxWrpFmPortDev->dev_attr_regs = &dev_attr_fm_port_regs; ++ p_LnxWrpFmPortDev->dev_attr_qmi_regs = &dev_attr_fm_port_qmi_regs; ++ p_LnxWrpFmPortDev->dev_attr_bmi_regs = &dev_attr_fm_port_bmi_regs; ++#if (DPAA_VERSION >= 11) ++ p_LnxWrpFmPortDev->dev_attr_ipv4_opt = &dev_attr_fm_port_ipv4_opt; ++#endif ++ p_LnxWrpFmPortDev->dev_attr_dsar_regs = &dev_attr_fm_port_dsar_regs; ++ p_LnxWrpFmPortDev->dev_attr_dsar_mem = &dev_attr_fm_port_dsar_mem; ++ /* Registers dump entry - in future will be moved to debugfs */ ++ if (device_create_file(dev, &dev_attr_fm_port_regs) != 0) ++ return -EIO; ++ if (device_create_file(dev, &dev_attr_fm_port_qmi_regs) != 0) ++ return -EIO; ++ if (device_create_file(dev, &dev_attr_fm_port_bmi_regs) != 0) ++ return -EIO; ++#if (DPAA_VERSION >= 11) ++ if (device_create_file(dev, &dev_attr_fm_port_ipv4_opt) != 0) ++ return -EIO; ++#endif ++ if (device_create_file(dev, &dev_attr_fm_port_dsar_regs) != 0) ++ return -EIO; ++ if (device_create_file(dev, &dev_attr_fm_port_dsar_mem) != 0) ++ return -EIO; ++ ++ /* FM Ports statistics */ ++ switch (p_LnxWrpFmPortDev->settings.param.portType) { ++ case e_FM_PORT_TYPE_TX: ++ case e_FM_PORT_TYPE_TX_10G: ++ if (sysfs_create_group ++ (&dev->kobj, &fm_tx_port_dev_stats_attr_grp) != 0) ++ return -EIO; ++ break; ++ case e_FM_PORT_TYPE_RX: ++ case e_FM_PORT_TYPE_RX_10G: ++ if (sysfs_create_group ++ (&dev->kobj, &fm_rx_port_dev_stats_attr_grp) != 0) ++ return -EIO; ++ break; ++ case e_FM_PORT_TYPE_DUMMY: ++ case e_FM_PORT_TYPE_OH_OFFLINE_PARSING: ++ if (sysfs_create_group ++ (&dev->kobj, &fm_oh_port_dev_stats_attr_grp) != 0) ++ return -EIO; ++ break; ++ default: ++ WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__, ++ __func__); ++ return -EINVAL; ++ break; ++ }; ++ ++ return 0; ++} ++ ++void fm_port_sysfs_destroy(struct device *dev) ++{ ++ t_LnxWrpFmPortDev *p_LnxWrpFmPortDev = NULL; ++ ++ /* this function has never been tested !!! */ ++ ++ if (WARN_ON(dev == NULL)) ++ return; ++ ++ p_LnxWrpFmPortDev = (t_LnxWrpFmPortDev *) dev_get_drvdata(dev); ++ if (WARN_ON(p_LnxWrpFmPortDev == NULL)) ++ return; ++ ++ /* The name attribute will be freed also by these 2 functions? */ ++ switch (p_LnxWrpFmPortDev->settings.param.portType) { ++ case e_FM_PORT_TYPE_TX: ++ case e_FM_PORT_TYPE_TX_10G: ++ sysfs_remove_group(&dev->kobj, &fm_tx_port_dev_stats_attr_grp); ++ break; ++ case e_FM_PORT_TYPE_RX: ++ case e_FM_PORT_TYPE_RX_10G: ++ sysfs_remove_group(&dev->kobj, &fm_rx_port_dev_stats_attr_grp); ++ break; ++ case e_FM_PORT_TYPE_DUMMY: ++ case e_FM_PORT_TYPE_OH_OFFLINE_PARSING: ++ sysfs_remove_group(&dev->kobj, &fm_oh_port_dev_stats_attr_grp); ++ break; ++ default: ++ WARN(1, "FMD: failure at %s:%d/%s()!\n", __FILE__, __LINE__, ++ __func__); ++ break; ++ }; ++ ++ device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_regs); ++ device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_qmi_regs); ++ device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_bmi_regs); ++#if (DPAA_VERSION >= 11) ++ device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_ipv4_opt); ++#endif ++ device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_dsar_regs); ++ device_remove_file(dev, p_LnxWrpFmPortDev->dev_attr_dsar_mem); ++} ++ ++ ++int fm_port_dump_regs(void *h_dev, char *buf, int nn) ++{ ++ t_FmPort *p_FmPort; ++ t_Fm *p_Fm; ++ uint8_t hardwarePortId; ++ int n = nn; ++ ++ p_FmPort = (t_FmPort *)h_dev; ++ hardwarePortId = p_FmPort->hardwarePortId; ++ p_Fm = (t_Fm *)p_FmPort->h_Fm; ++ ++ FM_DMP_TITLE(buf, n, &p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId - 1], ++ "fmbm_pp for port %u", hardwarePortId); ++ FM_DMP_MEM_32(buf, n, ++ &p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId - 1]); ++ ++ FM_DMP_TITLE(buf, n, &p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId - 1], ++ "fmbm_pfs for port %u", hardwarePortId); ++ FM_DMP_MEM_32(buf, n, ++ &p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId - 1]); ++ ++ FM_DMP_TITLE(buf, n, ++ &p_Fm->p_FmBmiRegs->fmbm_spliodn[hardwarePortId - 1], ++ "fmbm_spliodn for port %u", hardwarePortId); ++ FM_DMP_MEM_32(buf, n, ++ &p_Fm->p_FmBmiRegs->fmbm_spliodn[hardwarePortId - 1]); ++ ++ FM_DMP_TITLE(buf, n, &p_Fm->p_FmFpmRegs->fmfp_ps[hardwarePortId], ++ "fmfp_psfor port %u", hardwarePortId); ++ FM_DMP_MEM_32(buf, n, &p_Fm->p_FmFpmRegs->fmfp_ps[hardwarePortId]); ++ ++ FM_DMP_TITLE(buf, n, &p_Fm->p_FmDmaRegs->fmdmplr[hardwarePortId / 2], ++ "fmdmplrfor port %u", hardwarePortId); ++ FM_DMP_MEM_32(buf, n, ++ &p_Fm->p_FmDmaRegs->fmdmplr[hardwarePortId / 2]); ++ return n; ++} ++ ++#if (DPAA_VERSION >= 11) ++ ++int fm_port_dump_ipv4_opt(void *h_dev, char *buf, int nn) ++{ ++ t_FmPort *p_FmPort; ++ int n = nn; ++ ++ p_FmPort = (t_FmPort *)h_dev; ++ ++ FM_DMP_V32(buf, n, p_FmPort->p_ParamsPage, ipfOptionsCounter); ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ ++ return n; ++} ++#endif ++ ++int fm_port_dump_regs_bmi(void *h_dev, char *buf, int nn) ++{ ++ t_FmPort *p_FmPort; ++ u_FmPortBmiRegs *p_bmi; ++ ++ char arr[20]; ++ uint8_t flag; ++ int i = 0; ++ int n = nn; ++ ++ p_FmPort = (t_FmPort *)h_dev; ++ p_bmi = p_FmPort->p_FmPortBmiRegs; ++ ++ memset(arr, 0, sizeof(arr)); ++ switch (p_FmPort->portType) { ++ case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): ++ strcpy(arr, "OFFLINE-PARSING"); ++ flag = 0; ++ break; ++ case (e_FM_PORT_TYPE_OH_HOST_COMMAND): ++ strcpy(arr, "HOST-COMMAND"); ++ flag = 0; ++ break; ++ case (e_FM_PORT_TYPE_RX): ++ strcpy(arr, "RX"); ++ flag = 1; ++ break; ++ case (e_FM_PORT_TYPE_RX_10G): ++ strcpy(arr, "RX-10G"); ++ flag = 1; ++ break; ++ case (e_FM_PORT_TYPE_TX): ++ strcpy(arr, "TX"); ++ flag = 2; ++ break; ++ case (e_FM_PORT_TYPE_TX_10G): ++ strcpy(arr, "TX-10G"); ++ flag = 2; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ FM_DMP_TITLE(buf, n, NULL, ++ "FMan-Port (%s #%d) registers:", ++ arr, p_FmPort->portId); ++ ++ FM_DMP_TITLE(buf, n, p_bmi, "Bmi Port Regs"); ++ ++ switch (flag) { ++ case (0): ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ocfg); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ost); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_oda); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_oicp); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofdne); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofne); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofca); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofpne); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_opso); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_opp); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_occb); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_oim); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofp); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofed); ++ ++ FM_DMP_TITLE(buf, n, ++ &(p_bmi->ohPortBmiRegs.fmbm_oprai), "fmbm_oprai"); ++ for (i = 0; i < FM_PORT_PRS_RESULT_NUM_OF_WORDS; ++i) { ++ FM_DMP_MEM_32(buf, n, ++ &(p_bmi->ohPortBmiRegs.fmbm_oprai[i])); ++ } ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofqid); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_oefqid); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofsdm); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofsem); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofene); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_orlmts); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_orlmt); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ocmne); ++ { ++#ifndef FM_NO_OP_OBSERVED_POOLS ++ if (p_FmPort->fmRevInfo.majorRev == 4) { ++ FM_DMP_TITLE(buf, n, ++ &p_bmi->ohPortBmiRegs.fmbm_oebmpi, ++ "fmbm_oebmpi"); ++ ++ for (i = 0; i < FM_PORT_MAX_NUM_OF_OBSERVED_EXT_POOLS; ++i) { ++ FM_DMP_MEM_32(buf, n, ++ &(p_bmi->ohPortBmiRegs.fmbm_oebmpi[i])); ++ } ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ocgm); ++ } ++#endif /* !FM_NO_OP_OBSERVED_POOLS */ ++ } ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ostc); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofrc); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofdc); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofledc); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofufdc); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_offc); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofwdc); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofldec); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_opc); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_opcp); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_occn); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_otuc); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_oduc); ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ofuc); ++ FM_DMP_TITLE(buf, n, &(p_bmi->ohPortBmiRegs.fmbm_odcfg), ++ "fmbm_odcfg"); ++ for (i = 0; i < 3; ++i) { ++ FM_DMP_MEM_32(buf, n, ++ &(p_bmi->ohPortBmiRegs.fmbm_odcfg[i])); ++ } ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ ++ FM_DMP_V32(buf, n, &p_bmi->ohPortBmiRegs, fmbm_ogpr); ++ break; ++ case (1): ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rcfg); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rst); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rda); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfp); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_reth); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfed); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_ricp); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rebm); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfne); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfca); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfpne); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rpso); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rpp); ++ FM_DMP_TITLE(buf, n, &(p_bmi->rxPortBmiRegs.fmbm_rprai), ++ "fmbm_rprai"); ++ for (i = 0; i < FM_PORT_PRS_RESULT_NUM_OF_WORDS; ++i) { ++ FM_DMP_MEM_32(buf, n, ++ &(p_bmi->rxPortBmiRegs.fmbm_rprai[i])); ++ } ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfqid); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_refqid); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfsdm); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfsem); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfene); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rcmne); ++ FM_DMP_TITLE(buf, n, &p_bmi->rxPortBmiRegs.fmbm_ebmpi, ++ "fmbm_ebmpi"); ++ for (i = 0; i < FM_PORT_MAX_NUM_OF_EXT_POOLS; ++i) { ++ FM_DMP_MEM_32(buf, n, ++ &(p_bmi->rxPortBmiRegs.fmbm_ebmpi[i])); ++ } ++ FM_DMP_TITLE(buf, n, &p_bmi->rxPortBmiRegs.fmbm_acnt, ++ "fmbm_acnt"); ++ for (i = 0; i < FM_PORT_MAX_NUM_OF_EXT_POOLS; ++i) { ++ FM_DMP_MEM_32(buf, n, ++ &(p_bmi->rxPortBmiRegs.fmbm_acnt[i])); ++ } ++ FM_DMP_TITLE(buf, n, &p_bmi->rxPortBmiRegs.fmbm_rcgm, ++ "fmbm_rcgm"); ++ for (i = 0; i < FM_PORT_NUM_OF_CONGESTION_GRPS / 32; ++i) { ++ FM_DMP_MEM_32(buf, n, ++ &(p_bmi->rxPortBmiRegs.fmbm_rcgm[i])); ++ } ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rmpd); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rstc); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfrc); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfbc); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rlfc); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rffc); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfcd); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfldec); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rodc); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rpc); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rpcp); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rccn); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rtuc); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rrquc); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rduc); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rfuc); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rpac); ++ FM_DMP_TITLE(buf, n, &(p_bmi->rxPortBmiRegs.fmbm_rdcfg), ++ "fmbm_rdcfg"); ++ for (i = 0; i < 3; ++i) { ++ FM_DMP_MEM_32(buf, n, ++ &(p_bmi->rxPortBmiRegs.fmbm_rdcfg[i])); ++ } ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ FM_DMP_V32(buf, n, &p_bmi->rxPortBmiRegs, fmbm_rgpr); ++ break; ++ case (2): ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tcfg); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tst); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tda); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfp); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfed); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_ticp); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfdne); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfca); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tcfqid); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfeqid); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfene); ++#if (DPAA_VERSION >= 11) ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfne); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tcmne); ++#endif /* (DPAA_VERSION >= 11) */ ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_trlmts); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_trlmt); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tstc); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfrc); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfdc); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfledc); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfufdc); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tpc); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tpcp); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tccn); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_ttuc); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_ttcquc); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tduc); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tfuc); ++ FM_DMP_TITLE(buf, n, &(p_bmi->txPortBmiRegs.fmbm_tdcfg), ++ "fmbm_tdcfg"); ++ for (i = 0; i < 3 ; ++i) { ++ FM_DMP_MEM_32(buf, n, ++ &(p_bmi->txPortBmiRegs.fmbm_tdcfg[i])); ++ } ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ FM_DMP_V32(buf, n, &p_bmi->txPortBmiRegs, fmbm_tgpr); ++ break; ++ } ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ ++ return n; ++} ++ ++int fm_port_dump_regs_qmi(void *h_dev, char *buf, int nn) ++{ ++ t_FmPort *p_FmPort; ++ int n = nn; ++ ++ p_FmPort = (t_FmPort *)h_dev; ++ ++ FM_DMP_TITLE(buf, n, p_FmPort->p_FmPortQmiRegs, "Qmi Port Regs"); ++ ++ FM_DMP_V32(buf, n, p_FmPort->p_FmPortQmiRegs, fmqm_pnc); ++ FM_DMP_V32(buf, n, p_FmPort->p_FmPortQmiRegs, fmqm_pns); ++ FM_DMP_V32(buf, n, p_FmPort->p_FmPortQmiRegs, fmqm_pnts); ++ FM_DMP_V32(buf, n, p_FmPort->p_FmPortQmiRegs, fmqm_pnen); ++ FM_DMP_V32(buf, n, p_FmPort->p_FmPortQmiRegs, fmqm_pnetfc); ++ FM_DMP_V32(buf, n, ++ &p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs, fmqm_pndn); ++ FM_DMP_V32(buf, n, ++ &p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs, fmqm_pndc); ++ FM_DMP_V32(buf, n, ++ &p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs, fmqm_pndtfc); ++ FM_DMP_V32(buf, n, ++ &p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs, fmqm_pndfdc); ++ FM_DMP_V32(buf, n, ++ &p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs, fmqm_pndcc); ++ ++ FM_DMP_SUBTITLE(buf, n, "\n"); ++ ++ return n; ++} ++ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.h b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.h +new file mode 100644 +index 00000000..1e7636f4 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/wrapper/lnxwrp_sysfs_fm_port.h +@@ -0,0 +1,56 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ @File lnxwrp_sysfs_fm_port.h ++ ++ @Description FM port sysfs functions. ++ ++*/ ++ ++#ifndef LNXWRP_SYSFS_FM_PORT_H_ ++#define LNXWRP_SYSFS_FM_PORT_H_ ++ ++#include "lnxwrp_sysfs.h" ++ ++int fm_port_sysfs_create(struct device *dev); ++void fm_port_sysfs_destroy(struct device *dev); ++ ++int fm_port_dump_regs(void *h_dev, char *buf, int n); ++int fm_port_dump_regs_bmi(void *h_dev, char *buf, int n); ++int fm_port_dump_regs_qmi(void *h_dev, char *buf, int n); ++ ++#if (DPAA_VERSION >= 11) ++int fm_port_dump_ipv4_opt(void *h_dev, char *buf, int n); ++#endif ++ ++#endif /* LNXWRP_SYSFS_FM_PORT_H_ */ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/xx/Makefile b/drivers/net/ethernet/freescale/sdk_fman/src/xx/Makefile +new file mode 100644 +index 00000000..1071c22a +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/xx/Makefile +@@ -0,0 +1,18 @@ ++# ++# Makefile for the Freescale Ethernet controllers ++# ++ccflags-y += -DVERSION=\"\" ++# ++#Include netcomm SW specific definitions ++include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk ++ ++obj-y += fsl-ncsw-xx.o ++ ++ifneq ($(CONFIG_FMAN_ARM),y) ++fsl-ncsw-xx-objs := xx_linux.o \ ++ module_strings.o ++else ++fsl-ncsw-xx-objs := xx_arm_linux.o \ ++ module_strings.o ++endif ++ +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/xx/module_strings.c b/drivers/net/ethernet/freescale/sdk_fman/src/xx/module_strings.c +new file mode 100644 +index 00000000..d7fed170 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/xx/module_strings.c +@@ -0,0 +1,46 @@ ++/* ++ * Copyright 2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* Module names for debug messages */ ++const char *moduleStrings[] = ++{ ++ "", /* MODULE_UNKNOWN */ ++ "FM", /* MODULE_FM */ ++ "FM-MURAM", /* MODULE_FM_MURAM */ ++ "FM-PCD", /* MODULE_FM_PCD */ ++ "FM-RTC", /* MODULE_FM_RTC */ ++ "FM-MAC", /* MODULE_FM_MAC */ ++ "FM-Port", /* MODULE_FM_PORT */ ++ "MM", /* MODULE_MM */ ++ "FM-SP", /* MODULE_FM_SP */ ++ "FM-MACSEC" /* MODULE_FM_MACSEC */ ++}; +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_arm_linux.c b/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_arm_linux.c +new file mode 100644 +index 00000000..dd3e376e +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_arm_linux.c +@@ -0,0 +1,905 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/**************************************************************************//** ++ @File xx_arm_linux.c ++ ++ @Description XX routines implementation for Linux. ++*//***************************************************************************/ ++#include ++ ++#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) ++#define MODVERSIONS ++#endif ++#ifdef MODVERSIONS ++#include ++#endif /* MODVERSIONS */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#ifdef BIGPHYSAREA_ENABLE ++#include ++#endif /* BIGPHYSAREA_ENABLE */ ++ ++//#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "error_ext.h" ++#include "std_ext.h" ++#include "list_ext.h" ++#include "mm_ext.h" ++#include "sys_io_ext.h" ++#include "xx.h" ++ ++ ++#define __ERR_MODULE__ MODULE_UNKNOWN ++ ++#ifdef BIGPHYSAREA_ENABLE ++#define MAX_ALLOCATION_SIZE 128 * 1024 /* Maximum size allocated with kmalloc is 128K */ ++ ++ ++/* TODO: large allocations => use big phys area */ ++/****************************************************************************** ++ * routine: get_nr_pages ++ * ++ * description: ++ * calculates the number of memory pages for a given size (in bytes) ++ * ++ * arguments: ++ * size - the number of bytes ++ * ++ * return code: ++ * The number of pages ++ * ++ *****************************************************************************/ ++static __inline__ uint32_t get_nr_pages (uint32_t size) ++{ ++ return (uint32_t)((size >> PAGE_SHIFT) + (size & PAGE_SHIFT ? 1 : 0)); ++} ++ ++static bool in_big_phys_area (uint32_t addr) ++{ ++ uint32_t base, size; ++ ++ bigphysarea_get_details (&base, &size); ++ return ((addr >= base) && (addr < base + size)); ++} ++#endif /* BIGPHYSAREA_ENABLE */ ++ ++void * xx_Malloc(uint32_t n) ++{ ++ void *a; ++ uint32_t flags; ++ ++ flags = XX_DisableAllIntr(); ++#ifdef BIGPHYSAREA_ENABLE ++ if (n >= MAX_ALLOCATION_SIZE) ++ a = (void*)bigphysarea_alloc_pages(get_nr_pages(n), 0, GFP_ATOMIC); ++ else ++#endif /* BIGPHYSAREA_ENABLE */ ++ a = (void *)kmalloc((uint32_t)n, GFP_ATOMIC); ++ if (!a) ++ XX_Print("No memory for XX_Malloc\n"); ++ XX_RestoreAllIntr(flags); ++ ++ return a; ++} ++ ++void xx_Free(void *p) ++{ ++#ifdef BIGPHYSAREA_ENABLE ++ if (in_big_phys_area ((uint32_t)p)) ++ bigphysarea_free_pages(p); ++ else ++#endif /* BIGPHYSAREA_ENABLE */ ++ kfree(p); ++} ++ ++void XX_Exit(int status) ++{ ++ WARN(1, "\n\nFMD: fatal error, driver can't go on!!!\n\n"); ++} ++ ++#define BUF_SIZE 512 ++void XX_Print(char *str, ...) ++{ ++ va_list args; ++#ifdef CONFIG_SMP ++ char buf[BUF_SIZE]; ++#endif /* CONFIG_SMP */ ++ ++ va_start(args, str); ++#ifdef CONFIG_SMP ++ if (vsnprintf (buf, BUF_SIZE, str, args) >= BUF_SIZE) ++ printk(KERN_WARNING "Illegal string to print!\n more than %d characters.\n\tString was not printed completelly.\n", BUF_SIZE); ++ printk(KERN_CRIT "cpu %d: %s", raw_smp_processor_id(), buf); ++#else ++ vprintk(str, args); ++#endif /* CONFIG_SMP */ ++ va_end(args); ++} ++ ++void XX_Fprint(void *file, char *str, ...) ++{ ++ va_list args; ++#ifdef CONFIG_SMP ++ char buf[BUF_SIZE]; ++#endif /* CONFIG_SMP */ ++ ++ va_start(args, str); ++#ifdef CONFIG_SMP ++ if (vsnprintf (buf, BUF_SIZE, str, args) >= BUF_SIZE) ++ printk(KERN_WARNING "Illegal string to print!\n more than %d characters.\n\tString was not printed completelly.\n", BUF_SIZE); ++ printk (KERN_CRIT "cpu %d: %s", smp_processor_id(), buf); ++ ++#else ++ vprintk(str, args); ++#endif /* CONFIG_SMP */ ++ va_end(args); ++} ++ ++#ifdef DEBUG_XX_MALLOC ++typedef void (*t_ffn)(void *); ++typedef struct { ++ t_ffn f_free; ++ void *mem; ++ char *fname; ++ int fline; ++ uint32_t size; ++ t_List node; ++} t_MemDebug; ++#define MEMDBG_OBJECT(p_List) LIST_OBJECT(p_List, t_MemDebug, node) ++ ++LIST(memDbgLst); ++ ++ ++void * XX_MallocDebug(uint32_t size, char *fname, int line) ++{ ++ void *mem; ++ t_MemDebug *p_MemDbg; ++ ++ p_MemDbg = (t_MemDebug *)xx_Malloc(sizeof(t_MemDebug)); ++ if (p_MemDbg == NULL) ++ return NULL; ++ ++ mem = xx_Malloc(size); ++ if (mem == NULL) ++ { ++ XX_Free(p_MemDbg); ++ return NULL; ++ } ++ ++ INIT_LIST(&p_MemDbg->node); ++ p_MemDbg->f_free = xx_Free; ++ p_MemDbg->mem = mem; ++ p_MemDbg->fname = fname; ++ p_MemDbg->fline = line; ++ p_MemDbg->size = size+sizeof(t_MemDebug); ++ LIST_AddToTail(&p_MemDbg->node, &memDbgLst); ++ ++ return mem; ++} ++ ++void * XX_MallocSmartDebug(uint32_t size, ++ int memPartitionId, ++ uint32_t align, ++ char *fname, ++ int line) ++{ ++ void *mem; ++ t_MemDebug *p_MemDbg; ++ ++ p_MemDbg = (t_MemDebug *)XX_Malloc(sizeof(t_MemDebug)); ++ if (p_MemDbg == NULL) ++ return NULL; ++ ++ mem = xx_MallocSmart((uint32_t)size, memPartitionId, align); ++ if (mem == NULL) ++ { ++ XX_Free(p_MemDbg); ++ return NULL; ++ } ++ ++ INIT_LIST(&p_MemDbg->node); ++ p_MemDbg->f_free = xx_FreeSmart; ++ p_MemDbg->mem = mem; ++ p_MemDbg->fname = fname; ++ p_MemDbg->fline = line; ++ p_MemDbg->size = size+sizeof(t_MemDebug); ++ LIST_AddToTail(&p_MemDbg->node, &memDbgLst); ++ ++ return mem; ++} ++ ++static void debug_free(void *mem) ++{ ++ t_List *p_MemDbgLh = NULL; ++ t_MemDebug *p_MemDbg; ++ bool found = FALSE; ++ ++ if (LIST_IsEmpty(&memDbgLst)) ++ { ++ REPORT_ERROR(MAJOR, E_ALREADY_FREE, ("Unbalanced free (0x%08x)", mem)); ++ return; ++ } ++ ++ LIST_FOR_EACH(p_MemDbgLh, &memDbgLst) ++ { ++ p_MemDbg = MEMDBG_OBJECT(p_MemDbgLh); ++ if (p_MemDbg->mem == mem) ++ { ++ found = TRUE; ++ break; ++ } ++ } ++ ++ if (!found) ++ { ++ REPORT_ERROR(MAJOR, E_NOT_FOUND, ++ ("Attempt to free unallocated address (0x%08x)",mem)); ++ dump_stack(); ++ return; ++ } ++ ++ LIST_Del(p_MemDbgLh); ++ p_MemDbg->f_free(mem); ++ p_MemDbg->f_free(p_MemDbg); ++} ++ ++void XX_FreeSmart(void *p) ++{ ++ debug_free(p); ++} ++ ++ ++void XX_Free(void *p) ++{ ++ debug_free(p); ++} ++ ++#else /* not DEBUG_XX_MALLOC */ ++void * XX_Malloc(uint32_t size) ++{ ++ return xx_Malloc(size); ++} ++ ++void * XX_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment) ++{ ++ return xx_MallocSmart(size,memPartitionId, alignment); ++} ++ ++void XX_FreeSmart(void *p) ++{ ++ xx_FreeSmart(p); ++} ++ ++ ++void XX_Free(void *p) ++{ ++ xx_Free(p); ++} ++#endif /* not DEBUG_XX_MALLOC */ ++ ++ ++#if (defined(REPORT_EVENTS) && (REPORT_EVENTS > 0)) ++void XX_EventById(uint32_t event, t_Handle appId, uint16_t flags, char *msg) ++{ ++ e_Event eventCode = (e_Event)event; ++ ++ UNUSED(eventCode); ++ UNUSED(appId); ++ UNUSED(flags); ++ UNUSED(msg); ++} ++#endif /* (defined(REPORT_EVENTS) && ... */ ++ ++ ++uint32_t XX_DisableAllIntr(void) ++{ ++ unsigned long flags; ++ ++#ifdef local_irq_save_nort ++ local_irq_save_nort(flags); ++#else ++ local_irq_save(flags); ++#endif ++ ++ return (uint32_t)flags; ++} ++ ++void XX_RestoreAllIntr(uint32_t flags) ++{ ++#ifdef local_irq_restore_nort ++ local_irq_restore_nort((unsigned long)flags); ++#else ++ local_irq_restore((unsigned long)flags); ++#endif ++} ++ ++t_Error XX_Call( uint32_t qid, t_Error (* f)(t_Handle), t_Handle id, t_Handle appId, uint16_t flags ) ++{ ++ UNUSED(qid); ++ UNUSED(appId); ++ UNUSED(flags); ++ ++ return f(id); ++} ++ ++int XX_IsICacheEnable(void) ++{ ++ return TRUE; ++} ++ ++int XX_IsDCacheEnable(void) ++{ ++ return TRUE; ++} ++ ++ ++typedef struct { ++ t_Isr *f_Isr; ++ t_Handle handle; ++} t_InterruptHandler; ++ ++ ++t_Handle interruptHandlers[0x00010000]; ++ ++static irqreturn_t LinuxInterruptHandler (int irq, void *dev_id) ++{ ++ t_InterruptHandler *p_IntrHndl = (t_InterruptHandler *)dev_id; ++ p_IntrHndl->f_Isr(p_IntrHndl->handle); ++ return IRQ_HANDLED; ++} ++ ++t_Error XX_SetIntr(int irq, t_Isr *f_Isr, t_Handle handle) ++{ ++ const char *device; ++ t_InterruptHandler *p_IntrHndl; ++ ++ device = GetDeviceName(irq); ++ if (device == NULL) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Interrupt source - %d", irq)); ++ ++ p_IntrHndl = (t_InterruptHandler *)XX_Malloc(sizeof(t_InterruptHandler)); ++ if (p_IntrHndl == NULL) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); ++ p_IntrHndl->f_Isr = f_Isr; ++ p_IntrHndl->handle = handle; ++ interruptHandlers[irq] = p_IntrHndl; ++ ++ if (request_irq(GetDeviceIrqNum(irq), LinuxInterruptHandler, 0, device, p_IntrHndl) < 0) ++ RETURN_ERROR(MAJOR, E_BUSY, ("Can't get IRQ %s\n", device)); ++ disable_irq(GetDeviceIrqNum(irq)); ++ ++ return E_OK; ++} ++ ++t_Error XX_FreeIntr(int irq) ++{ ++ t_InterruptHandler *p_IntrHndl = interruptHandlers[irq]; ++ free_irq(GetDeviceIrqNum(irq), p_IntrHndl); ++ XX_Free(p_IntrHndl); ++ interruptHandlers[irq] = 0; ++ return E_OK; ++} ++ ++t_Error XX_EnableIntr(int irq) ++{ ++ enable_irq(GetDeviceIrqNum(irq)); ++ return E_OK; ++} ++ ++t_Error XX_DisableIntr(int irq) ++{ ++ disable_irq(GetDeviceIrqNum(irq)); ++ return E_OK; ++} ++ ++ ++/*****************************************************************************/ ++/* Tasklet Service Routines */ ++/*****************************************************************************/ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++typedef struct ++{ ++ t_Handle h_Data; ++ void (*f_Callback) (void *); ++ struct delayed_work dwork; ++} t_Tasklet; ++ ++static void GenericTaskletCallback(struct work_struct *p_Work) ++{ ++ t_Tasklet *p_Task = container_of(p_Work, t_Tasklet, dwork.work); ++ ++ p_Task->f_Callback(p_Task->h_Data); ++} ++#endif /* LINUX_VERSION_CODE */ ++ ++ ++t_TaskletHandle XX_InitTasklet (void (*routine)(void *), void *data) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ struct work_struct *p_Task; ++ p_Task = (struct work_struct *)XX_Malloc(sizeof(struct work_struct)); ++ INIT_WORK(p_Task, routine, data); ++#else ++ t_Tasklet *p_Task = (t_Tasklet *)XX_Malloc(sizeof(t_Tasklet)); ++ p_Task->h_Data = data; ++ p_Task->f_Callback = routine; ++ INIT_DELAYED_WORK(&p_Task->dwork, GenericTaskletCallback); ++#endif /* LINUX_VERSION_CODE */ ++ ++ return (t_TaskletHandle)p_Task; ++} ++ ++ ++void XX_FreeTasklet (t_TaskletHandle h_Tasklet) ++{ ++ if (h_Tasklet) ++ XX_Free(h_Tasklet); ++} ++ ++int XX_ScheduleTask(t_TaskletHandle h_Tasklet, int immediate) ++{ ++ int ans; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ if (immediate) ++ ans = schedule_work(h_Tasklet); ++ else ++ ans = schedule_delayed_work(h_Tasklet, 1); ++#else ++ if (immediate) ++ ans = schedule_delayed_work(&((t_Tasklet *)h_Tasklet)->dwork, 0); ++ else ++ ans = schedule_delayed_work(&((t_Tasklet *)h_Tasklet)->dwork, HZ); ++#endif /* LINUX_VERSION_CODE */ ++ ++ return ans; ++} ++ ++void XX_FlushScheduledTasks(void) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ flush_scheduled_tasks(); ++#else ++ flush_scheduled_work(); ++#endif /* LINUX_VERSION_CODE */ ++} ++ ++int XX_TaskletIsQueued(t_TaskletHandle h_Tasklet) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ return (int)(((struct work_struct *)h_Tasklet)->pending); ++#else ++ return (int)delayed_work_pending(&((t_Tasklet *)h_Tasklet)->dwork); ++#endif /* LINUX_VERSION_CODE */ ++} ++ ++void XX_SetTaskletData(t_TaskletHandle h_Tasklet, t_Handle data) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ ((struct tq_struct *)h_Tasklet)->data = data; ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ ((struct work_struct *)h_Tasklet)->data = data; ++#else ++ ((t_Tasklet *)h_Tasklet)->h_Data = data; ++#endif /* LINUX_VERSION_CODE */ ++} ++ ++t_Handle XX_GetTaskletData(t_TaskletHandle h_Tasklet) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ return (t_Handle)(((struct work_struct *)h_Tasklet)->data); ++#else ++ return ((t_Tasklet *)h_Tasklet)->h_Data; ++#endif /* LINUX_VERSION_CODE */ ++} ++ ++ ++/*****************************************************************************/ ++/* Spinlock Service Routines */ ++/*****************************************************************************/ ++ ++t_Handle XX_InitSpinlock(void) ++{ ++ spinlock_t *p_Spinlock = (spinlock_t *)XX_Malloc(sizeof(spinlock_t)); ++ if (!p_Spinlock) ++ return NULL; ++ ++ spin_lock_init(p_Spinlock); ++ ++ return (t_Handle)p_Spinlock; ++} ++ ++void XX_FreeSpinlock(t_Handle h_Spinlock) ++{ ++ if (h_Spinlock) ++ XX_Free(h_Spinlock); ++} ++ ++void XX_LockSpinlock(t_Handle h_Spinlock) ++{ ++ spin_lock((spinlock_t *)h_Spinlock); ++} ++ ++void XX_UnlockSpinlock(t_Handle h_Spinlock) ++{ ++ spin_unlock((spinlock_t *)h_Spinlock); ++} ++ ++uint32_t XX_LockIntrSpinlock(t_Handle h_Spinlock) ++{ ++ unsigned long intrFlags; ++ spin_lock_irqsave((spinlock_t *)h_Spinlock, intrFlags); ++ return intrFlags; ++} ++ ++void XX_UnlockIntrSpinlock(t_Handle h_Spinlock, uint32_t intrFlags) ++{ ++ spin_unlock_irqrestore((spinlock_t *)h_Spinlock, (unsigned long)intrFlags); ++} ++ ++ ++/*****************************************************************************/ ++/* Timers Service Routines */ ++/*****************************************************************************/ ++/* The time now is in mili sec. resolution */ ++uint32_t XX_CurrentTime(void) ++{ ++ return (jiffies*1000)/HZ; ++} ++ ++ ++t_Handle XX_CreateTimer(void) ++{ ++ struct timer_list *p_Timer = (struct timer_list *)XX_Malloc(sizeof(struct timer_list)); ++ if (p_Timer) ++ { ++ memset(p_Timer, 0, sizeof(struct timer_list)); ++ init_timer(p_Timer); ++ } ++ return (t_Handle)p_Timer; ++} ++ ++void XX_FreeTimer(t_Handle h_Timer) ++{ ++ if (h_Timer) ++ XX_Free(h_Timer); ++} ++ ++void XX_StartTimer(t_Handle h_Timer, ++ uint32_t msecs, ++ bool periodic, ++ void (*f_TimerExpired)(t_Handle), ++ t_Handle h_Arg) ++{ ++ int tmp_jiffies = (msecs*HZ)/1000; ++ struct timer_list *p_Timer = (struct timer_list *)h_Timer; ++ ++ SANITY_CHECK_RETURN((periodic == FALSE), E_NOT_SUPPORTED); ++ ++ p_Timer->function = (void (*)(unsigned long))f_TimerExpired; ++ p_Timer->data = (unsigned long)h_Arg; ++ if ((msecs*HZ)%1000) ++ tmp_jiffies++; ++ p_Timer->expires = (jiffies + tmp_jiffies); ++ ++ add_timer((struct timer_list *)h_Timer); ++} ++ ++void XX_SetTimerData(t_Handle h_Timer, t_Handle data) ++{ ++ struct timer_list *p_Timer = (struct timer_list *)h_Timer; ++ ++ p_Timer->data = (unsigned long)data; ++} ++ ++t_Handle XX_GetTimerData(t_Handle h_Timer) ++{ ++ struct timer_list *p_Timer = (struct timer_list *)h_Timer; ++ ++ return (t_Handle)p_Timer->data; ++} ++ ++uint32_t XX_GetExpirationTime(t_Handle h_Timer) ++{ ++ struct timer_list *p_Timer = (struct timer_list *)h_Timer; ++ ++ return (uint32_t)p_Timer->expires; ++} ++ ++void XX_StopTimer(t_Handle h_Timer) ++{ ++ del_timer((struct timer_list *)h_Timer); ++} ++ ++void XX_ModTimer(t_Handle h_Timer, uint32_t msecs) ++{ ++ int tmp_jiffies = (msecs*HZ)/1000; ++ ++ if ((msecs*HZ)%1000) ++ tmp_jiffies++; ++ mod_timer((struct timer_list *)h_Timer, jiffies + tmp_jiffies); ++} ++ ++int XX_TimerIsActive(t_Handle h_Timer) ++{ ++ return timer_pending((struct timer_list *)h_Timer); ++} ++ ++uint32_t XX_Sleep(uint32_t msecs) ++{ ++ int tmp_jiffies = (msecs*HZ)/1000; ++ ++ if ((msecs*HZ)%1000) ++ tmp_jiffies++; ++ return schedule_timeout(tmp_jiffies); ++} ++ ++/*BEWARE!!!!! UDelay routine is BUSY WAITTING!!!!!*/ ++void XX_UDelay(uint32_t usecs) ++{ ++ udelay(usecs); ++} ++ ++/* TODO: verify that these are correct */ ++#define MSG_BODY_SIZE 512 ++typedef t_Error (t_MsgHandler) (t_Handle h_Mod, uint32_t msgId, uint8_t msgBody[MSG_BODY_SIZE]); ++typedef void (t_MsgCompletionCB) (t_Handle h_Arg, uint8_t msgBody[MSG_BODY_SIZE]); ++t_Error XX_SendMessage(char *p_DestAddr, ++ uint32_t msgId, ++ uint8_t msgBody[MSG_BODY_SIZE], ++ t_MsgCompletionCB *f_CompletionCB, ++ t_Handle h_CBArg); ++ ++typedef struct { ++ char *p_Addr; ++ t_MsgHandler *f_MsgHandlerCB; ++ t_Handle h_Mod; ++ t_List node; ++} t_MsgHndlr; ++#define MSG_HNDLR_OBJECT(ptr) LIST_OBJECT(ptr, t_MsgHndlr, node) ++ ++LIST(msgHndlrList); ++ ++static void EnqueueMsgHndlr(t_MsgHndlr *p_MsgHndlr) ++{ ++ uint32_t intFlags; ++ ++ intFlags = XX_DisableAllIntr(); ++ LIST_AddToTail(&p_MsgHndlr->node, &msgHndlrList); ++ XX_RestoreAllIntr(intFlags); ++} ++/* TODO: add this for multi-platform support ++static t_MsgHndlr * DequeueMsgHndlr(void) ++{ ++ t_MsgHndlr *p_MsgHndlr = NULL; ++ uint32_t intFlags; ++ ++ intFlags = XX_DisableAllIntr(); ++ if (!LIST_IsEmpty(&msgHndlrList)) ++ { ++ p_MsgHndlr = MSG_HNDLR_OBJECT(msgHndlrList.p_Next); ++ LIST_DelAndInit(&p_MsgHndlr->node); ++ } ++ XX_RestoreAllIntr(intFlags); ++ ++ return p_MsgHndlr; ++} ++*/ ++static t_MsgHndlr * FindMsgHndlr(char *p_Addr) ++{ ++ t_MsgHndlr *p_MsgHndlr; ++ t_List *p_Pos; ++ ++ LIST_FOR_EACH(p_Pos, &msgHndlrList) ++ { ++ p_MsgHndlr = MSG_HNDLR_OBJECT(p_Pos); ++ if (strstr(p_MsgHndlr->p_Addr, p_Addr)) ++ return p_MsgHndlr; ++ } ++ ++ return NULL; ++} ++ ++t_Error XX_RegisterMessageHandler (char *p_Addr, t_MsgHandler *f_MsgHandlerCB, t_Handle h_Mod) ++{ ++ t_MsgHndlr *p_MsgHndlr; ++ uint32_t len; ++ ++ p_MsgHndlr = (t_MsgHndlr*)XX_Malloc(sizeof(t_MsgHndlr)); ++ if (!p_MsgHndlr) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("message handler object!!!")); ++ memset(p_MsgHndlr, 0, sizeof(t_MsgHndlr)); ++ ++ len = strlen(p_Addr); ++ p_MsgHndlr->p_Addr = (char*)XX_Malloc(len+1); ++ strncpy(p_MsgHndlr->p_Addr,p_Addr, (uint32_t)(len+1)); ++ ++ p_MsgHndlr->f_MsgHandlerCB = f_MsgHandlerCB; ++ p_MsgHndlr->h_Mod = h_Mod; ++ INIT_LIST(&p_MsgHndlr->node); ++ EnqueueMsgHndlr(p_MsgHndlr); ++ ++ return E_OK; ++} ++ ++t_Error XX_UnregisterMessageHandler (char *p_Addr) ++{ ++ t_MsgHndlr *p_MsgHndlr = FindMsgHndlr(p_Addr); ++ if (!p_MsgHndlr) ++ RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!")); ++ ++ LIST_Del(&p_MsgHndlr->node); ++ XX_Free(p_MsgHndlr->p_Addr); ++ XX_Free(p_MsgHndlr); ++ ++ return E_OK; ++} ++ ++t_Error XX_SendMessage(char *p_DestAddr, ++ uint32_t msgId, ++ uint8_t msgBody[MSG_BODY_SIZE], ++ t_MsgCompletionCB *f_CompletionCB, ++ t_Handle h_CBArg) ++{ ++ t_Error ans; ++ t_MsgHndlr *p_MsgHndlr = FindMsgHndlr(p_DestAddr); ++ if (!p_MsgHndlr) ++ RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!")); ++ ++ ans = p_MsgHndlr->f_MsgHandlerCB(p_MsgHndlr->h_Mod, msgId, msgBody); ++ ++ if (f_CompletionCB) ++ f_CompletionCB(h_CBArg, msgBody); ++ ++ return ans; ++} ++ ++t_Error XX_IpcRegisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH], ++ t_IpcMsgHandler *f_MsgHandler, ++ t_Handle h_Module, ++ uint32_t replyLength) ++{ ++ UNUSED(addr);UNUSED(f_MsgHandler);UNUSED(h_Module);UNUSED(replyLength); ++ return E_OK; ++} ++ ++t_Error XX_IpcUnregisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH]) ++{ ++ UNUSED(addr); ++ return E_OK; ++} ++ ++ ++t_Error XX_IpcSendMessage(t_Handle h_Session, ++ uint8_t *p_Msg, ++ uint32_t msgLength, ++ uint8_t *p_Reply, ++ uint32_t *p_ReplyLength, ++ t_IpcMsgCompletion *f_Completion, ++ t_Handle h_Arg) ++{ ++ UNUSED(h_Session); UNUSED(p_Msg); UNUSED(msgLength); UNUSED(p_Reply); ++ UNUSED(p_ReplyLength); UNUSED(f_Completion); UNUSED(h_Arg); ++ return E_OK; ++} ++ ++t_Handle XX_IpcInitSession(char destAddr[XX_IPC_MAX_ADDR_NAME_LENGTH], ++ char srcAddr[XX_IPC_MAX_ADDR_NAME_LENGTH]) ++{ ++ UNUSED(destAddr); UNUSED(srcAddr); ++ return E_OK; ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++int GetDeviceIrqNum(int irq) ++{ ++ struct device_node *iPar; ++ struct irq_domain *irqHost; ++ uint32_t hwIrq; ++ ++ /* Get the interrupt controller */ ++ iPar = of_find_node_by_name(NULL, "mpic"); ++ hwIrq = 0; ++ ++ ASSERT_COND(iPar != NULL); ++ /* Get the irq host */ ++ irqHost = irq_find_host(iPar); ++ of_node_put(iPar); ++ ++ /* Create irq mapping */ ++ return irq_create_mapping(irqHost, hwIrq); ++} ++#else ++#error "kernel not supported!!!" ++#endif /* LINUX_VERSION_CODE */ ++ ++void * XX_PhysToVirt(physAddress_t addr) ++{ ++ return UINT_TO_PTR(SYS_PhysToVirt((uint64_t)addr)); ++} ++ ++physAddress_t XX_VirtToPhys(void * addr) ++{ ++ return (physAddress_t)SYS_VirtToPhys(PTR_TO_UINT(addr)); ++} ++ ++void * xx_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment) ++{ ++ uintptr_t *returnCode, tmp; ++ ++ if (alignment < sizeof(uintptr_t)) ++ alignment = sizeof(uintptr_t); ++ size += alignment + sizeof(returnCode); ++ tmp = (uintptr_t)xx_Malloc(size); ++ if (tmp == 0) ++ return NULL; ++ returnCode = (uintptr_t*)((tmp + alignment + sizeof(returnCode)) & ~((uintptr_t)alignment - 1)); ++ *(returnCode - 1) = tmp; ++ ++ return (void*)returnCode; ++} ++ ++void xx_FreeSmart(void *p) ++{ ++ xx_Free((void*)(*((uintptr_t *)(p) - 1))); ++} +diff --git a/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_linux.c b/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_linux.c +new file mode 100644 +index 00000000..992757d4 +--- /dev/null ++++ b/drivers/net/ethernet/freescale/sdk_fman/src/xx/xx_linux.c +@@ -0,0 +1,918 @@ ++/* ++ * Copyright 2008-2012 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/**************************************************************************//** ++ @File xx_linux.c ++ ++ @Description XX routines implementation for Linux. ++*//***************************************************************************/ ++#include ++ ++#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) ++#define MODVERSIONS ++#endif ++#ifdef MODVERSIONS ++#include ++#endif /* MODVERSIONS */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef CONFIG_FMAN_ARM ++#include ++#endif ++ ++#include ++ ++#ifdef BIGPHYSAREA_ENABLE ++#include ++#endif /* BIGPHYSAREA_ENABLE */ ++ ++#ifndef CONFIG_FMAN_ARM ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "error_ext.h" ++#include "std_ext.h" ++#include "list_ext.h" ++#include "mm_ext.h" ++#include "sys_io_ext.h" ++#include "xx.h" ++ ++ ++#define __ERR_MODULE__ MODULE_UNKNOWN ++ ++#ifdef BIGPHYSAREA_ENABLE ++#define MAX_ALLOCATION_SIZE 128 * 1024 /* Maximum size allocated with kmalloc is 128K */ ++ ++ ++/* TODO: large allocations => use big phys area */ ++/****************************************************************************** ++ * routine: get_nr_pages ++ * ++ * description: ++ * calculates the number of memory pages for a given size (in bytes) ++ * ++ * arguments: ++ * size - the number of bytes ++ * ++ * return code: ++ * The number of pages ++ * ++ *****************************************************************************/ ++static __inline__ uint32_t get_nr_pages (uint32_t size) ++{ ++ return (uint32_t)((size >> PAGE_SHIFT) + (size & PAGE_SHIFT ? 1 : 0)); ++} ++ ++static bool in_big_phys_area (uint32_t addr) ++{ ++ uint32_t base, size; ++ ++ bigphysarea_get_details (&base, &size); ++ return ((addr >= base) && (addr < base + size)); ++} ++#endif /* BIGPHYSAREA_ENABLE */ ++ ++void * xx_Malloc(uint32_t n) ++{ ++ void *a; ++ uint32_t flags; ++ ++ flags = XX_DisableAllIntr(); ++#ifdef BIGPHYSAREA_ENABLE ++ if (n >= MAX_ALLOCATION_SIZE) ++ a = (void*)bigphysarea_alloc_pages(get_nr_pages(n), 0, GFP_ATOMIC); ++ else ++#endif /* BIGPHYSAREA_ENABLE */ ++ a = (void *)kmalloc((uint32_t)n, GFP_ATOMIC); ++ if (!a) ++ XX_Print("No memory for XX_Malloc\n"); ++ XX_RestoreAllIntr(flags); ++ ++ return a; ++} ++ ++void xx_Free(void *p) ++{ ++#ifdef BIGPHYSAREA_ENABLE ++ if (in_big_phys_area ((uint32_t)p)) ++ bigphysarea_free_pages(p); ++ else ++#endif /* BIGPHYSAREA_ENABLE */ ++ kfree(p); ++} ++ ++void XX_Exit(int status) ++{ ++ WARN(1, "\n\nFMD: fatal error, driver can't go on!!!\n\n"); ++} ++ ++#define BUF_SIZE 512 ++void XX_Print(char *str, ...) ++{ ++ va_list args; ++#ifdef CONFIG_SMP ++ char buf[BUF_SIZE]; ++#endif /* CONFIG_SMP */ ++ ++ va_start(args, str); ++#ifdef CONFIG_SMP ++ if (vsnprintf (buf, BUF_SIZE, str, args) >= BUF_SIZE) ++ printk(KERN_WARNING "Illegal string to print!\n more than %d characters.\n\tString was not printed completelly.\n", BUF_SIZE); ++ printk(KERN_CRIT "cpu%d/%d: %s", raw_smp_processor_id(), NR_CPUS, buf); ++#else ++ vprintk(str, args); ++#endif /* CONFIG_SMP */ ++ va_end(args); ++} ++ ++void XX_Fprint(void *file, char *str, ...) ++{ ++ va_list args; ++#ifdef CONFIG_SMP ++ char buf[BUF_SIZE]; ++#endif /* CONFIG_SMP */ ++ ++ va_start(args, str); ++#ifdef CONFIG_SMP ++ if (vsnprintf (buf, BUF_SIZE, str, args) >= BUF_SIZE) ++ printk(KERN_WARNING "Illegal string to print!\n more than %d characters.\n\tString was not printed completelly.\n", BUF_SIZE); ++ printk (KERN_CRIT "cpu%d/%d: %s", raw_smp_processor_id(), NR_CPUS, buf); ++ ++#else ++ vprintk(str, args); ++#endif /* CONFIG_SMP */ ++ va_end(args); ++} ++ ++#ifdef DEBUG_XX_MALLOC ++typedef void (*t_ffn)(void *); ++typedef struct { ++ t_ffn f_free; ++ void *mem; ++ char *fname; ++ int fline; ++ uint32_t size; ++ t_List node; ++} t_MemDebug; ++#define MEMDBG_OBJECT(p_List) LIST_OBJECT(p_List, t_MemDebug, node) ++ ++LIST(memDbgLst); ++ ++ ++void * XX_MallocDebug(uint32_t size, char *fname, int line) ++{ ++ void *mem; ++ t_MemDebug *p_MemDbg; ++ ++ p_MemDbg = (t_MemDebug *)xx_Malloc(sizeof(t_MemDebug)); ++ if (p_MemDbg == NULL) ++ return NULL; ++ ++ mem = xx_Malloc(size); ++ if (mem == NULL) ++ { ++ XX_Free(p_MemDbg); ++ return NULL; ++ } ++ ++ INIT_LIST(&p_MemDbg->node); ++ p_MemDbg->f_free = xx_Free; ++ p_MemDbg->mem = mem; ++ p_MemDbg->fname = fname; ++ p_MemDbg->fline = line; ++ p_MemDbg->size = size+sizeof(t_MemDebug); ++ LIST_AddToTail(&p_MemDbg->node, &memDbgLst); ++ ++ return mem; ++} ++ ++void * XX_MallocSmartDebug(uint32_t size, ++ int memPartitionId, ++ uint32_t align, ++ char *fname, ++ int line) ++{ ++ void *mem; ++ t_MemDebug *p_MemDbg; ++ ++ p_MemDbg = (t_MemDebug *)XX_Malloc(sizeof(t_MemDebug)); ++ if (p_MemDbg == NULL) ++ return NULL; ++ ++ mem = xx_MallocSmart((uint32_t)size, memPartitionId, align); ++ if (mem == NULL) ++ { ++ XX_Free(p_MemDbg); ++ return NULL; ++ } ++ ++ INIT_LIST(&p_MemDbg->node); ++ p_MemDbg->f_free = xx_FreeSmart; ++ p_MemDbg->mem = mem; ++ p_MemDbg->fname = fname; ++ p_MemDbg->fline = line; ++ p_MemDbg->size = size+sizeof(t_MemDebug); ++ LIST_AddToTail(&p_MemDbg->node, &memDbgLst); ++ ++ return mem; ++} ++ ++static void debug_free(void *mem) ++{ ++ t_List *p_MemDbgLh = NULL; ++ t_MemDebug *p_MemDbg; ++ bool found = FALSE; ++ ++ if (LIST_IsEmpty(&memDbgLst)) ++ { ++ REPORT_ERROR(MAJOR, E_ALREADY_FREE, ("Unbalanced free (0x%08x)", mem)); ++ return; ++ } ++ ++ LIST_FOR_EACH(p_MemDbgLh, &memDbgLst) ++ { ++ p_MemDbg = MEMDBG_OBJECT(p_MemDbgLh); ++ if (p_MemDbg->mem == mem) ++ { ++ found = TRUE; ++ break; ++ } ++ } ++ ++ if (!found) ++ { ++ REPORT_ERROR(MAJOR, E_NOT_FOUND, ++ ("Attempt to free unallocated address (0x%08x)",mem)); ++ dump_stack(); ++ return; ++ } ++ ++ LIST_Del(p_MemDbgLh); ++ p_MemDbg->f_free(mem); ++ p_MemDbg->f_free(p_MemDbg); ++} ++ ++void XX_FreeSmart(void *p) ++{ ++ debug_free(p); ++} ++ ++ ++void XX_Free(void *p) ++{ ++ debug_free(p); ++} ++ ++#else /* not DEBUG_XX_MALLOC */ ++void * XX_Malloc(uint32_t size) ++{ ++ return xx_Malloc(size); ++} ++ ++void * XX_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment) ++{ ++ return xx_MallocSmart(size,memPartitionId, alignment); ++} ++ ++void XX_FreeSmart(void *p) ++{ ++ xx_FreeSmart(p); ++} ++ ++ ++void XX_Free(void *p) ++{ ++ xx_Free(p); ++} ++#endif /* not DEBUG_XX_MALLOC */ ++ ++ ++#if (defined(REPORT_EVENTS) && (REPORT_EVENTS > 0)) ++void XX_EventById(uint32_t event, t_Handle appId, uint16_t flags, char *msg) ++{ ++ e_Event eventCode = (e_Event)event; ++ ++ UNUSED(eventCode); ++ UNUSED(appId); ++ UNUSED(flags); ++ UNUSED(msg); ++} ++#endif /* (defined(REPORT_EVENTS) && ... */ ++ ++ ++uint32_t XX_DisableAllIntr(void) ++{ ++ unsigned long flags; ++ ++#ifdef local_irq_save_nort ++ local_irq_save_nort(flags); ++#else ++ local_irq_save(flags); ++#endif ++ ++ return (uint32_t)flags; ++} ++ ++void XX_RestoreAllIntr(uint32_t flags) ++{ ++#ifdef local_irq_restore_nort ++ local_irq_restore_nort((unsigned long)flags); ++#else ++ local_irq_restore((unsigned long)flags); ++#endif ++} ++ ++t_Error XX_Call( uint32_t qid, t_Error (* f)(t_Handle), t_Handle id, t_Handle appId, uint16_t flags ) ++{ ++ UNUSED(qid); ++ UNUSED(appId); ++ UNUSED(flags); ++ ++ return f(id); ++} ++ ++int XX_IsICacheEnable(void) ++{ ++ return TRUE; ++} ++ ++int XX_IsDCacheEnable(void) ++{ ++ return TRUE; ++} ++ ++ ++typedef struct { ++ t_Isr *f_Isr; ++ t_Handle handle; ++} t_InterruptHandler; ++ ++ ++t_Handle interruptHandlers[0x00010000]; ++ ++#ifdef CONFIG_FMAN_ARM ++static irqreturn_t LinuxInterruptHandler (int irq, void *dev_id) ++{ ++ t_InterruptHandler *p_IntrHndl = (t_InterruptHandler *)dev_id; ++ p_IntrHndl->f_Isr(p_IntrHndl->handle); ++ return IRQ_HANDLED; ++} ++#endif ++ ++t_Error XX_SetIntr(int irq, t_Isr *f_Isr, t_Handle handle) ++{ ++#ifdef CONFIG_FMAN_ARM ++ const char *device; ++ t_InterruptHandler *p_IntrHndl; ++ ++ device = GetDeviceName(irq); ++ if (device == NULL) ++ RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Interrupt source - %d", irq)); ++ ++ p_IntrHndl = (t_InterruptHandler *)XX_Malloc(sizeof(t_InterruptHandler)); ++ if (p_IntrHndl == NULL) ++ RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); ++ p_IntrHndl->f_Isr = f_Isr; ++ p_IntrHndl->handle = handle; ++ interruptHandlers[irq] = p_IntrHndl; ++ ++ if (request_irq(GetDeviceIrqNum(irq), LinuxInterruptHandler, 0, device, p_IntrHndl) < 0) ++ RETURN_ERROR(MAJOR, E_BUSY, ("Can't get IRQ %s\n", device)); ++ disable_irq(GetDeviceIrqNum(irq)); ++#endif ++ return E_OK; ++} ++ ++t_Error XX_FreeIntr(int irq) ++{ ++ t_InterruptHandler *p_IntrHndl = interruptHandlers[irq]; ++ free_irq(GetDeviceIrqNum(irq), p_IntrHndl); ++ XX_Free(p_IntrHndl); ++ interruptHandlers[irq] = 0; ++ return E_OK; ++} ++ ++t_Error XX_EnableIntr(int irq) ++{ ++ enable_irq(GetDeviceIrqNum(irq)); ++ return E_OK; ++} ++ ++t_Error XX_DisableIntr(int irq) ++{ ++ disable_irq(GetDeviceIrqNum(irq)); ++ return E_OK; ++} ++ ++ ++/*****************************************************************************/ ++/* Tasklet Service Routines */ ++/*****************************************************************************/ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) ++typedef struct ++{ ++ t_Handle h_Data; ++ void (*f_Callback) (void *); ++ struct delayed_work dwork; ++} t_Tasklet; ++ ++static void GenericTaskletCallback(struct work_struct *p_Work) ++{ ++ t_Tasklet *p_Task = container_of(p_Work, t_Tasklet, dwork.work); ++ ++ p_Task->f_Callback(p_Task->h_Data); ++} ++#endif /* LINUX_VERSION_CODE */ ++ ++ ++t_TaskletHandle XX_InitTasklet (void (*routine)(void *), void *data) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ struct work_struct *p_Task; ++ p_Task = (struct work_struct *)XX_Malloc(sizeof(struct work_struct)); ++ INIT_WORK(p_Task, routine, data); ++#else ++ t_Tasklet *p_Task = (t_Tasklet *)XX_Malloc(sizeof(t_Tasklet)); ++ p_Task->h_Data = data; ++ p_Task->f_Callback = routine; ++ INIT_DELAYED_WORK(&p_Task->dwork, GenericTaskletCallback); ++#endif /* LINUX_VERSION_CODE */ ++ ++ return (t_TaskletHandle)p_Task; ++} ++ ++ ++void XX_FreeTasklet (t_TaskletHandle h_Tasklet) ++{ ++ if (h_Tasklet) ++ XX_Free(h_Tasklet); ++} ++ ++int XX_ScheduleTask(t_TaskletHandle h_Tasklet, int immediate) ++{ ++ int ans; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ if (immediate) ++ ans = schedule_work(h_Tasklet); ++ else ++ ans = schedule_delayed_work(h_Tasklet, 1); ++#else ++ if (immediate) ++ ans = schedule_delayed_work(&((t_Tasklet *)h_Tasklet)->dwork, 0); ++ else ++ ans = schedule_delayed_work(&((t_Tasklet *)h_Tasklet)->dwork, HZ); ++#endif /* LINUX_VERSION_CODE */ ++ ++ return ans; ++} ++ ++void XX_FlushScheduledTasks(void) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ flush_scheduled_tasks(); ++#else ++ flush_scheduled_work(); ++#endif /* LINUX_VERSION_CODE */ ++} ++ ++int XX_TaskletIsQueued(t_TaskletHandle h_Tasklet) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ return (int)(((struct work_struct *)h_Tasklet)->pending); ++#else ++ return (int)delayed_work_pending(&((t_Tasklet *)h_Tasklet)->dwork); ++#endif /* LINUX_VERSION_CODE */ ++} ++ ++void XX_SetTaskletData(t_TaskletHandle h_Tasklet, t_Handle data) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ ((struct tq_struct *)h_Tasklet)->data = data; ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ ((struct work_struct *)h_Tasklet)->data = data; ++#else ++ ((t_Tasklet *)h_Tasklet)->h_Data = data; ++#endif /* LINUX_VERSION_CODE */ ++} ++ ++t_Handle XX_GetTaskletData(t_TaskletHandle h_Tasklet) ++{ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++ return (t_Handle)(((struct work_struct *)h_Tasklet)->data); ++#else ++ return ((t_Tasklet *)h_Tasklet)->h_Data; ++#endif /* LINUX_VERSION_CODE */ ++} ++ ++ ++/*****************************************************************************/ ++/* Spinlock Service Routines */ ++/*****************************************************************************/ ++ ++t_Handle XX_InitSpinlock(void) ++{ ++ spinlock_t *p_Spinlock = (spinlock_t *)XX_Malloc(sizeof(spinlock_t)); ++ if (!p_Spinlock) ++ return NULL; ++ ++ spin_lock_init(p_Spinlock); ++ ++ return (t_Handle)p_Spinlock; ++} ++ ++void XX_FreeSpinlock(t_Handle h_Spinlock) ++{ ++ if (h_Spinlock) ++ XX_Free(h_Spinlock); ++} ++ ++void XX_LockSpinlock(t_Handle h_Spinlock) ++{ ++ spin_lock((spinlock_t *)h_Spinlock); ++} ++ ++void XX_UnlockSpinlock(t_Handle h_Spinlock) ++{ ++ spin_unlock((spinlock_t *)h_Spinlock); ++} ++ ++uint32_t XX_LockIntrSpinlock(t_Handle h_Spinlock) ++{ ++ unsigned long intrFlags; ++ spin_lock_irqsave((spinlock_t *)h_Spinlock, intrFlags); ++ return intrFlags; ++} ++ ++void XX_UnlockIntrSpinlock(t_Handle h_Spinlock, uint32_t intrFlags) ++{ ++ spin_unlock_irqrestore((spinlock_t *)h_Spinlock, (unsigned long)intrFlags); ++} ++ ++ ++/*****************************************************************************/ ++/* Timers Service Routines */ ++/*****************************************************************************/ ++/* The time now is in mili sec. resolution */ ++uint32_t XX_CurrentTime(void) ++{ ++ return (jiffies*1000)/HZ; ++} ++ ++ ++t_Handle XX_CreateTimer(void) ++{ ++ struct timer_list *p_Timer = (struct timer_list *)XX_Malloc(sizeof(struct timer_list)); ++ if (p_Timer) ++ { ++ memset(p_Timer, 0, sizeof(struct timer_list)); ++ init_timer(p_Timer); ++ } ++ return (t_Handle)p_Timer; ++} ++ ++void XX_FreeTimer(t_Handle h_Timer) ++{ ++ if (h_Timer) ++ XX_Free(h_Timer); ++} ++ ++void XX_StartTimer(t_Handle h_Timer, ++ uint32_t msecs, ++ bool periodic, ++ void (*f_TimerExpired)(t_Handle), ++ t_Handle h_Arg) ++{ ++ int tmp_jiffies = (msecs*HZ)/1000; ++ struct timer_list *p_Timer = (struct timer_list *)h_Timer; ++ ++ SANITY_CHECK_RETURN((periodic == FALSE), E_NOT_SUPPORTED); ++ ++ p_Timer->function = (void (*)(unsigned long))f_TimerExpired; ++ p_Timer->data = (unsigned long)h_Arg; ++ if ((msecs*HZ)%1000) ++ tmp_jiffies++; ++ p_Timer->expires = (jiffies + tmp_jiffies); ++ ++ add_timer((struct timer_list *)h_Timer); ++} ++ ++void XX_SetTimerData(t_Handle h_Timer, t_Handle data) ++{ ++ struct timer_list *p_Timer = (struct timer_list *)h_Timer; ++ ++ p_Timer->data = (unsigned long)data; ++} ++ ++t_Handle XX_GetTimerData(t_Handle h_Timer) ++{ ++ struct timer_list *p_Timer = (struct timer_list *)h_Timer; ++ ++ return (t_Handle)p_Timer->data; ++} ++ ++uint32_t XX_GetExpirationTime(t_Handle h_Timer) ++{ ++ struct timer_list *p_Timer = (struct timer_list *)h_Timer; ++ ++ return (uint32_t)p_Timer->expires; ++} ++ ++void XX_StopTimer(t_Handle h_Timer) ++{ ++ del_timer((struct timer_list *)h_Timer); ++} ++ ++void XX_ModTimer(t_Handle h_Timer, uint32_t msecs) ++{ ++ int tmp_jiffies = (msecs*HZ)/1000; ++ ++ if ((msecs*HZ)%1000) ++ tmp_jiffies++; ++ mod_timer((struct timer_list *)h_Timer, jiffies + tmp_jiffies); ++} ++ ++int XX_TimerIsActive(t_Handle h_Timer) ++{ ++ return timer_pending((struct timer_list *)h_Timer); ++} ++ ++uint32_t XX_Sleep(uint32_t msecs) ++{ ++ int tmp_jiffies = (msecs*HZ)/1000; ++ ++ if ((msecs*HZ)%1000) ++ tmp_jiffies++; ++ return schedule_timeout(tmp_jiffies); ++} ++ ++/*BEWARE!!!!! UDelay routine is BUSY WAITTING!!!!!*/ ++void XX_UDelay(uint32_t usecs) ++{ ++ udelay(usecs); ++} ++ ++/* TODO: verify that these are correct */ ++#define MSG_BODY_SIZE 512 ++typedef t_Error (t_MsgHandler) (t_Handle h_Mod, uint32_t msgId, uint8_t msgBody[MSG_BODY_SIZE]); ++typedef void (t_MsgCompletionCB) (t_Handle h_Arg, uint8_t msgBody[MSG_BODY_SIZE]); ++t_Error XX_SendMessage(char *p_DestAddr, ++ uint32_t msgId, ++ uint8_t msgBody[MSG_BODY_SIZE], ++ t_MsgCompletionCB *f_CompletionCB, ++ t_Handle h_CBArg); ++ ++typedef struct { ++ char *p_Addr; ++ t_MsgHandler *f_MsgHandlerCB; ++ t_Handle h_Mod; ++ t_List node; ++} t_MsgHndlr; ++#define MSG_HNDLR_OBJECT(ptr) LIST_OBJECT(ptr, t_MsgHndlr, node) ++ ++LIST(msgHndlrList); ++ ++static void EnqueueMsgHndlr(t_MsgHndlr *p_MsgHndlr) ++{ ++ uint32_t intFlags; ++ ++ intFlags = XX_DisableAllIntr(); ++ LIST_AddToTail(&p_MsgHndlr->node, &msgHndlrList); ++ XX_RestoreAllIntr(intFlags); ++} ++/* TODO: add this for multi-platform support ++static t_MsgHndlr * DequeueMsgHndlr(void) ++{ ++ t_MsgHndlr *p_MsgHndlr = NULL; ++ uint32_t intFlags; ++ ++ intFlags = XX_DisableAllIntr(); ++ if (!LIST_IsEmpty(&msgHndlrList)) ++ { ++ p_MsgHndlr = MSG_HNDLR_OBJECT(msgHndlrList.p_Next); ++ LIST_DelAndInit(&p_MsgHndlr->node); ++ } ++ XX_RestoreAllIntr(intFlags); ++ ++ return p_MsgHndlr; ++} ++*/ ++static t_MsgHndlr * FindMsgHndlr(char *p_Addr) ++{ ++ t_MsgHndlr *p_MsgHndlr; ++ t_List *p_Pos; ++ ++ LIST_FOR_EACH(p_Pos, &msgHndlrList) ++ { ++ p_MsgHndlr = MSG_HNDLR_OBJECT(p_Pos); ++ if (strstr(p_MsgHndlr->p_Addr, p_Addr)) ++ return p_MsgHndlr; ++ } ++ ++ return NULL; ++} ++ ++t_Error XX_RegisterMessageHandler (char *p_Addr, t_MsgHandler *f_MsgHandlerCB, t_Handle h_Mod) ++{ ++ t_MsgHndlr *p_MsgHndlr; ++ uint32_t len; ++ ++ p_MsgHndlr = (t_MsgHndlr*)XX_Malloc(sizeof(t_MsgHndlr)); ++ if (!p_MsgHndlr) ++ RETURN_ERROR(MINOR, E_NO_MEMORY, ("message handler object!!!")); ++ memset(p_MsgHndlr, 0, sizeof(t_MsgHndlr)); ++ ++ len = strlen(p_Addr); ++ p_MsgHndlr->p_Addr = (char*)XX_Malloc(len+1); ++ strncpy(p_MsgHndlr->p_Addr,p_Addr, (uint32_t)(len+1)); ++ ++ p_MsgHndlr->f_MsgHandlerCB = f_MsgHandlerCB; ++ p_MsgHndlr->h_Mod = h_Mod; ++ INIT_LIST(&p_MsgHndlr->node); ++ EnqueueMsgHndlr(p_MsgHndlr); ++ ++ return E_OK; ++} ++ ++t_Error XX_UnregisterMessageHandler (char *p_Addr) ++{ ++ t_MsgHndlr *p_MsgHndlr = FindMsgHndlr(p_Addr); ++ if (!p_MsgHndlr) ++ RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!")); ++ ++ LIST_Del(&p_MsgHndlr->node); ++ XX_Free(p_MsgHndlr->p_Addr); ++ XX_Free(p_MsgHndlr); ++ ++ return E_OK; ++} ++ ++t_Error XX_SendMessage(char *p_DestAddr, ++ uint32_t msgId, ++ uint8_t msgBody[MSG_BODY_SIZE], ++ t_MsgCompletionCB *f_CompletionCB, ++ t_Handle h_CBArg) ++{ ++ t_Error ans; ++ t_MsgHndlr *p_MsgHndlr = FindMsgHndlr(p_DestAddr); ++ if (!p_MsgHndlr) ++ RETURN_ERROR(MINOR, E_NO_DEVICE, ("message handler not found in list!!!")); ++ ++ ans = p_MsgHndlr->f_MsgHandlerCB(p_MsgHndlr->h_Mod, msgId, msgBody); ++ ++ if (f_CompletionCB) ++ f_CompletionCB(h_CBArg, msgBody); ++ ++ return ans; ++} ++ ++t_Error XX_IpcRegisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH], ++ t_IpcMsgHandler *f_MsgHandler, ++ t_Handle h_Module, ++ uint32_t replyLength) ++{ ++ UNUSED(addr);UNUSED(f_MsgHandler);UNUSED(h_Module);UNUSED(replyLength); ++ return E_OK; ++} ++ ++t_Error XX_IpcUnregisterMsgHandler(char addr[XX_IPC_MAX_ADDR_NAME_LENGTH]) ++{ ++ UNUSED(addr); ++ return E_OK; ++} ++ ++ ++t_Error XX_IpcSendMessage(t_Handle h_Session, ++ uint8_t *p_Msg, ++ uint32_t msgLength, ++ uint8_t *p_Reply, ++ uint32_t *p_ReplyLength, ++ t_IpcMsgCompletion *f_Completion, ++ t_Handle h_Arg) ++{ ++ UNUSED(h_Session); UNUSED(p_Msg); UNUSED(msgLength); UNUSED(p_Reply); ++ UNUSED(p_ReplyLength); UNUSED(f_Completion); UNUSED(h_Arg); ++ return E_OK; ++} ++ ++t_Handle XX_IpcInitSession(char destAddr[XX_IPC_MAX_ADDR_NAME_LENGTH], ++ char srcAddr[XX_IPC_MAX_ADDR_NAME_LENGTH]) ++{ ++ UNUSED(destAddr); UNUSED(srcAddr); ++ return E_OK; ++} ++ ++/*Forced to introduce due to PRINT_FMT_PARAMS define*/ ++uint32_t E500_GetId(void) ++{ ++ return raw_smp_processor_id(); ++} ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) ++int GetDeviceIrqNum(int irq) ++{ ++ struct device_node *iPar; ++ struct irq_domain *irqHost; ++ uint32_t hwIrq; ++ ++ /* Get the interrupt controller */ ++ iPar = of_find_node_by_name(NULL, "mpic"); ++ hwIrq = 0; ++ ++ ASSERT_COND(iPar != NULL); ++ /* Get the irq host */ ++ irqHost = irq_find_host(iPar); ++ of_node_put(iPar); ++ ++ /* Create irq mapping */ ++ return irq_create_mapping(irqHost, hwIrq); ++} ++#else ++#error "kernel not supported!!!" ++#endif /* LINUX_VERSION_CODE */ ++ ++void * XX_PhysToVirt(physAddress_t addr) ++{ ++ return UINT_TO_PTR(SYS_PhysToVirt((uint64_t)addr)); ++} ++ ++physAddress_t XX_VirtToPhys(void * addr) ++{ ++ return (physAddress_t)SYS_VirtToPhys(PTR_TO_UINT(addr)); ++} ++ ++void * xx_MallocSmart(uint32_t size, int memPartitionId, uint32_t alignment) ++{ ++ uintptr_t *returnCode, tmp; ++ ++ if (alignment < sizeof(uintptr_t)) ++ alignment = sizeof(uintptr_t); ++ size += alignment + sizeof(returnCode); ++ tmp = (uintptr_t)xx_Malloc(size); ++ if (tmp == 0) ++ return NULL; ++ returnCode = (uintptr_t*)((tmp + alignment + sizeof(returnCode)) & ~((uintptr_t)alignment - 1)); ++ *(returnCode - 1) = tmp; ++ ++ return (void*)returnCode; ++} ++ ++void xx_FreeSmart(void *p) ++{ ++ xx_Free((void*)(*((uintptr_t *)(p) - 1))); ++} +diff --git a/drivers/staging/fsl_qbman/Kconfig b/drivers/staging/fsl_qbman/Kconfig +new file mode 100644 +index 00000000..93dcb7d3 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/Kconfig +@@ -0,0 +1,228 @@ ++config FSL_SDK_DPA ++ bool "Freescale Datapath Queue and Buffer management" ++ depends on !FSL_DPAA ++ select FSL_QMAN_FQ_LOOKUP if PPC64 ++ select FSL_QMAN_FQ_LOOKUP if ARM64 ++ ++ ++menu "Freescale Datapath QMan/BMan options" ++ depends on FSL_SDK_DPA ++ ++config FSL_DPA_CHECKING ++ bool "additional driver checking" ++ default n ++ ---help--- ++ Compiles in additional checks to sanity-check the drivers and any ++ use of it by other code. Not recommended for performance. ++ ++config FSL_DPA_CAN_WAIT ++ bool ++ default y ++ ++config FSL_DPA_CAN_WAIT_SYNC ++ bool ++ default y ++ ++config FSL_DPA_PIRQ_FAST ++ bool ++ default y ++ ++config FSL_DPA_PIRQ_SLOW ++ bool ++ default y ++ ++config FSL_DPA_PORTAL_SHARE ++ bool ++ default y ++ ++config FSL_SDK_BMAN ++ bool "Freescale Buffer Manager (BMan) support" ++ default y ++ ++if FSL_SDK_BMAN ++ ++config FSL_BMAN_CONFIG ++ bool "BMan device management" ++ default y ++ ---help--- ++ If this linux image is running natively, you need this option. If this ++ linux image is running as a guest OS under the hypervisor, only one ++ guest OS ("the control plane") needs this option. ++ ++config FSL_BMAN_TEST ++ tristate "BMan self-tests" ++ default n ++ ---help--- ++ This option compiles self-test code for BMan. ++ ++config FSL_BMAN_TEST_HIGH ++ bool "BMan high-level self-test" ++ depends on FSL_BMAN_TEST ++ default y ++ ---help--- ++ This requires the presence of cpu-affine portals, and performs ++ high-level API testing with them (whichever portal(s) are affine to ++ the cpu(s) the test executes on). ++ ++config FSL_BMAN_TEST_THRESH ++ bool "BMan threshold test" ++ depends on FSL_BMAN_TEST ++ default y ++ ---help--- ++ Multi-threaded (SMP) test of BMan pool depletion. A pool is seeded ++ before multiple threads (one per cpu) create pool objects to track ++ depletion state changes. The pool is then drained to empty by a ++ "drainer" thread, and the other threads that they observe exactly ++ the depletion state changes that are expected. ++ ++config FSL_BMAN_DEBUGFS ++ tristate "BMan debugfs interface" ++ depends on DEBUG_FS ++ default y ++ ---help--- ++ This option compiles debugfs code for BMan. ++ ++endif # FSL_SDK_BMAN ++ ++config FSL_SDK_QMAN ++ bool "Freescale Queue Manager (QMan) support" ++ default y ++ ++if FSL_SDK_QMAN ++ ++config FSL_QMAN_POLL_LIMIT ++ int ++ default 32 ++ ++config FSL_QMAN_CONFIG ++ bool "QMan device management" ++ default y ++ ---help--- ++ If this linux image is running natively, you need this option. If this ++ linux image is running as a guest OS under the hypervisor, only one ++ guest OS ("the control plane") needs this option. ++ ++config FSL_QMAN_TEST ++ tristate "QMan self-tests" ++ default n ++ ---help--- ++ This option compiles self-test code for QMan. ++ ++config FSL_QMAN_TEST_STASH_POTATO ++ bool "QMan 'hot potato' data-stashing self-test" ++ depends on FSL_QMAN_TEST ++ default y ++ ---help--- ++ This performs a "hot potato" style test enqueuing/dequeuing a frame ++ across a series of FQs scheduled to different portals (and cpus), with ++ DQRR, data and context stashing always on. ++ ++config FSL_QMAN_TEST_HIGH ++ bool "QMan high-level self-test" ++ depends on FSL_QMAN_TEST ++ default y ++ ---help--- ++ This requires the presence of cpu-affine portals, and performs ++ high-level API testing with them (whichever portal(s) are affine to ++ the cpu(s) the test executes on). ++ ++config FSL_QMAN_DEBUGFS ++ tristate "QMan debugfs interface" ++ depends on DEBUG_FS ++ default y ++ ---help--- ++ This option compiles debugfs code for QMan. ++ ++# H/w settings that can be hard-coded for now. ++config FSL_QMAN_FQD_SZ ++ int "size of Frame Queue Descriptor region" ++ default 10 ++ ---help--- ++ This is the size of the FQD region defined as: PAGE_SIZE * (2^value) ++ ex: 10 => PAGE_SIZE * (2^10) ++ Note: Default device-trees now require minimum Kconfig setting of 10. ++ ++config FSL_QMAN_PFDR_SZ ++ int "size of the PFDR pool" ++ default 13 ++ ---help--- ++ This is the size of the PFDR pool defined as: PAGE_SIZE * (2^value) ++ ex: 13 => PAGE_SIZE * (2^13) ++ ++# Corenet initiator settings. Stash request queues are 4-deep to match cores' ++# ability to snart. Stash priority is 3, other priorities are 2. ++config FSL_QMAN_CI_SCHED_CFG_SRCCIV ++ int ++ depends on FSL_QMAN_CONFIG ++ default 4 ++config FSL_QMAN_CI_SCHED_CFG_SRQ_W ++ int ++ depends on FSL_QMAN_CONFIG ++ default 3 ++config FSL_QMAN_CI_SCHED_CFG_RW_W ++ int ++ depends on FSL_QMAN_CONFIG ++ default 2 ++config FSL_QMAN_CI_SCHED_CFG_BMAN_W ++ int ++ depends on FSL_QMAN_CONFIG ++ default 2 ++ ++# portal interrupt settings ++config FSL_QMAN_PIRQ_DQRR_ITHRESH ++ int ++ default 12 ++config FSL_QMAN_PIRQ_MR_ITHRESH ++ int ++ default 4 ++config FSL_QMAN_PIRQ_IPERIOD ++ int ++ default 100 ++ ++# 64 bit kernel support ++config FSL_QMAN_FQ_LOOKUP ++ bool ++ default n ++ ++config QMAN_CEETM_UPDATE_PERIOD ++ int "Token update period for shaping, in nanoseconds" ++ default 1000 ++ ---help--- ++ Traffic shaping works by performing token calculations (using ++ credits) on shaper instances periodically. This update period ++ sets the granularity for how often those token rate credit ++ updates are performed, and thus determines the accuracy and ++ range of traffic rates that can be configured by users. The ++ reference manual recommends a 1 microsecond period as providing ++ a good balance between granularity and range. ++ ++ Unless you know what you are doing, leave this value at its default. ++ ++config FSL_QMAN_INIT_TIMEOUT ++ int "timeout for qman init stage, in seconds" ++ default 10 ++ ---help--- ++ The timeout setting to quit the initialization loop for non-control ++ partition in case the control partition fails to boot-up. ++ ++endif # FSL_SDK_QMAN ++ ++config FSL_USDPAA ++ bool "Freescale USDPAA process driver" ++ depends on FSL_SDK_DPA ++ default y ++ ---help--- ++ This driver provides user-space access to kernel-managed ++ resource interfaces for USDPAA applications, on the assumption ++ that each process will open this device once. Specifically, this ++ device exposes functionality that would be awkward if exposed ++ via the portal devices - ie. this device exposes functionality ++ that is inherently process-wide rather than portal-specific. ++ This device is necessary for obtaining access to DMA memory and ++ for allocation of Qman and Bman resources. In short, if you wish ++ to use USDPAA applications, you need this. ++ ++ If unsure, say Y. ++ ++ ++endmenu +diff --git a/drivers/staging/fsl_qbman/Makefile b/drivers/staging/fsl_qbman/Makefile +new file mode 100644 +index 00000000..777d7d34 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/Makefile +@@ -0,0 +1,28 @@ ++subdir-ccflags-y := -Werror ++ ++# Common ++obj-$(CONFIG_FSL_SDK_DPA) += dpa_alloc.o ++obj-$(CONFIG_FSL_SDK_DPA) += qbman_driver.o ++ ++# Bman ++obj-$(CONFIG_FSL_SDK_BMAN) += bman_high.o ++obj-$(CONFIG_FSL_BMAN_CONFIG) += bman_config.o bman_driver.o ++obj-$(CONFIG_FSL_BMAN_TEST) += bman_tester.o ++obj-$(CONFIG_FSL_BMAN_DEBUGFS) += bman_debugfs_interface.o ++bman_tester-y = bman_test.o ++bman_tester-$(CONFIG_FSL_BMAN_TEST_HIGH) += bman_test_high.o ++bman_tester-$(CONFIG_FSL_BMAN_TEST_THRESH) += bman_test_thresh.o ++bman_debugfs_interface-y = bman_debugfs.o ++ ++# Qman ++obj-$(CONFIG_FSL_SDK_QMAN) += qman_high.o qman_utility.o ++obj-$(CONFIG_FSL_QMAN_CONFIG) += qman_config.o qman_driver.o ++obj-$(CONFIG_FSL_QMAN_TEST) += qman_tester.o ++qman_tester-y = qman_test.o ++qman_tester-$(CONFIG_FSL_QMAN_TEST_STASH_POTATO) += qman_test_hotpotato.o ++qman_tester-$(CONFIG_FSL_QMAN_TEST_HIGH) += qman_test_high.o ++obj-$(CONFIG_FSL_QMAN_DEBUGFS) += qman_debugfs_interface.o ++qman_debugfs_interface-y = qman_debugfs.o ++ ++# USDPAA ++obj-$(CONFIG_FSL_USDPAA) += fsl_usdpaa.o fsl_usdpaa_irq.o +diff --git a/drivers/staging/fsl_qbman/bman_config.c b/drivers/staging/fsl_qbman/bman_config.c +new file mode 100644 +index 00000000..bb397730 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/bman_config.c +@@ -0,0 +1,720 @@ ++/* Copyright (c) 2009-2012 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include "bman_private.h" ++#include ++ ++/* Last updated for v00.79 of the BG */ ++ ++struct bman; ++ ++/* Register offsets */ ++#define REG_POOL_SWDET(n) (0x0000 + ((n) * 0x04)) ++#define REG_POOL_HWDET(n) (0x0100 + ((n) * 0x04)) ++#define REG_POOL_SWDXT(n) (0x0200 + ((n) * 0x04)) ++#define REG_POOL_HWDXT(n) (0x0300 + ((n) * 0x04)) ++#define REG_POOL_CONTENT(n) (0x0600 + ((n) * 0x04)) ++#define REG_FBPR_FPC 0x0800 ++#define REG_STATE_IDLE 0x960 ++#define REG_STATE_STOP 0x964 ++#define REG_ECSR 0x0a00 ++#define REG_ECIR 0x0a04 ++#define REG_EADR 0x0a08 ++#define REG_EDATA(n) (0x0a10 + ((n) * 0x04)) ++#define REG_SBEC(n) (0x0a80 + ((n) * 0x04)) ++#define REG_IP_REV_1 0x0bf8 ++#define REG_IP_REV_2 0x0bfc ++#define REG_FBPR_BARE 0x0c00 ++#define REG_FBPR_BAR 0x0c04 ++#define REG_FBPR_AR 0x0c10 ++#define REG_SRCIDR 0x0d04 ++#define REG_LIODNR 0x0d08 ++#define REG_ERR_ISR 0x0e00 /* + "enum bm_isr_reg" */ ++ ++/* Used by all error interrupt registers except 'inhibit' */ ++#define BM_EIRQ_IVCI 0x00000010 /* Invalid Command Verb */ ++#define BM_EIRQ_FLWI 0x00000008 /* FBPR Low Watermark */ ++#define BM_EIRQ_MBEI 0x00000004 /* Multi-bit ECC Error */ ++#define BM_EIRQ_SBEI 0x00000002 /* Single-bit ECC Error */ ++#define BM_EIRQ_BSCN 0x00000001 /* pool State Change Notification */ ++ ++/* BMAN_ECIR valid error bit */ ++#define PORTAL_ECSR_ERR (BM_EIRQ_IVCI) ++ ++union bman_ecir { ++ u32 ecir_raw; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u32 __reserved1:4; ++ u32 portal_num:4; ++ u32 __reserved2:12; ++ u32 numb:4; ++ u32 __reserved3:2; ++ u32 pid:6; ++#else ++ u32 pid:6; ++ u32 __reserved3:2; ++ u32 numb:4; ++ u32 __reserved2:12; ++ u32 portal_num:4; ++ u32 __reserved1:4; ++#endif ++ } __packed info; ++}; ++ ++union bman_eadr { ++ u32 eadr_raw; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u32 __reserved1:5; ++ u32 memid:3; ++ u32 __reserved2:14; ++ u32 eadr:10; ++#else ++ u32 eadr:10; ++ u32 __reserved2:14; ++ u32 memid:3; ++ u32 __reserved1:5; ++#endif ++ } __packed info; ++}; ++ ++struct bman_hwerr_txt { ++ u32 mask; ++ const char *txt; ++}; ++ ++#define BMAN_HWE_TXT(a, b) { .mask = BM_EIRQ_##a, .txt = b } ++ ++static const struct bman_hwerr_txt bman_hwerr_txts[] = { ++ BMAN_HWE_TXT(IVCI, "Invalid Command Verb"), ++ BMAN_HWE_TXT(FLWI, "FBPR Low Watermark"), ++ BMAN_HWE_TXT(MBEI, "Multi-bit ECC Error"), ++ BMAN_HWE_TXT(SBEI, "Single-bit ECC Error"), ++ BMAN_HWE_TXT(BSCN, "Pool State Change Notification"), ++}; ++#define BMAN_HWE_COUNT (sizeof(bman_hwerr_txts)/sizeof(struct bman_hwerr_txt)) ++ ++struct bman_error_info_mdata { ++ u16 addr_mask; ++ u16 bits; ++ const char *txt; ++}; ++ ++#define BMAN_ERR_MDATA(a, b, c) { .addr_mask = a, .bits = b, .txt = c} ++static const struct bman_error_info_mdata error_mdata[] = { ++ BMAN_ERR_MDATA(0x03FF, 192, "Stockpile memory"), ++ BMAN_ERR_MDATA(0x00FF, 256, "SW portal ring memory port 1"), ++ BMAN_ERR_MDATA(0x00FF, 256, "SW portal ring memory port 2"), ++}; ++#define BMAN_ERR_MDATA_COUNT \ ++ (sizeof(error_mdata)/sizeof(struct bman_error_info_mdata)) ++ ++/* Add this in Kconfig */ ++#define BMAN_ERRS_TO_UNENABLE (BM_EIRQ_FLWI) ++ ++/** ++ * bm_err_isr__ - Manipulate global interrupt registers ++ * @v: for accessors that write values, this is the 32-bit value ++ * ++ * Manipulates BMAN_ERR_ISR, BMAN_ERR_IER, BMAN_ERR_ISDR, BMAN_ERR_IIR. All ++ * manipulations except bm_err_isr_[un]inhibit() use 32-bit masks composed of ++ * the BM_EIRQ_*** definitions. Note that "bm_err_isr_enable_write" means ++ * "write the enable register" rather than "enable the write register"! ++ */ ++#define bm_err_isr_status_read(bm) \ ++ __bm_err_isr_read(bm, bm_isr_status) ++#define bm_err_isr_status_clear(bm, m) \ ++ __bm_err_isr_write(bm, bm_isr_status, m) ++#define bm_err_isr_enable_read(bm) \ ++ __bm_err_isr_read(bm, bm_isr_enable) ++#define bm_err_isr_enable_write(bm, v) \ ++ __bm_err_isr_write(bm, bm_isr_enable, v) ++#define bm_err_isr_disable_read(bm) \ ++ __bm_err_isr_read(bm, bm_isr_disable) ++#define bm_err_isr_disable_write(bm, v) \ ++ __bm_err_isr_write(bm, bm_isr_disable, v) ++#define bm_err_isr_inhibit(bm) \ ++ __bm_err_isr_write(bm, bm_isr_inhibit, 1) ++#define bm_err_isr_uninhibit(bm) \ ++ __bm_err_isr_write(bm, bm_isr_inhibit, 0) ++ ++/* ++ * TODO: unimplemented registers ++ * ++ * BMAN_POOLk_SDCNT, BMAN_POOLk_HDCNT, BMAN_FULT, ++ * BMAN_VLDPL, BMAN_EECC, BMAN_SBET, BMAN_EINJ ++ */ ++ ++/* Encapsulate "struct bman *" as a cast of the register space address. */ ++ ++static struct bman *bm_create(void *regs) ++{ ++ return (struct bman *)regs; ++} ++ ++static inline u32 __bm_in(struct bman *bm, u32 offset) ++{ ++ return in_be32((void *)bm + offset); ++} ++static inline void __bm_out(struct bman *bm, u32 offset, u32 val) ++{ ++ out_be32((void *)bm + offset, val); ++} ++#define bm_in(reg) __bm_in(bm, REG_##reg) ++#define bm_out(reg, val) __bm_out(bm, REG_##reg, val) ++ ++static u32 __bm_err_isr_read(struct bman *bm, enum bm_isr_reg n) ++{ ++ return __bm_in(bm, REG_ERR_ISR + (n << 2)); ++} ++ ++static void __bm_err_isr_write(struct bman *bm, enum bm_isr_reg n, u32 val) ++{ ++ __bm_out(bm, REG_ERR_ISR + (n << 2), val); ++} ++ ++static void bm_get_version(struct bman *bm, u16 *id, u8 *major, u8 *minor) ++{ ++ u32 v = bm_in(IP_REV_1); ++ *id = (v >> 16); ++ *major = (v >> 8) & 0xff; ++ *minor = v & 0xff; ++} ++ ++static u32 __generate_thresh(u32 val, int roundup) ++{ ++ u32 e = 0; /* co-efficient, exponent */ ++ int oddbit = 0; ++ while (val > 0xff) { ++ oddbit = val & 1; ++ val >>= 1; ++ e++; ++ if (roundup && oddbit) ++ val++; ++ } ++ DPA_ASSERT(e < 0x10); ++ return val | (e << 8); ++} ++ ++static void bm_set_pool(struct bman *bm, u8 pool, u32 swdet, u32 swdxt, ++ u32 hwdet, u32 hwdxt) ++{ ++ DPA_ASSERT(pool < bman_pool_max); ++ bm_out(POOL_SWDET(pool), __generate_thresh(swdet, 0)); ++ bm_out(POOL_SWDXT(pool), __generate_thresh(swdxt, 1)); ++ bm_out(POOL_HWDET(pool), __generate_thresh(hwdet, 0)); ++ bm_out(POOL_HWDXT(pool), __generate_thresh(hwdxt, 1)); ++} ++ ++static void bm_set_memory(struct bman *bm, u64 ba, int prio, u32 size) ++{ ++ u32 exp = ilog2(size); ++ /* choke if size isn't within range */ ++ DPA_ASSERT((size >= 4096) && (size <= 1073741824) && ++ is_power_of_2(size)); ++ /* choke if '[e]ba' has lower-alignment than 'size' */ ++ DPA_ASSERT(!(ba & (size - 1))); ++ bm_out(FBPR_BARE, upper_32_bits(ba)); ++ bm_out(FBPR_BAR, lower_32_bits(ba)); ++ bm_out(FBPR_AR, (prio ? 0x40000000 : 0) | (exp - 1)); ++} ++ ++/*****************/ ++/* Config driver */ ++/*****************/ ++ ++/* TODO: Kconfig these? */ ++#define DEFAULT_FBPR_SZ (PAGE_SIZE << 12) ++ ++/* We support only one of these. */ ++static struct bman *bm; ++static struct device_node *bm_node; ++ ++/* And this state belongs to 'bm'. It is set during fsl_bman_init(), but used ++ * during bman_init_ccsr(). */ ++static dma_addr_t fbpr_a; ++static size_t fbpr_sz = DEFAULT_FBPR_SZ; ++ ++static int bman_fbpr(struct reserved_mem *rmem) ++{ ++ fbpr_a = rmem->base; ++ fbpr_sz = rmem->size; ++ ++ WARN_ON(!(fbpr_a && fbpr_sz)); ++ ++ return 0; ++} ++RESERVEDMEM_OF_DECLARE(bman_fbpr, "fsl,bman-fbpr", bman_fbpr); ++ ++static int __init fsl_bman_init(struct device_node *node) ++{ ++ struct resource res; ++ u32 __iomem *regs; ++ const char *s; ++ int ret, standby = 0; ++ u16 id; ++ u8 major, minor; ++ ++ ret = of_address_to_resource(node, 0, &res); ++ if (ret) { ++ pr_err("Can't get %s property 'reg'\n", ++ node->full_name); ++ return ret; ++ } ++ s = of_get_property(node, "fsl,hv-claimable", &ret); ++ if (s && !strcmp(s, "standby")) ++ standby = 1; ++ /* Global configuration */ ++ regs = ioremap(res.start, res.end - res.start + 1); ++ bm = bm_create(regs); ++ BUG_ON(!bm); ++ bm_node = node; ++ bm_get_version(bm, &id, &major, &minor); ++ pr_info("Bman ver:%04x,%02x,%02x\n", id, major, minor); ++ if ((major == 1) && (minor == 0)) { ++ bman_ip_rev = BMAN_REV10; ++ bman_pool_max = 64; ++ } else if ((major == 2) && (minor == 0)) { ++ bman_ip_rev = BMAN_REV20; ++ bman_pool_max = 8; ++ } else if ((major == 2) && (minor == 1)) { ++ bman_ip_rev = BMAN_REV21; ++ bman_pool_max = 64; ++ } else { ++ pr_warn("unknown Bman version, default to rev1.0\n"); ++ } ++ ++ if (standby) { ++ pr_info(" -> in standby mode\n"); ++ return 0; ++ } ++ return 0; ++} ++ ++int bman_have_ccsr(void) ++{ ++ return bm ? 1 : 0; ++} ++ ++int bm_pool_set(u32 bpid, const u32 *thresholds) ++{ ++ if (!bm) ++ return -ENODEV; ++ bm_set_pool(bm, bpid, thresholds[0], ++ thresholds[1], thresholds[2], ++ thresholds[3]); ++ return 0; ++} ++EXPORT_SYMBOL(bm_pool_set); ++ ++__init int bman_init_early(void) ++{ ++ struct device_node *dn; ++ int ret; ++ ++ for_each_compatible_node(dn, NULL, "fsl,bman") { ++ if (bm) ++ pr_err("%s: only one 'fsl,bman' allowed\n", ++ dn->full_name); ++ else { ++ if (!of_device_is_available(dn)) ++ continue; ++ ++ ret = fsl_bman_init(dn); ++ BUG_ON(ret); ++ } ++ } ++ return 0; ++} ++postcore_initcall_sync(bman_init_early); ++ ++ ++static void log_edata_bits(u32 bit_count) ++{ ++ u32 i, j, mask = 0xffffffff; ++ ++ pr_warn("Bman ErrInt, EDATA:\n"); ++ i = bit_count/32; ++ if (bit_count%32) { ++ i++; ++ mask = ~(mask << bit_count%32); ++ } ++ j = 16-i; ++ pr_warn(" 0x%08x\n", bm_in(EDATA(j)) & mask); ++ j++; ++ for (; j < 16; j++) ++ pr_warn(" 0x%08x\n", bm_in(EDATA(j))); ++} ++ ++static void log_additional_error_info(u32 isr_val, u32 ecsr_val) ++{ ++ union bman_ecir ecir_val; ++ union bman_eadr eadr_val; ++ ++ ecir_val.ecir_raw = bm_in(ECIR); ++ /* Is portal info valid */ ++ if (ecsr_val & PORTAL_ECSR_ERR) { ++ pr_warn("Bman ErrInt: SWP id %d, numb %d, pid %d\n", ++ ecir_val.info.portal_num, ecir_val.info.numb, ++ ecir_val.info.pid); ++ } ++ if (ecsr_val & (BM_EIRQ_SBEI|BM_EIRQ_MBEI)) { ++ eadr_val.eadr_raw = bm_in(EADR); ++ pr_warn("Bman ErrInt: EADR Memory: %s, 0x%x\n", ++ error_mdata[eadr_val.info.memid].txt, ++ error_mdata[eadr_val.info.memid].addr_mask ++ & eadr_val.info.eadr); ++ log_edata_bits(error_mdata[eadr_val.info.memid].bits); ++ } ++} ++ ++/* Bman interrupt handler */ ++static irqreturn_t bman_isr(int irq, void *ptr) ++{ ++ u32 isr_val, ier_val, ecsr_val, isr_mask, i; ++ ++ ier_val = bm_err_isr_enable_read(bm); ++ isr_val = bm_err_isr_status_read(bm); ++ ecsr_val = bm_in(ECSR); ++ isr_mask = isr_val & ier_val; ++ ++ if (!isr_mask) ++ return IRQ_NONE; ++ for (i = 0; i < BMAN_HWE_COUNT; i++) { ++ if (bman_hwerr_txts[i].mask & isr_mask) { ++ pr_warn("Bman ErrInt: %s\n", bman_hwerr_txts[i].txt); ++ if (bman_hwerr_txts[i].mask & ecsr_val) { ++ log_additional_error_info(isr_mask, ecsr_val); ++ /* Re-arm error capture registers */ ++ bm_out(ECSR, ecsr_val); ++ } ++ if (bman_hwerr_txts[i].mask & BMAN_ERRS_TO_UNENABLE) { ++ pr_devel("Bman un-enabling error 0x%x\n", ++ bman_hwerr_txts[i].mask); ++ ier_val &= ~bman_hwerr_txts[i].mask; ++ bm_err_isr_enable_write(bm, ier_val); ++ } ++ } ++ } ++ bm_err_isr_status_clear(bm, isr_val); ++ return IRQ_HANDLED; ++} ++ ++static int __bind_irq(void) ++{ ++ int ret, err_irq; ++ ++ err_irq = of_irq_to_resource(bm_node, 0, NULL); ++ if (err_irq == 0) { ++ pr_info("Can't get %s property '%s'\n", bm_node->full_name, ++ "interrupts"); ++ return -ENODEV; ++ } ++ ret = request_irq(err_irq, bman_isr, IRQF_SHARED, "bman-err", bm_node); ++ if (ret) { ++ pr_err("request_irq() failed %d for '%s'\n", ret, ++ bm_node->full_name); ++ return -ENODEV; ++ } ++ /* Disable Buffer Pool State Change */ ++ bm_err_isr_disable_write(bm, BM_EIRQ_BSCN); ++ /* Write-to-clear any stale bits, (eg. starvation being asserted prior ++ * to resource allocation during driver init). */ ++ bm_err_isr_status_clear(bm, 0xffffffff); ++ /* Enable Error Interrupts */ ++ bm_err_isr_enable_write(bm, 0xffffffff); ++ return 0; ++} ++ ++int bman_init_ccsr(struct device_node *node) ++{ ++ int ret; ++ if (!bman_have_ccsr()) ++ return 0; ++ if (node != bm_node) ++ return -EINVAL; ++ /* FBPR memory */ ++ bm_set_memory(bm, fbpr_a, 0, fbpr_sz); ++ pr_info("bman-fbpr addr %pad size 0x%zx\n", &fbpr_a, fbpr_sz); ++ ++ ret = __bind_irq(); ++ if (ret) ++ return ret; ++ return 0; ++} ++ ++u32 bm_pool_free_buffers(u32 bpid) ++{ ++ return bm_in(POOL_CONTENT(bpid)); ++} ++ ++#ifdef CONFIG_SYSFS ++ ++#define DRV_NAME "fsl-bman" ++#define SBEC_MAX_ID 1 ++#define SBEC_MIN_ID 0 ++ ++static ssize_t show_fbpr_fpc(struct device *dev, ++ struct device_attribute *dev_attr, char *buf) ++{ ++ return snprintf(buf, PAGE_SIZE, "%u\n", bm_in(FBPR_FPC)); ++}; ++ ++static ssize_t show_pool_count(struct device *dev, ++ struct device_attribute *dev_attr, char *buf) ++{ ++ u32 data; ++ int i; ++ ++ if (!sscanf(dev_attr->attr.name, "%d", &i) || (i >= bman_pool_max)) ++ return -EINVAL; ++ data = bm_in(POOL_CONTENT(i)); ++ return snprintf(buf, PAGE_SIZE, "%d\n", data); ++}; ++ ++static ssize_t show_err_isr(struct device *dev, ++ struct device_attribute *dev_attr, char *buf) ++{ ++ return snprintf(buf, PAGE_SIZE, "0x%08x\n", bm_in(ERR_ISR)); ++}; ++ ++static ssize_t show_sbec(struct device *dev, ++ struct device_attribute *dev_attr, char *buf) ++{ ++ int i; ++ ++ if (!sscanf(dev_attr->attr.name, "sbec_%d", &i)) ++ return -EINVAL; ++ if (i < SBEC_MIN_ID || i > SBEC_MAX_ID) ++ return -EINVAL; ++ return snprintf(buf, PAGE_SIZE, "%u\n", bm_in(SBEC(i))); ++}; ++ ++static DEVICE_ATTR(err_isr, S_IRUSR, show_err_isr, NULL); ++static DEVICE_ATTR(fbpr_fpc, S_IRUSR, show_fbpr_fpc, NULL); ++ ++/* Didn't use DEVICE_ATTR as 64 of this would be required. ++ * Initialize them when needed. */ ++static char *name_attrs_pool_count; /* "xx" + null-terminator */ ++static struct device_attribute *dev_attr_buffer_pool_count; ++ ++static DEVICE_ATTR(sbec_0, S_IRUSR, show_sbec, NULL); ++static DEVICE_ATTR(sbec_1, S_IRUSR, show_sbec, NULL); ++ ++static struct attribute *bman_dev_attributes[] = { ++ &dev_attr_fbpr_fpc.attr, ++ &dev_attr_err_isr.attr, ++ NULL ++}; ++ ++static struct attribute *bman_dev_ecr_attributes[] = { ++ &dev_attr_sbec_0.attr, ++ &dev_attr_sbec_1.attr, ++ NULL ++}; ++ ++static struct attribute **bman_dev_pool_count_attributes; ++ ++ ++/* root level */ ++static const struct attribute_group bman_dev_attr_grp = { ++ .name = NULL, ++ .attrs = bman_dev_attributes ++}; ++static const struct attribute_group bman_dev_ecr_grp = { ++ .name = "error_capture", ++ .attrs = bman_dev_ecr_attributes ++}; ++static struct attribute_group bman_dev_pool_countent_grp = { ++ .name = "pool_count", ++}; ++ ++static int of_fsl_bman_remove(struct platform_device *ofdev) ++{ ++ sysfs_remove_group(&ofdev->dev.kobj, &bman_dev_attr_grp); ++ return 0; ++}; ++ ++static int of_fsl_bman_probe(struct platform_device *ofdev) ++{ ++ int ret, i; ++ ++ ret = sysfs_create_group(&ofdev->dev.kobj, &bman_dev_attr_grp); ++ if (ret) ++ goto done; ++ ret = sysfs_create_group(&ofdev->dev.kobj, &bman_dev_ecr_grp); ++ if (ret) ++ goto del_group_0; ++ ++ name_attrs_pool_count = kmalloc(sizeof(char) * bman_pool_max * 3, ++ GFP_KERNEL); ++ if (!name_attrs_pool_count) { ++ pr_err("Can't alloc name_attrs_pool_count\n"); ++ goto del_group_1; ++ } ++ ++ dev_attr_buffer_pool_count = kmalloc(sizeof(struct device_attribute) * ++ bman_pool_max, GFP_KERNEL); ++ if (!dev_attr_buffer_pool_count) { ++ pr_err("Can't alloc dev_attr-buffer_pool_count\n"); ++ goto del_group_2; ++ } ++ ++ bman_dev_pool_count_attributes = kmalloc(sizeof(struct attribute *) * ++ (bman_pool_max + 1), GFP_KERNEL); ++ if (!bman_dev_pool_count_attributes) { ++ pr_err("can't alloc bman_dev_pool_count_attributes\n"); ++ goto del_group_3; ++ } ++ ++ for (i = 0; i < bman_pool_max; i++) { ++ ret = scnprintf((name_attrs_pool_count + i * 3), 3, "%d", i); ++ if (!ret) ++ goto del_group_4; ++ dev_attr_buffer_pool_count[i].attr.name = ++ (name_attrs_pool_count + i * 3); ++ dev_attr_buffer_pool_count[i].attr.mode = S_IRUSR; ++ dev_attr_buffer_pool_count[i].show = show_pool_count; ++ bman_dev_pool_count_attributes[i] = ++ &dev_attr_buffer_pool_count[i].attr; ++ sysfs_attr_init(bman_dev_pool_count_attributes[i]); ++ } ++ bman_dev_pool_count_attributes[bman_pool_max] = NULL; ++ ++ bman_dev_pool_countent_grp.attrs = bman_dev_pool_count_attributes; ++ ++ ret = sysfs_create_group(&ofdev->dev.kobj, &bman_dev_pool_countent_grp); ++ if (ret) ++ goto del_group_4; ++ ++ goto done; ++ ++del_group_4: ++ kfree(bman_dev_pool_count_attributes); ++del_group_3: ++ kfree(dev_attr_buffer_pool_count); ++del_group_2: ++ kfree(name_attrs_pool_count); ++del_group_1: ++ sysfs_remove_group(&ofdev->dev.kobj, &bman_dev_ecr_grp); ++del_group_0: ++ sysfs_remove_group(&ofdev->dev.kobj, &bman_dev_attr_grp); ++done: ++ if (ret) ++ dev_err(&ofdev->dev, ++ "Cannot create dev attributes ret=%d\n", ret); ++ return ret; ++}; ++ ++static struct of_device_id of_fsl_bman_ids[] = { ++ { ++ .compatible = "fsl,bman", ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, of_fsl_bman_ids); ++ ++#ifdef CONFIG_SUSPEND ++static u32 saved_isdr; ++ ++static int bman_pm_suspend_noirq(struct device *dev) ++{ ++ uint32_t idle_state; ++ ++ suspend_unused_bportal(); ++ /* save isdr, disable all, clear isr */ ++ saved_isdr = bm_err_isr_disable_read(bm); ++ bm_err_isr_disable_write(bm, 0xffffffff); ++ bm_err_isr_status_clear(bm, 0xffffffff); ++ ++ if (bman_ip_rev < BMAN_REV21) { ++#ifdef CONFIG_PM_DEBUG ++ pr_info("Bman version doesn't have STATE_IDLE\n"); ++#endif ++ return 0; ++ } ++ idle_state = bm_in(STATE_IDLE); ++ if (!(idle_state & 0x1)) { ++ pr_err("Bman not idle 0x%x aborting\n", idle_state); ++ bm_err_isr_disable_write(bm, saved_isdr); ++ resume_unused_bportal(); ++ return -EBUSY; ++ } ++#ifdef CONFIG_PM_DEBUG ++ pr_info("Bman suspend code, IDLE_STAT = 0x%x\n", idle_state); ++#endif ++ return 0; ++} ++ ++static int bman_pm_resume_noirq(struct device *dev) ++{ ++ /* restore isdr */ ++ bm_err_isr_disable_write(bm, saved_isdr); ++ resume_unused_bportal(); ++ return 0; ++} ++#else ++#define bman_pm_suspend_noirq NULL ++#define bman_pm_resume_noirq NULL ++#endif ++ ++static const struct dev_pm_ops bman_pm_ops = { ++ .suspend_noirq = bman_pm_suspend_noirq, ++ .resume_noirq = bman_pm_resume_noirq, ++}; ++ ++static struct platform_driver of_fsl_bman_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = DRV_NAME, ++ .of_match_table = of_fsl_bman_ids, ++ .pm = &bman_pm_ops, ++ }, ++ .probe = of_fsl_bman_probe, ++ .remove = of_fsl_bman_remove, ++}; ++ ++static int bman_ctrl_init(void) ++{ ++ return platform_driver_register(&of_fsl_bman_driver); ++} ++ ++static void bman_ctrl_exit(void) ++{ ++ platform_driver_unregister(&of_fsl_bman_driver); ++} ++ ++module_init(bman_ctrl_init); ++module_exit(bman_ctrl_exit); ++ ++#endif /* CONFIG_SYSFS */ +diff --git a/drivers/staging/fsl_qbman/bman_debugfs.c b/drivers/staging/fsl_qbman/bman_debugfs.c +new file mode 100644 +index 00000000..96909348 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/bman_debugfs.c +@@ -0,0 +1,119 @@ ++/* Copyright 2010-2011 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++static struct dentry *dfs_root; /* debugfs root directory */ ++ ++/******************************************************************************* ++ * Query Buffer Pool State ++ ******************************************************************************/ ++static int query_bp_state_show(struct seq_file *file, void *offset) ++{ ++ int ret; ++ struct bm_pool_state state; ++ int i, j; ++ u32 mask; ++ ++ memset(&state, 0, sizeof(struct bm_pool_state)); ++ ret = bman_query_pools(&state); ++ if (ret) { ++ seq_printf(file, "Error %d\n", ret); ++ return 0; ++ } ++ seq_puts(file, "bp_id free_buffers_avail bp_depleted\n"); ++ for (i = 0; i < 2; i++) { ++ mask = 0x80000000; ++ for (j = 0; j < 32; j++) { ++ seq_printf(file, ++ " %-2u %-3s %-3s\n", ++ (i*32)+j, ++ (state.as.state.__state[i] & mask) ? "no" : "yes", ++ (state.ds.state.__state[i] & mask) ? "yes" : "no"); ++ mask >>= 1; ++ } ++ } ++ return 0; ++} ++ ++static int query_bp_state_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, query_bp_state_show, NULL); ++} ++ ++static const struct file_operations query_bp_state_fops = { ++ .owner = THIS_MODULE, ++ .open = query_bp_state_open, ++ .read = seq_read, ++ .release = single_release, ++}; ++ ++static int __init bman_debugfs_module_init(void) ++{ ++ int ret = 0; ++ struct dentry *d; ++ ++ dfs_root = debugfs_create_dir("bman", NULL); ++ ++ if (dfs_root == NULL) { ++ ret = -ENOMEM; ++ pr_err("Cannot create bman debugfs dir\n"); ++ goto _return; ++ } ++ d = debugfs_create_file("query_bp_state", ++ S_IRUGO, ++ dfs_root, ++ NULL, ++ &query_bp_state_fops); ++ if (d == NULL) { ++ ret = -ENOMEM; ++ pr_err("Cannot create query_bp_state\n"); ++ goto _return; ++ } ++ return 0; ++ ++_return: ++ debugfs_remove_recursive(dfs_root); ++ return ret; ++} ++ ++static void __exit bman_debugfs_module_exit(void) ++{ ++ debugfs_remove_recursive(dfs_root); ++} ++ ++ ++module_init(bman_debugfs_module_init); ++module_exit(bman_debugfs_module_exit); ++MODULE_LICENSE("Dual BSD/GPL"); +diff --git a/drivers/staging/fsl_qbman/bman_driver.c b/drivers/staging/fsl_qbman/bman_driver.c +new file mode 100644 +index 00000000..86fabef6 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/bman_driver.c +@@ -0,0 +1,575 @@ ++/* Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++#include "bman_low.h" ++#ifdef CONFIG_HOTPLUG_CPU ++#include ++#endif ++/* ++ * Global variables of the max portal/pool number this bman version supported ++ */ ++u16 bman_ip_rev; ++EXPORT_SYMBOL(bman_ip_rev); ++u16 bman_pool_max; ++EXPORT_SYMBOL(bman_pool_max); ++static u16 bman_portal_max; ++ ++/* After initialising cpus that own shared portal configs, we cache the ++ * resulting portals (ie. not just the configs) in this array. Then we ++ * initialise slave cpus that don't have their own portals, redirecting them to ++ * portals from this cache in a round-robin assignment. */ ++static struct bman_portal *shared_portals[NR_CPUS]; ++static int num_shared_portals; ++static int shared_portals_idx; ++static LIST_HEAD(unused_pcfgs); ++static DEFINE_SPINLOCK(unused_pcfgs_lock); ++static void *affine_bportals[NR_CPUS]; ++ ++static int __init fsl_bpool_init(struct device_node *node) ++{ ++ int ret; ++ u32 *thresh, *bpid = (u32 *)of_get_property(node, "fsl,bpid", &ret); ++ if (!bpid || (ret != 4)) { ++ pr_err("Can't get %s property 'fsl,bpid'\n", node->full_name); ++ return -ENODEV; ++ } ++ thresh = (u32 *)of_get_property(node, "fsl,bpool-thresholds", &ret); ++ if (thresh) { ++ if (ret != 16) { ++ pr_err("Invalid %s property '%s'\n", ++ node->full_name, "fsl,bpool-thresholds"); ++ return -ENODEV; ++ } ++ } ++ if (thresh) { ++#ifdef CONFIG_FSL_BMAN_CONFIG ++ ret = bm_pool_set(be32_to_cpu(*bpid), thresh); ++ if (ret) ++ pr_err("No CCSR node for %s property '%s'\n", ++ node->full_name, "fsl,bpool-thresholds"); ++ return ret; ++#else ++ pr_err("Ignoring %s property '%s', no CCSR support\n", ++ node->full_name, "fsl,bpool-thresholds"); ++#endif ++ } ++ return 0; ++} ++ ++static int __init fsl_bpid_range_init(struct device_node *node) ++{ ++ int ret; ++ u32 *range = (u32 *)of_get_property(node, "fsl,bpid-range", &ret); ++ if (!range) { ++ pr_err("No 'fsl,bpid-range' property in node %s\n", ++ node->full_name); ++ return -EINVAL; ++ } ++ if (ret != 8) { ++ pr_err("'fsl,bpid-range' is not a 2-cell range in node %s\n", ++ node->full_name); ++ return -EINVAL; ++ } ++ bman_seed_bpid_range(be32_to_cpu(range[0]), be32_to_cpu(range[1])); ++ pr_info("Bman: BPID allocator includes range %d:%d\n", ++ be32_to_cpu(range[0]), be32_to_cpu(range[1])); ++ return 0; ++} ++ ++static struct bm_portal_config * __init parse_pcfg(struct device_node *node) ++{ ++ struct bm_portal_config *pcfg; ++ const u32 *index; ++ int irq, ret; ++ resource_size_t len; ++ ++ pcfg = kmalloc(sizeof(*pcfg), GFP_KERNEL); ++ if (!pcfg) { ++ pr_err("can't allocate portal config"); ++ return NULL; ++ } ++ ++ if (of_device_is_compatible(node, "fsl,bman-portal-1.0") || ++ of_device_is_compatible(node, "fsl,bman-portal-1.0.0")) { ++ bman_ip_rev = BMAN_REV10; ++ bman_pool_max = 64; ++ bman_portal_max = 10; ++ } else if (of_device_is_compatible(node, "fsl,bman-portal-2.0") || ++ of_device_is_compatible(node, "fsl,bman-portal-2.0.8")) { ++ bman_ip_rev = BMAN_REV20; ++ bman_pool_max = 8; ++ bman_portal_max = 3; ++ } else if (of_device_is_compatible(node, "fsl,bman-portal-2.1.0")) { ++ bman_ip_rev = BMAN_REV21; ++ bman_pool_max = 64; ++ bman_portal_max = 50; ++ } else if (of_device_is_compatible(node, "fsl,bman-portal-2.1.1")) { ++ bman_ip_rev = BMAN_REV21; ++ bman_pool_max = 64; ++ bman_portal_max = 25; ++ } else if (of_device_is_compatible(node, "fsl,bman-portal-2.1.2")) { ++ bman_ip_rev = BMAN_REV21; ++ bman_pool_max = 64; ++ bman_portal_max = 18; ++ } else if (of_device_is_compatible(node, "fsl,bman-portal-2.1.3")) { ++ bman_ip_rev = BMAN_REV21; ++ bman_pool_max = 64; ++ bman_portal_max = 10; ++ } else { ++ pr_warn("unknown BMan version in portal node," ++ "default to rev1.0\n"); ++ bman_ip_rev = BMAN_REV10; ++ bman_pool_max = 64; ++ bman_portal_max = 10; ++ } ++ ++ ret = of_address_to_resource(node, DPA_PORTAL_CE, ++ &pcfg->addr_phys[DPA_PORTAL_CE]); ++ if (ret) { ++ pr_err("Can't get %s property 'reg::CE'\n", node->full_name); ++ goto err; ++ } ++ ret = of_address_to_resource(node, DPA_PORTAL_CI, ++ &pcfg->addr_phys[DPA_PORTAL_CI]); ++ if (ret) { ++ pr_err("Can't get %s property 'reg::CI'\n", node->full_name); ++ goto err; ++ } ++ ++ index = of_get_property(node, "cell-index", &ret); ++ if (!index || (ret != 4)) { ++ pr_err("Can't get %s property '%s'\n", node->full_name, ++ "cell-index"); ++ goto err; ++ } ++ if (be32_to_cpu(*index) >= bman_portal_max) { ++ pr_err("BMan portal cell index %d out of range, max %d\n", ++ be32_to_cpu(*index), bman_portal_max); ++ goto err; ++ } ++ ++ pcfg->public_cfg.cpu = -1; ++ ++ irq = irq_of_parse_and_map(node, 0); ++ if (irq == 0) { ++ pr_err("Can't get %s property 'interrupts'\n", node->full_name); ++ goto err; ++ } ++ pcfg->public_cfg.irq = irq; ++ pcfg->public_cfg.index = be32_to_cpu(*index); ++ bman_depletion_fill(&pcfg->public_cfg.mask); ++ ++ len = resource_size(&pcfg->addr_phys[DPA_PORTAL_CE]); ++ if (len != (unsigned long)len) ++ goto err; ++ ++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) ++ pcfg->addr_virt[DPA_PORTAL_CE] = ioremap_cache_ns( ++ pcfg->addr_phys[DPA_PORTAL_CE].start, ++ resource_size(&pcfg->addr_phys[DPA_PORTAL_CE])); ++ pcfg->addr_virt[DPA_PORTAL_CI] = ioremap( ++ pcfg->addr_phys[DPA_PORTAL_CI].start, ++ resource_size(&pcfg->addr_phys[DPA_PORTAL_CI])); ++ ++#else ++ pcfg->addr_virt[DPA_PORTAL_CE] = ioremap_prot( ++ pcfg->addr_phys[DPA_PORTAL_CE].start, ++ (unsigned long)len, ++ 0); ++ pcfg->addr_virt[DPA_PORTAL_CI] = ioremap_prot( ++ pcfg->addr_phys[DPA_PORTAL_CI].start, ++ resource_size(&pcfg->addr_phys[DPA_PORTAL_CI]), ++ _PAGE_GUARDED | _PAGE_NO_CACHE); ++#endif ++ /* disable bp depletion */ ++ __raw_writel(0x0, pcfg->addr_virt[DPA_PORTAL_CI] + BM_REG_SCN(0)); ++ __raw_writel(0x0, pcfg->addr_virt[DPA_PORTAL_CI] + BM_REG_SCN(1)); ++ return pcfg; ++err: ++ kfree(pcfg); ++ return NULL; ++} ++ ++static struct bm_portal_config *get_pcfg(struct list_head *list) ++{ ++ struct bm_portal_config *pcfg; ++ if (list_empty(list)) ++ return NULL; ++ pcfg = list_entry(list->prev, struct bm_portal_config, list); ++ list_del(&pcfg->list); ++ return pcfg; ++} ++ ++static struct bm_portal_config *get_pcfg_idx(struct list_head *list, ++ uint32_t idx) ++{ ++ struct bm_portal_config *pcfg; ++ if (list_empty(list)) ++ return NULL; ++ list_for_each_entry(pcfg, list, list) { ++ if (pcfg->public_cfg.index == idx) { ++ list_del(&pcfg->list); ++ return pcfg; ++ } ++ } ++ return NULL; ++} ++ ++struct bm_portal_config *bm_get_unused_portal(void) ++{ ++ return bm_get_unused_portal_idx(QBMAN_ANY_PORTAL_IDX); ++} ++ ++struct bm_portal_config *bm_get_unused_portal_idx(uint32_t idx) ++{ ++ struct bm_portal_config *ret; ++ spin_lock(&unused_pcfgs_lock); ++ if (idx == QBMAN_ANY_PORTAL_IDX) ++ ret = get_pcfg(&unused_pcfgs); ++ else ++ ret = get_pcfg_idx(&unused_pcfgs, idx); ++ spin_unlock(&unused_pcfgs_lock); ++ return ret; ++} ++ ++void bm_put_unused_portal(struct bm_portal_config *pcfg) ++{ ++ spin_lock(&unused_pcfgs_lock); ++ list_add(&pcfg->list, &unused_pcfgs); ++ spin_unlock(&unused_pcfgs_lock); ++} ++ ++static struct bman_portal *init_pcfg(struct bm_portal_config *pcfg) ++{ ++ struct bman_portal *p; ++ p = bman_create_affine_portal(pcfg); ++ if (p) { ++#ifdef CONFIG_FSL_DPA_PIRQ_SLOW ++ bman_p_irqsource_add(p, BM_PIRQ_RCRI | BM_PIRQ_BSCN); ++#endif ++ pr_info("Bman portal %sinitialised, cpu %d\n", ++ pcfg->public_cfg.is_shared ? "(shared) " : "", ++ pcfg->public_cfg.cpu); ++ affine_bportals[pcfg->public_cfg.cpu] = p; ++ } else ++ pr_crit("Bman portal failure on cpu %d\n", ++ pcfg->public_cfg.cpu); ++ return p; ++} ++ ++static void init_slave(int cpu) ++{ ++ struct bman_portal *p; ++ p = bman_create_affine_slave(shared_portals[shared_portals_idx++], cpu); ++ if (!p) ++ pr_err("Bman slave portal failure on cpu %d\n", cpu); ++ else ++ pr_info("Bman portal %sinitialised, cpu %d\n", "(slave) ", cpu); ++ if (shared_portals_idx >= num_shared_portals) ++ shared_portals_idx = 0; ++ affine_bportals[cpu] = p; ++} ++ ++/* Bootarg "bportals=[...]" has the same syntax as "qportals=", and so the ++ * parsing is in dpa_sys.h. The syntax is a comma-separated list of indexes ++ * and/or ranges of indexes, with each being optionally prefixed by "s" to ++ * explicitly mark it or them for sharing. ++ * Eg; ++ * bportals=s0,1-3,s4 ++ * means that cpus 1,2,3 get "unshared" portals, cpus 0 and 4 get "shared" ++ * portals, and any remaining cpus share the portals that are assigned to cpus 0 ++ * or 4, selected in a round-robin fashion. (In this example, cpu 5 would share ++ * cpu 0's portal, cpu 6 would share cpu4's portal, and cpu 7 would share cpu ++ * 0's portal.) */ ++static struct cpumask want_unshared __initdata; /* cpus requested without "s" */ ++static struct cpumask want_shared __initdata; /* cpus requested with "s" */ ++ ++static int __init parse_bportals(char *str) ++{ ++ return parse_portals_bootarg(str, &want_shared, &want_unshared, ++ "bportals"); ++} ++__setup("bportals=", parse_bportals); ++ ++static int bman_offline_cpu(unsigned int cpu) ++{ ++ struct bman_portal *p; ++ const struct bm_portal_config *pcfg; ++ p = (struct bman_portal *)affine_bportals[cpu]; ++ if (p) { ++ pcfg = bman_get_bm_portal_config(p); ++ if (pcfg) ++ irq_set_affinity(pcfg->public_cfg.irq, cpumask_of(0)); ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_HOTPLUG_CPU ++static int bman_online_cpu(unsigned int cpu) ++{ ++ struct bman_portal *p; ++ const struct bm_portal_config *pcfg; ++ p = (struct bman_portal *)affine_bportals[cpu]; ++ if (p) { ++ pcfg = bman_get_bm_portal_config(p); ++ if (pcfg) ++ irq_set_affinity(pcfg->public_cfg.irq, cpumask_of(cpu)); ++ } ++ return 0; ++} ++static int bman_hotplug_cpu_callback(struct notifier_block *nfb, ++ unsigned long action, void *hcpu) ++{ ++ unsigned int cpu = (unsigned long)hcpu; ++ ++ switch (action) { ++ case CPU_ONLINE: ++ case CPU_ONLINE_FROZEN: ++ bman_online_cpu(cpu); ++ break; ++ case CPU_DOWN_PREPARE: ++ case CPU_DOWN_PREPARE_FROZEN: ++ bman_offline_cpu(cpu); ++ default: ++ break; ++ } ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block bman_hotplug_cpu_notifier = { ++ .notifier_call = bman_hotplug_cpu_callback, ++}; ++#endif /* CONFIG_HOTPLUG_CPU */ ++ ++/* Initialise the Bman driver. The meat of this function deals with portals. The ++ * following describes the flow of portal-handling, the code "steps" refer to ++ * this description; ++ * 1. Portal configs are parsed from the device-tree into 'unused_pcfgs', with ++ * ::cpu==-1. Regions and interrupts are mapped (but interrupts are not ++ * bound). ++ * 2. The "want_shared" and "want_unshared" lists (as filled by the ++ * "bportals=[...]" bootarg) are processed, allocating portals and assigning ++ * them to cpus, placing them in the relevant list and setting ::cpu as ++ * appropriate. If no "bportals" bootarg was present, the defaut is to try to ++ * assign portals to all online cpus at the time of driver initialisation. ++ * Any failure to allocate portals (when parsing the "want" lists or when ++ * using default behaviour) will be silently tolerated (the "fixup" logic in ++ * step 3 will determine what happens in this case). ++ * 3. Do fixups relative to cpu_online_mask(). If no portals are marked for ++ * sharing and sharing is required (because not all cpus have been assigned ++ * portals), then one portal will marked for sharing. Conversely if no ++ * sharing is required, any portals marked for sharing will not be shared. It ++ * may be that sharing occurs when it wasn't expected, if portal allocation ++ * failed to honour all the requested assignments (including the default ++ * assignments if no bootarg is present). ++ * 4. Unshared portals are initialised on their respective cpus. ++ * 5. Shared portals are initialised on their respective cpus. ++ * 6. Each remaining cpu is initialised to slave to one of the shared portals, ++ * which are selected in a round-robin fashion. ++ * Any portal configs left unused are available for USDPAA allocation. ++ */ ++__init int bman_init(void) ++{ ++ struct cpumask slave_cpus; ++ struct cpumask unshared_cpus = *cpu_none_mask; ++ struct cpumask shared_cpus = *cpu_none_mask; ++ LIST_HEAD(unshared_pcfgs); ++ LIST_HEAD(shared_pcfgs); ++ struct device_node *dn; ++ struct bm_portal_config *pcfg; ++ struct bman_portal *p; ++ int cpu, ret; ++ struct cpumask offline_cpus; ++ ++ /* Initialise the Bman (CCSR) device */ ++ for_each_compatible_node(dn, NULL, "fsl,bman") { ++ if (!bman_init_ccsr(dn)) ++ pr_info("Bman err interrupt handler present\n"); ++ else ++ pr_err("Bman CCSR setup failed\n"); ++ } ++ /* Initialise any declared buffer pools */ ++ for_each_compatible_node(dn, NULL, "fsl,bpool") { ++ ret = fsl_bpool_init(dn); ++ if (ret) ++ return ret; ++ } ++ /* Step 1. See comments at the beginning of the file. */ ++ for_each_compatible_node(dn, NULL, "fsl,bman-portal") { ++ if (!of_device_is_available(dn)) ++ continue; ++ pcfg = parse_pcfg(dn); ++ if (pcfg) ++ list_add_tail(&pcfg->list, &unused_pcfgs); ++ } ++ /* Step 2. */ ++ for_each_possible_cpu(cpu) { ++ if (cpumask_test_cpu(cpu, &want_shared)) { ++ pcfg = get_pcfg(&unused_pcfgs); ++ if (!pcfg) ++ break; ++ pcfg->public_cfg.cpu = cpu; ++ list_add_tail(&pcfg->list, &shared_pcfgs); ++ cpumask_set_cpu(cpu, &shared_cpus); ++ } ++ if (cpumask_test_cpu(cpu, &want_unshared)) { ++ if (cpumask_test_cpu(cpu, &shared_cpus)) ++ continue; ++ pcfg = get_pcfg(&unused_pcfgs); ++ if (!pcfg) ++ break; ++ pcfg->public_cfg.cpu = cpu; ++ list_add_tail(&pcfg->list, &unshared_pcfgs); ++ cpumask_set_cpu(cpu, &unshared_cpus); ++ } ++ } ++ if (list_empty(&shared_pcfgs) && list_empty(&unshared_pcfgs)) { ++ /* Default, give an unshared portal to each online cpu */ ++ for_each_online_cpu(cpu) { ++ pcfg = get_pcfg(&unused_pcfgs); ++ if (!pcfg) ++ break; ++ pcfg->public_cfg.cpu = cpu; ++ list_add_tail(&pcfg->list, &unshared_pcfgs); ++ cpumask_set_cpu(cpu, &unshared_cpus); ++ } ++ } ++ /* Step 3. */ ++ cpumask_andnot(&slave_cpus, cpu_possible_mask, &shared_cpus); ++ cpumask_andnot(&slave_cpus, &slave_cpus, &unshared_cpus); ++ if (cpumask_empty(&slave_cpus)) { ++ /* No sharing required */ ++ if (!list_empty(&shared_pcfgs)) { ++ /* Migrate "shared" to "unshared" */ ++ cpumask_or(&unshared_cpus, &unshared_cpus, ++ &shared_cpus); ++ cpumask_clear(&shared_cpus); ++ list_splice_tail(&shared_pcfgs, &unshared_pcfgs); ++ INIT_LIST_HEAD(&shared_pcfgs); ++ } ++ } else { ++ /* Sharing required */ ++ if (list_empty(&shared_pcfgs)) { ++ /* Migrate one "unshared" to "shared" */ ++ pcfg = get_pcfg(&unshared_pcfgs); ++ if (!pcfg) { ++ pr_crit("No BMan portals available!\n"); ++ return 0; ++ } ++ cpumask_clear_cpu(pcfg->public_cfg.cpu, &unshared_cpus); ++ cpumask_set_cpu(pcfg->public_cfg.cpu, &shared_cpus); ++ list_add_tail(&pcfg->list, &shared_pcfgs); ++ } ++ } ++ /* Step 4. */ ++ list_for_each_entry(pcfg, &unshared_pcfgs, list) { ++ pcfg->public_cfg.is_shared = 0; ++ p = init_pcfg(pcfg); ++ if (!p) { ++ pr_crit("Unable to initialize bman portal\n"); ++ return 0; ++ } ++ } ++ /* Step 5. */ ++ list_for_each_entry(pcfg, &shared_pcfgs, list) { ++ pcfg->public_cfg.is_shared = 1; ++ p = init_pcfg(pcfg); ++ if (p) ++ shared_portals[num_shared_portals++] = p; ++ } ++ /* Step 6. */ ++ if (!cpumask_empty(&slave_cpus)) ++ for_each_cpu(cpu, &slave_cpus) ++ init_slave(cpu); ++ pr_info("Bman portals initialised\n"); ++ cpumask_andnot(&offline_cpus, cpu_possible_mask, cpu_online_mask); ++ for_each_cpu(cpu, &offline_cpus) ++ bman_offline_cpu(cpu); ++#ifdef CONFIG_HOTPLUG_CPU ++ register_hotcpu_notifier(&bman_hotplug_cpu_notifier); ++#endif ++ return 0; ++} ++ ++__init int bman_resource_init(void) ++{ ++ struct device_node *dn; ++ int ret; ++ ++ /* Initialise BPID allocation ranges */ ++ for_each_compatible_node(dn, NULL, "fsl,bpid-range") { ++ ret = fsl_bpid_range_init(dn); ++ if (ret) ++ return ret; ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_SUSPEND ++void suspend_unused_bportal(void) ++{ ++ struct bm_portal_config *pcfg; ++ ++ if (list_empty(&unused_pcfgs)) ++ return; ++ ++ list_for_each_entry(pcfg, &unused_pcfgs, list) { ++#ifdef CONFIG_PM_DEBUG ++ pr_info("Need to save bportal %d\n", pcfg->public_cfg.index); ++#endif ++ /* save isdr, disable all via isdr, clear isr */ ++ pcfg->saved_isdr = ++ __raw_readl(pcfg->addr_virt[DPA_PORTAL_CI] + 0xe08); ++ __raw_writel(0xffffffff, pcfg->addr_virt[DPA_PORTAL_CI] + ++ 0xe08); ++ __raw_writel(0xffffffff, pcfg->addr_virt[DPA_PORTAL_CI] + ++ 0xe00); ++ } ++ return; ++} ++ ++void resume_unused_bportal(void) ++{ ++ struct bm_portal_config *pcfg; ++ ++ if (list_empty(&unused_pcfgs)) ++ return; ++ ++ list_for_each_entry(pcfg, &unused_pcfgs, list) { ++#ifdef CONFIG_PM_DEBUG ++ pr_info("Need to resume bportal %d\n", pcfg->public_cfg.index); ++#endif ++ /* restore isdr */ ++ __raw_writel(pcfg->saved_isdr, ++ pcfg->addr_virt[DPA_PORTAL_CI] + 0xe08); ++ } ++ return; ++} ++#endif +diff --git a/drivers/staging/fsl_qbman/bman_high.c b/drivers/staging/fsl_qbman/bman_high.c +new file mode 100644 +index 00000000..c066602d +--- /dev/null ++++ b/drivers/staging/fsl_qbman/bman_high.c +@@ -0,0 +1,1145 @@ ++/* Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "bman_low.h" ++ ++/* Compilation constants */ ++#define RCR_THRESH 2 /* reread h/w CI when running out of space */ ++#define IRQNAME "BMan portal %d" ++#define MAX_IRQNAME 16 /* big enough for "BMan portal %d" */ ++ ++struct bman_portal { ++ struct bm_portal p; ++ /* 2-element array. pools[0] is mask, pools[1] is snapshot. */ ++ struct bman_depletion *pools; ++ int thresh_set; ++ unsigned long irq_sources; ++ u32 slowpoll; /* only used when interrupts are off */ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ struct bman_pool *rcri_owned; /* only 1 release WAIT_SYNC at a time */ ++#endif ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ raw_spinlock_t sharing_lock; /* only used if is_shared */ ++ int is_shared; ++ struct bman_portal *sharing_redirect; ++#endif ++ /* When the cpu-affine portal is activated, this is non-NULL */ ++ const struct bm_portal_config *config; ++ /* This is needed for power management */ ++ struct platform_device *pdev; ++ /* 64-entry hash-table of pool objects that are tracking depletion ++ * entry/exit (ie. BMAN_POOL_FLAG_DEPLETION). This isn't fast-path, so ++ * we're not fussy about cache-misses and so forth - whereas the above ++ * members should all fit in one cacheline. ++ * BTW, with 64 entries in the hash table and 64 buffer pools to track, ++ * you'll never guess the hash-function ... */ ++ struct bman_pool *cb[64]; ++ char irqname[MAX_IRQNAME]; ++ /* Track if the portal was alloced by the driver */ ++ u8 alloced; ++ /* power management data */ ++ u32 save_isdr; ++}; ++ ++/* For an explanation of the locking, redirection, or affine-portal logic, ++ * please consult the Qman driver for details. This is the same, only simpler ++ * (no fiddly Qman-specific bits.) */ ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++#define PORTAL_IRQ_LOCK(p, irqflags) \ ++ do { \ ++ if ((p)->is_shared) \ ++ raw_spin_lock_irqsave(&(p)->sharing_lock, irqflags); \ ++ else \ ++ local_irq_save(irqflags); \ ++ } while (0) ++#define PORTAL_IRQ_UNLOCK(p, irqflags) \ ++ do { \ ++ if ((p)->is_shared) \ ++ raw_spin_unlock_irqrestore(&(p)->sharing_lock, \ ++ irqflags); \ ++ else \ ++ local_irq_restore(irqflags); \ ++ } while (0) ++#else ++#define PORTAL_IRQ_LOCK(p, irqflags) local_irq_save(irqflags) ++#define PORTAL_IRQ_UNLOCK(p, irqflags) local_irq_restore(irqflags) ++#endif ++ ++static cpumask_t affine_mask; ++static DEFINE_SPINLOCK(affine_mask_lock); ++static DEFINE_PER_CPU(struct bman_portal, bman_affine_portal); ++static inline struct bman_portal *get_raw_affine_portal(void) ++{ ++ return &get_cpu_var(bman_affine_portal); ++} ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++static inline struct bman_portal *get_affine_portal(void) ++{ ++ struct bman_portal *p = get_raw_affine_portal(); ++ if (p->sharing_redirect) ++ return p->sharing_redirect; ++ return p; ++} ++#else ++#define get_affine_portal() get_raw_affine_portal() ++#endif ++static inline void put_affine_portal(void) ++{ ++ put_cpu_var(bman_affine_portal); ++} ++static inline struct bman_portal *get_poll_portal(void) ++{ ++ return &get_cpu_var(bman_affine_portal); ++} ++#define put_poll_portal() ++ ++/* GOTCHA: this object type refers to a pool, it isn't *the* pool. There may be ++ * more than one such object per Bman buffer pool, eg. if different users of the ++ * pool are operating via different portals. */ ++struct bman_pool { ++ struct bman_pool_params params; ++ /* Used for hash-table admin when using depletion notifications. */ ++ struct bman_portal *portal; ++ struct bman_pool *next; ++ /* stockpile state - NULL unless BMAN_POOL_FLAG_STOCKPILE is set */ ++ struct bm_buffer *sp; ++ unsigned int sp_fill; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ atomic_t in_use; ++#endif ++}; ++ ++/* (De)Registration of depletion notification callbacks */ ++static void depletion_link(struct bman_portal *portal, struct bman_pool *pool) ++{ ++ __maybe_unused unsigned long irqflags; ++ pool->portal = portal; ++ PORTAL_IRQ_LOCK(portal, irqflags); ++ pool->next = portal->cb[pool->params.bpid]; ++ portal->cb[pool->params.bpid] = pool; ++ if (!pool->next) ++ /* First object for that bpid on this portal, enable the BSCN ++ * mask bit. */ ++ bm_isr_bscn_mask(&portal->p, pool->params.bpid, 1); ++ PORTAL_IRQ_UNLOCK(portal, irqflags); ++} ++static void depletion_unlink(struct bman_pool *pool) ++{ ++ struct bman_pool *it, *last = NULL; ++ struct bman_pool **base = &pool->portal->cb[pool->params.bpid]; ++ __maybe_unused unsigned long irqflags; ++ PORTAL_IRQ_LOCK(pool->portal, irqflags); ++ it = *base; /* <-- gotcha, don't do this prior to the irq_save */ ++ while (it != pool) { ++ last = it; ++ it = it->next; ++ } ++ if (!last) ++ *base = pool->next; ++ else ++ last->next = pool->next; ++ if (!last && !pool->next) { ++ /* Last object for that bpid on this portal, disable the BSCN ++ * mask bit. */ ++ bm_isr_bscn_mask(&pool->portal->p, pool->params.bpid, 0); ++ /* And "forget" that we last saw this pool as depleted */ ++ bman_depletion_unset(&pool->portal->pools[1], ++ pool->params.bpid); ++ } ++ PORTAL_IRQ_UNLOCK(pool->portal, irqflags); ++} ++ ++/* In the case that the application's core loop calls qman_poll() and ++ * bman_poll(), we ought to balance how often we incur the overheads of the ++ * slow-path poll. We'll use two decrementer sources. The idle decrementer ++ * constant is used when the last slow-poll detected no work to do, and the busy ++ * decrementer constant when the last slow-poll had work to do. */ ++#define SLOW_POLL_IDLE 1000 ++#define SLOW_POLL_BUSY 10 ++static u32 __poll_portal_slow(struct bman_portal *p, u32 is); ++ ++/* Portal interrupt handler */ ++static irqreturn_t portal_isr(__always_unused int irq, void *ptr) ++{ ++ struct bman_portal *p = ptr; ++ u32 clear = p->irq_sources; ++ u32 is = bm_isr_status_read(&p->p) & p->irq_sources; ++ clear |= __poll_portal_slow(p, is); ++ bm_isr_status_clear(&p->p, clear); ++ return IRQ_HANDLED; ++} ++ ++#ifdef CONFIG_SUSPEND ++static int _bman_portal_suspend_noirq(struct device *dev) ++{ ++ struct bman_portal *p = (struct bman_portal *)dev->platform_data; ++#ifdef CONFIG_PM_DEBUG ++ struct platform_device *pdev = to_platform_device(dev); ++#endif ++ p->save_isdr = bm_isr_disable_read(&p->p); ++ bm_isr_disable_write(&p->p, 0xffffffff); ++ bm_isr_status_clear(&p->p, 0xffffffff); ++#ifdef CONFIG_PM_DEBUG ++ pr_info("Suspend for %s\n", pdev->name); ++#endif ++ return 0; ++} ++ ++static int _bman_portal_resume_noirq(struct device *dev) ++{ ++ struct bman_portal *p = (struct bman_portal *)dev->platform_data; ++ ++ /* restore isdr */ ++ bm_isr_disable_write(&p->p, p->save_isdr); ++ return 0; ++} ++#else ++#define _bman_portal_suspend_noirq NULL ++#define _bman_portal_resume_noirq NULL ++#endif ++ ++struct dev_pm_domain bman_portal_device_pm_domain = { ++ .ops = { ++ USE_PLATFORM_PM_SLEEP_OPS ++ .suspend_noirq = _bman_portal_suspend_noirq, ++ .resume_noirq = _bman_portal_resume_noirq, ++ } ++}; ++ ++struct bman_portal *bman_create_portal( ++ struct bman_portal *portal, ++ const struct bm_portal_config *config) ++{ ++ struct bm_portal *__p; ++ const struct bman_depletion *pools = &config->public_cfg.mask; ++ int ret; ++ u8 bpid = 0; ++ char buf[16]; ++ ++ if (!portal) { ++ portal = kmalloc(sizeof(*portal), GFP_KERNEL); ++ if (!portal) ++ return portal; ++ portal->alloced = 1; ++ } else ++ portal->alloced = 0; ++ ++ __p = &portal->p; ++ ++ /* prep the low-level portal struct with the mapped addresses from the ++ * config, everything that follows depends on it and "config" is more ++ * for (de)reference... */ ++ __p->addr.addr_ce = config->addr_virt[DPA_PORTAL_CE]; ++ __p->addr.addr_ci = config->addr_virt[DPA_PORTAL_CI]; ++ if (bm_rcr_init(__p, bm_rcr_pvb, bm_rcr_cce)) { ++ pr_err("Bman RCR initialisation failed\n"); ++ goto fail_rcr; ++ } ++ if (bm_mc_init(__p)) { ++ pr_err("Bman MC initialisation failed\n"); ++ goto fail_mc; ++ } ++ if (bm_isr_init(__p)) { ++ pr_err("Bman ISR initialisation failed\n"); ++ goto fail_isr; ++ } ++ portal->pools = kmalloc(2 * sizeof(*pools), GFP_KERNEL); ++ if (!portal->pools) ++ goto fail_pools; ++ portal->pools[0] = *pools; ++ bman_depletion_init(portal->pools + 1); ++ while (bpid < bman_pool_max) { ++ /* Default to all BPIDs disabled, we enable as required at ++ * run-time. */ ++ bm_isr_bscn_mask(__p, bpid, 0); ++ bpid++; ++ } ++ portal->slowpoll = 0; ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ portal->rcri_owned = NULL; ++#endif ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ raw_spin_lock_init(&portal->sharing_lock); ++ portal->is_shared = config->public_cfg.is_shared; ++ portal->sharing_redirect = NULL; ++#endif ++ sprintf(buf, "bportal-%u", config->public_cfg.index); ++ portal->pdev = platform_device_alloc(buf, -1); ++ if (!portal->pdev) ++ goto fail_devalloc; ++ portal->pdev->dev.pm_domain = &bman_portal_device_pm_domain; ++ portal->pdev->dev.platform_data = portal; ++ ret = platform_device_add(portal->pdev); ++ if (ret) ++ goto fail_devadd; ++ memset(&portal->cb, 0, sizeof(portal->cb)); ++ /* Write-to-clear any stale interrupt status bits */ ++ bm_isr_disable_write(__p, 0xffffffff); ++ portal->irq_sources = 0; ++ bm_isr_enable_write(__p, portal->irq_sources); ++ bm_isr_status_clear(__p, 0xffffffff); ++ snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, config->public_cfg.cpu); ++ if (request_irq(config->public_cfg.irq, portal_isr, 0, portal->irqname, ++ portal)) { ++ pr_err("request_irq() failed\n"); ++ goto fail_irq; ++ } ++ if ((config->public_cfg.cpu != -1) && ++ irq_can_set_affinity(config->public_cfg.irq) && ++ irq_set_affinity(config->public_cfg.irq, ++ cpumask_of(config->public_cfg.cpu))) { ++ pr_err("irq_set_affinity() failed %s\n", portal->irqname); ++ goto fail_affinity; ++ } ++ ++ /* Need RCR to be empty before continuing */ ++ ret = bm_rcr_get_fill(__p); ++ if (ret) { ++ pr_err("Bman RCR unclean\n"); ++ goto fail_rcr_empty; ++ } ++ /* Success */ ++ portal->config = config; ++ ++ bm_isr_disable_write(__p, 0); ++ bm_isr_uninhibit(__p); ++ return portal; ++fail_rcr_empty: ++fail_affinity: ++ free_irq(config->public_cfg.irq, portal); ++fail_irq: ++ platform_device_del(portal->pdev); ++fail_devadd: ++ platform_device_put(portal->pdev); ++fail_devalloc: ++ kfree(portal->pools); ++fail_pools: ++ bm_isr_finish(__p); ++fail_isr: ++ bm_mc_finish(__p); ++fail_mc: ++ bm_rcr_finish(__p); ++fail_rcr: ++ if (portal->alloced) ++ kfree(portal); ++ return NULL; ++} ++ ++struct bman_portal *bman_create_affine_portal( ++ const struct bm_portal_config *config) ++{ ++ struct bman_portal *portal; ++ ++ portal = &per_cpu(bman_affine_portal, config->public_cfg.cpu); ++ portal = bman_create_portal(portal, config); ++ if (portal) { ++ spin_lock(&affine_mask_lock); ++ cpumask_set_cpu(config->public_cfg.cpu, &affine_mask); ++ spin_unlock(&affine_mask_lock); ++ } ++ return portal; ++} ++ ++ ++struct bman_portal *bman_create_affine_slave(struct bman_portal *redirect, ++ int cpu) ++{ ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ struct bman_portal *p; ++ p = &per_cpu(bman_affine_portal, cpu); ++ BUG_ON(p->config); ++ BUG_ON(p->is_shared); ++ BUG_ON(!redirect->config->public_cfg.is_shared); ++ p->irq_sources = 0; ++ p->sharing_redirect = redirect; ++ return p; ++#else ++ BUG(); ++ return NULL; ++#endif ++} ++ ++void bman_destroy_portal(struct bman_portal *bm) ++{ ++ const struct bm_portal_config *pcfg; ++ pcfg = bm->config; ++ bm_rcr_cce_update(&bm->p); ++ bm_rcr_cce_update(&bm->p); ++ ++ free_irq(pcfg->public_cfg.irq, bm); ++ ++ kfree(bm->pools); ++ bm_isr_finish(&bm->p); ++ bm_mc_finish(&bm->p); ++ bm_rcr_finish(&bm->p); ++ bm->config = NULL; ++ if (bm->alloced) ++ kfree(bm); ++} ++ ++const struct bm_portal_config *bman_destroy_affine_portal(void) ++{ ++ struct bman_portal *bm = get_raw_affine_portal(); ++ const struct bm_portal_config *pcfg; ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ if (bm->sharing_redirect) { ++ bm->sharing_redirect = NULL; ++ put_affine_portal(); ++ return NULL; ++ } ++ bm->is_shared = 0; ++#endif ++ pcfg = bm->config; ++ bman_destroy_portal(bm); ++ spin_lock(&affine_mask_lock); ++ cpumask_clear_cpu(pcfg->public_cfg.cpu, &affine_mask); ++ spin_unlock(&affine_mask_lock); ++ put_affine_portal(); ++ return pcfg; ++} ++ ++/* When release logic waits on available RCR space, we need a global waitqueue ++ * in the case of "affine" use (as the waits wake on different cpus which means ++ * different portals - so we can't wait on any per-portal waitqueue). */ ++static DECLARE_WAIT_QUEUE_HEAD(affine_queue); ++ ++static u32 __poll_portal_slow(struct bman_portal *p, u32 is) ++{ ++ struct bman_depletion tmp; ++ u32 ret = is; ++ ++ /* There is a gotcha to be aware of. If we do the query before clearing ++ * the status register, we may miss state changes that occur between the ++ * two. If we write to clear the status register before the query, the ++ * cache-enabled query command may overtake the status register write ++ * unless we use a heavyweight sync (which we don't want). Instead, we ++ * write-to-clear the status register then *read it back* before doing ++ * the query, hence the odd while loop with the 'is' accumulation. */ ++ if (is & BM_PIRQ_BSCN) { ++ struct bm_mc_result *mcr; ++ __maybe_unused unsigned long irqflags; ++ unsigned int i, j; ++ u32 __is; ++ bm_isr_status_clear(&p->p, BM_PIRQ_BSCN); ++ while ((__is = bm_isr_status_read(&p->p)) & BM_PIRQ_BSCN) { ++ is |= __is; ++ bm_isr_status_clear(&p->p, BM_PIRQ_BSCN); ++ } ++ is &= ~BM_PIRQ_BSCN; ++ PORTAL_IRQ_LOCK(p, irqflags); ++ bm_mc_start(&p->p); ++ bm_mc_commit(&p->p, BM_MCC_VERB_CMD_QUERY); ++ while (!(mcr = bm_mc_result(&p->p))) ++ cpu_relax(); ++ tmp = mcr->query.ds.state; ++ tmp.__state[0] = be32_to_cpu(tmp.__state[0]); ++ tmp.__state[1] = be32_to_cpu(tmp.__state[1]); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ for (i = 0; i < 2; i++) { ++ int idx = i * 32; ++ /* tmp is a mask of currently-depleted pools. ++ * pools[0] is mask of those we care about. ++ * pools[1] is our previous view (we only want to ++ * be told about changes). */ ++ tmp.__state[i] &= p->pools[0].__state[i]; ++ if (tmp.__state[i] == p->pools[1].__state[i]) ++ /* fast-path, nothing to see, move along */ ++ continue; ++ for (j = 0; j <= 31; j++, idx++) { ++ struct bman_pool *pool = p->cb[idx]; ++ int b4 = bman_depletion_get(&p->pools[1], idx); ++ int af = bman_depletion_get(&tmp, idx); ++ if (b4 == af) ++ continue; ++ while (pool) { ++ pool->params.cb(p, pool, ++ pool->params.cb_ctx, af); ++ pool = pool->next; ++ } ++ } ++ } ++ p->pools[1] = tmp; ++ } ++ ++ if (is & BM_PIRQ_RCRI) { ++ __maybe_unused unsigned long irqflags; ++ PORTAL_IRQ_LOCK(p, irqflags); ++ bm_rcr_cce_update(&p->p); ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ /* If waiting for sync, we only cancel the interrupt threshold ++ * when the ring utilisation hits zero. */ ++ if (p->rcri_owned) { ++ if (!bm_rcr_get_fill(&p->p)) { ++ p->rcri_owned = NULL; ++ bm_rcr_set_ithresh(&p->p, 0); ++ } ++ } else ++#endif ++ bm_rcr_set_ithresh(&p->p, 0); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ wake_up(&affine_queue); ++ bm_isr_status_clear(&p->p, BM_PIRQ_RCRI); ++ is &= ~BM_PIRQ_RCRI; ++ } ++ ++ /* There should be no status register bits left undefined */ ++ DPA_ASSERT(!is); ++ return ret; ++} ++ ++const struct bman_portal_config *bman_get_portal_config(void) ++{ ++ struct bman_portal *p = get_affine_portal(); ++ const struct bman_portal_config *ret = &p->config->public_cfg; ++ put_affine_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(bman_get_portal_config); ++ ++u32 bman_irqsource_get(void) ++{ ++ struct bman_portal *p = get_raw_affine_portal(); ++ u32 ret = p->irq_sources & BM_PIRQ_VISIBLE; ++ put_affine_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(bman_irqsource_get); ++ ++int bman_p_irqsource_add(struct bman_portal *p, __maybe_unused u32 bits) ++{ ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ if (p->sharing_redirect) ++ return -EINVAL; ++ else ++#endif ++ { ++ __maybe_unused unsigned long irqflags; ++ PORTAL_IRQ_LOCK(p, irqflags); ++ set_bits(bits & BM_PIRQ_VISIBLE, &p->irq_sources); ++ bm_isr_enable_write(&p->p, p->irq_sources); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ } ++ return 0; ++} ++EXPORT_SYMBOL(bman_p_irqsource_add); ++ ++int bman_irqsource_add(__maybe_unused u32 bits) ++{ ++ struct bman_portal *p = get_raw_affine_portal(); ++ int ret = 0; ++ ret = bman_p_irqsource_add(p, bits); ++ put_affine_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(bman_irqsource_add); ++ ++int bman_irqsource_remove(u32 bits) ++{ ++ struct bman_portal *p = get_raw_affine_portal(); ++ __maybe_unused unsigned long irqflags; ++ u32 ier; ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ if (p->sharing_redirect) { ++ put_affine_portal(); ++ return -EINVAL; ++ } ++#endif ++ /* Our interrupt handler only processes+clears status register bits that ++ * are in p->irq_sources. As we're trimming that mask, if one of them ++ * were to assert in the status register just before we remove it from ++ * the enable register, there would be an interrupt-storm when we ++ * release the IRQ lock. So we wait for the enable register update to ++ * take effect in h/w (by reading it back) and then clear all other bits ++ * in the status register. Ie. we clear them from ISR once it's certain ++ * IER won't allow them to reassert. */ ++ PORTAL_IRQ_LOCK(p, irqflags); ++ bits &= BM_PIRQ_VISIBLE; ++ clear_bits(bits, &p->irq_sources); ++ bm_isr_enable_write(&p->p, p->irq_sources); ++ ier = bm_isr_enable_read(&p->p); ++ /* Using "~ier" (rather than "bits" or "~p->irq_sources") creates a ++ * data-dependency, ie. to protect against re-ordering. */ ++ bm_isr_status_clear(&p->p, ~ier); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ return 0; ++} ++EXPORT_SYMBOL(bman_irqsource_remove); ++ ++const cpumask_t *bman_affine_cpus(void) ++{ ++ return &affine_mask; ++} ++EXPORT_SYMBOL(bman_affine_cpus); ++ ++u32 bman_poll_slow(void) ++{ ++ struct bman_portal *p = get_poll_portal(); ++ u32 ret; ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ if (unlikely(p->sharing_redirect)) ++ ret = (u32)-1; ++ else ++#endif ++ { ++ u32 is = bm_isr_status_read(&p->p) & ~p->irq_sources; ++ ret = __poll_portal_slow(p, is); ++ bm_isr_status_clear(&p->p, ret); ++ } ++ put_poll_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(bman_poll_slow); ++ ++/* Legacy wrapper */ ++void bman_poll(void) ++{ ++ struct bman_portal *p = get_poll_portal(); ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ if (unlikely(p->sharing_redirect)) ++ goto done; ++#endif ++ if (!(p->slowpoll--)) { ++ u32 is = bm_isr_status_read(&p->p) & ~p->irq_sources; ++ u32 active = __poll_portal_slow(p, is); ++ if (active) ++ p->slowpoll = SLOW_POLL_BUSY; ++ else ++ p->slowpoll = SLOW_POLL_IDLE; ++ } ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++done: ++#endif ++ put_poll_portal(); ++} ++EXPORT_SYMBOL(bman_poll); ++ ++static const u32 zero_thresholds[4] = {0, 0, 0, 0}; ++ ++struct bman_pool *bman_new_pool(const struct bman_pool_params *params) ++{ ++ struct bman_pool *pool = NULL; ++ u32 bpid; ++ ++ if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID) { ++ int ret = bman_alloc_bpid(&bpid); ++ if (ret) ++ return NULL; ++ } else { ++ if (params->bpid >= bman_pool_max) ++ return NULL; ++ bpid = params->bpid; ++ } ++#ifdef CONFIG_FSL_BMAN_CONFIG ++ if (params->flags & BMAN_POOL_FLAG_THRESH) { ++ int ret = bm_pool_set(bpid, params->thresholds); ++ if (ret) ++ goto err; ++ } ++#else ++ if (params->flags & BMAN_POOL_FLAG_THRESH) ++ goto err; ++#endif ++ pool = kmalloc(sizeof(*pool), GFP_KERNEL); ++ if (!pool) ++ goto err; ++ pool->sp = NULL; ++ pool->sp_fill = 0; ++ pool->params = *params; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ atomic_set(&pool->in_use, 1); ++#endif ++ if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID) ++ pool->params.bpid = bpid; ++ if (params->flags & BMAN_POOL_FLAG_STOCKPILE) { ++ pool->sp = kmalloc(sizeof(struct bm_buffer) * BMAN_STOCKPILE_SZ, ++ GFP_KERNEL); ++ if (!pool->sp) ++ goto err; ++ } ++ if (pool->params.flags & BMAN_POOL_FLAG_DEPLETION) { ++ struct bman_portal *p = get_affine_portal(); ++ if (!p->pools || !bman_depletion_get(&p->pools[0], bpid)) { ++ pr_err("Depletion events disabled for bpid %d\n", bpid); ++ goto err; ++ } ++ depletion_link(p, pool); ++ put_affine_portal(); ++ } ++ return pool; ++err: ++#ifdef CONFIG_FSL_BMAN_CONFIG ++ if (params->flags & BMAN_POOL_FLAG_THRESH) ++ bm_pool_set(bpid, zero_thresholds); ++#endif ++ if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID) ++ bman_release_bpid(bpid); ++ if (pool) { ++ kfree(pool->sp); ++ kfree(pool); ++ } ++ return NULL; ++} ++EXPORT_SYMBOL(bman_new_pool); ++ ++void bman_free_pool(struct bman_pool *pool) ++{ ++#ifdef CONFIG_FSL_BMAN_CONFIG ++ if (pool->params.flags & BMAN_POOL_FLAG_THRESH) ++ bm_pool_set(pool->params.bpid, zero_thresholds); ++#endif ++ if (pool->params.flags & BMAN_POOL_FLAG_DEPLETION) ++ depletion_unlink(pool); ++ if (pool->params.flags & BMAN_POOL_FLAG_STOCKPILE) { ++ if (pool->sp_fill) ++ pr_err("Stockpile not flushed, has %u in bpid %u.\n", ++ pool->sp_fill, pool->params.bpid); ++ kfree(pool->sp); ++ pool->sp = NULL; ++ pool->params.flags ^= BMAN_POOL_FLAG_STOCKPILE; ++ } ++ if (pool->params.flags & BMAN_POOL_FLAG_DYNAMIC_BPID) ++ bman_release_bpid(pool->params.bpid); ++ kfree(pool); ++} ++EXPORT_SYMBOL(bman_free_pool); ++ ++const struct bman_pool_params *bman_get_params(const struct bman_pool *pool) ++{ ++ return &pool->params; ++} ++EXPORT_SYMBOL(bman_get_params); ++ ++static noinline void update_rcr_ci(struct bman_portal *p, u8 avail) ++{ ++ if (avail) ++ bm_rcr_cce_prefetch(&p->p); ++ else ++ bm_rcr_cce_update(&p->p); ++} ++ ++int bman_rcr_is_empty(void) ++{ ++ __maybe_unused unsigned long irqflags; ++ struct bman_portal *p = get_affine_portal(); ++ u8 avail; ++ ++ PORTAL_IRQ_LOCK(p, irqflags); ++ update_rcr_ci(p, 0); ++ avail = bm_rcr_get_fill(&p->p); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ return avail == 0; ++} ++EXPORT_SYMBOL(bman_rcr_is_empty); ++ ++static inline struct bm_rcr_entry *try_rel_start(struct bman_portal **p, ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++ __maybe_unused struct bman_pool *pool, ++#endif ++ __maybe_unused unsigned long *irqflags, ++ __maybe_unused u32 flags) ++{ ++ struct bm_rcr_entry *r; ++ u8 avail; ++ ++ *p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(*p, (*irqflags)); ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ if (unlikely((flags & BMAN_RELEASE_FLAG_WAIT) && ++ (flags & BMAN_RELEASE_FLAG_WAIT_SYNC))) { ++ if ((*p)->rcri_owned) { ++ PORTAL_IRQ_UNLOCK(*p, (*irqflags)); ++ put_affine_portal(); ++ return NULL; ++ } ++ (*p)->rcri_owned = pool; ++ } ++#endif ++ avail = bm_rcr_get_avail(&(*p)->p); ++ if (avail < 2) ++ update_rcr_ci(*p, avail); ++ r = bm_rcr_start(&(*p)->p); ++ if (unlikely(!r)) { ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ if (unlikely((flags & BMAN_RELEASE_FLAG_WAIT) && ++ (flags & BMAN_RELEASE_FLAG_WAIT_SYNC))) ++ (*p)->rcri_owned = NULL; ++#endif ++ PORTAL_IRQ_UNLOCK(*p, (*irqflags)); ++ put_affine_portal(); ++ } ++ return r; ++} ++ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++static noinline struct bm_rcr_entry *__wait_rel_start(struct bman_portal **p, ++ struct bman_pool *pool, ++ __maybe_unused unsigned long *irqflags, ++ u32 flags) ++{ ++ struct bm_rcr_entry *rcr = try_rel_start(p, pool, irqflags, flags); ++ if (!rcr) ++ bm_rcr_set_ithresh(&(*p)->p, 1); ++ return rcr; ++} ++ ++static noinline struct bm_rcr_entry *wait_rel_start(struct bman_portal **p, ++ struct bman_pool *pool, ++ __maybe_unused unsigned long *irqflags, ++ u32 flags) ++{ ++ struct bm_rcr_entry *rcr; ++#ifndef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ pool = NULL; ++#endif ++ if (flags & BMAN_RELEASE_FLAG_WAIT_INT) ++ /* NB: return NULL if signal occurs before completion. Signal ++ * can occur during return. Caller must check for signal */ ++ wait_event_interruptible(affine_queue, ++ (rcr = __wait_rel_start(p, pool, irqflags, flags))); ++ else ++ wait_event(affine_queue, ++ (rcr = __wait_rel_start(p, pool, irqflags, flags))); ++ return rcr; ++} ++#endif ++ ++static inline int __bman_release(struct bman_pool *pool, ++ const struct bm_buffer *bufs, u8 num, u32 flags) ++{ ++ struct bman_portal *p; ++ struct bm_rcr_entry *r; ++ __maybe_unused unsigned long irqflags; ++ u32 i = num - 1; ++ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++ if (flags & BMAN_RELEASE_FLAG_WAIT) ++ r = wait_rel_start(&p, pool, &irqflags, flags); ++ else ++ r = try_rel_start(&p, pool, &irqflags, flags); ++#else ++ r = try_rel_start(&p, &irqflags, flags); ++#endif ++ if (!r) ++ return -EBUSY; ++ /* We can copy all but the first entry, as this can trigger badness ++ * with the valid-bit. Use the overlay to mask the verb byte. */ ++ r->bufs[0].opaque = ++ ((cpu_to_be64((bufs[0].opaque | ++ ((u64)pool->params.bpid<<48)) ++ & 0x00ffffffffffffff))); ++ if (i) { ++ for (i = 1; i < num; i++) ++ r->bufs[i].opaque = ++ cpu_to_be64(bufs[i].opaque); ++ } ++ ++ bm_rcr_pvb_commit(&p->p, BM_RCR_VERB_CMD_BPID_SINGLE | ++ (num & BM_RCR_VERB_BUFCOUNT_MASK)); ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ /* if we wish to sync we need to set the threshold after h/w sees the ++ * new ring entry. As we're mixing cache-enabled and cache-inhibited ++ * accesses, this requires a heavy-weight sync. */ ++ if (unlikely((flags & BMAN_RELEASE_FLAG_WAIT) && ++ (flags & BMAN_RELEASE_FLAG_WAIT_SYNC))) { ++ hwsync(); ++ bm_rcr_set_ithresh(&p->p, 1); ++ } ++#endif ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ if (unlikely((flags & BMAN_RELEASE_FLAG_WAIT) && ++ (flags & BMAN_RELEASE_FLAG_WAIT_SYNC))) { ++ if (flags & BMAN_RELEASE_FLAG_WAIT_INT) ++ /* NB: return success even if signal occurs before ++ * condition is true. pvb_commit guarantees success */ ++ wait_event_interruptible(affine_queue, ++ (p->rcri_owned != pool)); ++ else ++ wait_event(affine_queue, (p->rcri_owned != pool)); ++ } ++#endif ++ return 0; ++} ++ ++int bman_release(struct bman_pool *pool, const struct bm_buffer *bufs, u8 num, ++ u32 flags) ++{ ++ int ret; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ if (!num || (num > 8)) ++ return -EINVAL; ++ if (pool->params.flags & BMAN_POOL_FLAG_NO_RELEASE) ++ return -EINVAL; ++#endif ++ /* Without stockpile, this API is a pass-through to the h/w operation */ ++ if (!(pool->params.flags & BMAN_POOL_FLAG_STOCKPILE)) ++ return __bman_release(pool, bufs, num, flags); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ if (!atomic_dec_and_test(&pool->in_use)) { ++ pr_crit("Parallel attempts to enter bman_released() detected."); ++ panic("only one instance of bman_released/acquired allowed"); ++ } ++#endif ++ /* Two movements of buffers are possible, and can occur in either order. ++ * A: moving buffers from the caller to the stockpile. ++ * B: moving buffers from the stockpile to hardware. ++ * Order 1: if there is already enough space in the stockpile for A ++ * then we want to do A first, and only do B if we trigger the ++ * stockpile-high threshold. ++ * Order 2: if there is not enough space in the stockpile for A, then ++ * we want to do B first, then do A if B had succeeded. However in this ++ * case B is dependent on how many buffers the user needs to release, ++ * not the stockpile-high threshold. ++ * Due to the different handling of B between the two cases, putting A ++ * and B in a while() loop would require quite obscure logic, so handle ++ * the different sequences explicitly. */ ++ if ((pool->sp_fill + num) <= BMAN_STOCKPILE_SZ) { ++ /* Order 1: do A */ ++ copy_words(pool->sp + pool->sp_fill, bufs, ++ sizeof(struct bm_buffer) * num); ++ pool->sp_fill += num; ++ /* do B relative to STOCKPILE_HIGH */ ++ while (pool->sp_fill >= BMAN_STOCKPILE_HIGH) { ++ ret = __bman_release(pool, ++ pool->sp + (pool->sp_fill - 8), 8, ++ flags); ++ if (ret >= 0) ++ pool->sp_fill -= 8; ++ } ++ } else { ++ /* Order 2: do B relative to 'num' */ ++ do { ++ ret = __bman_release(pool, ++ pool->sp + (pool->sp_fill - 8), 8, ++ flags); ++ if (ret < 0) ++ /* failure */ ++ goto release_done; ++ pool->sp_fill -= 8; ++ } while ((pool->sp_fill + num) > BMAN_STOCKPILE_SZ); ++ /* do A */ ++ copy_words(pool->sp + pool->sp_fill, bufs, ++ sizeof(struct bm_buffer) * num); ++ pool->sp_fill += num; ++ } ++ /* success */ ++ ret = 0; ++release_done: ++#ifdef CONFIG_FSL_DPA_CHECKING ++ atomic_inc(&pool->in_use); ++#endif ++ return ret; ++} ++EXPORT_SYMBOL(bman_release); ++ ++static inline int __bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, ++ u8 num) ++{ ++ struct bman_portal *p = get_affine_portal(); ++ struct bm_mc_command *mcc; ++ struct bm_mc_result *mcr; ++ __maybe_unused unsigned long irqflags; ++ int ret, i; ++ ++ PORTAL_IRQ_LOCK(p, irqflags); ++ mcc = bm_mc_start(&p->p); ++ mcc->acquire.bpid = pool->params.bpid; ++ bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE | ++ (num & BM_MCC_VERB_ACQUIRE_BUFCOUNT)); ++ while (!(mcr = bm_mc_result(&p->p))) ++ cpu_relax(); ++ ret = mcr->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT; ++ if (bufs) { ++ for (i = 0; i < num; i++) ++ bufs[i].opaque = ++ be64_to_cpu(mcr->acquire.bufs[i].opaque); ++ } ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ if (ret != num) ++ ret = -ENOMEM; ++ return ret; ++} ++ ++int bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, u8 num, ++ u32 flags) ++{ ++ int ret; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ if (!num || (num > 8)) ++ return -EINVAL; ++ if (pool->params.flags & BMAN_POOL_FLAG_ONLY_RELEASE) ++ return -EINVAL; ++#endif ++ /* Without stockpile, this API is a pass-through to the h/w operation */ ++ if (!(pool->params.flags & BMAN_POOL_FLAG_STOCKPILE)) ++ return __bman_acquire(pool, bufs, num); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ if (!atomic_dec_and_test(&pool->in_use)) { ++ pr_crit("Parallel attempts to enter bman_acquire() detected."); ++ panic("only one instance of bman_released/acquired allowed"); ++ } ++#endif ++ /* Two movements of buffers are possible, and can occur in either order. ++ * A: moving buffers from stockpile to the caller. ++ * B: moving buffers from hardware to the stockpile. ++ * Order 1: if there are already enough buffers in the stockpile for A ++ * then we want to do A first, and only do B if we trigger the ++ * stockpile-low threshold. ++ * Order 2: if there are not enough buffers in the stockpile for A, ++ * then we want to do B first, then do A if B had succeeded. However in ++ * this case B is dependent on how many buffers the user needs, not the ++ * stockpile-low threshold. ++ * Due to the different handling of B between the two cases, putting A ++ * and B in a while() loop would require quite obscure logic, so handle ++ * the different sequences explicitly. */ ++ if (num <= pool->sp_fill) { ++ /* Order 1: do A */ ++ copy_words(bufs, pool->sp + (pool->sp_fill - num), ++ sizeof(struct bm_buffer) * num); ++ pool->sp_fill -= num; ++ /* do B relative to STOCKPILE_LOW */ ++ while (pool->sp_fill <= BMAN_STOCKPILE_LOW) { ++ ret = __bman_acquire(pool, pool->sp + pool->sp_fill, 8); ++ if (ret < 0) ++ ret = __bman_acquire(pool, ++ pool->sp + pool->sp_fill, 1); ++ if (ret < 0) ++ break; ++ pool->sp_fill += ret; ++ } ++ } else { ++ /* Order 2: do B relative to 'num' */ ++ do { ++ ret = __bman_acquire(pool, pool->sp + pool->sp_fill, 8); ++ if (ret < 0) ++ ret = __bman_acquire(pool, ++ pool->sp + pool->sp_fill, 1); ++ if (ret < 0) ++ /* failure */ ++ goto acquire_done; ++ pool->sp_fill += ret; ++ } while (pool->sp_fill < num); ++ /* do A */ ++ copy_words(bufs, pool->sp + (pool->sp_fill - num), ++ sizeof(struct bm_buffer) * num); ++ pool->sp_fill -= num; ++ } ++ /* success */ ++ ret = num; ++acquire_done: ++#ifdef CONFIG_FSL_DPA_CHECKING ++ atomic_inc(&pool->in_use); ++#endif ++ return ret; ++} ++EXPORT_SYMBOL(bman_acquire); ++ ++int bman_flush_stockpile(struct bman_pool *pool, u32 flags) ++{ ++ u8 num; ++ int ret; ++ ++ while (pool->sp_fill) { ++ num = ((pool->sp_fill > 8) ? 8 : pool->sp_fill); ++ ret = __bman_release(pool, pool->sp + (pool->sp_fill - num), ++ num, flags); ++ if (ret) ++ return ret; ++ pool->sp_fill -= num; ++ } ++ return 0; ++} ++EXPORT_SYMBOL(bman_flush_stockpile); ++ ++int bman_query_pools(struct bm_pool_state *state) ++{ ++ struct bman_portal *p = get_affine_portal(); ++ struct bm_mc_result *mcr; ++ __maybe_unused unsigned long irqflags; ++ ++ PORTAL_IRQ_LOCK(p, irqflags); ++ bm_mc_start(&p->p); ++ bm_mc_commit(&p->p, BM_MCC_VERB_CMD_QUERY); ++ while (!(mcr = bm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & BM_MCR_VERB_CMD_MASK) == BM_MCR_VERB_CMD_QUERY); ++ *state = mcr->query; ++ state->as.state.__state[0] = be32_to_cpu(state->as.state.__state[0]); ++ state->as.state.__state[1] = be32_to_cpu(state->as.state.__state[1]); ++ state->ds.state.__state[0] = be32_to_cpu(state->ds.state.__state[0]); ++ state->ds.state.__state[1] = be32_to_cpu(state->ds.state.__state[1]); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ return 0; ++} ++EXPORT_SYMBOL(bman_query_pools); ++ ++#ifdef CONFIG_FSL_BMAN_CONFIG ++u32 bman_query_free_buffers(struct bman_pool *pool) ++{ ++ return bm_pool_free_buffers(pool->params.bpid); ++} ++EXPORT_SYMBOL(bman_query_free_buffers); ++ ++int bman_update_pool_thresholds(struct bman_pool *pool, const u32 *thresholds) ++{ ++ u32 bpid; ++ ++ bpid = bman_get_params(pool)->bpid; ++ ++ return bm_pool_set(bpid, thresholds); ++} ++EXPORT_SYMBOL(bman_update_pool_thresholds); ++#endif ++ ++int bman_shutdown_pool(u32 bpid) ++{ ++ struct bman_portal *p = get_affine_portal(); ++ __maybe_unused unsigned long irqflags; ++ int ret; ++ ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ret = bm_shutdown_pool(&p->p, bpid); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(bman_shutdown_pool); ++ ++const struct bm_portal_config *bman_get_bm_portal_config( ++ struct bman_portal *portal) ++{ ++ return portal->sharing_redirect ? NULL : portal->config; ++} +diff --git a/drivers/staging/fsl_qbman/bman_low.h b/drivers/staging/fsl_qbman/bman_low.h +new file mode 100644 +index 00000000..3da70571 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/bman_low.h +@@ -0,0 +1,565 @@ ++/* Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "bman_private.h" ++ ++/***************************/ ++/* Portal register assists */ ++/***************************/ ++ ++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) ++ ++/* Cache-inhibited register offsets */ ++#define BM_REG_RCR_PI_CINH 0x0000 ++#define BM_REG_RCR_CI_CINH 0x0004 ++#define BM_REG_RCR_ITR 0x0008 ++#define BM_REG_CFG 0x0100 ++#define BM_REG_SCN(n) (0x0200 + ((n) << 2)) ++#define BM_REG_ISR 0x0e00 ++#define BM_REG_IIR 0x0e0c ++ ++/* Cache-enabled register offsets */ ++#define BM_CL_CR 0x0000 ++#define BM_CL_RR0 0x0100 ++#define BM_CL_RR1 0x0140 ++#define BM_CL_RCR 0x1000 ++#define BM_CL_RCR_PI_CENA 0x3000 ++#define BM_CL_RCR_CI_CENA 0x3100 ++ ++#endif ++ ++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) ++ ++/* Cache-inhibited register offsets */ ++#define BM_REG_RCR_PI_CINH 0x3000 ++#define BM_REG_RCR_CI_CINH 0x3100 ++#define BM_REG_RCR_ITR 0x3200 ++#define BM_REG_CFG 0x3300 ++#define BM_REG_SCN(n) (0x3400 + ((n) << 6)) ++#define BM_REG_ISR 0x3e00 ++#define BM_REG_IIR 0x3ec0 ++ ++/* Cache-enabled register offsets */ ++#define BM_CL_CR 0x0000 ++#define BM_CL_RR0 0x0100 ++#define BM_CL_RR1 0x0140 ++#define BM_CL_RCR 0x1000 ++#define BM_CL_RCR_PI_CENA 0x3000 ++#define BM_CL_RCR_CI_CENA 0x3100 ++ ++#endif ++ ++/* BTW, the drivers (and h/w programming model) already obtain the required ++ * synchronisation for portal accesses via lwsync(), hwsync(), and ++ * data-dependencies. Use of barrier()s or other order-preserving primitives ++ * simply degrade performance. Hence the use of the __raw_*() interfaces, which ++ * simply ensure that the compiler treats the portal registers as volatile (ie. ++ * non-coherent). */ ++ ++/* Cache-inhibited register access. */ ++#define __bm_in(bm, o) be32_to_cpu(__raw_readl((bm)->addr_ci + (o))) ++#define __bm_out(bm, o, val) __raw_writel(cpu_to_be32(val), \ ++ (bm)->addr_ci + (o)); ++#define bm_in(reg) __bm_in(&portal->addr, BM_REG_##reg) ++#define bm_out(reg, val) __bm_out(&portal->addr, BM_REG_##reg, val) ++ ++/* Cache-enabled (index) register access */ ++#define __bm_cl_touch_ro(bm, o) dcbt_ro((bm)->addr_ce + (o)) ++#define __bm_cl_touch_rw(bm, o) dcbt_rw((bm)->addr_ce + (o)) ++#define __bm_cl_in(bm, o) be32_to_cpu(__raw_readl((bm)->addr_ce + (o))) ++#define __bm_cl_out(bm, o, val) \ ++ do { \ ++ u32 *__tmpclout = (bm)->addr_ce + (o); \ ++ __raw_writel(cpu_to_be32(val), __tmpclout); \ ++ dcbf(__tmpclout); \ ++ } while (0) ++#define __bm_cl_invalidate(bm, o) dcbi((bm)->addr_ce + (o)) ++#define bm_cl_touch_ro(reg) __bm_cl_touch_ro(&portal->addr, BM_CL_##reg##_CENA) ++#define bm_cl_touch_rw(reg) __bm_cl_touch_rw(&portal->addr, BM_CL_##reg##_CENA) ++#define bm_cl_in(reg) __bm_cl_in(&portal->addr, BM_CL_##reg##_CENA) ++#define bm_cl_out(reg, val) __bm_cl_out(&portal->addr, BM_CL_##reg##_CENA, val) ++#define bm_cl_invalidate(reg)\ ++ __bm_cl_invalidate(&portal->addr, BM_CL_##reg##_CENA) ++ ++/* Cyclic helper for rings. FIXME: once we are able to do fine-grain perf ++ * analysis, look at using the "extra" bit in the ring index registers to avoid ++ * cyclic issues. */ ++static inline u8 bm_cyc_diff(u8 ringsize, u8 first, u8 last) ++{ ++ /* 'first' is included, 'last' is excluded */ ++ if (first <= last) ++ return last - first; ++ return ringsize + last - first; ++} ++ ++/* Portal modes. ++ * Enum types; ++ * pmode == production mode ++ * cmode == consumption mode, ++ * Enum values use 3 letter codes. First letter matches the portal mode, ++ * remaining two letters indicate; ++ * ci == cache-inhibited portal register ++ * ce == cache-enabled portal register ++ * vb == in-band valid-bit (cache-enabled) ++ */ ++enum bm_rcr_pmode { /* matches BCSP_CFG::RPM */ ++ bm_rcr_pci = 0, /* PI index, cache-inhibited */ ++ bm_rcr_pce = 1, /* PI index, cache-enabled */ ++ bm_rcr_pvb = 2 /* valid-bit */ ++}; ++enum bm_rcr_cmode { /* s/w-only */ ++ bm_rcr_cci, /* CI index, cache-inhibited */ ++ bm_rcr_cce /* CI index, cache-enabled */ ++}; ++ ++ ++/* ------------------------- */ ++/* --- Portal structures --- */ ++ ++#define BM_RCR_SIZE 8 ++ ++struct bm_rcr { ++ struct bm_rcr_entry *ring, *cursor; ++ u8 ci, available, ithresh, vbit; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ u32 busy; ++ enum bm_rcr_pmode pmode; ++ enum bm_rcr_cmode cmode; ++#endif ++}; ++ ++struct bm_mc { ++ struct bm_mc_command *cr; ++ struct bm_mc_result *rr; ++ u8 rridx, vbit; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ enum { ++ /* Can only be _mc_start()ed */ ++ mc_idle, ++ /* Can only be _mc_commit()ed or _mc_abort()ed */ ++ mc_user, ++ /* Can only be _mc_retry()ed */ ++ mc_hw ++ } state; ++#endif ++}; ++ ++struct bm_addr { ++ void __iomem *addr_ce; /* cache-enabled */ ++ void __iomem *addr_ci; /* cache-inhibited */ ++}; ++ ++struct bm_portal { ++ struct bm_addr addr; ++ struct bm_rcr rcr; ++ struct bm_mc mc; ++ struct bm_portal_config config; ++} ____cacheline_aligned; ++ ++ ++/* --------------- */ ++/* --- RCR API --- */ ++ ++/* Bit-wise logic to wrap a ring pointer by clearing the "carry bit" */ ++#define RCR_CARRYCLEAR(p) \ ++ (void *)((unsigned long)(p) & (~(unsigned long)(BM_RCR_SIZE << 6))) ++ ++/* Bit-wise logic to convert a ring pointer to a ring index */ ++static inline u8 RCR_PTR2IDX(struct bm_rcr_entry *e) ++{ ++ return ((uintptr_t)e >> 6) & (BM_RCR_SIZE - 1); ++} ++ ++/* Increment the 'cursor' ring pointer, taking 'vbit' into account */ ++static inline void RCR_INC(struct bm_rcr *rcr) ++{ ++ /* NB: this is odd-looking, but experiments show that it generates ++ * fast code with essentially no branching overheads. We increment to ++ * the next RCR pointer and handle overflow and 'vbit'. */ ++ struct bm_rcr_entry *partial = rcr->cursor + 1; ++ rcr->cursor = RCR_CARRYCLEAR(partial); ++ if (partial != rcr->cursor) ++ rcr->vbit ^= BM_RCR_VERB_VBIT; ++} ++ ++static inline int bm_rcr_init(struct bm_portal *portal, enum bm_rcr_pmode pmode, ++ __maybe_unused enum bm_rcr_cmode cmode) ++{ ++ /* This use of 'register', as well as all other occurrences, is because ++ * it has been observed to generate much faster code with gcc than is ++ * otherwise the case. */ ++ register struct bm_rcr *rcr = &portal->rcr; ++ u32 cfg; ++ u8 pi; ++ ++ rcr->ring = portal->addr.addr_ce + BM_CL_RCR; ++ rcr->ci = bm_in(RCR_CI_CINH) & (BM_RCR_SIZE - 1); ++ ++ pi = bm_in(RCR_PI_CINH) & (BM_RCR_SIZE - 1); ++ rcr->cursor = rcr->ring + pi; ++ rcr->vbit = (bm_in(RCR_PI_CINH) & BM_RCR_SIZE) ? BM_RCR_VERB_VBIT : 0; ++ rcr->available = BM_RCR_SIZE - 1 ++ - bm_cyc_diff(BM_RCR_SIZE, rcr->ci, pi); ++ rcr->ithresh = bm_in(RCR_ITR); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ rcr->busy = 0; ++ rcr->pmode = pmode; ++ rcr->cmode = cmode; ++#endif ++ cfg = (bm_in(CFG) & 0xffffffe0) | (pmode & 0x3); /* BCSP_CFG::RPM */ ++ bm_out(CFG, cfg); ++ return 0; ++} ++ ++static inline void bm_rcr_finish(struct bm_portal *portal) ++{ ++ register struct bm_rcr *rcr = &portal->rcr; ++ u8 pi = bm_in(RCR_PI_CINH) & (BM_RCR_SIZE - 1); ++ u8 ci = bm_in(RCR_CI_CINH) & (BM_RCR_SIZE - 1); ++ DPA_ASSERT(!rcr->busy); ++ if (pi != RCR_PTR2IDX(rcr->cursor)) ++ pr_crit("losing uncommited RCR entries\n"); ++ if (ci != rcr->ci) ++ pr_crit("missing existing RCR completions\n"); ++ if (rcr->ci != RCR_PTR2IDX(rcr->cursor)) ++ pr_crit("RCR destroyed unquiesced\n"); ++} ++ ++static inline struct bm_rcr_entry *bm_rcr_start(struct bm_portal *portal) ++{ ++ register struct bm_rcr *rcr = &portal->rcr; ++ DPA_ASSERT(!rcr->busy); ++ if (!rcr->available) ++ return NULL; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ rcr->busy = 1; ++#endif ++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) ++ dcbz_64(rcr->cursor); ++#endif ++ return rcr->cursor; ++} ++ ++static inline void bm_rcr_abort(struct bm_portal *portal) ++{ ++ __maybe_unused register struct bm_rcr *rcr = &portal->rcr; ++ DPA_ASSERT(rcr->busy); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ rcr->busy = 0; ++#endif ++} ++ ++static inline struct bm_rcr_entry *bm_rcr_pend_and_next( ++ struct bm_portal *portal, u8 myverb) ++{ ++ register struct bm_rcr *rcr = &portal->rcr; ++ DPA_ASSERT(rcr->busy); ++ DPA_ASSERT(rcr->pmode != bm_rcr_pvb); ++ if (rcr->available == 1) ++ return NULL; ++ rcr->cursor->__dont_write_directly__verb = myverb | rcr->vbit; ++ dcbf_64(rcr->cursor); ++ RCR_INC(rcr); ++ rcr->available--; ++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) ++ dcbz_64(rcr->cursor); ++#endif ++ return rcr->cursor; ++} ++ ++static inline void bm_rcr_pci_commit(struct bm_portal *portal, u8 myverb) ++{ ++ register struct bm_rcr *rcr = &portal->rcr; ++ DPA_ASSERT(rcr->busy); ++ DPA_ASSERT(rcr->pmode == bm_rcr_pci); ++ rcr->cursor->__dont_write_directly__verb = myverb | rcr->vbit; ++ RCR_INC(rcr); ++ rcr->available--; ++ hwsync(); ++ bm_out(RCR_PI_CINH, RCR_PTR2IDX(rcr->cursor)); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ rcr->busy = 0; ++#endif ++} ++ ++static inline void bm_rcr_pce_prefetch(struct bm_portal *portal) ++{ ++ __maybe_unused register struct bm_rcr *rcr = &portal->rcr; ++ DPA_ASSERT(rcr->pmode == bm_rcr_pce); ++ bm_cl_invalidate(RCR_PI); ++ bm_cl_touch_rw(RCR_PI); ++} ++ ++static inline void bm_rcr_pce_commit(struct bm_portal *portal, u8 myverb) ++{ ++ register struct bm_rcr *rcr = &portal->rcr; ++ DPA_ASSERT(rcr->busy); ++ DPA_ASSERT(rcr->pmode == bm_rcr_pce); ++ rcr->cursor->__dont_write_directly__verb = myverb | rcr->vbit; ++ RCR_INC(rcr); ++ rcr->available--; ++ lwsync(); ++ bm_cl_out(RCR_PI, RCR_PTR2IDX(rcr->cursor)); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ rcr->busy = 0; ++#endif ++} ++ ++static inline void bm_rcr_pvb_commit(struct bm_portal *portal, u8 myverb) ++{ ++ register struct bm_rcr *rcr = &portal->rcr; ++ struct bm_rcr_entry *rcursor; ++ DPA_ASSERT(rcr->busy); ++ DPA_ASSERT(rcr->pmode == bm_rcr_pvb); ++ lwsync(); ++ rcursor = rcr->cursor; ++ rcursor->__dont_write_directly__verb = myverb | rcr->vbit; ++ dcbf_64(rcursor); ++ RCR_INC(rcr); ++ rcr->available--; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ rcr->busy = 0; ++#endif ++} ++ ++static inline u8 bm_rcr_cci_update(struct bm_portal *portal) ++{ ++ register struct bm_rcr *rcr = &portal->rcr; ++ u8 diff, old_ci = rcr->ci; ++ DPA_ASSERT(rcr->cmode == bm_rcr_cci); ++ rcr->ci = bm_in(RCR_CI_CINH) & (BM_RCR_SIZE - 1); ++ diff = bm_cyc_diff(BM_RCR_SIZE, old_ci, rcr->ci); ++ rcr->available += diff; ++ return diff; ++} ++ ++static inline void bm_rcr_cce_prefetch(struct bm_portal *portal) ++{ ++ __maybe_unused register struct bm_rcr *rcr = &portal->rcr; ++ DPA_ASSERT(rcr->cmode == bm_rcr_cce); ++ bm_cl_touch_ro(RCR_CI); ++} ++ ++static inline u8 bm_rcr_cce_update(struct bm_portal *portal) ++{ ++ register struct bm_rcr *rcr = &portal->rcr; ++ u8 diff, old_ci = rcr->ci; ++ DPA_ASSERT(rcr->cmode == bm_rcr_cce); ++ rcr->ci = bm_cl_in(RCR_CI) & (BM_RCR_SIZE - 1); ++ bm_cl_invalidate(RCR_CI); ++ diff = bm_cyc_diff(BM_RCR_SIZE, old_ci, rcr->ci); ++ rcr->available += diff; ++ return diff; ++} ++ ++static inline u8 bm_rcr_get_ithresh(struct bm_portal *portal) ++{ ++ register struct bm_rcr *rcr = &portal->rcr; ++ return rcr->ithresh; ++} ++ ++static inline void bm_rcr_set_ithresh(struct bm_portal *portal, u8 ithresh) ++{ ++ register struct bm_rcr *rcr = &portal->rcr; ++ rcr->ithresh = ithresh; ++ bm_out(RCR_ITR, ithresh); ++} ++ ++static inline u8 bm_rcr_get_avail(struct bm_portal *portal) ++{ ++ register struct bm_rcr *rcr = &portal->rcr; ++ return rcr->available; ++} ++ ++static inline u8 bm_rcr_get_fill(struct bm_portal *portal) ++{ ++ register struct bm_rcr *rcr = &portal->rcr; ++ return BM_RCR_SIZE - 1 - rcr->available; ++} ++ ++ ++/* ------------------------------ */ ++/* --- Management command API --- */ ++ ++static inline int bm_mc_init(struct bm_portal *portal) ++{ ++ register struct bm_mc *mc = &portal->mc; ++ mc->cr = portal->addr.addr_ce + BM_CL_CR; ++ mc->rr = portal->addr.addr_ce + BM_CL_RR0; ++ mc->rridx = (__raw_readb(&mc->cr->__dont_write_directly__verb) & ++ BM_MCC_VERB_VBIT) ? 0 : 1; ++ mc->vbit = mc->rridx ? BM_MCC_VERB_VBIT : 0; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ mc->state = mc_idle; ++#endif ++ return 0; ++} ++ ++static inline void bm_mc_finish(struct bm_portal *portal) ++{ ++ __maybe_unused register struct bm_mc *mc = &portal->mc; ++ DPA_ASSERT(mc->state == mc_idle); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ if (mc->state != mc_idle) ++ pr_crit("Losing incomplete MC command\n"); ++#endif ++} ++ ++static inline struct bm_mc_command *bm_mc_start(struct bm_portal *portal) ++{ ++ register struct bm_mc *mc = &portal->mc; ++ DPA_ASSERT(mc->state == mc_idle); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ mc->state = mc_user; ++#endif ++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) ++ dcbz_64(mc->cr); ++#endif ++ return mc->cr; ++} ++ ++static inline void bm_mc_abort(struct bm_portal *portal) ++{ ++ __maybe_unused register struct bm_mc *mc = &portal->mc; ++ DPA_ASSERT(mc->state == mc_user); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ mc->state = mc_idle; ++#endif ++} ++ ++static inline void bm_mc_commit(struct bm_portal *portal, u8 myverb) ++{ ++ register struct bm_mc *mc = &portal->mc; ++ struct bm_mc_result *rr = mc->rr + mc->rridx; ++ DPA_ASSERT(mc->state == mc_user); ++ lwsync(); ++ mc->cr->__dont_write_directly__verb = myverb | mc->vbit; ++ dcbf(mc->cr); ++ dcbit_ro(rr); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ mc->state = mc_hw; ++#endif ++} ++ ++static inline struct bm_mc_result *bm_mc_result(struct bm_portal *portal) ++{ ++ register struct bm_mc *mc = &portal->mc; ++ struct bm_mc_result *rr = mc->rr + mc->rridx; ++ DPA_ASSERT(mc->state == mc_hw); ++ /* The inactive response register's verb byte always returns zero until ++ * its command is submitted and completed. This includes the valid-bit, ++ * in case you were wondering... */ ++ if (!__raw_readb(&rr->verb)) { ++ dcbit_ro(rr); ++ return NULL; ++ } ++ mc->rridx ^= 1; ++ mc->vbit ^= BM_MCC_VERB_VBIT; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ mc->state = mc_idle; ++#endif ++ return rr; ++} ++ ++ ++/* ------------------------------------- */ ++/* --- Portal interrupt register API --- */ ++ ++static inline int bm_isr_init(__always_unused struct bm_portal *portal) ++{ ++ return 0; ++} ++ ++static inline void bm_isr_finish(__always_unused struct bm_portal *portal) ++{ ++} ++ ++#define SCN_REG(bpid) BM_REG_SCN((bpid) / 32) ++#define SCN_BIT(bpid) (0x80000000 >> (bpid & 31)) ++static inline void bm_isr_bscn_mask(struct bm_portal *portal, u8 bpid, ++ int enable) ++{ ++ u32 val; ++ DPA_ASSERT(bpid < bman_pool_max); ++ /* REG_SCN for bpid=0..31, REG_SCN+4 for bpid=32..63 */ ++ val = __bm_in(&portal->addr, SCN_REG(bpid)); ++ if (enable) ++ val |= SCN_BIT(bpid); ++ else ++ val &= ~SCN_BIT(bpid); ++ __bm_out(&portal->addr, SCN_REG(bpid), val); ++} ++ ++static inline u32 __bm_isr_read(struct bm_portal *portal, enum bm_isr_reg n) ++{ ++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) ++ return __bm_in(&portal->addr, BM_REG_ISR + (n << 6)); ++#else ++ return __bm_in(&portal->addr, BM_REG_ISR + (n << 2)); ++#endif ++} ++ ++static inline void __bm_isr_write(struct bm_portal *portal, enum bm_isr_reg n, ++ u32 val) ++{ ++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) ++ __bm_out(&portal->addr, BM_REG_ISR + (n << 6), val); ++#else ++ __bm_out(&portal->addr, BM_REG_ISR + (n << 2), val); ++#endif ++} ++ ++/* Buffer Pool Cleanup */ ++static inline int bm_shutdown_pool(struct bm_portal *p, u32 bpid) ++{ ++ struct bm_mc_command *bm_cmd; ++ struct bm_mc_result *bm_res; ++ ++ int aq_count = 0; ++ bool stop = false; ++ while (!stop) { ++ /* Acquire buffers until empty */ ++ bm_cmd = bm_mc_start(p); ++ bm_cmd->acquire.bpid = bpid; ++ bm_mc_commit(p, BM_MCC_VERB_CMD_ACQUIRE | 1); ++ while (!(bm_res = bm_mc_result(p))) ++ cpu_relax(); ++ if (!(bm_res->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT)) { ++ /* Pool is empty */ ++ /* TBD : Should we do a few extra iterations in ++ case some other some blocks keep buffers 'on deck', ++ which may also be problematic */ ++ stop = true; ++ } else ++ ++aq_count; ++ } ++ return 0; ++} +diff --git a/drivers/staging/fsl_qbman/bman_private.h b/drivers/staging/fsl_qbman/bman_private.h +new file mode 100644 +index 00000000..64eefe7d +--- /dev/null ++++ b/drivers/staging/fsl_qbman/bman_private.h +@@ -0,0 +1,166 @@ ++/* Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "dpa_sys.h" ++#include ++ ++/* Revision info (for errata and feature handling) */ ++#define BMAN_REV10 0x0100 ++#define BMAN_REV20 0x0200 ++#define BMAN_REV21 0x0201 ++#define QBMAN_ANY_PORTAL_IDX 0xffffffff ++extern u16 bman_ip_rev; /* 0 if uninitialised, otherwise QMAN_REVx */ ++ ++/* ++ * Global variables of the max portal/pool number this bman version supported ++ */ ++extern u16 bman_pool_max; ++ ++/* used by CCSR and portal interrupt code */ ++enum bm_isr_reg { ++ bm_isr_status = 0, ++ bm_isr_enable = 1, ++ bm_isr_disable = 2, ++ bm_isr_inhibit = 3 ++}; ++ ++struct bm_portal_config { ++ /* Corenet portal addresses; ++ * [0]==cache-enabled, [1]==cache-inhibited. */ ++ __iomem void *addr_virt[2]; ++ struct resource addr_phys[2]; ++ /* Allow these to be joined in lists */ ++ struct list_head list; ++ /* User-visible portal configuration settings */ ++ struct bman_portal_config public_cfg; ++ /* power management saved data */ ++ u32 saved_isdr; ++}; ++ ++#ifdef CONFIG_FSL_BMAN_CONFIG ++/* Hooks from bman_driver.c to bman_config.c */ ++int bman_init_ccsr(struct device_node *node); ++#endif ++ ++/* Hooks from bman_driver.c in to bman_high.c */ ++struct bman_portal *bman_create_portal( ++ struct bman_portal *portal, ++ const struct bm_portal_config *config); ++struct bman_portal *bman_create_affine_portal( ++ const struct bm_portal_config *config); ++struct bman_portal *bman_create_affine_slave(struct bman_portal *redirect, ++ int cpu); ++void bman_destroy_portal(struct bman_portal *bm); ++ ++const struct bm_portal_config *bman_destroy_affine_portal(void); ++ ++/* Hooks from fsl_usdpaa.c to bman_driver.c */ ++struct bm_portal_config *bm_get_unused_portal(void); ++struct bm_portal_config *bm_get_unused_portal_idx(uint32_t idx); ++void bm_put_unused_portal(struct bm_portal_config *pcfg); ++void bm_set_liodns(struct bm_portal_config *pcfg); ++ ++/* Pool logic in the portal driver, during initialisation, needs to know if ++ * there's access to CCSR or not (if not, it'll cripple the pool allocator). */ ++#ifdef CONFIG_FSL_BMAN_CONFIG ++int bman_have_ccsr(void); ++#else ++#define bman_have_ccsr() 0 ++#endif ++ ++/* Stockpile build constants. The _LOW value: when bman_acquire() is called and ++ * the stockpile fill-level is <= _LOW, an acquire is attempted from h/w but it ++ * might fail (if the buffer pool is depleted). So this value provides some ++ * "stagger" in that the bman_acquire() function will only fail if lots of bufs ++ * are requested at once or if h/w has been tested a couple of times without ++ * luck. The _HIGH value: when bman_release() is called and the stockpile ++ * fill-level is >= _HIGH, a release is attempted to h/w but it might fail (if ++ * the release ring is full). So this value provides some "stagger" so that ++ * ring-access is retried a couple of times prior to the API returning a ++ * failure. The following *must* be true; ++ * BMAN_STOCKPILE_HIGH-BMAN_STOCKPILE_LOW > 8 ++ * (to avoid thrashing) ++ * BMAN_STOCKPILE_SZ >= 16 ++ * (as the release logic expects to either send 8 buffers to hw prior to ++ * adding the given buffers to the stockpile or add the buffers to the ++ * stockpile before sending 8 to hw, as the API must be an all-or-nothing ++ * success/fail.) ++ */ ++#define BMAN_STOCKPILE_SZ 16u /* number of bufs in per-pool cache */ ++#define BMAN_STOCKPILE_LOW 2u /* when fill is <= this, acquire from hw */ ++#define BMAN_STOCKPILE_HIGH 14u /* when fill is >= this, release to hw */ ++ ++/*************************************************/ ++/* BMan s/w corenet portal, low-level i/face */ ++/*************************************************/ ++ ++/* Used by all portal interrupt registers except 'inhibit' ++ * This mask contains all the "irqsource" bits visible to API users ++ */ ++#define BM_PIRQ_VISIBLE (BM_PIRQ_RCRI | BM_PIRQ_BSCN) ++ ++/* These are bm__(). So for example, bm_disable_write() means "write ++ * the disable register" rather than "disable the ability to write". */ ++#define bm_isr_status_read(bm) __bm_isr_read(bm, bm_isr_status) ++#define bm_isr_status_clear(bm, m) __bm_isr_write(bm, bm_isr_status, m) ++#define bm_isr_enable_read(bm) __bm_isr_read(bm, bm_isr_enable) ++#define bm_isr_enable_write(bm, v) __bm_isr_write(bm, bm_isr_enable, v) ++#define bm_isr_disable_read(bm) __bm_isr_read(bm, bm_isr_disable) ++#define bm_isr_disable_write(bm, v) __bm_isr_write(bm, bm_isr_disable, v) ++#define bm_isr_inhibit(bm) __bm_isr_write(bm, bm_isr_inhibit, 1) ++#define bm_isr_uninhibit(bm) __bm_isr_write(bm, bm_isr_inhibit, 0) ++ ++#ifdef CONFIG_FSL_BMAN_CONFIG ++/* Set depletion thresholds associated with a buffer pool. Requires that the ++ * operating system have access to Bman CCSR (ie. compiled in support and ++ * run-time access courtesy of the device-tree). */ ++int bm_pool_set(u32 bpid, const u32 *thresholds); ++#define BM_POOL_THRESH_SW_ENTER 0 ++#define BM_POOL_THRESH_SW_EXIT 1 ++#define BM_POOL_THRESH_HW_ENTER 2 ++#define BM_POOL_THRESH_HW_EXIT 3 ++ ++/* Read the free buffer count for a given buffer */ ++u32 bm_pool_free_buffers(u32 bpid); ++ ++__init int bman_init(void); ++__init int bman_resource_init(void); ++ ++const struct bm_portal_config *bman_get_bm_portal_config( ++ struct bman_portal *portal); ++ ++/* power management */ ++#ifdef CONFIG_SUSPEND ++void suspend_unused_bportal(void); ++void resume_unused_bportal(void); ++#endif ++ ++#endif /* CONFIG_FSL_BMAN_CONFIG */ +diff --git a/drivers/staging/fsl_qbman/bman_test.c b/drivers/staging/fsl_qbman/bman_test.c +new file mode 100644 +index 00000000..db5b7fd3 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/bman_test.c +@@ -0,0 +1,56 @@ ++/* Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "bman_test.h" ++ ++MODULE_AUTHOR("Geoff Thorpe"); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_DESCRIPTION("Bman testing"); ++ ++static int test_init(void) ++{ ++#ifdef CONFIG_FSL_BMAN_TEST_HIGH ++ int loop = 1; ++ while (loop--) ++ bman_test_high(); ++#endif ++#ifdef CONFIG_FSL_BMAN_TEST_THRESH ++ bman_test_thresh(); ++#endif ++ return 0; ++} ++ ++static void test_exit(void) ++{ ++} ++ ++module_init(test_init); ++module_exit(test_exit); +diff --git a/drivers/staging/fsl_qbman/bman_test.h b/drivers/staging/fsl_qbman/bman_test.h +new file mode 100644 +index 00000000..fcd65056 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/bman_test.h +@@ -0,0 +1,44 @@ ++/* Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++void bman_test_high(void); ++void bman_test_thresh(void); +diff --git a/drivers/staging/fsl_qbman/bman_test_high.c b/drivers/staging/fsl_qbman/bman_test_high.c +new file mode 100644 +index 00000000..1617a531 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/bman_test_high.c +@@ -0,0 +1,183 @@ ++/* Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "bman_test.h" ++#include "bman_private.h" ++ ++/*************/ ++/* constants */ ++/*************/ ++ ++#define PORTAL_OPAQUE ((void *)0xf00dbeef) ++#define POOL_OPAQUE ((void *)0xdeadabba) ++#define NUM_BUFS 93 ++#define LOOPS 3 ++#define BMAN_TOKEN_MASK 0x00FFFFFFFFFFLLU ++ ++/***************/ ++/* global vars */ ++/***************/ ++ ++static struct bman_pool *pool; ++static int depleted; ++static struct bm_buffer bufs_in[NUM_BUFS] ____cacheline_aligned; ++static struct bm_buffer bufs_out[NUM_BUFS] ____cacheline_aligned; ++static int bufs_received; ++ ++/* Predeclare the callback so we can instantiate pool parameters */ ++static void depletion_cb(struct bman_portal *, struct bman_pool *, void *, int); ++ ++/**********************/ ++/* internal functions */ ++/**********************/ ++ ++static void bufs_init(void) ++{ ++ int i; ++ for (i = 0; i < NUM_BUFS; i++) ++ bm_buffer_set64(&bufs_in[i], 0xfedc01234567LLU * i); ++ bufs_received = 0; ++} ++ ++static inline int bufs_cmp(const struct bm_buffer *a, const struct bm_buffer *b) ++{ ++ if ((bman_ip_rev == BMAN_REV20) || (bman_ip_rev == BMAN_REV21)) { ++ ++ /* On SoCs with Bman revison 2.0, Bman only respects the 40 ++ * LS-bits of buffer addresses, masking off the upper 8-bits on ++ * release commands. The API provides for 48-bit addresses ++ * because some SoCs support all 48-bits. When generating ++ * garbage addresses for testing, we either need to zero the ++ * upper 8-bits when releasing to Bman (otherwise we'll be ++ * disappointed when the buffers we acquire back from Bman ++ * don't match), or we need to mask the upper 8-bits off when ++ * comparing. We do the latter. ++ */ ++ if ((bm_buffer_get64(a) & BMAN_TOKEN_MASK) ++ < (bm_buffer_get64(b) & BMAN_TOKEN_MASK)) ++ return -1; ++ if ((bm_buffer_get64(a) & BMAN_TOKEN_MASK) ++ > (bm_buffer_get64(b) & BMAN_TOKEN_MASK)) ++ return 1; ++ } else { ++ if (bm_buffer_get64(a) < bm_buffer_get64(b)) ++ return -1; ++ if (bm_buffer_get64(a) > bm_buffer_get64(b)) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static void bufs_confirm(void) ++{ ++ int i, j; ++ for (i = 0; i < NUM_BUFS; i++) { ++ int matches = 0; ++ for (j = 0; j < NUM_BUFS; j++) ++ if (!bufs_cmp(&bufs_in[i], &bufs_out[j])) ++ matches++; ++ BUG_ON(matches != 1); ++ } ++} ++ ++/********/ ++/* test */ ++/********/ ++ ++static void depletion_cb(struct bman_portal *__portal, struct bman_pool *__pool, ++ void *pool_ctx, int __depleted) ++{ ++ BUG_ON(__pool != pool); ++ BUG_ON(pool_ctx != POOL_OPAQUE); ++ depleted = __depleted; ++} ++ ++void bman_test_high(void) ++{ ++ struct bman_pool_params pparams = { ++ .flags = BMAN_POOL_FLAG_DEPLETION | BMAN_POOL_FLAG_DYNAMIC_BPID, ++ .cb = depletion_cb, ++ .cb_ctx = POOL_OPAQUE, ++ }; ++ int i, loops = LOOPS; ++ struct bm_buffer tmp_buf; ++ ++ bufs_init(); ++ ++ pr_info("BMAN: --- starting high-level test ---\n"); ++ ++ pool = bman_new_pool(&pparams); ++ BUG_ON(!pool); ++ ++ /*******************/ ++ /* Release buffers */ ++ /*******************/ ++do_loop: ++ i = 0; ++ while (i < NUM_BUFS) { ++ u32 flags = BMAN_RELEASE_FLAG_WAIT; ++ int num = 8; ++ if ((i + num) > NUM_BUFS) ++ num = NUM_BUFS - i; ++ if ((i + num) == NUM_BUFS) ++ flags |= BMAN_RELEASE_FLAG_WAIT_SYNC; ++ if (bman_release(pool, bufs_in + i, num, flags)) ++ panic("bman_release() failed\n"); ++ i += num; ++ } ++ ++ /*******************/ ++ /* Acquire buffers */ ++ /*******************/ ++ while (i > 0) { ++ int tmp, num = 8; ++ if (num > i) ++ num = i; ++ tmp = bman_acquire(pool, bufs_out + i - num, num, 0); ++ BUG_ON(tmp != num); ++ i -= num; ++ } ++ ++ i = bman_acquire(pool, &tmp_buf, 1, 0); ++ BUG_ON(i > 0); ++ ++ bufs_confirm(); ++ ++ if (--loops) ++ goto do_loop; ++ ++ /************/ ++ /* Clean up */ ++ /************/ ++ bman_free_pool(pool); ++ pr_info("BMAN: --- finished high-level test ---\n"); ++} +diff --git a/drivers/staging/fsl_qbman/bman_test_thresh.c b/drivers/staging/fsl_qbman/bman_test_thresh.c +new file mode 100644 +index 00000000..67093693 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/bman_test_thresh.c +@@ -0,0 +1,196 @@ ++/* Copyright 2010-2011 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "bman_test.h" ++ ++/* Test constants */ ++#define TEST_NUMBUFS 129728 ++#define TEST_EXIT 129536 ++#define TEST_ENTRY 129024 ++ ++struct affine_test_data { ++ struct task_struct *t; ++ int cpu; ++ int expect_affinity; ++ int drain; ++ int num_enter; ++ int num_exit; ++ struct list_head node; ++ struct completion wakethread; ++ struct completion wakeparent; ++}; ++ ++static void cb_depletion(struct bman_portal *portal, ++ struct bman_pool *pool, ++ void *opaque, ++ int depleted) ++{ ++ struct affine_test_data *data = opaque; ++ int c = smp_processor_id(); ++ pr_info("cb_depletion: bpid=%d, depleted=%d, cpu=%d, original=%d\n", ++ bman_get_params(pool)->bpid, !!depleted, c, data->cpu); ++ /* We should be executing on the CPU of the thread that owns the pool if ++ * and that CPU has an affine portal (ie. it isn't slaved). */ ++ BUG_ON((c != data->cpu) && data->expect_affinity); ++ BUG_ON((c == data->cpu) && !data->expect_affinity); ++ if (depleted) ++ data->num_enter++; ++ else ++ data->num_exit++; ++} ++ ++/* Params used to set up a pool, this also dynamically allocates a BPID */ ++static const struct bman_pool_params params_nocb = { ++ .flags = BMAN_POOL_FLAG_DYNAMIC_BPID | BMAN_POOL_FLAG_THRESH, ++ .thresholds = { TEST_ENTRY, TEST_EXIT, 0, 0 } ++}; ++ ++/* Params used to set up each cpu's pool with callbacks enabled */ ++static struct bman_pool_params params_cb = { ++ .bpid = 0, /* will be replaced to match pool_nocb */ ++ .flags = BMAN_POOL_FLAG_DEPLETION, ++ .cb = cb_depletion ++}; ++ ++static struct bman_pool *pool_nocb; ++static LIST_HEAD(threads); ++ ++static int affine_test(void *__data) ++{ ++ struct bman_pool *pool; ++ struct affine_test_data *data = __data; ++ struct bman_pool_params my_params = params_cb; ++ ++ pr_info("thread %d: starting\n", data->cpu); ++ /* create the pool */ ++ my_params.cb_ctx = data; ++ pool = bman_new_pool(&my_params); ++ BUG_ON(!pool); ++ complete(&data->wakeparent); ++ wait_for_completion(&data->wakethread); ++ init_completion(&data->wakethread); ++ ++ /* if we're the drainer, we get signalled for that */ ++ if (data->drain) { ++ struct bm_buffer buf; ++ int ret; ++ pr_info("thread %d: draining...\n", data->cpu); ++ do { ++ ret = bman_acquire(pool, &buf, 1, 0); ++ } while (ret > 0); ++ pr_info("thread %d: draining done.\n", data->cpu); ++ complete(&data->wakeparent); ++ wait_for_completion(&data->wakethread); ++ init_completion(&data->wakethread); ++ } ++ ++ /* cleanup */ ++ bman_free_pool(pool); ++ while (!kthread_should_stop()) ++ cpu_relax(); ++ pr_info("thread %d: exiting\n", data->cpu); ++ return 0; ++} ++ ++static struct affine_test_data *start_affine_test(int cpu, int drain) ++{ ++ struct affine_test_data *data = kmalloc(sizeof(*data), GFP_KERNEL); ++ ++ if (!data) ++ return NULL; ++ data->cpu = cpu; ++ data->expect_affinity = cpumask_test_cpu(cpu, bman_affine_cpus()); ++ data->drain = drain; ++ data->num_enter = 0; ++ data->num_exit = 0; ++ init_completion(&data->wakethread); ++ init_completion(&data->wakeparent); ++ list_add_tail(&data->node, &threads); ++ data->t = kthread_create(affine_test, data, "threshtest%d", cpu); ++ BUG_ON(IS_ERR(data->t)); ++ kthread_bind(data->t, cpu); ++ wake_up_process(data->t); ++ return data; ++} ++ ++void bman_test_thresh(void) ++{ ++ int loop = TEST_NUMBUFS; ++ int ret, num_cpus = 0; ++ struct affine_test_data *data, *drainer = NULL; ++ ++ pr_info("bman_test_thresh: start\n"); ++ ++ /* allocate a BPID and seed it */ ++ pool_nocb = bman_new_pool(¶ms_nocb); ++ BUG_ON(!pool_nocb); ++ while (loop--) { ++ struct bm_buffer buf; ++ bm_buffer_set64(&buf, 0x0badbeef + loop); ++ ret = bman_release(pool_nocb, &buf, 1, ++ BMAN_RELEASE_FLAG_WAIT); ++ BUG_ON(ret); ++ } ++ while (!bman_rcr_is_empty()) ++ cpu_relax(); ++ pr_info("bman_test_thresh: buffers are in\n"); ++ ++ /* create threads and wait for them to create pools */ ++ params_cb.bpid = bman_get_params(pool_nocb)->bpid; ++ for_each_cpu(loop, cpu_online_mask) { ++ data = start_affine_test(loop, drainer ? 0 : 1); ++ BUG_ON(!data); ++ if (!drainer) ++ drainer = data; ++ num_cpus++; ++ wait_for_completion(&data->wakeparent); ++ } ++ ++ /* signal the drainer to start draining */ ++ complete(&drainer->wakethread); ++ wait_for_completion(&drainer->wakeparent); ++ init_completion(&drainer->wakeparent); ++ ++ /* tear down */ ++ list_for_each_entry_safe(data, drainer, &threads, node) { ++ complete(&data->wakethread); ++ ret = kthread_stop(data->t); ++ BUG_ON(ret); ++ list_del(&data->node); ++ /* check that we get the expected callbacks (and no others) */ ++ BUG_ON(data->num_enter != 1); ++ BUG_ON(data->num_exit != 0); ++ kfree(data); ++ } ++ bman_free_pool(pool_nocb); ++ ++ pr_info("bman_test_thresh: done\n"); ++} +diff --git a/drivers/staging/fsl_qbman/dpa_alloc.c b/drivers/staging/fsl_qbman/dpa_alloc.c +new file mode 100644 +index 00000000..44db3e1e +--- /dev/null ++++ b/drivers/staging/fsl_qbman/dpa_alloc.c +@@ -0,0 +1,706 @@ ++/* Copyright 2009-2012 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "dpa_sys.h" ++#include ++#include ++ ++/* Qman and Bman APIs are front-ends to the common code; */ ++ ++static DECLARE_DPA_ALLOC(bpalloc); /* BPID allocator */ ++static DECLARE_DPA_ALLOC(fqalloc); /* FQID allocator */ ++static DECLARE_DPA_ALLOC(qpalloc); /* pool-channel allocator */ ++static DECLARE_DPA_ALLOC(cgralloc); /* CGR ID allocator */ ++static DECLARE_DPA_ALLOC(ceetm0_challoc); /* CEETM Channel ID allocator */ ++static DECLARE_DPA_ALLOC(ceetm0_lfqidalloc); /* CEETM LFQID allocator */ ++static DECLARE_DPA_ALLOC(ceetm1_challoc); /* CEETM Channel ID allocator */ ++static DECLARE_DPA_ALLOC(ceetm1_lfqidalloc); /* CEETM LFQID allocator */ ++ ++/* This is a sort-of-conditional dpa_alloc_free() routine. Eg. when releasing ++ * FQIDs (probably from user-space), it can filter out those that aren't in the ++ * OOS state (better to leak a h/w resource than to crash). This function ++ * returns the number of invalid IDs that were not released. */ ++static u32 release_id_range(struct dpa_alloc *alloc, u32 id, u32 count, ++ int (*is_valid)(u32 id)) ++{ ++ int valid_mode = 0; ++ u32 loop = id, total_invalid = 0; ++ while (loop < (id + count)) { ++ int isvalid = is_valid ? is_valid(loop) : 1; ++ if (!valid_mode) { ++ /* We're looking for a valid ID to terminate an invalid ++ * range */ ++ if (isvalid) { ++ /* We finished a range of invalid IDs, a valid ++ * range is now underway */ ++ valid_mode = 1; ++ count -= (loop - id); ++ id = loop; ++ } else ++ total_invalid++; ++ } else { ++ /* We're looking for an invalid ID to terminate a ++ * valid range */ ++ if (!isvalid) { ++ /* Release the range of valid IDs, an unvalid ++ * range is now underway */ ++ if (loop > id) ++ dpa_alloc_free(alloc, id, loop - id); ++ valid_mode = 0; ++ } ++ } ++ loop++; ++ } ++ /* Release any unterminated range of valid IDs */ ++ if (valid_mode && count) ++ dpa_alloc_free(alloc, id, count); ++ return total_invalid; ++} ++ ++/* BPID allocator front-end */ ++ ++int bman_alloc_bpid_range(u32 *result, u32 count, u32 align, int partial) ++{ ++ return dpa_alloc_new(&bpalloc, result, count, align, partial); ++} ++EXPORT_SYMBOL(bman_alloc_bpid_range); ++ ++static int bp_cleanup(u32 bpid) ++{ ++ return bman_shutdown_pool(bpid) == 0; ++} ++void bman_release_bpid_range(u32 bpid, u32 count) ++{ ++ u32 total_invalid = release_id_range(&bpalloc, bpid, count, bp_cleanup); ++ if (total_invalid) ++ pr_err("BPID range [%d..%d] (%d) had %d leaks\n", ++ bpid, bpid + count - 1, count, total_invalid); ++} ++EXPORT_SYMBOL(bman_release_bpid_range); ++ ++void bman_seed_bpid_range(u32 bpid, u32 count) ++{ ++ dpa_alloc_seed(&bpalloc, bpid, count); ++} ++EXPORT_SYMBOL(bman_seed_bpid_range); ++ ++int bman_reserve_bpid_range(u32 bpid, u32 count) ++{ ++ return dpa_alloc_reserve(&bpalloc, bpid, count); ++} ++EXPORT_SYMBOL(bman_reserve_bpid_range); ++ ++ ++/* FQID allocator front-end */ ++ ++int qman_alloc_fqid_range(u32 *result, u32 count, u32 align, int partial) ++{ ++ return dpa_alloc_new(&fqalloc, result, count, align, partial); ++} ++EXPORT_SYMBOL(qman_alloc_fqid_range); ++ ++static int fq_cleanup(u32 fqid) ++{ ++ return qman_shutdown_fq(fqid) == 0; ++} ++void qman_release_fqid_range(u32 fqid, u32 count) ++{ ++ u32 total_invalid = release_id_range(&fqalloc, fqid, count, fq_cleanup); ++ if (total_invalid) ++ pr_err("FQID range [%d..%d] (%d) had %d leaks\n", ++ fqid, fqid + count - 1, count, total_invalid); ++} ++EXPORT_SYMBOL(qman_release_fqid_range); ++ ++int qman_reserve_fqid_range(u32 fqid, u32 count) ++{ ++ return dpa_alloc_reserve(&fqalloc, fqid, count); ++} ++EXPORT_SYMBOL(qman_reserve_fqid_range); ++ ++void qman_seed_fqid_range(u32 fqid, u32 count) ++{ ++ dpa_alloc_seed(&fqalloc, fqid, count); ++} ++EXPORT_SYMBOL(qman_seed_fqid_range); ++ ++/* Pool-channel allocator front-end */ ++ ++int qman_alloc_pool_range(u32 *result, u32 count, u32 align, int partial) ++{ ++ return dpa_alloc_new(&qpalloc, result, count, align, partial); ++} ++EXPORT_SYMBOL(qman_alloc_pool_range); ++ ++static int qpool_cleanup(u32 qp) ++{ ++ /* We query all FQDs starting from ++ * FQID 1 until we get an "invalid FQID" error, looking for non-OOS FQDs ++ * whose destination channel is the pool-channel being released. ++ * When a non-OOS FQD is found we attempt to clean it up */ ++ struct qman_fq fq = { ++ .fqid = 1 ++ }; ++ int err; ++ do { ++ struct qm_mcr_queryfq_np np; ++ err = qman_query_fq_np(&fq, &np); ++ if (err) ++ /* FQID range exceeded, found no problems */ ++ return 1; ++ if ((np.state & QM_MCR_NP_STATE_MASK) != QM_MCR_NP_STATE_OOS) { ++ struct qm_fqd fqd; ++ err = qman_query_fq(&fq, &fqd); ++ BUG_ON(err); ++ if (fqd.dest.channel == qp) { ++ /* The channel is the FQ's target, clean it */ ++ if (qman_shutdown_fq(fq.fqid) != 0) ++ /* Couldn't shut down the FQ ++ so the pool must be leaked */ ++ return 0; ++ } ++ } ++ /* Move to the next FQID */ ++ fq.fqid++; ++ } while (1); ++} ++void qman_release_pool_range(u32 qp, u32 count) ++{ ++ u32 total_invalid = release_id_range(&qpalloc, qp, ++ count, qpool_cleanup); ++ if (total_invalid) { ++ /* Pool channels are almost always used individually */ ++ if (count == 1) ++ pr_err("Pool channel 0x%x had %d leaks\n", ++ qp, total_invalid); ++ else ++ pr_err("Pool channels [%d..%d] (%d) had %d leaks\n", ++ qp, qp + count - 1, count, total_invalid); ++ } ++} ++EXPORT_SYMBOL(qman_release_pool_range); ++ ++ ++void qman_seed_pool_range(u32 poolid, u32 count) ++{ ++ dpa_alloc_seed(&qpalloc, poolid, count); ++ ++} ++EXPORT_SYMBOL(qman_seed_pool_range); ++ ++int qman_reserve_pool_range(u32 poolid, u32 count) ++{ ++ return dpa_alloc_reserve(&qpalloc, poolid, count); ++} ++EXPORT_SYMBOL(qman_reserve_pool_range); ++ ++ ++/* CGR ID allocator front-end */ ++ ++int qman_alloc_cgrid_range(u32 *result, u32 count, u32 align, int partial) ++{ ++ return dpa_alloc_new(&cgralloc, result, count, align, partial); ++} ++EXPORT_SYMBOL(qman_alloc_cgrid_range); ++ ++static int cqr_cleanup(u32 cgrid) ++{ ++ /* We query all FQDs starting from ++ * FQID 1 until we get an "invalid FQID" error, looking for non-OOS FQDs ++ * whose CGR is the CGR being released. ++ */ ++ struct qman_fq fq = { ++ .fqid = 1 ++ }; ++ int err; ++ do { ++ struct qm_mcr_queryfq_np np; ++ err = qman_query_fq_np(&fq, &np); ++ if (err) ++ /* FQID range exceeded, found no problems */ ++ return 1; ++ if ((np.state & QM_MCR_NP_STATE_MASK) != QM_MCR_NP_STATE_OOS) { ++ struct qm_fqd fqd; ++ err = qman_query_fq(&fq, &fqd); ++ BUG_ON(err); ++ if ((fqd.fq_ctrl & QM_FQCTRL_CGE) && ++ (fqd.cgid == cgrid)) { ++ pr_err("CRGID 0x%x is being used by FQID 0x%x," ++ " CGR will be leaked\n", ++ cgrid, fq.fqid); ++ return 1; ++ } ++ } ++ /* Move to the next FQID */ ++ fq.fqid++; ++ } while (1); ++} ++ ++void qman_release_cgrid_range(u32 cgrid, u32 count) ++{ ++ u32 total_invalid = release_id_range(&cgralloc, cgrid, ++ count, cqr_cleanup); ++ if (total_invalid) ++ pr_err("CGRID range [%d..%d] (%d) had %d leaks\n", ++ cgrid, cgrid + count - 1, count, total_invalid); ++} ++EXPORT_SYMBOL(qman_release_cgrid_range); ++ ++void qman_seed_cgrid_range(u32 cgrid, u32 count) ++{ ++ dpa_alloc_seed(&cgralloc, cgrid, count); ++ ++} ++EXPORT_SYMBOL(qman_seed_cgrid_range); ++ ++/* CEETM CHANNEL ID allocator front-end */ ++int qman_alloc_ceetm0_channel_range(u32 *result, u32 count, u32 align, ++ int partial) ++{ ++ return dpa_alloc_new(&ceetm0_challoc, result, count, align, partial); ++} ++EXPORT_SYMBOL(qman_alloc_ceetm0_channel_range); ++ ++int qman_alloc_ceetm1_channel_range(u32 *result, u32 count, u32 align, ++ int partial) ++{ ++ return dpa_alloc_new(&ceetm1_challoc, result, count, align, partial); ++} ++EXPORT_SYMBOL(qman_alloc_ceetm1_channel_range); ++ ++void qman_release_ceetm0_channel_range(u32 channelid, u32 count) ++{ ++ u32 total_invalid; ++ ++ total_invalid = release_id_range(&ceetm0_challoc, channelid, count, ++ NULL); ++ if (total_invalid) ++ pr_err("CEETM channel range [%d..%d] (%d) had %d leaks\n", ++ channelid, channelid + count - 1, count, total_invalid); ++} ++EXPORT_SYMBOL(qman_release_ceetm0_channel_range); ++ ++void qman_seed_ceetm0_channel_range(u32 channelid, u32 count) ++{ ++ dpa_alloc_seed(&ceetm0_challoc, channelid, count); ++ ++} ++EXPORT_SYMBOL(qman_seed_ceetm0_channel_range); ++ ++void qman_release_ceetm1_channel_range(u32 channelid, u32 count) ++{ ++ u32 total_invalid; ++ total_invalid = release_id_range(&ceetm1_challoc, channelid, count, ++ NULL); ++ if (total_invalid) ++ pr_err("CEETM channel range [%d..%d] (%d) had %d leaks\n", ++ channelid, channelid + count - 1, count, total_invalid); ++} ++EXPORT_SYMBOL(qman_release_ceetm1_channel_range); ++ ++void qman_seed_ceetm1_channel_range(u32 channelid, u32 count) ++{ ++ dpa_alloc_seed(&ceetm1_challoc, channelid, count); ++ ++} ++EXPORT_SYMBOL(qman_seed_ceetm1_channel_range); ++ ++/* CEETM LFQID allocator front-end */ ++int qman_alloc_ceetm0_lfqid_range(u32 *result, u32 count, u32 align, ++ int partial) ++{ ++ return dpa_alloc_new(&ceetm0_lfqidalloc, result, count, align, partial); ++} ++EXPORT_SYMBOL(qman_alloc_ceetm0_lfqid_range); ++ ++int qman_alloc_ceetm1_lfqid_range(u32 *result, u32 count, u32 align, ++ int partial) ++{ ++ return dpa_alloc_new(&ceetm1_lfqidalloc, result, count, align, partial); ++} ++EXPORT_SYMBOL(qman_alloc_ceetm1_lfqid_range); ++ ++void qman_release_ceetm0_lfqid_range(u32 lfqid, u32 count) ++{ ++ u32 total_invalid; ++ ++ total_invalid = release_id_range(&ceetm0_lfqidalloc, lfqid, count, ++ NULL); ++ if (total_invalid) ++ pr_err("CEETM LFQID range [0x%x..0x%x] (%d) had %d leaks\n", ++ lfqid, lfqid + count - 1, count, total_invalid); ++} ++EXPORT_SYMBOL(qman_release_ceetm0_lfqid_range); ++ ++void qman_seed_ceetm0_lfqid_range(u32 lfqid, u32 count) ++{ ++ dpa_alloc_seed(&ceetm0_lfqidalloc, lfqid, count); ++ ++} ++EXPORT_SYMBOL(qman_seed_ceetm0_lfqid_range); ++ ++void qman_release_ceetm1_lfqid_range(u32 lfqid, u32 count) ++{ ++ u32 total_invalid; ++ ++ total_invalid = release_id_range(&ceetm1_lfqidalloc, lfqid, count, ++ NULL); ++ if (total_invalid) ++ pr_err("CEETM LFQID range [0x%x..0x%x] (%d) had %d leaks\n", ++ lfqid, lfqid + count - 1, count, total_invalid); ++} ++EXPORT_SYMBOL(qman_release_ceetm1_lfqid_range); ++ ++void qman_seed_ceetm1_lfqid_range(u32 lfqid, u32 count) ++{ ++ dpa_alloc_seed(&ceetm1_lfqidalloc, lfqid, count); ++ ++} ++EXPORT_SYMBOL(qman_seed_ceetm1_lfqid_range); ++ ++ ++/* Everything else is the common backend to all the allocators */ ++ ++/* The allocator is a (possibly-empty) list of these; */ ++struct alloc_node { ++ struct list_head list; ++ u32 base; ++ u32 num; ++ /* refcount and is_alloced are only set ++ when the node is in the used list */ ++ unsigned int refcount; ++ int is_alloced; ++}; ++ ++/* #define DPA_ALLOC_DEBUG */ ++ ++#ifdef DPA_ALLOC_DEBUG ++#define DPRINT pr_info ++static void DUMP(struct dpa_alloc *alloc) ++{ ++ int off = 0; ++ char buf[256]; ++ struct alloc_node *p; ++ pr_info("Free Nodes\n"); ++ list_for_each_entry(p, &alloc->free, list) { ++ if (off < 255) ++ off += snprintf(buf + off, 255-off, "{%d,%d}", ++ p->base, p->base + p->num - 1); ++ } ++ pr_info("%s\n", buf); ++ ++ off = 0; ++ pr_info("Used Nodes\n"); ++ list_for_each_entry(p, &alloc->used, list) { ++ if (off < 255) ++ off += snprintf(buf + off, 255-off, "{%d,%d}", ++ p->base, p->base + p->num - 1); ++ } ++ pr_info("%s\n", buf); ++ ++ ++ ++} ++#else ++#define DPRINT(x...) ++#define DUMP(a) ++#endif ++ ++int dpa_alloc_new(struct dpa_alloc *alloc, u32 *result, u32 count, u32 align, ++ int partial) ++{ ++ struct alloc_node *i = NULL, *next_best = NULL, *used_node = NULL; ++ u32 base, next_best_base = 0, num = 0, next_best_num = 0; ++ struct alloc_node *margin_left, *margin_right; ++ ++ *result = (u32)-1; ++ DPRINT("alloc_range(%d,%d,%d)\n", count, align, partial); ++ DUMP(alloc); ++ /* If 'align' is 0, it should behave as though it was 1 */ ++ if (!align) ++ align = 1; ++ margin_left = kmalloc(sizeof(*margin_left), GFP_KERNEL); ++ if (!margin_left) ++ goto err; ++ margin_right = kmalloc(sizeof(*margin_right), GFP_KERNEL); ++ if (!margin_right) { ++ kfree(margin_left); ++ goto err; ++ } ++ spin_lock_irq(&alloc->lock); ++ list_for_each_entry(i, &alloc->free, list) { ++ base = (i->base + align - 1) / align; ++ base *= align; ++ if ((base - i->base) >= i->num) ++ /* alignment is impossible, regardless of count */ ++ continue; ++ num = i->num - (base - i->base); ++ if (num >= count) { ++ /* this one will do nicely */ ++ num = count; ++ goto done; ++ } ++ if (num > next_best_num) { ++ next_best = i; ++ next_best_base = base; ++ next_best_num = num; ++ } ++ } ++ if (partial && next_best) { ++ i = next_best; ++ base = next_best_base; ++ num = next_best_num; ++ } else ++ i = NULL; ++done: ++ if (i) { ++ if (base != i->base) { ++ margin_left->base = i->base; ++ margin_left->num = base - i->base; ++ list_add_tail(&margin_left->list, &i->list); ++ } else ++ kfree(margin_left); ++ if ((base + num) < (i->base + i->num)) { ++ margin_right->base = base + num; ++ margin_right->num = (i->base + i->num) - ++ (base + num); ++ list_add(&margin_right->list, &i->list); ++ } else ++ kfree(margin_right); ++ list_del(&i->list); ++ kfree(i); ++ *result = base; ++ } else { ++ spin_unlock_irq(&alloc->lock); ++ kfree(margin_left); ++ kfree(margin_right); ++ } ++ ++err: ++ DPRINT("returning %d\n", i ? num : -ENOMEM); ++ DUMP(alloc); ++ if (!i) ++ return -ENOMEM; ++ ++ /* Add the allocation to the used list with a refcount of 1 */ ++ used_node = kmalloc(sizeof(*used_node), GFP_KERNEL); ++ if (!used_node) { ++ spin_unlock_irq(&alloc->lock); ++ return -ENOMEM; ++ } ++ used_node->base = *result; ++ used_node->num = num; ++ used_node->refcount = 1; ++ used_node->is_alloced = 1; ++ list_add_tail(&used_node->list, &alloc->used); ++ spin_unlock_irq(&alloc->lock); ++ return (int)num; ++} ++ ++/* Allocate the list node using GFP_ATOMIC, because we *really* want to avoid ++ * forcing error-handling on to users in the deallocation path. */ ++static void _dpa_alloc_free(struct dpa_alloc *alloc, u32 base_id, u32 count) ++{ ++ struct alloc_node *i, *node = kmalloc(sizeof(*node), GFP_ATOMIC); ++ BUG_ON(!node); ++ DPRINT("release_range(%d,%d)\n", base_id, count); ++ DUMP(alloc); ++ BUG_ON(!count); ++ spin_lock_irq(&alloc->lock); ++ ++ ++ node->base = base_id; ++ node->num = count; ++ list_for_each_entry(i, &alloc->free, list) { ++ if (i->base >= node->base) { ++ /* BUG_ON(any overlapping) */ ++ BUG_ON(i->base < (node->base + node->num)); ++ list_add_tail(&node->list, &i->list); ++ goto done; ++ } ++ } ++ list_add_tail(&node->list, &alloc->free); ++done: ++ /* Merge to the left */ ++ i = list_entry(node->list.prev, struct alloc_node, list); ++ if (node->list.prev != &alloc->free) { ++ BUG_ON((i->base + i->num) > node->base); ++ if ((i->base + i->num) == node->base) { ++ node->base = i->base; ++ node->num += i->num; ++ list_del(&i->list); ++ kfree(i); ++ } ++ } ++ /* Merge to the right */ ++ i = list_entry(node->list.next, struct alloc_node, list); ++ if (node->list.next != &alloc->free) { ++ BUG_ON((node->base + node->num) > i->base); ++ if ((node->base + node->num) == i->base) { ++ node->num += i->num; ++ list_del(&i->list); ++ kfree(i); ++ } ++ } ++ spin_unlock_irq(&alloc->lock); ++ DUMP(alloc); ++} ++ ++ ++void dpa_alloc_free(struct dpa_alloc *alloc, u32 base_id, u32 count) ++{ ++ struct alloc_node *i = NULL; ++ spin_lock_irq(&alloc->lock); ++ ++ /* First find the node in the used list and decrement its ref count */ ++ list_for_each_entry(i, &alloc->used, list) { ++ if (i->base == base_id && i->num == count) { ++ --i->refcount; ++ if (i->refcount == 0) { ++ list_del(&i->list); ++ spin_unlock_irq(&alloc->lock); ++ if (i->is_alloced) ++ _dpa_alloc_free(alloc, base_id, count); ++ kfree(i); ++ return; ++ } ++ spin_unlock_irq(&alloc->lock); ++ return; ++ } ++ } ++ /* Couldn't find the allocation */ ++ pr_err("Attempt to free ID 0x%x COUNT %d that wasn't alloc'd or reserved\n", ++ base_id, count); ++ spin_unlock_irq(&alloc->lock); ++} ++ ++void dpa_alloc_seed(struct dpa_alloc *alloc, u32 base_id, u32 count) ++{ ++ /* Same as free but no previous allocation checking is needed */ ++ _dpa_alloc_free(alloc, base_id, count); ++} ++ ++ ++int dpa_alloc_reserve(struct dpa_alloc *alloc, u32 base, u32 num) ++{ ++ struct alloc_node *i = NULL, *used_node; ++ ++ DPRINT("alloc_reserve(%d,%d)\n", base, num); ++ DUMP(alloc); ++ ++ spin_lock_irq(&alloc->lock); ++ ++ /* Check for the node in the used list. ++ If found, increase it's refcount */ ++ list_for_each_entry(i, &alloc->used, list) { ++ if ((i->base == base) && (i->num == num)) { ++ ++i->refcount; ++ spin_unlock_irq(&alloc->lock); ++ return 0; ++ } ++ if ((base >= i->base) && (base < (i->base + i->num))) { ++ /* This is an attempt to reserve a region that was ++ already reserved or alloced with a different ++ base or num */ ++ pr_err("Cannot reserve %d - %d, it overlaps with" ++ " existing reservation from %d - %d\n", ++ base, base + num - 1, i->base, ++ i->base + i->num - 1); ++ spin_unlock_irq(&alloc->lock); ++ return -1; ++ } ++ } ++ /* Check to make sure this ID isn't in the free list */ ++ list_for_each_entry(i, &alloc->free, list) { ++ if ((base >= i->base) && (base < (i->base + i->num))) { ++ /* yep, the reservation is within this node */ ++ pr_err("Cannot reserve %d - %d, it overlaps with" ++ " free range %d - %d and must be alloced\n", ++ base, base + num - 1, ++ i->base, i->base + i->num - 1); ++ spin_unlock_irq(&alloc->lock); ++ return -1; ++ } ++ } ++ /* Add the allocation to the used list with a refcount of 1 */ ++ used_node = kmalloc(sizeof(*used_node), GFP_KERNEL); ++ if (!used_node) { ++ spin_unlock_irq(&alloc->lock); ++ return -ENOMEM; ++ ++ } ++ used_node->base = base; ++ used_node->num = num; ++ used_node->refcount = 1; ++ used_node->is_alloced = 0; ++ list_add_tail(&used_node->list, &alloc->used); ++ spin_unlock_irq(&alloc->lock); ++ return 0; ++} ++ ++ ++int dpa_alloc_pop(struct dpa_alloc *alloc, u32 *result, u32 *count) ++{ ++ struct alloc_node *i = NULL; ++ DPRINT("alloc_pop()\n"); ++ DUMP(alloc); ++ spin_lock_irq(&alloc->lock); ++ if (!list_empty(&alloc->free)) { ++ i = list_entry(alloc->free.next, struct alloc_node, list); ++ list_del(&i->list); ++ } ++ spin_unlock_irq(&alloc->lock); ++ DPRINT("returning %d\n", i ? 0 : -ENOMEM); ++ DUMP(alloc); ++ if (!i) ++ return -ENOMEM; ++ *result = i->base; ++ *count = i->num; ++ kfree(i); ++ return 0; ++} ++ ++int dpa_alloc_check(struct dpa_alloc *list_head, u32 item) ++{ ++ struct alloc_node *i = NULL; ++ int res = 0; ++ DPRINT("alloc_check()\n"); ++ spin_lock_irq(&list_head->lock); ++ ++ list_for_each_entry(i, &list_head->free, list) { ++ if ((item >= i->base) && (item < (i->base + i->num))) { ++ res = 1; ++ break; ++ } ++ } ++ spin_unlock_irq(&list_head->lock); ++ return res; ++} +diff --git a/drivers/staging/fsl_qbman/dpa_sys.h b/drivers/staging/fsl_qbman/dpa_sys.h +new file mode 100644 +index 00000000..e144f5a4 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/dpa_sys.h +@@ -0,0 +1,259 @@ ++/* Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef DPA_SYS_H ++#define DPA_SYS_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* When copying aligned words or shorts, try to avoid memcpy() */ ++#define CONFIG_TRY_BETTER_MEMCPY ++ ++/* For 2-element tables related to cache-inhibited and cache-enabled mappings */ ++#define DPA_PORTAL_CE 0 ++#define DPA_PORTAL_CI 1 ++ ++/***********************/ ++/* Misc inline assists */ ++/***********************/ ++ ++#if defined CONFIG_PPC32 ++#include "dpa_sys_ppc32.h" ++#elif defined CONFIG_PPC64 ++#include "dpa_sys_ppc64.h" ++#elif defined CONFIG_ARM ++#include "dpa_sys_arm.h" ++#elif defined CONFIG_ARM64 ++#include "dpa_sys_arm64.h" ++#endif ++ ++ ++#ifdef CONFIG_FSL_DPA_CHECKING ++#define DPA_ASSERT(x) \ ++ do { \ ++ if (!(x)) { \ ++ pr_crit("ASSERT: (%s:%d) %s\n", __FILE__, __LINE__, \ ++ __stringify_1(x)); \ ++ dump_stack(); \ ++ panic("assertion failure"); \ ++ } \ ++ } while (0) ++#else ++#define DPA_ASSERT(x) ++#endif ++ ++/* memcpy() stuff - when you know alignments in advance */ ++#ifdef CONFIG_TRY_BETTER_MEMCPY ++static inline void copy_words(void *dest, const void *src, size_t sz) ++{ ++ u32 *__dest = dest; ++ const u32 *__src = src; ++ size_t __sz = sz >> 2; ++ BUG_ON((unsigned long)dest & 0x3); ++ BUG_ON((unsigned long)src & 0x3); ++ BUG_ON(sz & 0x3); ++ while (__sz--) ++ *(__dest++) = *(__src++); ++} ++static inline void copy_shorts(void *dest, const void *src, size_t sz) ++{ ++ u16 *__dest = dest; ++ const u16 *__src = src; ++ size_t __sz = sz >> 1; ++ BUG_ON((unsigned long)dest & 0x1); ++ BUG_ON((unsigned long)src & 0x1); ++ BUG_ON(sz & 0x1); ++ while (__sz--) ++ *(__dest++) = *(__src++); ++} ++static inline void copy_bytes(void *dest, const void *src, size_t sz) ++{ ++ u8 *__dest = dest; ++ const u8 *__src = src; ++ while (sz--) ++ *(__dest++) = *(__src++); ++} ++#else ++#define copy_words memcpy ++#define copy_shorts memcpy ++#define copy_bytes memcpy ++#endif ++ ++/************/ ++/* RB-trees */ ++/************/ ++ ++/* We encapsulate RB-trees so that its easier to use non-linux forms in ++ * non-linux systems. This also encapsulates the extra plumbing that linux code ++ * usually provides when using RB-trees. This encapsulation assumes that the ++ * data type held by the tree is u32. */ ++ ++struct dpa_rbtree { ++ struct rb_root root; ++}; ++#define DPA_RBTREE { .root = RB_ROOT } ++ ++static inline void dpa_rbtree_init(struct dpa_rbtree *tree) ++{ ++ tree->root = RB_ROOT; ++} ++ ++#define IMPLEMENT_DPA_RBTREE(name, type, node_field, val_field) \ ++static inline int name##_push(struct dpa_rbtree *tree, type *obj) \ ++{ \ ++ struct rb_node *parent = NULL, **p = &tree->root.rb_node; \ ++ while (*p) { \ ++ u32 item; \ ++ parent = *p; \ ++ item = rb_entry(parent, type, node_field)->val_field; \ ++ if (obj->val_field < item) \ ++ p = &parent->rb_left; \ ++ else if (obj->val_field > item) \ ++ p = &parent->rb_right; \ ++ else \ ++ return -EBUSY; \ ++ } \ ++ rb_link_node(&obj->node_field, parent, p); \ ++ rb_insert_color(&obj->node_field, &tree->root); \ ++ return 0; \ ++} \ ++static inline void name##_del(struct dpa_rbtree *tree, type *obj) \ ++{ \ ++ rb_erase(&obj->node_field, &tree->root); \ ++} \ ++static inline type *name##_find(struct dpa_rbtree *tree, u32 val) \ ++{ \ ++ type *ret; \ ++ struct rb_node *p = tree->root.rb_node; \ ++ while (p) { \ ++ ret = rb_entry(p, type, node_field); \ ++ if (val < ret->val_field) \ ++ p = p->rb_left; \ ++ else if (val > ret->val_field) \ ++ p = p->rb_right; \ ++ else \ ++ return ret; \ ++ } \ ++ return NULL; \ ++} ++ ++/************/ ++/* Bootargs */ ++/************/ ++ ++/* Qman has "qportals=" and Bman has "bportals=", they use the same syntax ++ * though; a comma-separated list of items, each item being a cpu index and/or a ++ * range of cpu indices, and each item optionally be prefixed by "s" to indicate ++ * that the portal associated with that cpu should be shared. See bman_driver.c ++ * for more specifics. */ ++static int __parse_portals_cpu(const char **s, unsigned int *cpu) ++{ ++ *cpu = 0; ++ if (!isdigit(**s)) ++ return -EINVAL; ++ while (isdigit(**s)) ++ *cpu = *cpu * 10 + (*((*s)++) - '0'); ++ return 0; ++} ++static inline int parse_portals_bootarg(char *str, struct cpumask *want_shared, ++ struct cpumask *want_unshared, ++ const char *argname) ++{ ++ const char *s = str; ++ unsigned int shared, cpu1, cpu2, loop; ++ ++keep_going: ++ if (*s == 's') { ++ shared = 1; ++ s++; ++ } else ++ shared = 0; ++ if (__parse_portals_cpu(&s, &cpu1)) ++ goto err; ++ if (*s == '-') { ++ s++; ++ if (__parse_portals_cpu(&s, &cpu2)) ++ goto err; ++ if (cpu2 < cpu1) ++ goto err; ++ } else ++ cpu2 = cpu1; ++ for (loop = cpu1; loop <= cpu2; loop++) ++ cpumask_set_cpu(loop, shared ? want_shared : want_unshared); ++ if (*s == ',') { ++ s++; ++ goto keep_going; ++ } else if ((*s == '\0') || isspace(*s)) ++ return 0; ++err: ++ pr_crit("Malformed %s argument: %s, offset: %lu\n", argname, str, ++ (unsigned long)s - (unsigned long)str); ++ return -EINVAL; ++} ++#ifdef CONFIG_FSL_USDPAA ++/* Hooks from fsl_usdpaa_irq.c to fsl_usdpaa.c */ ++int usdpaa_get_portal_config(struct file *filp, void *cinh, ++ enum usdpaa_portal_type ptype, unsigned int *irq, ++ void **iir_reg); ++#endif ++#endif /* DPA_SYS_H */ +diff --git a/drivers/staging/fsl_qbman/dpa_sys_arm.h b/drivers/staging/fsl_qbman/dpa_sys_arm.h +new file mode 100644 +index 00000000..17c5500e +--- /dev/null ++++ b/drivers/staging/fsl_qbman/dpa_sys_arm.h +@@ -0,0 +1,95 @@ ++/* Copyright 2016 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef DPA_SYS_ARM_H ++#define DPA_SYS_ARM_H ++ ++#include ++#include ++ ++/* Implementation of ARM specific routines */ ++ ++/* TODO: NB, we currently assume that hwsync() and lwsync() imply compiler ++ * barriers and that dcb*() won't fall victim to compiler or execution ++ * reordering with respect to other code/instructions that manipulate the same ++ * cacheline. */ ++#define hwsync() { asm volatile("dmb st" : : : "memory"); } ++#define lwsync() { asm volatile("dmb st" : : : "memory"); } ++#define dcbf(p) { asm volatile("mcr p15, 0, %0, c7, c10, 1" : : "r" (p) : "memory"); } ++#define dcbt_ro(p) { asm volatile("pld [%0, #64];": : "r" (p)); } ++#define dcbt_rw(p) { asm volatile("pldw [%0, #64];": : "r" (p)); } ++#define dcbi(p) { asm volatile("mcr p15, 0, %0, c7, c6, 1" : : "r" (p) : "memory"); } ++ ++#define dcbz_64(p) { memset(p, 0, sizeof(*p)); } ++ ++#define dcbf_64(p) \ ++ do { \ ++ dcbf((u32)p); \ ++ } while (0) ++/* Commonly used combo */ ++#define dcbit_ro(p) \ ++ do { \ ++ dcbi((u32)p); \ ++ dcbt_ro((u32)p); \ ++ } while (0) ++ ++static inline u64 mfatb(void) ++{ ++ return get_cycles(); ++} ++ ++static inline u32 in_be32(volatile void *addr) ++{ ++ return be32_to_cpu(*((volatile u32 *) addr)); ++} ++ ++static inline void out_be32(void *addr, u32 val) ++{ ++ *((u32 *) addr) = cpu_to_be32(val); ++} ++ ++ ++static inline void set_bits(unsigned long mask, volatile unsigned long *p) ++{ ++ *p |= mask; ++} ++static inline void clear_bits(unsigned long mask, volatile unsigned long *p) ++{ ++ *p &= ~mask; ++} ++ ++static inline void flush_dcache_range(unsigned long start, unsigned long stop) ++{ ++ __cpuc_flush_dcache_area((void *) start, stop - start); ++} ++ ++#define hard_smp_processor_id() raw_smp_processor_id() ++#endif +diff --git a/drivers/staging/fsl_qbman/dpa_sys_arm64.h b/drivers/staging/fsl_qbman/dpa_sys_arm64.h +new file mode 100644 +index 00000000..247c8d97 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/dpa_sys_arm64.h +@@ -0,0 +1,102 @@ ++/* Copyright 2014 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef DPA_SYS_ARM64_H ++#define DPA_SYS_ARM64_H ++ ++#include ++#include ++ ++/* Implementation of ARM 64 bit specific routines */ ++ ++/* TODO: NB, we currently assume that hwsync() and lwsync() imply compiler ++ * barriers and that dcb*() won't fall victim to compiler or execution ++ * reordering with respect to other code/instructions that manipulate the same ++ * cacheline. */ ++#define hwsync() { asm volatile("dmb st" : : : "memory"); } ++#define lwsync() { asm volatile("dmb st" : : : "memory"); } ++#define dcbf(p) { asm volatile("dc cvac, %0;" : : "r" (p) : "memory"); } ++#define dcbt_ro(p) { asm volatile("prfm pldl1keep, [%0, #0]" : : "r" (p)); } ++#define dcbt_rw(p) { asm volatile("prfm pstl1keep, [%0, #0]" : : "r" (p)); } ++#define dcbi(p) { asm volatile("dc ivac, %0" : : "r"(p) : "memory"); } ++#define dcbz(p) { asm volatile("dc zva, %0" : : "r" (p) : "memory"); } ++ ++#define dcbz_64(p) \ ++ do { \ ++ dcbz(p); \ ++ } while (0) ++ ++#define dcbf_64(p) \ ++ do { \ ++ dcbf(p); \ ++ } while (0) ++/* Commonly used combo */ ++#define dcbit_ro(p) \ ++ do { \ ++ dcbi(p); \ ++ dcbt_ro(p); \ ++ } while (0) ++ ++static inline u64 mfatb(void) ++{ ++ return get_cycles(); ++} ++ ++static inline u32 in_be32(volatile void *addr) ++{ ++ return be32_to_cpu(*((volatile u32 *) addr)); ++} ++ ++static inline void out_be32(void *addr, u32 val) ++{ ++ *((u32 *) addr) = cpu_to_be32(val); ++} ++ ++ ++static inline void set_bits(unsigned long mask, volatile unsigned long *p) ++{ ++ *p |= mask; ++} ++static inline void clear_bits(unsigned long mask, volatile unsigned long *p) ++{ ++ *p &= ~mask; ++} ++ ++static inline void flush_dcache_range(unsigned long start, unsigned long stop) ++{ ++ __flush_dcache_area((void *) start, stop - start); ++} ++ ++#define hard_smp_processor_id() raw_smp_processor_id() ++ ++ ++ ++#endif +diff --git a/drivers/staging/fsl_qbman/dpa_sys_ppc32.h b/drivers/staging/fsl_qbman/dpa_sys_ppc32.h +new file mode 100644 +index 00000000..874616df +--- /dev/null ++++ b/drivers/staging/fsl_qbman/dpa_sys_ppc32.h +@@ -0,0 +1,70 @@ ++/* Copyright 2014 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef DPA_SYS_PPC32_H ++#define DPA_SYS_PPC32_H ++ ++/* Implementation of PowerPC 32 bit specific routines */ ++ ++/* TODO: NB, we currently assume that hwsync() and lwsync() imply compiler ++ * barriers and that dcb*() won't fall victim to compiler or execution ++ * reordering with respect to other code/instructions that manipulate the same ++ * cacheline. */ ++#define hwsync() __asm__ __volatile__ ("sync" : : : "memory") ++#define lwsync() __asm__ __volatile__ (stringify_in_c(LWSYNC) : : : "memory") ++#define dcbf(p) __asm__ __volatile__ ("dcbf 0,%0" : : "r" (p) : "memory") ++#define dcbt_ro(p) __asm__ __volatile__ ("dcbt 0,%0" : : "r" (p)) ++#define dcbt_rw(p) __asm__ __volatile__ ("dcbtst 0,%0" : : "r" (p)) ++#define dcbi(p) dcbf(p) ++ ++#define dcbzl(p) __asm__ __volatile__ ("dcbzl 0,%0" : : "r" (p)) ++#define dcbz_64(p) dcbzl(p) ++#define dcbf_64(p) dcbf(p) ++ ++/* Commonly used combo */ ++#define dcbit_ro(p) \ ++ do { \ ++ dcbi(p); \ ++ dcbt_ro(p); \ ++ } while (0) ++ ++static inline u64 mfatb(void) ++{ ++ u32 hi, lo, chk; ++ do { ++ hi = mfspr(SPRN_ATBU); ++ lo = mfspr(SPRN_ATBL); ++ chk = mfspr(SPRN_ATBU); ++ } while (unlikely(hi != chk)); ++ return ((u64)hi << 32) | (u64)lo; ++} ++ ++#endif +diff --git a/drivers/staging/fsl_qbman/dpa_sys_ppc64.h b/drivers/staging/fsl_qbman/dpa_sys_ppc64.h +new file mode 100644 +index 00000000..d9803199 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/dpa_sys_ppc64.h +@@ -0,0 +1,79 @@ ++/* Copyright 2014 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef DPA_SYS_PPC64_H ++#define DPA_SYS_PPC64_H ++ ++/* Implementation of PowerPC 64 bit specific routines */ ++ ++/* TODO: NB, we currently assume that hwsync() and lwsync() imply compiler ++ * barriers and that dcb*() won't fall victim to compiler or execution ++ * reordering with respect to other code/instructions that manipulate the same ++ * cacheline. */ ++#define hwsync() __asm__ __volatile__ ("sync" : : : "memory") ++#define lwsync() __asm__ __volatile__ (stringify_in_c(LWSYNC) : : : "memory") ++#define dcbf(p) __asm__ __volatile__ ("dcbf 0,%0" : : "r" (p) : "memory") ++#define dcbt_ro(p) __asm__ __volatile__ ("dcbt 0,%0" : : "r" (p)) ++#define dcbt_rw(p) __asm__ __volatile__ ("dcbtst 0,%0" : : "r" (p)) ++#define dcbi(p) dcbf(p) ++ ++#define dcbz(p) __asm__ __volatile__ ("dcbz 0,%0" : : "r" (p)) ++#define dcbz_64(p) \ ++ do { \ ++ dcbz((void*)p + 32); \ ++ dcbz(p); \ ++ } while (0) ++#define dcbf_64(p) \ ++ do { \ ++ dcbf((void*)p + 32); \ ++ dcbf(p); \ ++ } while (0) ++/* Commonly used combo */ ++#define dcbit_ro(p) \ ++ do { \ ++ dcbi(p); \ ++ dcbi((void*)p + 32); \ ++ dcbt_ro(p); \ ++ dcbt_ro((void*)p + 32); \ ++ } while (0) ++ ++static inline u64 mfatb(void) ++{ ++ u32 hi, lo, chk; ++ do { ++ hi = mfspr(SPRN_ATBU); ++ lo = mfspr(SPRN_ATBL); ++ chk = mfspr(SPRN_ATBU); ++ } while (unlikely(hi != chk)); ++ return ((u64)hi << 32) | (u64)lo; ++} ++ ++#endif +diff --git a/drivers/staging/fsl_qbman/fsl_usdpaa.c b/drivers/staging/fsl_qbman/fsl_usdpaa.c +new file mode 100644 +index 00000000..3a6d3722 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/fsl_usdpaa.c +@@ -0,0 +1,1983 @@ ++/* Copyright (C) 2008-2012 Freescale Semiconductor, Inc. ++ * Authors: Andy Fleming ++ * Timur Tabi ++ * Geoff Thorpe ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if !(defined(CONFIG_ARM) || defined(CONFIG_ARM64)) ++#include ++#endif ++ ++#include "dpa_sys.h" ++#include ++#include "bman_low.h" ++#include "qman_low.h" ++ ++/* Physical address range of the memory reservation, exported for mm/mem.c */ ++static u64 phys_start; ++static u64 phys_size; ++static u64 arg_phys_size; ++ ++/* PFN versions of the above */ ++static unsigned long pfn_start; ++static unsigned long pfn_size; ++ ++/* Memory reservations are manipulated under this spinlock (which is why 'refs' ++ * isn't atomic_t). */ ++static DEFINE_SPINLOCK(mem_lock); ++ ++/* The range of TLB1 indices */ ++static unsigned int first_tlb; ++static unsigned int num_tlb = 1; ++static unsigned int current_tlb; /* loops around for fault handling */ ++ ++/* Memory reservation is represented as a list of 'mem_fragment's, some of which ++ * may be mapped. Unmapped fragments are always merged where possible. */ ++static LIST_HEAD(mem_list); ++ ++struct mem_mapping; ++ ++/* Memory fragments are in 'mem_list'. */ ++struct mem_fragment { ++ u64 base; ++ u64 len; ++ unsigned long pfn_base; /* PFN version of 'base' */ ++ unsigned long pfn_len; /* PFN version of 'len' */ ++ unsigned int refs; /* zero if unmapped */ ++ u64 root_len; /* Size of the orignal fragment */ ++ unsigned long root_pfn; /* PFN of the orignal fragment */ ++ struct list_head list; ++ /* if mapped, flags+name captured at creation time */ ++ u32 flags; ++ char name[USDPAA_DMA_NAME_MAX]; ++ u64 map_len; ++ /* support multi-process locks per-memory-fragment. */ ++ int has_locking; ++ wait_queue_head_t wq; ++ struct mem_mapping *owner; ++}; ++ ++/* Mappings of memory fragments in 'struct ctx'. These are created from ++ * ioctl(USDPAA_IOCTL_DMA_MAP), though the actual mapping then happens via a ++ * mmap(). */ ++struct mem_mapping { ++ struct mem_fragment *root_frag; ++ u32 frag_count; ++ u64 total_size; ++ struct list_head list; ++ int refs; ++ void *virt_addr; ++}; ++ ++struct portal_mapping { ++ struct usdpaa_ioctl_portal_map user; ++ union { ++ struct qm_portal_config *qportal; ++ struct bm_portal_config *bportal; ++ }; ++ /* Declare space for the portals in case the process ++ exits unexpectedly and needs to be cleaned by the kernel */ ++ union { ++ struct qm_portal qman_portal_low; ++ struct bm_portal bman_portal_low; ++ }; ++ struct list_head list; ++ struct resource *phys; ++ struct iommu_domain *iommu_domain; ++}; ++ ++/* Track the DPAA resources the process is using */ ++struct active_resource { ++ struct list_head list; ++ u32 id; ++ u32 num; ++ unsigned int refcount; ++}; ++ ++/* Per-FD state (which should also be per-process but we don't enforce that) */ ++struct ctx { ++ /* Lock to protect the context */ ++ spinlock_t lock; ++ /* Allocated resources get put here for accounting */ ++ struct list_head resources[usdpaa_id_max]; ++ /* list of DMA maps */ ++ struct list_head maps; ++ /* list of portal maps */ ++ struct list_head portals; ++}; ++ ++/* Different resource classes */ ++static const struct alloc_backend { ++ enum usdpaa_id_type id_type; ++ int (*alloc)(u32 *, u32, u32, int); ++ void (*release)(u32 base, unsigned int count); ++ int (*reserve)(u32 base, unsigned int count); ++ const char *acronym; ++} alloc_backends[] = { ++ { ++ .id_type = usdpaa_id_fqid, ++ .alloc = qman_alloc_fqid_range, ++ .release = qman_release_fqid_range, ++ .reserve = qman_reserve_fqid_range, ++ .acronym = "FQID" ++ }, ++ { ++ .id_type = usdpaa_id_bpid, ++ .alloc = bman_alloc_bpid_range, ++ .release = bman_release_bpid_range, ++ .reserve = bman_reserve_bpid_range, ++ .acronym = "BPID" ++ }, ++ { ++ .id_type = usdpaa_id_qpool, ++ .alloc = qman_alloc_pool_range, ++ .release = qman_release_pool_range, ++ .reserve = qman_reserve_pool_range, ++ .acronym = "QPOOL" ++ }, ++ { ++ .id_type = usdpaa_id_cgrid, ++ .alloc = qman_alloc_cgrid_range, ++ .release = qman_release_cgrid_range, ++ .acronym = "CGRID" ++ }, ++ { ++ .id_type = usdpaa_id_ceetm0_lfqid, ++ .alloc = qman_alloc_ceetm0_lfqid_range, ++ .release = qman_release_ceetm0_lfqid_range, ++ .acronym = "CEETM0_LFQID" ++ }, ++ { ++ .id_type = usdpaa_id_ceetm0_channelid, ++ .alloc = qman_alloc_ceetm0_channel_range, ++ .release = qman_release_ceetm0_channel_range, ++ .acronym = "CEETM0_LFQID" ++ }, ++ { ++ .id_type = usdpaa_id_ceetm1_lfqid, ++ .alloc = qman_alloc_ceetm1_lfqid_range, ++ .release = qman_release_ceetm1_lfqid_range, ++ .acronym = "CEETM1_LFQID" ++ }, ++ { ++ .id_type = usdpaa_id_ceetm1_channelid, ++ .alloc = qman_alloc_ceetm1_channel_range, ++ .release = qman_release_ceetm1_channel_range, ++ .acronym = "CEETM1_LFQID" ++ }, ++ { ++ /* This terminates the array */ ++ .id_type = usdpaa_id_max ++ } ++}; ++ ++/* Determines the largest acceptable page size for a given size ++ The sizes are determined by what the TLB1 acceptable page sizes are */ ++static u32 largest_page_size(u32 size) ++{ ++ int shift = 30; /* Start at 1G size */ ++ if (size < 4096) ++ return 0; ++ do { ++ if (size >= (1<= 12); /* Up to 4k */ ++ return 0; ++} ++ ++/* Determine if value is power of 4 */ ++static inline bool is_power_of_4(u64 x) ++{ ++ if (x == 0 || ((x & (x - 1)) != 0)) ++ return false; ++ return !!(x & 0x5555555555555555ull); ++} ++ ++/* Helper for ioctl_dma_map() when we have a larger fragment than we need. This ++ * splits the fragment into 4 and returns the upper-most. (The caller can loop ++ * until it has a suitable fragment size.) */ ++static struct mem_fragment *split_frag(struct mem_fragment *frag) ++{ ++ struct mem_fragment *x[3]; ++ ++ x[0] = kmalloc(sizeof(struct mem_fragment), GFP_ATOMIC); ++ x[1] = kmalloc(sizeof(struct mem_fragment), GFP_ATOMIC); ++ x[2] = kmalloc(sizeof(struct mem_fragment), GFP_ATOMIC); ++ if (!x[0] || !x[1] || !x[2]) { ++ kfree(x[0]); ++ kfree(x[1]); ++ kfree(x[2]); ++ return NULL; ++ } ++ BUG_ON(frag->refs); ++ frag->len >>= 2; ++ frag->pfn_len >>= 2; ++ x[0]->base = frag->base + frag->len; ++ x[1]->base = x[0]->base + frag->len; ++ x[2]->base = x[1]->base + frag->len; ++ x[0]->len = x[1]->len = x[2]->len = frag->len; ++ x[0]->pfn_base = frag->pfn_base + frag->pfn_len; ++ x[1]->pfn_base = x[0]->pfn_base + frag->pfn_len; ++ x[2]->pfn_base = x[1]->pfn_base + frag->pfn_len; ++ x[0]->pfn_len = x[1]->pfn_len = x[2]->pfn_len = frag->pfn_len; ++ x[0]->refs = x[1]->refs = x[2]->refs = 0; ++ x[0]->root_len = x[1]->root_len = x[2]->root_len = frag->root_len; ++ x[0]->root_pfn = x[1]->root_pfn = x[2]->root_pfn = frag->root_pfn; ++ x[0]->name[0] = x[1]->name[0] = x[2]->name[0] = 0; ++ list_add_tail(&x[0]->list, &frag->list); ++ list_add_tail(&x[1]->list, &x[0]->list); ++ list_add_tail(&x[2]->list, &x[1]->list); ++ return x[2]; ++} ++ ++static __maybe_unused void dump_frags(void) ++{ ++ struct mem_fragment *frag; ++ int i = 0; ++ list_for_each_entry(frag, &mem_list, list) { ++ pr_info("FRAG %d: base 0x%llx pfn_base 0x%lx len 0x%llx root_len 0x%llx root_pfn 0x%lx refs %d name %s\n", ++ i, frag->base, frag->pfn_base, ++ frag->len, frag->root_len, frag->root_pfn, ++ frag->refs, frag->name); ++ ++i; ++ } ++} ++ ++/* Walk the list of fragments and adjoin neighbouring segments if possible */ ++static void compress_frags(void) ++{ ++ /* Walk the fragment list and combine fragments */ ++ struct mem_fragment *frag, *nxtfrag; ++ u64 len = 0; ++ ++ int i, numfrags; ++ ++ ++ frag = list_entry(mem_list.next, struct mem_fragment, list); ++ ++ while (&frag->list != &mem_list) { ++ /* Must combine consecutive fragemenst with ++ same root_pfn such that they are power of 4 */ ++ if (frag->refs != 0) { ++ frag = list_entry(frag->list.next, ++ struct mem_fragment, list); ++ continue; /* Not this window */ ++ } ++ len = frag->len; ++ numfrags = 0; ++ nxtfrag = list_entry(frag->list.next, ++ struct mem_fragment, list); ++ while (true) { ++ if (&nxtfrag->list == &mem_list) { ++ numfrags = 0; ++ break; /* End of list */ ++ } ++ if (nxtfrag->refs) { ++ numfrags = 0; ++ break; /* In use still */ ++ } ++ if (nxtfrag->root_pfn != frag->root_pfn) { ++ numfrags = 0; ++ break; /* Crosses root fragment boundary */ ++ } ++ len += nxtfrag->len; ++ numfrags++; ++ if (is_power_of_4(len)) { ++ /* These fragments can be combined */ ++ break; ++ } ++ nxtfrag = list_entry(nxtfrag->list.next, ++ struct mem_fragment, list); ++ } ++ if (numfrags == 0) { ++ frag = list_entry(frag->list.next, ++ struct mem_fragment, list); ++ continue; /* try the next window */ ++ } ++ for (i = 0; i < numfrags; i++) { ++ struct mem_fragment *todel = ++ list_entry(nxtfrag->list.prev, ++ struct mem_fragment, list); ++ nxtfrag->len += todel->len; ++ nxtfrag->pfn_len += todel->pfn_len; ++ list_del(&todel->list); ++ } ++ /* Re evaluate the list, things may merge now */ ++ frag = list_entry(mem_list.next, struct mem_fragment, list); ++ } ++} ++ ++/* Hook from arch/powerpc/mm/mem.c */ ++int usdpaa_test_fault(unsigned long pfn, u64 *phys_addr, u64 *size) ++{ ++ struct mem_fragment *frag; ++ int idx = -1; ++ if ((pfn < pfn_start) || (pfn >= (pfn_start + pfn_size))) ++ return -1; ++ /* It's in-range, we need to find the fragment */ ++ spin_lock(&mem_lock); ++ list_for_each_entry(frag, &mem_list, list) { ++ if ((pfn >= frag->pfn_base) && (pfn < (frag->pfn_base + ++ frag->pfn_len))) { ++ *phys_addr = frag->base; ++ *size = frag->len; ++ idx = current_tlb++; ++ if (current_tlb >= (first_tlb + num_tlb)) ++ current_tlb = first_tlb; ++ break; ++ } ++ } ++ spin_unlock(&mem_lock); ++ return idx; ++} ++ ++static int usdpaa_open(struct inode *inode, struct file *filp) ++{ ++ const struct alloc_backend *backend = &alloc_backends[0]; ++ struct ctx *ctx = kmalloc(sizeof(struct ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ filp->private_data = ctx; ++ ++ while (backend->id_type != usdpaa_id_max) { ++ INIT_LIST_HEAD(&ctx->resources[backend->id_type]); ++ backend++; ++ } ++ ++ INIT_LIST_HEAD(&ctx->maps); ++ INIT_LIST_HEAD(&ctx->portals); ++ spin_lock_init(&ctx->lock); ++ ++ //filp->f_mapping->backing_dev_info = &directly_mappable_cdev_bdi; ++ ++ return 0; ++} ++ ++#define DQRR_MAXFILL 15 ++ ++/* Reset a QMan portal to its default state */ ++static int init_qm_portal(struct qm_portal_config *config, ++ struct qm_portal *portal) ++{ ++ const struct qm_dqrr_entry *dqrr = NULL; ++ int i; ++ ++ portal->addr.addr_ce = config->addr_virt[DPA_PORTAL_CE]; ++ portal->addr.addr_ci = config->addr_virt[DPA_PORTAL_CI]; ++ ++ /* Make sure interrupts are inhibited */ ++ qm_out(IIR, 1); ++ ++ /* Initialize the DQRR. This will stop any dequeue ++ commands that are in progress */ ++ if (qm_dqrr_init(portal, config, qm_dqrr_dpush, qm_dqrr_pvb, ++ qm_dqrr_cdc, DQRR_MAXFILL)) { ++ pr_err("qm_dqrr_init() failed when trying to" ++ " recover portal, portal will be leaked\n"); ++ return 1; ++ } ++ ++ /* Discard any entries on the DQRR */ ++ /* If we consume the ring twice something is wrong */ ++ for (i = 0; i < DQRR_MAXFILL * 2; i++) { ++ qm_dqrr_pvb_update(portal); ++ dqrr = qm_dqrr_current(portal); ++ if (!dqrr) ++ break; ++ qm_dqrr_cdc_consume_1ptr(portal, dqrr, 0); ++ qm_dqrr_pvb_update(portal); ++ qm_dqrr_next(portal); ++ } ++ /* Initialize the EQCR */ ++ if (qm_eqcr_init(portal, qm_eqcr_pvb, ++ qm_eqcr_get_ci_stashing(portal), 1)) { ++ pr_err("Qman EQCR initialisation failed\n"); ++ return 1; ++ } ++ /* initialize the MR */ ++ if (qm_mr_init(portal, qm_mr_pvb, qm_mr_cci)) { ++ pr_err("Qman MR initialisation failed\n"); ++ return 1; ++ } ++ qm_mr_pvb_update(portal); ++ while (qm_mr_current(portal)) { ++ qm_mr_next(portal); ++ qm_mr_cci_consume_to_current(portal); ++ qm_mr_pvb_update(portal); ++ } ++ ++ if (qm_mc_init(portal)) { ++ pr_err("Qman MC initialisation failed\n"); ++ return 1; ++ } ++ return 0; ++} ++ ++static int init_bm_portal(struct bm_portal_config *config, ++ struct bm_portal *portal) ++{ ++ portal->addr.addr_ce = config->addr_virt[DPA_PORTAL_CE]; ++ portal->addr.addr_ci = config->addr_virt[DPA_PORTAL_CI]; ++ ++ if (bm_rcr_init(portal, bm_rcr_pvb, bm_rcr_cce)) { ++ pr_err("Bman RCR initialisation failed\n"); ++ return 1; ++ } ++ if (bm_mc_init(portal)) { ++ pr_err("Bman MC initialisation failed\n"); ++ return 1; ++ } ++ return 0; ++} ++ ++/* Function that will scan all FQ's in the system. For each FQ that is not ++ OOS it will call the check_channel helper to determine if the FQ should ++ be torn down. If the check_channel helper returns true the FQ will be ++ transitioned to the OOS state */ ++static int qm_check_and_destroy_fqs(struct qm_portal *portal, void *ctx, ++ bool (*check_channel)(void*, u32)) ++{ ++ u32 fq_id = 0; ++ while (1) { ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ u8 state; ++ u32 channel; ++ ++ /* Determine the channel for the FQID */ ++ mcc = qm_mc_start(portal); ++ mcc->queryfq.fqid = fq_id; ++ qm_mc_commit(portal, QM_MCC_VERB_QUERYFQ); ++ while (!(mcr = qm_mc_result(portal))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ++ == QM_MCR_VERB_QUERYFQ); ++ if (mcr->result != QM_MCR_RESULT_OK) ++ break; /* End of valid FQIDs */ ++ ++ channel = mcr->queryfq.fqd.dest.channel; ++ /* Determine the state of the FQID */ ++ mcc = qm_mc_start(portal); ++ mcc->queryfq_np.fqid = fq_id; ++ qm_mc_commit(portal, QM_MCC_VERB_QUERYFQ_NP); ++ while (!(mcr = qm_mc_result(portal))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ++ == QM_MCR_VERB_QUERYFQ_NP); ++ state = mcr->queryfq_np.state & QM_MCR_NP_STATE_MASK; ++ if (state == QM_MCR_NP_STATE_OOS) ++ /* Already OOS, no need to do anymore checks */ ++ goto next; ++ ++ if (check_channel(ctx, channel)) ++ qm_shutdown_fq(&portal, 1, fq_id); ++ next: ++ ++fq_id; ++ } ++ return 0; ++} ++ ++static bool check_channel_device(void *_ctx, u32 channel) ++{ ++ struct ctx *ctx = _ctx; ++ struct portal_mapping *portal, *tmpportal; ++ struct active_resource *res; ++ ++ /* See if the FQ is destined for one of the portals we're cleaning up */ ++ list_for_each_entry_safe(portal, tmpportal, &ctx->portals, list) { ++ if (portal->user.type == usdpaa_portal_qman) { ++ if (portal->qportal->public_cfg.channel == channel) { ++ /* This FQs destination is a portal ++ we're cleaning, send a retire */ ++ return true; ++ } ++ } ++ } ++ ++ /* Check the pool channels that will be released as well */ ++ list_for_each_entry(res, &ctx->resources[usdpaa_id_qpool], list) { ++ if ((res->id >= channel) && ++ ((res->id + res->num - 1) <= channel)) ++ return true; ++ } ++ return false; ++} ++ ++static bool check_portal_channel(void *ctx, u32 channel) ++{ ++ u32 portal_channel = *(u32 *)ctx; ++ if (portal_channel == channel) { ++ /* This FQs destination is a portal ++ we're cleaning, send a retire */ ++ return true; ++ } ++ return false; ++} ++ ++ ++ ++ ++static int usdpaa_release(struct inode *inode, struct file *filp) ++{ ++ struct ctx *ctx = filp->private_data; ++ struct mem_mapping *map, *tmpmap; ++ struct portal_mapping *portal, *tmpportal; ++ const struct alloc_backend *backend = &alloc_backends[0]; ++ struct active_resource *res; ++ struct qm_portal *qm_cleanup_portal = NULL; ++ struct bm_portal *bm_cleanup_portal = NULL; ++ struct qm_portal_config *qm_alloced_portal = NULL; ++ struct bm_portal_config *bm_alloced_portal = NULL; ++ ++ struct qm_portal *portal_array[qman_portal_max]; ++ int portal_count = 0; ++ ++ /* Ensure the release operation cannot be migrated to another ++ CPU as CPU specific variables may be needed during cleanup */ ++#ifdef CONFIG_PREEMPT_RT_FULL ++ migrate_disable(); ++#endif ++ /* The following logic is used to recover resources that were not ++ correctly released by the process that is closing the FD. ++ Step 1: syncronize the HW with the qm_portal/bm_portal structures ++ in the kernel ++ */ ++ ++ list_for_each_entry_safe(portal, tmpportal, &ctx->portals, list) { ++ /* Try to recover any portals that weren't shut down */ ++ if (portal->user.type == usdpaa_portal_qman) { ++ portal_array[portal_count] = &portal->qman_portal_low; ++ ++portal_count; ++ init_qm_portal(portal->qportal, ++ &portal->qman_portal_low); ++ if (!qm_cleanup_portal) { ++ qm_cleanup_portal = &portal->qman_portal_low; ++ } else { ++ /* Clean FQs on the dedicated channel */ ++ u32 chan = portal->qportal->public_cfg.channel; ++ qm_check_and_destroy_fqs( ++ &portal->qman_portal_low, &chan, ++ check_portal_channel); ++ } ++ } else { ++ /* BMAN */ ++ init_bm_portal(portal->bportal, ++ &portal->bman_portal_low); ++ if (!bm_cleanup_portal) ++ bm_cleanup_portal = &portal->bman_portal_low; ++ } ++ } ++ /* If no portal was found, allocate one for cleanup */ ++ if (!qm_cleanup_portal) { ++ qm_alloced_portal = qm_get_unused_portal(); ++ if (!qm_alloced_portal) { ++ pr_crit("No QMan portal avalaible for cleanup\n"); ++#ifdef CONFIG_PREEMPT_RT_FULL ++ migrate_enable(); ++#endif ++ return -1; ++ } ++ qm_cleanup_portal = kmalloc(sizeof(struct qm_portal), ++ GFP_KERNEL); ++ if (!qm_cleanup_portal) { ++#ifdef CONFIG_PREEMPT_RT_FULL ++ migrate_enable(); ++#endif ++ return -ENOMEM; ++ } ++ init_qm_portal(qm_alloced_portal, qm_cleanup_portal); ++ portal_array[portal_count] = qm_cleanup_portal; ++ ++portal_count; ++ } ++ if (!bm_cleanup_portal) { ++ bm_alloced_portal = bm_get_unused_portal(); ++ if (!bm_alloced_portal) { ++ pr_crit("No BMan portal avalaible for cleanup\n"); ++#ifdef CONFIG_PREEMPT_RT_FULL ++ migrate_enable(); ++#endif ++ return -1; ++ } ++ bm_cleanup_portal = kmalloc(sizeof(struct bm_portal), ++ GFP_KERNEL); ++ if (!bm_cleanup_portal) { ++#ifdef CONFIG_PREEMPT_RT_FULL ++ migrate_enable(); ++#endif ++ return -ENOMEM; ++ } ++ init_bm_portal(bm_alloced_portal, bm_cleanup_portal); ++ } ++ ++ /* OOS the FQs associated with this process */ ++ qm_check_and_destroy_fqs(qm_cleanup_portal, ctx, check_channel_device); ++ ++ while (backend->id_type != usdpaa_id_max) { ++ int leaks = 0; ++ list_for_each_entry(res, &ctx->resources[backend->id_type], ++ list) { ++ if (backend->id_type == usdpaa_id_fqid) { ++ int i = 0; ++ for (; i < res->num; i++) { ++ /* Clean FQs with the cleanup portal */ ++ qm_shutdown_fq(portal_array, ++ portal_count, ++ res->id + i); ++ } ++ } ++ leaks += res->num; ++ backend->release(res->id, res->num); ++ } ++ if (leaks) ++ pr_crit("USDPAA process leaking %d %s%s\n", leaks, ++ backend->acronym, (leaks > 1) ? "s" : ""); ++ backend++; ++ } ++ /* Release any DMA regions */ ++ spin_lock(&mem_lock); ++ list_for_each_entry_safe(map, tmpmap, &ctx->maps, list) { ++ struct mem_fragment *current_frag = map->root_frag; ++ int i; ++ if (map->root_frag->has_locking && ++ (map->root_frag->owner == map)) { ++ map->root_frag->owner = NULL; ++ wake_up(&map->root_frag->wq); ++ } ++ /* Check each fragment and merge if the ref count is 0 */ ++ for (i = 0; i < map->frag_count; i++) { ++ --current_frag->refs; ++ current_frag = list_entry(current_frag->list.prev, ++ struct mem_fragment, list); ++ } ++ ++ compress_frags(); ++ list_del(&map->list); ++ kfree(map); ++ } ++ spin_unlock(&mem_lock); ++ ++ /* Return portals */ ++ list_for_each_entry_safe(portal, tmpportal, &ctx->portals, list) { ++ if (portal->user.type == usdpaa_portal_qman) { ++ /* Give the portal back to the allocator */ ++ init_qm_portal(portal->qportal, ++ &portal->qman_portal_low); ++ qm_put_unused_portal(portal->qportal); ++ } else { ++ init_bm_portal(portal->bportal, ++ &portal->bman_portal_low); ++ bm_put_unused_portal(portal->bportal); ++ } ++ list_del(&portal->list); ++ kfree(portal); ++ } ++ if (qm_alloced_portal) { ++ qm_put_unused_portal(qm_alloced_portal); ++ kfree(qm_cleanup_portal); ++ } ++ if (bm_alloced_portal) { ++ bm_put_unused_portal(bm_alloced_portal); ++ kfree(bm_cleanup_portal); ++ } ++ ++ kfree(ctx); ++#ifdef CONFIG_PREEMPT_RT_FULL ++ migrate_enable(); ++#endif ++ return 0; ++} ++ ++static int check_mmap_dma(struct ctx *ctx, struct vm_area_struct *vma, ++ int *match, unsigned long *pfn) ++{ ++ struct mem_mapping *map; ++ ++ list_for_each_entry(map, &ctx->maps, list) { ++ int i; ++ struct mem_fragment *frag = map->root_frag; ++ ++ for (i = 0; i < map->frag_count; i++) { ++ if (frag->pfn_base == vma->vm_pgoff) { ++ *match = 1; ++ *pfn = frag->pfn_base; ++ return 0; ++ } ++ frag = list_entry(frag->list.next, struct mem_fragment, ++ list); ++ } ++ } ++ *match = 0; ++ return 0; ++} ++ ++static int check_mmap_resource(struct resource *res, struct vm_area_struct *vma, ++ int *match, unsigned long *pfn) ++{ ++ *pfn = res->start >> PAGE_SHIFT; ++ if (*pfn == vma->vm_pgoff) { ++ *match = 1; ++ if ((vma->vm_end - vma->vm_start) != resource_size(res)) ++ return -EINVAL; ++ } else ++ *match = 0; ++ return 0; ++} ++ ++static int check_mmap_portal(struct ctx *ctx, struct vm_area_struct *vma, ++ int *match, unsigned long *pfn) ++{ ++ struct portal_mapping *portal; ++ int ret; ++ ++ list_for_each_entry(portal, &ctx->portals, list) { ++ ret = check_mmap_resource(&portal->phys[DPA_PORTAL_CE], vma, ++ match, pfn); ++ if (*match) { ++ vma->vm_page_prot = ++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) ++ pgprot_cached_ns(vma->vm_page_prot); ++#else ++ pgprot_cached_noncoherent(vma->vm_page_prot); ++#endif ++ return ret; ++ } ++ ret = check_mmap_resource(&portal->phys[DPA_PORTAL_CI], vma, ++ match, pfn); ++ if (*match) { ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ return ret; ++ } ++ } ++ *match = 0; ++ return 0; ++} ++ ++static int usdpaa_mmap(struct file *filp, struct vm_area_struct *vma) ++{ ++ struct ctx *ctx = filp->private_data; ++ unsigned long pfn = 0; ++ int match, ret; ++ ++ spin_lock(&mem_lock); ++ ret = check_mmap_dma(ctx, vma, &match, &pfn); ++ if (!match) ++ ret = check_mmap_portal(ctx, vma, &match, &pfn); ++ spin_unlock(&mem_lock); ++ if (!match) ++ return -EINVAL; ++ if (!ret) ++ ret = remap_pfn_range(vma, vma->vm_start, pfn, ++ vma->vm_end - vma->vm_start, ++ vma->vm_page_prot); ++ return ret; ++} ++ ++/* Return the nearest rounded-up address >= 'addr' that is 'sz'-aligned. 'sz' ++ * must be a power of 2, but both 'addr' and 'sz' can be expressions. */ ++#define USDPAA_MEM_ROUNDUP(addr, sz) \ ++ ({ \ ++ unsigned long foo_align = (sz) - 1; \ ++ ((addr) + foo_align) & ~foo_align; \ ++ }) ++/* Searching for a size-aligned virtual address range starting from 'addr' */ ++static unsigned long usdpaa_get_unmapped_area(struct file *file, ++ unsigned long addr, ++ unsigned long len, ++ unsigned long pgoff, ++ unsigned long flags) ++{ ++ struct vm_area_struct *vma; ++ ++ if (len % PAGE_SIZE) ++ return -EINVAL; ++ if (!len) ++ return -EINVAL; ++ ++ /* Need to align the address to the largest pagesize of the mapping ++ * because the MMU requires the virtual address to have the same ++ * alignment as the physical address */ ++ addr = USDPAA_MEM_ROUNDUP(addr, largest_page_size(len)); ++ vma = find_vma(current->mm, addr); ++ /* Keep searching until we reach the end of currently-used virtual ++ * address-space or we find a big enough gap. */ ++ while (vma) { ++ if ((addr + len) < vma->vm_start) ++ return addr; ++ ++ addr = USDPAA_MEM_ROUNDUP(vma->vm_end, largest_page_size(len)); ++ vma = vma->vm_next; ++ } ++ if ((TASK_SIZE - len) < addr) ++ return -ENOMEM; ++ return addr; ++} ++ ++static long ioctl_id_alloc(struct ctx *ctx, void __user *arg) ++{ ++ struct usdpaa_ioctl_id_alloc i; ++ const struct alloc_backend *backend; ++ struct active_resource *res; ++ int ret = copy_from_user(&i, arg, sizeof(i)); ++ if (ret) ++ return ret; ++ if ((i.id_type >= usdpaa_id_max) || !i.num) ++ return -EINVAL; ++ backend = &alloc_backends[i.id_type]; ++ /* Allocate the required resource type */ ++ ret = backend->alloc(&i.base, i.num, i.align, i.partial); ++ if (ret < 0) ++ return ret; ++ i.num = ret; ++ /* Copy the result to user-space */ ++ ret = copy_to_user(arg, &i, sizeof(i)); ++ if (ret) { ++ backend->release(i.base, i.num); ++ return ret; ++ } ++ /* Assign the allocated range to the FD accounting */ ++ res = kmalloc(sizeof(*res), GFP_KERNEL); ++ if (!res) { ++ backend->release(i.base, i.num); ++ return -ENOMEM; ++ } ++ spin_lock(&ctx->lock); ++ res->id = i.base; ++ res->num = i.num; ++ res->refcount = 1; ++ list_add(&res->list, &ctx->resources[i.id_type]); ++ spin_unlock(&ctx->lock); ++ return 0; ++} ++ ++static long ioctl_id_release(struct ctx *ctx, void __user *arg) ++{ ++ struct usdpaa_ioctl_id_release i; ++ const struct alloc_backend *backend; ++ struct active_resource *tmp, *pos; ++ ++ int ret = copy_from_user(&i, arg, sizeof(i)); ++ if (ret) ++ return ret; ++ if ((i.id_type >= usdpaa_id_max) || !i.num) ++ return -EINVAL; ++ backend = &alloc_backends[i.id_type]; ++ /* Pull the range out of the FD accounting - the range is valid iff this ++ * succeeds. */ ++ spin_lock(&ctx->lock); ++ list_for_each_entry_safe(pos, tmp, &ctx->resources[i.id_type], list) { ++ if (pos->id == i.base && pos->num == i.num) { ++ pos->refcount--; ++ if (pos->refcount) { ++ spin_unlock(&ctx->lock); ++ return 0; /* Still being used */ ++ } ++ list_del(&pos->list); ++ kfree(pos); ++ spin_unlock(&ctx->lock); ++ goto found; ++ } ++ } ++ /* Failed to find the resource */ ++ spin_unlock(&ctx->lock); ++ pr_err("Couldn't find resource type %d base 0x%x num %d\n", ++ i.id_type, i.base, i.num); ++ return -EINVAL; ++found: ++ /* Release the resource to the backend */ ++ backend->release(i.base, i.num); ++ return 0; ++} ++ ++static long ioctl_id_reserve(struct ctx *ctx, void __user *arg) ++{ ++ struct usdpaa_ioctl_id_reserve i; ++ const struct alloc_backend *backend; ++ struct active_resource *tmp, *pos; ++ ++ int ret = copy_from_user(&i, arg, sizeof(i)); ++ if (ret) ++ return ret; ++ if ((i.id_type >= usdpaa_id_max) || !i.num) ++ return -EINVAL; ++ backend = &alloc_backends[i.id_type]; ++ if (!backend->reserve) ++ return -EINVAL; ++ /* Pull the range out of the FD accounting - the range is valid iff this ++ * succeeds. */ ++ spin_lock(&ctx->lock); ++ list_for_each_entry_safe(pos, tmp, &ctx->resources[i.id_type], list) { ++ if (pos->id == i.base && pos->num == i.num) { ++ pos->refcount++; ++ spin_unlock(&ctx->lock); ++ return 0; ++ } ++ } ++ ++ /* Failed to find the resource */ ++ spin_unlock(&ctx->lock); ++ ++ /* Reserve the resource in the backend */ ++ ret = backend->reserve(i.base, i.num); ++ if (ret) ++ return ret; ++ /* Assign the reserved range to the FD accounting */ ++ pos = kmalloc(sizeof(*pos), GFP_KERNEL); ++ if (!pos) { ++ backend->release(i.base, i.num); ++ return -ENOMEM; ++ } ++ spin_lock(&ctx->lock); ++ pos->id = i.base; ++ pos->num = i.num; ++ pos->refcount = 1; ++ list_add(&pos->list, &ctx->resources[i.id_type]); ++ spin_unlock(&ctx->lock); ++ return 0; ++} ++ ++static long ioctl_dma_map(struct file *fp, struct ctx *ctx, ++ struct usdpaa_ioctl_dma_map *i) ++{ ++ struct mem_fragment *frag, *start_frag, *next_frag; ++ struct mem_mapping *map, *tmp; ++ int ret = 0; ++ u32 largest_page, so_far = 0; ++ int frag_count = 0; ++ unsigned long next_addr = PAGE_SIZE, populate; ++ ++ /* error checking to ensure values copied from user space are valid */ ++ if (i->len % PAGE_SIZE) ++ return -EINVAL; ++ ++ map = kmalloc(sizeof(*map), GFP_KERNEL); ++ if (!map) ++ return -ENOMEM; ++ ++ spin_lock(&mem_lock); ++ if (i->flags & USDPAA_DMA_FLAG_SHARE) { ++ list_for_each_entry(frag, &mem_list, list) { ++ if (frag->refs && (frag->flags & ++ USDPAA_DMA_FLAG_SHARE) && ++ !strncmp(i->name, frag->name, ++ USDPAA_DMA_NAME_MAX)) { ++ /* Matching entry */ ++ if ((i->flags & USDPAA_DMA_FLAG_CREATE) && ++ !(i->flags & USDPAA_DMA_FLAG_LAZY)) { ++ ret = -EBUSY; ++ goto out; ++ } ++ ++ /* Check to ensure size matches record */ ++ if (i->len != frag->map_len && i->len) { ++ pr_err("ioctl_dma_map() Size requested does not match %s and is none zero\n", ++ frag->name); ++ return -EINVAL; ++ } ++ ++ /* Check if this has already been mapped ++ to this process */ ++ list_for_each_entry(tmp, &ctx->maps, list) ++ if (tmp->root_frag == frag) { ++ /* Already mapped, just need to ++ inc ref count */ ++ tmp->refs++; ++ kfree(map); ++ i->did_create = 0; ++ i->len = tmp->total_size; ++ i->phys_addr = frag->base; ++ i->ptr = tmp->virt_addr; ++ spin_unlock(&mem_lock); ++ return 0; ++ } ++ /* Matching entry - just need to map */ ++ i->has_locking = frag->has_locking; ++ i->did_create = 0; ++ i->len = frag->map_len; ++ start_frag = frag; ++ goto do_map; ++ } ++ } ++ /* No matching entry */ ++ if (!(i->flags & USDPAA_DMA_FLAG_CREATE)) { ++ pr_err("ioctl_dma_map() No matching entry\n"); ++ ret = -ENOMEM; ++ goto out; ++ } ++ } ++ /* New fragment required, size must be provided. */ ++ if (!i->len) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ /* Find one of more contiguous fragments that satisfy the total length ++ trying to minimize the number of fragments ++ compute the largest page size that the allocation could use */ ++ largest_page = largest_page_size(i->len); ++ start_frag = NULL; ++ while (largest_page && ++ largest_page <= largest_page_size(phys_size) && ++ start_frag == NULL) { ++ /* Search the list for a frag of that size */ ++ list_for_each_entry(frag, &mem_list, list) { ++ if (!frag->refs && (frag->len == largest_page)) { ++ /* See if the next x fragments are free ++ and can accomidate the size */ ++ u32 found_size = largest_page; ++ next_frag = list_entry(frag->list.prev, ++ struct mem_fragment, ++ list); ++ /* If the fragement is too small check ++ if the neighbours cab support it */ ++ while (found_size < i->len) { ++ if (&mem_list == &next_frag->list) ++ break; /* End of list */ ++ if (next_frag->refs != 0 || ++ next_frag->len == 0) ++ break; /* not enough space */ ++ found_size += next_frag->len; ++ next_frag = list_entry( ++ next_frag->list.prev, ++ struct mem_fragment, ++ list); ++ } ++ if (found_size >= i->len) { ++ /* Success! there is enough contigous ++ free space */ ++ start_frag = frag; ++ break; ++ } ++ } ++ } /* next frag loop */ ++ /* Couldn't statisfy the request with this ++ largest page size, try a smaller one */ ++ largest_page <<= 2; ++ } ++ if (start_frag == NULL) { ++ /* Couldn't find proper amount of space */ ++ ret = -ENOMEM; ++ goto out; ++ } ++ i->did_create = 1; ++do_map: ++ /* Verify there is sufficient space to do the mapping */ ++ down_write(¤t->mm->mmap_sem); ++ next_addr = usdpaa_get_unmapped_area(fp, next_addr, i->len, 0, 0); ++ up_write(¤t->mm->mmap_sem); ++ ++ if (next_addr & ~PAGE_MASK) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ /* We may need to divide the final fragment to accomidate the mapping */ ++ next_frag = start_frag; ++ while (so_far != i->len) { ++ BUG_ON(next_frag->len == 0); ++ while ((next_frag->len + so_far) > i->len) { ++ /* Split frag until they match */ ++ split_frag(next_frag); ++ } ++ so_far += next_frag->len; ++ next_frag->refs++; ++ ++frag_count; ++ next_frag = list_entry(next_frag->list.prev, ++ struct mem_fragment, list); ++ } ++ if (i->did_create) { ++ size_t name_len = 0; ++ start_frag->flags = i->flags; ++ strncpy(start_frag->name, i->name, USDPAA_DMA_NAME_MAX); ++ name_len = strnlen(start_frag->name, USDPAA_DMA_NAME_MAX); ++ if (name_len >= USDPAA_DMA_NAME_MAX) { ++ ret = -EFAULT; ++ goto out; ++ } ++ start_frag->map_len = i->len; ++ start_frag->has_locking = i->has_locking; ++ init_waitqueue_head(&start_frag->wq); ++ start_frag->owner = NULL; ++ } ++ ++ /* Setup the map entry */ ++ map->root_frag = start_frag; ++ map->total_size = i->len; ++ map->frag_count = frag_count; ++ map->refs = 1; ++ list_add(&map->list, &ctx->maps); ++ i->phys_addr = start_frag->base; ++out: ++ spin_unlock(&mem_lock); ++ ++ if (!ret) { ++ unsigned long longret; ++ down_write(¤t->mm->mmap_sem); ++ longret = do_mmap_pgoff(fp, next_addr, map->total_size, ++ PROT_READ | ++ (i->flags & ++ USDPAA_DMA_FLAG_RDONLY ? 0 ++ : PROT_WRITE), ++ MAP_SHARED, ++ start_frag->pfn_base, ++ &populate); ++ up_write(¤t->mm->mmap_sem); ++ if (longret & ~PAGE_MASK) { ++ ret = (int)longret; ++ } else { ++ i->ptr = (void *)longret; ++ map->virt_addr = i->ptr; ++ } ++ } else ++ kfree(map); ++ return ret; ++} ++ ++static long ioctl_dma_unmap(struct ctx *ctx, void __user *arg) ++{ ++ struct mem_mapping *map; ++ struct vm_area_struct *vma; ++ int ret, i; ++ struct mem_fragment *current_frag; ++ size_t sz; ++ unsigned long base; ++ unsigned long vaddr; ++ ++ down_write(¤t->mm->mmap_sem); ++ vma = find_vma(current->mm, (unsigned long)arg); ++ if (!vma || (vma->vm_start > (unsigned long)arg)) { ++ up_write(¤t->mm->mmap_sem); ++ return -EFAULT; ++ } ++ spin_lock(&mem_lock); ++ list_for_each_entry(map, &ctx->maps, list) { ++ if (map->root_frag->pfn_base == vma->vm_pgoff) { ++ /* Drop the map lock if we hold it */ ++ if (map->root_frag->has_locking && ++ (map->root_frag->owner == map)) { ++ map->root_frag->owner = NULL; ++ wake_up(&map->root_frag->wq); ++ } ++ goto map_match; ++ } ++ } ++ /* Failed to find a matching mapping for this process */ ++ ret = -EFAULT; ++ spin_unlock(&mem_lock); ++ goto out; ++map_match: ++ map->refs--; ++ if (map->refs != 0) { ++ /* Another call the dma_map is referencing this */ ++ ret = 0; ++ spin_unlock(&mem_lock); ++ goto out; ++ } ++ ++ current_frag = map->root_frag; ++ vaddr = (unsigned long) map->virt_addr; ++ for (i = 0; i < map->frag_count; i++) { ++ DPA_ASSERT(current_frag->refs > 0); ++ --current_frag->refs; ++#if !(defined(CONFIG_ARM) || defined(CONFIG_ARM64)) ++ /* ++ * Make sure we invalidate the TLB entry for ++ * this fragment, otherwise a remap of a different ++ * page to this vaddr would give acces to an ++ * incorrect piece of memory ++ */ ++ cleartlbcam(vaddr, mfspr(SPRN_PID)); ++#endif ++ vaddr += current_frag->len; ++ current_frag = list_entry(current_frag->list.prev, ++ struct mem_fragment, list); ++ } ++ map->root_frag->name[0] = 0; ++ list_del(&map->list); ++ compress_frags(); ++ spin_unlock(&mem_lock); ++ ++ base = vma->vm_start; ++ sz = vma->vm_end - vma->vm_start; ++ do_munmap(current->mm, base, sz); ++ ret = 0; ++ out: ++ up_write(¤t->mm->mmap_sem); ++ return ret; ++} ++ ++static long ioctl_dma_stats(struct ctx *ctx, void __user *arg) ++{ ++ struct mem_fragment *frag; ++ struct usdpaa_ioctl_dma_used result; ++ ++ result.free_bytes = 0; ++ result.total_bytes = phys_size; ++ ++ list_for_each_entry(frag, &mem_list, list) { ++ if (frag->refs == 0) ++ result.free_bytes += frag->len; ++ } ++ ++ return copy_to_user(arg, &result, sizeof(result)); } ++ ++static int test_lock(struct mem_mapping *map) ++{ ++ int ret = 0; ++ spin_lock(&mem_lock); ++ if (!map->root_frag->owner) { ++ map->root_frag->owner = map; ++ ret = 1; ++ } ++ spin_unlock(&mem_lock); ++ return ret; ++} ++ ++static long ioctl_dma_lock(struct ctx *ctx, void __user *arg) ++{ ++ struct mem_mapping *map; ++ struct vm_area_struct *vma; ++ ++ down_read(¤t->mm->mmap_sem); ++ vma = find_vma(current->mm, (unsigned long)arg); ++ if (!vma || (vma->vm_start > (unsigned long)arg)) { ++ up_read(¤t->mm->mmap_sem); ++ return -EFAULT; ++ } ++ spin_lock(&mem_lock); ++ list_for_each_entry(map, &ctx->maps, list) { ++ if (map->root_frag->pfn_base == vma->vm_pgoff) ++ goto map_match; ++ } ++ map = NULL; ++map_match: ++ spin_unlock(&mem_lock); ++ up_read(¤t->mm->mmap_sem); ++ ++ if (!map) ++ return -EFAULT; ++ if (!map->root_frag->has_locking) ++ return -ENODEV; ++ return wait_event_interruptible(map->root_frag->wq, test_lock(map)); ++} ++ ++static long ioctl_dma_unlock(struct ctx *ctx, void __user *arg) ++{ ++ struct mem_mapping *map; ++ struct vm_area_struct *vma; ++ int ret; ++ ++ down_read(¤t->mm->mmap_sem); ++ vma = find_vma(current->mm, (unsigned long)arg); ++ if (!vma || (vma->vm_start > (unsigned long)arg)) ++ ret = -EFAULT; ++ else { ++ spin_lock(&mem_lock); ++ list_for_each_entry(map, &ctx->maps, list) { ++ if (map->root_frag->pfn_base == vma->vm_pgoff) { ++ if (!map->root_frag->has_locking) ++ ret = -ENODEV; ++ else if (map->root_frag->owner == map) { ++ map->root_frag->owner = NULL; ++ wake_up(&map->root_frag->wq); ++ ret = 0; ++ } else ++ ret = -EBUSY; ++ goto map_match; ++ } ++ } ++ ret = -EINVAL; ++map_match: ++ spin_unlock(&mem_lock); ++ } ++ up_read(¤t->mm->mmap_sem); ++ return ret; ++} ++ ++static int portal_mmap(struct file *fp, struct resource *res, void **ptr) ++{ ++ unsigned long longret = 0, populate; ++ resource_size_t len; ++ ++ down_write(¤t->mm->mmap_sem); ++ len = resource_size(res); ++ if (len != (unsigned long)len) ++ return -EINVAL; ++ longret = do_mmap_pgoff(fp, PAGE_SIZE, (unsigned long)len, ++ PROT_READ | PROT_WRITE, MAP_SHARED, ++ res->start >> PAGE_SHIFT, &populate); ++ up_write(¤t->mm->mmap_sem); ++ ++ if (longret & ~PAGE_MASK) ++ return (int)longret; ++ ++ *ptr = (void *) longret; ++ return 0; ++} ++ ++static void portal_munmap(struct resource *res, void *ptr) ++{ ++ down_write(¤t->mm->mmap_sem); ++ do_munmap(current->mm, (unsigned long)ptr, resource_size(res)); ++ up_write(¤t->mm->mmap_sem); ++} ++ ++static long ioctl_portal_map(struct file *fp, struct ctx *ctx, ++ struct usdpaa_ioctl_portal_map *arg) ++{ ++ struct portal_mapping *mapping = kmalloc(sizeof(*mapping), GFP_KERNEL); ++ int ret; ++ ++ if (!mapping) ++ return -ENOMEM; ++ ++ mapping->user = *arg; ++ mapping->iommu_domain = NULL; ++ ++ if (mapping->user.type == usdpaa_portal_qman) { ++ mapping->qportal = ++ qm_get_unused_portal_idx(mapping->user.index); ++ if (!mapping->qportal) { ++ ret = -ENODEV; ++ goto err_get_portal; ++ } ++ mapping->phys = &mapping->qportal->addr_phys[0]; ++ mapping->user.channel = mapping->qportal->public_cfg.channel; ++ mapping->user.pools = mapping->qportal->public_cfg.pools; ++ mapping->user.index = mapping->qportal->public_cfg.index; ++ } else if (mapping->user.type == usdpaa_portal_bman) { ++ mapping->bportal = ++ bm_get_unused_portal_idx(mapping->user.index); ++ if (!mapping->bportal) { ++ ret = -ENODEV; ++ goto err_get_portal; ++ } ++ mapping->phys = &mapping->bportal->addr_phys[0]; ++ mapping->user.index = mapping->bportal->public_cfg.index; ++ } else { ++ ret = -EINVAL; ++ goto err_copy_from_user; ++ } ++ /* Need to put pcfg in ctx's list before the mmaps because the mmap ++ * handlers look it up. */ ++ spin_lock(&mem_lock); ++ list_add(&mapping->list, &ctx->portals); ++ spin_unlock(&mem_lock); ++ ret = portal_mmap(fp, &mapping->phys[DPA_PORTAL_CE], ++ &mapping->user.addr.cena); ++ if (ret) ++ goto err_mmap_cena; ++ ret = portal_mmap(fp, &mapping->phys[DPA_PORTAL_CI], ++ &mapping->user.addr.cinh); ++ if (ret) ++ goto err_mmap_cinh; ++ *arg = mapping->user; ++ return ret; ++ ++err_mmap_cinh: ++ portal_munmap(&mapping->phys[DPA_PORTAL_CE], mapping->user.addr.cena); ++err_mmap_cena: ++ if ((mapping->user.type == usdpaa_portal_qman) && mapping->qportal) ++ qm_put_unused_portal(mapping->qportal); ++ else if ((mapping->user.type == usdpaa_portal_bman) && mapping->bportal) ++ bm_put_unused_portal(mapping->bportal); ++ spin_lock(&mem_lock); ++ list_del(&mapping->list); ++ spin_unlock(&mem_lock); ++err_get_portal: ++err_copy_from_user: ++ kfree(mapping); ++ return ret; ++} ++ ++static long ioctl_portal_unmap(struct ctx *ctx, struct usdpaa_portal_map *i) ++{ ++ struct portal_mapping *mapping; ++ struct vm_area_struct *vma; ++ unsigned long pfn; ++ u32 channel; ++ ++ /* Get the PFN corresponding to one of the virt addresses */ ++ down_read(¤t->mm->mmap_sem); ++ vma = find_vma(current->mm, (unsigned long)i->cinh); ++ if (!vma || (vma->vm_start > (unsigned long)i->cinh)) { ++ up_read(¤t->mm->mmap_sem); ++ return -EFAULT; ++ } ++ pfn = vma->vm_pgoff; ++ up_read(¤t->mm->mmap_sem); ++ ++ /* Find the corresponding portal */ ++ spin_lock(&mem_lock); ++ list_for_each_entry(mapping, &ctx->portals, list) { ++ if (pfn == (mapping->phys[DPA_PORTAL_CI].start >> PAGE_SHIFT)) ++ goto found; ++ } ++ mapping = NULL; ++found: ++ if (mapping) ++ list_del(&mapping->list); ++ spin_unlock(&mem_lock); ++ if (!mapping) ++ return -ENODEV; ++ portal_munmap(&mapping->phys[DPA_PORTAL_CI], mapping->user.addr.cinh); ++ portal_munmap(&mapping->phys[DPA_PORTAL_CE], mapping->user.addr.cena); ++ if (mapping->user.type == usdpaa_portal_qman) { ++ init_qm_portal(mapping->qportal, ++ &mapping->qman_portal_low); ++ ++ /* Tear down any FQs this portal is referencing */ ++ channel = mapping->qportal->public_cfg.channel; ++ qm_check_and_destroy_fqs(&mapping->qman_portal_low, ++ &channel, ++ check_portal_channel); ++ qm_put_unused_portal(mapping->qportal); ++ } else if (mapping->user.type == usdpaa_portal_bman) { ++ init_bm_portal(mapping->bportal, ++ &mapping->bman_portal_low); ++ bm_put_unused_portal(mapping->bportal); ++ } ++ kfree(mapping); ++ return 0; ++} ++ ++static void portal_config_pamu(struct qm_portal_config *pcfg, uint8_t sdest, ++ uint32_t cpu, uint32_t cache, uint32_t window) ++{ ++#ifdef CONFIG_FSL_PAMU ++ int ret; ++ int window_count = 1; ++ struct iommu_domain_geometry geom_attr; ++ struct pamu_stash_attribute stash_attr; ++ ++ pcfg->iommu_domain = iommu_domain_alloc(&platform_bus_type); ++ if (!pcfg->iommu_domain) { ++ pr_err(KBUILD_MODNAME ":%s(): iommu_domain_alloc() failed", ++ __func__); ++ goto _no_iommu; ++ } ++ geom_attr.aperture_start = 0; ++ geom_attr.aperture_end = ++ ((dma_addr_t)1 << min(8 * sizeof(dma_addr_t), (size_t)36)) - 1; ++ geom_attr.force_aperture = true; ++ ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_GEOMETRY, ++ &geom_attr); ++ if (ret < 0) { ++ pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d", ++ __func__, ret); ++ goto _iommu_domain_free; ++ } ++ ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_WINDOWS, ++ &window_count); ++ if (ret < 0) { ++ pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d", ++ __func__, ret); ++ goto _iommu_domain_free; ++ } ++ stash_attr.cpu = cpu; ++ stash_attr.cache = cache; ++ /* set stash information for the window */ ++ stash_attr.window = 0; ++ ++ ret = iommu_domain_set_attr(pcfg->iommu_domain, ++ DOMAIN_ATTR_FSL_PAMU_STASH, ++ &stash_attr); ++ if (ret < 0) { ++ pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d", ++ __func__, ret); ++ goto _iommu_domain_free; ++ } ++ ret = iommu_domain_window_enable(pcfg->iommu_domain, 0, 0, 1ULL << 36, ++ IOMMU_READ | IOMMU_WRITE); ++ if (ret < 0) { ++ pr_err(KBUILD_MODNAME ":%s(): iommu_domain_window_enable() = %d", ++ __func__, ret); ++ goto _iommu_domain_free; ++ } ++ ret = iommu_attach_device(pcfg->iommu_domain, &pcfg->dev); ++ if (ret < 0) { ++ pr_err(KBUILD_MODNAME ":%s(): iommu_device_attach() = %d", ++ __func__, ret); ++ goto _iommu_domain_free; ++ } ++ ret = iommu_domain_set_attr(pcfg->iommu_domain, ++ DOMAIN_ATTR_FSL_PAMU_ENABLE, ++ &window_count); ++ if (ret < 0) { ++ pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d", ++ __func__, ret); ++ goto _iommu_detach_device; ++ } ++_no_iommu: ++#endif ++ ++#ifdef CONFIG_FSL_QMAN_CONFIG ++ if (qman_set_sdest(pcfg->public_cfg.channel, sdest)) ++#endif ++ pr_warn("Failed to set QMan portal's stash request queue\n"); ++ ++ return; ++ ++#ifdef CONFIG_FSL_PAMU ++_iommu_detach_device: ++ iommu_detach_device(pcfg->iommu_domain, NULL); ++_iommu_domain_free: ++ iommu_domain_free(pcfg->iommu_domain); ++#endif ++} ++ ++static long ioctl_allocate_raw_portal(struct file *fp, struct ctx *ctx, ++ struct usdpaa_ioctl_raw_portal *arg) ++{ ++ struct portal_mapping *mapping = kmalloc(sizeof(*mapping), GFP_KERNEL); ++ int ret; ++ ++ if (!mapping) ++ return -ENOMEM; ++ ++ mapping->user.type = arg->type; ++ mapping->iommu_domain = NULL; ++ if (arg->type == usdpaa_portal_qman) { ++ mapping->qportal = qm_get_unused_portal_idx(arg->index); ++ if (!mapping->qportal) { ++ ret = -ENODEV; ++ goto err; ++ } ++ mapping->phys = &mapping->qportal->addr_phys[0]; ++ arg->index = mapping->qportal->public_cfg.index; ++ arg->cinh = mapping->qportal->addr_phys[DPA_PORTAL_CI].start; ++ arg->cena = mapping->qportal->addr_phys[DPA_PORTAL_CE].start; ++ if (arg->enable_stash) { ++ /* Setup the PAMU with the supplied parameters */ ++ portal_config_pamu(mapping->qportal, arg->sdest, ++ arg->cpu, arg->cache, arg->window); ++ } ++ } else if (mapping->user.type == usdpaa_portal_bman) { ++ mapping->bportal = ++ bm_get_unused_portal_idx(arg->index); ++ if (!mapping->bportal) { ++ ret = -ENODEV; ++ goto err; ++ } ++ mapping->phys = &mapping->bportal->addr_phys[0]; ++ arg->index = mapping->bportal->public_cfg.index; ++ arg->cinh = mapping->bportal->addr_phys[DPA_PORTAL_CI].start; ++ arg->cena = mapping->bportal->addr_phys[DPA_PORTAL_CE].start; ++ } else { ++ ret = -EINVAL; ++ goto err; ++ } ++ /* Need to put pcfg in ctx's list before the mmaps because the mmap ++ * handlers look it up. */ ++ spin_lock(&mem_lock); ++ list_add(&mapping->list, &ctx->portals); ++ spin_unlock(&mem_lock); ++ return 0; ++err: ++ kfree(mapping); ++ return ret; ++} ++ ++static long ioctl_free_raw_portal(struct file *fp, struct ctx *ctx, ++ struct usdpaa_ioctl_raw_portal *arg) ++{ ++ struct portal_mapping *mapping; ++ u32 channel; ++ ++ /* Find the corresponding portal */ ++ spin_lock(&mem_lock); ++ list_for_each_entry(mapping, &ctx->portals, list) { ++ if (mapping->phys[DPA_PORTAL_CI].start == arg->cinh) ++ goto found; ++ } ++ mapping = NULL; ++found: ++ if (mapping) ++ list_del(&mapping->list); ++ spin_unlock(&mem_lock); ++ if (!mapping) ++ return -ENODEV; ++ if (mapping->user.type == usdpaa_portal_qman) { ++ init_qm_portal(mapping->qportal, ++ &mapping->qman_portal_low); ++ ++ /* Tear down any FQs this portal is referencing */ ++ channel = mapping->qportal->public_cfg.channel; ++ qm_check_and_destroy_fqs(&mapping->qman_portal_low, ++ &channel, ++ check_portal_channel); ++ qm_put_unused_portal(mapping->qportal); ++ } else if (mapping->user.type == usdpaa_portal_bman) { ++ init_bm_portal(mapping->bportal, ++ &mapping->bman_portal_low); ++ bm_put_unused_portal(mapping->bportal); ++ } ++ kfree(mapping); ++ return 0; ++} ++ ++static long usdpaa_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) ++{ ++ struct ctx *ctx = fp->private_data; ++ void __user *a = (void __user *)arg; ++ switch (cmd) { ++ case USDPAA_IOCTL_ID_ALLOC: ++ return ioctl_id_alloc(ctx, a); ++ case USDPAA_IOCTL_ID_RELEASE: ++ return ioctl_id_release(ctx, a); ++ case USDPAA_IOCTL_ID_RESERVE: ++ return ioctl_id_reserve(ctx, a); ++ case USDPAA_IOCTL_DMA_MAP: ++ { ++ struct usdpaa_ioctl_dma_map input; ++ int ret; ++ if (copy_from_user(&input, a, sizeof(input))) ++ return -EFAULT; ++ ret = ioctl_dma_map(fp, ctx, &input); ++ if (copy_to_user(a, &input, sizeof(input))) ++ return -EFAULT; ++ return ret; ++ } ++ case USDPAA_IOCTL_DMA_UNMAP: ++ return ioctl_dma_unmap(ctx, a); ++ case USDPAA_IOCTL_DMA_LOCK: ++ return ioctl_dma_lock(ctx, a); ++ case USDPAA_IOCTL_DMA_UNLOCK: ++ return ioctl_dma_unlock(ctx, a); ++ case USDPAA_IOCTL_PORTAL_MAP: ++ { ++ struct usdpaa_ioctl_portal_map input; ++ int ret; ++ if (copy_from_user(&input, a, sizeof(input))) ++ return -EFAULT; ++ ret = ioctl_portal_map(fp, ctx, &input); ++ if (copy_to_user(a, &input, sizeof(input))) ++ return -EFAULT; ++ return ret; ++ } ++ case USDPAA_IOCTL_PORTAL_UNMAP: ++ { ++ struct usdpaa_portal_map input; ++ if (copy_from_user(&input, a, sizeof(input))) ++ return -EFAULT; ++ return ioctl_portal_unmap(ctx, &input); ++ } ++ case USDPAA_IOCTL_DMA_USED: ++ return ioctl_dma_stats(ctx, a); ++ case USDPAA_IOCTL_ALLOC_RAW_PORTAL: ++ { ++ struct usdpaa_ioctl_raw_portal input; ++ int ret; ++ if (copy_from_user(&input, a, sizeof(input))) ++ return -EFAULT; ++ ret = ioctl_allocate_raw_portal(fp, ctx, &input); ++ if (copy_to_user(a, &input, sizeof(input))) ++ return -EFAULT; ++ return ret; ++ } ++ case USDPAA_IOCTL_FREE_RAW_PORTAL: ++ { ++ struct usdpaa_ioctl_raw_portal input; ++ if (copy_from_user(&input, a, sizeof(input))) ++ return -EFAULT; ++ return ioctl_free_raw_portal(fp, ctx, &input); ++ } ++ } ++ return -EINVAL; ++} ++ ++static long usdpaa_ioctl_compat(struct file *fp, unsigned int cmd, ++ unsigned long arg) ++{ ++#ifdef CONFIG_COMPAT ++ struct ctx *ctx = fp->private_data; ++ void __user *a = (void __user *)arg; ++#endif ++ switch (cmd) { ++#ifdef CONFIG_COMPAT ++ case USDPAA_IOCTL_DMA_MAP_COMPAT: ++ { ++ int ret; ++ struct usdpaa_ioctl_dma_map_compat input; ++ struct usdpaa_ioctl_dma_map converted; ++ ++ if (copy_from_user(&input, a, sizeof(input))) ++ return -EFAULT; ++ ++ converted.ptr = compat_ptr(input.ptr); ++ converted.phys_addr = input.phys_addr; ++ converted.len = input.len; ++ converted.flags = input.flags; ++ strncpy(converted.name, input.name, USDPAA_DMA_NAME_MAX); ++ converted.has_locking = input.has_locking; ++ converted.did_create = input.did_create; ++ ++ ret = ioctl_dma_map(fp, ctx, &converted); ++ input.ptr = ptr_to_compat(converted.ptr); ++ input.phys_addr = converted.phys_addr; ++ input.len = converted.len; ++ input.flags = converted.flags; ++ strncpy(input.name, converted.name, USDPAA_DMA_NAME_MAX); ++ input.has_locking = converted.has_locking; ++ input.did_create = converted.did_create; ++ if (copy_to_user(a, &input, sizeof(input))) ++ return -EFAULT; ++ return ret; ++ } ++ case USDPAA_IOCTL_PORTAL_MAP_COMPAT: ++ { ++ int ret; ++ struct compat_usdpaa_ioctl_portal_map input; ++ struct usdpaa_ioctl_portal_map converted; ++ if (copy_from_user(&input, a, sizeof(input))) ++ return -EFAULT; ++ converted.type = input.type; ++ converted.index = input.index; ++ ret = ioctl_portal_map(fp, ctx, &converted); ++ input.addr.cinh = ptr_to_compat(converted.addr.cinh); ++ input.addr.cena = ptr_to_compat(converted.addr.cena); ++ input.channel = converted.channel; ++ input.pools = converted.pools; ++ input.index = converted.index; ++ if (copy_to_user(a, &input, sizeof(input))) ++ return -EFAULT; ++ return ret; ++ } ++ case USDPAA_IOCTL_PORTAL_UNMAP_COMPAT: ++ { ++ struct usdpaa_portal_map_compat input; ++ struct usdpaa_portal_map converted; ++ ++ if (copy_from_user(&input, a, sizeof(input))) ++ return -EFAULT; ++ converted.cinh = compat_ptr(input.cinh); ++ converted.cena = compat_ptr(input.cena); ++ return ioctl_portal_unmap(ctx, &converted); ++ } ++ case USDPAA_IOCTL_ALLOC_RAW_PORTAL_COMPAT: ++ { ++ int ret; ++ struct usdpaa_ioctl_raw_portal converted; ++ struct compat_ioctl_raw_portal input; ++ if (copy_from_user(&input, a, sizeof(input))) ++ return -EFAULT; ++ converted.type = input.type; ++ converted.index = input.index; ++ converted.enable_stash = input.enable_stash; ++ converted.cpu = input.cpu; ++ converted.cache = input.cache; ++ converted.window = input.window; ++ converted.sdest = input.sdest; ++ ret = ioctl_allocate_raw_portal(fp, ctx, &converted); ++ ++ input.cinh = converted.cinh; ++ input.cena = converted.cena; ++ input.index = converted.index; ++ ++ if (copy_to_user(a, &input, sizeof(input))) ++ return -EFAULT; ++ return ret; ++ } ++ case USDPAA_IOCTL_FREE_RAW_PORTAL_COMPAT: ++ { ++ struct usdpaa_ioctl_raw_portal converted; ++ struct compat_ioctl_raw_portal input; ++ if (copy_from_user(&input, a, sizeof(input))) ++ return -EFAULT; ++ converted.type = input.type; ++ converted.index = input.index; ++ converted.cinh = input.cinh; ++ converted.cena = input.cena; ++ return ioctl_free_raw_portal(fp, ctx, &converted); ++ } ++#endif ++ default: ++ return usdpaa_ioctl(fp, cmd, arg); ++ } ++ return -EINVAL; ++} ++ ++int usdpaa_get_portal_config(struct file *filp, void *cinh, ++ enum usdpaa_portal_type ptype, unsigned int *irq, ++ void **iir_reg) ++{ ++ /* Walk the list of portals for filp and return the config ++ for the portal that matches the hint */ ++ struct ctx *context; ++ struct portal_mapping *portal; ++ ++ /* First sanitize the filp */ ++ if (filp->f_op->open != usdpaa_open) ++ return -ENODEV; ++ context = filp->private_data; ++ spin_lock(&context->lock); ++ list_for_each_entry(portal, &context->portals, list) { ++ if (portal->user.type == ptype && ++ portal->user.addr.cinh == cinh) { ++ if (ptype == usdpaa_portal_qman) { ++ *irq = portal->qportal->public_cfg.irq; ++ *iir_reg = portal->qportal->addr_virt[1] + ++ QM_REG_IIR; ++ } else { ++ *irq = portal->bportal->public_cfg.irq; ++ *iir_reg = portal->bportal->addr_virt[1] + ++ BM_REG_IIR; ++ } ++ spin_unlock(&context->lock); ++ return 0; ++ } ++ } ++ spin_unlock(&context->lock); ++ return -EINVAL; ++} ++ ++static const struct file_operations usdpaa_fops = { ++ .open = usdpaa_open, ++ .release = usdpaa_release, ++ .mmap = usdpaa_mmap, ++ .get_unmapped_area = usdpaa_get_unmapped_area, ++ .unlocked_ioctl = usdpaa_ioctl, ++ .compat_ioctl = usdpaa_ioctl_compat ++}; ++ ++static struct miscdevice usdpaa_miscdev = { ++ .name = "fsl-usdpaa", ++ .fops = &usdpaa_fops, ++ .minor = MISC_DYNAMIC_MINOR, ++}; ++ ++/* Early-boot memory allocation. The boot-arg "usdpaa_mem=" is used to ++ * indicate how much memory (if any) to allocate during early boot. If the ++ * format "usdpaa_mem=," is used, then will be interpreted as the ++ * number of TLB1 entries to reserve (default is 1). If there are more mappings ++ * than there are TLB1 entries, fault-handling will occur. */ ++ ++static __init int usdpaa_mem(char *arg) ++{ ++ pr_warn("uspdaa_mem argument is depracated\n"); ++ arg_phys_size = memparse(arg, &arg); ++ num_tlb = 1; ++ if (*arg == ',') { ++ unsigned long ul; ++ int err = kstrtoul(arg + 1, 0, &ul); ++ if (err < 0) { ++ num_tlb = 1; ++ pr_warn("ERROR, usdpaa_mem arg is invalid\n"); ++ } else ++ num_tlb = (unsigned int)ul; ++ } ++ return 0; ++} ++early_param("usdpaa_mem", usdpaa_mem); ++ ++static int usdpaa_mem_init(struct reserved_mem *rmem) ++{ ++ phys_start = rmem->base; ++ phys_size = rmem->size; ++ ++ WARN_ON(!(phys_start && phys_size)); ++ ++ return 0; ++} ++RESERVEDMEM_OF_DECLARE(usdpaa_mem_init, "fsl,usdpaa-mem", usdpaa_mem_init); ++ ++__init int fsl_usdpaa_init_early(void) ++{ ++ if (!phys_size || !phys_start) { ++ pr_info("No USDPAA memory, no 'fsl,usdpaa-mem' in device-tree\n"); ++ return 0; ++ } ++ if (phys_size % PAGE_SIZE) { ++ pr_err("'fsl,usdpaa-mem' size must be a multiple of page size\n"); ++ phys_size = 0; ++ return 0; ++ } ++ if (arg_phys_size && phys_size != arg_phys_size) { ++ pr_err("'usdpaa_mem argument size (0x%llx) does not match device tree size (0x%llx)\n", ++ arg_phys_size, phys_size); ++ phys_size = 0; ++ return 0; ++ } ++ pfn_start = phys_start >> PAGE_SHIFT; ++ pfn_size = phys_size >> PAGE_SHIFT; ++#ifdef CONFIG_PPC ++ first_tlb = current_tlb = tlbcam_index; ++ tlbcam_index += num_tlb; ++#endif ++ pr_info("USDPAA region at %llx:%llx(%lx:%lx), %d TLB1 entries)\n", ++ phys_start, phys_size, pfn_start, pfn_size, num_tlb); ++ return 0; ++} ++subsys_initcall(fsl_usdpaa_init_early); ++ ++ ++static int __init usdpaa_init(void) ++{ ++ struct mem_fragment *frag; ++ int ret; ++ u64 tmp_size = phys_size; ++ u64 tmp_start = phys_start; ++ u64 tmp_pfn_size = pfn_size; ++ u64 tmp_pfn_start = pfn_start; ++ ++ pr_info("Freescale USDPAA process driver\n"); ++ if (!phys_start) { ++ pr_warn("fsl-usdpaa: no region found\n"); ++ return 0; ++ } ++ ++ while (tmp_size != 0) { ++ u32 frag_size = largest_page_size(tmp_size); ++ frag = kmalloc(sizeof(*frag), GFP_KERNEL); ++ if (!frag) { ++ pr_err("Failed to setup USDPAA memory accounting\n"); ++ return -ENOMEM; ++ } ++ frag->base = tmp_start; ++ frag->len = frag->root_len = frag_size; ++ frag->root_pfn = tmp_pfn_start; ++ frag->pfn_base = tmp_pfn_start; ++ frag->pfn_len = frag_size / PAGE_SIZE; ++ frag->refs = 0; ++ init_waitqueue_head(&frag->wq); ++ frag->owner = NULL; ++ list_add(&frag->list, &mem_list); ++ ++ /* Adjust for this frag */ ++ tmp_start += frag_size; ++ tmp_size -= frag_size; ++ tmp_pfn_start += frag_size / PAGE_SIZE; ++ tmp_pfn_size -= frag_size / PAGE_SIZE; ++ } ++ ret = misc_register(&usdpaa_miscdev); ++ if (ret) ++ pr_err("fsl-usdpaa: failed to register misc device\n"); ++ return ret; ++} ++ ++static void __exit usdpaa_exit(void) ++{ ++ misc_deregister(&usdpaa_miscdev); ++} ++ ++module_init(usdpaa_init); ++module_exit(usdpaa_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Freescale Semiconductor"); ++MODULE_DESCRIPTION("Freescale USDPAA process driver"); +diff --git a/drivers/staging/fsl_qbman/fsl_usdpaa_irq.c b/drivers/staging/fsl_qbman/fsl_usdpaa_irq.c +new file mode 100644 +index 00000000..914c7471 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/fsl_usdpaa_irq.c +@@ -0,0 +1,289 @@ ++/* Copyright (c) 2013 Freescale Semiconductor, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* define a device that allows USPDAA processes to open a file ++ descriptor and specify which IRQ it wants to montior using an ioctl() ++ When an IRQ is received, the device becomes readable so that a process ++ can use read() or select() type calls to monitor for IRQs */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "qman_low.h" ++#include "bman_low.h" ++ ++struct usdpaa_irq_ctx { ++ int irq_set; /* Set to true once the irq is set via ioctl */ ++ unsigned int irq_num; ++ u32 last_irq_count; /* Last value returned from read */ ++ u32 irq_count; /* Number of irqs since last read */ ++ wait_queue_head_t wait_queue; /* Waiting processes */ ++ spinlock_t lock; ++ void *inhibit_addr; /* inhibit register address */ ++ struct file *usdpaa_filp; ++ char irq_name[128]; ++}; ++ ++static int usdpaa_irq_open(struct inode *inode, struct file *filp) ++{ ++ struct usdpaa_irq_ctx *ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ ctx->irq_set = 0; ++ ctx->irq_count = 0; ++ ctx->last_irq_count = 0; ++ init_waitqueue_head(&ctx->wait_queue); ++ spin_lock_init(&ctx->lock); ++ filp->private_data = ctx; ++ return 0; ++} ++ ++static int usdpaa_irq_release(struct inode *inode, struct file *filp) ++{ ++ struct usdpaa_irq_ctx *ctx = filp->private_data; ++ if (ctx->irq_set) { ++ /* Inhibit the IRQ */ ++ out_be32(ctx->inhibit_addr, 0x1); ++ irq_set_affinity_hint(ctx->irq_num, NULL); ++ free_irq(ctx->irq_num, ctx); ++ ctx->irq_set = 0; ++ fput(ctx->usdpaa_filp); ++ } ++ kfree(filp->private_data); ++ return 0; ++} ++ ++static irqreturn_t usdpaa_irq_handler(int irq, void *_ctx) ++{ ++ unsigned long flags; ++ struct usdpaa_irq_ctx *ctx = _ctx; ++ spin_lock_irqsave(&ctx->lock, flags); ++ ++ctx->irq_count; ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ wake_up_all(&ctx->wait_queue); ++ /* Set the inhibit register. This will be reenabled ++ once the USDPAA code handles the IRQ */ ++ out_be32(ctx->inhibit_addr, 0x1); ++ pr_info("Inhibit at %p count %d", ctx->inhibit_addr, ctx->irq_count); ++ return IRQ_HANDLED; ++} ++ ++static int map_irq(struct file *fp, struct usdpaa_ioctl_irq_map *irq_map) ++{ ++ struct usdpaa_irq_ctx *ctx = fp->private_data; ++ int ret; ++ ++ if (ctx->irq_set) { ++ pr_debug("Setting USDPAA IRQ when it was already set!\n"); ++ return -EBUSY; ++ } ++ ++ ctx->usdpaa_filp = fget(irq_map->fd); ++ if (!ctx->usdpaa_filp) { ++ pr_debug("USDPAA fget(%d) returned NULL\n", irq_map->fd); ++ return -EINVAL; ++ } ++ ++ ret = usdpaa_get_portal_config(ctx->usdpaa_filp, irq_map->portal_cinh, ++ irq_map->type, &ctx->irq_num, ++ &ctx->inhibit_addr); ++ if (ret) { ++ pr_debug("USDPAA IRQ couldn't identify portal\n"); ++ fput(ctx->usdpaa_filp); ++ return ret; ++ } ++ ++ ctx->irq_set = 1; ++ ++ snprintf(ctx->irq_name, sizeof(ctx->irq_name), ++ "usdpaa_irq %d", ctx->irq_num); ++ ++ ret = request_irq(ctx->irq_num, usdpaa_irq_handler, 0, ++ ctx->irq_name, ctx); ++ if (ret) { ++ pr_err("USDPAA request_irq(%d) failed, ret= %d\n", ++ ctx->irq_num, ret); ++ ctx->irq_set = 0; ++ fput(ctx->usdpaa_filp); ++ return ret; ++ } ++ ret = irq_set_affinity(ctx->irq_num, ¤t->cpus_allowed); ++ if (ret) ++ pr_err("USDPAA irq_set_affinity() failed, ret= %d\n", ret); ++ ++ ret = irq_set_affinity_hint(ctx->irq_num, ¤t->cpus_allowed); ++ if (ret) ++ pr_err("USDPAA irq_set_affinity_hint() failed, ret= %d\n", ret); ++ ++ return 0; ++} ++ ++static long usdpaa_irq_ioctl(struct file *fp, unsigned int cmd, ++ unsigned long arg) ++{ ++ int ret; ++ struct usdpaa_ioctl_irq_map irq_map; ++ ++ if (cmd != USDPAA_IOCTL_PORTAL_IRQ_MAP) { ++ pr_debug("USDPAA IRQ unknown command 0x%x\n", cmd); ++ return -EINVAL; ++ } ++ ++ ret = copy_from_user(&irq_map, (void __user *)arg, ++ sizeof(irq_map)); ++ if (ret) ++ return ret; ++ return map_irq(fp, &irq_map); ++} ++ ++static ssize_t usdpaa_irq_read(struct file *filp, char __user *buff, ++ size_t count, loff_t *offp) ++{ ++ struct usdpaa_irq_ctx *ctx = filp->private_data; ++ int ret; ++ ++ if (!ctx->irq_set) { ++ pr_debug("Reading USDPAA IRQ before it was set\n"); ++ return -EINVAL; ++ } ++ ++ if (count < sizeof(ctx->irq_count)) { ++ pr_debug("USDPAA IRQ Read too small\n"); ++ return -EINVAL; ++ } ++ if (ctx->irq_count == ctx->last_irq_count) { ++ if (filp->f_flags & O_NONBLOCK) ++ return -EAGAIN; ++ ++ ret = wait_event_interruptible(ctx->wait_queue, ++ ctx->irq_count != ctx->last_irq_count); ++ if (ret == -ERESTARTSYS) ++ return ret; ++ } ++ ++ ctx->last_irq_count = ctx->irq_count; ++ ++ if (copy_to_user(buff, &ctx->last_irq_count, ++ sizeof(ctx->last_irq_count))) ++ return -EFAULT; ++ return sizeof(ctx->irq_count); ++} ++ ++static unsigned int usdpaa_irq_poll(struct file *filp, poll_table *wait) ++{ ++ struct usdpaa_irq_ctx *ctx = filp->private_data; ++ unsigned int ret = 0; ++ unsigned long flags; ++ ++ if (!ctx->irq_set) ++ return POLLHUP; ++ ++ poll_wait(filp, &ctx->wait_queue, wait); ++ ++ spin_lock_irqsave(&ctx->lock, flags); ++ if (ctx->irq_count != ctx->last_irq_count) ++ ret |= POLLIN | POLLRDNORM; ++ spin_unlock_irqrestore(&ctx->lock, flags); ++ return ret; ++} ++ ++static long usdpaa_irq_ioctl_compat(struct file *fp, unsigned int cmd, ++ unsigned long arg) ++{ ++#ifdef CONFIG_COMPAT ++ void __user *a = (void __user *)arg; ++#endif ++ switch (cmd) { ++#ifdef CONFIG_COMPAT ++ case USDPAA_IOCTL_PORTAL_IRQ_MAP_COMPAT: ++ { ++ struct compat_ioctl_irq_map input; ++ struct usdpaa_ioctl_irq_map converted; ++ if (copy_from_user(&input, a, sizeof(input))) ++ return -EFAULT; ++ converted.type = input.type; ++ converted.fd = input.fd; ++ converted.portal_cinh = compat_ptr(input.portal_cinh); ++ return map_irq(fp, &converted); ++ } ++#endif ++ default: ++ return usdpaa_irq_ioctl(fp, cmd, arg); ++ } ++} ++ ++static const struct file_operations usdpaa_irq_fops = { ++ .open = usdpaa_irq_open, ++ .release = usdpaa_irq_release, ++ .unlocked_ioctl = usdpaa_irq_ioctl, ++ .compat_ioctl = usdpaa_irq_ioctl_compat, ++ .read = usdpaa_irq_read, ++ .poll = usdpaa_irq_poll ++}; ++ ++static struct miscdevice usdpaa_miscdev = { ++ .name = "fsl-usdpaa-irq", ++ .fops = &usdpaa_irq_fops, ++ .minor = MISC_DYNAMIC_MINOR, ++}; ++ ++static int __init usdpaa_irq_init(void) ++{ ++ int ret; ++ ++ pr_info("Freescale USDPAA process IRQ driver\n"); ++ ret = misc_register(&usdpaa_miscdev); ++ if (ret) ++ pr_err("fsl-usdpaa-irq: failed to register misc device\n"); ++ return ret; ++} ++ ++static void __exit usdpaa_irq_exit(void) ++{ ++ misc_deregister(&usdpaa_miscdev); ++} ++ ++module_init(usdpaa_irq_init); ++module_exit(usdpaa_irq_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Freescale Semiconductor"); ++MODULE_DESCRIPTION("Freescale USDPAA process IRQ driver"); +diff --git a/drivers/staging/fsl_qbman/qbman_driver.c b/drivers/staging/fsl_qbman/qbman_driver.c +new file mode 100644 +index 00000000..ab487d5f +--- /dev/null ++++ b/drivers/staging/fsl_qbman/qbman_driver.c +@@ -0,0 +1,88 @@ ++/* Copyright 2013 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include "qman_private.h" ++#include "bman_private.h" ++__init void qman_init_early(void); ++__init void bman_init_early(void); ++ ++static __init int qbman_init(void) ++{ ++ struct device_node *dn; ++ u32 is_portal_available; ++ ++ bman_init(); ++ qman_init(); ++ ++ is_portal_available = 0; ++ for_each_compatible_node(dn, NULL, "fsl,qman-portal") { ++ if (!of_device_is_available(dn)) ++ continue; ++ else ++ is_portal_available = 1; ++ } ++ ++ if (!qman_have_ccsr() && is_portal_available) { ++ struct qman_fq fq = { ++ .fqid = 1 ++ }; ++ struct qm_mcr_queryfq_np np; ++ int err, retry = CONFIG_FSL_QMAN_INIT_TIMEOUT; ++ struct timespec nowts, diffts, startts = current_kernel_time(); ++ /* Loop while querying given fqid succeeds or time out */ ++ while (1) { ++ err = qman_query_fq_np(&fq, &np); ++ if (!err) { ++ /* success, control-plane has configured QMan */ ++ break; ++ } else if (err != -ERANGE) { ++ pr_err("QMan: I/O error, continuing anyway\n"); ++ break; ++ } ++ nowts = current_kernel_time(); ++ diffts = timespec_sub(nowts, startts); ++ if (diffts.tv_sec > 0) { ++ if (!retry--) { ++ pr_err("QMan: time out, control-plane" ++ " dead?\n"); ++ break; ++ } ++ pr_warn("QMan: polling for the control-plane" ++ " (%d)\n", retry); ++ } ++ } ++ } ++ bman_resource_init(); ++ qman_resource_init(); ++ return 0; ++} ++subsys_initcall(qbman_init); +diff --git a/drivers/staging/fsl_qbman/qman_config.c b/drivers/staging/fsl_qbman/qman_config.c +new file mode 100644 +index 00000000..9bb1e11a +--- /dev/null ++++ b/drivers/staging/fsl_qbman/qman_config.c +@@ -0,0 +1,1224 @@ ++/* Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include "qman_private.h" ++#include ++#include ++ ++/* Last updated for v00.800 of the BG */ ++ ++/* Register offsets */ ++#define REG_QCSP_LIO_CFG(n) (0x0000 + ((n) * 0x10)) ++#define REG_QCSP_IO_CFG(n) (0x0004 + ((n) * 0x10)) ++#define REG_QCSP_DD_CFG(n) (0x000c + ((n) * 0x10)) ++#define REG_DD_CFG 0x0200 ++#define REG_DCP_CFG(n) (0x0300 + ((n) * 0x10)) ++#define REG_DCP_DD_CFG(n) (0x0304 + ((n) * 0x10)) ++#define REG_DCP_DLM_AVG(n) (0x030c + ((n) * 0x10)) ++#define REG_PFDR_FPC 0x0400 ++#define REG_PFDR_FP_HEAD 0x0404 ++#define REG_PFDR_FP_TAIL 0x0408 ++#define REG_PFDR_FP_LWIT 0x0410 ++#define REG_PFDR_CFG 0x0414 ++#define REG_SFDR_CFG 0x0500 ++#define REG_SFDR_IN_USE 0x0504 ++#define REG_WQ_CS_CFG(n) (0x0600 + ((n) * 0x04)) ++#define REG_WQ_DEF_ENC_WQID 0x0630 ++#define REG_WQ_SC_DD_CFG(n) (0x640 + ((n) * 0x04)) ++#define REG_WQ_PC_DD_CFG(n) (0x680 + ((n) * 0x04)) ++#define REG_WQ_DC0_DD_CFG(n) (0x6c0 + ((n) * 0x04)) ++#define REG_WQ_DC1_DD_CFG(n) (0x700 + ((n) * 0x04)) ++#define REG_WQ_DCn_DD_CFG(n) (0x6c0 + ((n) * 0x40)) /* n=2,3 */ ++#define REG_CM_CFG 0x0800 ++#define REG_ECSR 0x0a00 ++#define REG_ECIR 0x0a04 ++#define REG_EADR 0x0a08 ++#define REG_ECIR2 0x0a0c ++#define REG_EDATA(n) (0x0a10 + ((n) * 0x04)) ++#define REG_SBEC(n) (0x0a80 + ((n) * 0x04)) ++#define REG_MCR 0x0b00 ++#define REG_MCP(n) (0x0b04 + ((n) * 0x04)) ++#define REG_MISC_CFG 0x0be0 ++#define REG_HID_CFG 0x0bf0 ++#define REG_IDLE_STAT 0x0bf4 ++#define REG_IP_REV_1 0x0bf8 ++#define REG_IP_REV_2 0x0bfc ++#define REG_FQD_BARE 0x0c00 ++#define REG_PFDR_BARE 0x0c20 ++#define REG_offset_BAR 0x0004 /* relative to REG_[FQD|PFDR]_BARE */ ++#define REG_offset_AR 0x0010 /* relative to REG_[FQD|PFDR]_BARE */ ++#define REG_QCSP_BARE 0x0c80 ++#define REG_QCSP_BAR 0x0c84 ++#define REG_CI_SCHED_CFG 0x0d00 ++#define REG_SRCIDR 0x0d04 ++#define REG_LIODNR 0x0d08 ++#define REG_CI_RLM_AVG 0x0d14 ++#define REG_ERR_ISR 0x0e00 /* + "enum qm_isr_reg" */ ++#define REG_REV3_QCSP_LIO_CFG(n) (0x1000 + ((n) * 0x10)) ++#define REG_REV3_QCSP_IO_CFG(n) (0x1004 + ((n) * 0x10)) ++#define REG_REV3_QCSP_DD_CFG(n) (0x100c + ((n) * 0x10)) ++#define REG_CEETM_CFG_IDX 0x900 ++#define REG_CEETM_CFG_PRES 0x904 ++#define REG_CEETM_XSFDR_IN_USE 0x908 ++ ++/* Assists for QMAN_MCR */ ++#define MCR_INIT_PFDR 0x01000000 ++#define MCR_get_rslt(v) (u8)((v) >> 24) ++#define MCR_rslt_idle(r) (!rslt || (rslt >= 0xf0)) ++#define MCR_rslt_ok(r) (rslt == 0xf0) ++#define MCR_rslt_eaccess(r) (rslt == 0xf8) ++#define MCR_rslt_inval(r) (rslt == 0xff) ++ ++struct qman; ++ ++/* Follows WQ_CS_CFG0-5 */ ++enum qm_wq_class { ++ qm_wq_portal = 0, ++ qm_wq_pool = 1, ++ qm_wq_fman0 = 2, ++ qm_wq_fman1 = 3, ++ qm_wq_caam = 4, ++ qm_wq_pme = 5, ++ qm_wq_first = qm_wq_portal, ++ qm_wq_last = qm_wq_pme ++}; ++ ++/* Follows FQD_[BARE|BAR|AR] and PFDR_[BARE|BAR|AR] */ ++enum qm_memory { ++ qm_memory_fqd, ++ qm_memory_pfdr ++}; ++ ++/* Used by all error interrupt registers except 'inhibit' */ ++#define QM_EIRQ_CIDE 0x20000000 /* Corenet Initiator Data Error */ ++#define QM_EIRQ_CTDE 0x10000000 /* Corenet Target Data Error */ ++#define QM_EIRQ_CITT 0x08000000 /* Corenet Invalid Target Transaction */ ++#define QM_EIRQ_PLWI 0x04000000 /* PFDR Low Watermark */ ++#define QM_EIRQ_MBEI 0x02000000 /* Multi-bit ECC Error */ ++#define QM_EIRQ_SBEI 0x01000000 /* Single-bit ECC Error */ ++#define QM_EIRQ_PEBI 0x00800000 /* PFDR Enqueues Blocked Interrupt */ ++#define QM_EIRQ_IFSI 0x00020000 /* Invalid FQ Flow Control State */ ++#define QM_EIRQ_ICVI 0x00010000 /* Invalid Command Verb */ ++#define QM_EIRQ_IDDI 0x00000800 /* Invalid Dequeue (Direct-connect) */ ++#define QM_EIRQ_IDFI 0x00000400 /* Invalid Dequeue FQ */ ++#define QM_EIRQ_IDSI 0x00000200 /* Invalid Dequeue Source */ ++#define QM_EIRQ_IDQI 0x00000100 /* Invalid Dequeue Queue */ ++#define QM_EIRQ_IECE 0x00000010 /* Invalid Enqueue Configuration */ ++#define QM_EIRQ_IEOI 0x00000008 /* Invalid Enqueue Overflow */ ++#define QM_EIRQ_IESI 0x00000004 /* Invalid Enqueue State */ ++#define QM_EIRQ_IECI 0x00000002 /* Invalid Enqueue Channel */ ++#define QM_EIRQ_IEQI 0x00000001 /* Invalid Enqueue Queue */ ++ ++/* QMAN_ECIR valid error bit */ ++#define PORTAL_ECSR_ERR (QM_EIRQ_IEQI | QM_EIRQ_IESI | QM_EIRQ_IEOI | \ ++ QM_EIRQ_IDQI | QM_EIRQ_IDSI | QM_EIRQ_IDFI | \ ++ QM_EIRQ_IDDI | QM_EIRQ_ICVI | QM_EIRQ_IFSI) ++#define FQID_ECSR_ERR (QM_EIRQ_IEQI | QM_EIRQ_IECI | QM_EIRQ_IESI | \ ++ QM_EIRQ_IEOI | QM_EIRQ_IDQI | QM_EIRQ_IDFI | \ ++ QM_EIRQ_IFSI) ++ ++union qman_ecir { ++ u32 ecir_raw; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u32 __reserved:2; ++ u32 portal_type:1; ++ u32 portal_num:5; ++ u32 fqid:24; ++#else ++ u32 fqid:24; ++ u32 portal_num:5; ++ u32 portal_type:1; ++ u32 __reserved:2; ++#endif ++ } __packed info; ++}; ++ ++union qman_ecir2 { ++ u32 ecir2_raw; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u32 portal_type:1; ++ u32 __reserved:21; ++ u32 portal_num:10; ++#else ++ u32 portal_num:10; ++ u32 __reserved:21; ++ u32 portal_type:1; ++#endif ++ } __packed info; ++}; ++ ++union qman_eadr { ++ u32 eadr_raw; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u32 __reserved1:4; ++ u32 memid:4; ++ u32 __reserved2:12; ++ u32 eadr:12; ++#else ++ u32 eadr:12; ++ u32 __reserved2:12; ++ u32 memid:4; ++ u32 __reserved1:4; ++#endif ++ } __packed info; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u32 __reserved1:3; ++ u32 memid:5; ++ u32 __reserved:8; ++ u32 eadr:16; ++#else ++ u32 eadr:16; ++ u32 __reserved:8; ++ u32 memid:5; ++ u32 __reserved1:3; ++#endif ++ } __packed info_rev3; ++}; ++ ++struct qman_hwerr_txt { ++ u32 mask; ++ const char *txt; ++}; ++ ++#define QMAN_HWE_TXT(a, b) { .mask = QM_EIRQ_##a, .txt = b } ++ ++static const struct qman_hwerr_txt qman_hwerr_txts[] = { ++ QMAN_HWE_TXT(CIDE, "Corenet Initiator Data Error"), ++ QMAN_HWE_TXT(CTDE, "Corenet Target Data Error"), ++ QMAN_HWE_TXT(CITT, "Corenet Invalid Target Transaction"), ++ QMAN_HWE_TXT(PLWI, "PFDR Low Watermark"), ++ QMAN_HWE_TXT(MBEI, "Multi-bit ECC Error"), ++ QMAN_HWE_TXT(SBEI, "Single-bit ECC Error"), ++ QMAN_HWE_TXT(PEBI, "PFDR Enqueues Blocked Interrupt"), ++ QMAN_HWE_TXT(ICVI, "Invalid Command Verb"), ++ QMAN_HWE_TXT(IFSI, "Invalid Flow Control State"), ++ QMAN_HWE_TXT(IDDI, "Invalid Dequeue (Direct-connect)"), ++ QMAN_HWE_TXT(IDFI, "Invalid Dequeue FQ"), ++ QMAN_HWE_TXT(IDSI, "Invalid Dequeue Source"), ++ QMAN_HWE_TXT(IDQI, "Invalid Dequeue Queue"), ++ QMAN_HWE_TXT(IECE, "Invalid Enqueue Configuration"), ++ QMAN_HWE_TXT(IEOI, "Invalid Enqueue Overflow"), ++ QMAN_HWE_TXT(IESI, "Invalid Enqueue State"), ++ QMAN_HWE_TXT(IECI, "Invalid Enqueue Channel"), ++ QMAN_HWE_TXT(IEQI, "Invalid Enqueue Queue") ++}; ++#define QMAN_HWE_COUNT (sizeof(qman_hwerr_txts)/sizeof(struct qman_hwerr_txt)) ++ ++struct qman_error_info_mdata { ++ u16 addr_mask; ++ u16 bits; ++ const char *txt; ++}; ++ ++#define QMAN_ERR_MDATA(a, b, c) { .addr_mask = a, .bits = b, .txt = c} ++static const struct qman_error_info_mdata error_mdata[] = { ++ QMAN_ERR_MDATA(0x01FF, 24, "FQD cache tag memory 0"), ++ QMAN_ERR_MDATA(0x01FF, 24, "FQD cache tag memory 1"), ++ QMAN_ERR_MDATA(0x01FF, 24, "FQD cache tag memory 2"), ++ QMAN_ERR_MDATA(0x01FF, 24, "FQD cache tag memory 3"), ++ QMAN_ERR_MDATA(0x0FFF, 512, "FQD cache memory"), ++ QMAN_ERR_MDATA(0x07FF, 128, "SFDR memory"), ++ QMAN_ERR_MDATA(0x01FF, 72, "WQ context memory"), ++ QMAN_ERR_MDATA(0x00FF, 240, "CGR memory"), ++ QMAN_ERR_MDATA(0x00FF, 302, "Internal Order Restoration List memory"), ++ QMAN_ERR_MDATA(0x01FF, 256, "SW portal ring memory"), ++ QMAN_ERR_MDATA(0x07FF, 181, "CEETM class queue descriptor memory"), ++ QMAN_ERR_MDATA(0x0FFF, 140, "CEETM extended SFDR memory"), ++ QMAN_ERR_MDATA(0x0FFF, 25, "CEETM logical FQ mapping memory"), ++ QMAN_ERR_MDATA(0x0FFF, 96, "CEETM dequeue context memory"), ++ QMAN_ERR_MDATA(0x07FF, 396, "CEETM ccgr memory"), ++ QMAN_ERR_MDATA(0x00FF, 146, "CEETM CQ channel shaping memory"), ++ QMAN_ERR_MDATA(0x007F, 256, "CEETM CQ channel scheduling memory"), ++ QMAN_ERR_MDATA(0x01FF, 88, "CEETM dequeue statistics memory"), ++}; ++#define QMAN_ERR_MDATA_COUNT \ ++ (sizeof(error_mdata)/sizeof(struct qman_error_info_mdata)) ++ ++/* Add this in Kconfig */ ++#define QMAN_ERRS_TO_UNENABLE (QM_EIRQ_PLWI | QM_EIRQ_PEBI) ++ ++/** ++ * qm_err_isr__ - Manipulate global interrupt registers ++ * @v: for accessors that write values, this is the 32-bit value ++ * ++ * Manipulates QMAN_ERR_ISR, QMAN_ERR_IER, QMAN_ERR_ISDR, QMAN_ERR_IIR. All ++ * manipulations except qm_err_isr_[un]inhibit() use 32-bit masks composed of ++ * the QM_EIRQ_*** definitions. Note that "qm_err_isr_enable_write" means ++ * "write the enable register" rather than "enable the write register"! ++ */ ++#define qm_err_isr_status_read(qm) \ ++ __qm_err_isr_read(qm, qm_isr_status) ++#define qm_err_isr_status_clear(qm, m) \ ++ __qm_err_isr_write(qm, qm_isr_status, m) ++#define qm_err_isr_enable_read(qm) \ ++ __qm_err_isr_read(qm, qm_isr_enable) ++#define qm_err_isr_enable_write(qm, v) \ ++ __qm_err_isr_write(qm, qm_isr_enable, v) ++#define qm_err_isr_disable_read(qm) \ ++ __qm_err_isr_read(qm, qm_isr_disable) ++#define qm_err_isr_disable_write(qm, v) \ ++ __qm_err_isr_write(qm, qm_isr_disable, v) ++#define qm_err_isr_inhibit(qm) \ ++ __qm_err_isr_write(qm, qm_isr_inhibit, 1) ++#define qm_err_isr_uninhibit(qm) \ ++ __qm_err_isr_write(qm, qm_isr_inhibit, 0) ++ ++/* ++ * TODO: unimplemented registers ++ * ++ * Keeping a list here of Qman registers I have not yet covered; ++ * QCSP_DD_IHRSR, QCSP_DD_IHRFR, QCSP_DD_HASR, ++ * DCP_DD_IHRSR, DCP_DD_IHRFR, DCP_DD_HASR, CM_CFG, ++ * QMAN_EECC, QMAN_SBET, QMAN_EINJ, QMAN_SBEC0-12 ++ */ ++ ++/* Encapsulate "struct qman *" as a cast of the register space address. */ ++ ++static struct qman *qm_create(void *regs) ++{ ++ return (struct qman *)regs; ++} ++ ++static inline u32 __qm_in(struct qman *qm, u32 offset) ++{ ++ return in_be32((void *)qm + offset); ++} ++static inline void __qm_out(struct qman *qm, u32 offset, u32 val) ++{ ++ out_be32((void *)qm + offset, val); ++} ++#define qm_in(reg) __qm_in(qm, REG_##reg) ++#define qm_out(reg, val) __qm_out(qm, REG_##reg, val) ++ ++static u32 __qm_err_isr_read(struct qman *qm, enum qm_isr_reg n) ++{ ++ return __qm_in(qm, REG_ERR_ISR + (n << 2)); ++} ++ ++static void __qm_err_isr_write(struct qman *qm, enum qm_isr_reg n, u32 val) ++{ ++ __qm_out(qm, REG_ERR_ISR + (n << 2), val); ++} ++ ++static void qm_set_dc(struct qman *qm, enum qm_dc_portal portal, ++ int ed, u8 sernd) ++{ ++ DPA_ASSERT(!ed || (portal == qm_dc_portal_fman0) || ++ (portal == qm_dc_portal_fman1)); ++ if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) ++ qm_out(DCP_CFG(portal), (ed ? 0x1000 : 0) | (sernd & 0x3ff)); ++ else ++ qm_out(DCP_CFG(portal), (ed ? 0x100 : 0) | (sernd & 0x1f)); ++} ++ ++static void qm_set_wq_scheduling(struct qman *qm, enum qm_wq_class wq_class, ++ u8 cs_elev, u8 csw2, u8 csw3, u8 csw4, u8 csw5, ++ u8 csw6, u8 csw7) ++{ ++ qm_out(WQ_CS_CFG(wq_class), ((cs_elev & 0xff) << 24) | ++ ((csw2 & 0x7) << 20) | ((csw3 & 0x7) << 16) | ++ ((csw4 & 0x7) << 12) | ((csw5 & 0x7) << 8) | ++ ((csw6 & 0x7) << 4) | (csw7 & 0x7)); ++} ++ ++static void qm_set_hid(struct qman *qm) ++{ ++ qm_out(HID_CFG, 0); ++} ++ ++static void qm_set_corenet_initiator(struct qman *qm) ++{ ++ qm_out(CI_SCHED_CFG, ++ 0x80000000 | /* write srcciv enable */ ++ (CONFIG_FSL_QMAN_CI_SCHED_CFG_SRCCIV << 24) | ++ (CONFIG_FSL_QMAN_CI_SCHED_CFG_SRQ_W << 8) | ++ (CONFIG_FSL_QMAN_CI_SCHED_CFG_RW_W << 4) | ++ CONFIG_FSL_QMAN_CI_SCHED_CFG_BMAN_W); ++} ++ ++static void qm_get_version(struct qman *qm, u16 *id, u8 *major, u8 *minor, ++ u8 *cfg) ++{ ++ u32 v = qm_in(IP_REV_1); ++ u32 v2 = qm_in(IP_REV_2); ++ *id = (v >> 16); ++ *major = (v >> 8) & 0xff; ++ *minor = v & 0xff; ++ *cfg = v2 & 0xff; ++} ++ ++static void qm_set_memory(struct qman *qm, enum qm_memory memory, u64 ba, ++ int enable, int prio, int stash, u32 size) ++{ ++ u32 offset = (memory == qm_memory_fqd) ? REG_FQD_BARE : REG_PFDR_BARE; ++ u32 exp = ilog2(size); ++ /* choke if size isn't within range */ ++ DPA_ASSERT((size >= 4096) && (size <= 1073741824) && ++ is_power_of_2(size)); ++ /* choke if 'ba' has lower-alignment than 'size' */ ++ DPA_ASSERT(!(ba & (size - 1))); ++ __qm_out(qm, offset, upper_32_bits(ba)); ++ __qm_out(qm, offset + REG_offset_BAR, lower_32_bits(ba)); ++ __qm_out(qm, offset + REG_offset_AR, ++ (enable ? 0x80000000 : 0) | ++ (prio ? 0x40000000 : 0) | ++ (stash ? 0x20000000 : 0) | ++ (exp - 1)); ++} ++ ++static void qm_set_pfdr_threshold(struct qman *qm, u32 th, u8 k) ++{ ++ qm_out(PFDR_FP_LWIT, th & 0xffffff); ++ qm_out(PFDR_CFG, k); ++} ++ ++static void qm_set_sfdr_threshold(struct qman *qm, u16 th) ++{ ++ qm_out(SFDR_CFG, th & 0x3ff); ++} ++ ++static int qm_init_pfdr(struct qman *qm, u32 pfdr_start, u32 num) ++{ ++ u8 rslt = MCR_get_rslt(qm_in(MCR)); ++ ++ DPA_ASSERT(pfdr_start && !(pfdr_start & 7) && !(num & 7) && num); ++ /* Make sure the command interface is 'idle' */ ++ if (!MCR_rslt_idle(rslt)) ++ panic("QMAN_MCR isn't idle"); ++ ++ /* Write the MCR command params then the verb */ ++ qm_out(MCP(0), pfdr_start); ++ /* TODO: remove this - it's a workaround for a model bug that is ++ * corrected in more recent versions. We use the workaround until ++ * everyone has upgraded. */ ++ qm_out(MCP(1), (pfdr_start + num - 16)); ++ lwsync(); ++ qm_out(MCR, MCR_INIT_PFDR); ++ /* Poll for the result */ ++ do { ++ rslt = MCR_get_rslt(qm_in(MCR)); ++ } while (!MCR_rslt_idle(rslt)); ++ if (MCR_rslt_ok(rslt)) ++ return 0; ++ if (MCR_rslt_eaccess(rslt)) ++ return -EACCES; ++ if (MCR_rslt_inval(rslt)) ++ return -EINVAL; ++ pr_crit("Unexpected result from MCR_INIT_PFDR: %02x\n", rslt); ++ return -ENOSYS; ++} ++ ++/*****************/ ++/* Config driver */ ++/*****************/ ++ ++#define DEFAULT_FQD_SZ (PAGE_SIZE << CONFIG_FSL_QMAN_FQD_SZ) ++#define DEFAULT_PFDR_SZ (PAGE_SIZE << CONFIG_FSL_QMAN_PFDR_SZ) ++ ++/* We support only one of these */ ++static struct qman *qm; ++static struct device_node *qm_node; ++ ++/* And this state belongs to 'qm'. It is set during fsl_qman_init(), but used ++ * during qman_init_ccsr(). */ ++static dma_addr_t fqd_a, pfdr_a; ++static size_t fqd_sz = DEFAULT_FQD_SZ, pfdr_sz = DEFAULT_PFDR_SZ; ++ ++static int qman_fqd(struct reserved_mem *rmem) ++{ ++ fqd_a = rmem->base; ++ fqd_sz = rmem->size; ++ ++ WARN_ON(!(fqd_a && fqd_sz)); ++ ++ return 0; ++} ++RESERVEDMEM_OF_DECLARE(qman_fqd, "fsl,qman-fqd", qman_fqd); ++ ++static int qman_pfdr(struct reserved_mem *rmem) ++{ ++ pfdr_a = rmem->base; ++ pfdr_sz = rmem->size; ++ ++ WARN_ON(!(pfdr_a && pfdr_sz)); ++ ++ return 0; ++} ++RESERVEDMEM_OF_DECLARE(qman_fbpr, "fsl,qman-pfdr", qman_pfdr); ++ ++size_t get_qman_fqd_size() ++{ ++ return fqd_sz; ++} ++ ++/* Parse the property to extract the memory location and size and ++ * memblock_reserve() it. If it isn't supplied, memblock_alloc() the default ++ * size. Also flush this memory range from data cache so that QMAN originated ++ * transactions for this memory region could be marked non-coherent. ++ */ ++static __init int parse_mem_property(struct device_node *node, const char *name, ++ dma_addr_t *addr, size_t *sz, int zero) ++{ ++ int ret; ++ ++ /* If using a "zero-pma", don't try to zero it, even if you asked */ ++ if (zero && of_find_property(node, "zero-pma", &ret)) { ++ pr_info(" it's a 'zero-pma', not zeroing from s/w\n"); ++ zero = 0; ++ } ++ ++ if (zero) { ++ /* map as cacheable, non-guarded */ ++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) ++ void __iomem *tmpp = ioremap_cache(*addr, *sz); ++#else ++ void __iomem *tmpp = ioremap(*addr, *sz); ++#endif ++ ++ if (!tmpp) ++ return -ENOMEM; ++ memset_io(tmpp, 0, *sz); ++ flush_dcache_range((unsigned long)tmpp, ++ (unsigned long)tmpp + *sz); ++ iounmap(tmpp); ++ } ++ ++ return 0; ++} ++ ++/* TODO: ++ * - there is obviously no handling of errors, ++ * - the calls to qm_set_memory() hard-code the priority and CPC-stashing for ++ * both memory resources to zero. ++ */ ++static int __init fsl_qman_init(struct device_node *node) ++{ ++ struct resource res; ++ resource_size_t len; ++ u32 __iomem *regs; ++ const char *s; ++ int ret, standby = 0; ++ u16 id; ++ u8 major, minor, cfg; ++ ret = of_address_to_resource(node, 0, &res); ++ if (ret) { ++ pr_err("Can't get %s property '%s'\n", node->full_name, "reg"); ++ return ret; ++ } ++ s = of_get_property(node, "fsl,hv-claimable", &ret); ++ if (s && !strcmp(s, "standby")) ++ standby = 1; ++ if (!standby) { ++ ret = parse_mem_property(node, "fsl,qman-fqd", ++ &fqd_a, &fqd_sz, 1); ++ pr_info("qman-fqd addr %pad size 0x%zx\n", &fqd_a, fqd_sz); ++ BUG_ON(ret); ++ ret = parse_mem_property(node, "fsl,qman-pfdr", ++ &pfdr_a, &pfdr_sz, 0); ++ pr_info("qman-pfdr addr %pad size 0x%zx\n", &pfdr_a, pfdr_sz); ++ BUG_ON(ret); ++ } ++ /* Global configuration */ ++ len = resource_size(&res); ++ if (len != (unsigned long)len) ++ return -EINVAL; ++ regs = ioremap(res.start, (unsigned long)len); ++ qm = qm_create(regs); ++ qm_node = node; ++ qm_get_version(qm, &id, &major, &minor, &cfg); ++ pr_info("Qman ver:%04x,%02x,%02x,%02x\n", id, major, minor, cfg); ++ if (!qman_ip_rev) { ++ if ((major == 1) && (minor == 0)) { ++ pr_err("QMAN rev1.0 on P4080 rev1 is not supported!\n"); ++ iounmap(regs); ++ return -ENODEV; ++ } else if ((major == 1) && (minor == 1)) ++ qman_ip_rev = QMAN_REV11; ++ else if ((major == 1) && (minor == 2)) ++ qman_ip_rev = QMAN_REV12; ++ else if ((major == 2) && (minor == 0)) ++ qman_ip_rev = QMAN_REV20; ++ else if ((major == 3) && (minor == 0)) ++ qman_ip_rev = QMAN_REV30; ++ else if ((major == 3) && (minor == 1)) ++ qman_ip_rev = QMAN_REV31; ++ else if ((major == 3) && (minor == 2)) ++ qman_ip_rev = QMAN_REV32; ++ else { ++ pr_warn("unknown Qman version, default to rev1.1\n"); ++ qman_ip_rev = QMAN_REV11; ++ } ++ qman_ip_cfg = cfg; ++ } ++ ++ if (standby) { ++ pr_info(" -> in standby mode\n"); ++ return 0; ++ } ++ return 0; ++} ++ ++int qman_have_ccsr(void) ++{ ++ return qm ? 1 : 0; ++} ++ ++__init int qman_init_early(void) ++{ ++ struct device_node *dn; ++ int ret; ++ ++ for_each_compatible_node(dn, NULL, "fsl,qman") { ++ if (qm) ++ pr_err("%s: only one 'fsl,qman' allowed\n", ++ dn->full_name); ++ else { ++ if (!of_device_is_available(dn)) ++ continue; ++ ++ ret = fsl_qman_init(dn); ++ BUG_ON(ret); ++ } ++ } ++ return 0; ++} ++postcore_initcall_sync(qman_init_early); ++ ++static void log_edata_bits(u32 bit_count) ++{ ++ u32 i, j, mask = 0xffffffff; ++ ++ pr_warn("Qman ErrInt, EDATA:\n"); ++ i = bit_count/32; ++ if (bit_count%32) { ++ i++; ++ mask = ~(mask << bit_count%32); ++ } ++ j = 16-i; ++ pr_warn(" 0x%08x\n", qm_in(EDATA(j)) & mask); ++ j++; ++ for (; j < 16; j++) ++ pr_warn(" 0x%08x\n", qm_in(EDATA(j))); ++} ++ ++static void log_additional_error_info(u32 isr_val, u32 ecsr_val) ++{ ++ union qman_ecir ecir_val; ++ union qman_eadr eadr_val; ++ ++ ecir_val.ecir_raw = qm_in(ECIR); ++ /* Is portal info valid */ ++ if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) { ++ union qman_ecir2 ecir2_val; ++ ecir2_val.ecir2_raw = qm_in(ECIR2); ++ if (ecsr_val & PORTAL_ECSR_ERR) { ++ pr_warn("Qman ErrInt: %s id %d\n", ++ (ecir2_val.info.portal_type) ? ++ "DCP" : "SWP", ecir2_val.info.portal_num); ++ } ++ if (ecsr_val & (FQID_ECSR_ERR | QM_EIRQ_IECE)) { ++ pr_warn("Qman ErrInt: ecir.fqid 0x%x\n", ++ ecir_val.info.fqid); ++ } ++ if (ecsr_val & (QM_EIRQ_SBEI|QM_EIRQ_MBEI)) { ++ eadr_val.eadr_raw = qm_in(EADR); ++ pr_warn("Qman ErrInt: EADR Memory: %s, 0x%x\n", ++ error_mdata[eadr_val.info_rev3.memid].txt, ++ error_mdata[eadr_val.info_rev3.memid].addr_mask ++ & eadr_val.info_rev3.eadr); ++ log_edata_bits( ++ error_mdata[eadr_val.info_rev3.memid].bits); ++ } ++ } else { ++ if (ecsr_val & PORTAL_ECSR_ERR) { ++ pr_warn("Qman ErrInt: %s id %d\n", ++ (ecir_val.info.portal_type) ? ++ "DCP" : "SWP", ecir_val.info.portal_num); ++ } ++ if (ecsr_val & FQID_ECSR_ERR) { ++ pr_warn("Qman ErrInt: ecir.fqid 0x%x\n", ++ ecir_val.info.fqid); ++ } ++ if (ecsr_val & (QM_EIRQ_SBEI|QM_EIRQ_MBEI)) { ++ eadr_val.eadr_raw = qm_in(EADR); ++ pr_warn("Qman ErrInt: EADR Memory: %s, 0x%x\n", ++ error_mdata[eadr_val.info.memid].txt, ++ error_mdata[eadr_val.info.memid].addr_mask ++ & eadr_val.info.eadr); ++ log_edata_bits(error_mdata[eadr_val.info.memid].bits); ++ } ++ } ++} ++ ++/* Qman interrupt handler */ ++static irqreturn_t qman_isr(int irq, void *ptr) ++{ ++ u32 isr_val, ier_val, ecsr_val, isr_mask, i; ++ ++ ier_val = qm_err_isr_enable_read(qm); ++ isr_val = qm_err_isr_status_read(qm); ++ ecsr_val = qm_in(ECSR); ++ isr_mask = isr_val & ier_val; ++ ++ if (!isr_mask) ++ return IRQ_NONE; ++ for (i = 0; i < QMAN_HWE_COUNT; i++) { ++ if (qman_hwerr_txts[i].mask & isr_mask) { ++ pr_warn("Qman ErrInt: %s\n", qman_hwerr_txts[i].txt); ++ if (qman_hwerr_txts[i].mask & ecsr_val) { ++ log_additional_error_info(isr_mask, ecsr_val); ++ /* Re-arm error capture registers */ ++ qm_out(ECSR, ecsr_val); ++ } ++ if (qman_hwerr_txts[i].mask & QMAN_ERRS_TO_UNENABLE) { ++ pr_devel("Qman un-enabling error 0x%x\n", ++ qman_hwerr_txts[i].mask); ++ ier_val &= ~qman_hwerr_txts[i].mask; ++ qm_err_isr_enable_write(qm, ier_val); ++ } ++ } ++ } ++ qm_err_isr_status_clear(qm, isr_val); ++ return IRQ_HANDLED; ++} ++ ++static int __bind_irq(void) ++{ ++ int ret, err_irq; ++ ++ err_irq = of_irq_to_resource(qm_node, 0, NULL); ++ if (err_irq == 0) { ++ pr_info("Can't get %s property '%s'\n", qm_node->full_name, ++ "interrupts"); ++ return -ENODEV; ++ } ++ ret = request_irq(err_irq, qman_isr, IRQF_SHARED, "qman-err", qm_node); ++ if (ret) { ++ pr_err("request_irq() failed %d for '%s'\n", ret, ++ qm_node->full_name); ++ return -ENODEV; ++ } ++ /* Write-to-clear any stale bits, (eg. starvation being asserted prior ++ * to resource allocation during driver init). */ ++ qm_err_isr_status_clear(qm, 0xffffffff); ++ /* Enable Error Interrupts */ ++ qm_err_isr_enable_write(qm, 0xffffffff); ++ return 0; ++} ++ ++int qman_init_ccsr(struct device_node *node) ++{ ++ int ret; ++ if (!qman_have_ccsr()) ++ return 0; ++ if (node != qm_node) ++ return -EINVAL; ++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) ++ /* TEMP for LS1043 : should be done in uboot */ ++ qm_out(QCSP_BARE, 0x5); ++ qm_out(QCSP_BAR, 0x0); ++#endif ++ /* FQD memory */ ++ qm_set_memory(qm, qm_memory_fqd, fqd_a, 1, 0, 0, fqd_sz); ++ /* PFDR memory */ ++ qm_set_memory(qm, qm_memory_pfdr, pfdr_a, 1, 0, 0, pfdr_sz); ++ qm_init_pfdr(qm, 8, pfdr_sz / 64 - 8); ++ /* thresholds */ ++ qm_set_pfdr_threshold(qm, 512, 64); ++ qm_set_sfdr_threshold(qm, 128); ++ /* clear stale PEBI bit from interrupt status register */ ++ qm_err_isr_status_clear(qm, QM_EIRQ_PEBI); ++ /* corenet initiator settings */ ++ qm_set_corenet_initiator(qm); ++ /* HID settings */ ++ qm_set_hid(qm); ++ /* Set scheduling weights to defaults */ ++ for (ret = qm_wq_first; ret <= qm_wq_last; ret++) ++ qm_set_wq_scheduling(qm, ret, 0, 0, 0, 0, 0, 0, 0); ++ /* We are not prepared to accept ERNs for hardware enqueues */ ++ qm_set_dc(qm, qm_dc_portal_fman0, 1, 0); ++ qm_set_dc(qm, qm_dc_portal_fman1, 1, 0); ++ /* Initialise Error Interrupt Handler */ ++ ret = __bind_irq(); ++ if (ret) ++ return ret; ++ return 0; ++} ++ ++#define LIO_CFG_LIODN_MASK 0x0fff0000 ++void qman_liodn_fixup(u16 channel) ++{ ++ static int done; ++ static u32 liodn_offset; ++ u32 before, after; ++ int idx = channel - QM_CHANNEL_SWPORTAL0; ++ ++ if (!qman_have_ccsr()) ++ return; ++ if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) ++ before = qm_in(REV3_QCSP_LIO_CFG(idx)); ++ else ++ before = qm_in(QCSP_LIO_CFG(idx)); ++ if (!done) { ++ liodn_offset = before & LIO_CFG_LIODN_MASK; ++ done = 1; ++ return; ++ } ++ after = (before & (~LIO_CFG_LIODN_MASK)) | liodn_offset; ++ if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) ++ qm_out(REV3_QCSP_LIO_CFG(idx), after); ++ else ++ qm_out(QCSP_LIO_CFG(idx), after); ++} ++ ++#define IO_CFG_SDEST_MASK 0x00ff0000 ++int qman_set_sdest(u16 channel, unsigned int cpu_idx) ++{ ++ int idx = channel - QM_CHANNEL_SWPORTAL0; ++ u32 before, after; ++ ++ if (!qman_have_ccsr()) ++ return -ENODEV; ++ if ((qman_ip_rev & 0xFF00) == QMAN_REV31) { ++ /* LS1043A - only one L2 cache */ ++ cpu_idx = 0; ++ } ++ ++ if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) { ++ before = qm_in(REV3_QCSP_IO_CFG(idx)); ++ /* Each pair of vcpu share the same SRQ(SDEST) */ ++ cpu_idx /= 2; ++ after = (before & (~IO_CFG_SDEST_MASK)) | (cpu_idx << 16); ++ qm_out(REV3_QCSP_IO_CFG(idx), after); ++ } else { ++ before = qm_in(QCSP_IO_CFG(idx)); ++ after = (before & (~IO_CFG_SDEST_MASK)) | (cpu_idx << 16); ++ qm_out(QCSP_IO_CFG(idx), after); ++ } ++ return 0; ++} ++ ++#define MISC_CFG_WPM_MASK 0x00000002 ++int qm_set_wpm(int wpm) ++{ ++ u32 before; ++ u32 after; ++ ++ if (!qman_have_ccsr()) ++ return -ENODEV; ++ ++ before = qm_in(MISC_CFG); ++ after = (before & (~MISC_CFG_WPM_MASK)) | (wpm << 1); ++ qm_out(MISC_CFG, after); ++ return 0; ++} ++ ++int qm_get_wpm(int *wpm) ++{ ++ u32 before; ++ ++ if (!qman_have_ccsr()) ++ return -ENODEV; ++ ++ before = qm_in(MISC_CFG); ++ *wpm = (before & MISC_CFG_WPM_MASK) >> 1; ++ return 0; ++} ++ ++/* CEETM_CFG_PRES register has PRES field which is calculated by: ++ * PRES = (2^22 / credit update reference period) * QMan clock period ++ * = (2^22 * 10^9)/ CONFIG_QMAN_CEETM_UPDATE_PERIOD) / qman_clk ++ */ ++ ++int qman_ceetm_set_prescaler(enum qm_dc_portal portal) ++{ ++ u64 temp; ++ u16 pres; ++ ++ if (!qman_have_ccsr()) ++ return -ENODEV; ++ ++ temp = 0x400000 * 100; ++ do_div(temp, CONFIG_QMAN_CEETM_UPDATE_PERIOD); ++ temp *= 10000000; ++ do_div(temp, qman_clk); ++ pres = (u16) temp; ++ qm_out(CEETM_CFG_IDX, portal); ++ qm_out(CEETM_CFG_PRES, pres); ++ return 0; ++} ++ ++int qman_ceetm_get_prescaler(u16 *pres) ++{ ++ if (!qman_have_ccsr()) ++ return -ENODEV; ++ *pres = (u16)qm_in(CEETM_CFG_PRES); ++ return 0; ++} ++ ++#define DCP_CFG_CEETME_MASK 0xFFFF0000 ++#define QM_SP_ENABLE_CEETM(n) (0x80000000 >> (n)) ++int qman_sp_enable_ceetm_mode(enum qm_dc_portal portal, u16 sub_portal) ++{ ++ u32 dcp_cfg; ++ ++ if (!qman_have_ccsr()) ++ return -ENODEV; ++ ++ dcp_cfg = qm_in(DCP_CFG(portal)); ++ dcp_cfg |= QM_SP_ENABLE_CEETM(sub_portal); ++ qm_out(DCP_CFG(portal), dcp_cfg); ++ return 0; ++} ++ ++int qman_sp_disable_ceetm_mode(enum qm_dc_portal portal, u16 sub_portal) ++{ ++ u32 dcp_cfg; ++ ++ if (!qman_have_ccsr()) ++ return -ENODEV; ++ dcp_cfg = qm_in(DCP_CFG(portal)); ++ dcp_cfg &= ~(QM_SP_ENABLE_CEETM(sub_portal)); ++ qm_out(DCP_CFG(portal), dcp_cfg); ++ return 0; ++} ++ ++int qman_ceetm_get_xsfdr(enum qm_dc_portal portal, unsigned int *num) ++{ ++ if (!qman_have_ccsr()) ++ return -ENODEV; ++ *num = qm_in(CEETM_XSFDR_IN_USE); ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_get_xsfdr); ++ ++#ifdef CONFIG_SYSFS ++ ++#define DRV_NAME "fsl-qman" ++#define DCP_MAX_ID 3 ++#define DCP_MIN_ID 0 ++ ++static ssize_t show_pfdr_fpc(struct device *dev, ++ struct device_attribute *dev_attr, char *buf) ++{ ++ return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(PFDR_FPC)); ++}; ++ ++static ssize_t show_dlm_avg(struct device *dev, ++ struct device_attribute *dev_attr, char *buf) ++{ ++ u32 data; ++ int i; ++ ++ if (!sscanf(dev_attr->attr.name, "dcp%d_dlm_avg", &i)) ++ return -EINVAL; ++ if (i < DCP_MIN_ID || i > DCP_MAX_ID) ++ return -EINVAL; ++ data = qm_in(DCP_DLM_AVG(i)); ++ return snprintf(buf, PAGE_SIZE, "%d.%08d\n", data>>8, ++ (data & 0x000000ff)*390625); ++}; ++ ++static ssize_t set_dlm_avg(struct device *dev, ++ struct device_attribute *dev_attr, const char *buf, size_t count) ++{ ++ unsigned long val; ++ int i; ++ ++ if (!sscanf(dev_attr->attr.name, "dcp%d_dlm_avg", &i)) ++ return -EINVAL; ++ if (i < DCP_MIN_ID || i > DCP_MAX_ID) ++ return -EINVAL; ++ if (kstrtoul(buf, 0, &val)) { ++ dev_dbg(dev, "invalid input %s\n", buf); ++ return -EINVAL; ++ } ++ qm_out(DCP_DLM_AVG(i), val); ++ return count; ++}; ++ ++static ssize_t show_pfdr_cfg(struct device *dev, ++ struct device_attribute *dev_attr, char *buf) ++{ ++ return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(PFDR_CFG)); ++}; ++ ++static ssize_t set_pfdr_cfg(struct device *dev, ++ struct device_attribute *dev_attr, const char *buf, size_t count) ++{ ++ unsigned long val; ++ ++ if (kstrtoul(buf, 0, &val)) { ++ dev_dbg(dev, "invalid input %s\n", buf); ++ return -EINVAL; ++ } ++ qm_out(PFDR_CFG, val); ++ return count; ++}; ++ ++static ssize_t show_sfdr_in_use(struct device *dev, ++ struct device_attribute *dev_attr, char *buf) ++{ ++ return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(SFDR_IN_USE)); ++}; ++ ++static ssize_t show_idle_stat(struct device *dev, ++ struct device_attribute *dev_attr, char *buf) ++{ ++ return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(IDLE_STAT)); ++}; ++ ++static ssize_t show_ci_rlm_avg(struct device *dev, ++ struct device_attribute *dev_attr, char *buf) ++{ ++ u32 data = qm_in(CI_RLM_AVG); ++ return snprintf(buf, PAGE_SIZE, "%d.%08d\n", data>>8, ++ (data & 0x000000ff)*390625); ++}; ++ ++static ssize_t set_ci_rlm_avg(struct device *dev, ++ struct device_attribute *dev_attr, const char *buf, size_t count) ++{ ++ unsigned long val; ++ ++ if (kstrtoul(buf, 0, &val)) { ++ dev_dbg(dev, "invalid input %s\n", buf); ++ return -EINVAL; ++ } ++ qm_out(CI_RLM_AVG, val); ++ return count; ++}; ++ ++static ssize_t show_err_isr(struct device *dev, ++ struct device_attribute *dev_attr, char *buf) ++{ ++ return snprintf(buf, PAGE_SIZE, "0x%08x\n", qm_in(ERR_ISR)); ++}; ++ ++#define SBEC_MAX_ID 14 ++#define SBEC_MIN_ID 0 ++ ++static ssize_t show_sbec(struct device *dev, ++ struct device_attribute *dev_attr, char *buf) ++{ ++ int i; ++ ++ if (!sscanf(dev_attr->attr.name, "sbec_%d", &i)) ++ return -EINVAL; ++ if (i < SBEC_MIN_ID || i > SBEC_MAX_ID) ++ return -EINVAL; ++ return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(SBEC(i))); ++}; ++ ++static DEVICE_ATTR(pfdr_fpc, S_IRUSR, show_pfdr_fpc, NULL); ++static DEVICE_ATTR(pfdr_cfg, S_IRUSR, show_pfdr_cfg, set_pfdr_cfg); ++static DEVICE_ATTR(idle_stat, S_IRUSR, show_idle_stat, NULL); ++static DEVICE_ATTR(ci_rlm_avg, (S_IRUSR|S_IWUSR), ++ show_ci_rlm_avg, set_ci_rlm_avg); ++static DEVICE_ATTR(err_isr, S_IRUSR, show_err_isr, NULL); ++static DEVICE_ATTR(sfdr_in_use, S_IRUSR, show_sfdr_in_use, NULL); ++ ++static DEVICE_ATTR(dcp0_dlm_avg, (S_IRUSR|S_IWUSR), show_dlm_avg, set_dlm_avg); ++static DEVICE_ATTR(dcp1_dlm_avg, (S_IRUSR|S_IWUSR), show_dlm_avg, set_dlm_avg); ++static DEVICE_ATTR(dcp2_dlm_avg, (S_IRUSR|S_IWUSR), show_dlm_avg, set_dlm_avg); ++static DEVICE_ATTR(dcp3_dlm_avg, (S_IRUSR|S_IWUSR), show_dlm_avg, set_dlm_avg); ++ ++static DEVICE_ATTR(sbec_0, S_IRUSR, show_sbec, NULL); ++static DEVICE_ATTR(sbec_1, S_IRUSR, show_sbec, NULL); ++static DEVICE_ATTR(sbec_2, S_IRUSR, show_sbec, NULL); ++static DEVICE_ATTR(sbec_3, S_IRUSR, show_sbec, NULL); ++static DEVICE_ATTR(sbec_4, S_IRUSR, show_sbec, NULL); ++static DEVICE_ATTR(sbec_5, S_IRUSR, show_sbec, NULL); ++static DEVICE_ATTR(sbec_6, S_IRUSR, show_sbec, NULL); ++static DEVICE_ATTR(sbec_7, S_IRUSR, show_sbec, NULL); ++static DEVICE_ATTR(sbec_8, S_IRUSR, show_sbec, NULL); ++static DEVICE_ATTR(sbec_9, S_IRUSR, show_sbec, NULL); ++static DEVICE_ATTR(sbec_10, S_IRUSR, show_sbec, NULL); ++static DEVICE_ATTR(sbec_11, S_IRUSR, show_sbec, NULL); ++static DEVICE_ATTR(sbec_12, S_IRUSR, show_sbec, NULL); ++static DEVICE_ATTR(sbec_13, S_IRUSR, show_sbec, NULL); ++static DEVICE_ATTR(sbec_14, S_IRUSR, show_sbec, NULL); ++ ++static struct attribute *qman_dev_attributes[] = { ++ &dev_attr_pfdr_fpc.attr, ++ &dev_attr_pfdr_cfg.attr, ++ &dev_attr_idle_stat.attr, ++ &dev_attr_ci_rlm_avg.attr, ++ &dev_attr_err_isr.attr, ++ &dev_attr_dcp0_dlm_avg.attr, ++ &dev_attr_dcp1_dlm_avg.attr, ++ &dev_attr_dcp2_dlm_avg.attr, ++ &dev_attr_dcp3_dlm_avg.attr, ++ /* sfdr_in_use will be added if necessary */ ++ NULL ++}; ++ ++static struct attribute *qman_dev_ecr_attributes[] = { ++ &dev_attr_sbec_0.attr, ++ &dev_attr_sbec_1.attr, ++ &dev_attr_sbec_2.attr, ++ &dev_attr_sbec_3.attr, ++ &dev_attr_sbec_4.attr, ++ &dev_attr_sbec_5.attr, ++ &dev_attr_sbec_6.attr, ++ &dev_attr_sbec_7.attr, ++ &dev_attr_sbec_8.attr, ++ &dev_attr_sbec_9.attr, ++ &dev_attr_sbec_10.attr, ++ &dev_attr_sbec_11.attr, ++ &dev_attr_sbec_12.attr, ++ &dev_attr_sbec_13.attr, ++ &dev_attr_sbec_14.attr, ++ NULL ++}; ++ ++/* root level */ ++static const struct attribute_group qman_dev_attr_grp = { ++ .name = NULL, ++ .attrs = qman_dev_attributes ++}; ++static const struct attribute_group qman_dev_ecr_grp = { ++ .name = "error_capture", ++ .attrs = qman_dev_ecr_attributes ++}; ++ ++static int of_fsl_qman_remove(struct platform_device *ofdev) ++{ ++ sysfs_remove_group(&ofdev->dev.kobj, &qman_dev_attr_grp); ++ return 0; ++}; ++ ++static int of_fsl_qman_probe(struct platform_device *ofdev) ++{ ++ int ret; ++ ++ ret = sysfs_create_group(&ofdev->dev.kobj, &qman_dev_attr_grp); ++ if (ret) ++ goto done; ++ ret = sysfs_add_file_to_group(&ofdev->dev.kobj, ++ &dev_attr_sfdr_in_use.attr, qman_dev_attr_grp.name); ++ if (ret) ++ goto del_group_0; ++ ret = sysfs_create_group(&ofdev->dev.kobj, &qman_dev_ecr_grp); ++ if (ret) ++ goto del_group_0; ++ ++ goto done; ++ ++del_group_0: ++ sysfs_remove_group(&ofdev->dev.kobj, &qman_dev_attr_grp); ++done: ++ if (ret) ++ dev_err(&ofdev->dev, ++ "Cannot create dev attributes ret=%d\n", ret); ++ return ret; ++}; ++ ++static struct of_device_id of_fsl_qman_ids[] = { ++ { ++ .compatible = "fsl,qman", ++ }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, of_fsl_qman_ids); ++ ++#ifdef CONFIG_SUSPEND ++ ++static u32 saved_isdr; ++static int qman_pm_suspend_noirq(struct device *dev) ++{ ++ uint32_t idle_state; ++ ++ suspend_unused_qportal(); ++ /* save isdr, disable all, clear isr */ ++ saved_isdr = qm_err_isr_disable_read(qm); ++ qm_err_isr_disable_write(qm, 0xffffffff); ++ qm_err_isr_status_clear(qm, 0xffffffff); ++ idle_state = qm_in(IDLE_STAT); ++ if (!(idle_state & 0x1)) { ++ pr_err("Qman not idle 0x%x aborting\n", idle_state); ++ qm_err_isr_disable_write(qm, saved_isdr); ++ resume_unused_qportal(); ++ return -EBUSY; ++ } ++#ifdef CONFIG_PM_DEBUG ++ pr_info("Qman suspend code, IDLE_STAT = 0x%x\n", idle_state); ++#endif ++ return 0; ++} ++ ++static int qman_pm_resume_noirq(struct device *dev) ++{ ++ /* restore isdr */ ++ qm_err_isr_disable_write(qm, saved_isdr); ++ resume_unused_qportal(); ++ return 0; ++} ++#else ++#define qman_pm_suspend_noirq NULL ++#define qman_pm_resume_noirq NULL ++#endif ++ ++static const struct dev_pm_ops qman_pm_ops = { ++ .suspend_noirq = qman_pm_suspend_noirq, ++ .resume_noirq = qman_pm_resume_noirq, ++}; ++ ++static struct platform_driver of_fsl_qman_driver = { ++ .driver = { ++ .owner = THIS_MODULE, ++ .name = DRV_NAME, ++ .of_match_table = of_fsl_qman_ids, ++ .pm = &qman_pm_ops, ++ }, ++ .probe = of_fsl_qman_probe, ++ .remove = of_fsl_qman_remove, ++}; ++ ++static int qman_ctrl_init(void) ++{ ++ return platform_driver_register(&of_fsl_qman_driver); ++} ++ ++static void qman_ctrl_exit(void) ++{ ++ platform_driver_unregister(&of_fsl_qman_driver); ++} ++ ++module_init(qman_ctrl_init); ++module_exit(qman_ctrl_exit); ++ ++#endif /* CONFIG_SYSFS */ +diff --git a/drivers/staging/fsl_qbman/qman_debugfs.c b/drivers/staging/fsl_qbman/qman_debugfs.c +new file mode 100644 +index 00000000..fb8ecba1 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/qman_debugfs.c +@@ -0,0 +1,1594 @@ ++/* Copyright 2010-2011 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++#include "qman_private.h" ++ ++#define MAX_FQID (0x00ffffff) ++#define QM_FQD_BLOCK_SIZE 64 ++#define QM_FQD_AR (0xC10) ++ ++static u32 fqid_max; ++static u64 qman_ccsr_start; ++static u64 qman_ccsr_size; ++ ++static const char * const state_txt[] = { ++ "Out of Service", ++ "Retired", ++ "Tentatively Scheduled", ++ "Truly Scheduled", ++ "Parked", ++ "Active, Active Held or Held Suspended", ++ "Unknown State 6", ++ "Unknown State 7", ++ NULL, ++}; ++ ++static const u8 fqd_states[] = { ++ QM_MCR_NP_STATE_OOS, QM_MCR_NP_STATE_RETIRED, QM_MCR_NP_STATE_TEN_SCHED, ++ QM_MCR_NP_STATE_TRU_SCHED, QM_MCR_NP_STATE_PARKED, ++ QM_MCR_NP_STATE_ACTIVE}; ++ ++struct mask_to_text { ++ u16 mask; ++ const char *txt; ++}; ++ ++struct mask_filter_s { ++ u16 mask; ++ u8 filter; ++}; ++ ++static const struct mask_filter_s mask_filter[] = { ++ {QM_FQCTRL_PREFERINCACHE, 0}, ++ {QM_FQCTRL_PREFERINCACHE, 1}, ++ {QM_FQCTRL_HOLDACTIVE, 0}, ++ {QM_FQCTRL_HOLDACTIVE, 1}, ++ {QM_FQCTRL_AVOIDBLOCK, 0}, ++ {QM_FQCTRL_AVOIDBLOCK, 1}, ++ {QM_FQCTRL_FORCESFDR, 0}, ++ {QM_FQCTRL_FORCESFDR, 1}, ++ {QM_FQCTRL_CPCSTASH, 0}, ++ {QM_FQCTRL_CPCSTASH, 1}, ++ {QM_FQCTRL_CTXASTASHING, 0}, ++ {QM_FQCTRL_CTXASTASHING, 1}, ++ {QM_FQCTRL_ORP, 0}, ++ {QM_FQCTRL_ORP, 1}, ++ {QM_FQCTRL_TDE, 0}, ++ {QM_FQCTRL_TDE, 1}, ++ {QM_FQCTRL_CGE, 0}, ++ {QM_FQCTRL_CGE, 1} ++}; ++ ++static const struct mask_to_text fq_ctrl_text_list[] = { ++ { ++ .mask = QM_FQCTRL_PREFERINCACHE, ++ .txt = "Prefer in cache", ++ }, ++ { ++ .mask = QM_FQCTRL_HOLDACTIVE, ++ .txt = "Hold active in portal", ++ }, ++ { ++ .mask = QM_FQCTRL_AVOIDBLOCK, ++ .txt = "Avoid Blocking", ++ }, ++ { ++ .mask = QM_FQCTRL_FORCESFDR, ++ .txt = "High-priority SFDRs", ++ }, ++ { ++ .mask = QM_FQCTRL_CPCSTASH, ++ .txt = "CPC Stash Enable", ++ }, ++ { ++ .mask = QM_FQCTRL_CTXASTASHING, ++ .txt = "Context-A stashing", ++ }, ++ { ++ .mask = QM_FQCTRL_ORP, ++ .txt = "ORP Enable", ++ }, ++ { ++ .mask = QM_FQCTRL_TDE, ++ .txt = "Tail-Drop Enable", ++ }, ++ { ++ .mask = QM_FQCTRL_CGE, ++ .txt = "Congestion Group Enable", ++ }, ++ { ++ .mask = 0, ++ .txt = NULL, ++ } ++}; ++ ++static const char *get_fqd_ctrl_text(u16 mask) ++{ ++ int i = 0; ++ ++ while (fq_ctrl_text_list[i].txt != NULL) { ++ if (fq_ctrl_text_list[i].mask == mask) ++ return fq_ctrl_text_list[i].txt; ++ i++; ++ } ++ return NULL; ++} ++ ++static const struct mask_to_text stashing_text_list[] = { ++ { ++ .mask = QM_STASHING_EXCL_CTX, ++ .txt = "FQ Ctx Stash" ++ }, ++ { ++ .mask = QM_STASHING_EXCL_DATA, ++ .txt = "Frame Data Stash", ++ }, ++ { ++ .mask = QM_STASHING_EXCL_ANNOTATION, ++ .txt = "Frame Annotation Stash", ++ }, ++ { ++ .mask = 0, ++ .txt = NULL, ++ }, ++}; ++ ++static int user_input_convert(const char __user *user_buf, size_t count, ++ unsigned long *val) ++{ ++ char buf[12]; ++ ++ if (count > sizeof(buf) - 1) ++ return -EINVAL; ++ if (copy_from_user(buf, user_buf, count)) ++ return -EFAULT; ++ buf[count] = '\0'; ++ if (kstrtoul(buf, 0, val)) ++ return -EINVAL; ++ return 0; ++} ++ ++struct line_buffer_fq { ++ u32 buf[8]; ++ u32 buf_cnt; ++ int line_cnt; ++}; ++ ++static void add_to_line_buffer(struct line_buffer_fq *line_buf, u32 fqid, ++ struct seq_file *file) ++{ ++ line_buf->buf[line_buf->buf_cnt] = fqid; ++ line_buf->buf_cnt++; ++ if (line_buf->buf_cnt == 8) { ++ /* Buffer is full, flush it */ ++ if (line_buf->line_cnt != 0) ++ seq_puts(file, ",\n"); ++ seq_printf(file, "0x%06x,0x%06x,0x%06x,0x%06x,0x%06x," ++ "0x%06x,0x%06x,0x%06x", ++ line_buf->buf[0], line_buf->buf[1], line_buf->buf[2], ++ line_buf->buf[3], line_buf->buf[4], line_buf->buf[5], ++ line_buf->buf[6], line_buf->buf[7]); ++ line_buf->buf_cnt = 0; ++ line_buf->line_cnt++; ++ } ++} ++ ++static void flush_line_buffer(struct line_buffer_fq *line_buf, ++ struct seq_file *file) ++{ ++ if (line_buf->buf_cnt) { ++ int y = 0; ++ if (line_buf->line_cnt != 0) ++ seq_puts(file, ",\n"); ++ while (y != line_buf->buf_cnt) { ++ if (y+1 == line_buf->buf_cnt) ++ seq_printf(file, "0x%06x", line_buf->buf[y]); ++ else ++ seq_printf(file, "0x%06x,", line_buf->buf[y]); ++ y++; ++ } ++ line_buf->line_cnt++; ++ } ++ if (line_buf->line_cnt) ++ seq_putc(file, '\n'); ++} ++ ++static struct dentry *dfs_root; /* debugfs root directory */ ++ ++/******************************************************************************* ++ * Query Frame Queue Non Programmable Fields ++ ******************************************************************************/ ++struct query_fq_np_fields_data_s { ++ u32 fqid; ++}; ++static struct query_fq_np_fields_data_s query_fq_np_fields_data = { ++ .fqid = 1, ++}; ++ ++static int query_fq_np_fields_show(struct seq_file *file, void *offset) ++{ ++ int ret; ++ struct qm_mcr_queryfq_np np; ++ struct qman_fq fq; ++ ++ fq.fqid = query_fq_np_fields_data.fqid; ++ ret = qman_query_fq_np(&fq, &np); ++ if (ret) ++ return ret; ++ /* Print state */ ++ seq_printf(file, "Query FQ Non Programmable Fields Result fqid 0x%x\n", ++ fq.fqid); ++ seq_printf(file, " force eligible pending: %s\n", ++ (np.state & QM_MCR_NP_STATE_FE) ? "yes" : "no"); ++ seq_printf(file, " retirement pending: %s\n", ++ (np.state & QM_MCR_NP_STATE_R) ? "yes" : "no"); ++ seq_printf(file, " state: %s\n", ++ state_txt[np.state & QM_MCR_NP_STATE_MASK]); ++ seq_printf(file, " fq_link: 0x%x\n", np.fqd_link); ++ seq_printf(file, " odp_seq: %u\n", np.odp_seq); ++ seq_printf(file, " orp_nesn: %u\n", np.orp_nesn); ++ seq_printf(file, " orp_ea_hseq: %u\n", np.orp_ea_hseq); ++ seq_printf(file, " orp_ea_tseq: %u\n", np.orp_ea_tseq); ++ seq_printf(file, " orp_ea_hptr: 0x%x\n", np.orp_ea_hptr); ++ seq_printf(file, " orp_ea_tptr: 0x%x\n", np.orp_ea_tptr); ++ seq_printf(file, " pfdr_hptr: 0x%x\n", np.pfdr_hptr); ++ seq_printf(file, " pfdr_tptr: 0x%x\n", np.pfdr_tptr); ++ seq_printf(file, " is: ics_surp contains a %s\n", ++ (np.is) ? "deficit" : "surplus"); ++ seq_printf(file, " ics_surp: %u\n", np.ics_surp); ++ seq_printf(file, " byte_cnt: %u\n", np.byte_cnt); ++ seq_printf(file, " frm_cnt: %u\n", np.frm_cnt); ++ seq_printf(file, " ra1_sfdr: 0x%x\n", np.ra1_sfdr); ++ seq_printf(file, " ra2_sfdr: 0x%x\n", np.ra2_sfdr); ++ seq_printf(file, " od1_sfdr: 0x%x\n", np.od1_sfdr); ++ seq_printf(file, " od2_sfdr: 0x%x\n", np.od2_sfdr); ++ seq_printf(file, " od3_sfdr: 0x%x\n", np.od3_sfdr); ++ return 0; ++} ++ ++static int query_fq_np_fields_open(struct inode *inode, ++ struct file *file) ++{ ++ return single_open(file, query_fq_np_fields_show, NULL); ++} ++ ++static ssize_t query_fq_np_fields_write(struct file *f, ++ const char __user *buf, size_t count, loff_t *off) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = user_input_convert(buf, count, &val); ++ if (ret) ++ return ret; ++ if (val > MAX_FQID) ++ return -EINVAL; ++ query_fq_np_fields_data.fqid = (u32)val; ++ return count; ++} ++ ++static const struct file_operations query_fq_np_fields_fops = { ++ .owner = THIS_MODULE, ++ .open = query_fq_np_fields_open, ++ .read = seq_read, ++ .write = query_fq_np_fields_write, ++ .release = single_release, ++}; ++ ++/******************************************************************************* ++ * Frame Queue Programmable Fields ++ ******************************************************************************/ ++struct query_fq_fields_data_s { ++ u32 fqid; ++}; ++ ++static struct query_fq_fields_data_s query_fq_fields_data = { ++ .fqid = 1, ++}; ++ ++static int query_fq_fields_show(struct seq_file *file, void *offset) ++{ ++ int ret; ++ struct qm_fqd fqd; ++ struct qman_fq fq; ++ int i = 0; ++ ++ memset(&fqd, 0, sizeof(struct qm_fqd)); ++ fq.fqid = query_fq_fields_data.fqid; ++ ret = qman_query_fq(&fq, &fqd); ++ if (ret) ++ return ret; ++ seq_printf(file, "Query FQ Programmable Fields Result fqid 0x%x\n", ++ fq.fqid); ++ seq_printf(file, " orprws: %u\n", fqd.orprws); ++ seq_printf(file, " oa: %u\n", fqd.oa); ++ seq_printf(file, " olws: %u\n", fqd.olws); ++ ++ seq_printf(file, " cgid: %u\n", fqd.cgid); ++ ++ if ((fqd.fq_ctrl & QM_FQCTRL_MASK) == 0) ++ seq_puts(file, " fq_ctrl: None\n"); ++ else { ++ i = 0; ++ seq_puts(file, " fq_ctrl:\n"); ++ while (fq_ctrl_text_list[i].txt != NULL) { ++ if ((fqd.fq_ctrl & QM_FQCTRL_MASK) & ++ fq_ctrl_text_list[i].mask) ++ seq_printf(file, " %s\n", ++ fq_ctrl_text_list[i].txt); ++ i++; ++ } ++ } ++ seq_printf(file, " dest_channel: %u\n", fqd.dest.channel); ++ seq_printf(file, " dest_wq: %u\n", fqd.dest.wq); ++ seq_printf(file, " ics_cred: %u\n", fqd.ics_cred); ++ seq_printf(file, " td_mant: %u\n", fqd.td.mant); ++ seq_printf(file, " td_exp: %u\n", fqd.td.exp); ++ ++ seq_printf(file, " ctx_b: 0x%x\n", fqd.context_b); ++ ++ seq_printf(file, " ctx_a: 0x%llx\n", qm_fqd_stashing_get64(&fqd)); ++ /* Any stashing configured */ ++ if ((fqd.context_a.stashing.exclusive & 0x7) == 0) ++ seq_puts(file, " ctx_a_stash_exclusive: None\n"); ++ else { ++ seq_puts(file, " ctx_a_stash_exclusive:\n"); ++ i = 0; ++ while (stashing_text_list[i].txt != NULL) { ++ if ((fqd.fq_ctrl & 0x7) & stashing_text_list[i].mask) ++ seq_printf(file, " %s\n", ++ stashing_text_list[i].txt); ++ i++; ++ } ++ } ++ seq_printf(file, " ctx_a_stash_annotation_cl: %u\n", ++ fqd.context_a.stashing.annotation_cl); ++ seq_printf(file, " ctx_a_stash_data_cl: %u\n", ++ fqd.context_a.stashing.data_cl); ++ seq_printf(file, " ctx_a_stash_context_cl: %u\n", ++ fqd.context_a.stashing.context_cl); ++ return 0; ++} ++ ++static int query_fq_fields_open(struct inode *inode, ++ struct file *file) ++{ ++ return single_open(file, query_fq_fields_show, NULL); ++} ++ ++static ssize_t query_fq_fields_write(struct file *f, ++ const char __user *buf, size_t count, loff_t *off) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = user_input_convert(buf, count, &val); ++ if (ret) ++ return ret; ++ if (val > MAX_FQID) ++ return -EINVAL; ++ query_fq_fields_data.fqid = (u32)val; ++ return count; ++} ++ ++static const struct file_operations query_fq_fields_fops = { ++ .owner = THIS_MODULE, ++ .open = query_fq_fields_open, ++ .read = seq_read, ++ .write = query_fq_fields_write, ++ .release = single_release, ++}; ++ ++/******************************************************************************* ++ * Query WQ lengths ++ ******************************************************************************/ ++struct query_wq_lengths_data_s { ++ union { ++ u16 channel_wq; /* ignores wq (3 lsbits) */ ++ struct { ++ u16 id:13; /* qm_channel */ ++ u16 __reserved:3; ++ } __packed channel; ++ }; ++}; ++static struct query_wq_lengths_data_s query_wq_lengths_data; ++static int query_wq_lengths_show(struct seq_file *file, void *offset) ++{ ++ int ret; ++ struct qm_mcr_querywq wq; ++ int i; ++ ++ memset(&wq, 0, sizeof(struct qm_mcr_querywq)); ++ wq.channel.id = query_wq_lengths_data.channel.id; ++ ret = qman_query_wq(0, &wq); ++ if (ret) ++ return ret; ++ seq_printf(file, "Query Result For Channel: 0x%x\n", wq.channel.id); ++ for (i = 0; i < 8; i++) ++ /* mask out upper 4 bits since they are not part of length */ ++ seq_printf(file, " wq%d_len : %u\n", i, wq.wq_len[i] & 0x0fff); ++ return 0; ++} ++ ++static int query_wq_lengths_open(struct inode *inode, ++ struct file *file) ++{ ++ return single_open(file, query_wq_lengths_show, NULL); ++} ++ ++static ssize_t query_wq_lengths_write(struct file *f, ++ const char __user *buf, size_t count, loff_t *off) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = user_input_convert(buf, count, &val); ++ if (ret) ++ return ret; ++ if (val > 0xfff8) ++ return -EINVAL; ++ query_wq_lengths_data.channel.id = (u16)val; ++ return count; ++} ++ ++static const struct file_operations query_wq_lengths_fops = { ++ .owner = THIS_MODULE, ++ .open = query_wq_lengths_open, ++ .read = seq_read, ++ .write = query_wq_lengths_write, ++ .release = single_release, ++}; ++ ++/******************************************************************************* ++ * Query CGR ++ ******************************************************************************/ ++struct query_cgr_s { ++ u8 cgid; ++}; ++static struct query_cgr_s query_cgr_data; ++ ++static int query_cgr_show(struct seq_file *file, void *offset) ++{ ++ int ret; ++ struct qm_mcr_querycgr cgrd; ++ struct qman_cgr cgr; ++ int i, j; ++ u32 mask; ++ ++ memset(&cgr, 0, sizeof(cgr)); ++ memset(&cgrd, 0, sizeof(cgrd)); ++ cgr.cgrid = query_cgr_data.cgid; ++ ret = qman_query_cgr(&cgr, &cgrd); ++ if (ret) ++ return ret; ++ seq_printf(file, "Query CGR id 0x%x\n", cgr.cgrid); ++ seq_printf(file, " wr_parm_g MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n", ++ cgrd.cgr.wr_parm_g.MA, cgrd.cgr.wr_parm_g.Mn, ++ cgrd.cgr.wr_parm_g.SA, cgrd.cgr.wr_parm_g.Sn, ++ cgrd.cgr.wr_parm_g.Pn); ++ ++ seq_printf(file, " wr_parm_y MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n", ++ cgrd.cgr.wr_parm_y.MA, cgrd.cgr.wr_parm_y.Mn, ++ cgrd.cgr.wr_parm_y.SA, cgrd.cgr.wr_parm_y.Sn, ++ cgrd.cgr.wr_parm_y.Pn); ++ ++ seq_printf(file, " wr_parm_r MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n", ++ cgrd.cgr.wr_parm_r.MA, cgrd.cgr.wr_parm_r.Mn, ++ cgrd.cgr.wr_parm_r.SA, cgrd.cgr.wr_parm_r.Sn, ++ cgrd.cgr.wr_parm_r.Pn); ++ ++ seq_printf(file, " wr_en_g: %u, wr_en_y: %u, we_en_r: %u\n", ++ cgrd.cgr.wr_en_g, cgrd.cgr.wr_en_y, cgrd.cgr.wr_en_r); ++ ++ seq_printf(file, " cscn_en: %u\n", cgrd.cgr.cscn_en); ++ if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) { ++ seq_puts(file, " cscn_targ_dcp:\n"); ++ mask = 0x80000000; ++ for (i = 0; i < 32; i++) { ++ if (cgrd.cgr.cscn_targ & mask) ++ seq_printf(file, " send CSCN to dcp %u\n", ++ (31 - i)); ++ mask >>= 1; ++ } ++ ++ seq_puts(file, " cscn_targ_swp:\n"); ++ for (i = 0; i < 4; i++) { ++ mask = 0x80000000; ++ for (j = 0; j < 32; j++) { ++ if (cgrd.cscn_targ_swp[i] & mask) ++ seq_printf(file, " send CSCN to swp" ++ " %u\n", (127 - (i * 32) - j)); ++ mask >>= 1; ++ } ++ } ++ } else { ++ seq_printf(file, " cscn_targ: %u\n", cgrd.cgr.cscn_targ); ++ } ++ seq_printf(file, " cstd_en: %u\n", cgrd.cgr.cstd_en); ++ seq_printf(file, " cs: %u\n", cgrd.cgr.cs); ++ ++ seq_printf(file, " cs_thresh_TA: %u, cs_thresh_Tn: %u\n", ++ cgrd.cgr.cs_thres.TA, cgrd.cgr.cs_thres.Tn); ++ ++ seq_printf(file, " mode: %s\n", ++ (cgrd.cgr.mode & QMAN_CGR_MODE_FRAME) ? ++ "frame count" : "byte count"); ++ seq_printf(file, " i_bcnt: %llu\n", qm_mcr_querycgr_i_get64(&cgrd)); ++ seq_printf(file, " a_bcnt: %llu\n", qm_mcr_querycgr_a_get64(&cgrd)); ++ ++ return 0; ++} ++ ++static int query_cgr_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, query_cgr_show, NULL); ++} ++ ++static ssize_t query_cgr_write(struct file *f, const char __user *buf, ++ size_t count, loff_t *off) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = user_input_convert(buf, count, &val); ++ if (ret) ++ return ret; ++ if (val > 0xff) ++ return -EINVAL; ++ query_cgr_data.cgid = (u8)val; ++ return count; ++} ++ ++static const struct file_operations query_cgr_fops = { ++ .owner = THIS_MODULE, ++ .open = query_cgr_open, ++ .read = seq_read, ++ .write = query_cgr_write, ++ .release = single_release, ++}; ++ ++/******************************************************************************* ++ * Test Write CGR ++ ******************************************************************************/ ++struct test_write_cgr_s { ++ u64 i_bcnt; ++ u8 cgid; ++}; ++static struct test_write_cgr_s test_write_cgr_data; ++ ++static int testwrite_cgr_show(struct seq_file *file, void *offset) ++{ ++ int ret; ++ struct qm_mcr_cgrtestwrite result; ++ struct qman_cgr cgr; ++ u64 i_bcnt; ++ ++ memset(&cgr, 0, sizeof(struct qman_cgr)); ++ memset(&result, 0, sizeof(struct qm_mcr_cgrtestwrite)); ++ cgr.cgrid = test_write_cgr_data.cgid; ++ i_bcnt = test_write_cgr_data.i_bcnt; ++ ret = qman_testwrite_cgr(&cgr, i_bcnt, &result); ++ if (ret) ++ return ret; ++ seq_printf(file, "CGR Test Write CGR id 0x%x\n", cgr.cgrid); ++ seq_printf(file, " wr_parm_g MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n", ++ result.cgr.wr_parm_g.MA, result.cgr.wr_parm_g.Mn, ++ result.cgr.wr_parm_g.SA, result.cgr.wr_parm_g.Sn, ++ result.cgr.wr_parm_g.Pn); ++ seq_printf(file, " wr_parm_y MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n", ++ result.cgr.wr_parm_y.MA, result.cgr.wr_parm_y.Mn, ++ result.cgr.wr_parm_y.SA, result.cgr.wr_parm_y.Sn, ++ result.cgr.wr_parm_y.Pn); ++ seq_printf(file, " wr_parm_r MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n", ++ result.cgr.wr_parm_r.MA, result.cgr.wr_parm_r.Mn, ++ result.cgr.wr_parm_r.SA, result.cgr.wr_parm_r.Sn, ++ result.cgr.wr_parm_r.Pn); ++ seq_printf(file, " wr_en_g: %u, wr_en_y: %u, we_en_r: %u\n", ++ result.cgr.wr_en_g, result.cgr.wr_en_y, result.cgr.wr_en_r); ++ seq_printf(file, " cscn_en: %u\n", result.cgr.cscn_en); ++ seq_printf(file, " cscn_targ: %u\n", result.cgr.cscn_targ); ++ seq_printf(file, " cstd_en: %u\n", result.cgr.cstd_en); ++ seq_printf(file, " cs: %u\n", result.cgr.cs); ++ seq_printf(file, " cs_thresh_TA: %u, cs_thresh_Tn: %u\n", ++ result.cgr.cs_thres.TA, result.cgr.cs_thres.Tn); ++ ++ /* Add Mode for Si 2 */ ++ seq_printf(file, " mode: %s\n", ++ (result.cgr.mode & QMAN_CGR_MODE_FRAME) ? ++ "frame count" : "byte count"); ++ ++ seq_printf(file, " i_bcnt: %llu\n", ++ qm_mcr_cgrtestwrite_i_get64(&result)); ++ seq_printf(file, " a_bcnt: %llu\n", ++ qm_mcr_cgrtestwrite_a_get64(&result)); ++ seq_printf(file, " wr_prob_g: %u\n", result.wr_prob_g); ++ seq_printf(file, " wr_prob_y: %u\n", result.wr_prob_y); ++ seq_printf(file, " wr_prob_r: %u\n", result.wr_prob_r); ++ return 0; ++} ++ ++static int testwrite_cgr_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, testwrite_cgr_show, NULL); ++} ++ ++static const struct file_operations testwrite_cgr_fops = { ++ .owner = THIS_MODULE, ++ .open = testwrite_cgr_open, ++ .read = seq_read, ++ .release = single_release, ++}; ++ ++ ++static int testwrite_cgr_ibcnt_show(struct seq_file *file, void *offset) ++{ ++ seq_printf(file, "i_bcnt: %llu\n", test_write_cgr_data.i_bcnt); ++ return 0; ++} ++static int testwrite_cgr_ibcnt_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, testwrite_cgr_ibcnt_show, NULL); ++} ++ ++static ssize_t testwrite_cgr_ibcnt_write(struct file *f, const char __user *buf, ++ size_t count, loff_t *off) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = user_input_convert(buf, count, &val); ++ if (ret) ++ return ret; ++ test_write_cgr_data.i_bcnt = val; ++ return count; ++} ++ ++static const struct file_operations teswrite_cgr_ibcnt_fops = { ++ .owner = THIS_MODULE, ++ .open = testwrite_cgr_ibcnt_open, ++ .read = seq_read, ++ .write = testwrite_cgr_ibcnt_write, ++ .release = single_release, ++}; ++ ++static int testwrite_cgr_cgrid_show(struct seq_file *file, void *offset) ++{ ++ seq_printf(file, "cgrid: %u\n", (u32)test_write_cgr_data.cgid); ++ return 0; ++} ++static int testwrite_cgr_cgrid_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, testwrite_cgr_cgrid_show, NULL); ++} ++ ++static ssize_t testwrite_cgr_cgrid_write(struct file *f, const char __user *buf, ++ size_t count, loff_t *off) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = user_input_convert(buf, count, &val); ++ if (ret) ++ return ret; ++ if (val > 0xff) ++ return -EINVAL; ++ test_write_cgr_data.cgid = (u8)val; ++ return count; ++} ++ ++static const struct file_operations teswrite_cgr_cgrid_fops = { ++ .owner = THIS_MODULE, ++ .open = testwrite_cgr_cgrid_open, ++ .read = seq_read, ++ .write = testwrite_cgr_cgrid_write, ++ .release = single_release, ++}; ++ ++/******************************************************************************* ++ * Query Congestion State ++ ******************************************************************************/ ++static int query_congestion_show(struct seq_file *file, void *offset) ++{ ++ int ret; ++ struct qm_mcr_querycongestion cs; ++ int i, j, in_cong = 0; ++ u32 mask; ++ ++ memset(&cs, 0, sizeof(struct qm_mcr_querycongestion)); ++ ret = qman_query_congestion(&cs); ++ if (ret) ++ return ret; ++ seq_puts(file, "Query Congestion Result\n"); ++ for (i = 0; i < 8; i++) { ++ mask = 0x80000000; ++ for (j = 0; j < 32; j++) { ++ if (cs.state.__state[i] & mask) { ++ in_cong = 1; ++ seq_printf(file, " cg %u: %s\n", (i*32)+j, ++ "in congestion"); ++ } ++ mask >>= 1; ++ } ++ } ++ if (!in_cong) ++ seq_puts(file, " All congestion groups not congested.\n"); ++ return 0; ++} ++ ++static int query_congestion_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, query_congestion_show, NULL); ++} ++ ++static const struct file_operations query_congestion_fops = { ++ .owner = THIS_MODULE, ++ .open = query_congestion_open, ++ .read = seq_read, ++ .release = single_release, ++}; ++ ++/******************************************************************************* ++ * Query CCGR ++ ******************************************************************************/ ++struct query_ccgr_s { ++ u32 ccgid; ++}; ++static struct query_ccgr_s query_ccgr_data; ++ ++static int query_ccgr_show(struct seq_file *file, void *offset) ++{ ++ int ret; ++ struct qm_mcr_ceetm_ccgr_query ccgr_query; ++ struct qm_mcc_ceetm_ccgr_query query_opts; ++ int i, j; ++ u32 mask; ++ ++ memset(&ccgr_query, 0, sizeof(struct qm_mcr_ceetm_ccgr_query)); ++ memset(&query_opts, 0, sizeof(struct qm_mcc_ceetm_ccgr_query)); ++ ++ if ((qman_ip_rev & 0xFF00) < QMAN_REV30) ++ return -EINVAL; ++ ++ seq_printf(file, "Query CCGID %x\n", query_ccgr_data.ccgid); ++ query_opts.dcpid = ((query_ccgr_data.ccgid & 0xFF000000) >> 24); ++ query_opts.ccgrid = query_ccgr_data.ccgid & 0x000001FF; ++ ret = qman_ceetm_query_ccgr(&query_opts, &ccgr_query); ++ if (ret) ++ return ret; ++ seq_printf(file, "Query CCGR id %x in DCP %d\n", query_opts.ccgrid, ++ query_opts.dcpid); ++ seq_printf(file, " wr_parm_g MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n", ++ ccgr_query.cm_query.wr_parm_g.MA, ++ ccgr_query.cm_query.wr_parm_g.Mn, ++ ccgr_query.cm_query.wr_parm_g.SA, ++ ccgr_query.cm_query.wr_parm_g.Sn, ++ ccgr_query.cm_query.wr_parm_g.Pn); ++ ++ seq_printf(file, " wr_parm_y MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n", ++ ccgr_query.cm_query.wr_parm_y.MA, ++ ccgr_query.cm_query.wr_parm_y.Mn, ++ ccgr_query.cm_query.wr_parm_y.SA, ++ ccgr_query.cm_query.wr_parm_y.Sn, ++ ccgr_query.cm_query.wr_parm_y.Pn); ++ ++ seq_printf(file, " wr_parm_r MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n", ++ ccgr_query.cm_query.wr_parm_r.MA, ++ ccgr_query.cm_query.wr_parm_r.Mn, ++ ccgr_query.cm_query.wr_parm_r.SA, ++ ccgr_query.cm_query.wr_parm_r.Sn, ++ ccgr_query.cm_query.wr_parm_r.Pn); ++ ++ seq_printf(file, " wr_en_g: %u, wr_en_y: %u, we_en_r: %u\n", ++ ccgr_query.cm_query.ctl_wr_en_g, ++ ccgr_query.cm_query.ctl_wr_en_y, ++ ccgr_query.cm_query.ctl_wr_en_r); ++ ++ seq_printf(file, " cscn_en: %u\n", ccgr_query.cm_query.ctl_cscn_en); ++ seq_puts(file, " cscn_targ_dcp:\n"); ++ mask = 0x80000000; ++ for (i = 0; i < 32; i++) { ++ if (ccgr_query.cm_query.cscn_targ_dcp & mask) ++ seq_printf(file, " send CSCN to dcp %u\n", (31 - i)); ++ mask >>= 1; ++ } ++ ++ seq_puts(file, " cscn_targ_swp:\n"); ++ for (i = 0; i < 4; i++) { ++ mask = 0x80000000; ++ for (j = 0; j < 32; j++) { ++ if (ccgr_query.cm_query.cscn_targ_swp[i] & mask) ++ seq_printf(file, " send CSCN to swp" ++ "%u\n", (127 - (i * 32) - j)); ++ mask >>= 1; ++ } ++ } ++ ++ seq_printf(file, " td_en: %u\n", ccgr_query.cm_query.ctl_td_en); ++ ++ seq_printf(file, " cs_thresh_in_TA: %u, cs_thresh_in_Tn: %u\n", ++ ccgr_query.cm_query.cs_thres.TA, ++ ccgr_query.cm_query.cs_thres.Tn); ++ ++ seq_printf(file, " cs_thresh_out_TA: %u, cs_thresh_out_Tn: %u\n", ++ ccgr_query.cm_query.cs_thres_x.TA, ++ ccgr_query.cm_query.cs_thres_x.Tn); ++ ++ seq_printf(file, " td_thresh_TA: %u, td_thresh_Tn: %u\n", ++ ccgr_query.cm_query.td_thres.TA, ++ ccgr_query.cm_query.td_thres.Tn); ++ ++ seq_printf(file, " mode: %s\n", ++ (ccgr_query.cm_query.ctl_mode & ++ QMAN_CGR_MODE_FRAME) ? ++ "frame count" : "byte count"); ++ seq_printf(file, " i_cnt: %llu\n", (u64)ccgr_query.cm_query.i_cnt); ++ seq_printf(file, " a_cnt: %llu\n", (u64)ccgr_query.cm_query.a_cnt); ++ ++ return 0; ++} ++ ++static int query_ccgr_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, query_ccgr_show, NULL); ++} ++ ++static ssize_t query_ccgr_write(struct file *f, const char __user *buf, ++ size_t count, loff_t *off) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = user_input_convert(buf, count, &val); ++ if (ret) ++ return ret; ++ query_ccgr_data.ccgid = val; ++ return count; ++} ++ ++static const struct file_operations query_ccgr_fops = { ++ .owner = THIS_MODULE, ++ .open = query_ccgr_open, ++ .read = seq_read, ++ .write = query_ccgr_write, ++ .release = single_release, ++}; ++/******************************************************************************* ++ * QMan register ++ ******************************************************************************/ ++struct qman_register_s { ++ u32 val; ++}; ++static struct qman_register_s qman_register_data; ++ ++static void init_ccsrmempeek(void) ++{ ++ struct device_node *dn; ++ const u32 *regaddr_p; ++ ++ dn = of_find_compatible_node(NULL, NULL, "fsl,qman"); ++ if (!dn) { ++ pr_info("No fsl,qman node\n"); ++ return; ++ } ++ regaddr_p = of_get_address(dn, 0, &qman_ccsr_size, NULL); ++ if (!regaddr_p) { ++ of_node_put(dn); ++ return; ++ } ++ qman_ccsr_start = of_translate_address(dn, regaddr_p); ++ of_node_put(dn); ++} ++/* This function provides access to QMan ccsr memory map */ ++static int qman_ccsrmempeek(u32 *val, u32 offset) ++{ ++ void __iomem *addr; ++ u64 phys_addr; ++ ++ if (!qman_ccsr_start) ++ return -EINVAL; ++ ++ if (offset > (qman_ccsr_size - sizeof(u32))) ++ return -EINVAL; ++ ++ phys_addr = qman_ccsr_start + offset; ++ addr = ioremap(phys_addr, sizeof(u32)); ++ if (!addr) { ++ pr_err("ccsrmempeek, ioremap failed\n"); ++ return -EINVAL; ++ } ++ *val = in_be32(addr); ++ iounmap(addr); ++ return 0; ++} ++ ++static int qman_ccsrmempeek_show(struct seq_file *file, void *offset) ++{ ++ u32 b; ++ ++ qman_ccsrmempeek(&b, qman_register_data.val); ++ seq_printf(file, "QMan register offset = 0x%x\n", ++ qman_register_data.val); ++ seq_printf(file, "value = 0x%08x\n", b); ++ ++ return 0; ++} ++ ++static int qman_ccsrmempeek_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, qman_ccsrmempeek_show, NULL); ++} ++ ++static ssize_t qman_ccsrmempeek_write(struct file *f, const char __user *buf, ++ size_t count, loff_t *off) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = user_input_convert(buf, count, &val); ++ if (ret) ++ return ret; ++ /* multiple of 4 */ ++ if (val > (qman_ccsr_size - sizeof(u32))) { ++ pr_info("Input 0x%lx > 0x%llx\n", ++ val, (qman_ccsr_size - sizeof(u32))); ++ return -EINVAL; ++ } ++ if (val & 0x3) { ++ pr_info("Input 0x%lx not multiple of 4\n", val); ++ return -EINVAL; ++ } ++ qman_register_data.val = val; ++ return count; ++} ++ ++static const struct file_operations qman_ccsrmempeek_fops = { ++ .owner = THIS_MODULE, ++ .open = qman_ccsrmempeek_open, ++ .read = seq_read, ++ .write = qman_ccsrmempeek_write, ++}; ++ ++/******************************************************************************* ++ * QMan state ++ ******************************************************************************/ ++static int qman_fqd_state_show(struct seq_file *file, void *offset) ++{ ++ struct qm_mcr_queryfq_np np; ++ struct qman_fq fq; ++ struct line_buffer_fq line_buf; ++ int ret, i; ++ u8 *state = file->private; ++ u32 qm_fq_state_cnt[ARRAY_SIZE(fqd_states)]; ++ ++ memset(qm_fq_state_cnt, 0, sizeof(qm_fq_state_cnt)); ++ memset(&line_buf, 0, sizeof(line_buf)); ++ ++ seq_printf(file, "List of fq ids in state: %s\n", state_txt[*state]); ++ ++ for (i = 1; i < fqid_max; i++) { ++ fq.fqid = i; ++ ret = qman_query_fq_np(&fq, &np); ++ if (ret) ++ return ret; ++ if (*state == (np.state & QM_MCR_NP_STATE_MASK)) ++ add_to_line_buffer(&line_buf, fq.fqid, file); ++ /* Keep a summary count of all states */ ++ if ((np.state & QM_MCR_NP_STATE_MASK) < ARRAY_SIZE(fqd_states)) ++ qm_fq_state_cnt[(np.state & QM_MCR_NP_STATE_MASK)]++; ++ } ++ flush_line_buffer(&line_buf, file); ++ ++ for (i = 0; i < ARRAY_SIZE(fqd_states); i++) { ++ seq_printf(file, "%s count = %u\n", state_txt[i], ++ qm_fq_state_cnt[i]); ++ } ++ return 0; ++} ++ ++static int qman_fqd_state_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, qman_fqd_state_show, inode->i_private); ++} ++ ++static const struct file_operations qman_fqd_state_fops = { ++ .owner = THIS_MODULE, ++ .open = qman_fqd_state_open, ++ .read = seq_read, ++}; ++ ++static int qman_fqd_ctrl_show(struct seq_file *file, void *offset) ++{ ++ struct qm_fqd fqd; ++ struct qman_fq fq; ++ u32 fq_en_cnt = 0, fq_di_cnt = 0; ++ int ret, i; ++ struct mask_filter_s *data = file->private; ++ const char *ctrl_txt = get_fqd_ctrl_text(data->mask); ++ struct line_buffer_fq line_buf; ++ ++ memset(&line_buf, 0, sizeof(line_buf)); ++ seq_printf(file, "List of fq ids with: %s :%s\n", ++ ctrl_txt, (data->filter) ? "enabled" : "disabled"); ++ for (i = 1; i < fqid_max; i++) { ++ fq.fqid = i; ++ memset(&fqd, 0, sizeof(struct qm_fqd)); ++ ret = qman_query_fq(&fq, &fqd); ++ if (ret) ++ return ret; ++ if (data->filter) { ++ if (fqd.fq_ctrl & data->mask) ++ add_to_line_buffer(&line_buf, fq.fqid, file); ++ } else { ++ if (!(fqd.fq_ctrl & data->mask)) ++ add_to_line_buffer(&line_buf, fq.fqid, file); ++ } ++ if (fqd.fq_ctrl & data->mask) ++ fq_en_cnt++; ++ else ++ fq_di_cnt++; ++ } ++ flush_line_buffer(&line_buf, file); ++ ++ seq_printf(file, "Total FQD with: %s : enabled = %u\n", ++ ctrl_txt, fq_en_cnt); ++ seq_printf(file, "Total FQD with: %s : disabled = %u\n", ++ ctrl_txt, fq_di_cnt); ++ return 0; ++} ++ ++/******************************************************************************* ++ * QMan ctrl CGE, TDE, ORP, CTX, CPC, SFDR, BLOCK, HOLD, CACHE ++ ******************************************************************************/ ++static int qman_fqd_ctrl_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, qman_fqd_ctrl_show, inode->i_private); ++} ++ ++static const struct file_operations qman_fqd_ctrl_fops = { ++ .owner = THIS_MODULE, ++ .open = qman_fqd_ctrl_open, ++ .read = seq_read, ++}; ++ ++/******************************************************************************* ++ * QMan ctrl summary ++ ******************************************************************************/ ++/******************************************************************************* ++ * QMan summary state ++ ******************************************************************************/ ++static int qman_fqd_non_prog_summary_show(struct seq_file *file, void *offset) ++{ ++ struct qm_mcr_queryfq_np np; ++ struct qman_fq fq; ++ int ret, i; ++ u32 qm_fq_state_cnt[ARRAY_SIZE(fqd_states)]; ++ ++ memset(qm_fq_state_cnt, 0, sizeof(qm_fq_state_cnt)); ++ ++ for (i = 1; i < fqid_max; i++) { ++ fq.fqid = i; ++ ret = qman_query_fq_np(&fq, &np); ++ if (ret) ++ return ret; ++ /* Keep a summary count of all states */ ++ if ((np.state & QM_MCR_NP_STATE_MASK) < ARRAY_SIZE(fqd_states)) ++ qm_fq_state_cnt[(np.state & QM_MCR_NP_STATE_MASK)]++; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(fqd_states); i++) { ++ seq_printf(file, "%s count = %u\n", state_txt[i], ++ qm_fq_state_cnt[i]); ++ } ++ return 0; ++} ++ ++static int qman_fqd_prog_summary_show(struct seq_file *file, void *offset) ++{ ++ struct qm_fqd fqd; ++ struct qman_fq fq; ++ int ret, i , j; ++ u32 qm_prog_cnt[ARRAY_SIZE(mask_filter)/2]; ++ ++ memset(qm_prog_cnt, 0, sizeof(qm_prog_cnt)); ++ ++ for (i = 1; i < fqid_max; i++) { ++ memset(&fqd, 0, sizeof(struct qm_fqd)); ++ fq.fqid = i; ++ ret = qman_query_fq(&fq, &fqd); ++ if (ret) ++ return ret; ++ /* Keep a summary count of all states */ ++ for (j = 0; j < ARRAY_SIZE(mask_filter); j += 2) ++ if ((fqd.fq_ctrl & QM_FQCTRL_MASK) & ++ mask_filter[j].mask) ++ qm_prog_cnt[j/2]++; ++ } ++ for (i = 0; i < ARRAY_SIZE(mask_filter) / 2; i++) { ++ seq_printf(file, "%s count = %u\n", ++ get_fqd_ctrl_text(mask_filter[i*2].mask), ++ qm_prog_cnt[i]); ++ } ++ return 0; ++} ++ ++static int qman_fqd_summary_show(struct seq_file *file, void *offset) ++{ ++ int ret; ++ ++ /* Display summary of non programmable fields */ ++ ret = qman_fqd_non_prog_summary_show(file, offset); ++ if (ret) ++ return ret; ++ seq_puts(file, "-----------------------------------------\n"); ++ /* Display programmable fields */ ++ ret = qman_fqd_prog_summary_show(file, offset); ++ if (ret) ++ return ret; ++ return 0; ++} ++ ++static int qman_fqd_summary_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, qman_fqd_summary_show, NULL); ++} ++ ++static const struct file_operations qman_fqd_summary_fops = { ++ .owner = THIS_MODULE, ++ .open = qman_fqd_summary_open, ++ .read = seq_read, ++}; ++ ++/******************************************************************************* ++ * QMan destination work queue ++ ******************************************************************************/ ++struct qman_dest_wq_s { ++ u16 wq_id; ++}; ++static struct qman_dest_wq_s qman_dest_wq_data = { ++ .wq_id = 0, ++}; ++ ++static int qman_fqd_dest_wq_show(struct seq_file *file, void *offset) ++{ ++ struct qm_fqd fqd; ++ struct qman_fq fq; ++ int ret, i; ++ u16 *wq, wq_id = qman_dest_wq_data.wq_id; ++ struct line_buffer_fq line_buf; ++ ++ memset(&line_buf, 0, sizeof(line_buf)); ++ /* use vmalloc : need to allocate large memory region and don't ++ * require the memory to be physically contiguous. */ ++ wq = vzalloc(sizeof(u16) * (0xFFFF+1)); ++ if (!wq) ++ return -ENOMEM; ++ ++ seq_printf(file, "List of fq ids with destination work queue id" ++ " = 0x%x\n", wq_id); ++ ++ for (i = 1; i < fqid_max; i++) { ++ fq.fqid = i; ++ memset(&fqd, 0, sizeof(struct qm_fqd)); ++ ret = qman_query_fq(&fq, &fqd); ++ if (ret) { ++ vfree(wq); ++ return ret; ++ } ++ if (wq_id == fqd.dest_wq) ++ add_to_line_buffer(&line_buf, fq.fqid, file); ++ wq[fqd.dest_wq]++; ++ } ++ flush_line_buffer(&line_buf, file); ++ ++ seq_puts(file, "Summary of all FQD destination work queue values\n"); ++ for (i = 0; i < 0xFFFF; i++) { ++ if (wq[i]) ++ seq_printf(file, "Channel: 0x%x WQ: 0x%x WQ_ID: 0x%x, " ++ "count = %u\n", i >> 3, i & 0x3, i, wq[i]); ++ } ++ vfree(wq); ++ return 0; ++} ++ ++static ssize_t qman_fqd_dest_wq_write(struct file *f, const char __user *buf, ++ size_t count, loff_t *off) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = user_input_convert(buf, count, &val); ++ if (ret) ++ return ret; ++ if (val > 0xFFFF) ++ return -EINVAL; ++ qman_dest_wq_data.wq_id = val; ++ return count; ++} ++ ++static int qman_fqd_dest_wq_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, qman_fqd_dest_wq_show, NULL); ++} ++ ++static const struct file_operations qman_fqd_dest_wq_fops = { ++ .owner = THIS_MODULE, ++ .open = qman_fqd_dest_wq_open, ++ .read = seq_read, ++ .write = qman_fqd_dest_wq_write, ++}; ++ ++/******************************************************************************* ++ * QMan Intra-Class Scheduling Credit ++ ******************************************************************************/ ++static int qman_fqd_cred_show(struct seq_file *file, void *offset) ++{ ++ struct qm_fqd fqd; ++ struct qman_fq fq; ++ int ret, i; ++ u32 fq_cnt = 0; ++ struct line_buffer_fq line_buf; ++ ++ memset(&line_buf, 0, sizeof(line_buf)); ++ seq_puts(file, "List of fq ids with Intra-Class Scheduling Credit > 0" ++ "\n"); ++ ++ for (i = 1; i < fqid_max; i++) { ++ fq.fqid = i; ++ memset(&fqd, 0, sizeof(struct qm_fqd)); ++ ret = qman_query_fq(&fq, &fqd); ++ if (ret) ++ return ret; ++ if (fqd.ics_cred > 0) { ++ add_to_line_buffer(&line_buf, fq.fqid, file); ++ fq_cnt++; ++ } ++ } ++ flush_line_buffer(&line_buf, file); ++ ++ seq_printf(file, "Total FQD with ics_cred > 0 = %d\n", fq_cnt); ++ return 0; ++} ++ ++static int qman_fqd_cred_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, qman_fqd_cred_show, NULL); ++} ++ ++static const struct file_operations qman_fqd_cred_fops = { ++ .owner = THIS_MODULE, ++ .open = qman_fqd_cred_open, ++ .read = seq_read, ++}; ++ ++/******************************************************************************* ++ * Class Queue Fields ++ ******************************************************************************/ ++struct query_cq_fields_data_s { ++ u32 cqid; ++}; ++ ++static struct query_cq_fields_data_s query_cq_fields_data = { ++ .cqid = 1, ++}; ++ ++static int query_cq_fields_show(struct seq_file *file, void *offset) ++{ ++ int ret; ++ struct qm_mcr_ceetm_cq_query query_result; ++ unsigned int cqid; ++ unsigned int portal; ++ ++ if ((qman_ip_rev & 0xFF00) < QMAN_REV30) ++ return -EINVAL; ++ ++ cqid = query_cq_fields_data.cqid & 0x00FFFFFF; ++ portal = query_cq_fields_data.cqid >> 24; ++ if (portal > qm_dc_portal_fman1) ++ return -EINVAL; ++ ++ ret = qman_ceetm_query_cq(cqid, portal, &query_result); ++ if (ret) ++ return ret; ++ seq_printf(file, "Query CQ Fields Result cqid 0x%x on DCP %d\n", ++ cqid, portal); ++ seq_printf(file, " ccgid: %u\n", query_result.ccgid); ++ seq_printf(file, " state: %u\n", query_result.state); ++ seq_printf(file, " pfdr_hptr: %u\n", query_result.pfdr_hptr); ++ seq_printf(file, " pfdr_tptr: %u\n", query_result.pfdr_tptr); ++ seq_printf(file, " od1_xsfdr: %u\n", query_result.od1_xsfdr); ++ seq_printf(file, " od2_xsfdr: %u\n", query_result.od2_xsfdr); ++ seq_printf(file, " od3_xsfdr: %u\n", query_result.od3_xsfdr); ++ seq_printf(file, " od4_xsfdr: %u\n", query_result.od4_xsfdr); ++ seq_printf(file, " od5_xsfdr: %u\n", query_result.od5_xsfdr); ++ seq_printf(file, " od6_xsfdr: %u\n", query_result.od6_xsfdr); ++ seq_printf(file, " ra1_xsfdr: %u\n", query_result.ra1_xsfdr); ++ seq_printf(file, " ra2_xsfdr: %u\n", query_result.ra2_xsfdr); ++ seq_printf(file, " frame_count: %u\n", query_result.frm_cnt); ++ ++ return 0; ++} ++ ++static int query_cq_fields_open(struct inode *inode, ++ struct file *file) ++{ ++ return single_open(file, query_cq_fields_show, NULL); ++} ++ ++static ssize_t query_cq_fields_write(struct file *f, ++ const char __user *buf, size_t count, loff_t *off) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = user_input_convert(buf, count, &val); ++ if (ret) ++ return ret; ++ query_cq_fields_data.cqid = (u32)val; ++ return count; ++} ++ ++static const struct file_operations query_cq_fields_fops = { ++ .owner = THIS_MODULE, ++ .open = query_cq_fields_open, ++ .read = seq_read, ++ .write = query_cq_fields_write, ++ .release = single_release, ++}; ++ ++/******************************************************************************* ++ * READ CEETM_XSFDR_IN_USE ++ ******************************************************************************/ ++struct query_ceetm_xsfdr_data_s { ++ enum qm_dc_portal dcp_portal; ++}; ++ ++static struct query_ceetm_xsfdr_data_s query_ceetm_xsfdr_data; ++ ++static int query_ceetm_xsfdr_show(struct seq_file *file, void *offset) ++{ ++ int ret; ++ unsigned int xsfdr_in_use; ++ enum qm_dc_portal portal; ++ ++ ++ if (qman_ip_rev < QMAN_REV31) ++ return -EINVAL; ++ ++ portal = query_ceetm_xsfdr_data.dcp_portal; ++ ret = qman_ceetm_get_xsfdr(portal, &xsfdr_in_use); ++ if (ret) { ++ seq_printf(file, "Read CEETM_XSFDR_IN_USE on DCP %d failed\n", ++ portal); ++ return ret; ++ } ++ ++ seq_printf(file, "DCP%d: CEETM_XSFDR_IN_USE number is %u\n", portal, ++ (xsfdr_in_use & 0x1FFF)); ++ return 0; ++} ++ ++static int query_ceetm_xsfdr_open(struct inode *inode, ++ struct file *file) ++{ ++ return single_open(file, query_ceetm_xsfdr_show, NULL); ++} ++ ++static ssize_t query_ceetm_xsfdr_write(struct file *f, ++ const char __user *buf, size_t count, loff_t *off) ++{ ++ int ret; ++ unsigned long val; ++ ++ ret = user_input_convert(buf, count, &val); ++ if (ret) ++ return ret; ++ if (val > qm_dc_portal_fman1) ++ return -EINVAL; ++ query_ceetm_xsfdr_data.dcp_portal = (u32)val; ++ return count; ++} ++ ++static const struct file_operations query_ceetm_xsfdr_fops = { ++ .owner = THIS_MODULE, ++ .open = query_ceetm_xsfdr_open, ++ .read = seq_read, ++ .write = query_ceetm_xsfdr_write, ++ .release = single_release, ++}; ++ ++/* helper macros used in qman_debugfs_module_init */ ++#define QMAN_DBGFS_ENTRY(name, mode, parent, data, fops) \ ++ do { \ ++ d = debugfs_create_file(name, \ ++ mode, parent, \ ++ data, \ ++ fops); \ ++ if (d == NULL) { \ ++ ret = -ENOMEM; \ ++ goto _return; \ ++ } \ ++ } while (0) ++ ++/* dfs_root as parent */ ++#define QMAN_DBGFS_ENTRY_ROOT(name, mode, data, fops) \ ++ QMAN_DBGFS_ENTRY(name, mode, dfs_root, data, fops) ++ ++/* fqd_root as parent */ ++#define QMAN_DBGFS_ENTRY_FQDROOT(name, mode, data, fops) \ ++ QMAN_DBGFS_ENTRY(name, mode, fqd_root, data, fops) ++ ++/* fqd state */ ++#define QMAN_DBGFS_ENTRY_FQDSTATE(name, index) \ ++ QMAN_DBGFS_ENTRY_FQDROOT(name, S_IRUGO, \ ++ (void *)&mask_filter[index], &qman_fqd_ctrl_fops) ++ ++static int __init qman_debugfs_module_init(void) ++{ ++ int ret = 0; ++ struct dentry *d, *fqd_root; ++ u32 reg; ++ ++ fqid_max = 0; ++ init_ccsrmempeek(); ++ if (qman_ccsr_start) { ++ if (!qman_ccsrmempeek(®, QM_FQD_AR)) { ++ /* extract the size of the FQD window */ ++ reg = reg & 0x3f; ++ /* calculate valid frame queue descriptor range */ ++ fqid_max = (1 << (reg + 1)) / QM_FQD_BLOCK_SIZE; ++ } ++ } ++ dfs_root = debugfs_create_dir("qman", NULL); ++ fqd_root = debugfs_create_dir("fqd", dfs_root); ++ if (dfs_root == NULL || fqd_root == NULL) { ++ ret = -ENOMEM; ++ pr_err("Cannot create qman/fqd debugfs dir\n"); ++ goto _return; ++ } ++ if (fqid_max) { ++ QMAN_DBGFS_ENTRY_ROOT("ccsrmempeek", S_IRUGO | S_IWUGO, ++ NULL, &qman_ccsrmempeek_fops); ++ } ++ QMAN_DBGFS_ENTRY_ROOT("query_fq_np_fields", S_IRUGO | S_IWUGO, ++ &query_fq_np_fields_data, &query_fq_np_fields_fops); ++ ++ QMAN_DBGFS_ENTRY_ROOT("query_fq_fields", S_IRUGO | S_IWUGO, ++ &query_fq_fields_data, &query_fq_fields_fops); ++ ++ QMAN_DBGFS_ENTRY_ROOT("query_wq_lengths", S_IRUGO | S_IWUGO, ++ &query_wq_lengths_data, &query_wq_lengths_fops); ++ ++ QMAN_DBGFS_ENTRY_ROOT("query_cgr", S_IRUGO | S_IWUGO, ++ &query_cgr_data, &query_cgr_fops); ++ ++ QMAN_DBGFS_ENTRY_ROOT("query_congestion", S_IRUGO, ++ NULL, &query_congestion_fops); ++ ++ QMAN_DBGFS_ENTRY_ROOT("testwrite_cgr", S_IRUGO, ++ NULL, &testwrite_cgr_fops); ++ ++ QMAN_DBGFS_ENTRY_ROOT("testwrite_cgr_cgrid", S_IRUGO | S_IWUGO, ++ NULL, &teswrite_cgr_cgrid_fops); ++ ++ QMAN_DBGFS_ENTRY_ROOT("testwrite_cgr_ibcnt", S_IRUGO | S_IWUGO, ++ NULL, &teswrite_cgr_ibcnt_fops); ++ ++ QMAN_DBGFS_ENTRY_ROOT("query_ceetm_ccgr", S_IRUGO | S_IWUGO, ++ &query_ccgr_data, &query_ccgr_fops); ++ /* Create files with fqd_root as parent */ ++ ++ QMAN_DBGFS_ENTRY_FQDROOT("stateoos", S_IRUGO, ++ (void *)&fqd_states[QM_MCR_NP_STATE_OOS], &qman_fqd_state_fops); ++ ++ QMAN_DBGFS_ENTRY_FQDROOT("state_retired", S_IRUGO, ++ (void *)&fqd_states[QM_MCR_NP_STATE_RETIRED], ++ &qman_fqd_state_fops); ++ ++ QMAN_DBGFS_ENTRY_FQDROOT("state_tentatively_sched", S_IRUGO, ++ (void *)&fqd_states[QM_MCR_NP_STATE_TEN_SCHED], ++ &qman_fqd_state_fops); ++ ++ QMAN_DBGFS_ENTRY_FQDROOT("state_truly_sched", S_IRUGO, ++ (void *)&fqd_states[QM_MCR_NP_STATE_TRU_SCHED], ++ &qman_fqd_state_fops); ++ ++ QMAN_DBGFS_ENTRY_FQDROOT("state_parked", S_IRUGO, ++ (void *)&fqd_states[QM_MCR_NP_STATE_PARKED], ++ &qman_fqd_state_fops); ++ ++ QMAN_DBGFS_ENTRY_FQDROOT("state_active", S_IRUGO, ++ (void *)&fqd_states[QM_MCR_NP_STATE_ACTIVE], ++ &qman_fqd_state_fops); ++ QMAN_DBGFS_ENTRY_ROOT("query_cq_fields", S_IRUGO | S_IWUGO, ++ &query_cq_fields_data, &query_cq_fields_fops); ++ QMAN_DBGFS_ENTRY_ROOT("query_ceetm_xsfdr_in_use", S_IRUGO | S_IWUGO, ++ &query_ceetm_xsfdr_data, &query_ceetm_xsfdr_fops); ++ ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("cge_enable", 17); ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("cge_disable", 16); ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("tde_enable", 15); ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("tde_disable", 14); ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("orp_enable", 13); ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("orp_disable", 12); ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("ctx_a_stashing_enable", 11); ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("ctx_a_stashing_disable", 10); ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("cpc_enable", 9); ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("cpc_disable", 8); ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("sfdr_enable", 7); ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("sfdr_disable", 6); ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("avoid_blocking_enable", 5); ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("avoid_blocking_disable", 4); ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("hold_active_enable", 3); ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("hold_active_disable", 2); ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("prefer_in_cache_enable", 1); ++ ++ QMAN_DBGFS_ENTRY_FQDSTATE("prefer_in_cache_disable", 0); ++ ++ QMAN_DBGFS_ENTRY_FQDROOT("summary", S_IRUGO, ++ NULL, &qman_fqd_summary_fops); ++ ++ QMAN_DBGFS_ENTRY_FQDROOT("wq", S_IRUGO | S_IWUGO, ++ NULL, &qman_fqd_dest_wq_fops); ++ ++ QMAN_DBGFS_ENTRY_FQDROOT("cred", S_IRUGO, ++ NULL, &qman_fqd_cred_fops); ++ ++ return 0; ++ ++_return: ++ debugfs_remove_recursive(dfs_root); ++ return ret; ++} ++ ++static void __exit qman_debugfs_module_exit(void) ++{ ++ debugfs_remove_recursive(dfs_root); ++} ++ ++module_init(qman_debugfs_module_init); ++module_exit(qman_debugfs_module_exit); ++MODULE_LICENSE("Dual BSD/GPL"); +diff --git a/drivers/staging/fsl_qbman/qman_driver.c b/drivers/staging/fsl_qbman/qman_driver.c +new file mode 100644 +index 00000000..857ecd62 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/qman_driver.c +@@ -0,0 +1,977 @@ ++/* Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "qman_private.h" ++ ++#include /* hard_smp_processor_id() if !CONFIG_SMP */ ++#ifdef CONFIG_HOTPLUG_CPU ++#include ++#endif ++ ++/* Global variable containing revision id (even on non-control plane systems ++ * where CCSR isn't available) */ ++u16 qman_ip_rev; ++EXPORT_SYMBOL(qman_ip_rev); ++u8 qman_ip_cfg; ++EXPORT_SYMBOL(qman_ip_cfg); ++u16 qm_channel_pool1 = QMAN_CHANNEL_POOL1; ++EXPORT_SYMBOL(qm_channel_pool1); ++u16 qm_channel_caam = QMAN_CHANNEL_CAAM; ++EXPORT_SYMBOL(qm_channel_caam); ++u16 qm_channel_pme = QMAN_CHANNEL_PME; ++EXPORT_SYMBOL(qm_channel_pme); ++u16 qm_channel_dce = QMAN_CHANNEL_DCE; ++EXPORT_SYMBOL(qm_channel_dce); ++u16 qman_portal_max; ++EXPORT_SYMBOL(qman_portal_max); ++ ++u32 qman_clk; ++struct qm_ceetm qman_ceetms[QMAN_CEETM_MAX]; ++/* the qman ceetm instances on the given SoC */ ++u8 num_ceetms; ++ ++/* For these variables, and the portal-initialisation logic, the ++ * comments in bman_driver.c apply here so won't be repeated. */ ++static struct qman_portal *shared_portals[NR_CPUS]; ++static int num_shared_portals; ++static int shared_portals_idx; ++static LIST_HEAD(unused_pcfgs); ++static DEFINE_SPINLOCK(unused_pcfgs_lock); ++ ++/* A SDQCR mask comprising all the available/visible pool channels */ ++static u32 pools_sdqcr; ++ ++#define STR_ERR_NOPROP "No '%s' property in node %s\n" ++#define STR_ERR_CELL "'%s' is not a %d-cell range in node %s\n" ++#define STR_FQID_RANGE "fsl,fqid-range" ++#define STR_POOL_CHAN_RANGE "fsl,pool-channel-range" ++#define STR_CGRID_RANGE "fsl,cgrid-range" ++ ++/* A "fsl,fqid-range" node; release the given range to the allocator */ ++static __init int fsl_fqid_range_init(struct device_node *node) ++{ ++ int ret; ++ const u32 *range = of_get_property(node, STR_FQID_RANGE, &ret); ++ if (!range) { ++ pr_err(STR_ERR_NOPROP, STR_FQID_RANGE, node->full_name); ++ return -EINVAL; ++ } ++ if (ret != 8) { ++ pr_err(STR_ERR_CELL, STR_FQID_RANGE, 2, node->full_name); ++ return -EINVAL; ++ } ++ qman_seed_fqid_range(be32_to_cpu(range[0]), be32_to_cpu(range[1])); ++ pr_info("Qman: FQID allocator includes range %d:%d\n", ++ be32_to_cpu(range[0]), be32_to_cpu(range[1])); ++ return 0; ++} ++ ++/* A "fsl,pool-channel-range" node; add to the SDQCR mask only */ ++static __init int fsl_pool_channel_range_sdqcr(struct device_node *node) ++{ ++ int ret; ++ const u32 *chanid = of_get_property(node, STR_POOL_CHAN_RANGE, &ret); ++ if (!chanid) { ++ pr_err(STR_ERR_NOPROP, STR_POOL_CHAN_RANGE, node->full_name); ++ return -EINVAL; ++ } ++ if (ret != 8) { ++ pr_err(STR_ERR_CELL, STR_POOL_CHAN_RANGE, 1, node->full_name); ++ return -EINVAL; ++ } ++ for (ret = 0; ret < be32_to_cpu(chanid[1]); ret++) ++ pools_sdqcr |= QM_SDQCR_CHANNELS_POOL_CONV(be32_to_cpu(chanid[0]) + ret); ++ return 0; ++} ++ ++/* A "fsl,pool-channel-range" node; release the given range to the allocator */ ++static __init int fsl_pool_channel_range_init(struct device_node *node) ++{ ++ int ret; ++ const u32 *chanid = of_get_property(node, STR_POOL_CHAN_RANGE, &ret); ++ if (!chanid) { ++ pr_err(STR_ERR_NOPROP, STR_POOL_CHAN_RANGE, node->full_name); ++ return -EINVAL; ++ } ++ if (ret != 8) { ++ pr_err(STR_ERR_CELL, STR_POOL_CHAN_RANGE, 1, node->full_name); ++ return -EINVAL; ++ } ++ qman_seed_pool_range(be32_to_cpu(chanid[0]), be32_to_cpu(chanid[1])); ++ pr_info("Qman: pool channel allocator includes range %d:%d\n", ++ be32_to_cpu(chanid[0]), be32_to_cpu(chanid[1])); ++ return 0; ++} ++ ++/* A "fsl,cgrid-range" node; release the given range to the allocator */ ++static __init int fsl_cgrid_range_init(struct device_node *node) ++{ ++ struct qman_cgr cgr; ++ int ret, errors = 0; ++ const u32 *range = of_get_property(node, STR_CGRID_RANGE, &ret); ++ if (!range) { ++ pr_err(STR_ERR_NOPROP, STR_CGRID_RANGE, node->full_name); ++ return -EINVAL; ++ } ++ if (ret != 8) { ++ pr_err(STR_ERR_CELL, STR_CGRID_RANGE, 2, node->full_name); ++ return -EINVAL; ++ } ++ qman_seed_cgrid_range(be32_to_cpu(range[0]), be32_to_cpu(range[1])); ++ pr_info("Qman: CGRID allocator includes range %d:%d\n", ++ be32_to_cpu(range[0]), be32_to_cpu(range[1])); ++ for (cgr.cgrid = 0; cgr.cgrid < __CGR_NUM; cgr.cgrid++) { ++ ret = qman_modify_cgr(&cgr, QMAN_CGR_FLAG_USE_INIT, NULL); ++ if (ret) ++ errors++; ++ } ++ if (errors) ++ pr_err("Warning: %d error%s while initialising CGRs %d:%d\n", ++ errors, (errors > 1) ? "s" : "", range[0], range[1]); ++ return 0; ++} ++ ++static __init int fsl_ceetm_init(struct device_node *node) ++{ ++ enum qm_dc_portal dcp_portal; ++ struct qm_ceetm_sp *sp; ++ struct qm_ceetm_lni *lni; ++ int ret, i; ++ const u32 *range; ++ ++ /* Find LFQID range */ ++ range = of_get_property(node, "fsl,ceetm-lfqid-range", &ret); ++ if (!range) { ++ pr_err("No fsl,ceetm-lfqid-range in node %s\n", ++ node->full_name); ++ return -EINVAL; ++ } ++ if (ret != 8) { ++ pr_err("fsl,ceetm-lfqid-range is not a 2-cell range in node" ++ " %s\n", node->full_name); ++ return -EINVAL; ++ } ++ ++ dcp_portal = (be32_to_cpu(range[0]) & 0x0F0000) >> 16; ++ if (dcp_portal > qm_dc_portal_fman1) { ++ pr_err("The DCP portal %d doesn't support CEETM\n", dcp_portal); ++ return -EINVAL; ++ } ++ ++ if (dcp_portal == qm_dc_portal_fman0) ++ qman_seed_ceetm0_lfqid_range(be32_to_cpu(range[0]), be32_to_cpu(range[1])); ++ if (dcp_portal == qm_dc_portal_fman1) ++ qman_seed_ceetm1_lfqid_range(be32_to_cpu(range[0]), be32_to_cpu(range[1])); ++ pr_debug("Qman: The lfqid allocator of CEETM %d includes range" ++ " 0x%x:0x%x\n", dcp_portal, be32_to_cpu(range[0]), be32_to_cpu(range[1])); ++ ++ qman_ceetms[dcp_portal].idx = dcp_portal; ++ INIT_LIST_HEAD(&qman_ceetms[dcp_portal].sub_portals); ++ INIT_LIST_HEAD(&qman_ceetms[dcp_portal].lnis); ++ ++ /* Find Sub-portal range */ ++ range = of_get_property(node, "fsl,ceetm-sp-range", &ret); ++ if (!range) { ++ pr_err("No fsl,ceetm-sp-range in node %s\n", node->full_name); ++ return -EINVAL; ++ } ++ if (ret != 8) { ++ pr_err("fsl,ceetm-sp-range is not a 2-cell range in node %s\n", ++ node->full_name); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < be32_to_cpu(range[1]); i++) { ++ sp = kzalloc(sizeof(*sp), GFP_KERNEL); ++ if (!sp) { ++ pr_err("Can't alloc memory for sub-portal %d\n", ++ range[0] + i); ++ return -ENOMEM; ++ } ++ sp->idx = be32_to_cpu(range[0]) + i; ++ sp->dcp_idx = dcp_portal; ++ sp->is_claimed = 0; ++ list_add_tail(&sp->node, &qman_ceetms[dcp_portal].sub_portals); ++ sp++; ++ } ++ pr_debug("Qman: Reserve sub-portal %d:%d for CEETM %d\n", ++ be32_to_cpu(range[0]), be32_to_cpu(range[1]), dcp_portal); ++ qman_ceetms[dcp_portal].sp_range[0] = be32_to_cpu(range[0]); ++ qman_ceetms[dcp_portal].sp_range[1] = be32_to_cpu(range[1]); ++ ++ /* Find LNI range */ ++ range = of_get_property(node, "fsl,ceetm-lni-range", &ret); ++ if (!range) { ++ pr_err("No fsl,ceetm-lni-range in node %s\n", node->full_name); ++ return -EINVAL; ++ } ++ if (ret != 8) { ++ pr_err("fsl,ceetm-lni-range is not a 2-cell range in node %s\n", ++ node->full_name); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < be32_to_cpu(range[1]); i++) { ++ lni = kzalloc(sizeof(*lni), GFP_KERNEL); ++ if (!lni) { ++ pr_err("Can't alloc memory for LNI %d\n", ++ range[0] + i); ++ return -ENOMEM; ++ } ++ lni->idx = be32_to_cpu(range[0]) + i; ++ lni->dcp_idx = dcp_portal; ++ lni->is_claimed = 0; ++ INIT_LIST_HEAD(&lni->channels); ++ list_add_tail(&lni->node, &qman_ceetms[dcp_portal].lnis); ++ lni++; ++ } ++ pr_debug("Qman: Reserve LNI %d:%d for CEETM %d\n", ++ be32_to_cpu(range[0]), be32_to_cpu(range[1]), dcp_portal); ++ qman_ceetms[dcp_portal].lni_range[0] = be32_to_cpu(range[0]); ++ qman_ceetms[dcp_portal].lni_range[1] = be32_to_cpu(range[1]); ++ ++ /* Find CEETM channel range */ ++ range = of_get_property(node, "fsl,ceetm-channel-range", &ret); ++ if (!range) { ++ pr_err("No fsl,ceetm-channel-range in node %s\n", ++ node->full_name); ++ return -EINVAL; ++ } ++ if (ret != 8) { ++ pr_err("fsl,ceetm-channel-range is not a 2-cell range in node" ++ "%s\n", node->full_name); ++ return -EINVAL; ++ } ++ ++ if (dcp_portal == qm_dc_portal_fman0) ++ qman_seed_ceetm0_channel_range(be32_to_cpu(range[0]), be32_to_cpu(range[1])); ++ if (dcp_portal == qm_dc_portal_fman1) ++ qman_seed_ceetm1_channel_range(be32_to_cpu(range[0]), be32_to_cpu(range[1])); ++ pr_debug("Qman: The channel allocator of CEETM %d includes" ++ " range %d:%d\n", dcp_portal, be32_to_cpu(range[0]), be32_to_cpu(range[1])); ++ ++ /* Set CEETM PRES register */ ++ ret = qman_ceetm_set_prescaler(dcp_portal); ++ if (ret) ++ return ret; ++ return 0; ++} ++ ++static void qman_get_ip_revision(struct device_node *dn) ++{ ++ u16 ip_rev = 0; ++ u8 ip_cfg = QMAN_REV_CFG_0; ++ for_each_compatible_node(dn, NULL, "fsl,qman-portal") { ++ if (!of_device_is_available(dn)) ++ continue; ++ if (of_device_is_compatible(dn, "fsl,qman-portal-1.0") || ++ of_device_is_compatible(dn, "fsl,qman-portal-1.0.0")) { ++ pr_err("QMAN rev1.0 on P4080 rev1 is not supported!\n"); ++ BUG_ON(1); ++ } else if (of_device_is_compatible(dn, "fsl,qman-portal-1.1") || ++ of_device_is_compatible(dn, "fsl,qman-portal-1.1.0")) { ++ ip_rev = QMAN_REV11; ++ qman_portal_max = 10; ++ } else if (of_device_is_compatible(dn, "fsl,qman-portal-1.2") || ++ of_device_is_compatible(dn, "fsl,qman-portal-1.2.0")) { ++ ip_rev = QMAN_REV12; ++ qman_portal_max = 10; ++ } else if (of_device_is_compatible(dn, "fsl,qman-portal-2.0") || ++ of_device_is_compatible(dn, "fsl,qman-portal-2.0.0")) { ++ ip_rev = QMAN_REV20; ++ qman_portal_max = 3; ++ } else if (of_device_is_compatible(dn, ++ "fsl,qman-portal-3.0.0")) { ++ ip_rev = QMAN_REV30; ++ qman_portal_max = 50; ++ } else if (of_device_is_compatible(dn, ++ "fsl,qman-portal-3.0.1")) { ++ ip_rev = QMAN_REV30; ++ qman_portal_max = 25; ++ ip_cfg = QMAN_REV_CFG_1; ++ } else if (of_device_is_compatible(dn, ++ "fsl,qman-portal-3.1.0")) { ++ ip_rev = QMAN_REV31; ++ qman_portal_max = 50; ++ } else if (of_device_is_compatible(dn, ++ "fsl,qman-portal-3.1.1")) { ++ ip_rev = QMAN_REV31; ++ qman_portal_max = 25; ++ ip_cfg = QMAN_REV_CFG_1; ++ } else if (of_device_is_compatible(dn, ++ "fsl,qman-portal-3.1.2")) { ++ ip_rev = QMAN_REV31; ++ qman_portal_max = 18; ++ ip_cfg = QMAN_REV_CFG_2; ++ } else if (of_device_is_compatible(dn, ++ "fsl,qman-portal-3.1.3")) { ++ ip_rev = QMAN_REV31; ++ qman_portal_max = 10; ++ ip_cfg = QMAN_REV_CFG_3; ++ } else if (of_device_is_compatible(dn, ++ "fsl,qman-portal-3.2.0")) { ++ ip_rev = QMAN_REV32; ++ qman_portal_max = 10; ++ ip_cfg = QMAN_REV_CFG_3; // TODO: Verify for ls1043 ++ } else if (of_device_is_compatible(dn, ++ "fsl,qman-portal-3.2.1")) { ++ ip_rev = QMAN_REV32; ++ qman_portal_max = 10; ++ ip_cfg = QMAN_REV_CFG_3; ++ } else { ++ pr_warn("unknown QMan version in portal node," ++ "default to rev1.1\n"); ++ ip_rev = QMAN_REV11; ++ qman_portal_max = 10; ++ } ++ ++ if (!qman_ip_rev) { ++ if (ip_rev) { ++ qman_ip_rev = ip_rev; ++ qman_ip_cfg = ip_cfg; ++ } else { ++ pr_warn("unknown Qman version," ++ " default to rev1.1\n"); ++ qman_ip_rev = QMAN_REV11; ++ qman_ip_cfg = QMAN_REV_CFG_0; ++ } ++ } else if (ip_rev && (qman_ip_rev != ip_rev)) ++ pr_warn("Revision=0x%04x, but portal '%s' has" ++ " 0x%04x\n", ++ qman_ip_rev, dn->full_name, ip_rev); ++ if (qman_ip_rev == ip_rev) ++ break; ++ } ++} ++ ++/* Parse a portal node, perform generic mapping duties and return the config. It ++ * is not known at this stage for what purpose (or even if) the portal will be ++ * used. */ ++static struct qm_portal_config * __init parse_pcfg(struct device_node *node) ++{ ++ struct qm_portal_config *pcfg; ++ const u32 *index_p; ++ u32 index, channel; ++ int irq, ret; ++ resource_size_t len; ++ ++ pcfg = kmalloc(sizeof(*pcfg), GFP_KERNEL); ++ if (!pcfg) { ++ pr_err("can't allocate portal config"); ++ return NULL; ++ } ++ ++ /* ++ * This is a *horrible hack*, but the IOMMU/PAMU driver needs a ++ * 'struct device' in order to get the PAMU stashing setup and the QMan ++ * portal [driver] won't function at all without ring stashing ++ * ++ * Making the QMan portal driver nice and proper is part of the ++ * upstreaming effort ++ */ ++ pcfg->dev.bus = &platform_bus_type; ++ pcfg->dev.of_node = node; ++#ifdef CONFIG_FSL_PAMU ++ pcfg->dev.archdata.iommu_domain = NULL; ++#endif ++ ++ ret = of_address_to_resource(node, DPA_PORTAL_CE, ++ &pcfg->addr_phys[DPA_PORTAL_CE]); ++ if (ret) { ++ pr_err("Can't get %s property '%s'\n", node->full_name, ++ "reg::CE"); ++ goto err; ++ } ++ ret = of_address_to_resource(node, DPA_PORTAL_CI, ++ &pcfg->addr_phys[DPA_PORTAL_CI]); ++ if (ret) { ++ pr_err("Can't get %s property '%s'\n", node->full_name, ++ "reg::CI"); ++ goto err; ++ } ++ index_p = of_get_property(node, "cell-index", &ret); ++ if (!index_p || (ret != 4)) { ++ pr_err("Can't get %s property '%s'\n", node->full_name, ++ "cell-index"); ++ goto err; ++ } ++ index = be32_to_cpu(*index_p); ++ if (index >= qman_portal_max) { ++ pr_err("QMan portal index %d is beyond max (%d)\n", ++ index, qman_portal_max); ++ goto err; ++ } ++ ++ channel = index + QM_CHANNEL_SWPORTAL0; ++ pcfg->public_cfg.channel = channel; ++ pcfg->public_cfg.cpu = -1; ++ irq = irq_of_parse_and_map(node, 0); ++ if (irq == 0) { ++ pr_err("Can't get %s property '%s'\n", node->full_name, ++ "interrupts"); ++ goto err; ++ } ++ pcfg->public_cfg.irq = irq; ++ pcfg->public_cfg.index = index; ++#ifdef CONFIG_FSL_QMAN_CONFIG ++ /* We need the same LIODN offset for all portals */ ++ qman_liodn_fixup(pcfg->public_cfg.channel); ++#endif ++ ++ len = resource_size(&pcfg->addr_phys[DPA_PORTAL_CE]); ++ if (len != (unsigned long)len) ++ goto err; ++ ++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) ++ pcfg->addr_virt[DPA_PORTAL_CE] = ioremap_cache_ns( ++ pcfg->addr_phys[DPA_PORTAL_CE].start, ++ resource_size(&pcfg->addr_phys[DPA_PORTAL_CE])); ++ ++ pcfg->addr_virt[DPA_PORTAL_CI] = ioremap( ++ pcfg->addr_phys[DPA_PORTAL_CI].start, ++ resource_size(&pcfg->addr_phys[DPA_PORTAL_CI])); ++#else ++ pcfg->addr_virt[DPA_PORTAL_CE] = ioremap_prot( ++ pcfg->addr_phys[DPA_PORTAL_CE].start, ++ (unsigned long)len, ++ 0); ++ pcfg->addr_virt[DPA_PORTAL_CI] = ioremap_prot( ++ pcfg->addr_phys[DPA_PORTAL_CI].start, ++ resource_size(&pcfg->addr_phys[DPA_PORTAL_CI]), ++ _PAGE_GUARDED | _PAGE_NO_CACHE); ++#endif ++ return pcfg; ++err: ++ kfree(pcfg); ++ return NULL; ++} ++ ++static struct qm_portal_config *get_pcfg(struct list_head *list) ++{ ++ struct qm_portal_config *pcfg; ++ if (list_empty(list)) ++ return NULL; ++ pcfg = list_entry(list->prev, struct qm_portal_config, list); ++ list_del(&pcfg->list); ++ return pcfg; ++} ++ ++static struct qm_portal_config *get_pcfg_idx(struct list_head *list, u32 idx) ++{ ++ struct qm_portal_config *pcfg; ++ if (list_empty(list)) ++ return NULL; ++ list_for_each_entry(pcfg, list, list) { ++ if (pcfg->public_cfg.index == idx) { ++ list_del(&pcfg->list); ++ return pcfg; ++ } ++ } ++ return NULL; ++} ++ ++static void portal_set_cpu(struct qm_portal_config *pcfg, int cpu) ++{ ++#ifdef CONFIG_FSL_PAMU ++ int ret; ++ int window_count = 1; ++ struct iommu_domain_geometry geom_attr; ++ struct pamu_stash_attribute stash_attr; ++ ++ pcfg->iommu_domain = iommu_domain_alloc(&platform_bus_type); ++ if (!pcfg->iommu_domain) { ++ pr_err(KBUILD_MODNAME ":%s(): iommu_domain_alloc() failed", ++ __func__); ++ goto _no_iommu; ++ } ++ geom_attr.aperture_start = 0; ++ geom_attr.aperture_end = ++ ((dma_addr_t)1 << min(8 * sizeof(dma_addr_t), (size_t)36)) - 1; ++ geom_attr.force_aperture = true; ++ ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_GEOMETRY, ++ &geom_attr); ++ if (ret < 0) { ++ pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d", ++ __func__, ret); ++ goto _iommu_domain_free; ++ } ++ ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_WINDOWS, ++ &window_count); ++ if (ret < 0) { ++ pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d", ++ __func__, ret); ++ goto _iommu_domain_free; ++ } ++ stash_attr.cpu = cpu; ++ stash_attr.cache = PAMU_ATTR_CACHE_L1; ++ /* set stash information for the window */ ++ stash_attr.window = 0; ++ ret = iommu_domain_set_attr(pcfg->iommu_domain, ++ DOMAIN_ATTR_FSL_PAMU_STASH, ++ &stash_attr); ++ if (ret < 0) { ++ pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d", ++ __func__, ret); ++ goto _iommu_domain_free; ++ } ++ ret = iommu_domain_window_enable(pcfg->iommu_domain, 0, 0, 1ULL << 36, ++ IOMMU_READ | IOMMU_WRITE); ++ if (ret < 0) { ++ pr_err(KBUILD_MODNAME ":%s(): iommu_domain_window_enable() = %d", ++ __func__, ret); ++ goto _iommu_domain_free; ++ } ++ ret = iommu_attach_device(pcfg->iommu_domain, &pcfg->dev); ++ if (ret < 0) { ++ pr_err(KBUILD_MODNAME ":%s(): iommu_device_attach() = %d", ++ __func__, ret); ++ goto _iommu_domain_free; ++ } ++ ret = iommu_domain_set_attr(pcfg->iommu_domain, ++ DOMAIN_ATTR_FSL_PAMU_ENABLE, ++ &window_count); ++ if (ret < 0) { ++ pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d", ++ __func__, ret); ++ goto _iommu_detach_device; ++ } ++ ++_no_iommu: ++#endif ++#ifdef CONFIG_FSL_QMAN_CONFIG ++ if (qman_set_sdest(pcfg->public_cfg.channel, cpu)) ++#endif ++ pr_warn("Failed to set QMan portal's stash request queue\n"); ++ ++ return; ++ ++#ifdef CONFIG_FSL_PAMU ++_iommu_detach_device: ++ iommu_detach_device(pcfg->iommu_domain, NULL); ++_iommu_domain_free: ++ iommu_domain_free(pcfg->iommu_domain); ++#endif ++} ++ ++struct qm_portal_config *qm_get_unused_portal_idx(u32 idx) ++{ ++ struct qm_portal_config *ret; ++ spin_lock(&unused_pcfgs_lock); ++ if (idx == QBMAN_ANY_PORTAL_IDX) ++ ret = get_pcfg(&unused_pcfgs); ++ else ++ ret = get_pcfg_idx(&unused_pcfgs, idx); ++ spin_unlock(&unused_pcfgs_lock); ++ /* Bind stashing LIODNs to the CPU we are currently executing on, and ++ * set the portal to use the stashing request queue corresonding to the ++ * cpu as well. The user-space driver assumption is that the pthread has ++ * to already be affine to one cpu only before opening a portal. If that ++ * check is circumvented, the only risk is a performance degradation - ++ * stashing will go to whatever cpu they happened to be running on when ++ * opening the device file, and if that isn't the cpu they subsequently ++ * bind to and do their polling on, tough. */ ++ if (ret) ++ portal_set_cpu(ret, hard_smp_processor_id()); ++ return ret; ++} ++ ++struct qm_portal_config *qm_get_unused_portal(void) ++{ ++ return qm_get_unused_portal_idx(QBMAN_ANY_PORTAL_IDX); ++} ++ ++void qm_put_unused_portal(struct qm_portal_config *pcfg) ++{ ++ spin_lock(&unused_pcfgs_lock); ++ list_add(&pcfg->list, &unused_pcfgs); ++ spin_unlock(&unused_pcfgs_lock); ++} ++ ++static struct qman_portal *init_pcfg(struct qm_portal_config *pcfg) ++{ ++ struct qman_portal *p; ++ ++ pcfg->iommu_domain = NULL; ++ portal_set_cpu(pcfg, pcfg->public_cfg.cpu); ++ p = qman_create_affine_portal(pcfg, NULL); ++ if (p) { ++ u32 irq_sources = 0; ++ /* Determine what should be interrupt-vs-poll driven */ ++#ifdef CONFIG_FSL_DPA_PIRQ_SLOW ++ irq_sources |= QM_PIRQ_EQCI | QM_PIRQ_EQRI | QM_PIRQ_MRI | ++ QM_PIRQ_CSCI | QM_PIRQ_CCSCI; ++#endif ++#ifdef CONFIG_FSL_DPA_PIRQ_FAST ++ irq_sources |= QM_PIRQ_DQRI; ++#endif ++ qman_p_irqsource_add(p, irq_sources); ++ pr_info("Qman portal %sinitialised, cpu %d\n", ++ pcfg->public_cfg.is_shared ? "(shared) " : "", ++ pcfg->public_cfg.cpu); ++ } else ++ pr_crit("Qman portal failure on cpu %d\n", ++ pcfg->public_cfg.cpu); ++ return p; ++} ++ ++static void init_slave(int cpu) ++{ ++ struct qman_portal *p; ++ struct cpumask oldmask = current->cpus_allowed; ++ set_cpus_allowed_ptr(current, get_cpu_mask(cpu)); ++ p = qman_create_affine_slave(shared_portals[shared_portals_idx++], cpu); ++ if (!p) ++ pr_err("Qman slave portal failure on cpu %d\n", cpu); ++ else ++ pr_info("Qman portal %sinitialised, cpu %d\n", "(slave) ", cpu); ++ set_cpus_allowed_ptr(current, &oldmask); ++ if (shared_portals_idx >= num_shared_portals) ++ shared_portals_idx = 0; ++} ++ ++static struct cpumask want_unshared __initdata; ++static struct cpumask want_shared __initdata; ++ ++static int __init parse_qportals(char *str) ++{ ++ return parse_portals_bootarg(str, &want_shared, &want_unshared, ++ "qportals"); ++} ++__setup("qportals=", parse_qportals); ++ ++static void qman_portal_update_sdest(const struct qm_portal_config *pcfg, ++ unsigned int cpu) ++{ ++#ifdef CONFIG_FSL_PAMU ++ struct pamu_stash_attribute stash_attr; ++ int ret; ++ ++ if (pcfg->iommu_domain) { ++ stash_attr.cpu = cpu; ++ stash_attr.cache = PAMU_ATTR_CACHE_L1; ++ /* set stash information for the window */ ++ stash_attr.window = 0; ++ ret = iommu_domain_set_attr(pcfg->iommu_domain, ++ DOMAIN_ATTR_FSL_PAMU_STASH, &stash_attr); ++ if (ret < 0) { ++ pr_err("Failed to update pamu stash setting\n"); ++ return; ++ } ++ } ++#endif ++#ifdef CONFIG_FSL_QMAN_CONFIG ++ if (qman_set_sdest(pcfg->public_cfg.channel, cpu)) ++ pr_warn("Failed to update portal's stash request queue\n"); ++#endif ++} ++ ++static int qman_offline_cpu(unsigned int cpu) ++{ ++ struct qman_portal *p; ++ const struct qm_portal_config *pcfg; ++ p = (struct qman_portal *)affine_portals[cpu]; ++ if (p) { ++ pcfg = qman_get_qm_portal_config(p); ++ if (pcfg) { ++ irq_set_affinity(pcfg->public_cfg.irq, cpumask_of(0)); ++ qman_portal_update_sdest(pcfg, 0); ++ } ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_HOTPLUG_CPU ++static int qman_online_cpu(unsigned int cpu) ++{ ++ struct qman_portal *p; ++ const struct qm_portal_config *pcfg; ++ p = (struct qman_portal *)affine_portals[cpu]; ++ if (p) { ++ pcfg = qman_get_qm_portal_config(p); ++ if (pcfg) { ++ irq_set_affinity(pcfg->public_cfg.irq, cpumask_of(cpu)); ++ qman_portal_update_sdest(pcfg, cpu); ++ } ++ } ++ return 0; ++} ++ ++static int qman_hotplug_cpu_callback(struct notifier_block *nfb, ++ unsigned long action, void *hcpu) ++{ ++ unsigned int cpu = (unsigned long)hcpu; ++ ++ switch (action) { ++ case CPU_ONLINE: ++ case CPU_ONLINE_FROZEN: ++ qman_online_cpu(cpu); ++ break; ++ case CPU_DOWN_PREPARE: ++ case CPU_DOWN_PREPARE_FROZEN: ++ qman_offline_cpu(cpu); ++ default: ++ break; ++ } ++ return NOTIFY_OK; ++} ++ ++static struct notifier_block qman_hotplug_cpu_notifier = { ++ .notifier_call = qman_hotplug_cpu_callback, ++}; ++#endif /* CONFIG_HOTPLUG_CPU */ ++ ++__init int qman_init(void) ++{ ++ struct cpumask slave_cpus; ++ struct cpumask unshared_cpus = *cpu_none_mask; ++ struct cpumask shared_cpus = *cpu_none_mask; ++ LIST_HEAD(unshared_pcfgs); ++ LIST_HEAD(shared_pcfgs); ++ struct device_node *dn; ++ struct qm_portal_config *pcfg; ++ struct qman_portal *p; ++ int cpu, ret; ++ const u32 *clk; ++ struct cpumask offline_cpus; ++ ++ /* Initialise the Qman (CCSR) device */ ++ for_each_compatible_node(dn, NULL, "fsl,qman") { ++ if (!qman_init_ccsr(dn)) ++ pr_info("Qman err interrupt handler present\n"); ++ else ++ pr_err("Qman CCSR setup failed\n"); ++ ++ clk = of_get_property(dn, "clock-frequency", NULL); ++ if (!clk) ++ pr_warn("Can't find Qman clock frequency\n"); ++ else ++ qman_clk = be32_to_cpu(*clk); ++ } ++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP ++ /* Setup lookup table for FQ demux */ ++ ret = qman_setup_fq_lookup_table(get_qman_fqd_size()/64); ++ if (ret) ++ return ret; ++#endif ++ ++ /* Get qman ip revision */ ++ qman_get_ip_revision(dn); ++ if ((qman_ip_rev & 0xff00) >= QMAN_REV30) { ++ qm_channel_pool1 = QMAN_CHANNEL_POOL1_REV3; ++ qm_channel_caam = QMAN_CHANNEL_CAAM_REV3; ++ qm_channel_pme = QMAN_CHANNEL_PME_REV3; ++ } ++ ++ if ((qman_ip_rev == QMAN_REV31) && (qman_ip_cfg == QMAN_REV_CFG_2)) ++ qm_channel_dce = QMAN_CHANNEL_DCE_QMANREV312; ++ ++ /* ++ * Parse the ceetm node to get how many ceetm instances are supported ++ * on the current silicon. num_ceetms must be confirmed before portals ++ * are intiailized. ++ */ ++ num_ceetms = 0; ++ for_each_compatible_node(dn, NULL, "fsl,qman-ceetm") ++ num_ceetms++; ++ ++ /* Parse pool channels into the SDQCR mask. (Must happen before portals ++ * are initialised.) */ ++ for_each_compatible_node(dn, NULL, "fsl,pool-channel-range") { ++ ret = fsl_pool_channel_range_sdqcr(dn); ++ if (ret) ++ return ret; ++ } ++ ++ memset(affine_portals, 0, sizeof(void *) * num_possible_cpus()); ++ /* Initialise portals. See bman_driver.c for comments */ ++ for_each_compatible_node(dn, NULL, "fsl,qman-portal") { ++ if (!of_device_is_available(dn)) ++ continue; ++ pcfg = parse_pcfg(dn); ++ if (pcfg) { ++ pcfg->public_cfg.pools = pools_sdqcr; ++ list_add_tail(&pcfg->list, &unused_pcfgs); ++ } ++ } ++ for_each_possible_cpu(cpu) { ++ if (cpumask_test_cpu(cpu, &want_shared)) { ++ pcfg = get_pcfg(&unused_pcfgs); ++ if (!pcfg) ++ break; ++ pcfg->public_cfg.cpu = cpu; ++ list_add_tail(&pcfg->list, &shared_pcfgs); ++ cpumask_set_cpu(cpu, &shared_cpus); ++ } ++ if (cpumask_test_cpu(cpu, &want_unshared)) { ++ if (cpumask_test_cpu(cpu, &shared_cpus)) ++ continue; ++ pcfg = get_pcfg(&unused_pcfgs); ++ if (!pcfg) ++ break; ++ pcfg->public_cfg.cpu = cpu; ++ list_add_tail(&pcfg->list, &unshared_pcfgs); ++ cpumask_set_cpu(cpu, &unshared_cpus); ++ } ++ } ++ if (list_empty(&shared_pcfgs) && list_empty(&unshared_pcfgs)) { ++ for_each_online_cpu(cpu) { ++ pcfg = get_pcfg(&unused_pcfgs); ++ if (!pcfg) ++ break; ++ pcfg->public_cfg.cpu = cpu; ++ list_add_tail(&pcfg->list, &unshared_pcfgs); ++ cpumask_set_cpu(cpu, &unshared_cpus); ++ } ++ } ++ cpumask_andnot(&slave_cpus, cpu_possible_mask, &shared_cpus); ++ cpumask_andnot(&slave_cpus, &slave_cpus, &unshared_cpus); ++ if (cpumask_empty(&slave_cpus)) { ++ if (!list_empty(&shared_pcfgs)) { ++ cpumask_or(&unshared_cpus, &unshared_cpus, ++ &shared_cpus); ++ cpumask_clear(&shared_cpus); ++ list_splice_tail(&shared_pcfgs, &unshared_pcfgs); ++ INIT_LIST_HEAD(&shared_pcfgs); ++ } ++ } else { ++ if (list_empty(&shared_pcfgs)) { ++ pcfg = get_pcfg(&unshared_pcfgs); ++ if (!pcfg) { ++ pr_crit("No QMan portals available!\n"); ++ return 0; ++ } ++ cpumask_clear_cpu(pcfg->public_cfg.cpu, &unshared_cpus); ++ cpumask_set_cpu(pcfg->public_cfg.cpu, &shared_cpus); ++ list_add_tail(&pcfg->list, &shared_pcfgs); ++ } ++ } ++ list_for_each_entry(pcfg, &unshared_pcfgs, list) { ++ pcfg->public_cfg.is_shared = 0; ++ p = init_pcfg(pcfg); ++ if (!p) { ++ pr_crit("Unable to configure portals\n"); ++ return 0; ++ } ++ } ++ list_for_each_entry(pcfg, &shared_pcfgs, list) { ++ pcfg->public_cfg.is_shared = 1; ++ p = init_pcfg(pcfg); ++ if (p) ++ shared_portals[num_shared_portals++] = p; ++ } ++ if (!cpumask_empty(&slave_cpus)) ++ for_each_cpu(cpu, &slave_cpus) ++ init_slave(cpu); ++ pr_info("Qman portals initialised\n"); ++ cpumask_andnot(&offline_cpus, cpu_possible_mask, cpu_online_mask); ++ for_each_cpu(cpu, &offline_cpus) ++ qman_offline_cpu(cpu); ++#ifdef CONFIG_HOTPLUG_CPU ++ register_hotcpu_notifier(&qman_hotplug_cpu_notifier); ++#endif ++ return 0; ++} ++ ++__init int qman_resource_init(void) ++{ ++ struct device_node *dn; ++ int ret; ++ ++ /* Initialise FQID allocation ranges */ ++ for_each_compatible_node(dn, NULL, "fsl,fqid-range") { ++ ret = fsl_fqid_range_init(dn); ++ if (ret) ++ return ret; ++ } ++ /* Initialise CGRID allocation ranges */ ++ for_each_compatible_node(dn, NULL, "fsl,cgrid-range") { ++ ret = fsl_cgrid_range_init(dn); ++ if (ret) ++ return ret; ++ } ++ /* Parse pool channels into the allocator. (Must happen after portals ++ * are initialised.) */ ++ for_each_compatible_node(dn, NULL, "fsl,pool-channel-range") { ++ ret = fsl_pool_channel_range_init(dn); ++ if (ret) ++ return ret; ++ } ++ ++ /* Parse CEETM */ ++ for_each_compatible_node(dn, NULL, "fsl,qman-ceetm") { ++ ret = fsl_ceetm_init(dn); ++ if (ret) ++ return ret; ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_SUSPEND ++void suspend_unused_qportal(void) ++{ ++ struct qm_portal_config *pcfg; ++ ++ if (list_empty(&unused_pcfgs)) ++ return; ++ ++ list_for_each_entry(pcfg, &unused_pcfgs, list) { ++#ifdef CONFIG_PM_DEBUG ++ pr_info("Need to save qportal %d\n", pcfg->public_cfg.index); ++#endif ++ /* save isdr, disable all via isdr, clear isr */ ++ pcfg->saved_isdr = ++ __raw_readl(pcfg->addr_virt[DPA_PORTAL_CI] + 0xe08); ++ __raw_writel(0xffffffff, pcfg->addr_virt[DPA_PORTAL_CI] + ++ 0xe08); ++ __raw_writel(0xffffffff, pcfg->addr_virt[DPA_PORTAL_CI] + ++ 0xe00); ++ } ++ return; ++} ++ ++void resume_unused_qportal(void) ++{ ++ struct qm_portal_config *pcfg; ++ ++ if (list_empty(&unused_pcfgs)) ++ return; ++ ++ list_for_each_entry(pcfg, &unused_pcfgs, list) { ++#ifdef CONFIG_PM_DEBUG ++ pr_info("Need to resume qportal %d\n", pcfg->public_cfg.index); ++#endif ++ /* restore isdr */ ++ __raw_writel(pcfg->saved_isdr, ++ pcfg->addr_virt[DPA_PORTAL_CI] + 0xe08); ++ } ++ return; ++} ++#endif +diff --git a/drivers/staging/fsl_qbman/qman_high.c b/drivers/staging/fsl_qbman/qman_high.c +new file mode 100644 +index 00000000..1651e62c +--- /dev/null ++++ b/drivers/staging/fsl_qbman/qman_high.c +@@ -0,0 +1,5669 @@ ++/* Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "qman_low.h" ++ ++/* Compilation constants */ ++#define DQRR_MAXFILL 15 ++#define EQCR_ITHRESH 4 /* if EQCR congests, interrupt threshold */ ++#define IRQNAME "QMan portal %d" ++#define MAX_IRQNAME 16 /* big enough for "QMan portal %d" */ ++ ++/* Divide 'n' by 'd', rounding down if 'r' is negative, rounding up if it's ++ * positive, and rounding to the closest value if it's zero. NB, this macro ++ * implicitly upgrades parameters to unsigned 64-bit, so feed it with types ++ * that are compatible with this. NB, these arguments should not be expressions ++ * unless it is safe for them to be evaluated multiple times. Eg. do not pass ++ * in "some_value++" as a parameter to the macro! */ ++#define ROUNDING(n, d, r) \ ++ (((r) < 0) ? div64_u64((n), (d)) : \ ++ (((r) > 0) ? div64_u64(((n) + (d) - 1), (d)) : \ ++ div64_u64(((n) + ((d) / 2)), (d)))) ++ ++/* Lock/unlock frame queues, subject to the "LOCKED" flag. This is about ++ * inter-processor locking only. Note, FQLOCK() is always called either under a ++ * local_irq_save() or from interrupt context - hence there's no need for irq ++ * protection (and indeed, attempting to nest irq-protection doesn't work, as ++ * the "irq en/disable" machinery isn't recursive...). */ ++#define FQLOCK(fq) \ ++ do { \ ++ struct qman_fq *__fq478 = (fq); \ ++ if (fq_isset(__fq478, QMAN_FQ_FLAG_LOCKED)) \ ++ spin_lock(&__fq478->fqlock); \ ++ } while (0) ++#define FQUNLOCK(fq) \ ++ do { \ ++ struct qman_fq *__fq478 = (fq); \ ++ if (fq_isset(__fq478, QMAN_FQ_FLAG_LOCKED)) \ ++ spin_unlock(&__fq478->fqlock); \ ++ } while (0) ++ ++static inline void fq_set(struct qman_fq *fq, u32 mask) ++{ ++ set_bits(mask, &fq->flags); ++} ++static inline void fq_clear(struct qman_fq *fq, u32 mask) ++{ ++ clear_bits(mask, &fq->flags); ++} ++static inline int fq_isset(struct qman_fq *fq, u32 mask) ++{ ++ return fq->flags & mask; ++} ++static inline int fq_isclear(struct qman_fq *fq, u32 mask) ++{ ++ return !(fq->flags & mask); ++} ++ ++struct qman_portal { ++ struct qm_portal p; ++ unsigned long bits; /* PORTAL_BITS_*** - dynamic, strictly internal */ ++ unsigned long irq_sources; ++ u32 use_eqcr_ci_stashing; ++ u32 slowpoll; /* only used when interrupts are off */ ++ struct qman_fq *vdqcr_owned; /* only 1 volatile dequeue at a time */ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ struct qman_fq *eqci_owned; /* only 1 enqueue WAIT_SYNC at a time */ ++#endif ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ raw_spinlock_t sharing_lock; /* only used if is_shared */ ++ int is_shared; ++ struct qman_portal *sharing_redirect; ++#endif ++ u32 sdqcr; ++ int dqrr_disable_ref; ++ /* A portal-specific handler for DCP ERNs. If this is NULL, the global ++ * handler is called instead. */ ++ qman_cb_dc_ern cb_dc_ern; ++ /* When the cpu-affine portal is activated, this is non-NULL */ ++ const struct qm_portal_config *config; ++ /* This is needed for providing a non-NULL device to dma_map_***() */ ++ struct platform_device *pdev; ++ struct dpa_rbtree retire_table; ++ char irqname[MAX_IRQNAME]; ++ /* 2-element array. cgrs[0] is mask, cgrs[1] is snapshot. */ ++ struct qman_cgrs *cgrs; ++ /* linked-list of CSCN handlers. */ ++ struct list_head cgr_cbs; ++ /* list lock */ ++ spinlock_t cgr_lock; ++ /* 2-element array. ccgrs[0] is mask, ccgrs[1] is snapshot. */ ++ struct qman_ccgrs *ccgrs[QMAN_CEETM_MAX]; ++ /* 256-element array, each is a linked-list of CCSCN handlers. */ ++ struct list_head ccgr_cbs[QMAN_CEETM_MAX]; ++ /* list lock */ ++ spinlock_t ccgr_lock; ++ /* track if memory was allocated by the driver */ ++ u8 alloced; ++ /* power management data */ ++ u32 save_isdr; ++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ++ /* Keep a shadow copy of the DQRR on LE systems as the SW needs to ++ * do byte swaps of DQRR read only memory. First entry must be aligned ++ * to 2 ** 10 to ensure DQRR index calculations based shadow copy ++ * address (6 bits for address shift + 4 bits for the DQRR size). ++ */ ++ struct qm_dqrr_entry shadow_dqrr[QM_DQRR_SIZE] __aligned(1024); ++#endif ++}; ++ ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++#define PORTAL_IRQ_LOCK(p, irqflags) \ ++ do { \ ++ if ((p)->is_shared) \ ++ raw_spin_lock_irqsave(&(p)->sharing_lock, irqflags); \ ++ else \ ++ local_irq_save(irqflags); \ ++ } while (0) ++#define PORTAL_IRQ_UNLOCK(p, irqflags) \ ++ do { \ ++ if ((p)->is_shared) \ ++ raw_spin_unlock_irqrestore(&(p)->sharing_lock, \ ++ irqflags); \ ++ else \ ++ local_irq_restore(irqflags); \ ++ } while (0) ++#else ++#define PORTAL_IRQ_LOCK(p, irqflags) local_irq_save(irqflags) ++#define PORTAL_IRQ_UNLOCK(p, irqflags) local_irq_restore(irqflags) ++#endif ++ ++/* Global handler for DCP ERNs. Used when the portal receiving the message does ++ * not have a portal-specific handler. */ ++static qman_cb_dc_ern cb_dc_ern; ++ ++static cpumask_t affine_mask; ++static DEFINE_SPINLOCK(affine_mask_lock); ++static u16 affine_channels[NR_CPUS]; ++static DEFINE_PER_CPU(struct qman_portal, qman_affine_portal); ++void *affine_portals[NR_CPUS]; ++ ++/* "raw" gets the cpu-local struct whether it's a redirect or not. */ ++static inline struct qman_portal *get_raw_affine_portal(void) ++{ ++ return &get_cpu_var(qman_affine_portal); ++} ++/* For ops that can redirect, this obtains the portal to use */ ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++static inline struct qman_portal *get_affine_portal(void) ++{ ++ struct qman_portal *p = get_raw_affine_portal(); ++ if (p->sharing_redirect) ++ return p->sharing_redirect; ++ return p; ++} ++#else ++#define get_affine_portal() get_raw_affine_portal() ++#endif ++/* For every "get", there must be a "put" */ ++static inline void put_affine_portal(void) ++{ ++ put_cpu_var(qman_affine_portal); ++} ++/* Exception: poll functions assume the caller is cpu-affine and in no risk of ++ * re-entrance, which are the two reasons we usually use the get/put_cpu_var() ++ * semantic - ie. to disable pre-emption. Some use-cases expect the execution ++ * context to remain as non-atomic during poll-triggered callbacks as it was ++ * when the poll API was first called (eg. NAPI), so we go out of our way in ++ * this case to not disable pre-emption. */ ++static inline struct qman_portal *get_poll_portal(void) ++{ ++ return &get_cpu_var(qman_affine_portal); ++} ++#define put_poll_portal() ++ ++/* This gives a FQID->FQ lookup to cover the fact that we can't directly demux ++ * retirement notifications (the fact they are sometimes h/w-consumed means that ++ * contextB isn't always a s/w demux - and as we can't know which case it is ++ * when looking at the notification, we have to use the slow lookup for all of ++ * them). NB, it's possible to have multiple FQ objects refer to the same FQID ++ * (though at most one of them should be the consumer), so this table isn't for ++ * all FQs - FQs are added when retirement commands are issued, and removed when ++ * they complete, which also massively reduces the size of this table. */ ++IMPLEMENT_DPA_RBTREE(fqtree, struct qman_fq, node, fqid); ++ ++/* This is what everything can wait on, even if it migrates to a different cpu ++ * to the one whose affine portal it is waiting on. */ ++static DECLARE_WAIT_QUEUE_HEAD(affine_queue); ++ ++static inline int table_push_fq(struct qman_portal *p, struct qman_fq *fq) ++{ ++ int ret = fqtree_push(&p->retire_table, fq); ++ if (ret) ++ pr_err("ERROR: double FQ-retirement %d\n", fq->fqid); ++ return ret; ++} ++ ++static inline void table_del_fq(struct qman_portal *p, struct qman_fq *fq) ++{ ++ fqtree_del(&p->retire_table, fq); ++} ++ ++static inline struct qman_fq *table_find_fq(struct qman_portal *p, u32 fqid) ++{ ++ return fqtree_find(&p->retire_table, fqid); ++} ++ ++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP ++static void **qman_fq_lookup_table; ++static size_t qman_fq_lookup_table_size; ++ ++int qman_setup_fq_lookup_table(size_t num_entries) ++{ ++ num_entries++; ++ /* Allocate 1 more entry since the first entry is not used */ ++ qman_fq_lookup_table = vzalloc((num_entries * sizeof(void *))); ++ if (!qman_fq_lookup_table) { ++ pr_err("QMan: Could not allocate fq lookup table\n"); ++ return -ENOMEM; ++ } ++ qman_fq_lookup_table_size = num_entries; ++ pr_info("QMan: Allocated lookup table at %p, entry count %lu\n", ++ qman_fq_lookup_table, ++ (unsigned long)qman_fq_lookup_table_size); ++ return 0; ++} ++ ++/* global structure that maintains fq object mapping */ ++static DEFINE_SPINLOCK(fq_hash_table_lock); ++ ++static int find_empty_fq_table_entry(u32 *entry, struct qman_fq *fq) ++{ ++ u32 i; ++ ++ spin_lock(&fq_hash_table_lock); ++ /* Can't use index zero because this has special meaning ++ * in context_b field. */ ++ for (i = 1; i < qman_fq_lookup_table_size; i++) { ++ if (qman_fq_lookup_table[i] == NULL) { ++ *entry = i; ++ qman_fq_lookup_table[i] = fq; ++ spin_unlock(&fq_hash_table_lock); ++ return 0; ++ } ++ } ++ spin_unlock(&fq_hash_table_lock); ++ return -ENOMEM; ++} ++ ++static void clear_fq_table_entry(u32 entry) ++{ ++ spin_lock(&fq_hash_table_lock); ++ BUG_ON(entry >= qman_fq_lookup_table_size); ++ qman_fq_lookup_table[entry] = NULL; ++ spin_unlock(&fq_hash_table_lock); ++} ++ ++static inline struct qman_fq *get_fq_table_entry(u32 entry) ++{ ++ BUG_ON(entry >= qman_fq_lookup_table_size); ++ return qman_fq_lookup_table[entry]; ++} ++#endif ++ ++static inline void cpu_to_hw_fqd(struct qm_fqd *fqd) ++{ ++ /* Byteswap the FQD to HW format */ ++ fqd->fq_ctrl = cpu_to_be16(fqd->fq_ctrl); ++ fqd->dest_wq = cpu_to_be16(fqd->dest_wq); ++ fqd->ics_cred = cpu_to_be16(fqd->ics_cred); ++ fqd->context_b = cpu_to_be32(fqd->context_b); ++ fqd->context_a.opaque = cpu_to_be64(fqd->context_a.opaque); ++} ++ ++static inline void hw_fqd_to_cpu(struct qm_fqd *fqd) ++{ ++ /* Byteswap the FQD to CPU format */ ++ fqd->fq_ctrl = be16_to_cpu(fqd->fq_ctrl); ++ fqd->dest_wq = be16_to_cpu(fqd->dest_wq); ++ fqd->ics_cred = be16_to_cpu(fqd->ics_cred); ++ fqd->context_b = be32_to_cpu(fqd->context_b); ++ fqd->context_a.opaque = be64_to_cpu(fqd->context_a.opaque); ++} ++ ++/* Swap a 40 bit address */ ++static inline u64 cpu_to_be40(u64 in) ++{ ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ return in; ++#else ++ u64 out = 0; ++ u8 *p = (u8 *) &out; ++ p[0] = in >> 32; ++ p[1] = in >> 24; ++ p[2] = in >> 16; ++ p[3] = in >> 8; ++ p[4] = in >> 0; ++ return out; ++#endif ++} ++static inline u64 be40_to_cpu(u64 in) ++{ ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ return in; ++#else ++ u64 out = 0; ++ u8 *pout = (u8 *) &out; ++ u8 *pin = (u8 *) ∈ ++ pout[0] = pin[4]; ++ pout[1] = pin[3]; ++ pout[2] = pin[2]; ++ pout[3] = pin[1]; ++ pout[4] = pin[0]; ++ return out; ++#endif ++} ++ ++/* Swap a 24 bit value */ ++static inline u32 cpu_to_be24(u32 in) ++{ ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ return in; ++#else ++ u32 out = 0; ++ u8 *p = (u8 *) &out; ++ p[0] = in >> 16; ++ p[1] = in >> 8; ++ p[2] = in >> 0; ++ return out; ++#endif ++} ++ ++static inline u32 be24_to_cpu(u32 in) ++{ ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ return in; ++#else ++ u32 out = 0; ++ u8 *pout = (u8 *) &out; ++ u8 *pin = (u8 *) ∈ ++ pout[0] = pin[2]; ++ pout[1] = pin[1]; ++ pout[2] = pin[0]; ++ return out; ++#endif ++} ++ ++static inline u64 be48_to_cpu(u64 in) ++{ ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ return in; ++#else ++ u64 out = 0; ++ u8 *pout = (u8 *) &out; ++ u8 *pin = (u8 *) ∈ ++ ++ pout[0] = pin[5]; ++ pout[1] = pin[4]; ++ pout[2] = pin[3]; ++ pout[3] = pin[2]; ++ pout[4] = pin[1]; ++ pout[5] = pin[0]; ++ return out; ++#endif ++} ++static inline void cpu_to_hw_fd(struct qm_fd *fd) ++{ ++ fd->opaque_addr = cpu_to_be64(fd->opaque_addr); ++ fd->status = cpu_to_be32(fd->status); ++ fd->opaque = cpu_to_be32(fd->opaque); ++} ++ ++static inline void hw_fd_to_cpu(struct qm_fd *fd) ++{ ++ fd->opaque_addr = be64_to_cpu(fd->opaque_addr); ++ fd->status = be32_to_cpu(fd->status); ++ fd->opaque = be32_to_cpu(fd->opaque); ++} ++ ++static inline void hw_cq_query_to_cpu(struct qm_mcr_ceetm_cq_query *cq_query) ++{ ++ cq_query->ccgid = be16_to_cpu(cq_query->ccgid); ++ cq_query->state = be16_to_cpu(cq_query->state); ++ cq_query->pfdr_hptr = be24_to_cpu(cq_query->pfdr_hptr); ++ cq_query->pfdr_tptr = be24_to_cpu(cq_query->pfdr_tptr); ++ cq_query->od1_xsfdr = be16_to_cpu(cq_query->od1_xsfdr); ++ cq_query->od2_xsfdr = be16_to_cpu(cq_query->od2_xsfdr); ++ cq_query->od3_xsfdr = be16_to_cpu(cq_query->od3_xsfdr); ++ cq_query->od4_xsfdr = be16_to_cpu(cq_query->od4_xsfdr); ++ cq_query->od5_xsfdr = be16_to_cpu(cq_query->od5_xsfdr); ++ cq_query->od6_xsfdr = be16_to_cpu(cq_query->od6_xsfdr); ++ cq_query->ra1_xsfdr = be16_to_cpu(cq_query->ra1_xsfdr); ++ cq_query->ra2_xsfdr = be16_to_cpu(cq_query->ra2_xsfdr); ++ cq_query->frm_cnt = be24_to_cpu(cq_query->frm_cnt); ++} ++ ++static inline void hw_ccgr_query_to_cpu(struct qm_mcr_ceetm_ccgr_query *ccgr_q) ++{ ++ int i; ++ ++ ccgr_q->cm_query.cs_thres.hword = ++ be16_to_cpu(ccgr_q->cm_query.cs_thres.hword); ++ ccgr_q->cm_query.cs_thres_x.hword = ++ be16_to_cpu(ccgr_q->cm_query.cs_thres_x.hword); ++ ccgr_q->cm_query.td_thres.hword = ++ be16_to_cpu(ccgr_q->cm_query.td_thres.hword); ++ ccgr_q->cm_query.wr_parm_g.word = ++ be32_to_cpu(ccgr_q->cm_query.wr_parm_g.word); ++ ccgr_q->cm_query.wr_parm_y.word = ++ be32_to_cpu(ccgr_q->cm_query.wr_parm_y.word); ++ ccgr_q->cm_query.wr_parm_r.word = ++ be32_to_cpu(ccgr_q->cm_query.wr_parm_r.word); ++ ccgr_q->cm_query.cscn_targ_dcp = ++ be16_to_cpu(ccgr_q->cm_query.cscn_targ_dcp); ++ ccgr_q->cm_query.i_cnt = be40_to_cpu(ccgr_q->cm_query.i_cnt); ++ ccgr_q->cm_query.a_cnt = be40_to_cpu(ccgr_q->cm_query.a_cnt); ++ for (i = 0; i < ARRAY_SIZE(ccgr_q->cm_query.cscn_targ_swp); i++) ++ ccgr_q->cm_query.cscn_targ_swp[i] = ++ be32_to_cpu(ccgr_q->cm_query.cscn_targ_swp[i]); ++} ++ ++/* In the case that slow- and fast-path handling are both done by qman_poll() ++ * (ie. because there is no interrupt handling), we ought to balance how often ++ * we do the fast-path poll versus the slow-path poll. We'll use two decrementer ++ * sources, so we call the fast poll 'n' times before calling the slow poll ++ * once. The idle decrementer constant is used when the last slow-poll detected ++ * no work to do, and the busy decrementer constant when the last slow-poll had ++ * work to do. */ ++#define SLOW_POLL_IDLE 1000 ++#define SLOW_POLL_BUSY 10 ++static u32 __poll_portal_slow(struct qman_portal *p, u32 is); ++static inline unsigned int __poll_portal_fast(struct qman_portal *p, ++ unsigned int poll_limit); ++ ++/* Portal interrupt handler */ ++static irqreturn_t portal_isr(__always_unused int irq, void *ptr) ++{ ++ struct qman_portal *p = ptr; ++ /* ++ * The CSCI/CCSCI source is cleared inside __poll_portal_slow(), because ++ * it could race against a Query Congestion State command also given ++ * as part of the handling of this interrupt source. We mustn't ++ * clear it a second time in this top-level function. ++ */ ++ u32 clear = QM_DQAVAIL_MASK | (p->irq_sources & ++ ~(QM_PIRQ_CSCI | QM_PIRQ_CCSCI)); ++ u32 is = qm_isr_status_read(&p->p) & p->irq_sources; ++ /* DQRR-handling if it's interrupt-driven */ ++ if (is & QM_PIRQ_DQRI) ++ __poll_portal_fast(p, CONFIG_FSL_QMAN_POLL_LIMIT); ++ /* Handling of anything else that's interrupt-driven */ ++ clear |= __poll_portal_slow(p, is); ++ qm_isr_status_clear(&p->p, clear); ++ return IRQ_HANDLED; ++} ++ ++/* This inner version is used privately by qman_create_affine_portal(), as well ++ * as by the exported qman_stop_dequeues(). */ ++static inline void qman_stop_dequeues_ex(struct qman_portal *p) ++{ ++ unsigned long irqflags __maybe_unused; ++ PORTAL_IRQ_LOCK(p, irqflags); ++ if (!(p->dqrr_disable_ref++)) ++ qm_dqrr_set_maxfill(&p->p, 0); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++} ++ ++static int drain_mr_fqrni(struct qm_portal *p) ++{ ++ const struct qm_mr_entry *msg; ++loop: ++ msg = qm_mr_current(p); ++ if (!msg) { ++ /* if MR was full and h/w had other FQRNI entries to produce, we ++ * need to allow it time to produce those entries once the ++ * existing entries are consumed. A worst-case situation ++ * (fully-loaded system) means h/w sequencers may have to do 3-4 ++ * other things before servicing the portal's MR pump, each of ++ * which (if slow) may take ~50 qman cycles (which is ~200 ++ * processor cycles). So rounding up and then multiplying this ++ * worst-case estimate by a factor of 10, just to be ++ * ultra-paranoid, goes as high as 10,000 cycles. NB, we consume ++ * one entry at a time, so h/w has an opportunity to produce new ++ * entries well before the ring has been fully consumed, so ++ * we're being *really* paranoid here. */ ++ u64 now, then = mfatb(); ++ do { ++ now = mfatb(); ++ } while ((then + 10000) > now); ++ msg = qm_mr_current(p); ++ if (!msg) ++ return 0; ++ } ++ if ((msg->verb & QM_MR_VERB_TYPE_MASK) != QM_MR_VERB_FQRNI) { ++ /* We aren't draining anything but FQRNIs */ ++ pr_err("QMan found verb 0x%x in MR\n", msg->verb); ++ return -1; ++ } ++ qm_mr_next(p); ++ qm_mr_cci_consume(p, 1); ++ goto loop; ++} ++ ++#ifdef CONFIG_SUSPEND ++static int _qman_portal_suspend_noirq(struct device *dev) ++{ ++ struct qman_portal *p = (struct qman_portal *)dev->platform_data; ++#ifdef CONFIG_PM_DEBUG ++ struct platform_device *pdev = to_platform_device(dev); ++#endif ++ ++ p->save_isdr = qm_isr_disable_read(&p->p); ++ qm_isr_disable_write(&p->p, 0xffffffff); ++ qm_isr_status_clear(&p->p, 0xffffffff); ++#ifdef CONFIG_PM_DEBUG ++ pr_info("Suspend for %s\n", pdev->name); ++#endif ++ return 0; ++} ++ ++static int _qman_portal_resume_noirq(struct device *dev) ++{ ++ struct qman_portal *p = (struct qman_portal *)dev->platform_data; ++ ++ /* restore isdr */ ++ qm_isr_disable_write(&p->p, p->save_isdr); ++ return 0; ++} ++#else ++#define _qman_portal_suspend_noirq NULL ++#define _qman_portal_resume_noirq NULL ++#endif ++ ++struct dev_pm_domain qman_portal_device_pm_domain = { ++ .ops = { ++ USE_PLATFORM_PM_SLEEP_OPS ++ .suspend_noirq = _qman_portal_suspend_noirq, ++ .resume_noirq = _qman_portal_resume_noirq, ++ } ++}; ++ ++struct qman_portal *qman_create_portal( ++ struct qman_portal *portal, ++ const struct qm_portal_config *config, ++ const struct qman_cgrs *cgrs) ++{ ++ struct qm_portal *__p; ++ char buf[16]; ++ int ret; ++ u32 isdr; ++ ++ if (!portal) { ++ portal = kmalloc(sizeof(*portal), GFP_KERNEL); ++ if (!portal) ++ return portal; ++ portal->alloced = 1; ++ } else ++ portal->alloced = 0; ++ ++ __p = &portal->p; ++ ++#if (defined CONFIG_PPC || defined CONFIG_PPC64) && defined CONFIG_FSL_PAMU ++ /* PAMU is required for stashing */ ++ portal->use_eqcr_ci_stashing = ((qman_ip_rev >= QMAN_REV30) ? ++ 1 : 0); ++#elif defined(CONFIG_ARM) || defined(CONFIG_ARM64) ++ portal->use_eqcr_ci_stashing = 1; ++#else ++ portal->use_eqcr_ci_stashing = 0; ++#endif ++ ++ /* prep the low-level portal struct with the mapped addresses from the ++ * config, everything that follows depends on it and "config" is more ++ * for (de)reference... */ ++ __p->addr.addr_ce = config->addr_virt[DPA_PORTAL_CE]; ++ __p->addr.addr_ci = config->addr_virt[DPA_PORTAL_CI]; ++ /* ++ * If CI-stashing is used, the current defaults use a threshold of 3, ++ * and stash with high-than-DQRR priority. ++ */ ++ if (qm_eqcr_init(__p, qm_eqcr_pvb, ++ portal->use_eqcr_ci_stashing ? 3 : 0, 1)) { ++ pr_err("Qman EQCR initialisation failed\n"); ++ goto fail_eqcr; ++ } ++ if (qm_dqrr_init(__p, config, qm_dqrr_dpush, qm_dqrr_pvb, ++ qm_dqrr_cdc, DQRR_MAXFILL)) { ++ pr_err("Qman DQRR initialisation failed\n"); ++ goto fail_dqrr; ++ } ++ if (qm_mr_init(__p, qm_mr_pvb, qm_mr_cci)) { ++ pr_err("Qman MR initialisation failed\n"); ++ goto fail_mr; ++ } ++ if (qm_mc_init(__p)) { ++ pr_err("Qman MC initialisation failed\n"); ++ goto fail_mc; ++ } ++ if (qm_isr_init(__p)) { ++ pr_err("Qman ISR initialisation failed\n"); ++ goto fail_isr; ++ } ++ /* static interrupt-gating controls */ ++ qm_dqrr_set_ithresh(__p, CONFIG_FSL_QMAN_PIRQ_DQRR_ITHRESH); ++ qm_mr_set_ithresh(__p, CONFIG_FSL_QMAN_PIRQ_MR_ITHRESH); ++ qm_isr_set_iperiod(__p, CONFIG_FSL_QMAN_PIRQ_IPERIOD); ++ portal->cgrs = kmalloc(2 * sizeof(*cgrs), GFP_KERNEL); ++ if (!portal->cgrs) ++ goto fail_cgrs; ++ /* initial snapshot is no-depletion */ ++ qman_cgrs_init(&portal->cgrs[1]); ++ if (cgrs) ++ portal->cgrs[0] = *cgrs; ++ else ++ /* if the given mask is NULL, assume all CGRs can be seen */ ++ qman_cgrs_fill(&portal->cgrs[0]); ++ INIT_LIST_HEAD(&portal->cgr_cbs); ++ spin_lock_init(&portal->cgr_lock); ++ if (num_ceetms) { ++ for (ret = 0; ret < num_ceetms; ret++) { ++ portal->ccgrs[ret] = kmalloc(2 * ++ sizeof(struct qman_ccgrs), GFP_KERNEL); ++ if (!portal->ccgrs[ret]) ++ goto fail_ccgrs; ++ qman_ccgrs_init(&portal->ccgrs[ret][1]); ++ qman_ccgrs_fill(&portal->ccgrs[ret][0]); ++ INIT_LIST_HEAD(&portal->ccgr_cbs[ret]); ++ } ++ } ++ spin_lock_init(&portal->ccgr_lock); ++ portal->bits = 0; ++ portal->slowpoll = 0; ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ portal->eqci_owned = NULL; ++#endif ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ raw_spin_lock_init(&portal->sharing_lock); ++ portal->is_shared = config->public_cfg.is_shared; ++ portal->sharing_redirect = NULL; ++#endif ++ portal->sdqcr = QM_SDQCR_SOURCE_CHANNELS | QM_SDQCR_COUNT_UPTO3 | ++ QM_SDQCR_DEDICATED_PRECEDENCE | QM_SDQCR_TYPE_PRIO_QOS | ++ QM_SDQCR_TOKEN_SET(0xab) | QM_SDQCR_CHANNELS_DEDICATED; ++ portal->dqrr_disable_ref = 0; ++ portal->cb_dc_ern = NULL; ++ sprintf(buf, "qportal-%d", config->public_cfg.channel); ++ portal->pdev = platform_device_alloc(buf, -1); ++ if (!portal->pdev) { ++ pr_err("qman_portal - platform_device_alloc() failed\n"); ++ goto fail_devalloc; ++ } ++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) ++ portal->pdev->dev.coherent_dma_mask = DMA_BIT_MASK(40); ++ portal->pdev->dev.dma_mask = &portal->pdev->dev.coherent_dma_mask; ++#else ++ if (dma_set_mask(&portal->pdev->dev, DMA_BIT_MASK(40))) { ++ pr_err("qman_portal - dma_set_mask() failed\n"); ++ goto fail_devadd; ++ } ++#endif ++ portal->pdev->dev.pm_domain = &qman_portal_device_pm_domain; ++ portal->pdev->dev.platform_data = portal; ++ ret = platform_device_add(portal->pdev); ++ if (ret) { ++ pr_err("qman_portal - platform_device_add() failed\n"); ++ goto fail_devadd; ++ } ++ dpa_rbtree_init(&portal->retire_table); ++ isdr = 0xffffffff; ++ qm_isr_disable_write(__p, isdr); ++ portal->irq_sources = 0; ++ qm_isr_enable_write(__p, portal->irq_sources); ++ qm_isr_status_clear(__p, 0xffffffff); ++ snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, config->public_cfg.cpu); ++ if (request_irq(config->public_cfg.irq, portal_isr, 0, portal->irqname, ++ portal)) { ++ pr_err("request_irq() failed\n"); ++ goto fail_irq; ++ } ++ if ((config->public_cfg.cpu != -1) && ++ irq_can_set_affinity(config->public_cfg.irq) && ++ irq_set_affinity(config->public_cfg.irq, ++ cpumask_of(config->public_cfg.cpu))) { ++ pr_err("irq_set_affinity() failed\n"); ++ goto fail_affinity; ++ } ++ ++ /* Need EQCR to be empty before continuing */ ++ isdr ^= QM_PIRQ_EQCI; ++ qm_isr_disable_write(__p, isdr); ++ ret = qm_eqcr_get_fill(__p); ++ if (ret) { ++ pr_err("Qman EQCR unclean\n"); ++ goto fail_eqcr_empty; ++ } ++ isdr ^= (QM_PIRQ_DQRI | QM_PIRQ_MRI); ++ qm_isr_disable_write(__p, isdr); ++ if (qm_dqrr_current(__p) != NULL) { ++ pr_err("Qman DQRR unclean\n"); ++ qm_dqrr_cdc_consume_n(__p, 0xffff); ++ } ++ if (qm_mr_current(__p) != NULL) { ++ /* special handling, drain just in case it's a few FQRNIs */ ++ if (drain_mr_fqrni(__p)) { ++ const struct qm_mr_entry *e = qm_mr_current(__p); ++ /* ++ * Message ring cannot be empty no need to check ++ * qm_mr_current returned successfully ++ */ ++ pr_err("Qman MR unclean, MR VERB 0x%x, rc 0x%x\n, addr 0x%x", ++ e->verb, e->ern.rc, e->ern.fd.addr_lo); ++ goto fail_dqrr_mr_empty; ++ } ++ } ++ /* Success */ ++ portal->config = config; ++ qm_isr_disable_write(__p, 0); ++ qm_isr_uninhibit(__p); ++ /* Write a sane SDQCR */ ++ qm_dqrr_sdqcr_set(__p, portal->sdqcr); ++ return portal; ++fail_dqrr_mr_empty: ++fail_eqcr_empty: ++fail_affinity: ++ free_irq(config->public_cfg.irq, portal); ++fail_irq: ++ platform_device_del(portal->pdev); ++fail_devadd: ++ platform_device_put(portal->pdev); ++fail_devalloc: ++ if (num_ceetms) ++ for (ret = 0; ret < num_ceetms; ret++) ++ kfree(portal->ccgrs[ret]); ++fail_ccgrs: ++ kfree(portal->cgrs); ++fail_cgrs: ++ qm_isr_finish(__p); ++fail_isr: ++ qm_mc_finish(__p); ++fail_mc: ++ qm_mr_finish(__p); ++fail_mr: ++ qm_dqrr_finish(__p); ++fail_dqrr: ++ qm_eqcr_finish(__p); ++fail_eqcr: ++ if (portal->alloced) ++ kfree(portal); ++ return NULL; ++} ++ ++struct qman_portal *qman_create_affine_portal( ++ const struct qm_portal_config *config, ++ const struct qman_cgrs *cgrs) ++{ ++ struct qman_portal *res; ++ struct qman_portal *portal; ++ ++ portal = &per_cpu(qman_affine_portal, config->public_cfg.cpu); ++ res = qman_create_portal(portal, config, cgrs); ++ if (res) { ++ spin_lock(&affine_mask_lock); ++ cpumask_set_cpu(config->public_cfg.cpu, &affine_mask); ++ affine_channels[config->public_cfg.cpu] = ++ config->public_cfg.channel; ++ affine_portals[config->public_cfg.cpu] = portal; ++ spin_unlock(&affine_mask_lock); ++ } ++ return res; ++} ++ ++/* These checks are BUG_ON()s because the driver is already supposed to avoid ++ * these cases. */ ++struct qman_portal *qman_create_affine_slave(struct qman_portal *redirect, ++ int cpu) ++{ ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ struct qman_portal *p; ++ p = &per_cpu(qman_affine_portal, cpu); ++ /* Check that we don't already have our own portal */ ++ BUG_ON(p->config); ++ /* Check that we aren't already slaving to another portal */ ++ BUG_ON(p->is_shared); ++ /* Check that 'redirect' is prepared to have us */ ++ BUG_ON(!redirect->config->public_cfg.is_shared); ++ /* These are the only elements to initialise when redirecting */ ++ p->irq_sources = 0; ++ p->sharing_redirect = redirect; ++ affine_portals[cpu] = p; ++ return p; ++#else ++ BUG(); ++ return NULL; ++#endif ++} ++ ++void qman_destroy_portal(struct qman_portal *qm) ++{ ++ const struct qm_portal_config *pcfg; ++ int i; ++ ++ /* Stop dequeues on the portal */ ++ qm_dqrr_sdqcr_set(&qm->p, 0); ++ ++ /* NB we do this to "quiesce" EQCR. If we add enqueue-completions or ++ * something related to QM_PIRQ_EQCI, this may need fixing. ++ * Also, due to the prefetching model used for CI updates in the enqueue ++ * path, this update will only invalidate the CI cacheline *after* ++ * working on it, so we need to call this twice to ensure a full update ++ * irrespective of where the enqueue processing was at when the teardown ++ * began. */ ++ qm_eqcr_cce_update(&qm->p); ++ qm_eqcr_cce_update(&qm->p); ++ pcfg = qm->config; ++ ++ free_irq(pcfg->public_cfg.irq, qm); ++ ++ kfree(qm->cgrs); ++ if (num_ceetms) ++ for (i = 0; i < num_ceetms; i++) ++ kfree(qm->ccgrs[i]); ++ qm_isr_finish(&qm->p); ++ qm_mc_finish(&qm->p); ++ qm_mr_finish(&qm->p); ++ qm_dqrr_finish(&qm->p); ++ qm_eqcr_finish(&qm->p); ++ ++ platform_device_del(qm->pdev); ++ platform_device_put(qm->pdev); ++ ++ qm->config = NULL; ++ if (qm->alloced) ++ kfree(qm); ++} ++ ++const struct qm_portal_config *qman_destroy_affine_portal(void) ++{ ++ /* We don't want to redirect if we're a slave, use "raw" */ ++ struct qman_portal *qm = get_raw_affine_portal(); ++ const struct qm_portal_config *pcfg; ++ int cpu; ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ if (qm->sharing_redirect) { ++ qm->sharing_redirect = NULL; ++ put_affine_portal(); ++ return NULL; ++ } ++ qm->is_shared = 0; ++#endif ++ pcfg = qm->config; ++ cpu = pcfg->public_cfg.cpu; ++ ++ qman_destroy_portal(qm); ++ ++ spin_lock(&affine_mask_lock); ++ cpumask_clear_cpu(cpu, &affine_mask); ++ spin_unlock(&affine_mask_lock); ++ put_affine_portal(); ++ return pcfg; ++} ++ ++const struct qman_portal_config *qman_p_get_portal_config(struct qman_portal *p) ++{ ++ return &p->config->public_cfg; ++} ++EXPORT_SYMBOL(qman_p_get_portal_config); ++ ++const struct qman_portal_config *qman_get_portal_config(void) ++{ ++ struct qman_portal *p = get_affine_portal(); ++ const struct qman_portal_config *ret = qman_p_get_portal_config(p); ++ put_affine_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(qman_get_portal_config); ++ ++/* Inline helper to reduce nesting in __poll_portal_slow() */ ++static inline void fq_state_change(struct qman_portal *p, struct qman_fq *fq, ++ const struct qm_mr_entry *msg, u8 verb) ++{ ++ FQLOCK(fq); ++ switch (verb) { ++ case QM_MR_VERB_FQRL: ++ DPA_ASSERT(fq_isset(fq, QMAN_FQ_STATE_ORL)); ++ fq_clear(fq, QMAN_FQ_STATE_ORL); ++ table_del_fq(p, fq); ++ break; ++ case QM_MR_VERB_FQRN: ++ DPA_ASSERT((fq->state == qman_fq_state_parked) || ++ (fq->state == qman_fq_state_sched)); ++ DPA_ASSERT(fq_isset(fq, QMAN_FQ_STATE_CHANGING)); ++ fq_clear(fq, QMAN_FQ_STATE_CHANGING); ++ if (msg->fq.fqs & QM_MR_FQS_NOTEMPTY) ++ fq_set(fq, QMAN_FQ_STATE_NE); ++ if (msg->fq.fqs & QM_MR_FQS_ORLPRESENT) ++ fq_set(fq, QMAN_FQ_STATE_ORL); ++ else ++ table_del_fq(p, fq); ++ fq->state = qman_fq_state_retired; ++ break; ++ case QM_MR_VERB_FQPN: ++ DPA_ASSERT(fq->state == qman_fq_state_sched); ++ DPA_ASSERT(fq_isclear(fq, QMAN_FQ_STATE_CHANGING)); ++ fq->state = qman_fq_state_parked; ++ } ++ FQUNLOCK(fq); ++} ++ ++static u32 __poll_portal_slow(struct qman_portal *p, u32 is) ++{ ++ const struct qm_mr_entry *msg; ++ struct qm_mr_entry swapped_msg; ++ int k; ++ ++ if (is & QM_PIRQ_CSCI) { ++ struct qman_cgrs rr, c; ++ struct qm_mc_result *mcr; ++ struct qman_cgr *cgr; ++ unsigned long irqflags __maybe_unused; ++ ++ spin_lock_irqsave(&p->cgr_lock, irqflags); ++ /* ++ * The CSCI bit must be cleared _before_ issuing the ++ * Query Congestion State command, to ensure that a long ++ * CGR State Change callback cannot miss an intervening ++ * state change. ++ */ ++ qm_isr_status_clear(&p->p, QM_PIRQ_CSCI); ++ qm_mc_start(&p->p); ++ qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCONGESTION); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ for (k = 0; k < 8; k++) ++ mcr->querycongestion.state.__state[k] = be32_to_cpu( ++ mcr->querycongestion.state.__state[k]); ++ /* mask out the ones I'm not interested in */ ++ qman_cgrs_and(&rr, (const struct qman_cgrs *) ++ &mcr->querycongestion.state, &p->cgrs[0]); ++ /* check previous snapshot for delta, enter/exit congestion */ ++ qman_cgrs_xor(&c, &rr, &p->cgrs[1]); ++ /* update snapshot */ ++ qman_cgrs_cp(&p->cgrs[1], &rr); ++ /* Invoke callback */ ++ list_for_each_entry(cgr, &p->cgr_cbs, node) ++ if (cgr->cb && qman_cgrs_get(&c, cgr->cgrid)) ++ cgr->cb(p, cgr, qman_cgrs_get(&rr, cgr->cgrid)); ++ spin_unlock_irqrestore(&p->cgr_lock, irqflags); ++ } ++ if (is & QM_PIRQ_CCSCI) { ++ struct qman_ccgrs rr, c, congestion_result; ++ struct qm_mc_result *mcr; ++ struct qm_mc_command *mcc; ++ struct qm_ceetm_ccg *ccg; ++ unsigned long irqflags __maybe_unused; ++ int i, j; ++ ++ spin_lock_irqsave(&p->ccgr_lock, irqflags); ++ /* ++ * The CCSCI bit must be cleared _before_ issuing the ++ * Query Congestion State command, to ensure that a long ++ * CCGR State Change callback cannot miss an intervening ++ * state change. ++ */ ++ qm_isr_status_clear(&p->p, QM_PIRQ_CCSCI); ++ ++ for (i = 0; i < num_ceetms; i++) { ++ for (j = 0; j < 2; j++) { ++ mcc = qm_mc_start(&p->p); ++ mcc->ccgr_query.ccgrid = cpu_to_be16( ++ CEETM_QUERY_CONGESTION_STATE | j); ++ mcc->ccgr_query.dcpid = i; ++ qm_mc_commit(&p->p, QM_CEETM_VERB_CCGR_QUERY); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ for (k = 0; k < 8; k++) ++ mcr->ccgr_query.congestion_state.state. ++ __state[k] = be32_to_cpu( ++ mcr->ccgr_query. ++ congestion_state.state. ++ __state[k]); ++ congestion_result.q[j] = ++ mcr->ccgr_query.congestion_state.state; ++ } ++ /* mask out the ones I'm not interested in */ ++ qman_ccgrs_and(&rr, &congestion_result, ++ &p->ccgrs[i][0]); ++ /* ++ * check previous snapshot for delta, enter/exit ++ * congestion. ++ */ ++ qman_ccgrs_xor(&c, &rr, &p->ccgrs[i][1]); ++ /* update snapshot */ ++ qman_ccgrs_cp(&p->ccgrs[i][1], &rr); ++ /* Invoke callback */ ++ list_for_each_entry(ccg, &p->ccgr_cbs[i], cb_node) ++ if (ccg->cb && qman_ccgrs_get(&c, ++ (ccg->parent->idx << 4) | ccg->idx)) ++ ccg->cb(ccg, ccg->cb_ctx, ++ qman_ccgrs_get(&rr, ++ (ccg->parent->idx << 4) ++ | ccg->idx)); ++ } ++ spin_unlock_irqrestore(&p->ccgr_lock, irqflags); ++ } ++ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ if (is & QM_PIRQ_EQCI) { ++ unsigned long irqflags; ++ PORTAL_IRQ_LOCK(p, irqflags); ++ p->eqci_owned = NULL; ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ wake_up(&affine_queue); ++ } ++#endif ++ ++ if (is & QM_PIRQ_EQRI) { ++ unsigned long irqflags __maybe_unused; ++ PORTAL_IRQ_LOCK(p, irqflags); ++ qm_eqcr_cce_update(&p->p); ++ qm_eqcr_set_ithresh(&p->p, 0); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ wake_up(&affine_queue); ++ } ++ ++ if (is & QM_PIRQ_MRI) { ++ struct qman_fq *fq; ++ u8 verb, num = 0; ++mr_loop: ++ qm_mr_pvb_update(&p->p); ++ msg = qm_mr_current(&p->p); ++ if (!msg) ++ goto mr_done; ++ swapped_msg = *msg; ++ hw_fd_to_cpu(&swapped_msg.ern.fd); ++ verb = msg->verb & QM_MR_VERB_TYPE_MASK; ++ /* The message is a software ERN iff the 0x20 bit is set */ ++ if (verb & 0x20) { ++ switch (verb) { ++ case QM_MR_VERB_FQRNI: ++ /* nada, we drop FQRNIs on the floor */ ++ break; ++ case QM_MR_VERB_FQRN: ++ case QM_MR_VERB_FQRL: ++ /* Lookup in the retirement table */ ++ fq = table_find_fq(p, be32_to_cpu(msg->fq.fqid)); ++ BUG_ON(!fq); ++ fq_state_change(p, fq, &swapped_msg, verb); ++ if (fq->cb.fqs) ++ fq->cb.fqs(p, fq, &swapped_msg); ++ break; ++ case QM_MR_VERB_FQPN: ++ /* Parked */ ++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP ++ fq = get_fq_table_entry( ++ be32_to_cpu(msg->fq.contextB)); ++#else ++ fq = (void *)(uintptr_t) ++ be32_to_cpu(msg->fq.contextB); ++#endif ++ fq_state_change(p, fq, msg, verb); ++ if (fq->cb.fqs) ++ fq->cb.fqs(p, fq, &swapped_msg); ++ break; ++ case QM_MR_VERB_DC_ERN: ++ /* DCP ERN */ ++ if (p->cb_dc_ern) ++ p->cb_dc_ern(p, msg); ++ else if (cb_dc_ern) ++ cb_dc_ern(p, msg); ++ else { ++ static int warn_once; ++ if (!warn_once) { ++ pr_crit("Leaking DCP ERNs!\n"); ++ warn_once = 1; ++ } ++ } ++ break; ++ default: ++ pr_crit("Invalid MR verb 0x%02x\n", verb); ++ } ++ } else { ++ /* Its a software ERN */ ++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP ++ fq = get_fq_table_entry(be32_to_cpu(msg->ern.tag)); ++#else ++ fq = (void *)(uintptr_t)be32_to_cpu(msg->ern.tag); ++#endif ++ fq->cb.ern(p, fq, &swapped_msg); ++ } ++ num++; ++ qm_mr_next(&p->p); ++ goto mr_loop; ++mr_done: ++ qm_mr_cci_consume(&p->p, num); ++ } ++ /* ++ * QM_PIRQ_CSCI/CCSCI has already been cleared, as part of its specific ++ * processing. If that interrupt source has meanwhile been re-asserted, ++ * we mustn't clear it here (or in the top-level interrupt handler). ++ */ ++ return is & (QM_PIRQ_EQCI | QM_PIRQ_EQRI | QM_PIRQ_MRI); ++} ++ ++/* remove some slowish-path stuff from the "fast path" and make sure it isn't ++ * inlined. */ ++static noinline void clear_vdqcr(struct qman_portal *p, struct qman_fq *fq) ++{ ++ p->vdqcr_owned = NULL; ++ FQLOCK(fq); ++ fq_clear(fq, QMAN_FQ_STATE_VDQCR); ++ FQUNLOCK(fq); ++ wake_up(&affine_queue); ++} ++ ++/* Copy a DQRR entry ensuring reads reach QBMan in order */ ++static inline void safe_copy_dqrr(struct qm_dqrr_entry *dst, ++ const struct qm_dqrr_entry *src) ++{ ++ int i = 0; ++ const u64 *s64 = (u64*)src; ++ u64 *d64 = (u64*)dst; ++ ++ /* DQRR only has 32 bytes of valid data so only need to ++ * copy 4 - 64 bit values */ ++ *d64 = *s64; ++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) ++ { ++ u32 res, zero = 0; ++ /* Create a dependancy after copying first bytes ensures no wrap ++ transaction generated to QBMan */ ++ /* Logical AND the value pointed to by s64 with 0x0 and ++ store the result in res */ ++ asm volatile("and %[result], %[in1], %[in2]" ++ : [result] "=r" (res) ++ : [in1] "r" (zero), [in2] "r" (*s64) ++ : "memory"); ++ /* Add res to s64 - this creates a dependancy on the result of ++ reading the value of s64 before the next read. The side ++ effect of this is that the core must stall until the first ++ aligned read is complete therefore preventing a WRAP ++ transaction to be seen by the QBMan */ ++ asm volatile("add %[result], %[in1], %[in2]" ++ : [result] "=r" (s64) ++ : [in1] "r" (res), [in2] "r" (s64) ++ : "memory"); ++ } ++#endif ++ /* Copy the last 3 64 bit parts */ ++ d64++; s64++; ++ for (;i<3; i++) ++ *d64++ = *s64++; ++} ++ ++/* Look: no locks, no irq_save()s, no preempt_disable()s! :-) The only states ++ * that would conflict with other things if they ran at the same time on the ++ * same cpu are; ++ * ++ * (i) setting/clearing vdqcr_owned, and ++ * (ii) clearing the NE (Not Empty) flag. ++ * ++ * Both are safe. Because; ++ * ++ * (i) this clearing can only occur after qman_volatile_dequeue() has set the ++ * vdqcr_owned field (which it does before setting VDQCR), and ++ * qman_volatile_dequeue() blocks interrupts and preemption while this is ++ * done so that we can't interfere. ++ * (ii) the NE flag is only cleared after qman_retire_fq() has set it, and as ++ * with (i) that API prevents us from interfering until it's safe. ++ * ++ * The good thing is that qman_volatile_dequeue() and qman_retire_fq() run far ++ * less frequently (ie. per-FQ) than __poll_portal_fast() does, so the nett ++ * advantage comes from this function not having to "lock" anything at all. ++ * ++ * Note also that the callbacks are invoked at points which are safe against the ++ * above potential conflicts, but that this function itself is not re-entrant ++ * (this is because the function tracks one end of each FIFO in the portal and ++ * we do *not* want to lock that). So the consequence is that it is safe for ++ * user callbacks to call into any Qman API *except* qman_poll() (as that's the ++ * sole API that could be invoking the callback through this function). ++ */ ++static inline unsigned int __poll_portal_fast(struct qman_portal *p, ++ unsigned int poll_limit) ++{ ++ const struct qm_dqrr_entry *dq; ++ struct qman_fq *fq; ++ enum qman_cb_dqrr_result res; ++ unsigned int limit = 0; ++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ++ struct qm_dqrr_entry *shadow; ++ const struct qm_dqrr_entry *orig_dq; ++#endif ++loop: ++ qm_dqrr_pvb_update(&p->p); ++ dq = qm_dqrr_current(&p->p); ++ if (!dq) ++ goto done; ++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ++ /* If running on an LE system the fields of the ++ dequeue entry must be swapped. Because the ++ QMan HW will ignore writes the DQRR entry is ++ copied and the index stored within the copy */ ++ shadow = &p->shadow_dqrr[DQRR_PTR2IDX(dq)]; ++ /* Use safe copy here to avoid WRAP transaction */ ++ safe_copy_dqrr(shadow, dq); ++ orig_dq = dq; ++ dq = shadow; ++ shadow->fqid = be32_to_cpu(shadow->fqid); ++ shadow->contextB = be32_to_cpu(shadow->contextB); ++ shadow->seqnum = be16_to_cpu(shadow->seqnum); ++ hw_fd_to_cpu(&shadow->fd); ++#endif ++ if (dq->stat & QM_DQRR_STAT_UNSCHEDULED) { ++ /* VDQCR: don't trust contextB as the FQ may have been ++ * configured for h/w consumption and we're draining it ++ * post-retirement. */ ++ fq = p->vdqcr_owned; ++ /* We only set QMAN_FQ_STATE_NE when retiring, so we only need ++ * to check for clearing it when doing volatile dequeues. It's ++ * one less thing to check in the critical path (SDQCR). */ ++ if (dq->stat & QM_DQRR_STAT_FQ_EMPTY) ++ fq_clear(fq, QMAN_FQ_STATE_NE); ++ /* this is duplicated from the SDQCR code, but we have stuff to ++ * do before *and* after this callback, and we don't want ++ * multiple if()s in the critical path (SDQCR). */ ++ res = fq->cb.dqrr(p, fq, dq); ++ if (res == qman_cb_dqrr_stop) ++ goto done; ++ /* Check for VDQCR completion */ ++ if (dq->stat & QM_DQRR_STAT_DQCR_EXPIRED) ++ clear_vdqcr(p, fq); ++ } else { ++ /* SDQCR: contextB points to the FQ */ ++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP ++ fq = get_fq_table_entry(dq->contextB); ++#else ++ fq = (void *)(uintptr_t)dq->contextB; ++#endif ++ /* Now let the callback do its stuff */ ++ res = fq->cb.dqrr(p, fq, dq); ++ ++ /* The callback can request that we exit without consuming this ++ * entry nor advancing; */ ++ if (res == qman_cb_dqrr_stop) ++ goto done; ++ } ++ /* Interpret 'dq' from a driver perspective. */ ++ /* Parking isn't possible unless HELDACTIVE was set. NB, ++ * FORCEELIGIBLE implies HELDACTIVE, so we only need to ++ * check for HELDACTIVE to cover both. */ ++ DPA_ASSERT((dq->stat & QM_DQRR_STAT_FQ_HELDACTIVE) || ++ (res != qman_cb_dqrr_park)); ++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ++ if (res != qman_cb_dqrr_defer) ++ qm_dqrr_cdc_consume_1ptr(&p->p, orig_dq, ++ (res == qman_cb_dqrr_park)); ++#else ++ /* Defer just means "skip it, I'll consume it myself later on" */ ++ if (res != qman_cb_dqrr_defer) ++ qm_dqrr_cdc_consume_1ptr(&p->p, dq, (res == qman_cb_dqrr_park)); ++#endif ++ /* Move forward */ ++ qm_dqrr_next(&p->p); ++ /* Entry processed and consumed, increment our counter. The callback can ++ * request that we exit after consuming the entry, and we also exit if ++ * we reach our processing limit, so loop back only if neither of these ++ * conditions is met. */ ++ if ((++limit < poll_limit) && (res != qman_cb_dqrr_consume_stop)) ++ goto loop; ++done: ++ return limit; ++} ++ ++u32 qman_irqsource_get(void) ++{ ++ /* "irqsource" and "poll" APIs mustn't redirect when sharing, they ++ * should shut the user out if they are not the primary CPU hosting the ++ * portal. That's why we use the "raw" interface. */ ++ struct qman_portal *p = get_raw_affine_portal(); ++ u32 ret = p->irq_sources & QM_PIRQ_VISIBLE; ++ put_affine_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(qman_irqsource_get); ++ ++int qman_p_irqsource_add(struct qman_portal *p, u32 bits __maybe_unused) ++{ ++ __maybe_unused unsigned long irqflags; ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ if (p->sharing_redirect) ++ return -EINVAL; ++ else ++#endif ++ { ++ bits = bits & QM_PIRQ_VISIBLE; ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ++ /* Clear any previously remaining interrupt conditions in ++ * QCSP_ISR. This prevents raising a false interrupt when ++ * interrupt conditions are enabled in QCSP_IER. ++ */ ++ qm_isr_status_clear(&p->p, bits); ++ set_bits(bits, &p->irq_sources); ++ qm_isr_enable_write(&p->p, p->irq_sources); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ } ++ return 0; ++} ++EXPORT_SYMBOL(qman_p_irqsource_add); ++ ++int qman_irqsource_add(u32 bits __maybe_unused) ++{ ++ struct qman_portal *p = get_raw_affine_portal(); ++ int ret; ++ ret = qman_p_irqsource_add(p, bits); ++ put_affine_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(qman_irqsource_add); ++ ++int qman_p_irqsource_remove(struct qman_portal *p, u32 bits) ++{ ++ __maybe_unused unsigned long irqflags; ++ u32 ier; ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ if (p->sharing_redirect) { ++ put_affine_portal(); ++ return -EINVAL; ++ } ++#endif ++ /* Our interrupt handler only processes+clears status register bits that ++ * are in p->irq_sources. As we're trimming that mask, if one of them ++ * were to assert in the status register just before we remove it from ++ * the enable register, there would be an interrupt-storm when we ++ * release the IRQ lock. So we wait for the enable register update to ++ * take effect in h/w (by reading it back) and then clear all other bits ++ * in the status register. Ie. we clear them from ISR once it's certain ++ * IER won't allow them to reassert. */ ++ PORTAL_IRQ_LOCK(p, irqflags); ++ bits &= QM_PIRQ_VISIBLE; ++ clear_bits(bits, &p->irq_sources); ++ qm_isr_enable_write(&p->p, p->irq_sources); ++ ++ ier = qm_isr_enable_read(&p->p); ++ /* Using "~ier" (rather than "bits" or "~p->irq_sources") creates a ++ * data-dependency, ie. to protect against re-ordering. */ ++ qm_isr_status_clear(&p->p, ~ier); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ return 0; ++} ++EXPORT_SYMBOL(qman_p_irqsource_remove); ++ ++int qman_irqsource_remove(u32 bits) ++{ ++ struct qman_portal *p = get_raw_affine_portal(); ++ int ret; ++ ret = qman_p_irqsource_remove(p, bits); ++ put_affine_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(qman_irqsource_remove); ++ ++const cpumask_t *qman_affine_cpus(void) ++{ ++ return &affine_mask; ++} ++EXPORT_SYMBOL(qman_affine_cpus); ++ ++u16 qman_affine_channel(int cpu) ++{ ++ if (cpu < 0) { ++ struct qman_portal *portal = get_raw_affine_portal(); ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ BUG_ON(portal->sharing_redirect); ++#endif ++ cpu = portal->config->public_cfg.cpu; ++ put_affine_portal(); ++ } ++ BUG_ON(!cpumask_test_cpu(cpu, &affine_mask)); ++ return affine_channels[cpu]; ++} ++EXPORT_SYMBOL(qman_affine_channel); ++ ++void *qman_get_affine_portal(int cpu) ++{ ++ return affine_portals[cpu]; ++} ++EXPORT_SYMBOL(qman_get_affine_portal); ++ ++int qman_p_poll_dqrr(struct qman_portal *p, unsigned int limit) ++{ ++ int ret; ++ ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ if (unlikely(p->sharing_redirect)) ++ ret = -EINVAL; ++ else ++#endif ++ { ++ BUG_ON(p->irq_sources & QM_PIRQ_DQRI); ++ ret = __poll_portal_fast(p, limit); ++ } ++ return ret; ++} ++EXPORT_SYMBOL(qman_p_poll_dqrr); ++ ++int qman_poll_dqrr(unsigned int limit) ++{ ++ struct qman_portal *p = get_poll_portal(); ++ int ret; ++ ret = qman_p_poll_dqrr(p, limit); ++ put_poll_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(qman_poll_dqrr); ++ ++u32 qman_p_poll_slow(struct qman_portal *p) ++{ ++ u32 ret; ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ if (unlikely(p->sharing_redirect)) ++ ret = (u32)-1; ++ else ++#endif ++ { ++ u32 is = qm_isr_status_read(&p->p) & ~p->irq_sources; ++ ret = __poll_portal_slow(p, is); ++ qm_isr_status_clear(&p->p, ret); ++ } ++ return ret; ++} ++EXPORT_SYMBOL(qman_p_poll_slow); ++ ++u32 qman_poll_slow(void) ++{ ++ struct qman_portal *p = get_poll_portal(); ++ u32 ret; ++ ret = qman_p_poll_slow(p); ++ put_poll_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(qman_poll_slow); ++ ++/* Legacy wrapper */ ++void qman_p_poll(struct qman_portal *p) ++{ ++#ifdef CONFIG_FSL_DPA_PORTAL_SHARE ++ if (unlikely(p->sharing_redirect)) ++ return; ++#endif ++ if ((~p->irq_sources) & QM_PIRQ_SLOW) { ++ if (!(p->slowpoll--)) { ++ u32 is = qm_isr_status_read(&p->p) & ~p->irq_sources; ++ u32 active = __poll_portal_slow(p, is); ++ if (active) { ++ qm_isr_status_clear(&p->p, active); ++ p->slowpoll = SLOW_POLL_BUSY; ++ } else ++ p->slowpoll = SLOW_POLL_IDLE; ++ } ++ } ++ if ((~p->irq_sources) & QM_PIRQ_DQRI) ++ __poll_portal_fast(p, CONFIG_FSL_QMAN_POLL_LIMIT); ++} ++EXPORT_SYMBOL(qman_p_poll); ++ ++void qman_poll(void) ++{ ++ struct qman_portal *p = get_poll_portal(); ++ qman_p_poll(p); ++ put_poll_portal(); ++} ++EXPORT_SYMBOL(qman_poll); ++ ++void qman_p_stop_dequeues(struct qman_portal *p) ++{ ++ qman_stop_dequeues_ex(p); ++} ++EXPORT_SYMBOL(qman_p_stop_dequeues); ++ ++void qman_stop_dequeues(void) ++{ ++ struct qman_portal *p = get_affine_portal(); ++ qman_p_stop_dequeues(p); ++ put_affine_portal(); ++} ++EXPORT_SYMBOL(qman_stop_dequeues); ++ ++void qman_p_start_dequeues(struct qman_portal *p) ++{ ++ unsigned long irqflags __maybe_unused; ++ PORTAL_IRQ_LOCK(p, irqflags); ++ DPA_ASSERT(p->dqrr_disable_ref > 0); ++ if (!(--p->dqrr_disable_ref)) ++ qm_dqrr_set_maxfill(&p->p, DQRR_MAXFILL); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++} ++EXPORT_SYMBOL(qman_p_start_dequeues); ++ ++void qman_start_dequeues(void) ++{ ++ struct qman_portal *p = get_affine_portal(); ++ qman_p_start_dequeues(p); ++ put_affine_portal(); ++} ++EXPORT_SYMBOL(qman_start_dequeues); ++ ++void qman_p_static_dequeue_add(struct qman_portal *p, u32 pools) ++{ ++ unsigned long irqflags __maybe_unused; ++ PORTAL_IRQ_LOCK(p, irqflags); ++ pools &= p->config->public_cfg.pools; ++ p->sdqcr |= pools; ++ qm_dqrr_sdqcr_set(&p->p, p->sdqcr); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++} ++EXPORT_SYMBOL(qman_p_static_dequeue_add); ++ ++void qman_static_dequeue_add(u32 pools) ++{ ++ struct qman_portal *p = get_affine_portal(); ++ qman_p_static_dequeue_add(p, pools); ++ put_affine_portal(); ++} ++EXPORT_SYMBOL(qman_static_dequeue_add); ++ ++void qman_p_static_dequeue_del(struct qman_portal *p, u32 pools) ++{ ++ unsigned long irqflags __maybe_unused; ++ PORTAL_IRQ_LOCK(p, irqflags); ++ pools &= p->config->public_cfg.pools; ++ p->sdqcr &= ~pools; ++ qm_dqrr_sdqcr_set(&p->p, p->sdqcr); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++} ++EXPORT_SYMBOL(qman_p_static_dequeue_del); ++ ++void qman_static_dequeue_del(u32 pools) ++{ ++ struct qman_portal *p = get_affine_portal(); ++ qman_p_static_dequeue_del(p, pools); ++ put_affine_portal(); ++} ++EXPORT_SYMBOL(qman_static_dequeue_del); ++ ++u32 qman_p_static_dequeue_get(struct qman_portal *p) ++{ ++ return p->sdqcr; ++} ++EXPORT_SYMBOL(qman_p_static_dequeue_get); ++ ++u32 qman_static_dequeue_get(void) ++{ ++ struct qman_portal *p = get_affine_portal(); ++ u32 ret = qman_p_static_dequeue_get(p); ++ put_affine_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(qman_static_dequeue_get); ++ ++void qman_p_dca(struct qman_portal *p, struct qm_dqrr_entry *dq, ++ int park_request) ++{ ++ qm_dqrr_cdc_consume_1ptr(&p->p, dq, park_request); ++} ++EXPORT_SYMBOL(qman_p_dca); ++ ++void qman_dca(struct qm_dqrr_entry *dq, int park_request) ++{ ++ struct qman_portal *p = get_affine_portal(); ++ qman_p_dca(p, dq, park_request); ++ put_affine_portal(); ++} ++EXPORT_SYMBOL(qman_dca); ++ ++/*******************/ ++/* Frame queue API */ ++/*******************/ ++ ++static const char *mcr_result_str(u8 result) ++{ ++ switch (result) { ++ case QM_MCR_RESULT_NULL: ++ return "QM_MCR_RESULT_NULL"; ++ case QM_MCR_RESULT_OK: ++ return "QM_MCR_RESULT_OK"; ++ case QM_MCR_RESULT_ERR_FQID: ++ return "QM_MCR_RESULT_ERR_FQID"; ++ case QM_MCR_RESULT_ERR_FQSTATE: ++ return "QM_MCR_RESULT_ERR_FQSTATE"; ++ case QM_MCR_RESULT_ERR_NOTEMPTY: ++ return "QM_MCR_RESULT_ERR_NOTEMPTY"; ++ case QM_MCR_RESULT_PENDING: ++ return "QM_MCR_RESULT_PENDING"; ++ case QM_MCR_RESULT_ERR_BADCOMMAND: ++ return "QM_MCR_RESULT_ERR_BADCOMMAND"; ++ } ++ return ""; ++} ++ ++int qman_create_fq(u32 fqid, u32 flags, struct qman_fq *fq) ++{ ++ struct qm_fqd fqd; ++ struct qm_mcr_queryfq_np np; ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ ++ if (flags & QMAN_FQ_FLAG_DYNAMIC_FQID) { ++ int ret = qman_alloc_fqid(&fqid); ++ if (ret) ++ return ret; ++ } ++ spin_lock_init(&fq->fqlock); ++ fq->fqid = fqid; ++ fq->flags = flags; ++ fq->state = qman_fq_state_oos; ++ fq->cgr_groupid = 0; ++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP ++ if (unlikely(find_empty_fq_table_entry(&fq->key, fq))) ++ return -ENOMEM; ++#endif ++ if (!(flags & QMAN_FQ_FLAG_AS_IS) || (flags & QMAN_FQ_FLAG_NO_MODIFY)) ++ return 0; ++ /* Everything else is AS_IS support */ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ mcc = qm_mc_start(&p->p); ++ mcc->queryfq.fqid = cpu_to_be32(fqid); ++ qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYFQ); ++ if (mcr->result != QM_MCR_RESULT_OK) { ++ pr_err("QUERYFQ failed: %s\n", mcr_result_str(mcr->result)); ++ goto err; ++ } ++ fqd = mcr->queryfq.fqd; ++ hw_fqd_to_cpu(&fqd); ++ mcc = qm_mc_start(&p->p); ++ mcc->queryfq_np.fqid = cpu_to_be32(fqid); ++ qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ_NP); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYFQ_NP); ++ if (mcr->result != QM_MCR_RESULT_OK) { ++ pr_err("QUERYFQ_NP failed: %s\n", mcr_result_str(mcr->result)); ++ goto err; ++ } ++ np = mcr->queryfq_np; ++ /* Phew, have queryfq and queryfq_np results, stitch together ++ * the FQ object from those. */ ++ fq->cgr_groupid = fqd.cgid; ++ switch (np.state & QM_MCR_NP_STATE_MASK) { ++ case QM_MCR_NP_STATE_OOS: ++ break; ++ case QM_MCR_NP_STATE_RETIRED: ++ fq->state = qman_fq_state_retired; ++ if (np.frm_cnt) ++ fq_set(fq, QMAN_FQ_STATE_NE); ++ break; ++ case QM_MCR_NP_STATE_TEN_SCHED: ++ case QM_MCR_NP_STATE_TRU_SCHED: ++ case QM_MCR_NP_STATE_ACTIVE: ++ fq->state = qman_fq_state_sched; ++ if (np.state & QM_MCR_NP_STATE_R) ++ fq_set(fq, QMAN_FQ_STATE_CHANGING); ++ break; ++ case QM_MCR_NP_STATE_PARKED: ++ fq->state = qman_fq_state_parked; ++ break; ++ default: ++ DPA_ASSERT(NULL == "invalid FQ state"); ++ } ++ if (fqd.fq_ctrl & QM_FQCTRL_CGE) ++ fq->state |= QMAN_FQ_STATE_CGR_EN; ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ return 0; ++err: ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ if (flags & QMAN_FQ_FLAG_DYNAMIC_FQID) ++ qman_release_fqid(fqid); ++ return -EIO; ++} ++EXPORT_SYMBOL(qman_create_fq); ++ ++void qman_destroy_fq(struct qman_fq *fq, u32 flags __maybe_unused) ++{ ++ ++ /* We don't need to lock the FQ as it is a pre-condition that the FQ be ++ * quiesced. Instead, run some checks. */ ++ switch (fq->state) { ++ case qman_fq_state_parked: ++ DPA_ASSERT(flags & QMAN_FQ_DESTROY_PARKED); ++ case qman_fq_state_oos: ++ if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID)) ++ qman_release_fqid(fq->fqid); ++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP ++ clear_fq_table_entry(fq->key); ++#endif ++ return; ++ default: ++ break; ++ } ++ DPA_ASSERT(NULL == "qman_free_fq() on unquiesced FQ!"); ++} ++EXPORT_SYMBOL(qman_destroy_fq); ++ ++u32 qman_fq_fqid(struct qman_fq *fq) ++{ ++ return fq->fqid; ++} ++EXPORT_SYMBOL(qman_fq_fqid); ++ ++void qman_fq_state(struct qman_fq *fq, enum qman_fq_state *state, u32 *flags) ++{ ++ if (state) ++ *state = fq->state; ++ if (flags) ++ *flags = fq->flags; ++} ++EXPORT_SYMBOL(qman_fq_state); ++ ++int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ u8 res, myverb = (flags & QMAN_INITFQ_FLAG_SCHED) ? ++ QM_MCC_VERB_INITFQ_SCHED : QM_MCC_VERB_INITFQ_PARKED; ++ ++ if ((fq->state != qman_fq_state_oos) && ++ (fq->state != qman_fq_state_parked)) ++ return -EINVAL; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY))) ++ return -EINVAL; ++#endif ++ if (opts && (opts->we_mask & QM_INITFQ_WE_OAC)) { ++ /* And can't be set at the same time as TDTHRESH */ ++ if (opts->we_mask & QM_INITFQ_WE_TDTHRESH) ++ return -EINVAL; ++ } ++ /* Issue an INITFQ_[PARKED|SCHED] management command */ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ FQLOCK(fq); ++ if (unlikely((fq_isset(fq, QMAN_FQ_STATE_CHANGING)) || ++ ((fq->state != qman_fq_state_oos) && ++ (fq->state != qman_fq_state_parked)))) { ++ FQUNLOCK(fq); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ return -EBUSY; ++ } ++ mcc = qm_mc_start(&p->p); ++ if (opts) ++ mcc->initfq = *opts; ++ mcc->initfq.fqid = cpu_to_be32(fq->fqid); ++ mcc->initfq.count = 0; ++ ++ /* If the FQ does *not* have the TO_DCPORTAL flag, contextB is set as a ++ * demux pointer. Otherwise, the caller-provided value is allowed to ++ * stand, don't overwrite it. */ ++ if (fq_isclear(fq, QMAN_FQ_FLAG_TO_DCPORTAL)) { ++ dma_addr_t phys_fq; ++ mcc->initfq.we_mask |= QM_INITFQ_WE_CONTEXTB; ++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP ++ mcc->initfq.fqd.context_b = fq->key; ++#else ++ mcc->initfq.fqd.context_b = (u32)(uintptr_t)fq; ++#endif ++ /* and the physical address - NB, if the user wasn't trying to ++ * set CONTEXTA, clear the stashing settings. */ ++ if (!(mcc->initfq.we_mask & QM_INITFQ_WE_CONTEXTA)) { ++ mcc->initfq.we_mask |= QM_INITFQ_WE_CONTEXTA; ++ memset(&mcc->initfq.fqd.context_a, 0, ++ sizeof(mcc->initfq.fqd.context_a)); ++ } else { ++ phys_fq = dma_map_single(&p->pdev->dev, fq, sizeof(*fq), ++ DMA_TO_DEVICE); ++ qm_fqd_stashing_set64(&mcc->initfq.fqd, phys_fq); ++ } ++ } ++ if (flags & QMAN_INITFQ_FLAG_LOCAL) { ++ mcc->initfq.fqd.dest.channel = p->config->public_cfg.channel; ++ if (!(mcc->initfq.we_mask & QM_INITFQ_WE_DESTWQ)) { ++ mcc->initfq.we_mask |= QM_INITFQ_WE_DESTWQ; ++ mcc->initfq.fqd.dest.wq = 4; ++ } ++ } ++ mcc->initfq.we_mask = cpu_to_be16(mcc->initfq.we_mask); ++ cpu_to_hw_fqd(&mcc->initfq.fqd); ++ qm_mc_commit(&p->p, myverb); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == myverb); ++ res = mcr->result; ++ if (res != QM_MCR_RESULT_OK) { ++ FQUNLOCK(fq); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ return -EIO; ++ } ++ if (opts) { ++ if (opts->we_mask & QM_INITFQ_WE_FQCTRL) { ++ if (opts->fqd.fq_ctrl & QM_FQCTRL_CGE) ++ fq_set(fq, QMAN_FQ_STATE_CGR_EN); ++ else ++ fq_clear(fq, QMAN_FQ_STATE_CGR_EN); ++ } ++ if (opts->we_mask & QM_INITFQ_WE_CGID) ++ fq->cgr_groupid = opts->fqd.cgid; ++ } ++ fq->state = (flags & QMAN_INITFQ_FLAG_SCHED) ? ++ qman_fq_state_sched : qman_fq_state_parked; ++ FQUNLOCK(fq); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ return 0; ++} ++EXPORT_SYMBOL(qman_init_fq); ++ ++int qman_schedule_fq(struct qman_fq *fq) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ int ret = 0; ++ u8 res; ++ ++ if (fq->state != qman_fq_state_parked) ++ return -EINVAL; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY))) ++ return -EINVAL; ++#endif ++ /* Issue a ALTERFQ_SCHED management command */ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ FQLOCK(fq); ++ if (unlikely((fq_isset(fq, QMAN_FQ_STATE_CHANGING)) || ++ (fq->state != qman_fq_state_parked))) { ++ ret = -EBUSY; ++ goto out; ++ } ++ mcc = qm_mc_start(&p->p); ++ mcc->alterfq.fqid = cpu_to_be32(fq->fqid); ++ qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_SCHED); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_SCHED); ++ res = mcr->result; ++ if (res != QM_MCR_RESULT_OK) { ++ ret = -EIO; ++ goto out; ++ } ++ fq->state = qman_fq_state_sched; ++out: ++ FQUNLOCK(fq); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(qman_schedule_fq); ++ ++int qman_retire_fq(struct qman_fq *fq, u32 *flags) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ int rval; ++ u8 res; ++ ++ if ((fq->state != qman_fq_state_parked) && ++ (fq->state != qman_fq_state_sched)) ++ return -EINVAL; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY))) ++ return -EINVAL; ++#endif ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ FQLOCK(fq); ++ if (unlikely((fq_isset(fq, QMAN_FQ_STATE_CHANGING)) || ++ (fq->state == qman_fq_state_retired) || ++ (fq->state == qman_fq_state_oos))) { ++ rval = -EBUSY; ++ goto out; ++ } ++ rval = table_push_fq(p, fq); ++ if (rval) ++ goto out; ++ mcc = qm_mc_start(&p->p); ++ mcc->alterfq.fqid = cpu_to_be32(fq->fqid); ++ qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_RETIRE); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_RETIRE); ++ res = mcr->result; ++ /* "Elegant" would be to treat OK/PENDING the same way; set CHANGING, ++ * and defer the flags until FQRNI or FQRN (respectively) show up. But ++ * "Friendly" is to process OK immediately, and not set CHANGING. We do ++ * friendly, otherwise the caller doesn't necessarily have a fully ++ * "retired" FQ on return even if the retirement was immediate. However ++ * this does mean some code duplication between here and ++ * fq_state_change(). */ ++ if (likely(res == QM_MCR_RESULT_OK)) { ++ rval = 0; ++ /* Process 'fq' right away, we'll ignore FQRNI */ ++ if (mcr->alterfq.fqs & QM_MCR_FQS_NOTEMPTY) ++ fq_set(fq, QMAN_FQ_STATE_NE); ++ if (mcr->alterfq.fqs & QM_MCR_FQS_ORLPRESENT) ++ fq_set(fq, QMAN_FQ_STATE_ORL); ++ else ++ table_del_fq(p, fq); ++ if (flags) ++ *flags = fq->flags; ++ fq->state = qman_fq_state_retired; ++ if (fq->cb.fqs) { ++ /* Another issue with supporting "immediate" retirement ++ * is that we're forced to drop FQRNIs, because by the ++ * time they're seen it may already be "too late" (the ++ * fq may have been OOS'd and free()'d already). But if ++ * the upper layer wants a callback whether it's ++ * immediate or not, we have to fake a "MR" entry to ++ * look like an FQRNI... */ ++ struct qm_mr_entry msg; ++ msg.verb = QM_MR_VERB_FQRNI; ++ msg.fq.fqs = mcr->alterfq.fqs; ++ msg.fq.fqid = fq->fqid; ++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP ++ msg.fq.contextB = fq->key; ++#else ++ msg.fq.contextB = (u32)(uintptr_t)fq; ++#endif ++ fq->cb.fqs(p, fq, &msg); ++ } ++ } else if (res == QM_MCR_RESULT_PENDING) { ++ rval = 1; ++ fq_set(fq, QMAN_FQ_STATE_CHANGING); ++ } else { ++ rval = -EIO; ++ table_del_fq(p, fq); ++ } ++out: ++ FQUNLOCK(fq); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ return rval; ++} ++EXPORT_SYMBOL(qman_retire_fq); ++ ++int qman_oos_fq(struct qman_fq *fq) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ int ret = 0; ++ u8 res; ++ ++ if (fq->state != qman_fq_state_retired) ++ return -EINVAL; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY))) ++ return -EINVAL; ++#endif ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ FQLOCK(fq); ++ if (unlikely((fq_isset(fq, QMAN_FQ_STATE_BLOCKOOS)) || ++ (fq->state != qman_fq_state_retired))) { ++ ret = -EBUSY; ++ goto out; ++ } ++ mcc = qm_mc_start(&p->p); ++ mcc->alterfq.fqid = cpu_to_be32(fq->fqid); ++ qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_OOS); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_OOS); ++ res = mcr->result; ++ if (res != QM_MCR_RESULT_OK) { ++ ret = -EIO; ++ goto out; ++ } ++ fq->state = qman_fq_state_oos; ++out: ++ FQUNLOCK(fq); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(qman_oos_fq); ++ ++int qman_fq_flow_control(struct qman_fq *fq, int xon) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ int ret = 0; ++ u8 res; ++ u8 myverb; ++ ++ if ((fq->state == qman_fq_state_oos) || ++ (fq->state == qman_fq_state_retired) || ++ (fq->state == qman_fq_state_parked)) ++ return -EINVAL; ++ ++#ifdef CONFIG_FSL_DPA_CHECKING ++ if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY))) ++ return -EINVAL; ++#endif ++ /* Issue a ALTER_FQXON or ALTER_FQXOFF management command */ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ FQLOCK(fq); ++ if (unlikely((fq_isset(fq, QMAN_FQ_STATE_CHANGING)) || ++ (fq->state == qman_fq_state_parked) || ++ (fq->state == qman_fq_state_oos) || ++ (fq->state == qman_fq_state_retired))) { ++ ret = -EBUSY; ++ goto out; ++ } ++ mcc = qm_mc_start(&p->p); ++ mcc->alterfq.fqid = fq->fqid; ++ mcc->alterfq.count = 0; ++ myverb = xon ? QM_MCC_VERB_ALTER_FQXON : QM_MCC_VERB_ALTER_FQXOFF; ++ ++ qm_mc_commit(&p->p, myverb); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == myverb); ++ ++ res = mcr->result; ++ if (res != QM_MCR_RESULT_OK) { ++ ret = -EIO; ++ goto out; ++ } ++out: ++ FQUNLOCK(fq); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(qman_fq_flow_control); ++ ++int qman_query_fq(struct qman_fq *fq, struct qm_fqd *fqd) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p = get_affine_portal(); ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ PORTAL_IRQ_LOCK(p, irqflags); ++ mcc = qm_mc_start(&p->p); ++ mcc->queryfq.fqid = cpu_to_be32(fq->fqid); ++ qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ); ++ res = mcr->result; ++ if (res == QM_MCR_RESULT_OK) ++ *fqd = mcr->queryfq.fqd; ++ hw_fqd_to_cpu(fqd); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ if (res != QM_MCR_RESULT_OK) ++ return -EIO; ++ return 0; ++} ++EXPORT_SYMBOL(qman_query_fq); ++ ++int qman_query_fq_np(struct qman_fq *fq, struct qm_mcr_queryfq_np *np) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p = get_affine_portal(); ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ PORTAL_IRQ_LOCK(p, irqflags); ++ mcc = qm_mc_start(&p->p); ++ mcc->queryfq.fqid = cpu_to_be32(fq->fqid); ++ qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ_NP); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ_NP); ++ res = mcr->result; ++ if (res == QM_MCR_RESULT_OK) { ++ *np = mcr->queryfq_np; ++ np->fqd_link = be24_to_cpu(np->fqd_link); ++ np->odp_seq = be16_to_cpu(np->odp_seq); ++ np->orp_nesn = be16_to_cpu(np->orp_nesn); ++ np->orp_ea_hseq = be16_to_cpu(np->orp_ea_hseq); ++ np->orp_ea_tseq = be16_to_cpu(np->orp_ea_tseq); ++ np->orp_ea_hptr = be24_to_cpu(np->orp_ea_hptr); ++ np->orp_ea_tptr = be24_to_cpu(np->orp_ea_tptr); ++ np->pfdr_hptr = be24_to_cpu(np->pfdr_hptr); ++ np->pfdr_tptr = be24_to_cpu(np->pfdr_tptr); ++ np->ics_surp = be16_to_cpu(np->ics_surp); ++ np->byte_cnt = be32_to_cpu(np->byte_cnt); ++ np->frm_cnt = be24_to_cpu(np->frm_cnt); ++ np->ra1_sfdr = be16_to_cpu(np->ra1_sfdr); ++ np->ra2_sfdr = be16_to_cpu(np->ra2_sfdr); ++ np->od1_sfdr = be16_to_cpu(np->od1_sfdr); ++ np->od2_sfdr = be16_to_cpu(np->od2_sfdr); ++ np->od3_sfdr = be16_to_cpu(np->od3_sfdr); ++ } ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ if (res == QM_MCR_RESULT_ERR_FQID) ++ return -ERANGE; ++ else if (res != QM_MCR_RESULT_OK) ++ return -EIO; ++ return 0; ++} ++EXPORT_SYMBOL(qman_query_fq_np); ++ ++int qman_query_wq(u8 query_dedicated, struct qm_mcr_querywq *wq) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p = get_affine_portal(); ++ unsigned long irqflags __maybe_unused; ++ u8 res, myverb; ++ ++ PORTAL_IRQ_LOCK(p, irqflags); ++ myverb = (query_dedicated) ? QM_MCR_VERB_QUERYWQ_DEDICATED : ++ QM_MCR_VERB_QUERYWQ; ++ mcc = qm_mc_start(&p->p); ++ mcc->querywq.channel.id = cpu_to_be16(wq->channel.id); ++ qm_mc_commit(&p->p, myverb); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == myverb); ++ res = mcr->result; ++ if (res == QM_MCR_RESULT_OK) { ++ int i, array_len; ++ wq->channel.id = be16_to_cpu(mcr->querywq.channel.id); ++ array_len = ARRAY_SIZE(mcr->querywq.wq_len); ++ for (i = 0; i < array_len; i++) ++ wq->wq_len[i] = be32_to_cpu(mcr->querywq.wq_len[i]); ++ } ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("QUERYWQ failed: %s\n", mcr_result_str(res)); ++ return -EIO; ++ } ++ return 0; ++} ++EXPORT_SYMBOL(qman_query_wq); ++ ++int qman_testwrite_cgr(struct qman_cgr *cgr, u64 i_bcnt, ++ struct qm_mcr_cgrtestwrite *result) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p = get_affine_portal(); ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ PORTAL_IRQ_LOCK(p, irqflags); ++ mcc = qm_mc_start(&p->p); ++ mcc->cgrtestwrite.cgid = cgr->cgrid; ++ mcc->cgrtestwrite.i_bcnt_hi = (u8)(i_bcnt >> 32); ++ mcc->cgrtestwrite.i_bcnt_lo = (u32)i_bcnt; ++ qm_mc_commit(&p->p, QM_MCC_VERB_CGRTESTWRITE); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_CGRTESTWRITE); ++ res = mcr->result; ++ if (res == QM_MCR_RESULT_OK) ++ *result = mcr->cgrtestwrite; ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("CGR TEST WRITE failed: %s\n", mcr_result_str(res)); ++ return -EIO; ++ } ++ return 0; ++} ++EXPORT_SYMBOL(qman_testwrite_cgr); ++ ++int qman_query_cgr(struct qman_cgr *cgr, struct qm_mcr_querycgr *cgrd) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p = get_affine_portal(); ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ int i; ++ ++ PORTAL_IRQ_LOCK(p, irqflags); ++ mcc = qm_mc_start(&p->p); ++ mcc->querycgr.cgid = cgr->cgrid; ++ qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCGR); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYCGR); ++ res = mcr->result; ++ if (res == QM_MCR_RESULT_OK) ++ *cgrd = mcr->querycgr; ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("QUERY_CGR failed: %s\n", mcr_result_str(res)); ++ return -EIO; ++ } ++ cgrd->cgr.wr_parm_g.word = ++ be32_to_cpu(cgrd->cgr.wr_parm_g.word); ++ cgrd->cgr.wr_parm_y.word = ++ be32_to_cpu(cgrd->cgr.wr_parm_y.word); ++ cgrd->cgr.wr_parm_r.word = ++ be32_to_cpu(cgrd->cgr.wr_parm_r.word); ++ cgrd->cgr.cscn_targ = be32_to_cpu(cgrd->cgr.cscn_targ); ++ cgrd->cgr.__cs_thres = be16_to_cpu(cgrd->cgr.__cs_thres); ++ for (i = 0; i < ARRAY_SIZE(cgrd->cscn_targ_swp); i++) ++ be32_to_cpus(&cgrd->cscn_targ_swp[i]); ++ return 0; ++} ++EXPORT_SYMBOL(qman_query_cgr); ++ ++int qman_query_congestion(struct qm_mcr_querycongestion *congestion) ++{ ++ struct qm_mc_result *mcr; ++ struct qman_portal *p = get_affine_portal(); ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ int i; ++ ++ PORTAL_IRQ_LOCK(p, irqflags); ++ qm_mc_start(&p->p); ++ qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCONGESTION); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == ++ QM_MCC_VERB_QUERYCONGESTION); ++ res = mcr->result; ++ if (res == QM_MCR_RESULT_OK) ++ memcpy_fromio(congestion, &mcr->querycongestion, ++ sizeof(*congestion)); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("QUERY_CONGESTION failed: %s\n", mcr_result_str(res)); ++ return -EIO; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(congestion->state.__state); i++) ++ be32_to_cpus(&congestion->state.__state[i]); ++ return 0; ++} ++EXPORT_SYMBOL(qman_query_congestion); ++ ++/* internal function used as a wait_event() expression */ ++static int set_p_vdqcr(struct qman_portal *p, struct qman_fq *fq, u32 vdqcr) ++{ ++ unsigned long irqflags __maybe_unused; ++ int ret = -EBUSY; ++ PORTAL_IRQ_LOCK(p, irqflags); ++ if (!p->vdqcr_owned) { ++ FQLOCK(fq); ++ if (fq_isset(fq, QMAN_FQ_STATE_VDQCR)) ++ goto escape; ++ fq_set(fq, QMAN_FQ_STATE_VDQCR); ++ FQUNLOCK(fq); ++ p->vdqcr_owned = fq; ++ ret = 0; ++ } ++escape: ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ if (!ret) ++ qm_dqrr_vdqcr_set(&p->p, vdqcr); ++ return ret; ++} ++ ++static int set_vdqcr(struct qman_portal **p, struct qman_fq *fq, u32 vdqcr) ++{ ++ int ret; ++ *p = get_affine_portal(); ++ ret = set_p_vdqcr(*p, fq, vdqcr); ++ put_affine_portal(); ++ return ret; ++} ++ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++static int wait_p_vdqcr_start(struct qman_portal *p, struct qman_fq *fq, ++ u32 vdqcr, u32 flags) ++{ ++ int ret = 0; ++ if (flags & QMAN_VOLATILE_FLAG_WAIT_INT) ++ ret = wait_event_interruptible(affine_queue, ++ !(ret = set_p_vdqcr(p, fq, vdqcr))); ++ else ++ wait_event(affine_queue, !(ret = set_p_vdqcr(p, fq, vdqcr))); ++ return ret; ++} ++ ++static int wait_vdqcr_start(struct qman_portal **p, struct qman_fq *fq, ++ u32 vdqcr, u32 flags) ++{ ++ int ret = 0; ++ if (flags & QMAN_VOLATILE_FLAG_WAIT_INT) ++ ret = wait_event_interruptible(affine_queue, ++ !(ret = set_vdqcr(p, fq, vdqcr))); ++ else ++ wait_event(affine_queue, !(ret = set_vdqcr(p, fq, vdqcr))); ++ return ret; ++} ++#endif ++ ++int qman_p_volatile_dequeue(struct qman_portal *p, struct qman_fq *fq, ++ u32 flags __maybe_unused, u32 vdqcr) ++{ ++ int ret; ++ ++ if ((fq->state != qman_fq_state_parked) && ++ (fq->state != qman_fq_state_retired)) ++ return -EINVAL; ++ if (vdqcr & QM_VDQCR_FQID_MASK) ++ return -EINVAL; ++ if (fq_isset(fq, QMAN_FQ_STATE_VDQCR)) ++ return -EBUSY; ++ vdqcr = (vdqcr & ~QM_VDQCR_FQID_MASK) | fq->fqid; ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++ if (flags & QMAN_VOLATILE_FLAG_WAIT) ++ ret = wait_p_vdqcr_start(p, fq, vdqcr, flags); ++ else ++#endif ++ ret = set_p_vdqcr(p, fq, vdqcr); ++ if (ret) ++ return ret; ++ /* VDQCR is set */ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++ if (flags & QMAN_VOLATILE_FLAG_FINISH) { ++ if (flags & QMAN_VOLATILE_FLAG_WAIT_INT) ++ /* NB: don't propagate any error - the caller wouldn't ++ * know whether the VDQCR was issued or not. A signal ++ * could arrive after returning anyway, so the caller ++ * can check signal_pending() if that's an issue. */ ++ wait_event_interruptible(affine_queue, ++ !fq_isset(fq, QMAN_FQ_STATE_VDQCR)); ++ else ++ wait_event(affine_queue, ++ !fq_isset(fq, QMAN_FQ_STATE_VDQCR)); ++ } ++#endif ++ return 0; ++} ++EXPORT_SYMBOL(qman_p_volatile_dequeue); ++ ++int qman_volatile_dequeue(struct qman_fq *fq, u32 flags __maybe_unused, ++ u32 vdqcr) ++{ ++ struct qman_portal *p; ++ int ret; ++ ++ if ((fq->state != qman_fq_state_parked) && ++ (fq->state != qman_fq_state_retired)) ++ return -EINVAL; ++ if (vdqcr & QM_VDQCR_FQID_MASK) ++ return -EINVAL; ++ if (fq_isset(fq, QMAN_FQ_STATE_VDQCR)) ++ return -EBUSY; ++ vdqcr = (vdqcr & ~QM_VDQCR_FQID_MASK) | fq->fqid; ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++ if (flags & QMAN_VOLATILE_FLAG_WAIT) ++ ret = wait_vdqcr_start(&p, fq, vdqcr, flags); ++ else ++#endif ++ ret = set_vdqcr(&p, fq, vdqcr); ++ if (ret) ++ return ret; ++ /* VDQCR is set */ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++ if (flags & QMAN_VOLATILE_FLAG_FINISH) { ++ if (flags & QMAN_VOLATILE_FLAG_WAIT_INT) ++ /* NB: don't propagate any error - the caller wouldn't ++ * know whether the VDQCR was issued or not. A signal ++ * could arrive after returning anyway, so the caller ++ * can check signal_pending() if that's an issue. */ ++ wait_event_interruptible(affine_queue, ++ !fq_isset(fq, QMAN_FQ_STATE_VDQCR)); ++ else ++ wait_event(affine_queue, ++ !fq_isset(fq, QMAN_FQ_STATE_VDQCR)); ++ } ++#endif ++ return 0; ++} ++EXPORT_SYMBOL(qman_volatile_dequeue); ++ ++static noinline void update_eqcr_ci(struct qman_portal *p, u8 avail) ++{ ++ if (avail) ++ qm_eqcr_cce_prefetch(&p->p); ++ else ++ qm_eqcr_cce_update(&p->p); ++} ++ ++int qman_eqcr_is_empty(void) ++{ ++ unsigned long irqflags __maybe_unused; ++ struct qman_portal *p = get_affine_portal(); ++ u8 avail; ++ ++ PORTAL_IRQ_LOCK(p, irqflags); ++ update_eqcr_ci(p, 0); ++ avail = qm_eqcr_get_fill(&p->p); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ return avail == 0; ++} ++EXPORT_SYMBOL(qman_eqcr_is_empty); ++ ++void qman_set_dc_ern(qman_cb_dc_ern handler, int affine) ++{ ++ if (affine) { ++ unsigned long irqflags __maybe_unused; ++ struct qman_portal *p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ p->cb_dc_ern = handler; ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ } else ++ cb_dc_ern = handler; ++} ++EXPORT_SYMBOL(qman_set_dc_ern); ++ ++static inline struct qm_eqcr_entry *try_p_eq_start(struct qman_portal *p, ++ unsigned long *irqflags __maybe_unused, ++ struct qman_fq *fq, ++ const struct qm_fd *fd, ++ u32 flags) ++{ ++ struct qm_eqcr_entry *eq; ++ u8 avail; ++ PORTAL_IRQ_LOCK(p, (*irqflags)); ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) && ++ (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) { ++ if (p->eqci_owned) { ++ PORTAL_IRQ_UNLOCK(p, (*irqflags)); ++ return NULL; ++ } ++ p->eqci_owned = fq; ++ } ++#endif ++ if (p->use_eqcr_ci_stashing) { ++ /* ++ * The stashing case is easy, only update if we need to in ++ * order to try and liberate ring entries. ++ */ ++ eq = qm_eqcr_start_stash(&p->p); ++ } else { ++ /* ++ * The non-stashing case is harder, need to prefetch ahead of ++ * time. ++ */ ++ avail = qm_eqcr_get_avail(&p->p); ++ if (avail < 2) ++ update_eqcr_ci(p, avail); ++ eq = qm_eqcr_start_no_stash(&p->p); ++ } ++ ++ if (unlikely(!eq)) { ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) && ++ (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) ++ p->eqci_owned = NULL; ++#endif ++ PORTAL_IRQ_UNLOCK(p, (*irqflags)); ++ return NULL; ++ } ++ if (flags & QMAN_ENQUEUE_FLAG_DCA) ++ eq->dca = QM_EQCR_DCA_ENABLE | ++ ((flags & QMAN_ENQUEUE_FLAG_DCA_PARK) ? ++ QM_EQCR_DCA_PARK : 0) | ++ ((flags >> 8) & QM_EQCR_DCA_IDXMASK); ++ eq->fqid = cpu_to_be32(fq->fqid); ++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP ++ eq->tag = cpu_to_be32(fq->key); ++#else ++ eq->tag = cpu_to_be32((u32)(uintptr_t)fq); ++#endif ++ eq->fd = *fd; ++ cpu_to_hw_fd(&eq->fd); ++ return eq; ++} ++ ++static inline struct qm_eqcr_entry *try_eq_start(struct qman_portal **p, ++ unsigned long *irqflags __maybe_unused, ++ struct qman_fq *fq, ++ const struct qm_fd *fd, ++ u32 flags) ++{ ++ struct qm_eqcr_entry *eq; ++ *p = get_affine_portal(); ++ eq = try_p_eq_start(*p, irqflags, fq, fd, flags); ++ if (!eq) ++ put_affine_portal(); ++ return eq; ++} ++ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++static noinline struct qm_eqcr_entry *__wait_eq_start(struct qman_portal **p, ++ unsigned long *irqflags __maybe_unused, ++ struct qman_fq *fq, ++ const struct qm_fd *fd, ++ u32 flags) ++{ ++ struct qm_eqcr_entry *eq = try_eq_start(p, irqflags, fq, fd, flags); ++ if (!eq) ++ qm_eqcr_set_ithresh(&(*p)->p, EQCR_ITHRESH); ++ return eq; ++} ++static noinline struct qm_eqcr_entry *wait_eq_start(struct qman_portal **p, ++ unsigned long *irqflags __maybe_unused, ++ struct qman_fq *fq, ++ const struct qm_fd *fd, ++ u32 flags) ++{ ++ struct qm_eqcr_entry *eq; ++ if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT) ++ /* NB: return NULL if signal occurs before completion. Signal ++ * can occur during return. Caller must check for signal */ ++ wait_event_interruptible(affine_queue, ++ (eq = __wait_eq_start(p, irqflags, fq, fd, flags))); ++ else ++ wait_event(affine_queue, ++ (eq = __wait_eq_start(p, irqflags, fq, fd, flags))); ++ return eq; ++} ++static noinline struct qm_eqcr_entry *__wait_p_eq_start(struct qman_portal *p, ++ unsigned long *irqflags __maybe_unused, ++ struct qman_fq *fq, ++ const struct qm_fd *fd, ++ u32 flags) ++{ ++ struct qm_eqcr_entry *eq = try_p_eq_start(p, irqflags, fq, fd, flags); ++ if (!eq) ++ qm_eqcr_set_ithresh(&p->p, EQCR_ITHRESH); ++ return eq; ++} ++static noinline struct qm_eqcr_entry *wait_p_eq_start(struct qman_portal *p, ++ unsigned long *irqflags __maybe_unused, ++ struct qman_fq *fq, ++ const struct qm_fd *fd, ++ u32 flags) ++{ ++ struct qm_eqcr_entry *eq; ++ if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT) ++ /* NB: return NULL if signal occurs before completion. Signal ++ * can occur during return. Caller must check for signal */ ++ wait_event_interruptible(affine_queue, ++ (eq = __wait_p_eq_start(p, irqflags, fq, fd, flags))); ++ else ++ wait_event(affine_queue, ++ (eq = __wait_p_eq_start(p, irqflags, fq, fd, flags))); ++ return eq; ++} ++#endif ++ ++int qman_p_enqueue(struct qman_portal *p, struct qman_fq *fq, ++ const struct qm_fd *fd, u32 flags) ++{ ++ struct qm_eqcr_entry *eq; ++ unsigned long irqflags __maybe_unused; ++ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++ if (flags & QMAN_ENQUEUE_FLAG_WAIT) ++ eq = wait_p_eq_start(p, &irqflags, fq, fd, flags); ++ else ++#endif ++ eq = try_p_eq_start(p, &irqflags, fq, fd, flags); ++ if (!eq) ++ return -EBUSY; ++ /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */ ++ qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_CMD_ENQUEUE | ++ (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT))); ++ /* Factor the below out, it's used from qman_enqueue_orp() too */ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) && ++ (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) { ++ if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT) ++ /* NB: return success even if signal occurs before ++ * condition is true. pvb_commit guarantees success */ ++ wait_event_interruptible(affine_queue, ++ (p->eqci_owned != fq)); ++ else ++ wait_event(affine_queue, (p->eqci_owned != fq)); ++ } ++#endif ++ return 0; ++} ++EXPORT_SYMBOL(qman_p_enqueue); ++ ++int qman_enqueue(struct qman_fq *fq, const struct qm_fd *fd, u32 flags) ++{ ++ struct qman_portal *p; ++ struct qm_eqcr_entry *eq; ++ unsigned long irqflags __maybe_unused; ++ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++ if (flags & QMAN_ENQUEUE_FLAG_WAIT) ++ eq = wait_eq_start(&p, &irqflags, fq, fd, flags); ++ else ++#endif ++ eq = try_eq_start(&p, &irqflags, fq, fd, flags); ++ if (!eq) ++ return -EBUSY; ++ /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */ ++ qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_CMD_ENQUEUE | ++ (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT))); ++ /* Factor the below out, it's used from qman_enqueue_orp() too */ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) && ++ (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) { ++ if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT) ++ /* NB: return success even if signal occurs before ++ * condition is true. pvb_commit guarantees success */ ++ wait_event_interruptible(affine_queue, ++ (p->eqci_owned != fq)); ++ else ++ wait_event(affine_queue, (p->eqci_owned != fq)); ++ } ++#endif ++ return 0; ++} ++EXPORT_SYMBOL(qman_enqueue); ++ ++int qman_p_enqueue_orp(struct qman_portal *p, struct qman_fq *fq, ++ const struct qm_fd *fd, u32 flags, ++ struct qman_fq *orp, u16 orp_seqnum) ++{ ++ struct qm_eqcr_entry *eq; ++ unsigned long irqflags __maybe_unused; ++ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++ if (flags & QMAN_ENQUEUE_FLAG_WAIT) ++ eq = wait_p_eq_start(p, &irqflags, fq, fd, flags); ++ else ++#endif ++ eq = try_p_eq_start(p, &irqflags, fq, fd, flags); ++ if (!eq) ++ return -EBUSY; ++ /* Process ORP-specifics here */ ++ if (flags & QMAN_ENQUEUE_FLAG_NLIS) ++ orp_seqnum |= QM_EQCR_SEQNUM_NLIS; ++ else { ++ orp_seqnum &= ~QM_EQCR_SEQNUM_NLIS; ++ if (flags & QMAN_ENQUEUE_FLAG_NESN) ++ orp_seqnum |= QM_EQCR_SEQNUM_NESN; ++ else ++ /* No need to check 4 QMAN_ENQUEUE_FLAG_HOLE */ ++ orp_seqnum &= ~QM_EQCR_SEQNUM_NESN; ++ } ++ eq->seqnum = cpu_to_be16(orp_seqnum); ++ eq->orp = cpu_to_be32(orp->fqid); ++ /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */ ++ qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_ORP | ++ ((flags & (QMAN_ENQUEUE_FLAG_HOLE | QMAN_ENQUEUE_FLAG_NESN)) ? ++ 0 : QM_EQCR_VERB_CMD_ENQUEUE) | ++ (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT))); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) && ++ (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) { ++ if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT) ++ /* NB: return success even if signal occurs before ++ * condition is true. pvb_commit guarantees success */ ++ wait_event_interruptible(affine_queue, ++ (p->eqci_owned != fq)); ++ else ++ wait_event(affine_queue, (p->eqci_owned != fq)); ++ } ++#endif ++ return 0; ++} ++EXPORT_SYMBOL(qman_p_enqueue_orp); ++ ++int qman_enqueue_orp(struct qman_fq *fq, const struct qm_fd *fd, u32 flags, ++ struct qman_fq *orp, u16 orp_seqnum) ++{ ++ struct qman_portal *p; ++ struct qm_eqcr_entry *eq; ++ unsigned long irqflags __maybe_unused; ++ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++ if (flags & QMAN_ENQUEUE_FLAG_WAIT) ++ eq = wait_eq_start(&p, &irqflags, fq, fd, flags); ++ else ++#endif ++ eq = try_eq_start(&p, &irqflags, fq, fd, flags); ++ if (!eq) ++ return -EBUSY; ++ /* Process ORP-specifics here */ ++ if (flags & QMAN_ENQUEUE_FLAG_NLIS) ++ orp_seqnum |= QM_EQCR_SEQNUM_NLIS; ++ else { ++ orp_seqnum &= ~QM_EQCR_SEQNUM_NLIS; ++ if (flags & QMAN_ENQUEUE_FLAG_NESN) ++ orp_seqnum |= QM_EQCR_SEQNUM_NESN; ++ else ++ /* No need to check 4 QMAN_ENQUEUE_FLAG_HOLE */ ++ orp_seqnum &= ~QM_EQCR_SEQNUM_NESN; ++ } ++ eq->seqnum = cpu_to_be16(orp_seqnum); ++ eq->orp = cpu_to_be32(orp->fqid); ++ /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */ ++ qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_ORP | ++ ((flags & (QMAN_ENQUEUE_FLAG_HOLE | QMAN_ENQUEUE_FLAG_NESN)) ? ++ 0 : QM_EQCR_VERB_CMD_ENQUEUE) | ++ (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT))); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) && ++ (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) { ++ if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT) ++ /* NB: return success even if signal occurs before ++ * condition is true. pvb_commit guarantees success */ ++ wait_event_interruptible(affine_queue, ++ (p->eqci_owned != fq)); ++ else ++ wait_event(affine_queue, (p->eqci_owned != fq)); ++ } ++#endif ++ return 0; ++} ++EXPORT_SYMBOL(qman_enqueue_orp); ++ ++int qman_p_enqueue_precommit(struct qman_portal *p, struct qman_fq *fq, ++ const struct qm_fd *fd, u32 flags, ++ qman_cb_precommit cb, void *cb_arg) ++{ ++ struct qm_eqcr_entry *eq; ++ unsigned long irqflags __maybe_unused; ++ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++ if (flags & QMAN_ENQUEUE_FLAG_WAIT) ++ eq = wait_p_eq_start(p, &irqflags, fq, fd, flags); ++ else ++#endif ++ eq = try_p_eq_start(p, &irqflags, fq, fd, flags); ++ if (!eq) ++ return -EBUSY; ++ /* invoke user supplied callback function before writing commit verb */ ++ if (cb(cb_arg)) { ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ return -EINVAL; ++ } ++ /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */ ++ qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_CMD_ENQUEUE | ++ (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT))); ++ /* Factor the below out, it's used from qman_enqueue_orp() too */ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) && ++ (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) { ++ if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT) ++ /* NB: return success even if signal occurs before ++ * condition is true. pvb_commit guarantees success */ ++ wait_event_interruptible(affine_queue, ++ (p->eqci_owned != fq)); ++ else ++ wait_event(affine_queue, (p->eqci_owned != fq)); ++ } ++#endif ++ return 0; ++} ++EXPORT_SYMBOL(qman_p_enqueue_precommit); ++ ++int qman_enqueue_precommit(struct qman_fq *fq, const struct qm_fd *fd, ++ u32 flags, qman_cb_precommit cb, void *cb_arg) ++{ ++ struct qman_portal *p; ++ struct qm_eqcr_entry *eq; ++ unsigned long irqflags __maybe_unused; ++ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++ if (flags & QMAN_ENQUEUE_FLAG_WAIT) ++ eq = wait_eq_start(&p, &irqflags, fq, fd, flags); ++ else ++#endif ++ eq = try_eq_start(&p, &irqflags, fq, fd, flags); ++ if (!eq) ++ return -EBUSY; ++ /* invoke user supplied callback function before writing commit verb */ ++ if (cb(cb_arg)) { ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ return -EINVAL; ++ } ++ /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */ ++ qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_CMD_ENQUEUE | ++ (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT))); ++ /* Factor the below out, it's used from qman_enqueue_orp() too */ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++ if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) && ++ (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) { ++ if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT) ++ /* NB: return success even if signal occurs before ++ * condition is true. pvb_commit guarantees success */ ++ wait_event_interruptible(affine_queue, ++ (p->eqci_owned != fq)); ++ else ++ wait_event(affine_queue, (p->eqci_owned != fq)); ++ } ++#endif ++ return 0; ++} ++EXPORT_SYMBOL(qman_enqueue_precommit); ++ ++int qman_modify_cgr(struct qman_cgr *cgr, u32 flags, ++ struct qm_mcc_initcgr *opts) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p = get_affine_portal(); ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ u8 verb = QM_MCC_VERB_MODIFYCGR; ++ ++ PORTAL_IRQ_LOCK(p, irqflags); ++ mcc = qm_mc_start(&p->p); ++ if (opts) ++ mcc->initcgr = *opts; ++ mcc->initcgr.we_mask = cpu_to_be16(mcc->initcgr.we_mask); ++ mcc->initcgr.cgr.wr_parm_g.word = ++ cpu_to_be32(mcc->initcgr.cgr.wr_parm_g.word); ++ mcc->initcgr.cgr.wr_parm_y.word = ++ cpu_to_be32(mcc->initcgr.cgr.wr_parm_y.word); ++ mcc->initcgr.cgr.wr_parm_r.word = ++ cpu_to_be32(mcc->initcgr.cgr.wr_parm_r.word); ++ mcc->initcgr.cgr.cscn_targ = cpu_to_be32(mcc->initcgr.cgr.cscn_targ); ++ mcc->initcgr.cgr.__cs_thres = cpu_to_be16(mcc->initcgr.cgr.__cs_thres); ++ ++ mcc->initcgr.cgid = cgr->cgrid; ++ if (flags & QMAN_CGR_FLAG_USE_INIT) ++ verb = QM_MCC_VERB_INITCGR; ++ qm_mc_commit(&p->p, verb); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == verb); ++ res = mcr->result; ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ return (res == QM_MCR_RESULT_OK) ? 0 : -EIO; ++} ++EXPORT_SYMBOL(qman_modify_cgr); ++ ++#define TARG_MASK(n) (0x80000000 >> (n->config->public_cfg.channel - \ ++ QM_CHANNEL_SWPORTAL0)) ++#define TARG_DCP_MASK(n) (0x80000000 >> (10 + n)) ++#define PORTAL_IDX(n) (n->config->public_cfg.channel - QM_CHANNEL_SWPORTAL0) ++ ++static u8 qman_cgr_cpus[__CGR_NUM]; ++ ++int qman_create_cgr(struct qman_cgr *cgr, u32 flags, ++ struct qm_mcc_initcgr *opts) ++{ ++ unsigned long irqflags __maybe_unused; ++ struct qm_mcr_querycgr cgr_state; ++ struct qm_mcc_initcgr local_opts; ++ int ret; ++ struct qman_portal *p; ++ ++ /* We have to check that the provided CGRID is within the limits of the ++ * data-structures, for obvious reasons. However we'll let h/w take ++ * care of determining whether it's within the limits of what exists on ++ * the SoC. */ ++ if (cgr->cgrid >= __CGR_NUM) ++ return -EINVAL; ++ ++ preempt_disable(); ++ p = get_affine_portal(); ++ qman_cgr_cpus[cgr->cgrid] = smp_processor_id(); ++ preempt_enable(); ++ ++ memset(&local_opts, 0, sizeof(struct qm_mcc_initcgr)); ++ cgr->chan = p->config->public_cfg.channel; ++ spin_lock_irqsave(&p->cgr_lock, irqflags); ++ ++ /* if no opts specified, just add it to the list */ ++ if (!opts) ++ goto add_list; ++ ++ ret = qman_query_cgr(cgr, &cgr_state); ++ if (ret) ++ goto release_lock; ++ if (opts) ++ local_opts = *opts; ++ if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) ++ local_opts.cgr.cscn_targ_upd_ctrl = ++ QM_CGR_TARG_UDP_CTRL_WRITE_BIT | PORTAL_IDX(p); ++ else ++ /* Overwrite TARG */ ++ local_opts.cgr.cscn_targ = cgr_state.cgr.cscn_targ | ++ TARG_MASK(p); ++ local_opts.we_mask |= QM_CGR_WE_CSCN_TARG; ++ ++ /* send init if flags indicate so */ ++ if (opts && (flags & QMAN_CGR_FLAG_USE_INIT)) ++ ret = qman_modify_cgr(cgr, QMAN_CGR_FLAG_USE_INIT, &local_opts); ++ else ++ ret = qman_modify_cgr(cgr, 0, &local_opts); ++ if (ret) ++ goto release_lock; ++add_list: ++ list_add(&cgr->node, &p->cgr_cbs); ++ ++ /* Determine if newly added object requires its callback to be called */ ++ ret = qman_query_cgr(cgr, &cgr_state); ++ if (ret) { ++ /* we can't go back, so proceed and return success, but screen ++ * and wail to the log file */ ++ pr_crit("CGR HW state partially modified\n"); ++ ret = 0; ++ goto release_lock; ++ } ++ if (cgr->cb && cgr_state.cgr.cscn_en && qman_cgrs_get(&p->cgrs[1], ++ cgr->cgrid)) ++ cgr->cb(p, cgr, 1); ++release_lock: ++ spin_unlock_irqrestore(&p->cgr_lock, irqflags); ++ put_affine_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(qman_create_cgr); ++ ++int qman_create_cgr_to_dcp(struct qman_cgr *cgr, u32 flags, u16 dcp_portal, ++ struct qm_mcc_initcgr *opts) ++{ ++ unsigned long irqflags __maybe_unused; ++ struct qm_mcc_initcgr local_opts; ++ struct qm_mcr_querycgr cgr_state; ++ int ret; ++ ++ if ((qman_ip_rev & 0xFF00) < QMAN_REV30) { ++ pr_warn("This QMan version doesn't support to send CSCN to DCP portal\n"); ++ return -EINVAL; ++ } ++ /* We have to check that the provided CGRID is within the limits of the ++ * data-structures, for obvious reasons. However we'll let h/w take ++ * care of determining whether it's within the limits of what exists on ++ * the SoC. ++ */ ++ if (cgr->cgrid >= __CGR_NUM) ++ return -EINVAL; ++ ++ ret = qman_query_cgr(cgr, &cgr_state); ++ if (ret) ++ return ret; ++ ++ memset(&local_opts, 0, sizeof(struct qm_mcc_initcgr)); ++ if (opts) ++ local_opts = *opts; ++ ++ if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) ++ local_opts.cgr.cscn_targ_upd_ctrl = ++ QM_CGR_TARG_UDP_CTRL_WRITE_BIT | ++ QM_CGR_TARG_UDP_CTRL_DCP | dcp_portal; ++ else ++ local_opts.cgr.cscn_targ = cgr_state.cgr.cscn_targ | ++ TARG_DCP_MASK(dcp_portal); ++ local_opts.we_mask |= QM_CGR_WE_CSCN_TARG; ++ ++ /* send init if flags indicate so */ ++ if (opts && (flags & QMAN_CGR_FLAG_USE_INIT)) ++ ret = qman_modify_cgr(cgr, QMAN_CGR_FLAG_USE_INIT, ++ &local_opts); ++ else ++ ret = qman_modify_cgr(cgr, 0, &local_opts); ++ ++ return ret; ++} ++EXPORT_SYMBOL(qman_create_cgr_to_dcp); ++ ++int qman_delete_cgr(struct qman_cgr *cgr) ++{ ++ unsigned long irqflags __maybe_unused; ++ struct qm_mcr_querycgr cgr_state; ++ struct qm_mcc_initcgr local_opts; ++ int ret = 0; ++ struct qman_cgr *i; ++ struct qman_portal *p = get_affine_portal(); ++ ++ if (cgr->chan != p->config->public_cfg.channel) { ++ pr_crit("Attempting to delete cgr from different portal " ++ "than it was create: create 0x%x, delete 0x%x\n", ++ cgr->chan, p->config->public_cfg.channel); ++ ret = -EINVAL; ++ goto put_portal; ++ } ++ memset(&local_opts, 0, sizeof(struct qm_mcc_initcgr)); ++ spin_lock_irqsave(&p->cgr_lock, irqflags); ++ list_del(&cgr->node); ++ /* ++ * If there are no other CGR objects for this CGRID in the list, update ++ * CSCN_TARG accordingly ++ */ ++ list_for_each_entry(i, &p->cgr_cbs, node) ++ if ((i->cgrid == cgr->cgrid) && i->cb) ++ goto release_lock; ++ ret = qman_query_cgr(cgr, &cgr_state); ++ if (ret) { ++ /* add back to the list */ ++ list_add(&cgr->node, &p->cgr_cbs); ++ goto release_lock; ++ } ++ /* Overwrite TARG */ ++ local_opts.we_mask = QM_CGR_WE_CSCN_TARG; ++ if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) ++ local_opts.cgr.cscn_targ_upd_ctrl = PORTAL_IDX(p); ++ else ++ local_opts.cgr.cscn_targ = cgr_state.cgr.cscn_targ & ++ ~(TARG_MASK(p)); ++ ret = qman_modify_cgr(cgr, 0, &local_opts); ++ if (ret) ++ /* add back to the list */ ++ list_add(&cgr->node, &p->cgr_cbs); ++release_lock: ++ spin_unlock_irqrestore(&p->cgr_lock, irqflags); ++put_portal: ++ put_affine_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(qman_delete_cgr); ++ ++struct cgr_comp { ++ struct qman_cgr *cgr; ++ struct completion completion; ++}; ++ ++static int qman_delete_cgr_thread(void *p) ++{ ++ struct cgr_comp *cgr_comp = (struct cgr_comp *)p; ++ int res; ++ ++ res = qman_delete_cgr((struct qman_cgr *)cgr_comp->cgr); ++ complete(&cgr_comp->completion); ++ ++ return res; ++} ++ ++void qman_delete_cgr_safe(struct qman_cgr *cgr) ++{ ++ struct task_struct *thread; ++ struct cgr_comp cgr_comp; ++ ++ preempt_disable(); ++ if (qman_cgr_cpus[cgr->cgrid] != smp_processor_id()) { ++ init_completion(&cgr_comp.completion); ++ cgr_comp.cgr = cgr; ++ thread = kthread_create(qman_delete_cgr_thread, &cgr_comp, ++ "cgr_del"); ++ ++ if (likely(!IS_ERR(thread))) { ++ kthread_bind(thread, qman_cgr_cpus[cgr->cgrid]); ++ wake_up_process(thread); ++ wait_for_completion(&cgr_comp.completion); ++ preempt_enable(); ++ return; ++ } ++ } ++ qman_delete_cgr(cgr); ++ preempt_enable(); ++} ++EXPORT_SYMBOL(qman_delete_cgr_safe); ++ ++int qm_get_clock(u64 *clock_hz) ++{ ++ if (!qman_clk) { ++ pr_warn("Qman clock speed is unknown\n"); ++ return -EINVAL; ++ } ++ *clock_hz = (u64)qman_clk; ++ return 0; ++} ++EXPORT_SYMBOL(qm_get_clock); ++ ++int qm_set_clock(u64 clock_hz) ++{ ++ if (qman_clk) ++ return -1; ++ qman_clk = (u32)clock_hz; ++ return 0; ++} ++EXPORT_SYMBOL(qm_set_clock); ++ ++/* CEETM management command */ ++static int qman_ceetm_configure_lfqmt(struct qm_mcc_ceetm_lfqmt_config *opts) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ++ mcc = qm_mc_start(&p->p); ++ mcc->lfqmt_config = *opts; ++ qm_mc_commit(&p->p, QM_CEETM_VERB_LFQMT_CONFIG); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == ++ QM_CEETM_VERB_LFQMT_CONFIG); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ ++ res = mcr->result; ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("CEETM: CONFIGURE LFQMT failed\n"); ++ return -EIO; ++ } ++ return 0; ++} ++ ++int qman_ceetm_query_lfqmt(int lfqid, ++ struct qm_mcr_ceetm_lfqmt_query *lfqmt_query) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ++ mcc = qm_mc_start(&p->p); ++ mcc->lfqmt_query.lfqid = lfqid; ++ qm_mc_commit(&p->p, QM_CEETM_VERB_LFQMT_QUERY); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_LFQMT_QUERY); ++ res = mcr->result; ++ if (res == QM_MCR_RESULT_OK) ++ *lfqmt_query = mcr->lfqmt_query; ++ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("CEETM: QUERY LFQMT failed\n"); ++ return -EIO; ++ } ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_query_lfqmt); ++ ++static int qman_ceetm_configure_cq(struct qm_mcc_ceetm_cq_config *opts) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ++ mcc = qm_mc_start(&p->p); ++ mcc->cq_config = *opts; ++ qm_mc_commit(&p->p, QM_CEETM_VERB_CQ_CONFIG); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ res = mcr->result; ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_CQ_CONFIG); ++ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("CEETM: CONFIGURE CQ failed\n"); ++ return -EIO; ++ } ++ return 0; ++} ++ ++int qman_ceetm_query_cq(unsigned int cqid, unsigned int dcpid, ++ struct qm_mcr_ceetm_cq_query *cq_query) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ++ mcc = qm_mc_start(&p->p); ++ mcc->cq_query.cqid = cpu_to_be16(cqid); ++ mcc->cq_query.dcpid = dcpid; ++ qm_mc_commit(&p->p, QM_CEETM_VERB_CQ_QUERY); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_CQ_QUERY); ++ res = mcr->result; ++ if (res == QM_MCR_RESULT_OK) { ++ *cq_query = mcr->cq_query; ++ hw_cq_query_to_cpu(cq_query); ++ } ++ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("CEETM: QUERY CQ failed\n"); ++ return -EIO; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_query_cq); ++ ++static int qman_ceetm_configure_dct(struct qm_mcc_ceetm_dct_config *opts) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ++ mcc = qm_mc_start(&p->p); ++ mcc->dct_config = *opts; ++ qm_mc_commit(&p->p, QM_CEETM_VERB_DCT_CONFIG); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_DCT_CONFIG); ++ res = mcr->result; ++ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("CEETM: CONFIGURE DCT failed\n"); ++ return -EIO; ++ } ++ return 0; ++} ++ ++static int qman_ceetm_query_dct(struct qm_mcc_ceetm_dct_query *opts, ++ struct qm_mcr_ceetm_dct_query *dct_query) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p = get_affine_portal(); ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ++ mcc = qm_mc_start(&p->p); ++ mcc->dct_query = *opts; ++ qm_mc_commit(&p->p, QM_CEETM_VERB_DCT_QUERY); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_DCT_QUERY); ++ res = mcr->result; ++ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("CEETM: QUERY DCT failed\n"); ++ return -EIO; ++ } ++ ++ *dct_query = mcr->dct_query; ++ return 0; ++} ++ ++static int qman_ceetm_configure_class_scheduler( ++ struct qm_mcc_ceetm_class_scheduler_config *opts) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ++ mcc = qm_mc_start(&p->p); ++ mcc->csch_config = *opts; ++ qm_mc_commit(&p->p, QM_CEETM_VERB_CLASS_SCHEDULER_CONFIG); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == ++ QM_CEETM_VERB_CLASS_SCHEDULER_CONFIG); ++ res = mcr->result; ++ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("CEETM: CONFIGURE CLASS SCHEDULER failed\n"); ++ return -EIO; ++ } ++ return 0; ++} ++ ++static int qman_ceetm_query_class_scheduler(struct qm_ceetm_channel *channel, ++ struct qm_mcr_ceetm_class_scheduler_query *query) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ++ mcc = qm_mc_start(&p->p); ++ mcc->csch_query.cqcid = cpu_to_be16(channel->idx); ++ mcc->csch_query.dcpid = channel->dcp_idx; ++ qm_mc_commit(&p->p, QM_CEETM_VERB_CLASS_SCHEDULER_QUERY); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == ++ QM_CEETM_VERB_CLASS_SCHEDULER_QUERY); ++ res = mcr->result; ++ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("CEETM: QUERY CLASS SCHEDULER failed\n"); ++ return -EIO; ++ } ++ *query = mcr->csch_query; ++ return 0; ++} ++ ++static int qman_ceetm_configure_mapping_shaper_tcfc( ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_config *opts) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ++ mcc = qm_mc_start(&p->p); ++ mcc->mst_config = *opts; ++ qm_mc_commit(&p->p, QM_CEETM_VERB_MAPPING_SHAPER_TCFC_CONFIG); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == ++ QM_CEETM_VERB_MAPPING_SHAPER_TCFC_CONFIG); ++ res = mcr->result; ++ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("CEETM: CONFIGURE CHANNEL MAPPING failed\n"); ++ return -EIO; ++ } ++ return 0; ++} ++ ++static int qman_ceetm_query_mapping_shaper_tcfc( ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_query *opts, ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_query *response) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ++ mcc = qm_mc_start(&p->p); ++ mcc->mst_query = *opts; ++ qm_mc_commit(&p->p, QM_CEETM_VERB_MAPPING_SHAPER_TCFC_QUERY); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == ++ QM_CEETM_VERB_MAPPING_SHAPER_TCFC_QUERY); ++ res = mcr->result; ++ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("CEETM: QUERY CHANNEL MAPPING failed\n"); ++ return -EIO; ++ } ++ ++ *response = mcr->mst_query; ++ return 0; ++} ++ ++static int qman_ceetm_configure_ccgr(struct qm_mcc_ceetm_ccgr_config *opts) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ++ mcc = qm_mc_start(&p->p); ++ mcc->ccgr_config = *opts; ++ ++ qm_mc_commit(&p->p, QM_CEETM_VERB_CCGR_CONFIG); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_CCGR_CONFIG); ++ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ ++ res = mcr->result; ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("CEETM: CONFIGURE CCGR failed\n"); ++ return -EIO; ++ } ++ return 0; ++} ++ ++int qman_ceetm_query_ccgr(struct qm_mcc_ceetm_ccgr_query *ccgr_query, ++ struct qm_mcr_ceetm_ccgr_query *response) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ++ mcc = qm_mc_start(&p->p); ++ mcc->ccgr_query.ccgrid = cpu_to_be16(ccgr_query->ccgrid); ++ mcc->ccgr_query.dcpid = ccgr_query->dcpid; ++ qm_mc_commit(&p->p, QM_CEETM_VERB_CCGR_QUERY); ++ ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_CCGR_QUERY); ++ res = mcr->result; ++ if (res == QM_MCR_RESULT_OK) { ++ *response = mcr->ccgr_query; ++ hw_ccgr_query_to_cpu(response); ++ } ++ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("CEETM: QUERY CCGR failed\n"); ++ return -EIO; ++ } ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_query_ccgr); ++ ++static int qman_ceetm_cq_peek_pop_xsfdrread(struct qm_ceetm_cq *cq, ++ u8 command_type, u16 xsfdr, ++ struct qm_mcr_ceetm_cq_peek_pop_xsfdrread *cq_ppxr) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ++ mcc = qm_mc_start(&p->p); ++ switch (command_type) { ++ case 0: ++ case 1: ++ mcc->cq_ppxr.cqid = (cq->parent->idx << 4) | cq->idx; ++ break; ++ case 2: ++ mcc->cq_ppxr.xsfdr = xsfdr; ++ break; ++ default: ++ break; ++ } ++ mcc->cq_ppxr.ct = command_type; ++ mcc->cq_ppxr.dcpid = cq->parent->dcp_idx; ++ qm_mc_commit(&p->p, QM_CEETM_VERB_CQ_PEEK_POP_XFDRREAD); ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == ++ QM_CEETM_VERB_CQ_PEEK_POP_XFDRREAD); ++ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ ++ res = mcr->result; ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("CEETM: CQ PEEK/POP/XSFDR READ failed\n"); ++ return -EIO; ++ } ++ *cq_ppxr = mcr->cq_ppxr; ++ return 0; ++} ++ ++static int qman_ceetm_query_statistics(u16 cid, ++ enum qm_dc_portal dcp_idx, ++ u16 command_type, ++ struct qm_mcr_ceetm_statistics_query *query_result) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ++ mcc = qm_mc_start(&p->p); ++ mcc->stats_query_write.cid = cid; ++ mcc->stats_query_write.dcpid = dcp_idx; ++ mcc->stats_query_write.ct = command_type; ++ qm_mc_commit(&p->p, QM_CEETM_VERB_STATISTICS_QUERY_WRITE); ++ ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == ++ QM_CEETM_VERB_STATISTICS_QUERY_WRITE); ++ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ ++ res = mcr->result; ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("CEETM: STATISTICS QUERY failed\n"); ++ return -EIO; ++ } ++ *query_result = mcr->stats_query; ++ return 0; ++} ++ ++int qman_ceetm_query_write_statistics(u16 cid, enum qm_dc_portal dcp_idx, ++ u16 command_type, u64 frame_count, ++ u64 byte_count) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ++ mcc = qm_mc_start(&p->p); ++ mcc->stats_query_write.cid = cid; ++ mcc->stats_query_write.dcpid = dcp_idx; ++ mcc->stats_query_write.ct = command_type; ++ mcc->stats_query_write.frm_cnt = frame_count; ++ mcc->stats_query_write.byte_cnt = byte_count; ++ qm_mc_commit(&p->p, QM_CEETM_VERB_STATISTICS_QUERY_WRITE); ++ ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == ++ QM_CEETM_VERB_STATISTICS_QUERY_WRITE); ++ ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ ++ res = mcr->result; ++ if (res != QM_MCR_RESULT_OK) { ++ pr_err("CEETM: STATISTICS WRITE failed\n"); ++ return -EIO; ++ } ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_query_write_statistics); ++ ++int qman_ceetm_bps2tokenrate(u64 bps, struct qm_ceetm_rate *token_rate, ++ int rounding) ++{ ++ u16 pres; ++ u64 temp; ++ u64 qman_freq; ++ int ret; ++ ++ /* Read PRES from CEET_CFG_PRES register */ ++ ret = qman_ceetm_get_prescaler(&pres); ++ if (ret) ++ return -EINVAL; ++ ++ ret = qm_get_clock(&qman_freq); ++ if (ret) ++ return -EINVAL; ++ ++ /* token-rate = bytes-per-second * update-reference-period ++ * ++ * Where token-rate is N/8192 for a integer N, and ++ * update-reference-period is (2^22)/(PRES*QHz), where PRES ++ * is the prescalar value and QHz is the QMan clock frequency. ++ * So: ++ * ++ * token-rate = (byte-per-second*2^22)/PRES*QHZ) ++ * ++ * Converting to bits-per-second gives; ++ * ++ * token-rate = (bps*2^19) / (PRES*QHZ) ++ * N = (bps*2^32) / (PRES*QHz) ++ * ++ * And to avoid 64-bit overflow if 'bps' is larger than 4Gbps ++ * (yet minimise rounding error if 'bps' is small), we reorganise ++ * the formula to use two 16-bit shifts rather than 1 32-bit shift. ++ * N = (((bps*2^16)/PRES)*2^16)/QHz ++ */ ++ temp = ROUNDING((bps << 16), pres, rounding); ++ temp = ROUNDING((temp << 16), qman_freq, rounding); ++ token_rate->whole = temp >> 13; ++ token_rate->fraction = temp & (((u64)1 << 13) - 1); ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_bps2tokenrate); ++ ++int qman_ceetm_tokenrate2bps(const struct qm_ceetm_rate *token_rate, u64 *bps, ++ int rounding) ++{ ++ u16 pres; ++ u64 temp; ++ u64 qman_freq; ++ int ret; ++ ++ /* Read PRES from CEET_CFG_PRES register */ ++ ret = qman_ceetm_get_prescaler(&pres); ++ if (ret) ++ return -EINVAL; ++ ++ ret = qm_get_clock(&qman_freq); ++ if (ret) ++ return -EINVAL; ++ ++ /* bytes-per-second = token-rate / update-reference-period ++ * ++ * where "token-rate" is N/8192 for an integer N, and ++ * "update-reference-period" is (2^22)/(PRES*QHz), where PRES is ++ * the prescalar value and QHz is the QMan clock frequency. So; ++ * ++ * bytes-per-second = (N/8192) / (4194304/PRES*QHz) ++ * = N*PRES*QHz / (4194304*8192) ++ * = N*PRES*QHz / (2^35) ++ * ++ * Converting to bits-per-second gives; ++ * ++ * bps = N*PRES*QHZ / (2^32) ++ * ++ * Note, the numerator has a maximum width of 72 bits! So to ++ * avoid 64-bit overflow errors, we calculate PRES*QHZ (maximum ++ * width 48 bits) divided by 2^9 (reducing to maximum 39 bits), before ++ * multiplying by N (goes to maximum of 63 bits). ++ * ++ * temp = PRES*QHZ / (2^16) ++ * kbps = temp*N / (2^16) ++ */ ++ temp = ROUNDING(qman_freq * pres, (u64)1 << 16 , rounding); ++ temp *= ((token_rate->whole << 13) + token_rate->fraction); ++ *bps = ROUNDING(temp, (u64)(1) << 16, rounding); ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_tokenrate2bps); ++ ++int qman_ceetm_sp_claim(struct qm_ceetm_sp **sp, enum qm_dc_portal dcp_idx, ++ unsigned int sp_idx) ++{ ++ struct qm_ceetm_sp *p; ++ ++ DPA_ASSERT((dcp_idx == qm_dc_portal_fman0) || ++ (dcp_idx == qm_dc_portal_fman1)); ++ ++ if ((sp_idx < qman_ceetms[dcp_idx].sp_range[0]) || ++ (sp_idx >= (qman_ceetms[dcp_idx].sp_range[0] + ++ qman_ceetms[dcp_idx].sp_range[1]))) { ++ pr_err("Sub-portal index doesn't exist\n"); ++ return -EINVAL; ++ } ++ ++ list_for_each_entry(p, &qman_ceetms[dcp_idx].sub_portals, node) { ++ if ((p->idx == sp_idx) && (p->is_claimed == 0)) { ++ p->is_claimed = 1; ++ *sp = p; ++ return 0; ++ } ++ } ++ pr_err("The sub-portal#%d is not available!\n", sp_idx); ++ return -ENODEV; ++} ++EXPORT_SYMBOL(qman_ceetm_sp_claim); ++ ++int qman_ceetm_sp_release(struct qm_ceetm_sp *sp) ++{ ++ struct qm_ceetm_sp *p; ++ ++ if (sp->lni && sp->lni->is_claimed == 1) { ++ pr_err("The dependency of sub-portal has not been released!\n"); ++ return -EBUSY; ++ } ++ ++ list_for_each_entry(p, &qman_ceetms[sp->dcp_idx].sub_portals, node) { ++ if (p->idx == sp->idx) { ++ p->is_claimed = 0; ++ p->lni = NULL; ++ } ++ } ++ /* Disable CEETM mode of this sub-portal */ ++ qman_sp_disable_ceetm_mode(sp->dcp_idx, sp->idx); ++ ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_sp_release); ++ ++int qman_ceetm_lni_claim(struct qm_ceetm_lni **lni, enum qm_dc_portal dcp_idx, ++ unsigned int lni_idx) ++{ ++ struct qm_ceetm_lni *p; ++ ++ if ((lni_idx < qman_ceetms[dcp_idx].lni_range[0]) || ++ (lni_idx >= (qman_ceetms[dcp_idx].lni_range[0] + ++ qman_ceetms[dcp_idx].lni_range[1]))) { ++ pr_err("The lni index is out of range\n"); ++ return -EINVAL; ++ } ++ ++ list_for_each_entry(p, &qman_ceetms[dcp_idx].lnis, node) { ++ if ((p->idx == lni_idx) && (p->is_claimed == 0)) { ++ *lni = p; ++ p->is_claimed = 1; ++ return 0; ++ } ++ } ++ ++ pr_err("The LNI#%d is not available!\n", lni_idx); ++ return -EINVAL; ++} ++EXPORT_SYMBOL(qman_ceetm_lni_claim); ++ ++int qman_ceetm_lni_release(struct qm_ceetm_lni *lni) ++{ ++ struct qm_ceetm_lni *p; ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts; ++ ++ if (!list_empty(&lni->channels)) { ++ pr_err("The LNI dependencies are not released!\n"); ++ return -EBUSY; ++ } ++ ++ list_for_each_entry(p, &qman_ceetms[lni->dcp_idx].lnis, node) { ++ if (p->idx == lni->idx) { ++ p->shaper_enable = 0; ++ p->shaper_couple = 0; ++ p->cr_token_rate.whole = 0; ++ p->cr_token_rate.fraction = 0; ++ p->er_token_rate.whole = 0; ++ p->er_token_rate.fraction = 0; ++ p->cr_token_bucket_limit = 0; ++ p->er_token_bucket_limit = 0; ++ p->is_claimed = 0; ++ } ++ } ++ config_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx); ++ config_opts.dcpid = lni->dcp_idx; ++ memset(&config_opts.shaper_config, 0, ++ sizeof(config_opts.shaper_config)); ++ return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts); ++} ++EXPORT_SYMBOL(qman_ceetm_lni_release); ++ ++int qman_ceetm_sp_set_lni(struct qm_ceetm_sp *sp, struct qm_ceetm_lni *lni) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts; ++ ++ config_opts.cid = cpu_to_be16(CEETM_COMMAND_SP_MAPPING | sp->idx); ++ config_opts.dcpid = sp->dcp_idx; ++ config_opts.sp_mapping.map_lni_id = lni->idx; ++ sp->lni = lni; ++ ++ if (qman_ceetm_configure_mapping_shaper_tcfc(&config_opts)) ++ return -EINVAL; ++ ++ /* Enable CEETM mode for this sub-portal */ ++ return qman_sp_enable_ceetm_mode(sp->dcp_idx, sp->idx); ++} ++EXPORT_SYMBOL(qman_ceetm_sp_set_lni); ++ ++int qman_ceetm_sp_get_lni(struct qm_ceetm_sp *sp, unsigned int *lni_idx) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts; ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result; ++ ++ query_opts.cid = cpu_to_be16(CEETM_COMMAND_SP_MAPPING | sp->idx); ++ query_opts.dcpid = sp->dcp_idx; ++ if (qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result)) { ++ pr_err("Can't get SP <-> LNI mapping\n"); ++ return -EINVAL; ++ } ++ *lni_idx = query_result.sp_mapping_query.map_lni_id; ++ sp->lni->idx = query_result.sp_mapping_query.map_lni_id; ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_sp_get_lni); ++ ++int qman_ceetm_lni_enable_shaper(struct qm_ceetm_lni *lni, int coupled, ++ int oal) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts; ++ ++ if (lni->shaper_enable) { ++ pr_err("The shaper has already been enabled\n"); ++ return -EINVAL; ++ } ++ lni->shaper_enable = 1; ++ lni->shaper_couple = coupled; ++ lni->oal = oal; ++ ++ config_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx); ++ config_opts.dcpid = lni->dcp_idx; ++ config_opts.shaper_config.cpl = coupled; ++ config_opts.shaper_config.oal = oal; ++ config_opts.shaper_config.crtcr = cpu_to_be24((lni->cr_token_rate.whole ++ << 13) | lni->cr_token_rate.fraction); ++ config_opts.shaper_config.ertcr = cpu_to_be24((lni->er_token_rate.whole ++ << 13) | lni->er_token_rate.fraction); ++ config_opts.shaper_config.crtbl = ++ cpu_to_be16(lni->cr_token_bucket_limit); ++ config_opts.shaper_config.ertbl = ++ cpu_to_be16(lni->er_token_bucket_limit); ++ config_opts.shaper_config.mps = 60; ++ ++ return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts); ++} ++EXPORT_SYMBOL(qman_ceetm_lni_enable_shaper); ++ ++int qman_ceetm_lni_disable_shaper(struct qm_ceetm_lni *lni) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts; ++ ++ if (!lni->shaper_enable) { ++ pr_err("The shaper has been disabled\n"); ++ return -EINVAL; ++ } ++ ++ config_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx); ++ config_opts.dcpid = lni->dcp_idx; ++ config_opts.shaper_config.cpl = lni->shaper_couple; ++ config_opts.shaper_config.oal = lni->oal; ++ config_opts.shaper_config.crtbl = ++ cpu_to_be16(lni->cr_token_bucket_limit); ++ config_opts.shaper_config.ertbl = ++ cpu_to_be16(lni->er_token_bucket_limit); ++ /* Set CR/ER rate with all 1's to configure an infinite rate, thus ++ * disable the shaping. ++ */ ++ config_opts.shaper_config.crtcr = 0xFFFFFF; ++ config_opts.shaper_config.ertcr = 0xFFFFFF; ++ config_opts.shaper_config.mps = 60; ++ lni->shaper_enable = 0; ++ return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts); ++} ++EXPORT_SYMBOL(qman_ceetm_lni_disable_shaper); ++ ++int qman_ceetm_lni_is_shaper_enabled(struct qm_ceetm_lni *lni) ++{ ++ return lni->shaper_enable; ++} ++EXPORT_SYMBOL(qman_ceetm_lni_is_shaper_enabled); ++ ++int qman_ceetm_lni_set_commit_rate(struct qm_ceetm_lni *lni, ++ const struct qm_ceetm_rate *token_rate, ++ u16 token_limit) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts; ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts; ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result; ++ int ret; ++ ++ lni->cr_token_rate.whole = token_rate->whole; ++ lni->cr_token_rate.fraction = token_rate->fraction; ++ lni->cr_token_bucket_limit = token_limit; ++ if (!lni->shaper_enable) ++ return 0; ++ query_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx); ++ query_opts.dcpid = lni->dcp_idx; ++ ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, ++ &query_result); ++ if (ret) { ++ pr_err("Fail to get current LNI shaper setting\n"); ++ return -EINVAL; ++ } ++ ++ config_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx); ++ config_opts.dcpid = lni->dcp_idx; ++ config_opts.shaper_config.crtcr = cpu_to_be24((token_rate->whole << 13) ++ | (token_rate->fraction)); ++ config_opts.shaper_config.crtbl = cpu_to_be16(token_limit); ++ config_opts.shaper_config.cpl = query_result.shaper_query.cpl; ++ config_opts.shaper_config.oal = query_result.shaper_query.oal; ++ config_opts.shaper_config.ertcr = query_result.shaper_query.ertcr; ++ config_opts.shaper_config.ertbl = query_result.shaper_query.ertbl; ++ config_opts.shaper_config.mps = query_result.shaper_query.mps; ++ return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts); ++} ++EXPORT_SYMBOL(qman_ceetm_lni_set_commit_rate); ++ ++int qman_ceetm_lni_set_commit_rate_bps(struct qm_ceetm_lni *lni, ++ u64 bps, ++ u16 token_limit) ++{ ++ struct qm_ceetm_rate token_rate; ++ int ret; ++ ++ ret = qman_ceetm_bps2tokenrate(bps, &token_rate, 0); ++ if (ret) { ++ pr_err("Can not convert bps to token rate\n"); ++ return -EINVAL; ++ } ++ ++ return qman_ceetm_lni_set_commit_rate(lni, &token_rate, token_limit); ++} ++EXPORT_SYMBOL(qman_ceetm_lni_set_commit_rate_bps); ++ ++int qman_ceetm_lni_get_commit_rate(struct qm_ceetm_lni *lni, ++ struct qm_ceetm_rate *token_rate, ++ u16 *token_limit) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts; ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result; ++ int ret; ++ ++ query_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx); ++ query_opts.dcpid = lni->dcp_idx; ++ ++ ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result); ++ if (ret) { ++ pr_err("The LNI CR rate or limit is not set\n"); ++ return -EINVAL; ++ } ++ token_rate->whole = be24_to_cpu(query_result.shaper_query.crtcr) >> 13; ++ token_rate->fraction = be24_to_cpu(query_result.shaper_query.crtcr) & ++ 0x1FFF; ++ *token_limit = be16_to_cpu(query_result.shaper_query.crtbl); ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_lni_get_commit_rate); ++ ++int qman_ceetm_lni_get_commit_rate_bps(struct qm_ceetm_lni *lni, ++ u64 *bps, u16 *token_limit) ++{ ++ struct qm_ceetm_rate token_rate; ++ int ret; ++ ++ ret = qman_ceetm_lni_get_commit_rate(lni, &token_rate, token_limit); ++ if (ret) { ++ pr_err("The LNI CR rate or limit is not available\n"); ++ return -EINVAL; ++ } ++ ++ return qman_ceetm_tokenrate2bps(&token_rate, bps, 0); ++} ++EXPORT_SYMBOL(qman_ceetm_lni_get_commit_rate_bps); ++ ++int qman_ceetm_lni_set_excess_rate(struct qm_ceetm_lni *lni, ++ const struct qm_ceetm_rate *token_rate, ++ u16 token_limit) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts; ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts; ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result; ++ int ret; ++ ++ lni->er_token_rate.whole = token_rate->whole; ++ lni->er_token_rate.fraction = token_rate->fraction; ++ lni->er_token_bucket_limit = token_limit; ++ if (!lni->shaper_enable) ++ return 0; ++ ++ query_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx); ++ query_opts.dcpid = lni->dcp_idx; ++ ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, ++ &query_result); ++ if (ret) { ++ pr_err("Fail to get current LNI shaper setting\n"); ++ return -EINVAL; ++ } ++ ++ config_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx); ++ config_opts.dcpid = lni->dcp_idx; ++ config_opts.shaper_config.ertcr = cpu_to_be24( ++ (token_rate->whole << 13) | (token_rate->fraction)); ++ config_opts.shaper_config.ertbl = cpu_to_be16(token_limit); ++ config_opts.shaper_config.cpl = query_result.shaper_query.cpl; ++ config_opts.shaper_config.oal = query_result.shaper_query.oal; ++ config_opts.shaper_config.crtcr = query_result.shaper_query.crtcr; ++ config_opts.shaper_config.crtbl = query_result.shaper_query.crtbl; ++ config_opts.shaper_config.mps = query_result.shaper_query.mps; ++ return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts); ++} ++EXPORT_SYMBOL(qman_ceetm_lni_set_excess_rate); ++ ++int qman_ceetm_lni_set_excess_rate_bps(struct qm_ceetm_lni *lni, ++ u64 bps, ++ u16 token_limit) ++{ ++ struct qm_ceetm_rate token_rate; ++ int ret; ++ ++ ret = qman_ceetm_bps2tokenrate(bps, &token_rate, 0); ++ if (ret) { ++ pr_err("Can not convert bps to token rate\n"); ++ return -EINVAL; ++ } ++ return qman_ceetm_lni_set_excess_rate(lni, &token_rate, token_limit); ++} ++EXPORT_SYMBOL(qman_ceetm_lni_set_excess_rate_bps); ++ ++int qman_ceetm_lni_get_excess_rate(struct qm_ceetm_lni *lni, ++ struct qm_ceetm_rate *token_rate, ++ u16 *token_limit) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts; ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result; ++ int ret; ++ ++ query_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx); ++ query_opts.dcpid = lni->dcp_idx; ++ ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result); ++ if (ret) { ++ pr_err("The LNI ER rate or limit is not set\n"); ++ return -EINVAL; ++ } ++ token_rate->whole = be24_to_cpu(query_result.shaper_query.ertcr) >> 13; ++ token_rate->fraction = be24_to_cpu(query_result.shaper_query.ertcr) & ++ 0x1FFF; ++ *token_limit = be16_to_cpu(query_result.shaper_query.ertbl); ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_lni_get_excess_rate); ++ ++int qman_ceetm_lni_get_excess_rate_bps(struct qm_ceetm_lni *lni, ++ u64 *bps, u16 *token_limit) ++{ ++ struct qm_ceetm_rate token_rate; ++ int ret; ++ ++ ret = qman_ceetm_lni_get_excess_rate(lni, &token_rate, token_limit); ++ if (ret) { ++ pr_err("The LNI ER rate or limit is not available\n"); ++ return -EINVAL; ++ } ++ ++ return qman_ceetm_tokenrate2bps(&token_rate, bps, 0); ++} ++EXPORT_SYMBOL(qman_ceetm_lni_get_excess_rate_bps); ++ ++#define QMAN_CEETM_LNITCFCC_CQ_LEVEL_SHIFT(n) ((15 - n) * 4) ++#define QMAN_CEETM_LNITCFCC_ENABLE 0x8 ++int qman_ceetm_lni_set_tcfcc(struct qm_ceetm_lni *lni, ++ unsigned int cq_level, ++ int traffic_class) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts; ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts; ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result; ++ u64 lnitcfcc; ++ ++ if ((cq_level > 15) | (traffic_class > 7)) { ++ pr_err("The CQ or traffic class id is out of range\n"); ++ return -EINVAL; ++ } ++ ++ query_opts.cid = cpu_to_be16(CEETM_COMMAND_TCFC | lni->idx); ++ query_opts.dcpid = lni->dcp_idx; ++ if (qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result)) { ++ pr_err("Fail to query tcfcc\n"); ++ return -EINVAL; ++ } ++ ++ lnitcfcc = be64_to_cpu(query_result.tcfc_query.lnitcfcc); ++ if (traffic_class == -1) { ++ /* disable tcfc for this CQ */ ++ lnitcfcc &= ~((u64)QMAN_CEETM_LNITCFCC_ENABLE << ++ QMAN_CEETM_LNITCFCC_CQ_LEVEL_SHIFT(cq_level)); ++ } else { ++ lnitcfcc &= ~((u64)0xF << ++ QMAN_CEETM_LNITCFCC_CQ_LEVEL_SHIFT(cq_level)); ++ lnitcfcc |= ((u64)(QMAN_CEETM_LNITCFCC_ENABLE | ++ traffic_class)) << ++ QMAN_CEETM_LNITCFCC_CQ_LEVEL_SHIFT(cq_level); ++ } ++ config_opts.tcfc_config.lnitcfcc = cpu_to_be64(lnitcfcc); ++ config_opts.cid = cpu_to_be16(CEETM_COMMAND_TCFC | lni->idx); ++ config_opts.dcpid = lni->dcp_idx; ++ return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts); ++} ++EXPORT_SYMBOL(qman_ceetm_lni_set_tcfcc); ++ ++#define QMAN_CEETM_LNITCFCC_TC_MASK 0x7 ++int qman_ceetm_lni_get_tcfcc(struct qm_ceetm_lni *lni, unsigned int cq_level, ++ int *traffic_class) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts; ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result; ++ int ret; ++ u8 lnitcfcc; ++ ++ if (cq_level > 15) { ++ pr_err("the CQ level is out of range\n"); ++ return -EINVAL; ++ } ++ ++ query_opts.cid = cpu_to_be16(CEETM_COMMAND_TCFC | lni->idx); ++ query_opts.dcpid = lni->dcp_idx; ++ ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result); ++ if (ret) ++ return ret; ++ lnitcfcc = (u8)be64_to_cpu((query_result.tcfc_query.lnitcfcc) >> ++ QMAN_CEETM_LNITCFCC_CQ_LEVEL_SHIFT(cq_level)); ++ if (lnitcfcc & QMAN_CEETM_LNITCFCC_ENABLE) ++ *traffic_class = lnitcfcc & QMAN_CEETM_LNITCFCC_TC_MASK; ++ else ++ *traffic_class = -1; ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_lni_get_tcfcc); ++ ++int qman_ceetm_channel_claim(struct qm_ceetm_channel **channel, ++ struct qm_ceetm_lni *lni) ++{ ++ struct qm_ceetm_channel *p; ++ u32 channel_idx; ++ int ret = 0; ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts; ++ ++ if (lni->dcp_idx == qm_dc_portal_fman0) { ++ ret = qman_alloc_ceetm0_channel(&channel_idx); ++ } else if (lni->dcp_idx == qm_dc_portal_fman1) { ++ ret = qman_alloc_ceetm1_channel(&channel_idx); ++ } else { ++ pr_err("dcp_idx %u does not correspond to a known fman in this driver\n", ++ lni->dcp_idx); ++ return -EINVAL; ++ } ++ ++ if (ret) { ++ pr_err("The is no channel available for LNI#%d\n", lni->idx); ++ return -ENODEV; ++ } ++ ++ p = kzalloc(sizeof(*p), GFP_KERNEL); ++ if (!p) ++ return -ENOMEM; ++ p->idx = channel_idx; ++ p->dcp_idx = lni->dcp_idx; ++ p->lni_idx = lni->idx; ++ list_add_tail(&p->node, &lni->channels); ++ INIT_LIST_HEAD(&p->class_queues); ++ INIT_LIST_HEAD(&p->ccgs); ++ config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_MAPPING | ++ channel_idx); ++ config_opts.dcpid = lni->dcp_idx; ++ config_opts.channel_mapping.map_lni_id = lni->idx; ++ config_opts.channel_mapping.map_shaped = 0; ++ if (qman_ceetm_configure_mapping_shaper_tcfc(&config_opts)) { ++ pr_err("Can't map channel#%d for LNI#%d\n", ++ channel_idx, lni->idx); ++ return -EINVAL; ++ } ++ *channel = p; ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_channel_claim); ++ ++int qman_ceetm_channel_release(struct qm_ceetm_channel *channel) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts; ++ if (!list_empty(&channel->class_queues)) { ++ pr_err("CEETM channel#%d has class queue unreleased!\n", ++ channel->idx); ++ return -EBUSY; ++ } ++ if (!list_empty(&channel->ccgs)) { ++ pr_err("CEETM channel#%d has ccg unreleased!\n", ++ channel->idx); ++ return -EBUSY; ++ } ++ ++ /* channel->dcp_idx corresponds to known fman validation */ ++ if ((channel->dcp_idx != qm_dc_portal_fman0) && ++ (channel->dcp_idx != qm_dc_portal_fman1)) { ++ pr_err("dcp_idx %u does not correspond to a known fman in this driver\n", ++ channel->dcp_idx); ++ return -EINVAL; ++ } ++ ++ config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER | ++ channel->idx); ++ config_opts.dcpid = channel->dcp_idx; ++ memset(&config_opts.shaper_config, 0, ++ sizeof(config_opts.shaper_config)); ++ if (qman_ceetm_configure_mapping_shaper_tcfc(&config_opts)) { ++ pr_err("Can't reset channel shapping parameters\n"); ++ return -EINVAL; ++ } ++ ++ if (channel->dcp_idx == qm_dc_portal_fman0) { ++ qman_release_ceetm0_channelid(channel->idx); ++ } else if (channel->dcp_idx == qm_dc_portal_fman1) { ++ qman_release_ceetm1_channelid(channel->idx); ++ } else { ++ pr_err("dcp_idx %u does not correspond to a known fman in this driver\n", ++ channel->dcp_idx); ++ return -EINVAL; ++ } ++ list_del(&channel->node); ++ kfree(channel); ++ ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_channel_release); ++ ++int qman_ceetm_channel_enable_shaper(struct qm_ceetm_channel *channel, ++ int coupled) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts; ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result; ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts; ++ ++ if (channel->shaper_enable == 1) { ++ pr_err("This channel shaper has been enabled!\n"); ++ return -EINVAL; ++ } ++ ++ channel->shaper_enable = 1; ++ channel->shaper_couple = coupled; ++ ++ query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_MAPPING | ++ channel->idx); ++ query_opts.dcpid = channel->dcp_idx; ++ ++ if (qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result)) { ++ pr_err("Can't query channel mapping\n"); ++ return -EINVAL; ++ } ++ ++ config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_MAPPING | ++ channel->idx); ++ config_opts.dcpid = channel->dcp_idx; ++ config_opts.channel_mapping.map_lni_id = ++ query_result.channel_mapping_query.map_lni_id; ++ config_opts.channel_mapping.map_shaped = 1; ++ if (qman_ceetm_configure_mapping_shaper_tcfc(&config_opts)) { ++ pr_err("Can't enable shaper for channel #%d\n", channel->idx); ++ return -EINVAL; ++ } ++ ++ config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER | ++ channel->idx); ++ config_opts.shaper_config.cpl = coupled; ++ config_opts.shaper_config.crtcr = ++ cpu_to_be24((channel->cr_token_rate.whole ++ << 13) | ++ channel->cr_token_rate.fraction); ++ config_opts.shaper_config.ertcr = ++ cpu_to_be24(channel->er_token_rate.whole ++ << 13 | ++ channel->er_token_rate.fraction); ++ config_opts.shaper_config.crtbl = ++ cpu_to_be16(channel->cr_token_bucket_limit); ++ config_opts.shaper_config.ertbl = ++ cpu_to_be16(channel->er_token_bucket_limit); ++ ++ return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts); ++} ++EXPORT_SYMBOL(qman_ceetm_channel_enable_shaper); ++ ++int qman_ceetm_channel_disable_shaper(struct qm_ceetm_channel *channel) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts; ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result; ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts; ++ ++ ++ query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_MAPPING | ++ channel->idx); ++ query_opts.dcpid = channel->dcp_idx; ++ ++ if (qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result)) { ++ pr_err("Can't query channel mapping\n"); ++ return -EINVAL; ++ } ++ ++ config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_MAPPING | ++ channel->idx); ++ config_opts.dcpid = channel->dcp_idx; ++ config_opts.channel_mapping.map_shaped = 0; ++ config_opts.channel_mapping.map_lni_id = ++ query_result.channel_mapping_query.map_lni_id; ++ ++ return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts); ++} ++EXPORT_SYMBOL(qman_ceetm_channel_disable_shaper); ++ ++int qman_ceetm_channel_is_shaper_enabled(struct qm_ceetm_channel *channel) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts; ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result; ++ ++ query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_MAPPING | ++ channel->idx); ++ query_opts.dcpid = channel->dcp_idx; ++ ++ if (qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result)) { ++ pr_err("Can't query channel mapping\n"); ++ return -EINVAL; ++ } ++ ++ return query_result.channel_mapping_query.map_shaped; ++} ++EXPORT_SYMBOL(qman_ceetm_channel_is_shaper_enabled); ++ ++int qman_ceetm_channel_set_commit_rate(struct qm_ceetm_channel *channel, ++ const struct qm_ceetm_rate *token_rate, ++ u16 token_limit) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts; ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts; ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result; ++ int ret; ++ ++ query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER | ++ channel->idx); ++ query_opts.dcpid = channel->dcp_idx; ++ ++ ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result); ++ if (ret) { ++ pr_err("Fail to get the current channel shaper setting\n"); ++ return -EINVAL; ++ } ++ ++ channel->cr_token_rate.whole = token_rate->whole; ++ channel->cr_token_rate.fraction = token_rate->fraction; ++ channel->cr_token_bucket_limit = token_limit; ++ config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER | ++ channel->idx); ++ config_opts.dcpid = channel->dcp_idx; ++ config_opts.shaper_config.crtcr = cpu_to_be24((token_rate->whole ++ << 13) | (token_rate->fraction)); ++ config_opts.shaper_config.crtbl = cpu_to_be16(token_limit); ++ config_opts.shaper_config.cpl = query_result.shaper_query.cpl; ++ config_opts.shaper_config.ertcr = query_result.shaper_query.ertcr; ++ config_opts.shaper_config.ertbl = query_result.shaper_query.ertbl; ++ return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts); ++} ++EXPORT_SYMBOL(qman_ceetm_channel_set_commit_rate); ++ ++int qman_ceetm_channel_set_commit_rate_bps(struct qm_ceetm_channel *channel, ++ u64 bps, u16 token_limit) ++{ ++ struct qm_ceetm_rate token_rate; ++ int ret; ++ ++ ret = qman_ceetm_bps2tokenrate(bps, &token_rate, 0); ++ if (ret) { ++ pr_err("Can not convert bps to token rate\n"); ++ return -EINVAL; ++ } ++ return qman_ceetm_channel_set_commit_rate(channel, &token_rate, ++ token_limit); ++} ++EXPORT_SYMBOL(qman_ceetm_channel_set_commit_rate_bps); ++ ++int qman_ceetm_channel_get_commit_rate(struct qm_ceetm_channel *channel, ++ struct qm_ceetm_rate *token_rate, ++ u16 *token_limit) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts; ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result; ++ int ret; ++ ++ query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER | ++ channel->idx); ++ query_opts.dcpid = channel->dcp_idx; ++ ++ ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result); ++ if (ret | !query_result.shaper_query.crtcr | ++ !query_result.shaper_query.crtbl) { ++ pr_err("The channel commit rate or limit is not set\n"); ++ return -EINVAL; ++ } ++ token_rate->whole = be24_to_cpu(query_result.shaper_query.crtcr) >> 13; ++ token_rate->fraction = be24_to_cpu(query_result.shaper_query.crtcr) & ++ 0x1FFF; ++ *token_limit = be16_to_cpu(query_result.shaper_query.crtbl); ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_channel_get_commit_rate); ++ ++int qman_ceetm_channel_get_commit_rate_bps(struct qm_ceetm_channel *channel, ++ u64 *bps, u16 *token_limit) ++{ ++ struct qm_ceetm_rate token_rate; ++ int ret; ++ ++ ret = qman_ceetm_channel_get_commit_rate(channel, &token_rate, ++ token_limit); ++ if (ret) { ++ pr_err("The channel CR rate or limit is not available\n"); ++ return -EINVAL; ++ } ++ ++ return qman_ceetm_tokenrate2bps(&token_rate, bps, 0); ++} ++EXPORT_SYMBOL(qman_ceetm_channel_get_commit_rate_bps); ++ ++int qman_ceetm_channel_set_excess_rate(struct qm_ceetm_channel *channel, ++ const struct qm_ceetm_rate *token_rate, ++ u16 token_limit) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts; ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts; ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result; ++ int ret; ++ ++ query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER | ++ channel->idx); ++ query_opts.dcpid = channel->dcp_idx; ++ ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result); ++ if (ret) { ++ pr_err("Fail to get the current channel shaper setting\n"); ++ return -EINVAL; ++ } ++ ++ channel->er_token_rate.whole = token_rate->whole; ++ channel->er_token_rate.fraction = token_rate->fraction; ++ channel->er_token_bucket_limit = token_limit; ++ config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER | ++ channel->idx); ++ config_opts.dcpid = channel->dcp_idx; ++ config_opts.shaper_config.ertcr = cpu_to_be24( ++ (token_rate->whole << 13) | (token_rate->fraction)); ++ config_opts.shaper_config.ertbl = cpu_to_be16(token_limit); ++ config_opts.shaper_config.cpl = query_result.shaper_query.cpl; ++ config_opts.shaper_config.crtcr = query_result.shaper_query.crtcr; ++ config_opts.shaper_config.crtbl = query_result.shaper_query.crtbl; ++ return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts); ++} ++EXPORT_SYMBOL(qman_ceetm_channel_set_excess_rate); ++ ++int qman_ceetm_channel_set_excess_rate_bps(struct qm_ceetm_channel *channel, ++ u64 bps, u16 token_limit) ++{ ++ struct qm_ceetm_rate token_rate; ++ int ret; ++ ++ ret = qman_ceetm_bps2tokenrate(bps, &token_rate, 0); ++ if (ret) { ++ pr_err("Can not convert bps to token rate\n"); ++ return -EINVAL; ++ } ++ return qman_ceetm_channel_set_excess_rate(channel, &token_rate, ++ token_limit); ++} ++EXPORT_SYMBOL(qman_ceetm_channel_set_excess_rate_bps); ++ ++int qman_ceetm_channel_get_excess_rate(struct qm_ceetm_channel *channel, ++ struct qm_ceetm_rate *token_rate, ++ u16 *token_limit) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts; ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result; ++ int ret; ++ ++ query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER | ++ channel->idx); ++ query_opts.dcpid = channel->dcp_idx; ++ ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result); ++ if (ret | !query_result.shaper_query.ertcr | ++ !query_result.shaper_query.ertbl) { ++ pr_err("The channel excess rate or limit is not set\n"); ++ return -EINVAL; ++ } ++ token_rate->whole = be24_to_cpu(query_result.shaper_query.ertcr) >> 13; ++ token_rate->fraction = be24_to_cpu(query_result.shaper_query.ertcr) & ++ 0x1FFF; ++ *token_limit = be16_to_cpu(query_result.shaper_query.ertbl); ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_channel_get_excess_rate); ++ ++int qman_ceetm_channel_get_excess_rate_bps(struct qm_ceetm_channel *channel, ++ u64 *bps, u16 *token_limit) ++{ ++ struct qm_ceetm_rate token_rate; ++ int ret; ++ ++ ret = qman_ceetm_channel_get_excess_rate(channel, &token_rate, ++ token_limit); ++ if (ret) { ++ pr_err("The channel ER rate or limit is not available\n"); ++ return -EINVAL; ++ } ++ ++ return qman_ceetm_tokenrate2bps(&token_rate, bps, 0); ++} ++EXPORT_SYMBOL(qman_ceetm_channel_get_excess_rate_bps); ++ ++int qman_ceetm_channel_set_weight(struct qm_ceetm_channel *channel, ++ u16 token_limit) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts; ++ ++ if (channel->shaper_enable) { ++ pr_err("This channel is a shaped one\n"); ++ return -EINVAL; ++ } ++ ++ channel->cr_token_bucket_limit = token_limit; ++ config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER | ++ channel->idx); ++ config_opts.dcpid = channel->dcp_idx; ++ config_opts.shaper_config.crtbl = cpu_to_be16(token_limit); ++ return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts); ++} ++EXPORT_SYMBOL(qman_ceetm_channel_set_weight); ++ ++int qman_ceetm_channel_get_weight(struct qm_ceetm_channel *channel, ++ u16 *token_limit) ++{ ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts; ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result; ++ int ret; ++ ++ query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER | ++ channel->idx); ++ query_opts.dcpid = channel->dcp_idx; ++ ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result); ++ if (ret | !query_result.shaper_query.crtbl) { ++ pr_err("This unshaped channel's uFQ wight is unavailable\n"); ++ return -EINVAL; ++ } ++ *token_limit = be16_to_cpu(query_result.shaper_query.crtbl); ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_channel_get_weight); ++ ++int qman_ceetm_channel_set_group(struct qm_ceetm_channel *channel, int group_b, ++ unsigned int prio_a, unsigned int prio_b) ++{ ++ struct qm_mcc_ceetm_class_scheduler_config config_opts; ++ struct qm_mcr_ceetm_class_scheduler_query query_result; ++ int i; ++ ++ if (prio_a > 7) { ++ pr_err("The priority of group A is out of range\n"); ++ return -EINVAL; ++ } ++ if (group_b && (prio_b > 7)) { ++ pr_err("The priority of group B is out of range\n"); ++ return -EINVAL; ++ } ++ ++ if (qman_ceetm_query_class_scheduler(channel, &query_result)) { ++ pr_err("Can't query channel#%d's scheduler!\n", channel->idx); ++ return -EINVAL; ++ } ++ ++ config_opts.cqcid = cpu_to_be16(channel->idx); ++ config_opts.dcpid = channel->dcp_idx; ++ config_opts.gpc_combine_flag = !group_b; ++ config_opts.gpc_prio_a = prio_a; ++ config_opts.gpc_prio_b = prio_b; ++ ++ for (i = 0; i < 8; i++) ++ config_opts.w[i] = query_result.w[i]; ++ config_opts.crem = query_result.crem; ++ config_opts.erem = query_result.erem; ++ ++ return qman_ceetm_configure_class_scheduler(&config_opts); ++} ++EXPORT_SYMBOL(qman_ceetm_channel_set_group); ++ ++int qman_ceetm_channel_get_group(struct qm_ceetm_channel *channel, int *group_b, ++ unsigned int *prio_a, unsigned int *prio_b) ++{ ++ struct qm_mcr_ceetm_class_scheduler_query query_result; ++ ++ if (qman_ceetm_query_class_scheduler(channel, &query_result)) { ++ pr_err("Can't query channel#%d's scheduler!\n", channel->idx); ++ return -EINVAL; ++ } ++ *group_b = !query_result.gpc_combine_flag; ++ *prio_a = query_result.gpc_prio_a; ++ *prio_b = query_result.gpc_prio_b; ++ ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_channel_get_group); ++ ++#define GROUP_A_ELIGIBILITY_SET (1 << 8) ++#define GROUP_B_ELIGIBILITY_SET (1 << 9) ++#define CQ_ELIGIBILITY_SET(n) (1 << (7 - n)) ++int qman_ceetm_channel_set_group_cr_eligibility(struct qm_ceetm_channel ++ *channel, int group_b, int cre) ++{ ++ struct qm_mcc_ceetm_class_scheduler_config csch_config; ++ struct qm_mcr_ceetm_class_scheduler_query csch_query; ++ int i; ++ ++ if (qman_ceetm_query_class_scheduler(channel, &csch_query)) { ++ pr_err("Cannot get the channel %d scheduler setting.\n", ++ channel->idx); ++ return -EINVAL; ++ } ++ csch_config.cqcid = cpu_to_be16(channel->idx); ++ csch_config.dcpid = channel->dcp_idx; ++ csch_config.gpc_combine_flag = csch_query.gpc_combine_flag; ++ csch_config.gpc_prio_a = csch_query.gpc_prio_a; ++ csch_config.gpc_prio_b = csch_query.gpc_prio_b; ++ ++ for (i = 0; i < 8; i++) ++ csch_config.w[i] = csch_query.w[i]; ++ csch_config.erem = csch_query.erem; ++ if (group_b) ++ csch_config.crem = (be16_to_cpu(csch_query.crem) ++ & ~GROUP_B_ELIGIBILITY_SET) ++ | (cre ? GROUP_B_ELIGIBILITY_SET : 0); ++ else ++ csch_config.crem = (be16_to_cpu(csch_query.crem) ++ & ~GROUP_A_ELIGIBILITY_SET) ++ | (cre ? GROUP_A_ELIGIBILITY_SET : 0); ++ ++ csch_config.crem = cpu_to_be16(csch_config.crem); ++ ++ if (qman_ceetm_configure_class_scheduler(&csch_config)) { ++ pr_err("Cannot config channel %d's scheduler with " ++ "group_%c's cr eligibility\n", channel->idx, ++ group_b ? 'b' : 'a'); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_channel_set_group_cr_eligibility); ++ ++int qman_ceetm_channel_set_group_er_eligibility(struct qm_ceetm_channel ++ *channel, int group_b, int ere) ++{ ++ struct qm_mcc_ceetm_class_scheduler_config csch_config; ++ struct qm_mcr_ceetm_class_scheduler_query csch_query; ++ int i; ++ ++ if (qman_ceetm_query_class_scheduler(channel, &csch_query)) { ++ pr_err("Cannot get the channel %d scheduler setting.\n", ++ channel->idx); ++ return -EINVAL; ++ } ++ csch_config.cqcid = cpu_to_be16(channel->idx); ++ csch_config.dcpid = channel->dcp_idx; ++ csch_config.gpc_combine_flag = csch_query.gpc_combine_flag; ++ csch_config.gpc_prio_a = csch_query.gpc_prio_a; ++ csch_config.gpc_prio_b = csch_query.gpc_prio_b; ++ ++ for (i = 0; i < 8; i++) ++ csch_config.w[i] = csch_query.w[i]; ++ csch_config.crem = csch_query.crem; ++ if (group_b) ++ csch_config.erem = (be16_to_cpu(csch_query.erem) ++ & ~GROUP_B_ELIGIBILITY_SET) ++ | (ere ? GROUP_B_ELIGIBILITY_SET : 0); ++ else ++ csch_config.erem = (be16_to_cpu(csch_query.erem) ++ & ~GROUP_A_ELIGIBILITY_SET) ++ | (ere ? GROUP_A_ELIGIBILITY_SET : 0); ++ ++ csch_config.erem = cpu_to_be16(csch_config.erem); ++ ++ if (qman_ceetm_configure_class_scheduler(&csch_config)) { ++ pr_err("Cannot config channel %d's scheduler with " ++ "group_%c's er eligibility\n", channel->idx, ++ group_b ? 'b' : 'a'); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_channel_set_group_er_eligibility); ++ ++int qman_ceetm_channel_set_cq_cr_eligibility(struct qm_ceetm_channel *channel, ++ unsigned int idx, int cre) ++{ ++ struct qm_mcc_ceetm_class_scheduler_config csch_config; ++ struct qm_mcr_ceetm_class_scheduler_query csch_query; ++ int i; ++ ++ if (idx > 7) { ++ pr_err("CQ index is out of range\n"); ++ return -EINVAL; ++ } ++ if (qman_ceetm_query_class_scheduler(channel, &csch_query)) { ++ pr_err("Cannot get the channel %d scheduler setting.\n", ++ channel->idx); ++ return -EINVAL; ++ } ++ csch_config.cqcid = cpu_to_be16(channel->idx); ++ csch_config.dcpid = channel->dcp_idx; ++ csch_config.gpc_combine_flag = csch_query.gpc_combine_flag; ++ csch_config.gpc_prio_a = csch_query.gpc_prio_a; ++ csch_config.gpc_prio_b = csch_query.gpc_prio_b; ++ for (i = 0; i < 8; i++) ++ csch_config.w[i] = csch_query.w[i]; ++ csch_config.erem = csch_query.erem; ++ csch_config.crem = (be16_to_cpu(csch_query.crem) ++ & ~CQ_ELIGIBILITY_SET(idx)) | ++ (cre ? CQ_ELIGIBILITY_SET(idx) : 0); ++ csch_config.crem = cpu_to_be16(csch_config.crem); ++ if (qman_ceetm_configure_class_scheduler(&csch_config)) { ++ pr_err("Cannot config channel scheduler to set " ++ "cr eligibility mask for CQ#%d\n", idx); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_channel_set_cq_cr_eligibility); ++ ++int qman_ceetm_channel_set_cq_er_eligibility(struct qm_ceetm_channel *channel, ++ unsigned int idx, int ere) ++{ ++ struct qm_mcc_ceetm_class_scheduler_config csch_config; ++ struct qm_mcr_ceetm_class_scheduler_query csch_query; ++ int i; ++ ++ if (idx > 7) { ++ pr_err("CQ index is out of range\n"); ++ return -EINVAL; ++ } ++ if (qman_ceetm_query_class_scheduler(channel, &csch_query)) { ++ pr_err("Cannot get the channel %d scheduler setting.\n", ++ channel->idx); ++ return -EINVAL; ++ } ++ csch_config.cqcid = cpu_to_be16(channel->idx); ++ csch_config.dcpid = channel->dcp_idx; ++ csch_config.gpc_combine_flag = csch_query.gpc_combine_flag; ++ csch_config.gpc_prio_a = csch_query.gpc_prio_a; ++ csch_config.gpc_prio_b = csch_query.gpc_prio_b; ++ for (i = 0; i < 8; i++) ++ csch_config.w[i] = csch_query.w[i]; ++ csch_config.crem = csch_query.crem; ++ csch_config.erem = (be16_to_cpu(csch_query.erem) ++ & ~CQ_ELIGIBILITY_SET(idx)) | ++ (ere ? CQ_ELIGIBILITY_SET(idx) : 0); ++ csch_config.erem = cpu_to_be16(csch_config.erem); ++ if (qman_ceetm_configure_class_scheduler(&csch_config)) { ++ pr_err("Cannot config channel scheduler to set " ++ "er eligibility mask for CQ#%d\n", idx); ++ return -EINVAL; ++ } ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_channel_set_cq_er_eligibility); ++ ++int qman_ceetm_cq_claim(struct qm_ceetm_cq **cq, ++ struct qm_ceetm_channel *channel, unsigned int idx, ++ struct qm_ceetm_ccg *ccg) ++{ ++ struct qm_ceetm_cq *p; ++ struct qm_mcc_ceetm_cq_config cq_config; ++ ++ if (idx > 7) { ++ pr_err("The independent class queue id is out of range\n"); ++ return -EINVAL; ++ } ++ ++ list_for_each_entry(p, &channel->class_queues, node) { ++ if (p->idx == idx) { ++ pr_err("The CQ#%d has been claimed!\n", idx); ++ return -EINVAL; ++ } ++ } ++ ++ p = kmalloc(sizeof(*p), GFP_KERNEL); ++ if (!p) { ++ pr_err("Can't allocate memory for CQ#%d!\n", idx); ++ return -ENOMEM; ++ } ++ ++ list_add_tail(&p->node, &channel->class_queues); ++ p->idx = idx; ++ p->is_claimed = 1; ++ p->parent = channel; ++ INIT_LIST_HEAD(&p->bound_lfqids); ++ ++ if (ccg) { ++ cq_config.cqid = cpu_to_be16((channel->idx << 4) | idx); ++ cq_config.dcpid = channel->dcp_idx; ++ cq_config.ccgid = cpu_to_be16(ccg->idx); ++ if (qman_ceetm_configure_cq(&cq_config)) { ++ pr_err("Can't configure the CQ#%d with CCGRID#%d\n", ++ idx, ccg->idx); ++ list_del(&p->node); ++ kfree(p); ++ return -EINVAL; ++ } ++ } ++ ++ *cq = p; ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_cq_claim); ++ ++int qman_ceetm_cq_claim_A(struct qm_ceetm_cq **cq, ++ struct qm_ceetm_channel *channel, unsigned int idx, ++ struct qm_ceetm_ccg *ccg) ++{ ++ struct qm_ceetm_cq *p; ++ struct qm_mcc_ceetm_cq_config cq_config; ++ ++ if ((idx < 8) || (idx > 15)) { ++ pr_err("This grouped class queue id is out of range\n"); ++ return -EINVAL; ++ } ++ ++ list_for_each_entry(p, &channel->class_queues, node) { ++ if (p->idx == idx) { ++ pr_err("The CQ#%d has been claimed!\n", idx); ++ return -EINVAL; ++ } ++ } ++ ++ p = kmalloc(sizeof(*p), GFP_KERNEL); ++ if (!p) { ++ pr_err("Can't allocate memory for CQ#%d!\n", idx); ++ return -ENOMEM; ++ } ++ ++ list_add_tail(&p->node, &channel->class_queues); ++ p->idx = idx; ++ p->is_claimed = 1; ++ p->parent = channel; ++ INIT_LIST_HEAD(&p->bound_lfqids); ++ ++ if (ccg) { ++ cq_config.cqid = cpu_to_be16((channel->idx << 4) | idx); ++ cq_config.dcpid = channel->dcp_idx; ++ cq_config.ccgid = cpu_to_be16(ccg->idx); ++ if (qman_ceetm_configure_cq(&cq_config)) { ++ pr_err("Can't configure the CQ#%d with CCGRID#%d\n", ++ idx, ccg->idx); ++ list_del(&p->node); ++ kfree(p); ++ return -EINVAL; ++ } ++ } ++ *cq = p; ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_cq_claim_A); ++ ++int qman_ceetm_cq_claim_B(struct qm_ceetm_cq **cq, ++ struct qm_ceetm_channel *channel, unsigned int idx, ++ struct qm_ceetm_ccg *ccg) ++{ ++ struct qm_ceetm_cq *p; ++ struct qm_mcc_ceetm_cq_config cq_config; ++ ++ if ((idx < 12) || (idx > 15)) { ++ pr_err("This grouped class queue id is out of range\n"); ++ return -EINVAL; ++ } ++ ++ list_for_each_entry(p, &channel->class_queues, node) { ++ if (p->idx == idx) { ++ pr_err("The CQ#%d has been claimed!\n", idx); ++ return -EINVAL; ++ } ++ } ++ ++ p = kmalloc(sizeof(*p), GFP_KERNEL); ++ if (!p) { ++ pr_err("Can't allocate memory for CQ#%d!\n", idx); ++ return -ENOMEM; ++ } ++ ++ list_add_tail(&p->node, &channel->class_queues); ++ p->idx = idx; ++ p->is_claimed = 1; ++ p->parent = channel; ++ INIT_LIST_HEAD(&p->bound_lfqids); ++ ++ if (ccg) { ++ cq_config.cqid = cpu_to_be16((channel->idx << 4) | idx); ++ cq_config.dcpid = channel->dcp_idx; ++ cq_config.ccgid = cpu_to_be16(ccg->idx); ++ if (qman_ceetm_configure_cq(&cq_config)) { ++ pr_err("Can't configure the CQ#%d with CCGRID#%d\n", ++ idx, ccg->idx); ++ list_del(&p->node); ++ kfree(p); ++ return -EINVAL; ++ } ++ } ++ *cq = p; ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_cq_claim_B); ++ ++int qman_ceetm_cq_release(struct qm_ceetm_cq *cq) ++{ ++ if (!list_empty(&cq->bound_lfqids)) { ++ pr_err("The CQ#%d has unreleased LFQID\n", cq->idx); ++ return -EBUSY; ++ } ++ list_del(&cq->node); ++ qman_ceetm_drain_cq(cq); ++ kfree(cq); ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_cq_release); ++ ++int qman_ceetm_set_queue_weight(struct qm_ceetm_cq *cq, ++ struct qm_ceetm_weight_code *weight_code) ++{ ++ struct qm_mcc_ceetm_class_scheduler_config config_opts; ++ struct qm_mcr_ceetm_class_scheduler_query query_result; ++ int i; ++ ++ if (cq->idx < 8) { ++ pr_err("Can not set weight for ungrouped class queue\n"); ++ return -EINVAL; ++ } ++ ++ if (qman_ceetm_query_class_scheduler(cq->parent, &query_result)) { ++ pr_err("Can't query channel#%d's scheduler!\n", ++ cq->parent->idx); ++ return -EINVAL; ++ } ++ ++ config_opts.cqcid = cpu_to_be16(cq->parent->idx); ++ config_opts.dcpid = cq->parent->dcp_idx; ++ config_opts.crem = query_result.crem; ++ config_opts.erem = query_result.erem; ++ config_opts.gpc_combine_flag = query_result.gpc_combine_flag; ++ config_opts.gpc_prio_a = query_result.gpc_prio_a; ++ config_opts.gpc_prio_b = query_result.gpc_prio_b; ++ ++ for (i = 0; i < 8; i++) ++ config_opts.w[i] = query_result.w[i]; ++ config_opts.w[cq->idx - 8] = ((weight_code->y << 3) | ++ (weight_code->x & 0x7)); ++ return qman_ceetm_configure_class_scheduler(&config_opts); ++} ++EXPORT_SYMBOL(qman_ceetm_set_queue_weight); ++ ++int qman_ceetm_get_queue_weight(struct qm_ceetm_cq *cq, ++ struct qm_ceetm_weight_code *weight_code) ++{ ++ struct qm_mcr_ceetm_class_scheduler_query query_result; ++ ++ if (cq->idx < 8) { ++ pr_err("Can not get weight for ungrouped class queue\n"); ++ return -EINVAL; ++ } ++ ++ if (qman_ceetm_query_class_scheduler(cq->parent, ++ &query_result)) { ++ pr_err("Can't get the weight code for CQ#%d!\n", cq->idx); ++ return -EINVAL; ++ } ++ weight_code->y = query_result.w[cq->idx - 8] >> 3; ++ weight_code->x = query_result.w[cq->idx - 8] & 0x7; ++ ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_get_queue_weight); ++ ++/* The WBFS code is represent as {x,y}, the effect wieght can be calculated as: ++ * effective weight = 2^x / (1 - (y/64)) ++ * = 2^(x+6) / (64 - y) ++ */ ++static void reduce_fraction(u32 *n, u32 *d) ++{ ++ u32 factor = 2; ++ u32 lesser = (*n < *d) ? *n : *d; ++ /* If factor exceeds the square-root of the lesser of *n and *d, ++ * then there's no point continuing. Proof: if there was a factor ++ * bigger than the square root, that would imply there exists ++ * another factor smaller than the square-root with which it ++ * multiplies to give 'lesser' - but that's a contradiction ++ * because the other factor would have already been found and ++ * divided out. ++ */ ++ while ((factor * factor) <= lesser) { ++ /* If 'factor' is a factor of *n and *d, divide them both ++ * by 'factor' as many times as possible. ++ */ ++ while (!(*n % factor) && !(*d % factor)) { ++ *n /= factor; ++ *d /= factor; ++ lesser /= factor; ++ } ++ if (factor == 2) ++ factor = 3; ++ else ++ factor += 2; ++ } ++} ++ ++int qman_ceetm_wbfs2ratio(struct qm_ceetm_weight_code *weight_code, ++ u32 *numerator, ++ u32 *denominator) ++{ ++ *numerator = (u32) 1 << (weight_code->x + 6); ++ *denominator = 64 - weight_code->y; ++ reduce_fraction(numerator, denominator); ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_wbfs2ratio); ++ ++/* For a given x, the weight is between 2^x (inclusive) and 2^(x+1) (exclusive). ++ * So find 'x' by range, and then estimate 'y' using: ++ * 64 - y = 2^(x + 6) / weight ++ * = 2^(x + 6) / (n/d) ++ * = d * 2^(x+6) / n ++ * y = 64 - (d * 2^(x+6) / n) ++ */ ++int qman_ceetm_ratio2wbfs(u32 numerator, ++ u32 denominator, ++ struct qm_ceetm_weight_code *weight_code, ++ int rounding) ++{ ++ unsigned int y, x = 0; ++ /* search incrementing 'x' until: ++ * weight < 2^(x+1) ++ * n/d < 2^(x+1) ++ * n < d * 2^(x+1) ++ */ ++ while ((x < 8) && (numerator >= (denominator << (x + 1)))) ++ x++; ++ if (x >= 8) ++ return -ERANGE; ++ /* because of the subtraction, use '-rounding' */ ++ y = 64 - ROUNDING(denominator << (x + 6), numerator, -rounding); ++ if (y >= 32) ++ return -ERANGE; ++ weight_code->x = x; ++ weight_code->y = y; ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_ratio2wbfs); ++ ++int qman_ceetm_set_queue_weight_in_ratio(struct qm_ceetm_cq *cq, u32 ratio) ++{ ++ struct qm_ceetm_weight_code weight_code; ++ ++ if (qman_ceetm_ratio2wbfs(ratio, 100, &weight_code, 0)) { ++ pr_err("Cannot get wbfs code for cq %x\n", cq->idx); ++ return -EINVAL; ++ } ++ return qman_ceetm_set_queue_weight(cq, &weight_code); ++} ++EXPORT_SYMBOL(qman_ceetm_set_queue_weight_in_ratio); ++ ++int qman_ceetm_get_queue_weight_in_ratio(struct qm_ceetm_cq *cq, u32 *ratio) ++{ ++ struct qm_ceetm_weight_code weight_code; ++ u32 n, d; ++ ++ if (qman_ceetm_get_queue_weight(cq, &weight_code)) { ++ pr_err("Cannot query the weight code for cq%x\n", cq->idx); ++ return -EINVAL; ++ } ++ ++ if (qman_ceetm_wbfs2ratio(&weight_code, &n, &d)) { ++ pr_err("Cannot get the ratio with wbfs code\n"); ++ return -EINVAL; ++ } ++ ++ *ratio = (n * 100) / d; ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_get_queue_weight_in_ratio); ++ ++int qman_ceetm_cq_get_dequeue_statistics(struct qm_ceetm_cq *cq, u32 flags, ++ u64 *frame_count, u64 *byte_count) ++{ ++ struct qm_mcr_ceetm_statistics_query result; ++ u16 cid, command_type; ++ enum qm_dc_portal dcp_idx; ++ int ret; ++ ++ cid = cpu_to_be16((cq->parent->idx << 4) | cq->idx); ++ dcp_idx = cq->parent->dcp_idx; ++ if (flags == QMAN_CEETM_FLAG_CLEAR_STATISTICS_COUNTER) ++ command_type = CEETM_QUERY_DEQUEUE_CLEAR_STATISTICS; ++ else ++ command_type = CEETM_QUERY_DEQUEUE_STATISTICS; ++ ++ ret = qman_ceetm_query_statistics(cid, dcp_idx, command_type, &result); ++ if (ret) { ++ pr_err("Can't query the statistics of CQ#%d!\n", cq->idx); ++ return -EINVAL; ++ } ++ ++ *frame_count = be40_to_cpu(result.frm_cnt); ++ *byte_count = be48_to_cpu(result.byte_cnt); ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_cq_get_dequeue_statistics); ++ ++int qman_ceetm_drain_cq(struct qm_ceetm_cq *cq) ++{ ++ struct qm_mcr_ceetm_cq_peek_pop_xsfdrread ppxr; ++ int ret; ++ ++ do { ++ ret = qman_ceetm_cq_peek_pop_xsfdrread(cq, 1, 0, &ppxr); ++ if (ret) { ++ pr_err("Failed to pop frame from CQ\n"); ++ return -EINVAL; ++ } ++ } while (!(ppxr.stat & 0x2)); ++ ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_drain_cq); ++ ++#define CEETM_LFQMT_LFQID_MSB 0xF00000 ++#define CEETM_LFQMT_LFQID_LSB 0x000FFF ++int qman_ceetm_lfq_claim(struct qm_ceetm_lfq **lfq, ++ struct qm_ceetm_cq *cq) ++{ ++ struct qm_ceetm_lfq *p; ++ u32 lfqid; ++ int ret = 0; ++ struct qm_mcc_ceetm_lfqmt_config lfqmt_config; ++ ++ if (cq->parent->dcp_idx == qm_dc_portal_fman0) { ++ ret = qman_alloc_ceetm0_lfqid(&lfqid); ++ } else if (cq->parent->dcp_idx == qm_dc_portal_fman1) { ++ ret = qman_alloc_ceetm1_lfqid(&lfqid); ++ } else { ++ pr_err("dcp_idx %u does not correspond to a known fman in this driver\n", ++ cq->parent->dcp_idx); ++ return -EINVAL; ++ } ++ ++ if (ret) { ++ pr_err("There is no lfqid avalaible for CQ#%d!\n", cq->idx); ++ return -ENODEV; ++ } ++ p = kmalloc(sizeof(*p), GFP_KERNEL); ++ if (!p) ++ return -ENOMEM; ++ p->idx = lfqid; ++ p->dctidx = (u16)(lfqid & CEETM_LFQMT_LFQID_LSB); ++ p->parent = cq->parent; ++ list_add_tail(&p->node, &cq->bound_lfqids); ++ ++ lfqmt_config.lfqid = cpu_to_be24(CEETM_LFQMT_LFQID_MSB | ++ (cq->parent->dcp_idx << 16) | ++ (lfqid & CEETM_LFQMT_LFQID_LSB)); ++ lfqmt_config.cqid = cpu_to_be16((cq->parent->idx << 4) | (cq->idx)); ++ lfqmt_config.dctidx = cpu_to_be16(p->dctidx); ++ if (qman_ceetm_configure_lfqmt(&lfqmt_config)) { ++ pr_err("Can't configure LFQMT for LFQID#%d @ CQ#%d\n", ++ lfqid, cq->idx); ++ list_del(&p->node); ++ kfree(p); ++ return -EINVAL; ++ } ++ *lfq = p; ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_lfq_claim); ++ ++int qman_ceetm_lfq_release(struct qm_ceetm_lfq *lfq) ++{ ++ if (lfq->parent->dcp_idx == qm_dc_portal_fman0) { ++ qman_release_ceetm0_lfqid(lfq->idx); ++ } else if (lfq->parent->dcp_idx == qm_dc_portal_fman1) { ++ qman_release_ceetm1_lfqid(lfq->idx); ++ } else { ++ pr_err("dcp_idx %u does not correspond to a known fman in this driver\n", ++ lfq->parent->dcp_idx); ++ return -EINVAL; ++ } ++ list_del(&lfq->node); ++ kfree(lfq); ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_lfq_release); ++ ++int qman_ceetm_lfq_set_context(struct qm_ceetm_lfq *lfq, u64 context_a, ++ u32 context_b) ++{ ++ struct qm_mcc_ceetm_dct_config dct_config; ++ lfq->context_a = context_a; ++ lfq->context_b = context_b; ++ dct_config.dctidx = cpu_to_be16((u16)lfq->dctidx); ++ dct_config.dcpid = lfq->parent->dcp_idx; ++ dct_config.context_b = cpu_to_be32(context_b); ++ dct_config.context_a = cpu_to_be64(context_a); ++ ++ return qman_ceetm_configure_dct(&dct_config); ++} ++EXPORT_SYMBOL(qman_ceetm_lfq_set_context); ++ ++int qman_ceetm_lfq_get_context(struct qm_ceetm_lfq *lfq, u64 *context_a, ++ u32 *context_b) ++{ ++ struct qm_mcc_ceetm_dct_query dct_query; ++ struct qm_mcr_ceetm_dct_query query_result; ++ ++ dct_query.dctidx = cpu_to_be16(lfq->dctidx); ++ dct_query.dcpid = lfq->parent->dcp_idx; ++ if (qman_ceetm_query_dct(&dct_query, &query_result)) { ++ pr_err("Can't query LFQID#%d's context!\n", lfq->idx); ++ return -EINVAL; ++ } ++ *context_a = be64_to_cpu(query_result.context_a); ++ *context_b = be32_to_cpu(query_result.context_b); ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_lfq_get_context); ++ ++int qman_ceetm_create_fq(struct qm_ceetm_lfq *lfq, struct qman_fq *fq) ++{ ++ spin_lock_init(&fq->fqlock); ++ fq->fqid = lfq->idx; ++ fq->flags = QMAN_FQ_FLAG_NO_MODIFY; ++ if (lfq->ern) ++ fq->cb.ern = lfq->ern; ++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP ++ if (unlikely(find_empty_fq_table_entry(&fq->key, fq))) ++ return -ENOMEM; ++#endif ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_create_fq); ++ ++#define MAX_CCG_IDX 0x000F ++int qman_ceetm_ccg_claim(struct qm_ceetm_ccg **ccg, ++ struct qm_ceetm_channel *channel, ++ unsigned int idx, ++ void (*cscn)(struct qm_ceetm_ccg *, ++ void *cb_ctx, ++ int congested), ++ void *cb_ctx) ++{ ++ struct qm_ceetm_ccg *p; ++ ++ if (idx > MAX_CCG_IDX) { ++ pr_err("The given ccg index is out of range\n"); ++ return -EINVAL; ++ } ++ ++ list_for_each_entry(p, &channel->ccgs, node) { ++ if (p->idx == idx) { ++ pr_err("The CCG#%d has been claimed\n", idx); ++ return -EINVAL; ++ } ++ } ++ ++ p = kmalloc(sizeof(*p), GFP_KERNEL); ++ if (!p) { ++ pr_err("Can't allocate memory for CCG#%d!\n", idx); ++ return -ENOMEM; ++ } ++ ++ list_add_tail(&p->node, &channel->ccgs); ++ ++ p->idx = idx; ++ p->parent = channel; ++ p->cb = cscn; ++ p->cb_ctx = cb_ctx; ++ INIT_LIST_HEAD(&p->cb_node); ++ ++ *ccg = p; ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_ccg_claim); ++ ++int qman_ceetm_ccg_release(struct qm_ceetm_ccg *ccg) ++{ ++ unsigned long irqflags __maybe_unused; ++ struct qm_mcc_ceetm_ccgr_config config_opts; ++ int ret = 0; ++ struct qman_portal *p = get_affine_portal(); ++ ++ memset(&config_opts, 0, sizeof(struct qm_mcc_ceetm_ccgr_config)); ++ spin_lock_irqsave(&p->ccgr_lock, irqflags); ++ if (!list_empty(&ccg->cb_node)) ++ list_del(&ccg->cb_node); ++ config_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_CONFIGURE | ++ (ccg->parent->idx << 4) | ccg->idx); ++ config_opts.dcpid = ccg->parent->dcp_idx; ++ config_opts.we_mask = cpu_to_be16(QM_CCGR_WE_CSCN_TUPD); ++ config_opts.cm_config.cscn_tupd = cpu_to_be16(PORTAL_IDX(p)); ++ ret = qman_ceetm_configure_ccgr(&config_opts); ++ spin_unlock_irqrestore(&p->ccgr_lock, irqflags); ++ put_affine_portal(); ++ ++ list_del(&ccg->node); ++ kfree(ccg); ++ return ret; ++} ++EXPORT_SYMBOL(qman_ceetm_ccg_release); ++ ++int qman_ceetm_ccg_set(struct qm_ceetm_ccg *ccg, u16 we_mask, ++ const struct qm_ceetm_ccg_params *params) ++{ ++ struct qm_mcc_ceetm_ccgr_config config_opts; ++ unsigned long irqflags __maybe_unused; ++ int ret; ++ struct qman_portal *p; ++ ++ if (((ccg->parent->idx << 4) | ccg->idx) >= (2 * __CGR_NUM)) ++ return -EINVAL; ++ ++ p = get_affine_portal(); ++ ++ memset(&config_opts, 0, sizeof(struct qm_mcc_ceetm_ccgr_config)); ++ spin_lock_irqsave(&p->ccgr_lock, irqflags); ++ ++ config_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_CONFIGURE | ++ (ccg->parent->idx << 4) | ccg->idx); ++ config_opts.dcpid = ccg->parent->dcp_idx; ++ config_opts.we_mask = we_mask; ++ if (we_mask & QM_CCGR_WE_CSCN_EN) { ++ config_opts.we_mask |= QM_CCGR_WE_CSCN_TUPD; ++ config_opts.cm_config.cscn_tupd = cpu_to_be16( ++ QM_CGR_TARG_UDP_CTRL_WRITE_BIT | PORTAL_IDX(p)); ++ } ++ config_opts.we_mask = cpu_to_be16(config_opts.we_mask); ++ config_opts.cm_config.ctl_wr_en_g = params->wr_en_g; ++ config_opts.cm_config.ctl_wr_en_y = params->wr_en_y; ++ config_opts.cm_config.ctl_wr_en_r = params->wr_en_r; ++ config_opts.cm_config.ctl_td_en = params->td_en; ++ config_opts.cm_config.ctl_td_mode = params->td_mode; ++ config_opts.cm_config.ctl_cscn_en = params->cscn_en; ++ config_opts.cm_config.ctl_mode = params->mode; ++ config_opts.cm_config.oal = params->oal; ++ config_opts.cm_config.cs_thres.hword = ++ cpu_to_be16(params->cs_thres_in.hword); ++ config_opts.cm_config.cs_thres_x.hword = ++ cpu_to_be16(params->cs_thres_out.hword); ++ config_opts.cm_config.td_thres.hword = ++ cpu_to_be16(params->td_thres.hword); ++ config_opts.cm_config.wr_parm_g.word = ++ cpu_to_be32(params->wr_parm_g.word); ++ config_opts.cm_config.wr_parm_y.word = ++ cpu_to_be32(params->wr_parm_y.word); ++ config_opts.cm_config.wr_parm_r.word = ++ cpu_to_be32(params->wr_parm_r.word); ++ ret = qman_ceetm_configure_ccgr(&config_opts); ++ if (ret) { ++ pr_err("Configure CCGR CM failed!\n"); ++ goto release_lock; ++ } ++ ++ if (we_mask & QM_CCGR_WE_CSCN_EN) ++ if (list_empty(&ccg->cb_node)) ++ list_add(&ccg->cb_node, ++ &p->ccgr_cbs[ccg->parent->dcp_idx]); ++release_lock: ++ spin_unlock_irqrestore(&p->ccgr_lock, irqflags); ++ put_affine_portal(); ++ return ret; ++} ++EXPORT_SYMBOL(qman_ceetm_ccg_set); ++ ++#define CEETM_CCGR_CTL_MASK 0x01 ++int qman_ceetm_ccg_get(struct qm_ceetm_ccg *ccg, ++ struct qm_ceetm_ccg_params *params) ++{ ++ struct qm_mcc_ceetm_ccgr_query query_opts; ++ struct qm_mcr_ceetm_ccgr_query query_result; ++ ++ query_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_QUERY | ++ (ccg->parent->idx << 4) | ccg->idx); ++ query_opts.dcpid = ccg->parent->dcp_idx; ++ ++ if (qman_ceetm_query_ccgr(&query_opts, &query_result)) { ++ pr_err("Can't query CCGR#%d\n", ccg->idx); ++ return -EINVAL; ++ } ++ ++ params->wr_parm_r.word = query_result.cm_query.wr_parm_r.word; ++ params->wr_parm_y.word = query_result.cm_query.wr_parm_y.word; ++ params->wr_parm_g.word = query_result.cm_query.wr_parm_g.word; ++ params->td_thres.hword = query_result.cm_query.td_thres.hword; ++ params->cs_thres_out.hword = query_result.cm_query.cs_thres_x.hword; ++ params->cs_thres_in.hword = query_result.cm_query.cs_thres.hword; ++ params->oal = query_result.cm_query.oal; ++ params->wr_en_g = query_result.cm_query.ctl_wr_en_g; ++ params->wr_en_y = query_result.cm_query.ctl_wr_en_y; ++ params->wr_en_r = query_result.cm_query.ctl_wr_en_r; ++ params->td_en = query_result.cm_query.ctl_td_en; ++ params->td_mode = query_result.cm_query.ctl_td_mode; ++ params->cscn_en = query_result.cm_query.ctl_cscn_en; ++ params->mode = query_result.cm_query.ctl_mode; ++ ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_ccg_get); ++ ++int qman_ceetm_ccg_get_reject_statistics(struct qm_ceetm_ccg *ccg, u32 flags, ++ u64 *frame_count, u64 *byte_count) ++{ ++ struct qm_mcr_ceetm_statistics_query result; ++ u16 cid, command_type; ++ enum qm_dc_portal dcp_idx; ++ int ret; ++ ++ cid = cpu_to_be16((ccg->parent->idx << 4) | ccg->idx); ++ dcp_idx = ccg->parent->dcp_idx; ++ if (flags == QMAN_CEETM_FLAG_CLEAR_STATISTICS_COUNTER) ++ command_type = CEETM_QUERY_REJECT_CLEAR_STATISTICS; ++ else ++ command_type = CEETM_QUERY_REJECT_STATISTICS; ++ ++ ret = qman_ceetm_query_statistics(cid, dcp_idx, command_type, &result); ++ if (ret) { ++ pr_err("Can't query the statistics of CCG#%d!\n", ccg->idx); ++ return -EINVAL; ++ } ++ ++ *frame_count = be40_to_cpu(result.frm_cnt); ++ *byte_count = be48_to_cpu(result.byte_cnt); ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_ccg_get_reject_statistics); ++ ++int qman_ceetm_cscn_swp_get(struct qm_ceetm_ccg *ccg, ++ u16 swp_idx, ++ unsigned int *cscn_enabled) ++{ ++ struct qm_mcc_ceetm_ccgr_query query_opts; ++ struct qm_mcr_ceetm_ccgr_query query_result; ++ int i; ++ ++ DPA_ASSERT(swp_idx < 127); ++ query_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_QUERY | ++ (ccg->parent->idx << 4) | ccg->idx); ++ query_opts.dcpid = ccg->parent->dcp_idx; ++ ++ if (qman_ceetm_query_ccgr(&query_opts, &query_result)) { ++ pr_err("Can't query CCGR#%d\n", ccg->idx); ++ return -EINVAL; ++ } ++ ++ i = swp_idx / 32; ++ i = 3 - i; ++ *cscn_enabled = query_result.cm_query.cscn_targ_swp[i] >> ++ (31 - swp_idx % 32); ++ ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_cscn_swp_get); ++ ++int qman_ceetm_cscn_dcp_set(struct qm_ceetm_ccg *ccg, ++ u16 dcp_idx, ++ u8 vcgid, ++ unsigned int cscn_enabled, ++ u16 we_mask, ++ const struct qm_ceetm_ccg_params *params) ++{ ++ struct qm_mcc_ceetm_ccgr_config config_opts; ++ int ret; ++ ++ config_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_CONFIGURE | ++ (ccg->parent->idx << 4) | ccg->idx); ++ config_opts.dcpid = ccg->parent->dcp_idx; ++ config_opts.we_mask = cpu_to_be16(we_mask | QM_CCGR_WE_CSCN_TUPD | ++ QM_CCGR_WE_CDV); ++ config_opts.cm_config.cdv = vcgid; ++ config_opts.cm_config.cscn_tupd = cpu_to_be16((cscn_enabled << 15) | ++ QM_CGR_TARG_UDP_CTRL_DCP | dcp_idx); ++ config_opts.cm_config.ctl_wr_en_g = params->wr_en_g; ++ config_opts.cm_config.ctl_wr_en_y = params->wr_en_y; ++ config_opts.cm_config.ctl_wr_en_r = params->wr_en_r; ++ config_opts.cm_config.ctl_td_en = params->td_en; ++ config_opts.cm_config.ctl_td_mode = params->td_mode; ++ config_opts.cm_config.ctl_cscn_en = params->cscn_en; ++ config_opts.cm_config.ctl_mode = params->mode; ++ config_opts.cm_config.cs_thres.hword = ++ cpu_to_be16(params->cs_thres_in.hword); ++ config_opts.cm_config.cs_thres_x.hword = ++ cpu_to_be16(params->cs_thres_out.hword); ++ config_opts.cm_config.td_thres.hword = ++ cpu_to_be16(params->td_thres.hword); ++ config_opts.cm_config.wr_parm_g.word = ++ cpu_to_be32(params->wr_parm_g.word); ++ config_opts.cm_config.wr_parm_y.word = ++ cpu_to_be32(params->wr_parm_y.word); ++ config_opts.cm_config.wr_parm_r.word = ++ cpu_to_be32(params->wr_parm_r.word); ++ ++ ret = qman_ceetm_configure_ccgr(&config_opts); ++ if (ret) { ++ pr_err("Configure CSCN_TARG_DCP failed!\n"); ++ return -EINVAL; ++ } ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_cscn_dcp_set); ++ ++int qman_ceetm_cscn_dcp_get(struct qm_ceetm_ccg *ccg, ++ u16 dcp_idx, ++ u8 *vcgid, ++ unsigned int *cscn_enabled) ++{ ++ struct qm_mcc_ceetm_ccgr_query query_opts; ++ struct qm_mcr_ceetm_ccgr_query query_result; ++ ++ query_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_QUERY | ++ (ccg->parent->idx << 4) | ccg->idx); ++ query_opts.dcpid = ccg->parent->dcp_idx; ++ ++ if (qman_ceetm_query_ccgr(&query_opts, &query_result)) { ++ pr_err("Can't query CCGR#%d\n", ccg->idx); ++ return -EINVAL; ++ } ++ ++ *vcgid = query_result.cm_query.cdv; ++ *cscn_enabled = (query_result.cm_query.cscn_targ_dcp >> dcp_idx) & 0x1; ++ return 0; ++} ++EXPORT_SYMBOL(qman_ceetm_cscn_dcp_get); ++ ++int qman_ceetm_querycongestion(struct __qm_mcr_querycongestion *ccg_state, ++ unsigned int dcp_idx) ++{ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ u8 res; ++ int i, j; ++ ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ ++ mcc = qm_mc_start(&p->p); ++ for (i = 0; i < 2; i++) { ++ mcc->ccgr_query.ccgrid = ++ cpu_to_be16(CEETM_QUERY_CONGESTION_STATE | i); ++ mcc->ccgr_query.dcpid = dcp_idx; ++ qm_mc_commit(&p->p, QM_CEETM_VERB_CCGR_QUERY); ++ ++ while (!(mcr = qm_mc_result(&p->p))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == ++ QM_CEETM_VERB_CCGR_QUERY); ++ res = mcr->result; ++ if (res == QM_MCR_RESULT_OK) { ++ for (j = 0; j < 8; j++) ++ mcr->ccgr_query.congestion_state.state. ++ __state[j] = be32_to_cpu(mcr->ccgr_query. ++ congestion_state.state.__state[j]); ++ *(ccg_state + i) = ++ mcr->ccgr_query.congestion_state.state; ++ } else { ++ pr_err("QUERY CEETM CONGESTION STATE failed\n"); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ return -EIO; ++ } ++ } ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ return 0; ++} ++ ++int qman_set_wpm(int wpm_enable) ++{ ++ return qm_set_wpm(wpm_enable); ++} ++EXPORT_SYMBOL(qman_set_wpm); ++ ++int qman_get_wpm(int *wpm_enable) ++{ ++ return qm_get_wpm(wpm_enable); ++} ++EXPORT_SYMBOL(qman_get_wpm); ++ ++int qman_shutdown_fq(u32 fqid) ++{ ++ struct qman_portal *p; ++ unsigned long irqflags __maybe_unused; ++ int ret; ++ struct qm_portal *low_p; ++ p = get_affine_portal(); ++ PORTAL_IRQ_LOCK(p, irqflags); ++ low_p = &p->p; ++ ret = qm_shutdown_fq(&low_p, 1, fqid); ++ PORTAL_IRQ_UNLOCK(p, irqflags); ++ put_affine_portal(); ++ return ret; ++} ++ ++const struct qm_portal_config *qman_get_qm_portal_config( ++ struct qman_portal *portal) ++{ ++ return portal->sharing_redirect ? NULL : portal->config; ++} +diff --git a/drivers/staging/fsl_qbman/qman_low.h b/drivers/staging/fsl_qbman/qman_low.h +new file mode 100644 +index 00000000..547b5fa2 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/qman_low.h +@@ -0,0 +1,1427 @@ ++/* Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "qman_private.h" ++ ++/***************************/ ++/* Portal register assists */ ++/***************************/ ++ ++/* Cache-inhibited register offsets */ ++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) ++ ++#define QM_REG_EQCR_PI_CINH 0x0000 ++#define QM_REG_EQCR_CI_CINH 0x0004 ++#define QM_REG_EQCR_ITR 0x0008 ++#define QM_REG_DQRR_PI_CINH 0x0040 ++#define QM_REG_DQRR_CI_CINH 0x0044 ++#define QM_REG_DQRR_ITR 0x0048 ++#define QM_REG_DQRR_DCAP 0x0050 ++#define QM_REG_DQRR_SDQCR 0x0054 ++#define QM_REG_DQRR_VDQCR 0x0058 ++#define QM_REG_DQRR_PDQCR 0x005c ++#define QM_REG_MR_PI_CINH 0x0080 ++#define QM_REG_MR_CI_CINH 0x0084 ++#define QM_REG_MR_ITR 0x0088 ++#define QM_REG_CFG 0x0100 ++#define QM_REG_ISR 0x0e00 ++#define QM_REG_IIR 0x0e0c ++#define QM_REG_ITPR 0x0e14 ++ ++/* Cache-enabled register offsets */ ++#define QM_CL_EQCR 0x0000 ++#define QM_CL_DQRR 0x1000 ++#define QM_CL_MR 0x2000 ++#define QM_CL_EQCR_PI_CENA 0x3000 ++#define QM_CL_EQCR_CI_CENA 0x3100 ++#define QM_CL_DQRR_PI_CENA 0x3200 ++#define QM_CL_DQRR_CI_CENA 0x3300 ++#define QM_CL_MR_PI_CENA 0x3400 ++#define QM_CL_MR_CI_CENA 0x3500 ++#define QM_CL_CR 0x3800 ++#define QM_CL_RR0 0x3900 ++#define QM_CL_RR1 0x3940 ++ ++#endif ++ ++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) ++ ++#define QM_REG_EQCR_PI_CINH 0x3000 ++#define QM_REG_EQCR_CI_CINH 0x3040 ++#define QM_REG_EQCR_ITR 0x3080 ++#define QM_REG_DQRR_PI_CINH 0x3100 ++#define QM_REG_DQRR_CI_CINH 0x3140 ++#define QM_REG_DQRR_ITR 0x3180 ++#define QM_REG_DQRR_DCAP 0x31C0 ++#define QM_REG_DQRR_SDQCR 0x3200 ++#define QM_REG_DQRR_VDQCR 0x3240 ++#define QM_REG_DQRR_PDQCR 0x3280 ++#define QM_REG_MR_PI_CINH 0x3300 ++#define QM_REG_MR_CI_CINH 0x3340 ++#define QM_REG_MR_ITR 0x3380 ++#define QM_REG_CFG 0x3500 ++#define QM_REG_ISR 0x3600 ++#define QM_REG_IIR 0x36C0 ++#define QM_REG_ITPR 0x3740 ++ ++/* Cache-enabled register offsets */ ++#define QM_CL_EQCR 0x0000 ++#define QM_CL_DQRR 0x1000 ++#define QM_CL_MR 0x2000 ++#define QM_CL_EQCR_PI_CENA 0x3000 ++#define QM_CL_EQCR_CI_CENA 0x3040 ++#define QM_CL_DQRR_PI_CENA 0x3100 ++#define QM_CL_DQRR_CI_CENA 0x3140 ++#define QM_CL_MR_PI_CENA 0x3300 ++#define QM_CL_MR_CI_CENA 0x3340 ++#define QM_CL_CR 0x3800 ++#define QM_CL_RR0 0x3900 ++#define QM_CL_RR1 0x3940 ++ ++#endif ++ ++ ++/* BTW, the drivers (and h/w programming model) already obtain the required ++ * synchronisation for portal accesses via lwsync(), hwsync(), and ++ * data-dependencies. Use of barrier()s or other order-preserving primitives ++ * simply degrade performance. Hence the use of the __raw_*() interfaces, which ++ * simply ensure that the compiler treats the portal registers as volatile (ie. ++ * non-coherent). */ ++ ++/* Cache-inhibited register access. */ ++#define __qm_in(qm, o) be32_to_cpu(__raw_readl((qm)->addr_ci + (o))) ++#define __qm_out(qm, o, val) __raw_writel((cpu_to_be32(val)), \ ++ (qm)->addr_ci + (o)); ++#define qm_in(reg) __qm_in(&portal->addr, QM_REG_##reg) ++#define qm_out(reg, val) __qm_out(&portal->addr, QM_REG_##reg, val) ++ ++/* Cache-enabled (index) register access */ ++#define __qm_cl_touch_ro(qm, o) dcbt_ro((qm)->addr_ce + (o)) ++#define __qm_cl_touch_rw(qm, o) dcbt_rw((qm)->addr_ce + (o)) ++#define __qm_cl_in(qm, o) be32_to_cpu(__raw_readl((qm)->addr_ce + (o))) ++#define __qm_cl_out(qm, o, val) \ ++ do { \ ++ u32 *__tmpclout = (qm)->addr_ce + (o); \ ++ __raw_writel(cpu_to_be32(val), __tmpclout); \ ++ dcbf(__tmpclout); \ ++ } while (0) ++#define __qm_cl_invalidate(qm, o) dcbi((qm)->addr_ce + (o)) ++#define qm_cl_touch_ro(reg) __qm_cl_touch_ro(&portal->addr, QM_CL_##reg##_CENA) ++#define qm_cl_touch_rw(reg) __qm_cl_touch_rw(&portal->addr, QM_CL_##reg##_CENA) ++#define qm_cl_in(reg) __qm_cl_in(&portal->addr, QM_CL_##reg##_CENA) ++#define qm_cl_out(reg, val) __qm_cl_out(&portal->addr, QM_CL_##reg##_CENA, val) ++#define qm_cl_invalidate(reg)\ ++ __qm_cl_invalidate(&portal->addr, QM_CL_##reg##_CENA) ++ ++/* Cache-enabled ring access */ ++#define qm_cl(base, idx) ((void *)base + ((idx) << 6)) ++ ++/* Cyclic helper for rings. FIXME: once we are able to do fine-grain perf ++ * analysis, look at using the "extra" bit in the ring index registers to avoid ++ * cyclic issues. */ ++static inline u8 qm_cyc_diff(u8 ringsize, u8 first, u8 last) ++{ ++ /* 'first' is included, 'last' is excluded */ ++ if (first <= last) ++ return last - first; ++ return ringsize + last - first; ++} ++ ++/* Portal modes. ++ * Enum types; ++ * pmode == production mode ++ * cmode == consumption mode, ++ * dmode == h/w dequeue mode. ++ * Enum values use 3 letter codes. First letter matches the portal mode, ++ * remaining two letters indicate; ++ * ci == cache-inhibited portal register ++ * ce == cache-enabled portal register ++ * vb == in-band valid-bit (cache-enabled) ++ * dc == DCA (Discrete Consumption Acknowledgement), DQRR-only ++ * As for "enum qm_dqrr_dmode", it should be self-explanatory. ++ */ ++enum qm_eqcr_pmode { /* matches QCSP_CFG::EPM */ ++ qm_eqcr_pci = 0, /* PI index, cache-inhibited */ ++ qm_eqcr_pce = 1, /* PI index, cache-enabled */ ++ qm_eqcr_pvb = 2 /* valid-bit */ ++}; ++enum qm_dqrr_dmode { /* matches QCSP_CFG::DP */ ++ qm_dqrr_dpush = 0, /* SDQCR + VDQCR */ ++ qm_dqrr_dpull = 1 /* PDQCR */ ++}; ++enum qm_dqrr_pmode { /* s/w-only */ ++ qm_dqrr_pci, /* reads DQRR_PI_CINH */ ++ qm_dqrr_pce, /* reads DQRR_PI_CENA */ ++ qm_dqrr_pvb /* reads valid-bit */ ++}; ++enum qm_dqrr_cmode { /* matches QCSP_CFG::DCM */ ++ qm_dqrr_cci = 0, /* CI index, cache-inhibited */ ++ qm_dqrr_cce = 1, /* CI index, cache-enabled */ ++ qm_dqrr_cdc = 2 /* Discrete Consumption Acknowledgement */ ++}; ++enum qm_mr_pmode { /* s/w-only */ ++ qm_mr_pci, /* reads MR_PI_CINH */ ++ qm_mr_pce, /* reads MR_PI_CENA */ ++ qm_mr_pvb /* reads valid-bit */ ++}; ++enum qm_mr_cmode { /* matches QCSP_CFG::MM */ ++ qm_mr_cci = 0, /* CI index, cache-inhibited */ ++ qm_mr_cce = 1 /* CI index, cache-enabled */ ++}; ++ ++ ++/* ------------------------- */ ++/* --- Portal structures --- */ ++ ++#define QM_EQCR_SIZE 8 ++#define QM_DQRR_SIZE 16 ++#define QM_MR_SIZE 8 ++ ++struct qm_eqcr { ++ struct qm_eqcr_entry *ring, *cursor; ++ u8 ci, available, ithresh, vbit; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ u32 busy; ++ enum qm_eqcr_pmode pmode; ++#endif ++}; ++ ++struct qm_dqrr { ++ const struct qm_dqrr_entry *ring, *cursor; ++ u8 pi, ci, fill, ithresh, vbit; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ enum qm_dqrr_dmode dmode; ++ enum qm_dqrr_pmode pmode; ++ enum qm_dqrr_cmode cmode; ++#endif ++}; ++ ++struct qm_mr { ++ const struct qm_mr_entry *ring, *cursor; ++ u8 pi, ci, fill, ithresh, vbit; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ enum qm_mr_pmode pmode; ++ enum qm_mr_cmode cmode; ++#endif ++}; ++ ++struct qm_mc { ++ struct qm_mc_command *cr; ++ struct qm_mc_result *rr; ++ u8 rridx, vbit; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ enum { ++ /* Can be _mc_start()ed */ ++ qman_mc_idle, ++ /* Can be _mc_commit()ed or _mc_abort()ed */ ++ qman_mc_user, ++ /* Can only be _mc_retry()ed */ ++ qman_mc_hw ++ } state; ++#endif ++}; ++ ++#define QM_PORTAL_ALIGNMENT ____cacheline_aligned ++ ++struct qm_addr { ++ void __iomem *addr_ce; /* cache-enabled */ ++ void __iomem *addr_ci; /* cache-inhibited */ ++}; ++ ++struct qm_portal { ++ /* In the non-CONFIG_FSL_DPA_CHECKING case, the following stuff up to ++ * and including 'mc' fits within a cacheline (yay!). The 'config' part ++ * is setup-only, so isn't a cause for a concern. In other words, don't ++ * rearrange this structure on a whim, there be dragons ... */ ++ struct qm_addr addr; ++ struct qm_eqcr eqcr; ++ struct qm_dqrr dqrr; ++ struct qm_mr mr; ++ struct qm_mc mc; ++} QM_PORTAL_ALIGNMENT; ++ ++ ++/* ---------------- */ ++/* --- EQCR API --- */ ++ ++/* Bit-wise logic to wrap a ring pointer by clearing the "carry bit" */ ++#define EQCR_CARRYCLEAR(p) \ ++ (void *)((unsigned long)(p) & (~(unsigned long)(QM_EQCR_SIZE << 6))) ++ ++/* Bit-wise logic to convert a ring pointer to a ring index */ ++static inline u8 EQCR_PTR2IDX(struct qm_eqcr_entry *e) ++{ ++ return ((uintptr_t)e >> 6) & (QM_EQCR_SIZE - 1); ++} ++ ++/* Increment the 'cursor' ring pointer, taking 'vbit' into account */ ++static inline void EQCR_INC(struct qm_eqcr *eqcr) ++{ ++ /* NB: this is odd-looking, but experiments show that it generates fast ++ * code with essentially no branching overheads. We increment to the ++ * next EQCR pointer and handle overflow and 'vbit'. */ ++ struct qm_eqcr_entry *partial = eqcr->cursor + 1; ++ eqcr->cursor = EQCR_CARRYCLEAR(partial); ++ if (partial != eqcr->cursor) ++ eqcr->vbit ^= QM_EQCR_VERB_VBIT; ++} ++ ++static inline int qm_eqcr_init(struct qm_portal *portal, ++ enum qm_eqcr_pmode pmode, ++ unsigned int eq_stash_thresh, ++ int eq_stash_prio) ++{ ++ /* This use of 'register', as well as all other occurrences, is because ++ * it has been observed to generate much faster code with gcc than is ++ * otherwise the case. */ ++ register struct qm_eqcr *eqcr = &portal->eqcr; ++ u32 cfg; ++ u8 pi; ++ ++ eqcr->ring = portal->addr.addr_ce + QM_CL_EQCR; ++ eqcr->ci = qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1); ++ qm_cl_invalidate(EQCR_CI); ++ pi = qm_in(EQCR_PI_CINH) & (QM_EQCR_SIZE - 1); ++ eqcr->cursor = eqcr->ring + pi; ++ eqcr->vbit = (qm_in(EQCR_PI_CINH) & QM_EQCR_SIZE) ? ++ QM_EQCR_VERB_VBIT : 0; ++ eqcr->available = QM_EQCR_SIZE - 1 - ++ qm_cyc_diff(QM_EQCR_SIZE, eqcr->ci, pi); ++ eqcr->ithresh = qm_in(EQCR_ITR); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ eqcr->busy = 0; ++ eqcr->pmode = pmode; ++#endif ++ cfg = (qm_in(CFG) & 0x00ffffff) | ++ (eq_stash_thresh << 28) | /* QCSP_CFG: EST */ ++ (eq_stash_prio << 26) | /* QCSP_CFG: EP */ ++ ((pmode & 0x3) << 24); /* QCSP_CFG::EPM */ ++ qm_out(CFG, cfg); ++ return 0; ++} ++ ++static inline unsigned int qm_eqcr_get_ci_stashing(struct qm_portal *portal) ++{ ++ return (qm_in(CFG) >> 28) & 0x7; ++} ++ ++static inline void qm_eqcr_finish(struct qm_portal *portal) ++{ ++ register struct qm_eqcr *eqcr = &portal->eqcr; ++ u8 pi, ci; ++ u32 cfg; ++ ++ /* ++ * Disable EQCI stashing because the QMan only ++ * presents the value it previously stashed to ++ * maintain coherency. Setting the stash threshold ++ * to 1 then 0 ensures that QMan has resyncronized ++ * its internal copy so that the portal is clean ++ * when it is reinitialized in the future ++ */ ++ cfg = (qm_in(CFG) & 0x0fffffff) | ++ (1 << 28); /* QCSP_CFG: EST */ ++ qm_out(CFG, cfg); ++ cfg &= 0x0fffffff; /* stash threshold = 0 */ ++ qm_out(CFG, cfg); ++ ++ pi = qm_in(EQCR_PI_CINH) & (QM_EQCR_SIZE - 1); ++ ci = qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1); ++ ++ /* Refresh EQCR CI cache value */ ++ qm_cl_invalidate(EQCR_CI); ++ eqcr->ci = qm_cl_in(EQCR_CI) & (QM_EQCR_SIZE - 1); ++ ++ DPA_ASSERT(!eqcr->busy); ++ if (pi != EQCR_PTR2IDX(eqcr->cursor)) ++ pr_crit("losing uncommited EQCR entries\n"); ++ if (ci != eqcr->ci) ++ pr_crit("missing existing EQCR completions\n"); ++ if (eqcr->ci != EQCR_PTR2IDX(eqcr->cursor)) ++ pr_crit("EQCR destroyed unquiesced\n"); ++} ++ ++static inline struct qm_eqcr_entry *qm_eqcr_start_no_stash(struct qm_portal ++ *portal) ++{ ++ register struct qm_eqcr *eqcr = &portal->eqcr; ++ DPA_ASSERT(!eqcr->busy); ++ if (!eqcr->available) ++ return NULL; ++ ++ ++#ifdef CONFIG_FSL_DPA_CHECKING ++ eqcr->busy = 1; ++#endif ++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) ++ dcbz_64(eqcr->cursor); ++#endif ++ return eqcr->cursor; ++} ++ ++static inline struct qm_eqcr_entry *qm_eqcr_start_stash(struct qm_portal ++ *portal) ++{ ++ register struct qm_eqcr *eqcr = &portal->eqcr; ++ u8 diff, old_ci; ++ ++ DPA_ASSERT(!eqcr->busy); ++ if (!eqcr->available) { ++ old_ci = eqcr->ci; ++ eqcr->ci = qm_cl_in(EQCR_CI) & (QM_EQCR_SIZE - 1); ++ diff = qm_cyc_diff(QM_EQCR_SIZE, old_ci, eqcr->ci); ++ eqcr->available += diff; ++ if (!diff) ++ return NULL; ++ } ++#ifdef CONFIG_FSL_DPA_CHECKING ++ eqcr->busy = 1; ++#endif ++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) ++ dcbz_64(eqcr->cursor); ++#endif ++ return eqcr->cursor; ++} ++ ++static inline void qm_eqcr_abort(struct qm_portal *portal) ++{ ++ __maybe_unused register struct qm_eqcr *eqcr = &portal->eqcr; ++ DPA_ASSERT(eqcr->busy); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ eqcr->busy = 0; ++#endif ++} ++ ++static inline struct qm_eqcr_entry *qm_eqcr_pend_and_next( ++ struct qm_portal *portal, u8 myverb) ++{ ++ register struct qm_eqcr *eqcr = &portal->eqcr; ++ DPA_ASSERT(eqcr->busy); ++ DPA_ASSERT(eqcr->pmode != qm_eqcr_pvb); ++ if (eqcr->available == 1) ++ return NULL; ++ eqcr->cursor->__dont_write_directly__verb = myverb | eqcr->vbit; ++ dcbf(eqcr->cursor); ++ EQCR_INC(eqcr); ++ eqcr->available--; ++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) ++ dcbz_64(eqcr->cursor); ++#endif ++ return eqcr->cursor; ++} ++ ++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ++#define EQCR_COMMIT_CHECKS(eqcr) \ ++do { \ ++ DPA_ASSERT(eqcr->busy); \ ++ DPA_ASSERT(eqcr->cursor->orp == (eqcr->cursor->orp & 0xffffff00)); \ ++ DPA_ASSERT(eqcr->cursor->fqid == (eqcr->cursor->fqid & 0xffffff00)); \ ++} while (0) ++#else ++#define EQCR_COMMIT_CHECKS(eqcr) \ ++do { \ ++ DPA_ASSERT(eqcr->busy); \ ++ DPA_ASSERT(eqcr->cursor->orp == (eqcr->cursor->orp & \ ++ cpu_to_be32(0x00ffffff))); \ ++ DPA_ASSERT(eqcr->cursor->fqid == (eqcr->cursor->fqid & \ ++ cpu_to_be32(0x00ffffff))); \ ++} while (0) ++#endif ++ ++static inline void qm_eqcr_pci_commit(struct qm_portal *portal, u8 myverb) ++{ ++ register struct qm_eqcr *eqcr = &portal->eqcr; ++ EQCR_COMMIT_CHECKS(eqcr); ++ DPA_ASSERT(eqcr->pmode == qm_eqcr_pci); ++ eqcr->cursor->__dont_write_directly__verb = myverb | eqcr->vbit; ++ EQCR_INC(eqcr); ++ eqcr->available--; ++ dcbf(eqcr->cursor); ++ hwsync(); ++ qm_out(EQCR_PI_CINH, EQCR_PTR2IDX(eqcr->cursor)); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ eqcr->busy = 0; ++#endif ++} ++ ++static inline void qm_eqcr_pce_prefetch(struct qm_portal *portal) ++{ ++ __maybe_unused register struct qm_eqcr *eqcr = &portal->eqcr; ++ DPA_ASSERT(eqcr->pmode == qm_eqcr_pce); ++ qm_cl_invalidate(EQCR_PI); ++ qm_cl_touch_rw(EQCR_PI); ++} ++ ++static inline void qm_eqcr_pce_commit(struct qm_portal *portal, u8 myverb) ++{ ++ register struct qm_eqcr *eqcr = &portal->eqcr; ++ EQCR_COMMIT_CHECKS(eqcr); ++ DPA_ASSERT(eqcr->pmode == qm_eqcr_pce); ++ eqcr->cursor->__dont_write_directly__verb = myverb | eqcr->vbit; ++ EQCR_INC(eqcr); ++ eqcr->available--; ++ dcbf(eqcr->cursor); ++ lwsync(); ++ qm_cl_out(EQCR_PI, EQCR_PTR2IDX(eqcr->cursor)); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ eqcr->busy = 0; ++#endif ++} ++ ++static inline void qm_eqcr_pvb_commit(struct qm_portal *portal, u8 myverb) ++{ ++ register struct qm_eqcr *eqcr = &portal->eqcr; ++ struct qm_eqcr_entry *eqcursor; ++ EQCR_COMMIT_CHECKS(eqcr); ++ DPA_ASSERT(eqcr->pmode == qm_eqcr_pvb); ++ lwsync(); ++ eqcursor = eqcr->cursor; ++ eqcursor->__dont_write_directly__verb = myverb | eqcr->vbit; ++ dcbf(eqcursor); ++ EQCR_INC(eqcr); ++ eqcr->available--; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ eqcr->busy = 0; ++#endif ++} ++ ++static inline u8 qm_eqcr_cci_update(struct qm_portal *portal) ++{ ++ register struct qm_eqcr *eqcr = &portal->eqcr; ++ u8 diff, old_ci = eqcr->ci; ++ eqcr->ci = qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1); ++ diff = qm_cyc_diff(QM_EQCR_SIZE, old_ci, eqcr->ci); ++ eqcr->available += diff; ++ return diff; ++} ++ ++static inline void qm_eqcr_cce_prefetch(struct qm_portal *portal) ++{ ++ __maybe_unused register struct qm_eqcr *eqcr = &portal->eqcr; ++ qm_cl_touch_ro(EQCR_CI); ++} ++ ++static inline u8 qm_eqcr_cce_update(struct qm_portal *portal) ++{ ++ register struct qm_eqcr *eqcr = &portal->eqcr; ++ u8 diff, old_ci = eqcr->ci; ++ eqcr->ci = qm_cl_in(EQCR_CI) & (QM_EQCR_SIZE - 1); ++ qm_cl_invalidate(EQCR_CI); ++ diff = qm_cyc_diff(QM_EQCR_SIZE, old_ci, eqcr->ci); ++ eqcr->available += diff; ++ return diff; ++} ++ ++static inline u8 qm_eqcr_get_ithresh(struct qm_portal *portal) ++{ ++ register struct qm_eqcr *eqcr = &portal->eqcr; ++ return eqcr->ithresh; ++} ++ ++static inline void qm_eqcr_set_ithresh(struct qm_portal *portal, u8 ithresh) ++{ ++ register struct qm_eqcr *eqcr = &portal->eqcr; ++ eqcr->ithresh = ithresh; ++ qm_out(EQCR_ITR, ithresh); ++} ++ ++static inline u8 qm_eqcr_get_avail(struct qm_portal *portal) ++{ ++ register struct qm_eqcr *eqcr = &portal->eqcr; ++ return eqcr->available; ++} ++ ++static inline u8 qm_eqcr_get_fill(struct qm_portal *portal) ++{ ++ register struct qm_eqcr *eqcr = &portal->eqcr; ++ return QM_EQCR_SIZE - 1 - eqcr->available; ++} ++ ++ ++/* ---------------- */ ++/* --- DQRR API --- */ ++ ++/* FIXME: many possible improvements; ++ * - look at changing the API to use pointer rather than index parameters now ++ * that 'cursor' is a pointer, ++ * - consider moving other parameters to pointer if it could help (ci) ++ */ ++ ++#define DQRR_CARRYCLEAR(p) \ ++ (void *)((unsigned long)(p) & (~(unsigned long)(QM_DQRR_SIZE << 6))) ++ ++static inline u8 DQRR_PTR2IDX(const struct qm_dqrr_entry *e) ++{ ++ return ((uintptr_t)e >> 6) & (QM_DQRR_SIZE - 1); ++} ++ ++static inline const struct qm_dqrr_entry *DQRR_INC( ++ const struct qm_dqrr_entry *e) ++{ ++ return DQRR_CARRYCLEAR(e + 1); ++} ++ ++static inline void qm_dqrr_set_maxfill(struct qm_portal *portal, u8 mf) ++{ ++ qm_out(CFG, (qm_in(CFG) & 0xff0fffff) | ++ ((mf & (QM_DQRR_SIZE - 1)) << 20)); ++} ++ ++static inline void qm_dqrr_cci_consume(struct qm_portal *portal, u8 num) ++{ ++ register struct qm_dqrr *dqrr = &portal->dqrr; ++ DPA_ASSERT(dqrr->cmode == qm_dqrr_cci); ++ dqrr->ci = (dqrr->ci + num) & (QM_DQRR_SIZE - 1); ++ qm_out(DQRR_CI_CINH, dqrr->ci); ++} ++ ++static inline void qm_dqrr_cce_consume(struct qm_portal *portal, u8 num) ++{ ++ register struct qm_dqrr *dqrr = &portal->dqrr; ++ DPA_ASSERT(dqrr->cmode == qm_dqrr_cce); ++ dqrr->ci = (dqrr->ci + num) & (QM_DQRR_SIZE - 1); ++ qm_cl_out(DQRR_CI, dqrr->ci); ++} ++ ++static inline void qm_dqrr_cdc_consume_n(struct qm_portal *portal, u16 bitmask) ++{ ++ __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; ++ DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc); ++ qm_out(DQRR_DCAP, (1 << 8) | /* DQRR_DCAP::S */ ++ ((u32)bitmask << 16)); /* DQRR_DCAP::DCAP_CI */ ++ dqrr->ci = qm_in(DQRR_CI_CINH) & (QM_DQRR_SIZE - 1); ++ dqrr->fill = qm_cyc_diff(QM_DQRR_SIZE, dqrr->ci, dqrr->pi); ++} ++ ++static inline int qm_dqrr_init(struct qm_portal *portal, ++ const struct qm_portal_config *config, ++ enum qm_dqrr_dmode dmode, ++ __maybe_unused enum qm_dqrr_pmode pmode, ++ enum qm_dqrr_cmode cmode, u8 max_fill) ++{ ++ register struct qm_dqrr *dqrr = &portal->dqrr; ++ u32 cfg; ++ ++ /* Make sure the DQRR will be idle when we enable */ ++ qm_out(DQRR_SDQCR, 0); ++ qm_out(DQRR_VDQCR, 0); ++ qm_out(DQRR_PDQCR, 0); ++ dqrr->ring = portal->addr.addr_ce + QM_CL_DQRR; ++ dqrr->pi = qm_in(DQRR_PI_CINH) & (QM_DQRR_SIZE - 1); ++ dqrr->ci = qm_in(DQRR_CI_CINH) & (QM_DQRR_SIZE - 1); ++ dqrr->cursor = dqrr->ring + dqrr->ci; ++ dqrr->fill = qm_cyc_diff(QM_DQRR_SIZE, dqrr->ci, dqrr->pi); ++ dqrr->vbit = (qm_in(DQRR_PI_CINH) & QM_DQRR_SIZE) ? ++ QM_DQRR_VERB_VBIT : 0; ++ dqrr->ithresh = qm_in(DQRR_ITR); ++ ++ /* Free up pending DQRR entries if any as per current DCM */ ++ if (dqrr->fill) { ++ enum qm_dqrr_cmode dcm = (qm_in(CFG) >> 16) & 3; ++ ++#ifdef CONFIG_FSL_DPA_CHECKING ++ dqrr->cmode = dcm; ++#endif ++ switch (dcm) { ++ case qm_dqrr_cci: ++ qm_dqrr_cci_consume(portal, dqrr->fill); ++ break; ++ case qm_dqrr_cce: ++ qm_dqrr_cce_consume(portal, dqrr->fill); ++ break; ++ case qm_dqrr_cdc: ++ qm_dqrr_cdc_consume_n(portal, (QM_DQRR_SIZE - 1)); ++ break; ++ default: ++ DPA_ASSERT(0); ++ } ++ } ++ ++#ifdef CONFIG_FSL_DPA_CHECKING ++ dqrr->dmode = dmode; ++ dqrr->pmode = pmode; ++ dqrr->cmode = cmode; ++#endif ++ /* Invalidate every ring entry before beginning */ ++ for (cfg = 0; cfg < QM_DQRR_SIZE; cfg++) ++ dcbi(qm_cl(dqrr->ring, cfg)); ++ cfg = (qm_in(CFG) & 0xff000f00) | ++ ((max_fill & (QM_DQRR_SIZE - 1)) << 20) | /* DQRR_MF */ ++ ((dmode & 1) << 18) | /* DP */ ++ ((cmode & 3) << 16) | /* DCM */ ++ 0xa0 | /* RE+SE */ ++ (0 ? 0x40 : 0) | /* Ignore RP */ ++ (0 ? 0x10 : 0); /* Ignore SP */ ++ qm_out(CFG, cfg); ++ qm_dqrr_set_maxfill(portal, max_fill); ++ return 0; ++} ++ ++static inline void qm_dqrr_finish(struct qm_portal *portal) ++{ ++ __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ if ((dqrr->cmode != qm_dqrr_cdc) && ++ (dqrr->ci != DQRR_PTR2IDX(dqrr->cursor))) ++ pr_crit("Ignoring completed DQRR entries\n"); ++#endif ++} ++ ++static inline const struct qm_dqrr_entry *qm_dqrr_current( ++ struct qm_portal *portal) ++{ ++ register struct qm_dqrr *dqrr = &portal->dqrr; ++ if (!dqrr->fill) ++ return NULL; ++ return dqrr->cursor; ++} ++ ++static inline u8 qm_dqrr_cursor(struct qm_portal *portal) ++{ ++ register struct qm_dqrr *dqrr = &portal->dqrr; ++ return DQRR_PTR2IDX(dqrr->cursor); ++} ++ ++static inline u8 qm_dqrr_next(struct qm_portal *portal) ++{ ++ register struct qm_dqrr *dqrr = &portal->dqrr; ++ DPA_ASSERT(dqrr->fill); ++ dqrr->cursor = DQRR_INC(dqrr->cursor); ++ return --dqrr->fill; ++} ++ ++static inline u8 qm_dqrr_pci_update(struct qm_portal *portal) ++{ ++ register struct qm_dqrr *dqrr = &portal->dqrr; ++ u8 diff, old_pi = dqrr->pi; ++ DPA_ASSERT(dqrr->pmode == qm_dqrr_pci); ++ dqrr->pi = qm_in(DQRR_PI_CINH) & (QM_DQRR_SIZE - 1); ++ diff = qm_cyc_diff(QM_DQRR_SIZE, old_pi, dqrr->pi); ++ dqrr->fill += diff; ++ return diff; ++} ++ ++static inline void qm_dqrr_pce_prefetch(struct qm_portal *portal) ++{ ++ __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; ++ DPA_ASSERT(dqrr->pmode == qm_dqrr_pce); ++ qm_cl_invalidate(DQRR_PI); ++ qm_cl_touch_ro(DQRR_PI); ++} ++ ++static inline u8 qm_dqrr_pce_update(struct qm_portal *portal) ++{ ++ register struct qm_dqrr *dqrr = &portal->dqrr; ++ u8 diff, old_pi = dqrr->pi; ++ DPA_ASSERT(dqrr->pmode == qm_dqrr_pce); ++ dqrr->pi = qm_cl_in(DQRR_PI) & (QM_DQRR_SIZE - 1); ++ diff = qm_cyc_diff(QM_DQRR_SIZE, old_pi, dqrr->pi); ++ dqrr->fill += diff; ++ return diff; ++} ++ ++static inline void qm_dqrr_pvb_update(struct qm_portal *portal) ++{ ++ register struct qm_dqrr *dqrr = &portal->dqrr; ++ const struct qm_dqrr_entry *res = qm_cl(dqrr->ring, dqrr->pi); ++ DPA_ASSERT(dqrr->pmode == qm_dqrr_pvb); ++#if (defined CONFIG_PPC || defined CONFIG_PPC64) && !defined CONFIG_FSL_PAMU ++ /* ++ * On PowerPC platforms if PAMU is not available we need to ++ * manually invalidate the cache. When PAMU is available the ++ * cache is updated by stashing operations generated by QMan ++ */ ++ dcbi(res); ++ dcbt_ro(res); ++#endif ++ ++ /* when accessing 'verb', use __raw_readb() to ensure that compiler ++ * inlining doesn't try to optimise out "excess reads". */ ++ if ((__raw_readb(&res->verb) & QM_DQRR_VERB_VBIT) == dqrr->vbit) { ++ dqrr->pi = (dqrr->pi + 1) & (QM_DQRR_SIZE - 1); ++ if (!dqrr->pi) ++ dqrr->vbit ^= QM_DQRR_VERB_VBIT; ++ dqrr->fill++; ++ } ++} ++ ++ ++static inline void qm_dqrr_cci_consume_to_current(struct qm_portal *portal) ++{ ++ register struct qm_dqrr *dqrr = &portal->dqrr; ++ DPA_ASSERT(dqrr->cmode == qm_dqrr_cci); ++ dqrr->ci = DQRR_PTR2IDX(dqrr->cursor); ++ qm_out(DQRR_CI_CINH, dqrr->ci); ++} ++ ++static inline void qm_dqrr_cce_prefetch(struct qm_portal *portal) ++{ ++ __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; ++ DPA_ASSERT(dqrr->cmode == qm_dqrr_cce); ++ qm_cl_invalidate(DQRR_CI); ++ qm_cl_touch_rw(DQRR_CI); ++} ++ ++static inline void qm_dqrr_cce_consume_to_current(struct qm_portal *portal) ++{ ++ register struct qm_dqrr *dqrr = &portal->dqrr; ++ DPA_ASSERT(dqrr->cmode == qm_dqrr_cce); ++ dqrr->ci = DQRR_PTR2IDX(dqrr->cursor); ++ qm_cl_out(DQRR_CI, dqrr->ci); ++} ++ ++static inline void qm_dqrr_cdc_consume_1(struct qm_portal *portal, u8 idx, ++ int park) ++{ ++ __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; ++ DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc); ++ DPA_ASSERT(idx < QM_DQRR_SIZE); ++ qm_out(DQRR_DCAP, (0 << 8) | /* S */ ++ ((park ? 1 : 0) << 6) | /* PK */ ++ idx); /* DCAP_CI */ ++} ++ ++static inline void qm_dqrr_cdc_consume_1ptr(struct qm_portal *portal, ++ const struct qm_dqrr_entry *dq, ++ int park) ++{ ++ __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; ++ u8 idx = DQRR_PTR2IDX(dq); ++ DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc); ++ DPA_ASSERT((dqrr->ring + idx) == dq); ++ DPA_ASSERT(idx < QM_DQRR_SIZE); ++ qm_out(DQRR_DCAP, (0 << 8) | /* DQRR_DCAP::S */ ++ ((park ? 1 : 0) << 6) | /* DQRR_DCAP::PK */ ++ idx); /* DQRR_DCAP::DCAP_CI */ ++} ++ ++static inline u8 qm_dqrr_cdc_cci(struct qm_portal *portal) ++{ ++ __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; ++ DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc); ++ return qm_in(DQRR_CI_CINH) & (QM_DQRR_SIZE - 1); ++} ++ ++static inline void qm_dqrr_cdc_cce_prefetch(struct qm_portal *portal) ++{ ++ __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; ++ DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc); ++ qm_cl_invalidate(DQRR_CI); ++ qm_cl_touch_ro(DQRR_CI); ++} ++ ++static inline u8 qm_dqrr_cdc_cce(struct qm_portal *portal) ++{ ++ __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; ++ DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc); ++ return qm_cl_in(DQRR_CI) & (QM_DQRR_SIZE - 1); ++} ++ ++static inline u8 qm_dqrr_get_ci(struct qm_portal *portal) ++{ ++ register struct qm_dqrr *dqrr = &portal->dqrr; ++ DPA_ASSERT(dqrr->cmode != qm_dqrr_cdc); ++ return dqrr->ci; ++} ++ ++static inline void qm_dqrr_park(struct qm_portal *portal, u8 idx) ++{ ++ __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr; ++ DPA_ASSERT(dqrr->cmode != qm_dqrr_cdc); ++ qm_out(DQRR_DCAP, (0 << 8) | /* S */ ++ (1 << 6) | /* PK */ ++ (idx & (QM_DQRR_SIZE - 1))); /* DCAP_CI */ ++} ++ ++static inline void qm_dqrr_park_current(struct qm_portal *portal) ++{ ++ register struct qm_dqrr *dqrr = &portal->dqrr; ++ DPA_ASSERT(dqrr->cmode != qm_dqrr_cdc); ++ qm_out(DQRR_DCAP, (0 << 8) | /* S */ ++ (1 << 6) | /* PK */ ++ DQRR_PTR2IDX(dqrr->cursor)); /* DCAP_CI */ ++} ++ ++static inline void qm_dqrr_sdqcr_set(struct qm_portal *portal, u32 sdqcr) ++{ ++ qm_out(DQRR_SDQCR, sdqcr); ++} ++ ++static inline u32 qm_dqrr_sdqcr_get(struct qm_portal *portal) ++{ ++ return qm_in(DQRR_SDQCR); ++} ++ ++static inline void qm_dqrr_vdqcr_set(struct qm_portal *portal, u32 vdqcr) ++{ ++ qm_out(DQRR_VDQCR, vdqcr); ++} ++ ++static inline u32 qm_dqrr_vdqcr_get(struct qm_portal *portal) ++{ ++ return qm_in(DQRR_VDQCR); ++} ++ ++static inline void qm_dqrr_pdqcr_set(struct qm_portal *portal, u32 pdqcr) ++{ ++ qm_out(DQRR_PDQCR, pdqcr); ++} ++ ++static inline u32 qm_dqrr_pdqcr_get(struct qm_portal *portal) ++{ ++ return qm_in(DQRR_PDQCR); ++} ++ ++static inline u8 qm_dqrr_get_ithresh(struct qm_portal *portal) ++{ ++ register struct qm_dqrr *dqrr = &portal->dqrr; ++ return dqrr->ithresh; ++} ++ ++static inline void qm_dqrr_set_ithresh(struct qm_portal *portal, u8 ithresh) ++{ ++ qm_out(DQRR_ITR, ithresh); ++} ++ ++static inline u8 qm_dqrr_get_maxfill(struct qm_portal *portal) ++{ ++ return (qm_in(CFG) & 0x00f00000) >> 20; ++} ++ ++ ++/* -------------- */ ++/* --- MR API --- */ ++ ++#define MR_CARRYCLEAR(p) \ ++ (void *)((unsigned long)(p) & (~(unsigned long)(QM_MR_SIZE << 6))) ++ ++static inline u8 MR_PTR2IDX(const struct qm_mr_entry *e) ++{ ++ return ((uintptr_t)e >> 6) & (QM_MR_SIZE - 1); ++} ++ ++static inline const struct qm_mr_entry *MR_INC(const struct qm_mr_entry *e) ++{ ++ return MR_CARRYCLEAR(e + 1); ++} ++ ++static inline int qm_mr_init(struct qm_portal *portal, enum qm_mr_pmode pmode, ++ enum qm_mr_cmode cmode) ++{ ++ register struct qm_mr *mr = &portal->mr; ++ u32 cfg; ++ ++ mr->ring = portal->addr.addr_ce + QM_CL_MR; ++ mr->pi = qm_in(MR_PI_CINH) & (QM_MR_SIZE - 1); ++ mr->ci = qm_in(MR_CI_CINH) & (QM_MR_SIZE - 1); ++ mr->cursor = mr->ring + mr->ci; ++ mr->fill = qm_cyc_diff(QM_MR_SIZE, mr->ci, mr->pi); ++ mr->vbit = (qm_in(MR_PI_CINH) & QM_MR_SIZE) ? QM_MR_VERB_VBIT : 0; ++ mr->ithresh = qm_in(MR_ITR); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ mr->pmode = pmode; ++ mr->cmode = cmode; ++#endif ++ cfg = (qm_in(CFG) & 0xfffff0ff) | ++ ((cmode & 1) << 8); /* QCSP_CFG:MM */ ++ qm_out(CFG, cfg); ++ return 0; ++} ++ ++static inline void qm_mr_finish(struct qm_portal *portal) ++{ ++ register struct qm_mr *mr = &portal->mr; ++ if (mr->ci != MR_PTR2IDX(mr->cursor)) ++ pr_crit("Ignoring completed MR entries\n"); ++} ++ ++static inline const struct qm_mr_entry *qm_mr_current(struct qm_portal *portal) ++{ ++ register struct qm_mr *mr = &portal->mr; ++ if (!mr->fill) ++ return NULL; ++ return mr->cursor; ++} ++ ++static inline u8 qm_mr_cursor(struct qm_portal *portal) ++{ ++ register struct qm_mr *mr = &portal->mr; ++ return MR_PTR2IDX(mr->cursor); ++} ++ ++static inline u8 qm_mr_next(struct qm_portal *portal) ++{ ++ register struct qm_mr *mr = &portal->mr; ++ DPA_ASSERT(mr->fill); ++ mr->cursor = MR_INC(mr->cursor); ++ return --mr->fill; ++} ++ ++static inline u8 qm_mr_pci_update(struct qm_portal *portal) ++{ ++ register struct qm_mr *mr = &portal->mr; ++ u8 diff, old_pi = mr->pi; ++ DPA_ASSERT(mr->pmode == qm_mr_pci); ++ mr->pi = qm_in(MR_PI_CINH); ++ diff = qm_cyc_diff(QM_MR_SIZE, old_pi, mr->pi); ++ mr->fill += diff; ++ return diff; ++} ++ ++static inline void qm_mr_pce_prefetch(struct qm_portal *portal) ++{ ++ __maybe_unused register struct qm_mr *mr = &portal->mr; ++ DPA_ASSERT(mr->pmode == qm_mr_pce); ++ qm_cl_invalidate(MR_PI); ++ qm_cl_touch_ro(MR_PI); ++} ++ ++static inline u8 qm_mr_pce_update(struct qm_portal *portal) ++{ ++ register struct qm_mr *mr = &portal->mr; ++ u8 diff, old_pi = mr->pi; ++ DPA_ASSERT(mr->pmode == qm_mr_pce); ++ mr->pi = qm_cl_in(MR_PI) & (QM_MR_SIZE - 1); ++ diff = qm_cyc_diff(QM_MR_SIZE, old_pi, mr->pi); ++ mr->fill += diff; ++ return diff; ++} ++ ++static inline void qm_mr_pvb_update(struct qm_portal *portal) ++{ ++ register struct qm_mr *mr = &portal->mr; ++ const struct qm_mr_entry *res = qm_cl(mr->ring, mr->pi); ++ DPA_ASSERT(mr->pmode == qm_mr_pvb); ++ /* when accessing 'verb', use __raw_readb() to ensure that compiler ++ * inlining doesn't try to optimise out "excess reads". */ ++ if ((__raw_readb(&res->verb) & QM_MR_VERB_VBIT) == mr->vbit) { ++ mr->pi = (mr->pi + 1) & (QM_MR_SIZE - 1); ++ if (!mr->pi) ++ mr->vbit ^= QM_MR_VERB_VBIT; ++ mr->fill++; ++ res = MR_INC(res); ++ } ++ dcbit_ro(res); ++} ++ ++static inline void qm_mr_cci_consume(struct qm_portal *portal, u8 num) ++{ ++ register struct qm_mr *mr = &portal->mr; ++ DPA_ASSERT(mr->cmode == qm_mr_cci); ++ mr->ci = (mr->ci + num) & (QM_MR_SIZE - 1); ++ qm_out(MR_CI_CINH, mr->ci); ++} ++ ++static inline void qm_mr_cci_consume_to_current(struct qm_portal *portal) ++{ ++ register struct qm_mr *mr = &portal->mr; ++ DPA_ASSERT(mr->cmode == qm_mr_cci); ++ mr->ci = MR_PTR2IDX(mr->cursor); ++ qm_out(MR_CI_CINH, mr->ci); ++} ++ ++static inline void qm_mr_cce_prefetch(struct qm_portal *portal) ++{ ++ __maybe_unused register struct qm_mr *mr = &portal->mr; ++ DPA_ASSERT(mr->cmode == qm_mr_cce); ++ qm_cl_invalidate(MR_CI); ++ qm_cl_touch_rw(MR_CI); ++} ++ ++static inline void qm_mr_cce_consume(struct qm_portal *portal, u8 num) ++{ ++ register struct qm_mr *mr = &portal->mr; ++ DPA_ASSERT(mr->cmode == qm_mr_cce); ++ mr->ci = (mr->ci + num) & (QM_MR_SIZE - 1); ++ qm_cl_out(MR_CI, mr->ci); ++} ++ ++static inline void qm_mr_cce_consume_to_current(struct qm_portal *portal) ++{ ++ register struct qm_mr *mr = &portal->mr; ++ DPA_ASSERT(mr->cmode == qm_mr_cce); ++ mr->ci = MR_PTR2IDX(mr->cursor); ++ qm_cl_out(MR_CI, mr->ci); ++} ++ ++static inline u8 qm_mr_get_ci(struct qm_portal *portal) ++{ ++ register struct qm_mr *mr = &portal->mr; ++ return mr->ci; ++} ++ ++static inline u8 qm_mr_get_ithresh(struct qm_portal *portal) ++{ ++ register struct qm_mr *mr = &portal->mr; ++ return mr->ithresh; ++} ++ ++static inline void qm_mr_set_ithresh(struct qm_portal *portal, u8 ithresh) ++{ ++ qm_out(MR_ITR, ithresh); ++} ++ ++ ++/* ------------------------------ */ ++/* --- Management command API --- */ ++ ++static inline int qm_mc_init(struct qm_portal *portal) ++{ ++ register struct qm_mc *mc = &portal->mc; ++ mc->cr = portal->addr.addr_ce + QM_CL_CR; ++ mc->rr = portal->addr.addr_ce + QM_CL_RR0; ++ mc->rridx = (__raw_readb(&mc->cr->__dont_write_directly__verb) & ++ QM_MCC_VERB_VBIT) ? 0 : 1; ++ mc->vbit = mc->rridx ? QM_MCC_VERB_VBIT : 0; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ mc->state = qman_mc_idle; ++#endif ++ return 0; ++} ++ ++static inline void qm_mc_finish(struct qm_portal *portal) ++{ ++ __maybe_unused register struct qm_mc *mc = &portal->mc; ++ DPA_ASSERT(mc->state == qman_mc_idle); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ if (mc->state != qman_mc_idle) ++ pr_crit("Losing incomplete MC command\n"); ++#endif ++} ++ ++static inline struct qm_mc_command *qm_mc_start(struct qm_portal *portal) ++{ ++ register struct qm_mc *mc = &portal->mc; ++ DPA_ASSERT(mc->state == qman_mc_idle); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ mc->state = qman_mc_user; ++#endif ++#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) ++ dcbz_64(mc->cr); ++#endif ++ return mc->cr; ++} ++ ++static inline void qm_mc_abort(struct qm_portal *portal) ++{ ++ __maybe_unused register struct qm_mc *mc = &portal->mc; ++ DPA_ASSERT(mc->state == qman_mc_user); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ mc->state = qman_mc_idle; ++#endif ++} ++ ++static inline void qm_mc_commit(struct qm_portal *portal, u8 myverb) ++{ ++ register struct qm_mc *mc = &portal->mc; ++ struct qm_mc_result *rr = mc->rr + mc->rridx; ++ DPA_ASSERT(mc->state == qman_mc_user); ++ lwsync(); ++ mc->cr->__dont_write_directly__verb = myverb | mc->vbit; ++ dcbf(mc->cr); ++ dcbit_ro(rr); ++#ifdef CONFIG_FSL_DPA_CHECKING ++ mc->state = qman_mc_hw; ++#endif ++} ++ ++static inline struct qm_mc_result *qm_mc_result(struct qm_portal *portal) ++{ ++ register struct qm_mc *mc = &portal->mc; ++ struct qm_mc_result *rr = mc->rr + mc->rridx; ++ DPA_ASSERT(mc->state == qman_mc_hw); ++ /* The inactive response register's verb byte always returns zero until ++ * its command is submitted and completed. This includes the valid-bit, ++ * in case you were wondering... */ ++ if (!__raw_readb(&rr->verb)) { ++ dcbit_ro(rr); ++ return NULL; ++ } ++ mc->rridx ^= 1; ++ mc->vbit ^= QM_MCC_VERB_VBIT; ++#ifdef CONFIG_FSL_DPA_CHECKING ++ mc->state = qman_mc_idle; ++#endif ++ return rr; ++} ++ ++ ++/* ------------------------------------- */ ++/* --- Portal interrupt register API --- */ ++ ++static inline int qm_isr_init(__always_unused struct qm_portal *portal) ++{ ++ return 0; ++} ++ ++static inline void qm_isr_finish(__always_unused struct qm_portal *portal) ++{ ++} ++ ++static inline void qm_isr_set_iperiod(struct qm_portal *portal, u16 iperiod) ++{ ++ qm_out(ITPR, iperiod); ++} ++ ++static inline u32 __qm_isr_read(struct qm_portal *portal, enum qm_isr_reg n) ++{ ++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) ++ return __qm_in(&portal->addr, QM_REG_ISR + (n << 6)); ++#else ++ return __qm_in(&portal->addr, QM_REG_ISR + (n << 2)); ++#endif ++} ++ ++static inline void __qm_isr_write(struct qm_portal *portal, enum qm_isr_reg n, ++ u32 val) ++{ ++#if defined(CONFIG_ARM) || defined(CONFIG_ARM64) ++ __qm_out(&portal->addr, QM_REG_ISR + (n << 6), val); ++#else ++ __qm_out(&portal->addr, QM_REG_ISR + (n << 2), val); ++#endif ++} ++ ++/* Cleanup FQs */ ++static inline int qm_shutdown_fq(struct qm_portal **portal, int portal_count, ++ u32 fqid) ++{ ++ ++ struct qm_mc_command *mcc; ++ struct qm_mc_result *mcr; ++ u8 state; ++ int orl_empty, fq_empty, i, drain = 0; ++ u32 result; ++ u32 channel, wq; ++ u16 dest_wq; ++ ++ /* Determine the state of the FQID */ ++ mcc = qm_mc_start(portal[0]); ++ mcc->queryfq_np.fqid = cpu_to_be32(fqid); ++ qm_mc_commit(portal[0], QM_MCC_VERB_QUERYFQ_NP); ++ while (!(mcr = qm_mc_result(portal[0]))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ_NP); ++ state = mcr->queryfq_np.state & QM_MCR_NP_STATE_MASK; ++ if (state == QM_MCR_NP_STATE_OOS) ++ return 0; /* Already OOS, no need to do anymore checks */ ++ ++ /* Query which channel the FQ is using */ ++ mcc = qm_mc_start(portal[0]); ++ mcc->queryfq.fqid = cpu_to_be32(fqid); ++ qm_mc_commit(portal[0], QM_MCC_VERB_QUERYFQ); ++ while (!(mcr = qm_mc_result(portal[0]))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ); ++ ++ /* Need to store these since the MCR gets reused */ ++ dest_wq = be16_to_cpu(mcr->queryfq.fqd.dest_wq); ++ wq = dest_wq & 0x7; ++ channel = dest_wq>>3; ++ ++ switch (state) { ++ case QM_MCR_NP_STATE_TEN_SCHED: ++ case QM_MCR_NP_STATE_TRU_SCHED: ++ case QM_MCR_NP_STATE_ACTIVE: ++ case QM_MCR_NP_STATE_PARKED: ++ orl_empty = 0; ++ mcc = qm_mc_start(portal[0]); ++ mcc->alterfq.fqid = cpu_to_be32(fqid); ++ qm_mc_commit(portal[0], QM_MCC_VERB_ALTER_RETIRE); ++ while (!(mcr = qm_mc_result(portal[0]))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == ++ QM_MCR_VERB_ALTER_RETIRE); ++ result = mcr->result; /* Make a copy as we reuse MCR below */ ++ ++ if (result == QM_MCR_RESULT_PENDING) { ++ /* Need to wait for the FQRN in the message ring, which ++ will only occur once the FQ has been drained. In ++ order for the FQ to drain the portal needs to be set ++ to dequeue from the channel the FQ is scheduled on */ ++ const struct qm_mr_entry *msg; ++ const struct qm_dqrr_entry *dqrr = NULL; ++ int found_fqrn = 0; ++ u16 dequeue_wq = 0; ++ ++ /* Flag that we need to drain FQ */ ++ drain = 1; ++ ++ if (channel >= qm_channel_pool1 && ++ channel < (qm_channel_pool1 + 15)) { ++ /* Pool channel, enable the bit in the portal */ ++ dequeue_wq = (channel - ++ qm_channel_pool1 + 1)<<4 | wq; ++ } else if (channel < qm_channel_pool1) { ++ /* Dedicated channel */ ++ dequeue_wq = wq; ++ } else { ++ pr_info("Cannot recover FQ 0x%x, it is " ++ "scheduled on channel 0x%x", ++ fqid, channel); ++ return -EBUSY; ++ } ++ /* Set the sdqcr to drain this channel */ ++ if (channel < qm_channel_pool1) ++ for (i = 0; i < portal_count; i++) ++ qm_dqrr_sdqcr_set(portal[i], ++ QM_SDQCR_TYPE_ACTIVE | ++ QM_SDQCR_CHANNELS_DEDICATED); ++ else ++ for (i = 0; i < portal_count; i++) ++ qm_dqrr_sdqcr_set( ++ portal[i], ++ QM_SDQCR_TYPE_ACTIVE | ++ QM_SDQCR_CHANNELS_POOL_CONV ++ (channel)); ++ while (!found_fqrn) { ++ /* Keep draining DQRR while checking the MR*/ ++ for (i = 0; i < portal_count; i++) { ++ qm_dqrr_pvb_update(portal[i]); ++ dqrr = qm_dqrr_current(portal[i]); ++ while (dqrr) { ++ qm_dqrr_cdc_consume_1ptr( ++ portal[i], dqrr, 0); ++ qm_dqrr_pvb_update(portal[i]); ++ qm_dqrr_next(portal[i]); ++ dqrr = qm_dqrr_current( ++ portal[i]); ++ } ++ /* Process message ring too */ ++ qm_mr_pvb_update(portal[i]); ++ msg = qm_mr_current(portal[i]); ++ while (msg) { ++ if ((msg->verb & ++ QM_MR_VERB_TYPE_MASK) ++ == QM_MR_VERB_FQRN) ++ found_fqrn = 1; ++ qm_mr_next(portal[i]); ++ qm_mr_cci_consume_to_current( ++ portal[i]); ++ qm_mr_pvb_update(portal[i]); ++ msg = qm_mr_current(portal[i]); ++ } ++ cpu_relax(); ++ } ++ } ++ } ++ if (result != QM_MCR_RESULT_OK && ++ result != QM_MCR_RESULT_PENDING) { ++ /* error */ ++ pr_err("qman_retire_fq failed on FQ 0x%x, result=0x%x\n", ++ fqid, result); ++ return -1; ++ } ++ if (!(mcr->alterfq.fqs & QM_MCR_FQS_ORLPRESENT)) { ++ /* ORL had no entries, no need to wait until the ++ ERNs come in */ ++ orl_empty = 1; ++ } ++ /* Retirement succeeded, check to see if FQ needs ++ to be drained */ ++ if (drain || mcr->alterfq.fqs & QM_MCR_FQS_NOTEMPTY) { ++ /* FQ is Not Empty, drain using volatile DQ commands */ ++ fq_empty = 0; ++ do { ++ const struct qm_dqrr_entry *dqrr = NULL; ++ u32 vdqcr = fqid | QM_VDQCR_NUMFRAMES_SET(3); ++ qm_dqrr_vdqcr_set(portal[0], vdqcr); ++ ++ /* Wait for a dequeue to occur */ ++ while (dqrr == NULL) { ++ qm_dqrr_pvb_update(portal[0]); ++ dqrr = qm_dqrr_current(portal[0]); ++ if (!dqrr) ++ cpu_relax(); ++ } ++ /* Process the dequeues, making sure to ++ empty the ring completely */ ++ while (dqrr) { ++ if (be32_to_cpu(dqrr->fqid) == fqid && ++ dqrr->stat & QM_DQRR_STAT_FQ_EMPTY) ++ fq_empty = 1; ++ qm_dqrr_cdc_consume_1ptr(portal[0], ++ dqrr, 0); ++ qm_dqrr_pvb_update(portal[0]); ++ qm_dqrr_next(portal[0]); ++ dqrr = qm_dqrr_current(portal[0]); ++ } ++ } while (fq_empty == 0); ++ } ++ for (i = 0; i < portal_count; i++) ++ qm_dqrr_sdqcr_set(portal[i], 0); ++ ++ /* Wait for the ORL to have been completely drained */ ++ while (orl_empty == 0) { ++ const struct qm_mr_entry *msg; ++ qm_mr_pvb_update(portal[0]); ++ msg = qm_mr_current(portal[0]); ++ while (msg) { ++ if ((msg->verb & QM_MR_VERB_TYPE_MASK) == ++ QM_MR_VERB_FQRL) ++ orl_empty = 1; ++ qm_mr_next(portal[0]); ++ qm_mr_cci_consume_to_current(portal[0]); ++ qm_mr_pvb_update(portal[0]); ++ msg = qm_mr_current(portal[0]); ++ } ++ cpu_relax(); ++ } ++ mcc = qm_mc_start(portal[0]); ++ mcc->alterfq.fqid = cpu_to_be32(fqid); ++ qm_mc_commit(portal[0], QM_MCC_VERB_ALTER_OOS); ++ while (!(mcr = qm_mc_result(portal[0]))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == ++ QM_MCR_VERB_ALTER_OOS); ++ if (mcr->result != QM_MCR_RESULT_OK) { ++ pr_err("OOS after drain Failed on FQID 0x%x, result 0x%x\n", ++ fqid, mcr->result); ++ return -1; ++ } ++ return 0; ++ case QM_MCR_NP_STATE_RETIRED: ++ /* Send OOS Command */ ++ mcc = qm_mc_start(portal[0]); ++ mcc->alterfq.fqid = cpu_to_be32(fqid); ++ qm_mc_commit(portal[0], QM_MCC_VERB_ALTER_OOS); ++ while (!(mcr = qm_mc_result(portal[0]))) ++ cpu_relax(); ++ DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == ++ QM_MCR_VERB_ALTER_OOS); ++ if (mcr->result) { ++ pr_err("OOS Failed on FQID 0x%x\n", fqid); ++ return -1; ++ } ++ return 0; ++ } ++ return -1; ++} +diff --git a/drivers/staging/fsl_qbman/qman_private.h b/drivers/staging/fsl_qbman/qman_private.h +new file mode 100644 +index 00000000..ee025cff +--- /dev/null ++++ b/drivers/staging/fsl_qbman/qman_private.h +@@ -0,0 +1,398 @@ ++/* Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "dpa_sys.h" ++#include ++#include ++ ++#if defined(CONFIG_FSL_PAMU) ++#include ++#endif ++ ++#if !defined(CONFIG_FSL_QMAN_FQ_LOOKUP) && defined(CONFIG_PPC64) ++#error "_PPC64 requires _FSL_QMAN_FQ_LOOKUP" ++#endif ++ ++#define QBMAN_ANY_PORTAL_IDX 0xffffffff ++ /* ----------------- */ ++ /* Congestion Groups */ ++ /* ----------------- */ ++/* This wrapper represents a bit-array for the state of the 256 Qman congestion ++ * groups. Is also used as a *mask* for congestion groups, eg. so we ignore ++ * those that don't concern us. We harness the structure and accessor details ++ * already used in the management command to query congestion groups. */ ++struct qman_cgrs { ++ struct __qm_mcr_querycongestion q; ++}; ++static inline void qman_cgrs_init(struct qman_cgrs *c) ++{ ++ memset(c, 0, sizeof(*c)); ++} ++static inline void qman_cgrs_fill(struct qman_cgrs *c) ++{ ++ memset(c, 0xff, sizeof(*c)); ++} ++static inline int qman_cgrs_get(struct qman_cgrs *c, int num) ++{ ++ return QM_MCR_QUERYCONGESTION(&c->q, num); ++} ++static inline void qman_cgrs_set(struct qman_cgrs *c, int num) ++{ ++ c->q.__state[__CGR_WORD(num)] |= (0x80000000 >> __CGR_SHIFT(num)); ++} ++static inline void qman_cgrs_unset(struct qman_cgrs *c, int num) ++{ ++ c->q.__state[__CGR_WORD(num)] &= ~(0x80000000 >> __CGR_SHIFT(num)); ++} ++static inline int qman_cgrs_next(struct qman_cgrs *c, int num) ++{ ++ while ((++num < __CGR_NUM) && !qman_cgrs_get(c, num)) ++ ; ++ return num; ++} ++static inline void qman_cgrs_cp(struct qman_cgrs *dest, ++ const struct qman_cgrs *src) ++{ ++ *dest = *src; ++} ++static inline void qman_cgrs_and(struct qman_cgrs *dest, ++ const struct qman_cgrs *a, const struct qman_cgrs *b) ++{ ++ int ret; ++ u32 *_d = dest->q.__state; ++ const u32 *_a = a->q.__state; ++ const u32 *_b = b->q.__state; ++ for (ret = 0; ret < 8; ret++) ++ *(_d++) = *(_a++) & *(_b++); ++} ++static inline void qman_cgrs_xor(struct qman_cgrs *dest, ++ const struct qman_cgrs *a, const struct qman_cgrs *b) ++{ ++ int ret; ++ u32 *_d = dest->q.__state; ++ const u32 *_a = a->q.__state; ++ const u32 *_b = b->q.__state; ++ for (ret = 0; ret < 8; ret++) ++ *(_d++) = *(_a++) ^ *(_b++); ++} ++ ++ /* ----------------------- */ ++ /* CEETM Congestion Groups */ ++ /* ----------------------- */ ++/* This wrapper represents a bit-array for the state of the 512 Qman CEETM ++ * congestion groups. ++ */ ++struct qman_ccgrs { ++ struct __qm_mcr_querycongestion q[2]; ++}; ++static inline void qman_ccgrs_init(struct qman_ccgrs *c) ++{ ++ memset(c, 0, sizeof(*c)); ++} ++static inline void qman_ccgrs_fill(struct qman_ccgrs *c) ++{ ++ memset(c, 0xff, sizeof(*c)); ++} ++static inline int qman_ccgrs_get(struct qman_ccgrs *c, int num) ++{ ++ if (num < __CGR_NUM) ++ return QM_MCR_QUERYCONGESTION(&c->q[0], num); ++ else ++ return QM_MCR_QUERYCONGESTION(&c->q[1], (num - __CGR_NUM)); ++} ++static inline int qman_ccgrs_next(struct qman_ccgrs *c, int num) ++{ ++ while ((++num < __CGR_NUM) && !qman_ccgrs_get(c, num)) ++ ; ++ return num; ++} ++static inline void qman_ccgrs_cp(struct qman_ccgrs *dest, ++ const struct qman_ccgrs *src) ++{ ++ *dest = *src; ++} ++static inline void qman_ccgrs_and(struct qman_ccgrs *dest, ++ const struct qman_ccgrs *a, const struct qman_ccgrs *b) ++{ ++ int ret, i; ++ u32 *_d; ++ const u32 *_a, *_b; ++ for (i = 0; i < 2; i++) { ++ _d = dest->q[i].__state; ++ _a = a->q[i].__state; ++ _b = b->q[i].__state; ++ for (ret = 0; ret < 8; ret++) ++ *(_d++) = *(_a++) & *(_b++); ++ } ++} ++static inline void qman_ccgrs_xor(struct qman_ccgrs *dest, ++ const struct qman_ccgrs *a, const struct qman_ccgrs *b) ++{ ++ int ret, i; ++ u32 *_d; ++ const u32 *_a, *_b; ++ for (i = 0; i < 2; i++) { ++ _d = dest->q[i].__state; ++ _a = a->q[i].__state; ++ _b = b->q[i].__state; ++ for (ret = 0; ret < 8; ret++) ++ *(_d++) = *(_a++) ^ *(_b++); ++ } ++} ++ ++/* used by CCSR and portal interrupt code */ ++enum qm_isr_reg { ++ qm_isr_status = 0, ++ qm_isr_enable = 1, ++ qm_isr_disable = 2, ++ qm_isr_inhibit = 3 ++}; ++ ++struct qm_portal_config { ++ /* Corenet portal addresses; ++ * [0]==cache-enabled, [1]==cache-inhibited. */ ++ __iomem void *addr_virt[2]; ++ struct resource addr_phys[2]; ++ struct device dev; ++ struct iommu_domain *iommu_domain; ++ /* Allow these to be joined in lists */ ++ struct list_head list; ++ /* User-visible portal configuration settings */ ++ struct qman_portal_config public_cfg; ++ /* power management saved data */ ++ u32 saved_isdr; ++}; ++ ++/* Revision info (for errata and feature handling) */ ++#define QMAN_REV11 0x0101 ++#define QMAN_REV12 0x0102 ++#define QMAN_REV20 0x0200 ++#define QMAN_REV30 0x0300 ++#define QMAN_REV31 0x0301 ++#define QMAN_REV32 0x0302 ++ ++/* QMan REV_2 register contains the Cfg option */ ++#define QMAN_REV_CFG_0 0x0 ++#define QMAN_REV_CFG_1 0x1 ++#define QMAN_REV_CFG_2 0x2 ++#define QMAN_REV_CFG_3 0x3 ++ ++extern u16 qman_ip_rev; /* 0 if uninitialised, otherwise QMAN_REVx */ ++extern u8 qman_ip_cfg; ++extern u32 qman_clk; ++extern u16 qman_portal_max; ++ ++#ifdef CONFIG_FSL_QMAN_CONFIG ++/* Hooks from qman_driver.c to qman_config.c */ ++int qman_init_ccsr(struct device_node *node); ++void qman_liodn_fixup(u16 channel); ++int qman_set_sdest(u16 channel, unsigned int cpu_idx); ++size_t get_qman_fqd_size(void); ++#else ++static inline size_t get_qman_fqd_size(void) ++{ ++ return (PAGE_SIZE << CONFIG_FSL_QMAN_FQD_SZ); ++} ++#endif ++ ++int qm_set_wpm(int wpm); ++int qm_get_wpm(int *wpm); ++ ++/* Hooks from qman_driver.c in to qman_high.c */ ++struct qman_portal *qman_create_portal( ++ struct qman_portal *portal, ++ const struct qm_portal_config *config, ++ const struct qman_cgrs *cgrs); ++ ++struct qman_portal *qman_create_affine_portal( ++ const struct qm_portal_config *config, ++ const struct qman_cgrs *cgrs); ++struct qman_portal *qman_create_affine_slave(struct qman_portal *redirect, ++ int cpu); ++const struct qm_portal_config *qman_destroy_affine_portal(void); ++void qman_destroy_portal(struct qman_portal *qm); ++ ++/* Hooks from fsl_usdpaa.c to qman_driver.c */ ++struct qm_portal_config *qm_get_unused_portal(void); ++struct qm_portal_config *qm_get_unused_portal_idx(uint32_t idx); ++ ++void qm_put_unused_portal(struct qm_portal_config *pcfg); ++void qm_set_liodns(struct qm_portal_config *pcfg); ++ ++/* This CGR feature is supported by h/w and required by unit-tests and the ++ * debugfs hooks, so is implemented in the driver. However it allows an explicit ++ * corruption of h/w fields by s/w that are usually incorruptible (because the ++ * counters are usually maintained entirely within h/w). As such, we declare ++ * this API internally. */ ++int qman_testwrite_cgr(struct qman_cgr *cgr, u64 i_bcnt, ++ struct qm_mcr_cgrtestwrite *result); ++ ++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP ++/* If the fq object pointer is greater than the size of context_b field, ++ * than a lookup table is required. */ ++int qman_setup_fq_lookup_table(size_t num_entries); ++#endif ++ ++ ++/*************************************************/ ++/* QMan s/w corenet portal, low-level i/face */ ++/*************************************************/ ++ ++/* Note: most functions are only used by the high-level interface, so are ++ * inlined from qman_low.h. The stuff below is for use by other parts of the ++ * driver. */ ++ ++/* For qm_dqrr_sdqcr_set(); Choose one SOURCE. Choose one COUNT. Choose one ++ * dequeue TYPE. Choose TOKEN (8-bit). ++ * If SOURCE == CHANNELS, ++ * Choose CHANNELS_DEDICATED and/or CHANNELS_POOL(n). ++ * You can choose DEDICATED_PRECEDENCE if the portal channel should have ++ * priority. ++ * If SOURCE == SPECIFICWQ, ++ * Either select the work-queue ID with SPECIFICWQ_WQ(), or select the ++ * channel (SPECIFICWQ_DEDICATED or SPECIFICWQ_POOL()) and specify the ++ * work-queue priority (0-7) with SPECIFICWQ_WQ() - either way, you get the ++ * same value. ++ */ ++#define QM_SDQCR_SOURCE_CHANNELS 0x0 ++#define QM_SDQCR_SOURCE_SPECIFICWQ 0x40000000 ++#define QM_SDQCR_COUNT_EXACT1 0x0 ++#define QM_SDQCR_COUNT_UPTO3 0x20000000 ++#define QM_SDQCR_DEDICATED_PRECEDENCE 0x10000000 ++#define QM_SDQCR_TYPE_MASK 0x03000000 ++#define QM_SDQCR_TYPE_NULL 0x0 ++#define QM_SDQCR_TYPE_PRIO_QOS 0x01000000 ++#define QM_SDQCR_TYPE_ACTIVE_QOS 0x02000000 ++#define QM_SDQCR_TYPE_ACTIVE 0x03000000 ++#define QM_SDQCR_TOKEN_MASK 0x00ff0000 ++#define QM_SDQCR_TOKEN_SET(v) (((v) & 0xff) << 16) ++#define QM_SDQCR_TOKEN_GET(v) (((v) >> 16) & 0xff) ++#define QM_SDQCR_CHANNELS_DEDICATED 0x00008000 ++#define QM_SDQCR_SPECIFICWQ_MASK 0x000000f7 ++#define QM_SDQCR_SPECIFICWQ_DEDICATED 0x00000000 ++#define QM_SDQCR_SPECIFICWQ_POOL(n) ((n) << 4) ++#define QM_SDQCR_SPECIFICWQ_WQ(n) (n) ++ ++/* For qm_dqrr_vdqcr_set(): use FQID(n) to fill in the frame queue ID */ ++#define QM_VDQCR_FQID_MASK 0x00ffffff ++#define QM_VDQCR_FQID(n) ((n) & QM_VDQCR_FQID_MASK) ++ ++/* For qm_dqrr_pdqcr_set(); Choose one MODE. Choose one COUNT. ++ * If MODE==SCHEDULED ++ * Choose SCHEDULED_CHANNELS or SCHEDULED_SPECIFICWQ. Choose one dequeue TYPE. ++ * If CHANNELS, ++ * Choose CHANNELS_DEDICATED and/or CHANNELS_POOL() channels. ++ * You can choose DEDICATED_PRECEDENCE if the portal channel should have ++ * priority. ++ * If SPECIFICWQ, ++ * Either select the work-queue ID with SPECIFICWQ_WQ(), or select the ++ * channel (SPECIFICWQ_DEDICATED or SPECIFICWQ_POOL()) and specify the ++ * work-queue priority (0-7) with SPECIFICWQ_WQ() - either way, you get the ++ * same value. ++ * If MODE==UNSCHEDULED ++ * Choose FQID(). ++ */ ++#define QM_PDQCR_MODE_SCHEDULED 0x0 ++#define QM_PDQCR_MODE_UNSCHEDULED 0x80000000 ++#define QM_PDQCR_SCHEDULED_CHANNELS 0x0 ++#define QM_PDQCR_SCHEDULED_SPECIFICWQ 0x40000000 ++#define QM_PDQCR_COUNT_EXACT1 0x0 ++#define QM_PDQCR_COUNT_UPTO3 0x20000000 ++#define QM_PDQCR_DEDICATED_PRECEDENCE 0x10000000 ++#define QM_PDQCR_TYPE_MASK 0x03000000 ++#define QM_PDQCR_TYPE_NULL 0x0 ++#define QM_PDQCR_TYPE_PRIO_QOS 0x01000000 ++#define QM_PDQCR_TYPE_ACTIVE_QOS 0x02000000 ++#define QM_PDQCR_TYPE_ACTIVE 0x03000000 ++#define QM_PDQCR_CHANNELS_DEDICATED 0x00008000 ++#define QM_PDQCR_CHANNELS_POOL(n) (0x00008000 >> (n)) ++#define QM_PDQCR_SPECIFICWQ_MASK 0x000000f7 ++#define QM_PDQCR_SPECIFICWQ_DEDICATED 0x00000000 ++#define QM_PDQCR_SPECIFICWQ_POOL(n) ((n) << 4) ++#define QM_PDQCR_SPECIFICWQ_WQ(n) (n) ++#define QM_PDQCR_FQID(n) ((n) & 0xffffff) ++ ++/* Used by all portal interrupt registers except 'inhibit' ++ * Channels with frame availability ++ */ ++#define QM_PIRQ_DQAVAIL 0x0000ffff ++ ++/* The DQAVAIL interrupt fields break down into these bits; */ ++#define QM_DQAVAIL_PORTAL 0x8000 /* Portal channel */ ++#define QM_DQAVAIL_POOL(n) (0x8000 >> (n)) /* Pool channel, n==[1..15] */ ++#define QM_DQAVAIL_MASK 0xffff ++/* This mask contains all the "irqsource" bits visible to API users */ ++#define QM_PIRQ_VISIBLE (QM_PIRQ_SLOW | QM_PIRQ_DQRI) ++ ++/* These are qm__(). So for example, qm_disable_write() means "write ++ * the disable register" rather than "disable the ability to write". */ ++#define qm_isr_status_read(qm) __qm_isr_read(qm, qm_isr_status) ++#define qm_isr_status_clear(qm, m) __qm_isr_write(qm, qm_isr_status, m) ++#define qm_isr_enable_read(qm) __qm_isr_read(qm, qm_isr_enable) ++#define qm_isr_enable_write(qm, v) __qm_isr_write(qm, qm_isr_enable, v) ++#define qm_isr_disable_read(qm) __qm_isr_read(qm, qm_isr_disable) ++#define qm_isr_disable_write(qm, v) __qm_isr_write(qm, qm_isr_disable, v) ++/* TODO: unfortunate name-clash here, reword? */ ++#define qm_isr_inhibit(qm) __qm_isr_write(qm, qm_isr_inhibit, 1) ++#define qm_isr_uninhibit(qm) __qm_isr_write(qm, qm_isr_inhibit, 0) ++ ++#ifdef CONFIG_FSL_QMAN_CONFIG ++int qman_have_ccsr(void); ++#else ++#define qman_have_ccsr 0 ++#endif ++ ++__init int qman_init(void); ++__init int qman_resource_init(void); ++ ++/* CEETM related */ ++#define QMAN_CEETM_MAX 2 ++extern u8 num_ceetms; ++extern struct qm_ceetm qman_ceetms[QMAN_CEETM_MAX]; ++int qman_sp_enable_ceetm_mode(enum qm_dc_portal portal, u16 sub_portal); ++int qman_sp_disable_ceetm_mode(enum qm_dc_portal portal, u16 sub_portal); ++int qman_ceetm_set_prescaler(enum qm_dc_portal portal); ++int qman_ceetm_get_prescaler(u16 *pres); ++int qman_ceetm_query_cq(unsigned int cqid, unsigned int dcpid, ++ struct qm_mcr_ceetm_cq_query *cq_query); ++int qman_ceetm_query_ccgr(struct qm_mcc_ceetm_ccgr_query *ccgr_query, ++ struct qm_mcr_ceetm_ccgr_query *response); ++int qman_ceetm_get_xsfdr(enum qm_dc_portal portal, unsigned int *num); ++ ++extern void *affine_portals[NR_CPUS]; ++const struct qm_portal_config *qman_get_qm_portal_config( ++ struct qman_portal *portal); ++ ++/* power management */ ++#ifdef CONFIG_SUSPEND ++void suspend_unused_qportal(void); ++void resume_unused_qportal(void); ++#endif +diff --git a/drivers/staging/fsl_qbman/qman_test.c b/drivers/staging/fsl_qbman/qman_test.c +new file mode 100644 +index 00000000..7995dd8c +--- /dev/null ++++ b/drivers/staging/fsl_qbman/qman_test.c +@@ -0,0 +1,57 @@ ++/* Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "qman_test.h" ++ ++MODULE_AUTHOR("Geoff Thorpe"); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_DESCRIPTION("Qman testing"); ++ ++static int test_init(void) ++{ ++ int loop = 1; ++ while (loop--) { ++#ifdef CONFIG_FSL_QMAN_TEST_STASH_POTATO ++ qman_test_hotpotato(); ++#endif ++#ifdef CONFIG_FSL_QMAN_TEST_HIGH ++ qman_test_high(); ++#endif ++ } ++ return 0; ++} ++ ++static void test_exit(void) ++{ ++} ++ ++module_init(test_init); ++module_exit(test_exit); +diff --git a/drivers/staging/fsl_qbman/qman_test.h b/drivers/staging/fsl_qbman/qman_test.h +new file mode 100644 +index 00000000..8c4181c7 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/qman_test.h +@@ -0,0 +1,45 @@ ++/* Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++void qman_test_hotpotato(void); ++void qman_test_high(void); ++ +diff --git a/drivers/staging/fsl_qbman/qman_test_high.c b/drivers/staging/fsl_qbman/qman_test_high.c +new file mode 100644 +index 00000000..65ee270e +--- /dev/null ++++ b/drivers/staging/fsl_qbman/qman_test_high.c +@@ -0,0 +1,216 @@ ++/* Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "qman_test.h" ++ ++/*************/ ++/* constants */ ++/*************/ ++ ++#define CGR_ID 27 ++#define POOL_ID 2 ++#define FQ_FLAGS QMAN_FQ_FLAG_DYNAMIC_FQID ++#define NUM_ENQUEUES 10 ++#define NUM_PARTIAL 4 ++#define PORTAL_SDQCR (QM_SDQCR_SOURCE_CHANNELS | \ ++ QM_SDQCR_TYPE_PRIO_QOS | \ ++ QM_SDQCR_TOKEN_SET(0x98) | \ ++ QM_SDQCR_CHANNELS_DEDICATED | \ ++ QM_SDQCR_CHANNELS_POOL(POOL_ID)) ++#define PORTAL_OPAQUE ((void *)0xf00dbeef) ++#define VDQCR_FLAGS (QMAN_VOLATILE_FLAG_WAIT | QMAN_VOLATILE_FLAG_FINISH) ++ ++/*************************************/ ++/* Predeclarations (eg. for fq_base) */ ++/*************************************/ ++ ++static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *, ++ struct qman_fq *, ++ const struct qm_dqrr_entry *); ++static void cb_ern(struct qman_portal *, struct qman_fq *, ++ const struct qm_mr_entry *); ++static void cb_fqs(struct qman_portal *, struct qman_fq *, ++ const struct qm_mr_entry *); ++ ++/***************/ ++/* global vars */ ++/***************/ ++ ++static struct qm_fd fd, fd_dq; ++static struct qman_fq fq_base = { ++ .cb.dqrr = cb_dqrr, ++ .cb.ern = cb_ern, ++ .cb.fqs = cb_fqs ++}; ++static DECLARE_WAIT_QUEUE_HEAD(waitqueue); ++static int retire_complete, sdqcr_complete; ++ ++/**********************/ ++/* internal functions */ ++/**********************/ ++ ++/* Helpers for initialising and "incrementing" a frame descriptor */ ++static void fd_init(struct qm_fd *__fd) ++{ ++ qm_fd_addr_set64(__fd, 0xabdeadbeefLLU); ++ __fd->format = qm_fd_contig_big; ++ __fd->length29 = 0x0000ffff; ++ __fd->cmd = 0xfeedf00d; ++} ++ ++static void fd_inc(struct qm_fd *__fd) ++{ ++ u64 t = qm_fd_addr_get64(__fd); ++ int z = t >> 40; ++ t <<= 1; ++ if (z) ++ t |= 1; ++ qm_fd_addr_set64(__fd, t); ++ __fd->length29--; ++ __fd->cmd++; ++} ++ ++/* The only part of the 'fd' we can't memcmp() is the ppid */ ++static int fd_cmp(const struct qm_fd *a, const struct qm_fd *b) ++{ ++ int r = (qm_fd_addr_get64(a) == qm_fd_addr_get64(b)) ? 0 : -1; ++ if (!r) ++ r = a->format - b->format; ++ if (!r) ++ r = a->opaque - b->opaque; ++ if (!r) ++ r = a->cmd - b->cmd; ++ return r; ++} ++ ++/********/ ++/* test */ ++/********/ ++ ++static void do_enqueues(struct qman_fq *fq) ++{ ++ unsigned int loop; ++ for (loop = 0; loop < NUM_ENQUEUES; loop++) { ++ if (qman_enqueue(fq, &fd, QMAN_ENQUEUE_FLAG_WAIT | ++ (((loop + 1) == NUM_ENQUEUES) ? ++ QMAN_ENQUEUE_FLAG_WAIT_SYNC : 0))) ++ panic("qman_enqueue() failed\n"); ++ fd_inc(&fd); ++ } ++} ++ ++void qman_test_high(void) ++{ ++ unsigned int flags; ++ int res; ++ struct qman_fq *fq = &fq_base; ++ ++ pr_info("qman_test_high starting\n"); ++ fd_init(&fd); ++ fd_init(&fd_dq); ++ ++ /* Initialise (parked) FQ */ ++ if (qman_create_fq(0, FQ_FLAGS, fq)) ++ panic("qman_create_fq() failed\n"); ++ if (qman_init_fq(fq, QMAN_INITFQ_FLAG_LOCAL, NULL)) ++ panic("qman_init_fq() failed\n"); ++ ++ /* Do enqueues + VDQCR, twice. (Parked FQ) */ ++ do_enqueues(fq); ++ pr_info("VDQCR (till-empty);\n"); ++ if (qman_volatile_dequeue(fq, VDQCR_FLAGS, ++ QM_VDQCR_NUMFRAMES_TILLEMPTY)) ++ panic("qman_volatile_dequeue() failed\n"); ++ do_enqueues(fq); ++ pr_info("VDQCR (%d of %d);\n", NUM_PARTIAL, NUM_ENQUEUES); ++ if (qman_volatile_dequeue(fq, VDQCR_FLAGS, ++ QM_VDQCR_NUMFRAMES_SET(NUM_PARTIAL))) ++ panic("qman_volatile_dequeue() failed\n"); ++ pr_info("VDQCR (%d of %d);\n", NUM_ENQUEUES - NUM_PARTIAL, ++ NUM_ENQUEUES); ++ if (qman_volatile_dequeue(fq, VDQCR_FLAGS, ++ QM_VDQCR_NUMFRAMES_SET(NUM_ENQUEUES - NUM_PARTIAL))) ++ panic("qman_volatile_dequeue() failed\n"); ++ ++ do_enqueues(fq); ++ pr_info("scheduled dequeue (till-empty)\n"); ++ if (qman_schedule_fq(fq)) ++ panic("qman_schedule_fq() failed\n"); ++ wait_event(waitqueue, sdqcr_complete); ++ ++ /* Retire and OOS the FQ */ ++ res = qman_retire_fq(fq, &flags); ++ if (res < 0) ++ panic("qman_retire_fq() failed\n"); ++ wait_event(waitqueue, retire_complete); ++ if (flags & QMAN_FQ_STATE_BLOCKOOS) ++ panic("leaking frames\n"); ++ if (qman_oos_fq(fq)) ++ panic("qman_oos_fq() failed\n"); ++ qman_destroy_fq(fq, 0); ++ pr_info("qman_test_high finished\n"); ++} ++ ++static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *p, ++ struct qman_fq *fq, ++ const struct qm_dqrr_entry *dq) ++{ ++ if (fd_cmp(&fd_dq, &dq->fd)) { ++ pr_err("BADNESS: dequeued frame doesn't match;\n"); ++ pr_err("Expected 0x%llx, got 0x%llx\n", ++ (unsigned long long)fd_dq.length29, ++ (unsigned long long)dq->fd.length29); ++ BUG(); ++ } ++ fd_inc(&fd_dq); ++ if (!(dq->stat & QM_DQRR_STAT_UNSCHEDULED) && !fd_cmp(&fd_dq, &fd)) { ++ sdqcr_complete = 1; ++ wake_up(&waitqueue); ++ } ++ return qman_cb_dqrr_consume; ++} ++ ++static void cb_ern(struct qman_portal *p, struct qman_fq *fq, ++ const struct qm_mr_entry *msg) ++{ ++ panic("cb_ern() unimplemented"); ++} ++ ++static void cb_fqs(struct qman_portal *p, struct qman_fq *fq, ++ const struct qm_mr_entry *msg) ++{ ++ u8 verb = (msg->verb & QM_MR_VERB_TYPE_MASK); ++ if ((verb != QM_MR_VERB_FQRN) && (verb != QM_MR_VERB_FQRNI)) ++ panic("unexpected FQS message"); ++ pr_info("Retirement message received\n"); ++ retire_complete = 1; ++ wake_up(&waitqueue); ++} +diff --git a/drivers/staging/fsl_qbman/qman_test_hotpotato.c b/drivers/staging/fsl_qbman/qman_test_hotpotato.c +new file mode 100644 +index 00000000..899d2aa9 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/qman_test_hotpotato.c +@@ -0,0 +1,502 @@ ++/* Copyright 2009-2012 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++#include "qman_test.h" ++ ++/* Algorithm: ++ * ++ * Each cpu will have HP_PER_CPU "handlers" set up, each of which incorporates ++ * an rx/tx pair of FQ objects (both of which are stashed on dequeue). The ++ * organisation of FQIDs is such that the HP_PER_CPU*NUM_CPUS handlers will ++ * shuttle a "hot potato" frame around them such that every forwarding action ++ * moves it from one cpu to another. (The use of more than one handler per cpu ++ * is to allow enough handlers/FQs to truly test the significance of caching - ++ * ie. when cache-expiries are occurring.) ++ * ++ * The "hot potato" frame content will be HP_NUM_WORDS*4 bytes in size, and the ++ * first and last words of the frame data will undergo a transformation step on ++ * each forwarding action. To achieve this, each handler will be assigned a ++ * 32-bit "mixer", that is produced using a 32-bit LFSR. When a frame is ++ * received by a handler, the mixer of the expected sender is XOR'd into all ++ * words of the entire frame, which is then validated against the original ++ * values. Then, before forwarding, the entire frame is XOR'd with the mixer of ++ * the current handler. Apart from validating that the frame is taking the ++ * expected path, this also provides some quasi-realistic overheads to each ++ * forwarding action - dereferencing *all* the frame data, computation, and ++ * conditional branching. There is a "special" handler designated to act as the ++ * instigator of the test by creating an enqueuing the "hot potato" frame, and ++ * to determine when the test has completed by counting HP_LOOPS iterations. ++ * ++ * Init phases: ++ * ++ * 1. prepare each cpu's 'hp_cpu' struct using on_each_cpu(,,1) and link them ++ * into 'hp_cpu_list'. Specifically, set processor_id, allocate HP_PER_CPU ++ * handlers and link-list them (but do no other handler setup). ++ * ++ * 2. scan over 'hp_cpu_list' HP_PER_CPU times, the first time sets each ++ * hp_cpu's 'iterator' to point to its first handler. With each loop, ++ * allocate rx/tx FQIDs and mixer values to the hp_cpu's iterator handler ++ * and advance the iterator for the next loop. This includes a final fixup, ++ * which connects the last handler to the first (and which is why phase 2 ++ * and 3 are separate). ++ * ++ * 3. scan over 'hp_cpu_list' HP_PER_CPU times, the first time sets each ++ * hp_cpu's 'iterator' to point to its first handler. With each loop, ++ * initialise FQ objects and advance the iterator for the next loop. ++ * Moreover, do this initialisation on the cpu it applies to so that Rx FQ ++ * initialisation targets the correct cpu. ++ */ ++ ++/* helper to run something on all cpus (can't use on_each_cpu(), as that invokes ++ * the fn from irq context, which is too restrictive). */ ++struct bstrap { ++ void (*fn)(void); ++ atomic_t started; ++}; ++static int bstrap_fn(void *__bstrap) ++{ ++ struct bstrap *bstrap = __bstrap; ++ atomic_inc(&bstrap->started); ++ bstrap->fn(); ++ while (!kthread_should_stop()) ++ msleep(1); ++ return 0; ++} ++static int on_all_cpus(void (*fn)(void)) ++{ ++ int cpu; ++ for_each_cpu(cpu, cpu_online_mask) { ++ struct bstrap bstrap = { ++ .fn = fn, ++ .started = ATOMIC_INIT(0) ++ }; ++ struct task_struct *k = kthread_create(bstrap_fn, &bstrap, ++ "hotpotato%d", cpu); ++ int ret; ++ if (IS_ERR(k)) ++ return -ENOMEM; ++ kthread_bind(k, cpu); ++ wake_up_process(k); ++ /* If we call kthread_stop() before the "wake up" has had an ++ * effect, then the thread may exit with -EINTR without ever ++ * running the function. So poll until it's started before ++ * requesting it to stop. */ ++ while (!atomic_read(&bstrap.started)) ++ msleep(10); ++ ret = kthread_stop(k); ++ if (ret) ++ return ret; ++ } ++ return 0; ++} ++ ++struct hp_handler { ++ ++ /* The following data is stashed when 'rx' is dequeued; */ ++ /* -------------- */ ++ /* The Rx FQ, dequeues of which will stash the entire hp_handler */ ++ struct qman_fq rx; ++ /* The Tx FQ we should forward to */ ++ struct qman_fq tx; ++ /* The value we XOR post-dequeue, prior to validating */ ++ u32 rx_mixer; ++ /* The value we XOR pre-enqueue, after validating */ ++ u32 tx_mixer; ++ /* what the hotpotato address should be on dequeue */ ++ dma_addr_t addr; ++ u32 *frame_ptr; ++ ++ /* The following data isn't (necessarily) stashed on dequeue; */ ++ /* -------------- */ ++ u32 fqid_rx, fqid_tx; ++ /* list node for linking us into 'hp_cpu' */ ++ struct list_head node; ++ /* Just to check ... */ ++ unsigned int processor_id; ++} ____cacheline_aligned; ++ ++struct hp_cpu { ++ /* identify the cpu we run on; */ ++ unsigned int processor_id; ++ /* root node for the per-cpu list of handlers */ ++ struct list_head handlers; ++ /* list node for linking us into 'hp_cpu_list' */ ++ struct list_head node; ++ /* when repeatedly scanning 'hp_list', each time linking the n'th ++ * handlers together, this is used as per-cpu iterator state */ ++ struct hp_handler *iterator; ++}; ++ ++/* Each cpu has one of these */ ++static DEFINE_PER_CPU(struct hp_cpu, hp_cpus); ++ ++/* links together the hp_cpu structs, in first-come first-serve order. */ ++static LIST_HEAD(hp_cpu_list); ++static spinlock_t hp_lock = __SPIN_LOCK_UNLOCKED(hp_lock); ++ ++static unsigned int hp_cpu_list_length; ++ ++/* the "special" handler, that starts and terminates the test. */ ++static struct hp_handler *special_handler; ++static int loop_counter; ++ ++/* handlers are allocated out of this, so they're properly aligned. */ ++static struct kmem_cache *hp_handler_slab; ++ ++/* this is the frame data */ ++static void *__frame_ptr; ++static u32 *frame_ptr; ++static dma_addr_t frame_dma; ++ ++/* the main function waits on this */ ++static DECLARE_WAIT_QUEUE_HEAD(queue); ++ ++#define HP_PER_CPU 2 ++#define HP_LOOPS 8 ++/* 80 bytes, like a small ethernet frame, and bleeds into a second cacheline */ ++#define HP_NUM_WORDS 80 ++/* First word of the LFSR-based frame data */ ++#define HP_FIRST_WORD 0xabbaf00d ++ ++static inline u32 do_lfsr(u32 prev) ++{ ++ return (prev >> 1) ^ (-(prev & 1u) & 0xd0000001u); ++} ++ ++static void allocate_frame_data(void) ++{ ++ u32 lfsr = HP_FIRST_WORD; ++ int loop; ++ struct platform_device *pdev = platform_device_alloc("foobar", -1); ++ if (!pdev) ++ panic("platform_device_alloc() failed"); ++ if (platform_device_add(pdev)) ++ panic("platform_device_add() failed"); ++ __frame_ptr = kmalloc(4 * HP_NUM_WORDS, GFP_KERNEL); ++ if (!__frame_ptr) ++ panic("kmalloc() failed"); ++ frame_ptr = (void *)(((unsigned long)__frame_ptr + 63) & ++ ~(unsigned long)63); ++ for (loop = 0; loop < HP_NUM_WORDS; loop++) { ++ frame_ptr[loop] = lfsr; ++ lfsr = do_lfsr(lfsr); ++ } ++ frame_dma = dma_map_single(&pdev->dev, frame_ptr, 4 * HP_NUM_WORDS, ++ DMA_BIDIRECTIONAL); ++ platform_device_del(pdev); ++ platform_device_put(pdev); ++} ++ ++static void deallocate_frame_data(void) ++{ ++ kfree(__frame_ptr); ++} ++ ++static inline void process_frame_data(struct hp_handler *handler, ++ const struct qm_fd *fd) ++{ ++ u32 *p = handler->frame_ptr; ++ u32 lfsr = HP_FIRST_WORD; ++ int loop; ++ if (qm_fd_addr_get64(fd) != (handler->addr & 0xffffffffff)) { ++ pr_err("Got 0x%llx expected 0x%llx\n", ++ qm_fd_addr_get64(fd), handler->addr); ++ panic("bad frame address"); ++ } ++ for (loop = 0; loop < HP_NUM_WORDS; loop++, p++) { ++ *p ^= handler->rx_mixer; ++ if (*p != lfsr) ++ panic("corrupt frame data"); ++ *p ^= handler->tx_mixer; ++ lfsr = do_lfsr(lfsr); ++ } ++} ++ ++static enum qman_cb_dqrr_result normal_dqrr(struct qman_portal *portal, ++ struct qman_fq *fq, ++ const struct qm_dqrr_entry *dqrr) ++{ ++ struct hp_handler *handler = (struct hp_handler *)fq; ++ ++ process_frame_data(handler, &dqrr->fd); ++ if (qman_enqueue(&handler->tx, &dqrr->fd, 0)) ++ panic("qman_enqueue() failed"); ++ return qman_cb_dqrr_consume; ++} ++ ++static enum qman_cb_dqrr_result special_dqrr(struct qman_portal *portal, ++ struct qman_fq *fq, ++ const struct qm_dqrr_entry *dqrr) ++{ ++ struct hp_handler *handler = (struct hp_handler *)fq; ++ ++ process_frame_data(handler, &dqrr->fd); ++ if (++loop_counter < HP_LOOPS) { ++ if (qman_enqueue(&handler->tx, &dqrr->fd, 0)) ++ panic("qman_enqueue() failed"); ++ } else { ++ pr_info("Received final (%dth) frame\n", loop_counter); ++ wake_up(&queue); ++ } ++ return qman_cb_dqrr_consume; ++} ++ ++static void create_per_cpu_handlers(void) ++{ ++ struct hp_handler *handler; ++ int loop; ++ struct hp_cpu *hp_cpu = &get_cpu_var(hp_cpus); ++ ++ hp_cpu->processor_id = smp_processor_id(); ++ spin_lock(&hp_lock); ++ list_add_tail(&hp_cpu->node, &hp_cpu_list); ++ hp_cpu_list_length++; ++ spin_unlock(&hp_lock); ++ INIT_LIST_HEAD(&hp_cpu->handlers); ++ for (loop = 0; loop < HP_PER_CPU; loop++) { ++ handler = kmem_cache_alloc(hp_handler_slab, GFP_KERNEL); ++ if (!handler) ++ panic("kmem_cache_alloc() failed"); ++ handler->processor_id = hp_cpu->processor_id; ++ handler->addr = frame_dma; ++ handler->frame_ptr = frame_ptr; ++ list_add_tail(&handler->node, &hp_cpu->handlers); ++ } ++ put_cpu_var(hp_cpus); ++} ++ ++static void destroy_per_cpu_handlers(void) ++{ ++ struct list_head *loop, *tmp; ++ struct hp_cpu *hp_cpu = &get_cpu_var(hp_cpus); ++ ++ spin_lock(&hp_lock); ++ list_del(&hp_cpu->node); ++ spin_unlock(&hp_lock); ++ list_for_each_safe(loop, tmp, &hp_cpu->handlers) { ++ u32 flags; ++ struct hp_handler *handler = list_entry(loop, struct hp_handler, ++ node); ++ if (qman_retire_fq(&handler->rx, &flags)) ++ panic("qman_retire_fq(rx) failed"); ++ BUG_ON(flags & QMAN_FQ_STATE_BLOCKOOS); ++ if (qman_oos_fq(&handler->rx)) ++ panic("qman_oos_fq(rx) failed"); ++ qman_destroy_fq(&handler->rx, 0); ++ qman_destroy_fq(&handler->tx, 0); ++ qman_release_fqid(handler->fqid_rx); ++ list_del(&handler->node); ++ kmem_cache_free(hp_handler_slab, handler); ++ } ++ put_cpu_var(hp_cpus); ++} ++ ++static inline u8 num_cachelines(u32 offset) ++{ ++ u8 res = (offset + (L1_CACHE_BYTES - 1)) ++ / (L1_CACHE_BYTES); ++ if (res > 3) ++ return 3; ++ return res; ++} ++#define STASH_DATA_CL \ ++ num_cachelines(HP_NUM_WORDS * 4) ++#define STASH_CTX_CL \ ++ num_cachelines(offsetof(struct hp_handler, fqid_rx)) ++ ++static void init_handler(void *__handler) ++{ ++ struct qm_mcc_initfq opts; ++ struct hp_handler *handler = __handler; ++ BUG_ON(handler->processor_id != smp_processor_id()); ++ /* Set up rx */ ++ memset(&handler->rx, 0, sizeof(handler->rx)); ++ if (handler == special_handler) ++ handler->rx.cb.dqrr = special_dqrr; ++ else ++ handler->rx.cb.dqrr = normal_dqrr; ++ if (qman_create_fq(handler->fqid_rx, 0, &handler->rx)) ++ panic("qman_create_fq(rx) failed"); ++ memset(&opts, 0, sizeof(opts)); ++ opts.we_mask = QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_CONTEXTA; ++ opts.fqd.fq_ctrl = QM_FQCTRL_CTXASTASHING; ++ opts.fqd.context_a.stashing.data_cl = STASH_DATA_CL; ++ opts.fqd.context_a.stashing.context_cl = STASH_CTX_CL; ++ if (qman_init_fq(&handler->rx, QMAN_INITFQ_FLAG_SCHED | ++ QMAN_INITFQ_FLAG_LOCAL, &opts)) ++ panic("qman_init_fq(rx) failed"); ++ /* Set up tx */ ++ memset(&handler->tx, 0, sizeof(handler->tx)); ++ if (qman_create_fq(handler->fqid_tx, QMAN_FQ_FLAG_NO_MODIFY, ++ &handler->tx)) ++ panic("qman_create_fq(tx) failed"); ++} ++ ++static void init_phase2(void) ++{ ++ int loop; ++ u32 fqid = 0; ++ u32 lfsr = 0xdeadbeef; ++ struct hp_cpu *hp_cpu; ++ struct hp_handler *handler; ++ ++ for (loop = 0; loop < HP_PER_CPU; loop++) { ++ list_for_each_entry(hp_cpu, &hp_cpu_list, node) { ++ int ret; ++ if (!loop) ++ hp_cpu->iterator = list_first_entry( ++ &hp_cpu->handlers, ++ struct hp_handler, node); ++ else ++ hp_cpu->iterator = list_entry( ++ hp_cpu->iterator->node.next, ++ struct hp_handler, node); ++ /* Rx FQID is the previous handler's Tx FQID */ ++ hp_cpu->iterator->fqid_rx = fqid; ++ /* Allocate new FQID for Tx */ ++ ret = qman_alloc_fqid(&fqid); ++ if (ret) ++ panic("qman_alloc_fqid() failed"); ++ hp_cpu->iterator->fqid_tx = fqid; ++ /* Rx mixer is the previous handler's Tx mixer */ ++ hp_cpu->iterator->rx_mixer = lfsr; ++ /* Get new mixer for Tx */ ++ lfsr = do_lfsr(lfsr); ++ hp_cpu->iterator->tx_mixer = lfsr; ++ } ++ } ++ /* Fix up the first handler (fqid_rx==0, rx_mixer=0xdeadbeef) */ ++ hp_cpu = list_first_entry(&hp_cpu_list, struct hp_cpu, node); ++ handler = list_first_entry(&hp_cpu->handlers, struct hp_handler, node); ++ BUG_ON((handler->fqid_rx != 0) || (handler->rx_mixer != 0xdeadbeef)); ++ handler->fqid_rx = fqid; ++ handler->rx_mixer = lfsr; ++ /* and tag it as our "special" handler */ ++ special_handler = handler; ++} ++ ++static void init_phase3(void) ++{ ++ int loop; ++ struct hp_cpu *hp_cpu; ++ ++ for (loop = 0; loop < HP_PER_CPU; loop++) { ++ list_for_each_entry(hp_cpu, &hp_cpu_list, node) { ++ if (!loop) ++ hp_cpu->iterator = list_first_entry( ++ &hp_cpu->handlers, ++ struct hp_handler, node); ++ else ++ hp_cpu->iterator = list_entry( ++ hp_cpu->iterator->node.next, ++ struct hp_handler, node); ++ preempt_disable(); ++ if (hp_cpu->processor_id == smp_processor_id()) ++ init_handler(hp_cpu->iterator); ++ else ++ smp_call_function_single(hp_cpu->processor_id, ++ init_handler, hp_cpu->iterator, 1); ++ preempt_enable(); ++ } ++ } ++} ++ ++static void send_first_frame(void *ignore) ++{ ++ u32 *p = special_handler->frame_ptr; ++ u32 lfsr = HP_FIRST_WORD; ++ int loop; ++ struct qm_fd fd; ++ ++ BUG_ON(special_handler->processor_id != smp_processor_id()); ++ memset(&fd, 0, sizeof(fd)); ++ qm_fd_addr_set64(&fd, special_handler->addr); ++ fd.format = qm_fd_contig_big; ++ fd.length29 = HP_NUM_WORDS * 4; ++ for (loop = 0; loop < HP_NUM_WORDS; loop++, p++) { ++ if (*p != lfsr) ++ panic("corrupt frame data"); ++ *p ^= special_handler->tx_mixer; ++ lfsr = do_lfsr(lfsr); ++ } ++ pr_info("Sending first frame\n"); ++ if (qman_enqueue(&special_handler->tx, &fd, 0)) ++ panic("qman_enqueue() failed"); ++} ++ ++void qman_test_hotpotato(void) ++{ ++ if (cpumask_weight(cpu_online_mask) < 2) { ++ pr_info("qman_test_hotpotato, skip - only 1 CPU\n"); ++ return; ++ } ++ ++ pr_info("qman_test_hotpotato starting\n"); ++ ++ hp_cpu_list_length = 0; ++ loop_counter = 0; ++ hp_handler_slab = kmem_cache_create("hp_handler_slab", ++ sizeof(struct hp_handler), L1_CACHE_BYTES, ++ SLAB_HWCACHE_ALIGN, NULL); ++ if (!hp_handler_slab) ++ panic("kmem_cache_create() failed"); ++ ++ allocate_frame_data(); ++ ++ /* Init phase 1 */ ++ pr_info("Creating %d handlers per cpu...\n", HP_PER_CPU); ++ if (on_all_cpus(create_per_cpu_handlers)) ++ panic("on_each_cpu() failed"); ++ pr_info("Number of cpus: %d, total of %d handlers\n", ++ hp_cpu_list_length, hp_cpu_list_length * HP_PER_CPU); ++ ++ init_phase2(); ++ ++ init_phase3(); ++ ++ preempt_disable(); ++ if (special_handler->processor_id == smp_processor_id()) ++ send_first_frame(NULL); ++ else ++ smp_call_function_single(special_handler->processor_id, ++ send_first_frame, NULL, 1); ++ preempt_enable(); ++ ++ wait_event(queue, loop_counter == HP_LOOPS); ++ deallocate_frame_data(); ++ if (on_all_cpus(destroy_per_cpu_handlers)) ++ panic("on_each_cpu() failed"); ++ kmem_cache_destroy(hp_handler_slab); ++ pr_info("qman_test_hotpotato finished\n"); ++} +diff --git a/drivers/staging/fsl_qbman/qman_utility.c b/drivers/staging/fsl_qbman/qman_utility.c +new file mode 100644 +index 00000000..f1e39023 +--- /dev/null ++++ b/drivers/staging/fsl_qbman/qman_utility.c +@@ -0,0 +1,129 @@ ++/* Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "qman_private.h" ++ ++/* ----------------- */ ++/* --- FQID Pool --- */ ++ ++struct qman_fqid_pool { ++ /* Base and size of the FQID range */ ++ u32 fqid_base; ++ u32 total; ++ /* Number of FQIDs currently "allocated" */ ++ u32 used; ++ /* Allocation optimisation. When 'usedfqid_base = fqid_start; ++ pool->total = num; ++ pool->used = 0; ++ pool->next = 0; ++ pool->bits = kzalloc(QNUM_BYTES(num), GFP_KERNEL); ++ if (!pool->bits) { ++ kfree(pool); ++ return NULL; ++ } ++ /* If num is not an even multiple of QLONG_BITS (or even 8, for ++ * byte-oriented searching) then we fill the trailing bits with 1, to ++ * make them look allocated (permanently). */ ++ for (i = num + 1; i < QNUM_BITS(num); i++) ++ set_bit(i, pool->bits); ++ return pool; ++} ++EXPORT_SYMBOL(qman_fqid_pool_create); ++ ++int qman_fqid_pool_destroy(struct qman_fqid_pool *pool) ++{ ++ int ret = pool->used; ++ kfree(pool->bits); ++ kfree(pool); ++ return ret; ++} ++EXPORT_SYMBOL(qman_fqid_pool_destroy); ++ ++int qman_fqid_pool_alloc(struct qman_fqid_pool *pool, u32 *fqid) ++{ ++ int ret; ++ if (pool->used == pool->total) ++ return -ENOMEM; ++ *fqid = pool->fqid_base + pool->next; ++ ret = test_and_set_bit(pool->next, pool->bits); ++ BUG_ON(ret); ++ if (++pool->used == pool->total) ++ return 0; ++ pool->next = find_next_zero_bit(pool->bits, pool->total, pool->next); ++ if (pool->next >= pool->total) ++ pool->next = find_first_zero_bit(pool->bits, pool->total); ++ BUG_ON(pool->next >= pool->total); ++ return 0; ++} ++EXPORT_SYMBOL(qman_fqid_pool_alloc); ++ ++void qman_fqid_pool_free(struct qman_fqid_pool *pool, u32 fqid) ++{ ++ int ret; ++ ++ fqid -= pool->fqid_base; ++ ret = test_and_clear_bit(fqid, pool->bits); ++ BUG_ON(!ret); ++ if (pool->used-- == pool->total) ++ pool->next = fqid; ++} ++EXPORT_SYMBOL(qman_fqid_pool_free); ++ ++u32 qman_fqid_pool_used(struct qman_fqid_pool *pool) ++{ ++ return pool->used; ++} ++EXPORT_SYMBOL(qman_fqid_pool_used); +diff --git a/include/linux/fsl_bman.h b/include/linux/fsl_bman.h +new file mode 100644 +index 00000000..43942221 +--- /dev/null ++++ b/include/linux/fsl_bman.h +@@ -0,0 +1,532 @@ ++/* Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef FSL_BMAN_H ++#define FSL_BMAN_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Last updated for v00.79 of the BG */ ++ ++/* Portal processing (interrupt) sources */ ++#define BM_PIRQ_RCRI 0x00000002 /* RCR Ring (below threshold) */ ++#define BM_PIRQ_BSCN 0x00000001 /* Buffer depletion State Change */ ++ ++/* This wrapper represents a bit-array for the depletion state of the 64 Bman ++ * buffer pools. */ ++struct bman_depletion { ++ u32 __state[2]; ++}; ++#define BMAN_DEPLETION_EMPTY { { 0x00000000, 0x00000000 } } ++#define BMAN_DEPLETION_FULL { { 0xffffffff, 0xffffffff } } ++#define __bmdep_word(x) ((x) >> 5) ++#define __bmdep_shift(x) ((x) & 0x1f) ++#define __bmdep_bit(x) (0x80000000 >> __bmdep_shift(x)) ++static inline void bman_depletion_init(struct bman_depletion *c) ++{ ++ c->__state[0] = c->__state[1] = 0; ++} ++static inline void bman_depletion_fill(struct bman_depletion *c) ++{ ++ c->__state[0] = c->__state[1] = ~0; ++} ++static inline int bman_depletion_get(const struct bman_depletion *c, u8 bpid) ++{ ++ return c->__state[__bmdep_word(bpid)] & __bmdep_bit(bpid); ++} ++static inline void bman_depletion_set(struct bman_depletion *c, u8 bpid) ++{ ++ c->__state[__bmdep_word(bpid)] |= __bmdep_bit(bpid); ++} ++static inline void bman_depletion_unset(struct bman_depletion *c, u8 bpid) ++{ ++ c->__state[__bmdep_word(bpid)] &= ~__bmdep_bit(bpid); ++} ++ ++/* ------------------------------------------------------- */ ++/* --- Bman data structures (and associated constants) --- */ ++ ++/* Represents s/w corenet portal mapped data structures */ ++struct bm_rcr_entry; /* RCR (Release Command Ring) entries */ ++struct bm_mc_command; /* MC (Management Command) command */ ++struct bm_mc_result; /* MC result */ ++ ++/* Code-reduction, define a wrapper for 48-bit buffers. In cases where a buffer ++ * pool id specific to this buffer is needed (BM_RCR_VERB_CMD_BPID_MULTI, ++ * BM_MCC_VERB_ACQUIRE), the 'bpid' field is used. */ ++struct bm_buffer { ++ union { ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 __reserved1; ++ u8 bpid; ++ u16 hi; /* High 16-bits of 48-bit address */ ++ u32 lo; /* Low 32-bits of 48-bit address */ ++#else ++ u32 lo; ++ u16 hi; ++ u8 bpid; ++ u8 __reserved; ++#endif ++ }; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u64 __notaddress:16; ++ u64 addr:48; ++#else ++ u64 addr:48; ++ u64 __notaddress:16; ++#endif ++ }; ++ u64 opaque; ++ }; ++} __aligned(8); ++static inline u64 bm_buffer_get64(const struct bm_buffer *buf) ++{ ++ return buf->addr; ++} ++static inline dma_addr_t bm_buf_addr(const struct bm_buffer *buf) ++{ ++ return (dma_addr_t)buf->addr; ++} ++/* Macro, so we compile better if 'v' isn't always 64-bit */ ++#define bm_buffer_set64(buf, v) \ ++ do { \ ++ struct bm_buffer *__buf931 = (buf); \ ++ __buf931->hi = upper_32_bits(v); \ ++ __buf931->lo = lower_32_bits(v); \ ++ } while (0) ++ ++/* See 1.5.3.5.4: "Release Command" */ ++struct bm_rcr_entry { ++ union { ++ struct { ++ u8 __dont_write_directly__verb; ++ u8 bpid; /* used with BM_RCR_VERB_CMD_BPID_SINGLE */ ++ u8 __reserved1[62]; ++ }; ++ struct bm_buffer bufs[8]; ++ }; ++} __packed; ++#define BM_RCR_VERB_VBIT 0x80 ++#define BM_RCR_VERB_CMD_MASK 0x70 /* one of two values; */ ++#define BM_RCR_VERB_CMD_BPID_SINGLE 0x20 ++#define BM_RCR_VERB_CMD_BPID_MULTI 0x30 ++#define BM_RCR_VERB_BUFCOUNT_MASK 0x0f /* values 1..8 */ ++ ++/* See 1.5.3.1: "Acquire Command" */ ++/* See 1.5.3.2: "Query Command" */ ++struct bm_mcc_acquire { ++ u8 bpid; ++ u8 __reserved1[62]; ++} __packed; ++struct bm_mcc_query { ++ u8 __reserved2[63]; ++} __packed; ++struct bm_mc_command { ++ u8 __dont_write_directly__verb; ++ union { ++ struct bm_mcc_acquire acquire; ++ struct bm_mcc_query query; ++ }; ++} __packed; ++#define BM_MCC_VERB_VBIT 0x80 ++#define BM_MCC_VERB_CMD_MASK 0x70 /* where the verb contains; */ ++#define BM_MCC_VERB_CMD_ACQUIRE 0x10 ++#define BM_MCC_VERB_CMD_QUERY 0x40 ++#define BM_MCC_VERB_ACQUIRE_BUFCOUNT 0x0f /* values 1..8 go here */ ++ ++/* See 1.5.3.3: "Acquire Response" */ ++/* See 1.5.3.4: "Query Response" */ ++struct bm_pool_state { ++ u8 __reserved1[32]; ++ /* "availability state" and "depletion state" */ ++ struct { ++ u8 __reserved1[8]; ++ /* Access using bman_depletion_***() */ ++ struct bman_depletion state; ++ } as, ds; ++}; ++struct bm_mc_result { ++ union { ++ struct { ++ u8 verb; ++ u8 __reserved1[63]; ++ }; ++ union { ++ struct { ++ u8 __reserved1; ++ u8 bpid; ++ u8 __reserved2[62]; ++ }; ++ struct bm_buffer bufs[8]; ++ } acquire; ++ struct bm_pool_state query; ++ }; ++} __packed; ++#define BM_MCR_VERB_VBIT 0x80 ++#define BM_MCR_VERB_CMD_MASK BM_MCC_VERB_CMD_MASK ++#define BM_MCR_VERB_CMD_ACQUIRE BM_MCC_VERB_CMD_ACQUIRE ++#define BM_MCR_VERB_CMD_QUERY BM_MCC_VERB_CMD_QUERY ++#define BM_MCR_VERB_CMD_ERR_INVALID 0x60 ++#define BM_MCR_VERB_CMD_ERR_ECC 0x70 ++#define BM_MCR_VERB_ACQUIRE_BUFCOUNT BM_MCC_VERB_ACQUIRE_BUFCOUNT /* 0..8 */ ++/* Determine the "availability state" of pool 'p' from a query result 'r' */ ++#define BM_MCR_QUERY_AVAILABILITY(r, p) \ ++ bman_depletion_get(&r->query.as.state, p) ++/* Determine the "depletion state" of pool 'p' from a query result 'r' */ ++#define BM_MCR_QUERY_DEPLETION(r, p) \ ++ bman_depletion_get(&r->query.ds.state, p) ++ ++/*******************************************************************/ ++/* Managed (aka "shared" or "mux/demux") portal, high-level i/face */ ++/*******************************************************************/ ++ ++ /* Portal and Buffer Pools */ ++ /* ----------------------- */ ++/* Represents a managed portal */ ++struct bman_portal; ++ ++/* This object type represents Bman buffer pools. */ ++struct bman_pool; ++ ++struct bman_portal_config { ++ /* This is used for any "core-affine" portals, ie. default portals ++ * associated to the corresponding cpu. -1 implies that there is no core ++ * affinity configured. */ ++ int cpu; ++ /* portal interrupt line */ ++ int irq; ++ /* the unique index of this portal */ ++ u32 index; ++ /* Is this portal shared? (If so, it has coarser locking and demuxes ++ * processing on behalf of other CPUs.) */ ++ int is_shared; ++ /* These are the buffer pool IDs that may be used via this portal. */ ++ struct bman_depletion mask; ++}; ++ ++/* This callback type is used when handling pool depletion entry/exit. The ++ * 'cb_ctx' value is the opaque value associated with the pool object in ++ * bman_new_pool(). 'depleted' is non-zero on depletion-entry, and zero on ++ * depletion-exit. */ ++typedef void (*bman_cb_depletion)(struct bman_portal *bm, ++ struct bman_pool *pool, void *cb_ctx, int depleted); ++ ++/* This struct specifies parameters for a bman_pool object. */ ++struct bman_pool_params { ++ /* index of the buffer pool to encapsulate (0-63), ignored if ++ * BMAN_POOL_FLAG_DYNAMIC_BPID is set. */ ++ u32 bpid; ++ /* bit-mask of BMAN_POOL_FLAG_*** options */ ++ u32 flags; ++ /* depletion-entry/exit callback, if BMAN_POOL_FLAG_DEPLETION is set */ ++ bman_cb_depletion cb; ++ /* opaque user value passed as a parameter to 'cb' */ ++ void *cb_ctx; ++ /* depletion-entry/exit thresholds, if BMAN_POOL_FLAG_THRESH is set. NB: ++ * this is only allowed if BMAN_POOL_FLAG_DYNAMIC_BPID is used *and* ++ * when run in the control plane (which controls Bman CCSR). This array ++ * matches the definition of bm_pool_set(). */ ++ u32 thresholds[4]; ++}; ++ ++/* Flags to bman_new_pool() */ ++#define BMAN_POOL_FLAG_NO_RELEASE 0x00000001 /* can't release to pool */ ++#define BMAN_POOL_FLAG_ONLY_RELEASE 0x00000002 /* can only release to pool */ ++#define BMAN_POOL_FLAG_DEPLETION 0x00000004 /* track depletion entry/exit */ ++#define BMAN_POOL_FLAG_DYNAMIC_BPID 0x00000008 /* (de)allocate bpid */ ++#define BMAN_POOL_FLAG_THRESH 0x00000010 /* set depletion thresholds */ ++#define BMAN_POOL_FLAG_STOCKPILE 0x00000020 /* stockpile to reduce hw ops */ ++ ++/* Flags to bman_release() */ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++#define BMAN_RELEASE_FLAG_WAIT 0x00000001 /* wait if RCR is full */ ++#define BMAN_RELEASE_FLAG_WAIT_INT 0x00000002 /* if we wait, interruptible? */ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++#define BMAN_RELEASE_FLAG_WAIT_SYNC 0x00000004 /* if wait, until consumed? */ ++#endif ++#endif ++#define BMAN_RELEASE_FLAG_NOW 0x00000008 /* issue immediate release */ ++ ++/* Flags to bman_acquire() */ ++#define BMAN_ACQUIRE_FLAG_STOCKPILE 0x00000001 /* no hw op, stockpile only */ ++ ++ /* Portal Management */ ++ /* ----------------- */ ++/** ++ * bman_get_portal_config - get portal configuration settings ++ * ++ * This returns a read-only view of the current cpu's affine portal settings. ++ */ ++const struct bman_portal_config *bman_get_portal_config(void); ++ ++/** ++ * bman_irqsource_get - return the portal work that is interrupt-driven ++ * ++ * Returns a bitmask of BM_PIRQ_**I processing sources that are currently ++ * enabled for interrupt handling on the current cpu's affine portal. These ++ * sources will trigger the portal interrupt and the interrupt handler (or a ++ * tasklet/bottom-half it defers to) will perform the corresponding processing ++ * work. The bman_poll_***() functions will only process sources that are not in ++ * this bitmask. If the current CPU is sharing a portal hosted on another CPU, ++ * this always returns zero. ++ */ ++u32 bman_irqsource_get(void); ++ ++/** ++ * bman_irqsource_add - add processing sources to be interrupt-driven ++ * @bits: bitmask of BM_PIRQ_**I processing sources ++ * ++ * Adds processing sources that should be interrupt-driven (rather than ++ * processed via bman_poll_***() functions). Returns zero for success, or ++ * -EINVAL if the current CPU is sharing a portal hosted on another CPU. */ ++int bman_irqsource_add(u32 bits); ++ ++/** ++ * bman_irqsource_remove - remove processing sources from being interrupt-driven ++ * @bits: bitmask of BM_PIRQ_**I processing sources ++ * ++ * Removes processing sources from being interrupt-driven, so that they will ++ * instead be processed via bman_poll_***() functions. Returns zero for success, ++ * or -EINVAL if the current CPU is sharing a portal hosted on another CPU. */ ++int bman_irqsource_remove(u32 bits); ++ ++/** ++ * bman_affine_cpus - return a mask of cpus that have affine portals ++ */ ++const cpumask_t *bman_affine_cpus(void); ++ ++/** ++ * bman_poll_slow - process anything that isn't interrupt-driven. ++ * ++ * This function does any portal processing that isn't interrupt-driven. If the ++ * current CPU is sharing a portal hosted on another CPU, this function will ++ * return -EINVAL, otherwise the return value is a bitmask of BM_PIRQ_* sources ++ * indicating what interrupt sources were actually processed by the call. ++ * ++ * NB, unlike the legacy wrapper bman_poll(), this function will ++ * deterministically check for the presence of portal processing work and do it, ++ * which implies some latency even if there's nothing to do. The bman_poll() ++ * wrapper on the other hand (like the qman_poll() wrapper) attenuates this by ++ * checking for (and doing) portal processing infrequently. Ie. such that ++ * qman_poll() and bman_poll() can be called from core-processing loops. Use ++ * bman_poll_slow() when you yourself are deciding when to incur the overhead of ++ * processing. ++ */ ++u32 bman_poll_slow(void); ++ ++/** ++ * bman_poll - process anything that isn't interrupt-driven. ++ * ++ * Dispatcher logic on a cpu can use this to trigger any maintenance of the ++ * affine portal. This function does whatever processing is not triggered by ++ * interrupts. This is a legacy wrapper that can be used in core-processing ++ * loops but mitigates the performance overhead of portal processing by ++ * adaptively bypassing true portal processing most of the time. (Processing is ++ * done once every 10 calls if the previous processing revealed that work needed ++ * to be done, or once very 1000 calls if the previous processing revealed no ++ * work needed doing.) If you wish to control this yourself, call ++ * bman_poll_slow() instead, which always checks for portal processing work. ++ */ ++void bman_poll(void); ++ ++/** ++ * bman_rcr_is_empty - Determine if portal's RCR is empty ++ * ++ * For use in situations where a cpu-affine caller needs to determine when all ++ * releases for the local portal have been processed by Bman but can't use the ++ * BMAN_RELEASE_FLAG_WAIT_SYNC flag to do this from the final bman_release(). ++ * The function forces tracking of RCR consumption (which normally doesn't ++ * happen until release processing needs to find space to put new release ++ * commands), and returns zero if the ring still has unprocessed entries, ++ * non-zero if it is empty. ++ */ ++int bman_rcr_is_empty(void); ++ ++/** ++ * bman_alloc_bpid_range - Allocate a contiguous range of BPIDs ++ * @result: is set by the API to the base BPID of the allocated range ++ * @count: the number of BPIDs required ++ * @align: required alignment of the allocated range ++ * @partial: non-zero if the API can return fewer than @count BPIDs ++ * ++ * Returns the number of buffer pools allocated, or a negative error code. If ++ * @partial is non zero, the allocation request may return a smaller range of ++ * BPs than requested (though alignment will be as requested). If @partial is ++ * zero, the return value will either be 'count' or negative. ++ */ ++int bman_alloc_bpid_range(u32 *result, u32 count, u32 align, int partial); ++static inline int bman_alloc_bpid(u32 *result) ++{ ++ int ret = bman_alloc_bpid_range(result, 1, 0, 0); ++ return (ret > 0) ? 0 : ret; ++} ++ ++/** ++ * bman_release_bpid_range - Release the specified range of buffer pool IDs ++ * @bpid: the base BPID of the range to deallocate ++ * @count: the number of BPIDs in the range ++ * ++ * This function can also be used to seed the allocator with ranges of BPIDs ++ * that it can subsequently allocate from. ++ */ ++void bman_release_bpid_range(u32 bpid, unsigned int count); ++static inline void bman_release_bpid(u32 bpid) ++{ ++ bman_release_bpid_range(bpid, 1); ++} ++ ++int bman_reserve_bpid_range(u32 bpid, unsigned int count); ++static inline int bman_reserve_bpid(u32 bpid) ++{ ++ return bman_reserve_bpid_range(bpid, 1); ++} ++ ++void bman_seed_bpid_range(u32 bpid, unsigned int count); ++ ++ ++int bman_shutdown_pool(u32 bpid); ++ ++ /* Pool management */ ++ /* --------------- */ ++/** ++ * bman_new_pool - Allocates a Buffer Pool object ++ * @params: parameters specifying the buffer pool ID and behaviour ++ * ++ * Creates a pool object for the given @params. A portal and the depletion ++ * callback field of @params are only used if the BMAN_POOL_FLAG_DEPLETION flag ++ * is set. NB, the fields from @params are copied into the new pool object, so ++ * the structure provided by the caller can be released or reused after the ++ * function returns. ++ */ ++struct bman_pool *bman_new_pool(const struct bman_pool_params *params); ++ ++/** ++ * bman_free_pool - Deallocates a Buffer Pool object ++ * @pool: the pool object to release ++ * ++ */ ++void bman_free_pool(struct bman_pool *pool); ++ ++/** ++ * bman_get_params - Returns a pool object's parameters. ++ * @pool: the pool object ++ * ++ * The returned pointer refers to state within the pool object so must not be ++ * modified and can no longer be read once the pool object is destroyed. ++ */ ++const struct bman_pool_params *bman_get_params(const struct bman_pool *pool); ++ ++/** ++ * bman_release - Release buffer(s) to the buffer pool ++ * @pool: the buffer pool object to release to ++ * @bufs: an array of buffers to release ++ * @num: the number of buffers in @bufs (1-8) ++ * @flags: bit-mask of BMAN_RELEASE_FLAG_*** options ++ * ++ * Adds the given buffers to RCR entries. If the portal @p was created with the ++ * "COMPACT" flag, then it will be using a compaction algorithm to improve ++ * utilisation of RCR. As such, these buffers may join an existing ring entry ++ * and/or it may not be issued right away so as to allow future releases to join ++ * the same ring entry. Use the BMAN_RELEASE_FLAG_NOW flag to override this ++ * behaviour by committing the RCR entry (or entries) right away. If the RCR ++ * ring is full, the function will return -EBUSY unless BMAN_RELEASE_FLAG_WAIT ++ * is selected, in which case it will sleep waiting for space to become ++ * available in RCR. If the function receives a signal before such time (and ++ * BMAN_RELEASE_FLAG_WAIT_INT is set), the function returns -EINTR. Otherwise, ++ * it returns zero. ++ */ ++int bman_release(struct bman_pool *pool, const struct bm_buffer *bufs, u8 num, ++ u32 flags); ++ ++/** ++ * bman_acquire - Acquire buffer(s) from a buffer pool ++ * @pool: the buffer pool object to acquire from ++ * @bufs: array for storing the acquired buffers ++ * @num: the number of buffers desired (@bufs is at least this big) ++ * ++ * Issues an "Acquire" command via the portal's management command interface. ++ * The return value will be the number of buffers obtained from the pool, or a ++ * negative error code if a h/w error or pool starvation was encountered. In ++ * the latter case, the content of @bufs is undefined. ++ */ ++int bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, u8 num, ++ u32 flags); ++ ++/** ++ * bman_flush_stockpile - Flush stockpile buffer(s) to the buffer pool ++ * @pool: the buffer pool object the stockpile belongs ++ * @flags: bit-mask of BMAN_RELEASE_FLAG_*** options ++ * ++ * Adds stockpile buffers to RCR entries until the stockpile is empty. ++ * The return value will be a negative error code if a h/w error occurred. ++ * If BMAN_RELEASE_FLAG_NOW flag is passed and RCR ring is full, ++ * -EAGAIN will be returned. ++ */ ++int bman_flush_stockpile(struct bman_pool *pool, u32 flags); ++ ++/** ++ * bman_query_pools - Query all buffer pool states ++ * @state: storage for the queried availability and depletion states ++ */ ++int bman_query_pools(struct bm_pool_state *state); ++ ++#ifdef CONFIG_FSL_BMAN_CONFIG ++/** ++ * bman_query_free_buffers - Query how many free buffers are in buffer pool ++ * @pool: the buffer pool object to query ++ * ++ * Return the number of the free buffers ++ */ ++u32 bman_query_free_buffers(struct bman_pool *pool); ++ ++/** ++ * bman_update_pool_thresholds - Change the buffer pool's depletion thresholds ++ * @pool: the buffer pool object to which the thresholds will be set ++ * @thresholds: the new thresholds ++ */ ++int bman_update_pool_thresholds(struct bman_pool *pool, const u32 *thresholds); ++#endif ++ ++/** ++ * The below bman_p_***() variant might be called in a situation that the cpu ++ * which the portal affine to is not online yet. ++ * @bman_portal specifies which portal the API will use. ++*/ ++int bman_p_irqsource_add(struct bman_portal *p, __maybe_unused u32 bits); ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* FSL_BMAN_H */ +diff --git a/include/linux/fsl_qman.h b/include/linux/fsl_qman.h +new file mode 100644 +index 00000000..4e4b21d5 +--- /dev/null ++++ b/include/linux/fsl_qman.h +@@ -0,0 +1,3888 @@ ++/* Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef FSL_QMAN_H ++#define FSL_QMAN_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Last updated for v00.800 of the BG */ ++ ++/* Hardware constants */ ++#define QM_CHANNEL_SWPORTAL0 0 ++#define QMAN_CHANNEL_POOL1 0x21 ++#define QMAN_CHANNEL_CAAM 0x80 ++#define QMAN_CHANNEL_PME 0xa0 ++#define QMAN_CHANNEL_POOL1_REV3 0x401 ++#define QMAN_CHANNEL_CAAM_REV3 0x840 ++#define QMAN_CHANNEL_PME_REV3 0x860 ++#define QMAN_CHANNEL_DCE 0x8a0 ++#define QMAN_CHANNEL_DCE_QMANREV312 0x880 ++extern u16 qm_channel_pool1; ++extern u16 qm_channel_caam; ++extern u16 qm_channel_pme; ++extern u16 qm_channel_dce; ++enum qm_dc_portal { ++ qm_dc_portal_fman0 = 0, ++ qm_dc_portal_fman1 = 1, ++ qm_dc_portal_caam = 2, ++ qm_dc_portal_pme = 3, ++ qm_dc_portal_rman = 4, ++ qm_dc_portal_dce = 5 ++}; ++ ++/* Portal processing (interrupt) sources */ ++#define QM_PIRQ_CCSCI 0x00200000 /* CEETM Congestion State Change */ ++#define QM_PIRQ_CSCI 0x00100000 /* Congestion State Change */ ++#define QM_PIRQ_EQCI 0x00080000 /* Enqueue Command Committed */ ++#define QM_PIRQ_EQRI 0x00040000 /* EQCR Ring (below threshold) */ ++#define QM_PIRQ_DQRI 0x00020000 /* DQRR Ring (non-empty) */ ++#define QM_PIRQ_MRI 0x00010000 /* MR Ring (non-empty) */ ++/* This mask contains all the interrupt sources that need handling except DQRI, ++ * ie. that if present should trigger slow-path processing. */ ++#define QM_PIRQ_SLOW (QM_PIRQ_CSCI | QM_PIRQ_EQCI | QM_PIRQ_EQRI | \ ++ QM_PIRQ_MRI | QM_PIRQ_CCSCI) ++ ++/* --- Clock speed --- */ ++/* A qman driver instance may or may not know the current qman clock speed. ++ * However, certain CEETM calculations may not be possible if this is not known. ++ * The 'set' function will only succeed (return zero) if the driver did not ++ * already know the clock speed. Likewise, the 'get' function will only succeed ++ * if the driver does know the clock speed (either because it knew when booting, ++ * or was told via 'set'). In cases where software is running on a driver ++ * instance that does not know the clock speed (eg. on a hypervised data-plane), ++ * and the user can obtain the current qman clock speed by other means (eg. from ++ * a message sent from the control-plane), then the 'set' function can be used ++ * to enable rate-calculations in a driver where it would otherwise not be ++ * possible. */ ++int qm_get_clock(u64 *clock_hz); ++int qm_set_clock(u64 clock_hz); ++ ++/* For qman_static_dequeue_*** APIs */ ++#define QM_SDQCR_CHANNELS_POOL_MASK 0x00007fff ++/* for n in [1,15] */ ++#define QM_SDQCR_CHANNELS_POOL(n) (0x00008000 >> (n)) ++/* for conversion from n of qm_channel */ ++static inline u32 QM_SDQCR_CHANNELS_POOL_CONV(u16 channel) ++{ ++ return QM_SDQCR_CHANNELS_POOL(channel + 1 - qm_channel_pool1); ++} ++ ++/* For qman_volatile_dequeue(); Choose one PRECEDENCE. EXACT is optional. Use ++ * NUMFRAMES(n) (6-bit) or NUMFRAMES_TILLEMPTY to fill in the frame-count. Use ++ * FQID(n) to fill in the frame queue ID. */ ++#define QM_VDQCR_PRECEDENCE_VDQCR 0x0 ++#define QM_VDQCR_PRECEDENCE_SDQCR 0x80000000 ++#define QM_VDQCR_EXACT 0x40000000 ++#define QM_VDQCR_NUMFRAMES_MASK 0x3f000000 ++#define QM_VDQCR_NUMFRAMES_SET(n) (((n) & 0x3f) << 24) ++#define QM_VDQCR_NUMFRAMES_GET(n) (((n) >> 24) & 0x3f) ++#define QM_VDQCR_NUMFRAMES_TILLEMPTY QM_VDQCR_NUMFRAMES_SET(0) ++ ++ ++/* ------------------------------------------------------- */ ++/* --- Qman data structures (and associated constants) --- */ ++ ++/* Represents s/w corenet portal mapped data structures */ ++struct qm_eqcr_entry; /* EQCR (EnQueue Command Ring) entries */ ++struct qm_dqrr_entry; /* DQRR (DeQueue Response Ring) entries */ ++struct qm_mr_entry; /* MR (Message Ring) entries */ ++struct qm_mc_command; /* MC (Management Command) command */ ++struct qm_mc_result; /* MC result */ ++ ++/* See David Lapp's "Frame formats" document, "dpateam", Jan 07, 2008 */ ++#define QM_FD_FORMAT_SG 0x4 ++#define QM_FD_FORMAT_LONG 0x2 ++#define QM_FD_FORMAT_COMPOUND 0x1 ++enum qm_fd_format { ++ /* 'contig' implies a contiguous buffer, whereas 'sg' implies a ++ * scatter-gather table. 'big' implies a 29-bit length with no offset ++ * field, otherwise length is 20-bit and offset is 9-bit. 'compound' ++ * implies a s/g-like table, where each entry itself represents a frame ++ * (contiguous or scatter-gather) and the 29-bit "length" is ++ * interpreted purely for congestion calculations, ie. a "congestion ++ * weight". */ ++ qm_fd_contig = 0, ++ qm_fd_contig_big = QM_FD_FORMAT_LONG, ++ qm_fd_sg = QM_FD_FORMAT_SG, ++ qm_fd_sg_big = QM_FD_FORMAT_SG | QM_FD_FORMAT_LONG, ++ qm_fd_compound = QM_FD_FORMAT_COMPOUND ++}; ++ ++/* Capitalised versions are un-typed but can be used in static expressions */ ++#define QM_FD_CONTIG 0 ++#define QM_FD_CONTIG_BIG QM_FD_FORMAT_LONG ++#define QM_FD_SG QM_FD_FORMAT_SG ++#define QM_FD_SG_BIG (QM_FD_FORMAT_SG | QM_FD_FORMAT_LONG) ++#define QM_FD_COMPOUND QM_FD_FORMAT_COMPOUND ++ ++/* See 1.5.1.1: "Frame Descriptor (FD)" */ ++struct qm_fd { ++ union { ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 dd:2; /* dynamic debug */ ++ u8 liodn_offset:6; ++ u8 bpid:8; /* Buffer Pool ID */ ++ u8 eliodn_offset:4; ++ u8 __reserved:4; ++ u8 addr_hi; /* high 8-bits of 40-bit address */ ++ u32 addr_lo; /* low 32-bits of 40-bit address */ ++#else ++ u32 addr_lo; /* low 32-bits of 40-bit address */ ++ u8 addr_hi; /* high 8-bits of 40-bit address */ ++ u8 __reserved:4; ++ u8 eliodn_offset:4; ++ u8 bpid:8; /* Buffer Pool ID */ ++ u8 liodn_offset:6; ++ u8 dd:2; /* dynamic debug */ ++#endif ++ }; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u64 __notaddress:24; ++ u64 addr:40; ++#else ++ u64 addr:40; ++ u64 __notaddress:24; ++#endif ++ }; ++ u64 opaque_addr; ++ }; ++ /* The 'format' field indicates the interpretation of the remaining 29 ++ * bits of the 32-bit word. For packing reasons, it is duplicated in the ++ * other union elements. Note, union'd structs are difficult to use with ++ * static initialisation under gcc, in which case use the "opaque" form ++ * with one of the macros. */ ++ union { ++ /* For easier/faster copying of this part of the fd (eg. from a ++ * DQRR entry to an EQCR entry) copy 'opaque' */ ++ u32 opaque; ++ /* If 'format' is _contig or _sg, 20b length and 9b offset */ ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ enum qm_fd_format format:3; ++ u16 offset:9; ++ u32 length20:20; ++#else ++ u32 length20:20; ++ u16 offset:9; ++ enum qm_fd_format format:3; ++#endif ++ }; ++ /* If 'format' is _contig_big or _sg_big, 29b length */ ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ enum qm_fd_format _format1:3; ++ u32 length29:29; ++#else ++ u32 length29:29; ++ enum qm_fd_format _format1:3; ++#endif ++ }; ++ /* If 'format' is _compound, 29b "congestion weight" */ ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ enum qm_fd_format _format2:3; ++ u32 cong_weight:29; ++#else ++ u32 cong_weight:29; ++ enum qm_fd_format _format2:3; ++#endif ++ }; ++ }; ++ union { ++ u32 cmd; ++ u32 status; ++ }; ++} __aligned(8); ++#define QM_FD_DD_NULL 0x00 ++#define QM_FD_PID_MASK 0x3f ++static inline u64 qm_fd_addr_get64(const struct qm_fd *fd) ++{ ++ return fd->addr; ++} ++ ++static inline dma_addr_t qm_fd_addr(const struct qm_fd *fd) ++{ ++ return (dma_addr_t)fd->addr; ++} ++/* Macro, so we compile better if 'v' isn't always 64-bit */ ++#define qm_fd_addr_set64(fd, v) \ ++ do { \ ++ struct qm_fd *__fd931 = (fd); \ ++ __fd931->addr = v; \ ++ } while (0) ++ ++/* For static initialisation of FDs (which is complicated by the use of unions ++ * in "struct qm_fd"), use the following macros. Note that; ++ * - 'dd', 'pid' and 'bpid' are ignored because there's no static initialisation ++ * use-case), ++ * - use capitalised QM_FD_*** formats for static initialisation. ++ */ ++#define QM_FD_FMT_20(cmd, addr_hi, addr_lo, fmt, off, len) \ ++ { 0, 0, 0, 0, 0, addr_hi, addr_lo, \ ++ { (((fmt)&0x7) << 29) | (((off)&0x1ff) << 20) | ((len)&0xfffff) }, \ ++ { cmd } } ++#define QM_FD_FMT_29(cmd, addr_hi, addr_lo, fmt, len) \ ++ { 0, 0, 0, 0, 0, addr_hi, addr_lo, \ ++ { (((fmt)&0x7) << 29) | ((len)&0x1fffffff) }, \ ++ { cmd } } ++ ++/* See 2.2.1.3 Multi-Core Datapath Acceleration Architecture */ ++#define QM_SG_OFFSET_MASK 0x1FFF ++struct qm_sg_entry { ++ union { ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 __reserved1[3]; ++ u8 addr_hi; /* high 8-bits of 40-bit address */ ++ u32 addr_lo; /* low 32-bits of 40-bit address */ ++#else ++ u32 addr_lo; /* low 32-bits of 40-bit address */ ++ u8 addr_hi; /* high 8-bits of 40-bit address */ ++ u8 __reserved1[3]; ++#endif ++ }; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u64 __notaddress:24; ++ u64 addr:40; ++#else ++ u64 addr:40; ++ u64 __notaddress:24; ++#endif ++ }; ++ u64 opaque; ++ }; ++ union { ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u32 extension:1; /* Extension bit */ ++ u32 final:1; /* Final bit */ ++ u32 length:30; ++#else ++ u32 length:30; ++ u32 final:1; /* Final bit */ ++ u32 extension:1; /* Extension bit */ ++#endif ++ }; ++ u32 sgt_efl; ++ }; ++ u8 __reserved2; ++ u8 bpid; ++ union { ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u16 __reserved3:3; ++ u16 offset:13; ++#else ++ u16 offset:13; ++ u16 __reserved3:3; ++#endif ++ }; ++ u16 opaque_offset; ++ }; ++} __packed; ++union qm_sg_efl { ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u32 extension:1; /* Extension bit */ ++ u32 final:1; /* Final bit */ ++ u32 length:30; ++#else ++ u32 length:30; ++ u32 final:1; /* Final bit */ ++ u32 extension:1; /* Extension bit */ ++#endif ++ }; ++ u32 efl; ++}; ++static inline dma_addr_t qm_sg_addr(const struct qm_sg_entry *sg) ++{ ++ return (dma_addr_t)be64_to_cpu(sg->opaque) & 0xffffffffffULL; ++} ++static inline u8 qm_sg_entry_get_ext(const struct qm_sg_entry *sg) ++{ ++ union qm_sg_efl u; ++ ++ u.efl = be32_to_cpu(sg->sgt_efl); ++ return u.extension; ++} ++static inline u8 qm_sg_entry_get_final(const struct qm_sg_entry *sg) ++{ ++ union qm_sg_efl u; ++ ++ u.efl = be32_to_cpu(sg->sgt_efl); ++ return u.final; ++} ++static inline u32 qm_sg_entry_get_len(const struct qm_sg_entry *sg) ++{ ++ union qm_sg_efl u; ++ ++ u.efl = be32_to_cpu(sg->sgt_efl); ++ return u.length; ++} ++static inline u8 qm_sg_entry_get_bpid(const struct qm_sg_entry *sg) ++{ ++ return sg->bpid; ++} ++static inline u16 qm_sg_entry_get_offset(const struct qm_sg_entry *sg) ++{ ++ u32 opaque_offset = be16_to_cpu(sg->opaque_offset); ++ ++ return opaque_offset & 0x1fff; ++} ++ ++/* Macro, so we compile better if 'v' isn't always 64-bit */ ++#define qm_sg_entry_set64(sg, v) \ ++ do { \ ++ struct qm_sg_entry *__sg931 = (sg); \ ++ __sg931->opaque = cpu_to_be64(v); \ ++ } while (0) ++#define qm_sg_entry_set_ext(sg, v) \ ++ do { \ ++ union qm_sg_efl __u932; \ ++ __u932.efl = be32_to_cpu((sg)->sgt_efl); \ ++ __u932.extension = v; \ ++ (sg)->sgt_efl = cpu_to_be32(__u932.efl); \ ++ } while (0) ++#define qm_sg_entry_set_final(sg, v) \ ++ do { \ ++ union qm_sg_efl __u933; \ ++ __u933.efl = be32_to_cpu((sg)->sgt_efl); \ ++ __u933.final = v; \ ++ (sg)->sgt_efl = cpu_to_be32(__u933.efl); \ ++ } while (0) ++#define qm_sg_entry_set_len(sg, v) \ ++ do { \ ++ union qm_sg_efl __u934; \ ++ __u934.efl = be32_to_cpu((sg)->sgt_efl); \ ++ __u934.length = v; \ ++ (sg)->sgt_efl = cpu_to_be32(__u934.efl); \ ++ } while (0) ++#define qm_sg_entry_set_bpid(sg, v) \ ++ do { \ ++ struct qm_sg_entry *__u935 = (sg); \ ++ __u935->bpid = v; \ ++ } while (0) ++#define qm_sg_entry_set_offset(sg, v) \ ++ do { \ ++ struct qm_sg_entry *__u936 = (sg); \ ++ __u936->opaque_offset = cpu_to_be16(v); \ ++ } while (0) ++ ++/* See 1.5.8.1: "Enqueue Command" */ ++struct qm_eqcr_entry { ++ u8 __dont_write_directly__verb; ++ u8 dca; ++ u16 seqnum; ++ u32 orp; /* 24-bit */ ++ u32 fqid; /* 24-bit */ ++ u32 tag; ++ struct qm_fd fd; ++ u8 __reserved3[32]; ++} __packed; ++#define QM_EQCR_VERB_VBIT 0x80 ++#define QM_EQCR_VERB_CMD_MASK 0x61 /* but only one value; */ ++#define QM_EQCR_VERB_CMD_ENQUEUE 0x01 ++#define QM_EQCR_VERB_COLOUR_MASK 0x18 /* 4 possible values; */ ++#define QM_EQCR_VERB_COLOUR_GREEN 0x00 ++#define QM_EQCR_VERB_COLOUR_YELLOW 0x08 ++#define QM_EQCR_VERB_COLOUR_RED 0x10 ++#define QM_EQCR_VERB_COLOUR_OVERRIDE 0x18 ++#define QM_EQCR_VERB_INTERRUPT 0x04 /* on command consumption */ ++#define QM_EQCR_VERB_ORP 0x02 /* enable order restoration */ ++#define QM_EQCR_DCA_ENABLE 0x80 ++#define QM_EQCR_DCA_PARK 0x40 ++#define QM_EQCR_DCA_IDXMASK 0x0f /* "DQRR::idx" goes here */ ++#define QM_EQCR_SEQNUM_NESN 0x8000 /* Advance NESN */ ++#define QM_EQCR_SEQNUM_NLIS 0x4000 /* More fragments to come */ ++#define QM_EQCR_SEQNUM_SEQMASK 0x3fff /* sequence number goes here */ ++#define QM_EQCR_FQID_NULL 0 /* eg. for an ORP seqnum hole */ ++ ++/* See 1.5.8.2: "Frame Dequeue Response" */ ++struct qm_dqrr_entry { ++ u8 verb; ++ u8 stat; ++ u16 seqnum; /* 15-bit */ ++ u8 tok; ++ u8 __reserved2[3]; ++ u32 fqid; /* 24-bit */ ++ u32 contextB; ++ struct qm_fd fd; ++ u8 __reserved4[32]; ++}; ++#define QM_DQRR_VERB_VBIT 0x80 ++#define QM_DQRR_VERB_MASK 0x7f /* where the verb contains; */ ++#define QM_DQRR_VERB_FRAME_DEQUEUE 0x60 /* "this format" */ ++#define QM_DQRR_STAT_FQ_EMPTY 0x80 /* FQ empty */ ++#define QM_DQRR_STAT_FQ_HELDACTIVE 0x40 /* FQ held active */ ++#define QM_DQRR_STAT_FQ_FORCEELIGIBLE 0x20 /* FQ was force-eligible'd */ ++#define QM_DQRR_STAT_FD_VALID 0x10 /* has a non-NULL FD */ ++#define QM_DQRR_STAT_UNSCHEDULED 0x02 /* Unscheduled dequeue */ ++#define QM_DQRR_STAT_DQCR_EXPIRED 0x01 /* VDQCR or PDQCR expired*/ ++ ++/* See 1.5.8.3: "ERN Message Response" */ ++/* See 1.5.8.4: "FQ State Change Notification" */ ++struct qm_mr_entry { ++ u8 verb; ++ union { ++ struct { ++ u8 dca; ++ u16 seqnum; ++ u8 rc; /* Rejection Code */ ++ u32 orp:24; ++ u32 fqid; /* 24-bit */ ++ u32 tag; ++ struct qm_fd fd; ++ } __packed ern; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 colour:2; /* See QM_MR_DCERN_COLOUR_* */ ++ u8 __reserved1:3; ++ enum qm_dc_portal portal:3; ++#else ++ enum qm_dc_portal portal:3; ++ u8 __reserved1:3; ++ u8 colour:2; /* See QM_MR_DCERN_COLOUR_* */ ++#endif ++ u16 __reserved2; ++ u8 rc; /* Rejection Code */ ++ u32 __reserved3:24; ++ u32 fqid; /* 24-bit */ ++ u32 tag; ++ struct qm_fd fd; ++ } __packed dcern; ++ struct { ++ u8 fqs; /* Frame Queue Status */ ++ u8 __reserved1[6]; ++ u32 fqid; /* 24-bit */ ++ u32 contextB; ++ u8 __reserved2[16]; ++ } __packed fq; /* FQRN/FQRNI/FQRL/FQPN */ ++ }; ++ u8 __reserved2[32]; ++} __packed; ++#define QM_MR_VERB_VBIT 0x80 ++/* The "ern" VERB bits match QM_EQCR_VERB_*** so aren't reproduced here. ERNs ++ * originating from direct-connect portals ("dcern") use 0x20 as a verb which ++ * would be invalid as a s/w enqueue verb. A s/w ERN can be distinguished from ++ * the other MR types by noting if the 0x20 bit is unset. */ ++#define QM_MR_VERB_TYPE_MASK 0x27 ++#define QM_MR_VERB_DC_ERN 0x20 ++#define QM_MR_VERB_FQRN 0x21 ++#define QM_MR_VERB_FQRNI 0x22 ++#define QM_MR_VERB_FQRL 0x23 ++#define QM_MR_VERB_FQPN 0x24 ++#define QM_MR_RC_MASK 0xf0 /* contains one of; */ ++#define QM_MR_RC_CGR_TAILDROP 0x00 ++#define QM_MR_RC_WRED 0x10 ++#define QM_MR_RC_ERROR 0x20 ++#define QM_MR_RC_ORPWINDOW_EARLY 0x30 ++#define QM_MR_RC_ORPWINDOW_LATE 0x40 ++#define QM_MR_RC_FQ_TAILDROP 0x50 ++#define QM_MR_RC_ORPWINDOW_RETIRED 0x60 ++#define QM_MR_RC_ORP_ZERO 0x70 ++#define QM_MR_FQS_ORLPRESENT 0x02 /* ORL fragments to come */ ++#define QM_MR_FQS_NOTEMPTY 0x01 /* FQ has enqueued frames */ ++#define QM_MR_DCERN_COLOUR_GREEN 0x00 ++#define QM_MR_DCERN_COLOUR_YELLOW 0x01 ++#define QM_MR_DCERN_COLOUR_RED 0x02 ++#define QM_MR_DCERN_COLOUR_OVERRIDE 0x03 ++ ++/* An identical structure of FQD fields is present in the "Init FQ" command and ++ * the "Query FQ" result, it's suctioned out into the "struct qm_fqd" type. ++ * Within that, the 'stashing' and 'taildrop' pieces are also factored out, the ++ * latter has two inlines to assist with converting to/from the mant+exp ++ * representation. */ ++struct qm_fqd_stashing { ++ /* See QM_STASHING_EXCL_<...> */ ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 exclusive; ++ u8 __reserved1:2; ++ /* Numbers of cachelines */ ++ u8 annotation_cl:2; ++ u8 data_cl:2; ++ u8 context_cl:2; ++#else ++ u8 context_cl:2; ++ u8 data_cl:2; ++ u8 annotation_cl:2; ++ u8 __reserved1:2; ++ u8 exclusive; ++#endif ++} __packed; ++struct qm_fqd_taildrop { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u16 __reserved1:3; ++ u16 mant:8; ++ u16 exp:5; ++#else ++ u16 exp:5; ++ u16 mant:8; ++ u16 __reserved1:3; ++#endif ++} __packed; ++struct qm_fqd_oac { ++ /* See QM_OAC_<...> */ ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 oac:2; /* "Overhead Accounting Control" */ ++ u8 __reserved1:6; ++#else ++ u8 __reserved1:6; ++ u8 oac:2; /* "Overhead Accounting Control" */ ++#endif ++ /* Two's-complement value (-128 to +127) */ ++ signed char oal; /* "Overhead Accounting Length" */ ++} __packed; ++struct qm_fqd { ++ union { ++ u8 orpc; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 __reserved1:2; ++ u8 orprws:3; ++ u8 oa:1; ++ u8 olws:2; ++#else ++ u8 olws:2; ++ u8 oa:1; ++ u8 orprws:3; ++ u8 __reserved1:2; ++#endif ++ } __packed; ++ }; ++ u8 cgid; ++ u16 fq_ctrl; /* See QM_FQCTRL_<...> */ ++ union { ++ u16 dest_wq; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u16 channel:13; /* qm_channel */ ++ u16 wq:3; ++#else ++ u16 wq:3; ++ u16 channel:13; /* qm_channel */ ++#endif ++ } __packed dest; ++ }; ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u16 __reserved2:1; ++ u16 ics_cred:15; ++#else ++ u16 __reserved2:1; ++ u16 ics_cred:15; ++#endif ++ /* For "Initialize Frame Queue" commands, the write-enable mask ++ * determines whether 'td' or 'oac_init' is observed. For query ++ * commands, this field is always 'td', and 'oac_query' (below) reflects ++ * the Overhead ACcounting values. */ ++ union { ++ struct qm_fqd_taildrop td; ++ struct qm_fqd_oac oac_init; ++ }; ++ u32 context_b; ++ union { ++ /* Treat it as 64-bit opaque */ ++ u64 opaque; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u32 hi; ++ u32 lo; ++#else ++ u32 lo; ++ u32 hi; ++#endif ++ }; ++ /* Treat it as s/w portal stashing config */ ++ /* See 1.5.6.7.1: "FQD Context_A field used for [...] */ ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ struct qm_fqd_stashing stashing; ++ /* 48-bit address of FQ context to ++ * stash, must be cacheline-aligned */ ++ u16 context_hi; ++ u32 context_lo; ++#else ++ u32 context_lo; ++ u16 context_hi; ++ struct qm_fqd_stashing stashing; ++#endif ++ } __packed; ++ } context_a; ++ struct qm_fqd_oac oac_query; ++} __packed; ++/* 64-bit converters for context_hi/lo */ ++static inline u64 qm_fqd_stashing_get64(const struct qm_fqd *fqd) ++{ ++ return ((u64)fqd->context_a.context_hi << 32) | ++ (u64)fqd->context_a.context_lo; ++} ++static inline dma_addr_t qm_fqd_stashing_addr(const struct qm_fqd *fqd) ++{ ++ return (dma_addr_t)qm_fqd_stashing_get64(fqd); ++} ++static inline u64 qm_fqd_context_a_get64(const struct qm_fqd *fqd) ++{ ++ return ((u64)fqd->context_a.hi << 32) | ++ (u64)fqd->context_a.lo; ++} ++/* Macro, so we compile better when 'v' isn't necessarily 64-bit */ ++#define qm_fqd_stashing_set64(fqd, v) \ ++ do { \ ++ struct qm_fqd *__fqd931 = (fqd); \ ++ __fqd931->context_a.context_hi = upper_32_bits(v); \ ++ __fqd931->context_a.context_lo = lower_32_bits(v); \ ++ } while (0) ++#define qm_fqd_context_a_set64(fqd, v) \ ++ do { \ ++ struct qm_fqd *__fqd931 = (fqd); \ ++ __fqd931->context_a.hi = upper_32_bits(v); \ ++ __fqd931->context_a.lo = lower_32_bits(v); \ ++ } while (0) ++/* convert a threshold value into mant+exp representation */ ++static inline int qm_fqd_taildrop_set(struct qm_fqd_taildrop *td, u32 val, ++ int roundup) ++{ ++ u32 e = 0; ++ int oddbit = 0; ++ if (val > 0xe0000000) ++ return -ERANGE; ++ while (val > 0xff) { ++ oddbit = val & 1; ++ val >>= 1; ++ e++; ++ if (roundup && oddbit) ++ val++; ++ } ++ td->exp = e; ++ td->mant = val; ++ return 0; ++} ++/* and the other direction */ ++static inline u32 qm_fqd_taildrop_get(const struct qm_fqd_taildrop *td) ++{ ++ return (u32)td->mant << td->exp; ++} ++ ++/* See 1.5.2.2: "Frame Queue Descriptor (FQD)" */ ++/* Frame Queue Descriptor (FQD) field 'fq_ctrl' uses these constants */ ++#define QM_FQCTRL_MASK 0x07ff /* 'fq_ctrl' flags; */ ++#define QM_FQCTRL_CGE 0x0400 /* Congestion Group Enable */ ++#define QM_FQCTRL_TDE 0x0200 /* Tail-Drop Enable */ ++#define QM_FQCTRL_ORP 0x0100 /* ORP Enable */ ++#define QM_FQCTRL_CTXASTASHING 0x0080 /* Context-A stashing */ ++#define QM_FQCTRL_CPCSTASH 0x0040 /* CPC Stash Enable */ ++#define QM_FQCTRL_FORCESFDR 0x0008 /* High-priority SFDRs */ ++#define QM_FQCTRL_AVOIDBLOCK 0x0004 /* Don't block active */ ++#define QM_FQCTRL_HOLDACTIVE 0x0002 /* Hold active in portal */ ++#define QM_FQCTRL_PREFERINCACHE 0x0001 /* Aggressively cache FQD */ ++#define QM_FQCTRL_LOCKINCACHE QM_FQCTRL_PREFERINCACHE /* older naming */ ++ ++/* See 1.5.6.7.1: "FQD Context_A field used for [...] */ ++/* Frame Queue Descriptor (FQD) field 'CONTEXT_A' uses these constants */ ++#define QM_STASHING_EXCL_ANNOTATION 0x04 ++#define QM_STASHING_EXCL_DATA 0x02 ++#define QM_STASHING_EXCL_CTX 0x01 ++ ++/* See 1.5.5.3: "Intra Class Scheduling" */ ++/* FQD field 'OAC' (Overhead ACcounting) uses these constants */ ++#define QM_OAC_ICS 0x2 /* Accounting for Intra-Class Scheduling */ ++#define QM_OAC_CG 0x1 /* Accounting for Congestion Groups */ ++ ++/* See 1.5.8.4: "FQ State Change Notification" */ ++/* This struct represents the 32-bit "WR_PARM_[GYR]" parameters in CGR fields ++ * and associated commands/responses. The WRED parameters are calculated from ++ * these fields as follows; ++ * MaxTH = MA * (2 ^ Mn) ++ * Slope = SA / (2 ^ Sn) ++ * MaxP = 4 * (Pn + 1) ++ */ ++struct qm_cgr_wr_parm { ++ union { ++ u32 word; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u32 MA:8; ++ u32 Mn:5; ++ u32 SA:7; /* must be between 64-127 */ ++ u32 Sn:6; ++ u32 Pn:6; ++#else ++ u32 Pn:6; ++ u32 Sn:6; ++ u32 SA:7; /* must be between 64-127 */ ++ u32 Mn:5; ++ u32 MA:8; ++#endif ++ } __packed; ++ }; ++} __packed; ++/* This struct represents the 13-bit "CS_THRES" CGR field. In the corresponding ++ * management commands, this is padded to a 16-bit structure field, so that's ++ * how we represent it here. The congestion state threshold is calculated from ++ * these fields as follows; ++ * CS threshold = TA * (2 ^ Tn) ++ */ ++struct qm_cgr_cs_thres { ++ union { ++ u16 hword; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u16 __reserved:3; ++ u16 TA:8; ++ u16 Tn:5; ++#else ++ u16 Tn:5; ++ u16 TA:8; ++ u16 __reserved:3; ++#endif ++ } __packed; ++ }; ++} __packed; ++/* This identical structure of CGR fields is present in the "Init/Modify CGR" ++ * commands and the "Query CGR" result. It's suctioned out here into its own ++ * struct. */ ++struct __qm_mc_cgr { ++ struct qm_cgr_wr_parm wr_parm_g; ++ struct qm_cgr_wr_parm wr_parm_y; ++ struct qm_cgr_wr_parm wr_parm_r; ++ u8 wr_en_g; /* boolean, use QM_CGR_EN */ ++ u8 wr_en_y; /* boolean, use QM_CGR_EN */ ++ u8 wr_en_r; /* boolean, use QM_CGR_EN */ ++ u8 cscn_en; /* boolean, use QM_CGR_EN */ ++ union { ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u16 cscn_targ_upd_ctrl; /* use QM_CSCN_TARG_UDP_ */ ++ u16 cscn_targ_dcp_low; /* CSCN_TARG_DCP low-16bits */ ++#else ++ u16 cscn_targ_dcp_low; /* CSCN_TARG_DCP low-16bits */ ++ u16 cscn_targ_upd_ctrl; /* use QM_CSCN_TARG_UDP_ */ ++#endif ++ }; ++ u32 cscn_targ; /* use QM_CGR_TARG_* */ ++ }; ++ u8 cstd_en; /* boolean, use QM_CGR_EN */ ++ u8 cs; /* boolean, only used in query response */ ++ union { ++ /* use qm_cgr_cs_thres_set64() */ ++ struct qm_cgr_cs_thres cs_thres; ++ u16 __cs_thres; ++ }; ++ u8 mode; /* QMAN_CGR_MODE_FRAME not supported in rev1.0 */ ++} __packed; ++#define QM_CGR_EN 0x01 /* For wr_en_*, cscn_en, cstd_en */ ++#define QM_CGR_TARG_UDP_CTRL_WRITE_BIT 0x8000 /* value written to portal bit*/ ++#define QM_CGR_TARG_UDP_CTRL_DCP 0x4000 /* 0: SWP, 1: DCP */ ++#define QM_CGR_TARG_PORTAL(n) (0x80000000 >> (n)) /* s/w portal, 0-9 */ ++#define QM_CGR_TARG_FMAN0 0x00200000 /* direct-connect portal: fman0 */ ++#define QM_CGR_TARG_FMAN1 0x00100000 /* : fman1 */ ++/* Convert CGR thresholds to/from "cs_thres" format */ ++static inline u64 qm_cgr_cs_thres_get64(const struct qm_cgr_cs_thres *th) ++{ ++ return (u64)th->TA << th->Tn; ++} ++static inline int qm_cgr_cs_thres_set64(struct qm_cgr_cs_thres *th, u64 val, ++ int roundup) ++{ ++ u32 e = 0; ++ int oddbit = 0; ++ while (val > 0xff) { ++ oddbit = val & 1; ++ val >>= 1; ++ e++; ++ if (roundup && oddbit) ++ val++; ++ } ++ th->Tn = e; ++ th->TA = val; ++ return 0; ++} ++ ++/* See 1.5.8.5.1: "Initialize FQ" */ ++/* See 1.5.8.5.2: "Query FQ" */ ++/* See 1.5.8.5.3: "Query FQ Non-Programmable Fields" */ ++/* See 1.5.8.5.4: "Alter FQ State Commands " */ ++/* See 1.5.8.6.1: "Initialize/Modify CGR" */ ++/* See 1.5.8.6.2: "CGR Test Write" */ ++/* See 1.5.8.6.3: "Query CGR" */ ++/* See 1.5.8.6.4: "Query Congestion Group State" */ ++struct qm_mcc_initfq { ++ u8 __reserved1; ++ u16 we_mask; /* Write Enable Mask */ ++ u32 fqid; /* 24-bit */ ++ u16 count; /* Initialises 'count+1' FQDs */ ++ struct qm_fqd fqd; /* the FQD fields go here */ ++ u8 __reserved3[30]; ++} __packed; ++struct qm_mcc_queryfq { ++ u8 __reserved1[3]; ++ u32 fqid; /* 24-bit */ ++ u8 __reserved2[56]; ++} __packed; ++struct qm_mcc_queryfq_np { ++ u8 __reserved1[3]; ++ u32 fqid; /* 24-bit */ ++ u8 __reserved2[56]; ++} __packed; ++struct qm_mcc_alterfq { ++ u8 __reserved1[3]; ++ u32 fqid; /* 24-bit */ ++ u8 __reserved2; ++ u8 count; /* number of consecutive FQID */ ++ u8 __reserved3[10]; ++ u32 context_b; /* frame queue context b */ ++ u8 __reserved4[40]; ++} __packed; ++struct qm_mcc_initcgr { ++ u8 __reserved1; ++ u16 we_mask; /* Write Enable Mask */ ++ struct __qm_mc_cgr cgr; /* CGR fields */ ++ u8 __reserved2[2]; ++ u8 cgid; ++ u8 __reserved4[32]; ++} __packed; ++struct qm_mcc_cgrtestwrite { ++ u8 __reserved1[2]; ++ u8 i_bcnt_hi:8;/* high 8-bits of 40-bit "Instant" */ ++ u32 i_bcnt_lo; /* low 32-bits of 40-bit */ ++ u8 __reserved2[23]; ++ u8 cgid; ++ u8 __reserved3[32]; ++} __packed; ++struct qm_mcc_querycgr { ++ u8 __reserved1[30]; ++ u8 cgid; ++ u8 __reserved2[32]; ++} __packed; ++struct qm_mcc_querycongestion { ++ u8 __reserved[63]; ++} __packed; ++struct qm_mcc_querywq { ++ u8 __reserved; ++ /* select channel if verb != QUERYWQ_DEDICATED */ ++ union { ++ u16 channel_wq; /* ignores wq (3 lsbits) */ ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u16 id:13; /* qm_channel */ ++ u16 __reserved1:3; ++#else ++ u16 __reserved1:3; ++ u16 id:13; /* qm_channel */ ++#endif ++ } __packed channel; ++ }; ++ u8 __reserved2[60]; ++} __packed; ++ ++struct qm_mcc_ceetm_lfqmt_config { ++ u8 __reserved1[4]; ++ u32 lfqid:24; ++ u8 __reserved2[2]; ++ u16 cqid; ++ u8 __reserved3[2]; ++ u16 dctidx; ++ u8 __reserved4[48]; ++} __packed; ++ ++struct qm_mcc_ceetm_lfqmt_query { ++ u8 __reserved1[4]; ++ u32 lfqid:24; ++ u8 __reserved2[56]; ++} __packed; ++ ++struct qm_mcc_ceetm_cq_config { ++ u8 __reserved1; ++ u16 cqid; ++ u8 dcpid; ++ u8 __reserved2; ++ u16 ccgid; ++ u8 __reserved3[56]; ++} __packed; ++ ++struct qm_mcc_ceetm_cq_query { ++ u8 __reserved1; ++ u16 cqid; ++ u8 dcpid; ++ u8 __reserved2[59]; ++} __packed; ++ ++struct qm_mcc_ceetm_dct_config { ++ u8 __reserved1; ++ u16 dctidx; ++ u8 dcpid; ++ u8 __reserved2[15]; ++ u32 context_b; ++ u64 context_a; ++ u8 __reserved3[32]; ++} __packed; ++ ++struct qm_mcc_ceetm_dct_query { ++ u8 __reserved1; ++ u16 dctidx; ++ u8 dcpid; ++ u8 __reserved2[59]; ++} __packed; ++ ++struct qm_mcc_ceetm_class_scheduler_config { ++ u8 __reserved1; ++ u16 cqcid; ++ u8 dcpid; ++ u8 __reserved2[6]; ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 gpc_reserved:1; ++ u8 gpc_combine_flag:1; ++ u8 gpc_prio_b:3; ++ u8 gpc_prio_a:3; ++#else ++ u8 gpc_prio_a:3; ++ u8 gpc_prio_b:3; ++ u8 gpc_combine_flag:1; ++ u8 gpc_reserved:1; ++#endif ++ u16 crem; ++ u16 erem; ++ u8 w[8]; ++ u8 __reserved3[40]; ++} __packed; ++ ++struct qm_mcc_ceetm_class_scheduler_query { ++ u8 __reserved1; ++ u16 cqcid; ++ u8 dcpid; ++ u8 __reserved2[59]; ++} __packed; ++ ++#define CEETM_COMMAND_CHANNEL_MAPPING (0 << 12) ++#define CEETM_COMMAND_SP_MAPPING (1 << 12) ++#define CEETM_COMMAND_CHANNEL_SHAPER (2 << 12) ++#define CEETM_COMMAND_LNI_SHAPER (3 << 12) ++#define CEETM_COMMAND_TCFC (4 << 12) ++ ++#define CEETM_CCGRID_MASK 0x01FF ++#define CEETM_CCGR_CM_CONFIGURE (0 << 14) ++#define CEETM_CCGR_DN_CONFIGURE (1 << 14) ++#define CEETM_CCGR_TEST_WRITE (2 << 14) ++#define CEETM_CCGR_CM_QUERY (0 << 14) ++#define CEETM_CCGR_DN_QUERY (1 << 14) ++#define CEETM_CCGR_DN_QUERY_FLUSH (2 << 14) ++#define CEETM_QUERY_CONGESTION_STATE (3 << 14) ++ ++struct qm_mcc_ceetm_mapping_shaper_tcfc_config { ++ u8 __reserved1; ++ u16 cid; ++ u8 dcpid; ++ union { ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 map_shaped:1; ++ u8 map_reserved:4; ++ u8 map_lni_id:3; ++#else ++ u8 map_lni_id:3; ++ u8 map_reserved:4; ++ u8 map_shaped:1; ++#endif ++ u8 __reserved2[58]; ++ } __packed channel_mapping; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 map_reserved:5; ++ u8 map_lni_id:3; ++#else ++ u8 map_lni_id:3; ++ u8 map_reserved:5; ++#endif ++ u8 __reserved2[58]; ++ } __packed sp_mapping; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 cpl:1; ++ u8 cpl_reserved:2; ++ u8 oal:5; ++#else ++ u8 oal:5; ++ u8 cpl_reserved:2; ++ u8 cpl:1; ++#endif ++ u32 crtcr:24; ++ u32 ertcr:24; ++ u16 crtbl; ++ u16 ertbl; ++ u8 mps; /* This will be hardcoded by driver with 60 */ ++ u8 __reserved2[47]; ++ } __packed shaper_config; ++ struct { ++ u8 __reserved2[11]; ++ u64 lnitcfcc; ++ u8 __reserved3[40]; ++ } __packed tcfc_config; ++ }; ++} __packed; ++ ++struct qm_mcc_ceetm_mapping_shaper_tcfc_query { ++ u8 __reserved1; ++ u16 cid; ++ u8 dcpid; ++ u8 __reserved2[59]; ++} __packed; ++ ++struct qm_mcc_ceetm_ccgr_config { ++ u8 __reserved1; ++ u16 ccgrid; ++ u8 dcpid; ++ u8 __reserved2; ++ u16 we_mask; ++ union { ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 ctl_reserved:1; ++ u8 ctl_wr_en_g:1; ++ u8 ctl_wr_en_y:1; ++ u8 ctl_wr_en_r:1; ++ u8 ctl_td_en:1; ++ u8 ctl_td_mode:1; ++ u8 ctl_cscn_en:1; ++ u8 ctl_mode:1; ++#else ++ u8 ctl_mode:1; ++ u8 ctl_cscn_en:1; ++ u8 ctl_td_mode:1; ++ u8 ctl_td_en:1; ++ u8 ctl_wr_en_r:1; ++ u8 ctl_wr_en_y:1; ++ u8 ctl_wr_en_g:1; ++ u8 ctl_reserved:1; ++#endif ++ u8 cdv; ++ u16 cscn_tupd; ++ u8 oal; ++ u8 __reserved3; ++ struct qm_cgr_cs_thres cs_thres; ++ struct qm_cgr_cs_thres cs_thres_x; ++ struct qm_cgr_cs_thres td_thres; ++ struct qm_cgr_wr_parm wr_parm_g; ++ struct qm_cgr_wr_parm wr_parm_y; ++ struct qm_cgr_wr_parm wr_parm_r; ++ } __packed cm_config; ++ struct { ++ u8 dnc; ++ u8 dn0; ++ u8 dn1; ++ u64 dnba:40; ++ u8 __reserved3[2]; ++ u16 dnth_0; ++ u8 __reserved4[2]; ++ u16 dnth_1; ++ u8 __reserved5[8]; ++ } __packed dn_config; ++ struct { ++ u8 __reserved3[3]; ++ u64 i_cnt:40; ++ u8 __reserved4[16]; ++ } __packed test_write; ++ }; ++ u8 __reserved5[32]; ++} __packed; ++ ++struct qm_mcc_ceetm_ccgr_query { ++ u8 __reserved1; ++ u16 ccgrid; ++ u8 dcpid; ++ u8 __reserved2[59]; ++} __packed; ++ ++struct qm_mcc_ceetm_cq_peek_pop_xsfdrread { ++ u8 __reserved1; ++ u16 cqid; ++ u8 dcpid; ++ u8 ct; ++ u16 xsfdr; ++ u8 __reserved2[56]; ++} __packed; ++ ++#define CEETM_QUERY_DEQUEUE_STATISTICS 0x00 ++#define CEETM_QUERY_DEQUEUE_CLEAR_STATISTICS 0x01 ++#define CEETM_WRITE_DEQUEUE_STATISTICS 0x02 ++#define CEETM_QUERY_REJECT_STATISTICS 0x03 ++#define CEETM_QUERY_REJECT_CLEAR_STATISTICS 0x04 ++#define CEETM_WRITE_REJECT_STATISTICS 0x05 ++struct qm_mcc_ceetm_statistics_query_write { ++ u8 __reserved1; ++ u16 cid; ++ u8 dcpid; ++ u8 ct; ++ u8 __reserved2[13]; ++ u64 frm_cnt:40; ++ u8 __reserved3[2]; ++ u64 byte_cnt:48; ++ u8 __reserved[32]; ++} __packed; ++ ++struct qm_mc_command { ++ u8 __dont_write_directly__verb; ++ union { ++ struct qm_mcc_initfq initfq; ++ struct qm_mcc_queryfq queryfq; ++ struct qm_mcc_queryfq_np queryfq_np; ++ struct qm_mcc_alterfq alterfq; ++ struct qm_mcc_initcgr initcgr; ++ struct qm_mcc_cgrtestwrite cgrtestwrite; ++ struct qm_mcc_querycgr querycgr; ++ struct qm_mcc_querycongestion querycongestion; ++ struct qm_mcc_querywq querywq; ++ struct qm_mcc_ceetm_lfqmt_config lfqmt_config; ++ struct qm_mcc_ceetm_lfqmt_query lfqmt_query; ++ struct qm_mcc_ceetm_cq_config cq_config; ++ struct qm_mcc_ceetm_cq_query cq_query; ++ struct qm_mcc_ceetm_dct_config dct_config; ++ struct qm_mcc_ceetm_dct_query dct_query; ++ struct qm_mcc_ceetm_class_scheduler_config csch_config; ++ struct qm_mcc_ceetm_class_scheduler_query csch_query; ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_config mst_config; ++ struct qm_mcc_ceetm_mapping_shaper_tcfc_query mst_query; ++ struct qm_mcc_ceetm_ccgr_config ccgr_config; ++ struct qm_mcc_ceetm_ccgr_query ccgr_query; ++ struct qm_mcc_ceetm_cq_peek_pop_xsfdrread cq_ppxr; ++ struct qm_mcc_ceetm_statistics_query_write stats_query_write; ++ }; ++} __packed; ++#define QM_MCC_VERB_VBIT 0x80 ++#define QM_MCC_VERB_MASK 0x7f /* where the verb contains; */ ++#define QM_MCC_VERB_INITFQ_PARKED 0x40 ++#define QM_MCC_VERB_INITFQ_SCHED 0x41 ++#define QM_MCC_VERB_QUERYFQ 0x44 ++#define QM_MCC_VERB_QUERYFQ_NP 0x45 /* "non-programmable" fields */ ++#define QM_MCC_VERB_QUERYWQ 0x46 ++#define QM_MCC_VERB_QUERYWQ_DEDICATED 0x47 ++#define QM_MCC_VERB_ALTER_SCHED 0x48 /* Schedule FQ */ ++#define QM_MCC_VERB_ALTER_FE 0x49 /* Force Eligible FQ */ ++#define QM_MCC_VERB_ALTER_RETIRE 0x4a /* Retire FQ */ ++#define QM_MCC_VERB_ALTER_OOS 0x4b /* Take FQ out of service */ ++#define QM_MCC_VERB_ALTER_FQXON 0x4d /* FQ XON */ ++#define QM_MCC_VERB_ALTER_FQXOFF 0x4e /* FQ XOFF */ ++#define QM_MCC_VERB_INITCGR 0x50 ++#define QM_MCC_VERB_MODIFYCGR 0x51 ++#define QM_MCC_VERB_CGRTESTWRITE 0x52 ++#define QM_MCC_VERB_QUERYCGR 0x58 ++#define QM_MCC_VERB_QUERYCONGESTION 0x59 ++/* INITFQ-specific flags */ ++#define QM_INITFQ_WE_MASK 0x01ff /* 'Write Enable' flags; */ ++#define QM_INITFQ_WE_OAC 0x0100 ++#define QM_INITFQ_WE_ORPC 0x0080 ++#define QM_INITFQ_WE_CGID 0x0040 ++#define QM_INITFQ_WE_FQCTRL 0x0020 ++#define QM_INITFQ_WE_DESTWQ 0x0010 ++#define QM_INITFQ_WE_ICSCRED 0x0008 ++#define QM_INITFQ_WE_TDTHRESH 0x0004 ++#define QM_INITFQ_WE_CONTEXTB 0x0002 ++#define QM_INITFQ_WE_CONTEXTA 0x0001 ++/* INITCGR/MODIFYCGR-specific flags */ ++#define QM_CGR_WE_MASK 0x07ff /* 'Write Enable Mask'; */ ++#define QM_CGR_WE_WR_PARM_G 0x0400 ++#define QM_CGR_WE_WR_PARM_Y 0x0200 ++#define QM_CGR_WE_WR_PARM_R 0x0100 ++#define QM_CGR_WE_WR_EN_G 0x0080 ++#define QM_CGR_WE_WR_EN_Y 0x0040 ++#define QM_CGR_WE_WR_EN_R 0x0020 ++#define QM_CGR_WE_CSCN_EN 0x0010 ++#define QM_CGR_WE_CSCN_TARG 0x0008 ++#define QM_CGR_WE_CSTD_EN 0x0004 ++#define QM_CGR_WE_CS_THRES 0x0002 ++#define QM_CGR_WE_MODE 0x0001 ++ ++/* See 1.5.9.7 CEETM Management Commands */ ++#define QM_CEETM_VERB_LFQMT_CONFIG 0x70 ++#define QM_CEETM_VERB_LFQMT_QUERY 0x71 ++#define QM_CEETM_VERB_CQ_CONFIG 0x72 ++#define QM_CEETM_VERB_CQ_QUERY 0x73 ++#define QM_CEETM_VERB_DCT_CONFIG 0x74 ++#define QM_CEETM_VERB_DCT_QUERY 0x75 ++#define QM_CEETM_VERB_CLASS_SCHEDULER_CONFIG 0x76 ++#define QM_CEETM_VERB_CLASS_SCHEDULER_QUERY 0x77 ++#define QM_CEETM_VERB_MAPPING_SHAPER_TCFC_CONFIG 0x78 ++#define QM_CEETM_VERB_MAPPING_SHAPER_TCFC_QUERY 0x79 ++#define QM_CEETM_VERB_CCGR_CONFIG 0x7A ++#define QM_CEETM_VERB_CCGR_QUERY 0x7B ++#define QM_CEETM_VERB_CQ_PEEK_POP_XFDRREAD 0x7C ++#define QM_CEETM_VERB_STATISTICS_QUERY_WRITE 0x7D ++ ++/* See 1.5.8.5.1: "Initialize FQ" */ ++/* See 1.5.8.5.2: "Query FQ" */ ++/* See 1.5.8.5.3: "Query FQ Non-Programmable Fields" */ ++/* See 1.5.8.5.4: "Alter FQ State Commands " */ ++/* See 1.5.8.6.1: "Initialize/Modify CGR" */ ++/* See 1.5.8.6.2: "CGR Test Write" */ ++/* See 1.5.8.6.3: "Query CGR" */ ++/* See 1.5.8.6.4: "Query Congestion Group State" */ ++struct qm_mcr_initfq { ++ u8 __reserved1[62]; ++} __packed; ++struct qm_mcr_queryfq { ++ u8 __reserved1[8]; ++ struct qm_fqd fqd; /* the FQD fields are here */ ++ u8 __reserved2[30]; ++} __packed; ++struct qm_mcr_queryfq_np { ++ u8 __reserved1; ++ u8 state; /* QM_MCR_NP_STATE_*** */ ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 __reserved2; ++ u32 fqd_link:24; ++ u16 __reserved3:2; ++ u16 odp_seq:14; ++ u16 __reserved4:2; ++ u16 orp_nesn:14; ++ u16 __reserved5:1; ++ u16 orp_ea_hseq:15; ++ u16 __reserved6:1; ++ u16 orp_ea_tseq:15; ++ u8 __reserved7; ++ u32 orp_ea_hptr:24; ++ u8 __reserved8; ++ u32 orp_ea_tptr:24; ++ u8 __reserved9; ++ u32 pfdr_hptr:24; ++ u8 __reserved10; ++ u32 pfdr_tptr:24; ++ u8 __reserved11[5]; ++ u8 __reserved12:7; ++ u8 is:1; ++ u16 ics_surp; ++ u32 byte_cnt; ++ u8 __reserved13; ++ u32 frm_cnt:24; ++ u32 __reserved14; ++ u16 ra1_sfdr; /* QM_MCR_NP_RA1_*** */ ++ u16 ra2_sfdr; /* QM_MCR_NP_RA2_*** */ ++ u16 __reserved15; ++ u16 od1_sfdr; /* QM_MCR_NP_OD1_*** */ ++ u16 od2_sfdr; /* QM_MCR_NP_OD2_*** */ ++ u16 od3_sfdr; /* QM_MCR_NP_OD3_*** */ ++#else ++ u8 __reserved2; ++ u32 fqd_link:24; ++ ++ u16 odp_seq:14; ++ u16 __reserved3:2; ++ ++ u16 orp_nesn:14; ++ u16 __reserved4:2; ++ ++ u16 orp_ea_hseq:15; ++ u16 __reserved5:1; ++ ++ u16 orp_ea_tseq:15; ++ u16 __reserved6:1; ++ ++ u8 __reserved7; ++ u32 orp_ea_hptr:24; ++ ++ u8 __reserved8; ++ u32 orp_ea_tptr:24; ++ ++ u8 __reserved9; ++ u32 pfdr_hptr:24; ++ ++ u8 __reserved10; ++ u32 pfdr_tptr:24; ++ ++ u8 __reserved11[5]; ++ u8 is:1; ++ u8 __reserved12:7; ++ u16 ics_surp; ++ u32 byte_cnt; ++ u8 __reserved13; ++ u32 frm_cnt:24; ++ u32 __reserved14; ++ u16 ra1_sfdr; /* QM_MCR_NP_RA1_*** */ ++ u16 ra2_sfdr; /* QM_MCR_NP_RA2_*** */ ++ u16 __reserved15; ++ u16 od1_sfdr; /* QM_MCR_NP_OD1_*** */ ++ u16 od2_sfdr; /* QM_MCR_NP_OD2_*** */ ++ u16 od3_sfdr; /* QM_MCR_NP_OD3_*** */ ++#endif ++} __packed; ++ ++ ++struct qm_mcr_alterfq { ++ u8 fqs; /* Frame Queue Status */ ++ u8 __reserved1[61]; ++} __packed; ++struct qm_mcr_initcgr { ++ u8 __reserved1[62]; ++} __packed; ++struct qm_mcr_cgrtestwrite { ++ u16 __reserved1; ++ struct __qm_mc_cgr cgr; /* CGR fields */ ++ u8 __reserved2[3]; ++ u32 __reserved3:24; ++ u32 i_bcnt_hi:8;/* high 8-bits of 40-bit "Instant" */ ++ u32 i_bcnt_lo; /* low 32-bits of 40-bit */ ++ u32 __reserved4:24; ++ u32 a_bcnt_hi:8;/* high 8-bits of 40-bit "Average" */ ++ u32 a_bcnt_lo; /* low 32-bits of 40-bit */ ++ u16 lgt; /* Last Group Tick */ ++ u16 wr_prob_g; ++ u16 wr_prob_y; ++ u16 wr_prob_r; ++ u8 __reserved5[8]; ++} __packed; ++struct qm_mcr_querycgr { ++ u16 __reserved1; ++ struct __qm_mc_cgr cgr; /* CGR fields */ ++ u8 __reserved2[3]; ++ union { ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u32 __reserved3:24; ++ u32 i_bcnt_hi:8;/* high 8-bits of 40-bit "Instant" */ ++ u32 i_bcnt_lo; /* low 32-bits of 40-bit */ ++#else ++ u32 i_bcnt_lo; /* low 32-bits of 40-bit */ ++ u32 i_bcnt_hi:8;/* high 8-bits of 40-bit "Instant" */ ++ u32 __reserved3:24; ++#endif ++ }; ++ u64 i_bcnt; ++ }; ++ union { ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u32 __reserved4:24; ++ u32 a_bcnt_hi:8;/* high 8-bits of 40-bit "Average" */ ++ u32 a_bcnt_lo; /* low 32-bits of 40-bit */ ++#else ++ u32 a_bcnt_lo; /* low 32-bits of 40-bit */ ++ u32 a_bcnt_hi:8;/* high 8-bits of 40-bit "Average" */ ++ u32 __reserved4:24; ++#endif ++ }; ++ u64 a_bcnt; ++ }; ++ union { ++ u32 cscn_targ_swp[4]; ++ u8 __reserved5[16]; ++ }; ++} __packed; ++static inline u64 qm_mcr_querycgr_i_get64(const struct qm_mcr_querycgr *q) ++{ ++ return be64_to_cpu(q->i_bcnt); ++} ++static inline u64 qm_mcr_querycgr_a_get64(const struct qm_mcr_querycgr *q) ++{ ++ return be64_to_cpu(q->a_bcnt); ++} ++static inline u64 qm_mcr_cgrtestwrite_i_get64( ++ const struct qm_mcr_cgrtestwrite *q) ++{ ++ return be64_to_cpu(((u64)q->i_bcnt_hi << 32) | (u64)q->i_bcnt_lo); ++} ++static inline u64 qm_mcr_cgrtestwrite_a_get64( ++ const struct qm_mcr_cgrtestwrite *q) ++{ ++ return be64_to_cpu(((u64)q->a_bcnt_hi << 32) | (u64)q->a_bcnt_lo); ++} ++/* Macro, so we compile better if 'v' isn't always 64-bit */ ++#define qm_mcr_querycgr_i_set64(q, v) \ ++ do { \ ++ struct qm_mcr_querycgr *__q931 = (fd); \ ++ __q931->i_bcnt_hi = upper_32_bits(v); \ ++ __q931->i_bcnt_lo = lower_32_bits(v); \ ++ } while (0) ++#define qm_mcr_querycgr_a_set64(q, v) \ ++ do { \ ++ struct qm_mcr_querycgr *__q931 = (fd); \ ++ __q931->a_bcnt_hi = upper_32_bits(v); \ ++ __q931->a_bcnt_lo = lower_32_bits(v); \ ++ } while (0) ++struct __qm_mcr_querycongestion { ++ u32 __state[8]; ++}; ++struct qm_mcr_querycongestion { ++ u8 __reserved[30]; ++ /* Access this struct using QM_MCR_QUERYCONGESTION() */ ++ struct __qm_mcr_querycongestion state; ++} __packed; ++struct qm_mcr_querywq { ++ union { ++ u16 channel_wq; /* ignores wq (3 lsbits) */ ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u16 id:13; /* qm_channel */ ++ u16 __reserved:3; ++#else ++ u16 __reserved:3; ++ u16 id:13; /* qm_channel */ ++#endif ++ } __packed channel; ++ }; ++ u8 __reserved[28]; ++ u32 wq_len[8]; ++} __packed; ++ ++/* QMAN CEETM Management Command Response */ ++struct qm_mcr_ceetm_lfqmt_config { ++ u8 __reserved1[62]; ++} __packed; ++struct qm_mcr_ceetm_lfqmt_query { ++ u8 __reserved1[8]; ++ u16 cqid; ++ u8 __reserved2[2]; ++ u16 dctidx; ++ u8 __reserved3[2]; ++ u16 ccgid; ++ u8 __reserved4[44]; ++} __packed; ++ ++struct qm_mcr_ceetm_cq_config { ++ u8 __reserved1[62]; ++} __packed; ++ ++struct qm_mcr_ceetm_cq_query { ++ u8 __reserved1[4]; ++ u16 ccgid; ++ u16 state; ++ u32 pfdr_hptr:24; ++ u32 pfdr_tptr:24; ++ u16 od1_xsfdr; ++ u16 od2_xsfdr; ++ u16 od3_xsfdr; ++ u16 od4_xsfdr; ++ u16 od5_xsfdr; ++ u16 od6_xsfdr; ++ u16 ra1_xsfdr; ++ u16 ra2_xsfdr; ++ u8 __reserved2; ++ u32 frm_cnt:24; ++ u8 __reserved333[28]; ++} __packed; ++ ++struct qm_mcr_ceetm_dct_config { ++ u8 __reserved1[62]; ++} __packed; ++ ++struct qm_mcr_ceetm_dct_query { ++ u8 __reserved1[18]; ++ u32 context_b; ++ u64 context_a; ++ u8 __reserved2[32]; ++} __packed; ++ ++struct qm_mcr_ceetm_class_scheduler_config { ++ u8 __reserved1[62]; ++} __packed; ++ ++struct qm_mcr_ceetm_class_scheduler_query { ++ u8 __reserved1[9]; ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 gpc_reserved:1; ++ u8 gpc_combine_flag:1; ++ u8 gpc_prio_b:3; ++ u8 gpc_prio_a:3; ++#else ++ u8 gpc_prio_a:3; ++ u8 gpc_prio_b:3; ++ u8 gpc_combine_flag:1; ++ u8 gpc_reserved:1; ++#endif ++ u16 crem; ++ u16 erem; ++ u8 w[8]; ++ u8 __reserved2[5]; ++ u32 wbfslist:24; ++ u32 d8; ++ u32 d9; ++ u32 d10; ++ u32 d11; ++ u32 d12; ++ u32 d13; ++ u32 d14; ++ u32 d15; ++} __packed; ++ ++struct qm_mcr_ceetm_mapping_shaper_tcfc_config { ++ u16 cid; ++ u8 __reserved2[60]; ++} __packed; ++ ++struct qm_mcr_ceetm_mapping_shaper_tcfc_query { ++ u16 cid; ++ u8 __reserved1; ++ union { ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 map_shaped:1; ++ u8 map_reserved:4; ++ u8 map_lni_id:3; ++#else ++ u8 map_lni_id:3; ++ u8 map_reserved:4; ++ u8 map_shaped:1; ++#endif ++ u8 __reserved2[58]; ++ } __packed channel_mapping_query; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 map_reserved:5; ++ u8 map_lni_id:3; ++#else ++ u8 map_lni_id:3; ++ u8 map_reserved:5; ++#endif ++ u8 __reserved2[58]; ++ } __packed sp_mapping_query; ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 cpl:1; ++ u8 cpl_reserved:2; ++ u8 oal:5; ++#else ++ u8 oal:5; ++ u8 cpl_reserved:2; ++ u8 cpl:1; ++#endif ++ u32 crtcr:24; ++ u32 ertcr:24; ++ u16 crtbl; ++ u16 ertbl; ++ u8 mps; ++ u8 __reserved2[15]; ++ u32 crat; ++ u32 erat; ++ u8 __reserved3[24]; ++ } __packed shaper_query; ++ struct { ++ u8 __reserved1[11]; ++ u64 lnitcfcc; ++ u8 __reserved3[40]; ++ } __packed tcfc_query; ++ }; ++} __packed; ++ ++struct qm_mcr_ceetm_ccgr_config { ++ u8 __reserved1[46]; ++ union { ++ u8 __reserved2[8]; ++ struct { ++ u16 timestamp; ++ u16 wr_porb_g; ++ u16 wr_prob_y; ++ u16 wr_prob_r; ++ } __packed test_write; ++ }; ++ u8 __reserved3[8]; ++} __packed; ++ ++struct qm_mcr_ceetm_ccgr_query { ++ u8 __reserved1[6]; ++ union { ++ struct { ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ u8 ctl_reserved:1; ++ u8 ctl_wr_en_g:1; ++ u8 ctl_wr_en_y:1; ++ u8 ctl_wr_en_r:1; ++ u8 ctl_td_en:1; ++ u8 ctl_td_mode:1; ++ u8 ctl_cscn_en:1; ++ u8 ctl_mode:1; ++#else ++ u8 ctl_mode:1; ++ u8 ctl_cscn_en:1; ++ u8 ctl_td_mode:1; ++ u8 ctl_td_en:1; ++ u8 ctl_wr_en_r:1; ++ u8 ctl_wr_en_y:1; ++ u8 ctl_wr_en_g:1; ++ u8 ctl_reserved:1; ++#endif ++ u8 cdv; ++ u8 __reserved2[2]; ++ u8 oal; ++ u8 __reserved3; ++ struct qm_cgr_cs_thres cs_thres; ++ struct qm_cgr_cs_thres cs_thres_x; ++ struct qm_cgr_cs_thres td_thres; ++ struct qm_cgr_wr_parm wr_parm_g; ++ struct qm_cgr_wr_parm wr_parm_y; ++ struct qm_cgr_wr_parm wr_parm_r; ++ u16 cscn_targ_dcp; ++ u8 dcp_lsn; ++ u64 i_cnt:40; ++ u8 __reserved4[3]; ++ u64 a_cnt:40; ++ u32 cscn_targ_swp[4]; ++ } __packed cm_query; ++ struct { ++ u8 dnc; ++ u8 dn0; ++ u8 dn1; ++ u64 dnba:40; ++ u8 __reserved2[2]; ++ u16 dnth_0; ++ u8 __reserved3[2]; ++ u16 dnth_1; ++ u8 __reserved4[10]; ++ u16 dnacc_0; ++ u8 __reserved5[2]; ++ u16 dnacc_1; ++ u8 __reserved6[24]; ++ } __packed dn_query; ++ struct { ++ u8 __reserved2[24]; ++ struct __qm_mcr_querycongestion state; ++ } __packed congestion_state; ++ ++ }; ++} __packed; ++ ++struct qm_mcr_ceetm_cq_peek_pop_xsfdrread { ++ u8 stat; ++ u8 __reserved1[11]; ++ u16 dctidx; ++ struct qm_fd fd; ++ u8 __reserved2[32]; ++} __packed; ++ ++struct qm_mcr_ceetm_statistics_query { ++ u8 __reserved1[17]; ++ u64 frm_cnt:40; ++ u8 __reserved2[2]; ++ u64 byte_cnt:48; ++ u8 __reserved3[32]; ++} __packed; ++ ++struct qm_mc_result { ++ u8 verb; ++ u8 result; ++ union { ++ struct qm_mcr_initfq initfq; ++ struct qm_mcr_queryfq queryfq; ++ struct qm_mcr_queryfq_np queryfq_np; ++ struct qm_mcr_alterfq alterfq; ++ struct qm_mcr_initcgr initcgr; ++ struct qm_mcr_cgrtestwrite cgrtestwrite; ++ struct qm_mcr_querycgr querycgr; ++ struct qm_mcr_querycongestion querycongestion; ++ struct qm_mcr_querywq querywq; ++ struct qm_mcr_ceetm_lfqmt_config lfqmt_config; ++ struct qm_mcr_ceetm_lfqmt_query lfqmt_query; ++ struct qm_mcr_ceetm_cq_config cq_config; ++ struct qm_mcr_ceetm_cq_query cq_query; ++ struct qm_mcr_ceetm_dct_config dct_config; ++ struct qm_mcr_ceetm_dct_query dct_query; ++ struct qm_mcr_ceetm_class_scheduler_config csch_config; ++ struct qm_mcr_ceetm_class_scheduler_query csch_query; ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_config mst_config; ++ struct qm_mcr_ceetm_mapping_shaper_tcfc_query mst_query; ++ struct qm_mcr_ceetm_ccgr_config ccgr_config; ++ struct qm_mcr_ceetm_ccgr_query ccgr_query; ++ struct qm_mcr_ceetm_cq_peek_pop_xsfdrread cq_ppxr; ++ struct qm_mcr_ceetm_statistics_query stats_query; ++ }; ++} __packed; ++ ++#define QM_MCR_VERB_RRID 0x80 ++#define QM_MCR_VERB_MASK QM_MCC_VERB_MASK ++#define QM_MCR_VERB_INITFQ_PARKED QM_MCC_VERB_INITFQ_PARKED ++#define QM_MCR_VERB_INITFQ_SCHED QM_MCC_VERB_INITFQ_SCHED ++#define QM_MCR_VERB_QUERYFQ QM_MCC_VERB_QUERYFQ ++#define QM_MCR_VERB_QUERYFQ_NP QM_MCC_VERB_QUERYFQ_NP ++#define QM_MCR_VERB_QUERYWQ QM_MCC_VERB_QUERYWQ ++#define QM_MCR_VERB_QUERYWQ_DEDICATED QM_MCC_VERB_QUERYWQ_DEDICATED ++#define QM_MCR_VERB_ALTER_SCHED QM_MCC_VERB_ALTER_SCHED ++#define QM_MCR_VERB_ALTER_FE QM_MCC_VERB_ALTER_FE ++#define QM_MCR_VERB_ALTER_RETIRE QM_MCC_VERB_ALTER_RETIRE ++#define QM_MCR_VERB_ALTER_OOS QM_MCC_VERB_ALTER_OOS ++#define QM_MCR_RESULT_NULL 0x00 ++#define QM_MCR_RESULT_OK 0xf0 ++#define QM_MCR_RESULT_ERR_FQID 0xf1 ++#define QM_MCR_RESULT_ERR_FQSTATE 0xf2 ++#define QM_MCR_RESULT_ERR_NOTEMPTY 0xf3 /* OOS fails if FQ is !empty */ ++#define QM_MCR_RESULT_ERR_BADCHANNEL 0xf4 ++#define QM_MCR_RESULT_PENDING 0xf8 ++#define QM_MCR_RESULT_ERR_BADCOMMAND 0xff ++#define QM_MCR_NP_STATE_FE 0x10 ++#define QM_MCR_NP_STATE_R 0x08 ++#define QM_MCR_NP_STATE_MASK 0x07 /* Reads FQD::STATE; */ ++#define QM_MCR_NP_STATE_OOS 0x00 ++#define QM_MCR_NP_STATE_RETIRED 0x01 ++#define QM_MCR_NP_STATE_TEN_SCHED 0x02 ++#define QM_MCR_NP_STATE_TRU_SCHED 0x03 ++#define QM_MCR_NP_STATE_PARKED 0x04 ++#define QM_MCR_NP_STATE_ACTIVE 0x05 ++#define QM_MCR_NP_PTR_MASK 0x07ff /* for RA[12] & OD[123] */ ++#define QM_MCR_NP_RA1_NRA(v) (((v) >> 14) & 0x3) /* FQD::NRA */ ++#define QM_MCR_NP_RA2_IT(v) (((v) >> 14) & 0x1) /* FQD::IT */ ++#define QM_MCR_NP_OD1_NOD(v) (((v) >> 14) & 0x3) /* FQD::NOD */ ++#define QM_MCR_NP_OD3_NPC(v) (((v) >> 14) & 0x3) /* FQD::NPC */ ++#define QM_MCR_FQS_ORLPRESENT 0x02 /* ORL fragments to come */ ++#define QM_MCR_FQS_NOTEMPTY 0x01 /* FQ has enqueued frames */ ++/* This extracts the state for congestion group 'n' from a query response. ++ * Eg. ++ * u8 cgr = [...]; ++ * struct qm_mc_result *res = [...]; ++ * printf("congestion group %d congestion state: %d\n", cgr, ++ * QM_MCR_QUERYCONGESTION(&res->querycongestion.state, cgr)); ++ */ ++#define __CGR_WORD(num) (num >> 5) ++#define __CGR_SHIFT(num) (num & 0x1f) ++#define __CGR_NUM (sizeof(struct __qm_mcr_querycongestion) << 3) ++static inline int QM_MCR_QUERYCONGESTION(struct __qm_mcr_querycongestion *p, ++ u8 cgr) ++{ ++ return p->__state[__CGR_WORD(cgr)] & (0x80000000 >> __CGR_SHIFT(cgr)); ++} ++ ++ ++/*********************/ ++/* Utility interface */ ++/*********************/ ++ ++/* Represents an allocator over a range of FQIDs. NB, accesses are not locked, ++ * spinlock them yourself if needed. */ ++struct qman_fqid_pool; ++ ++/* Create/destroy a FQID pool, num must be a multiple of 32. NB, _destroy() ++ * always succeeds, but returns non-zero if there were "leaked" FQID ++ * allocations. */ ++struct qman_fqid_pool *qman_fqid_pool_create(u32 fqid_start, u32 num); ++int qman_fqid_pool_destroy(struct qman_fqid_pool *pool); ++/* Alloc/free a FQID from the range. _alloc() returns zero for success. */ ++int qman_fqid_pool_alloc(struct qman_fqid_pool *pool, u32 *fqid); ++void qman_fqid_pool_free(struct qman_fqid_pool *pool, u32 fqid); ++u32 qman_fqid_pool_used(struct qman_fqid_pool *pool); ++ ++/*******************************************************************/ ++/* Managed (aka "shared" or "mux/demux") portal, high-level i/face */ ++/*******************************************************************/ ++ ++ /* Portal and Frame Queues */ ++ /* ----------------------- */ ++/* Represents a managed portal */ ++struct qman_portal; ++ ++/* This object type represents Qman frame queue descriptors (FQD), it is ++ * cacheline-aligned, and initialised by qman_create_fq(). The structure is ++ * defined further down. */ ++struct qman_fq; ++ ++/* This object type represents a Qman congestion group, it is defined further ++ * down. */ ++struct qman_cgr; ++ ++struct qman_portal_config { ++ /* If the caller enables DQRR stashing (and thus wishes to operate the ++ * portal from only one cpu), this is the logical CPU that the portal ++ * will stash to. Whether stashing is enabled or not, this setting is ++ * also used for any "core-affine" portals, ie. default portals ++ * associated to the corresponding cpu. -1 implies that there is no core ++ * affinity configured. */ ++ int cpu; ++ /* portal interrupt line */ ++ int irq; ++ /* the unique index of this portal */ ++ u32 index; ++ /* Is this portal shared? (If so, it has coarser locking and demuxes ++ * processing on behalf of other CPUs.) */ ++ int is_shared; ++ /* The portal's dedicated channel id, use this value for initialising ++ * frame queues to target this portal when scheduled. */ ++ u16 channel; ++ /* A mask of which pool channels this portal has dequeue access to ++ * (using QM_SDQCR_CHANNELS_POOL(n) for the bitmask) */ ++ u32 pools; ++}; ++ ++/* This enum, and the callback type that returns it, are used when handling ++ * dequeued frames via DQRR. Note that for "null" callbacks registered with the ++ * portal object (for handling dequeues that do not demux because contextB is ++ * NULL), the return value *MUST* be qman_cb_dqrr_consume. */ ++enum qman_cb_dqrr_result { ++ /* DQRR entry can be consumed */ ++ qman_cb_dqrr_consume, ++ /* Like _consume, but requests parking - FQ must be held-active */ ++ qman_cb_dqrr_park, ++ /* Does not consume, for DCA mode only. This allows out-of-order ++ * consumes by explicit calls to qman_dca() and/or the use of implicit ++ * DCA via EQCR entries. */ ++ qman_cb_dqrr_defer, ++ /* Stop processing without consuming this ring entry. Exits the current ++ * qman_poll_dqrr() or interrupt-handling, as appropriate. If within an ++ * interrupt handler, the callback would typically call ++ * qman_irqsource_remove(QM_PIRQ_DQRI) before returning this value, ++ * otherwise the interrupt will reassert immediately. */ ++ qman_cb_dqrr_stop, ++ /* Like qman_cb_dqrr_stop, but consumes the current entry. */ ++ qman_cb_dqrr_consume_stop ++}; ++typedef enum qman_cb_dqrr_result (*qman_cb_dqrr)(struct qman_portal *qm, ++ struct qman_fq *fq, ++ const struct qm_dqrr_entry *dqrr); ++ ++/* This callback type is used when handling ERNs, FQRNs and FQRLs via MR. They ++ * are always consumed after the callback returns. */ ++typedef void (*qman_cb_mr)(struct qman_portal *qm, struct qman_fq *fq, ++ const struct qm_mr_entry *msg); ++ ++/* This callback type is used when handling DCP ERNs */ ++typedef void (*qman_cb_dc_ern)(struct qman_portal *qm, ++ const struct qm_mr_entry *msg); ++ ++/* s/w-visible states. Ie. tentatively scheduled + truly scheduled + active + ++ * held-active + held-suspended are just "sched". Things like "retired" will not ++ * be assumed until it is complete (ie. QMAN_FQ_STATE_CHANGING is set until ++ * then, to indicate it's completing and to gate attempts to retry the retire ++ * command). Note, park commands do not set QMAN_FQ_STATE_CHANGING because it's ++ * technically impossible in the case of enqueue DCAs (which refer to DQRR ring ++ * index rather than the FQ that ring entry corresponds to), so repeated park ++ * commands are allowed (if you're silly enough to try) but won't change FQ ++ * state, and the resulting park notifications move FQs from "sched" to ++ * "parked". */ ++enum qman_fq_state { ++ qman_fq_state_oos, ++ qman_fq_state_parked, ++ qman_fq_state_sched, ++ qman_fq_state_retired ++}; ++ ++/* Frame queue objects (struct qman_fq) are stored within memory passed to ++ * qman_create_fq(), as this allows stashing of caller-provided demux callback ++ * pointers at no extra cost to stashing of (driver-internal) FQ state. If the ++ * caller wishes to add per-FQ state and have it benefit from dequeue-stashing, ++ * they should; ++ * ++ * (a) extend the qman_fq structure with their state; eg. ++ * ++ * // myfq is allocated and driver_fq callbacks filled in; ++ * struct my_fq { ++ * struct qman_fq base; ++ * int an_extra_field; ++ * [ ... add other fields to be associated with each FQ ...] ++ * } *myfq = some_my_fq_allocator(); ++ * struct qman_fq *fq = qman_create_fq(fqid, flags, &myfq->base); ++ * ++ * // in a dequeue callback, access extra fields from 'fq' via a cast; ++ * struct my_fq *myfq = (struct my_fq *)fq; ++ * do_something_with(myfq->an_extra_field); ++ * [...] ++ * ++ * (b) when and if configuring the FQ for context stashing, specify how ever ++ * many cachelines are required to stash 'struct my_fq', to accelerate not ++ * only the Qman driver but the callback as well. ++ */ ++ ++struct qman_fq_cb { ++ qman_cb_dqrr dqrr; /* for dequeued frames */ ++ qman_cb_mr ern; /* for s/w ERNs */ ++ qman_cb_mr fqs; /* frame-queue state changes*/ ++}; ++ ++struct qman_fq { ++ /* Caller of qman_create_fq() provides these demux callbacks */ ++ struct qman_fq_cb cb; ++ /* These are internal to the driver, don't touch. In particular, they ++ * may change, be removed, or extended (so you shouldn't rely on ++ * sizeof(qman_fq) being a constant). */ ++ spinlock_t fqlock; ++ u32 fqid; ++ volatile unsigned long flags; ++ enum qman_fq_state state; ++ int cgr_groupid; ++ struct rb_node node; ++#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP ++ u32 key; ++#endif ++}; ++ ++/* This callback type is used when handling congestion group entry/exit. ++ * 'congested' is non-zero on congestion-entry, and zero on congestion-exit. */ ++typedef void (*qman_cb_cgr)(struct qman_portal *qm, ++ struct qman_cgr *cgr, int congested); ++ ++struct qman_cgr { ++ /* Set these prior to qman_create_cgr() */ ++ u32 cgrid; /* 0..255, but u32 to allow specials like -1, 256, etc.*/ ++ qman_cb_cgr cb; ++ /* These are private to the driver */ ++ u16 chan; /* portal channel this object is created on */ ++ struct list_head node; ++}; ++ ++/* Flags to qman_create_fq() */ ++#define QMAN_FQ_FLAG_NO_ENQUEUE 0x00000001 /* can't enqueue */ ++#define QMAN_FQ_FLAG_NO_MODIFY 0x00000002 /* can only enqueue */ ++#define QMAN_FQ_FLAG_TO_DCPORTAL 0x00000004 /* consumed by CAAM/PME/Fman */ ++#define QMAN_FQ_FLAG_LOCKED 0x00000008 /* multi-core locking */ ++#define QMAN_FQ_FLAG_AS_IS 0x00000010 /* query h/w state */ ++#define QMAN_FQ_FLAG_DYNAMIC_FQID 0x00000020 /* (de)allocate fqid */ ++ ++/* Flags to qman_destroy_fq() */ ++#define QMAN_FQ_DESTROY_PARKED 0x00000001 /* FQ can be parked or OOS */ ++ ++/* Flags from qman_fq_state() */ ++#define QMAN_FQ_STATE_CHANGING 0x80000000 /* 'state' is changing */ ++#define QMAN_FQ_STATE_NE 0x40000000 /* retired FQ isn't empty */ ++#define QMAN_FQ_STATE_ORL 0x20000000 /* retired FQ has ORL */ ++#define QMAN_FQ_STATE_BLOCKOOS 0xe0000000 /* if any are set, no OOS */ ++#define QMAN_FQ_STATE_CGR_EN 0x10000000 /* CGR enabled */ ++#define QMAN_FQ_STATE_VDQCR 0x08000000 /* being volatile dequeued */ ++ ++/* Flags to qman_init_fq() */ ++#define QMAN_INITFQ_FLAG_SCHED 0x00000001 /* schedule rather than park */ ++#define QMAN_INITFQ_FLAG_LOCAL 0x00000004 /* set dest portal */ ++ ++/* Flags to qman_volatile_dequeue() */ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++#define QMAN_VOLATILE_FLAG_WAIT 0x00000001 /* wait if VDQCR is in use */ ++#define QMAN_VOLATILE_FLAG_WAIT_INT 0x00000002 /* if wait, interruptible? */ ++#define QMAN_VOLATILE_FLAG_FINISH 0x00000004 /* wait till VDQCR completes */ ++#endif ++ ++/* Flags to qman_enqueue(). NB, the strange numbering is to align with hardware, ++ * bit-wise. (NB: the PME API is sensitive to these precise numberings too, so ++ * any change here should be audited in PME.) */ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT ++#define QMAN_ENQUEUE_FLAG_WAIT 0x00010000 /* wait if EQCR is full */ ++#define QMAN_ENQUEUE_FLAG_WAIT_INT 0x00020000 /* if wait, interruptible? */ ++#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC ++#define QMAN_ENQUEUE_FLAG_WAIT_SYNC 0x00000004 /* if wait, until consumed? */ ++#endif ++#endif ++#define QMAN_ENQUEUE_FLAG_WATCH_CGR 0x00080000 /* watch congestion state */ ++#define QMAN_ENQUEUE_FLAG_DCA 0x00008000 /* perform enqueue-DCA */ ++#define QMAN_ENQUEUE_FLAG_DCA_PARK 0x00004000 /* If DCA, requests park */ ++#define QMAN_ENQUEUE_FLAG_DCA_PTR(p) /* If DCA, p is DQRR entry */ \ ++ (((u32)(p) << 2) & 0x00000f00) ++#define QMAN_ENQUEUE_FLAG_C_GREEN 0x00000000 /* choose one C_*** flag */ ++#define QMAN_ENQUEUE_FLAG_C_YELLOW 0x00000008 ++#define QMAN_ENQUEUE_FLAG_C_RED 0x00000010 ++#define QMAN_ENQUEUE_FLAG_C_OVERRIDE 0x00000018 ++/* For the ORP-specific qman_enqueue_orp() variant; ++ * - this flag indicates "Not Last In Sequence", ie. all but the final fragment ++ * of a frame. */ ++#define QMAN_ENQUEUE_FLAG_NLIS 0x01000000 ++/* - this flag performs no enqueue but fills in an ORP sequence number that ++ * would otherwise block it (eg. if a frame has been dropped). */ ++#define QMAN_ENQUEUE_FLAG_HOLE 0x02000000 ++/* - this flag performs no enqueue but advances NESN to the given sequence ++ * number. */ ++#define QMAN_ENQUEUE_FLAG_NESN 0x04000000 ++ ++/* Flags to qman_modify_cgr() */ ++#define QMAN_CGR_FLAG_USE_INIT 0x00000001 ++#define QMAN_CGR_MODE_FRAME 0x00000001 ++ ++ /* Portal Management */ ++ /* ----------------- */ ++/** ++ * qman_get_portal_config - get portal configuration settings ++ * ++ * This returns a read-only view of the current cpu's affine portal settings. ++ */ ++const struct qman_portal_config *qman_get_portal_config(void); ++ ++/** ++ * qman_irqsource_get - return the portal work that is interrupt-driven ++ * ++ * Returns a bitmask of QM_PIRQ_**I processing sources that are currently ++ * enabled for interrupt handling on the current cpu's affine portal. These ++ * sources will trigger the portal interrupt and the interrupt handler (or a ++ * tasklet/bottom-half it defers to) will perform the corresponding processing ++ * work. The qman_poll_***() functions will only process sources that are not in ++ * this bitmask. If the current CPU is sharing a portal hosted on another CPU, ++ * this always returns zero. ++ */ ++u32 qman_irqsource_get(void); ++ ++/** ++ * qman_irqsource_add - add processing sources to be interrupt-driven ++ * @bits: bitmask of QM_PIRQ_**I processing sources ++ * ++ * Adds processing sources that should be interrupt-driven (rather than ++ * processed via qman_poll_***() functions). Returns zero for success, or ++ * -EINVAL if the current CPU is sharing a portal hosted on another CPU. ++ */ ++int qman_irqsource_add(u32 bits); ++ ++/** ++ * qman_irqsource_remove - remove processing sources from being interrupt-driven ++ * @bits: bitmask of QM_PIRQ_**I processing sources ++ * ++ * Removes processing sources from being interrupt-driven, so that they will ++ * instead be processed via qman_poll_***() functions. Returns zero for success, ++ * or -EINVAL if the current CPU is sharing a portal hosted on another CPU. ++ */ ++int qman_irqsource_remove(u32 bits); ++ ++/** ++ * qman_affine_cpus - return a mask of cpus that have affine portals ++ */ ++const cpumask_t *qman_affine_cpus(void); ++ ++/** ++ * qman_affine_channel - return the channel ID of an portal ++ * @cpu: the cpu whose affine portal is the subject of the query ++ * ++ * If @cpu is -1, the affine portal for the current CPU will be used. It is a ++ * bug to call this function for any value of @cpu (other than -1) that is not a ++ * member of the mask returned from qman_affine_cpus(). ++ */ ++u16 qman_affine_channel(int cpu); ++ ++/** ++ * qman_get_affine_portal - return the portal pointer affine to cpu ++ * @cpu: the cpu whose affine portal is the subject of the query ++ * ++ */ ++void *qman_get_affine_portal(int cpu); ++ ++/** ++ * qman_poll_dqrr - process DQRR (fast-path) entries ++ * @limit: the maximum number of DQRR entries to process ++ * ++ * Use of this function requires that DQRR processing not be interrupt-driven. ++ * Ie. the value returned by qman_irqsource_get() should not include ++ * QM_PIRQ_DQRI. If the current CPU is sharing a portal hosted on another CPU, ++ * this function will return -EINVAL, otherwise the return value is >=0 and ++ * represents the number of DQRR entries processed. ++ */ ++int qman_poll_dqrr(unsigned int limit); ++ ++/** ++ * qman_poll_slow - process anything (except DQRR) that isn't interrupt-driven. ++ * ++ * This function does any portal processing that isn't interrupt-driven. If the ++ * current CPU is sharing a portal hosted on another CPU, this function will ++ * return (u32)-1, otherwise the return value is a bitmask of QM_PIRQ_* sources ++ * indicating what interrupt sources were actually processed by the call. ++ */ ++u32 qman_poll_slow(void); ++ ++/** ++ * qman_poll - legacy wrapper for qman_poll_dqrr() and qman_poll_slow() ++ * ++ * Dispatcher logic on a cpu can use this to trigger any maintenance of the ++ * affine portal. There are two classes of portal processing in question; ++ * fast-path (which involves demuxing dequeue ring (DQRR) entries and tracking ++ * enqueue ring (EQCR) consumption), and slow-path (which involves EQCR ++ * thresholds, congestion state changes, etc). This function does whatever ++ * processing is not triggered by interrupts. ++ * ++ * Note, if DQRR and some slow-path processing are poll-driven (rather than ++ * interrupt-driven) then this function uses a heuristic to determine how often ++ * to run slow-path processing - as slow-path processing introduces at least a ++ * minimum latency each time it is run, whereas fast-path (DQRR) processing is ++ * close to zero-cost if there is no work to be done. Applications can tune this ++ * behaviour themselves by using qman_poll_dqrr() and qman_poll_slow() directly ++ * rather than going via this wrapper. ++ */ ++void qman_poll(void); ++ ++/** ++ * qman_stop_dequeues - Stop h/w dequeuing to the s/w portal ++ * ++ * Disables DQRR processing of the portal. This is reference-counted, so ++ * qman_start_dequeues() must be called as many times as qman_stop_dequeues() to ++ * truly re-enable dequeuing. ++ */ ++void qman_stop_dequeues(void); ++ ++/** ++ * qman_start_dequeues - (Re)start h/w dequeuing to the s/w portal ++ * ++ * Enables DQRR processing of the portal. This is reference-counted, so ++ * qman_start_dequeues() must be called as many times as qman_stop_dequeues() to ++ * truly re-enable dequeuing. ++ */ ++void qman_start_dequeues(void); ++ ++/** ++ * qman_static_dequeue_add - Add pool channels to the portal SDQCR ++ * @pools: bit-mask of pool channels, using QM_SDQCR_CHANNELS_POOL(n) ++ * ++ * Adds a set of pool channels to the portal's static dequeue command register ++ * (SDQCR). The requested pools are limited to those the portal has dequeue ++ * access to. ++ */ ++void qman_static_dequeue_add(u32 pools); ++ ++/** ++ * qman_static_dequeue_del - Remove pool channels from the portal SDQCR ++ * @pools: bit-mask of pool channels, using QM_SDQCR_CHANNELS_POOL(n) ++ * ++ * Removes a set of pool channels from the portal's static dequeue command ++ * register (SDQCR). The requested pools are limited to those the portal has ++ * dequeue access to. ++ */ ++void qman_static_dequeue_del(u32 pools); ++ ++/** ++ * qman_static_dequeue_get - return the portal's current SDQCR ++ * ++ * Returns the portal's current static dequeue command register (SDQCR). The ++ * entire register is returned, so if only the currently-enabled pool channels ++ * are desired, mask the return value with QM_SDQCR_CHANNELS_POOL_MASK. ++ */ ++u32 qman_static_dequeue_get(void); ++ ++/** ++ * qman_dca - Perform a Discrete Consumption Acknowledgement ++ * @dq: the DQRR entry to be consumed ++ * @park_request: indicates whether the held-active @fq should be parked ++ * ++ * Only allowed in DCA-mode portals, for DQRR entries whose handler callback had ++ * previously returned 'qman_cb_dqrr_defer'. NB, as with the other APIs, this ++ * does not take a 'portal' argument but implies the core affine portal from the ++ * cpu that is currently executing the function. For reasons of locking, this ++ * function must be called from the same CPU as that which processed the DQRR ++ * entry in the first place. ++ */ ++void qman_dca(struct qm_dqrr_entry *dq, int park_request); ++ ++/** ++ * qman_eqcr_is_empty - Determine if portal's EQCR is empty ++ * ++ * For use in situations where a cpu-affine caller needs to determine when all ++ * enqueues for the local portal have been processed by Qman but can't use the ++ * QMAN_ENQUEUE_FLAG_WAIT_SYNC flag to do this from the final qman_enqueue(). ++ * The function forces tracking of EQCR consumption (which normally doesn't ++ * happen until enqueue processing needs to find space to put new enqueue ++ * commands), and returns zero if the ring still has unprocessed entries, ++ * non-zero if it is empty. ++ */ ++int qman_eqcr_is_empty(void); ++ ++/** ++ * qman_set_dc_ern - Set the handler for DCP enqueue rejection notifications ++ * @handler: callback for processing DCP ERNs ++ * @affine: whether this handler is specific to the locally affine portal ++ * ++ * If a hardware block's interface to Qman (ie. its direct-connect portal, or ++ * DCP) is configured not to receive enqueue rejections, then any enqueues ++ * through that DCP that are rejected will be sent to a given software portal. ++ * If @affine is non-zero, then this handler will only be used for DCP ERNs ++ * received on the portal affine to the current CPU. If multiple CPUs share a ++ * portal and they all call this function, they will be setting the handler for ++ * the same portal! If @affine is zero, then this handler will be global to all ++ * portals handled by this instance of the driver. Only those portals that do ++ * not have their own affine handler will use the global handler. ++ */ ++void qman_set_dc_ern(qman_cb_dc_ern handler, int affine); ++ ++ /* FQ management */ ++ /* ------------- */ ++/** ++ * qman_create_fq - Allocates a FQ ++ * @fqid: the index of the FQD to encapsulate, must be "Out of Service" ++ * @flags: bit-mask of QMAN_FQ_FLAG_*** options ++ * @fq: memory for storing the 'fq', with callbacks filled in ++ * ++ * Creates a frame queue object for the given @fqid, unless the ++ * QMAN_FQ_FLAG_DYNAMIC_FQID flag is set in @flags, in which case a FQID is ++ * dynamically allocated (or the function fails if none are available). Once ++ * created, the caller should not touch the memory at 'fq' except as extended to ++ * adjacent memory for user-defined fields (see the definition of "struct ++ * qman_fq" for more info). NO_MODIFY is only intended for enqueuing to ++ * pre-existing frame-queues that aren't to be otherwise interfered with, it ++ * prevents all other modifications to the frame queue. The TO_DCPORTAL flag ++ * causes the driver to honour any contextB modifications requested in the ++ * qm_init_fq() API, as this indicates the frame queue will be consumed by a ++ * direct-connect portal (PME, CAAM, or Fman). When frame queues are consumed by ++ * software portals, the contextB field is controlled by the driver and can't be ++ * modified by the caller. If the AS_IS flag is specified, management commands ++ * will be used on portal @p to query state for frame queue @fqid and construct ++ * a frame queue object based on that, rather than assuming/requiring that it be ++ * Out of Service. ++ */ ++int qman_create_fq(u32 fqid, u32 flags, struct qman_fq *fq); ++ ++/** ++ * qman_destroy_fq - Deallocates a FQ ++ * @fq: the frame queue object to release ++ * @flags: bit-mask of QMAN_FQ_FREE_*** options ++ * ++ * The memory for this frame queue object ('fq' provided in qman_create_fq()) is ++ * not deallocated but the caller regains ownership, to do with as desired. The ++ * FQ must be in the 'out-of-service' state unless the QMAN_FQ_FREE_PARKED flag ++ * is specified, in which case it may also be in the 'parked' state. ++ */ ++void qman_destroy_fq(struct qman_fq *fq, u32 flags); ++ ++/** ++ * qman_fq_fqid - Queries the frame queue ID of a FQ object ++ * @fq: the frame queue object to query ++ */ ++u32 qman_fq_fqid(struct qman_fq *fq); ++ ++/** ++ * qman_fq_state - Queries the state of a FQ object ++ * @fq: the frame queue object to query ++ * @state: pointer to state enum to return the FQ scheduling state ++ * @flags: pointer to state flags to receive QMAN_FQ_STATE_*** bitmask ++ * ++ * Queries the state of the FQ object, without performing any h/w commands. ++ * This captures the state, as seen by the driver, at the time the function ++ * executes. ++ */ ++void qman_fq_state(struct qman_fq *fq, enum qman_fq_state *state, u32 *flags); ++ ++/** ++ * qman_init_fq - Initialises FQ fields, leaves the FQ "parked" or "scheduled" ++ * @fq: the frame queue object to modify, must be 'parked' or new. ++ * @flags: bit-mask of QMAN_INITFQ_FLAG_*** options ++ * @opts: the FQ-modification settings, as defined in the low-level API ++ * ++ * The @opts parameter comes from the low-level portal API. Select ++ * QMAN_INITFQ_FLAG_SCHED in @flags to cause the frame queue to be scheduled ++ * rather than parked. NB, @opts can be NULL. ++ * ++ * Note that some fields and options within @opts may be ignored or overwritten ++ * by the driver; ++ * 1. the 'count' and 'fqid' fields are always ignored (this operation only ++ * affects one frame queue: @fq). ++ * 2. the QM_INITFQ_WE_CONTEXTB option of the 'we_mask' field and the associated ++ * 'fqd' structure's 'context_b' field are sometimes overwritten; ++ * - if @fq was not created with QMAN_FQ_FLAG_TO_DCPORTAL, then context_b is ++ * initialised to a value used by the driver for demux. ++ * - if context_b is initialised for demux, so is context_a in case stashing ++ * is requested (see item 4). ++ * (So caller control of context_b is only possible for TO_DCPORTAL frame queue ++ * objects.) ++ * 3. if @flags contains QMAN_INITFQ_FLAG_LOCAL, the 'fqd' structure's ++ * 'dest::channel' field will be overwritten to match the portal used to issue ++ * the command. If the WE_DESTWQ write-enable bit had already been set by the ++ * caller, the channel workqueue will be left as-is, otherwise the write-enable ++ * bit is set and the workqueue is set to a default of 4. If the "LOCAL" flag ++ * isn't set, the destination channel/workqueue fields and the write-enable bit ++ * are left as-is. ++ * 4. if the driver overwrites context_a/b for demux, then if ++ * QM_INITFQ_WE_CONTEXTA is set, the driver will only overwrite ++ * context_a.address fields and will leave the stashing fields provided by the ++ * user alone, otherwise it will zero out the context_a.stashing fields. ++ */ ++int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts); ++ ++/** ++ * qman_schedule_fq - Schedules a FQ ++ * @fq: the frame queue object to schedule, must be 'parked' ++ * ++ * Schedules the frame queue, which must be Parked, which takes it to ++ * Tentatively-Scheduled or Truly-Scheduled depending on its fill-level. ++ */ ++int qman_schedule_fq(struct qman_fq *fq); ++ ++/** ++ * qman_retire_fq - Retires a FQ ++ * @fq: the frame queue object to retire ++ * @flags: FQ flags (as per qman_fq_state) if retirement completes immediately ++ * ++ * Retires the frame queue. This returns zero if it succeeds immediately, +1 if ++ * the retirement was started asynchronously, otherwise it returns negative for ++ * failure. When this function returns zero, @flags is set to indicate whether ++ * the retired FQ is empty and/or whether it has any ORL fragments (to show up ++ * as ERNs). Otherwise the corresponding flags will be known when a subsequent ++ * FQRN message shows up on the portal's message ring. ++ * ++ * NB, if the retirement is asynchronous (the FQ was in the Truly Scheduled or ++ * Active state), the completion will be via the message ring as a FQRN - but ++ * the corresponding callback may occur before this function returns!! Ie. the ++ * caller should be prepared to accept the callback as the function is called, ++ * not only once it has returned. ++ */ ++int qman_retire_fq(struct qman_fq *fq, u32 *flags); ++ ++/** ++ * qman_oos_fq - Puts a FQ "out of service" ++ * @fq: the frame queue object to be put out-of-service, must be 'retired' ++ * ++ * The frame queue must be retired and empty, and if any order restoration list ++ * was released as ERNs at the time of retirement, they must all be consumed. ++ */ ++int qman_oos_fq(struct qman_fq *fq); ++ ++/** ++ * qman_fq_flow_control - Set the XON/XOFF state of a FQ ++ * @fq: the frame queue object to be set to XON/XOFF state, must not be 'oos', ++ * or 'retired' or 'parked' state ++ * @xon: boolean to set fq in XON or XOFF state ++ * ++ * The frame should be in Tentatively Scheduled state or Truly Schedule sate, ++ * otherwise the IFSI interrupt will be asserted. ++ */ ++int qman_fq_flow_control(struct qman_fq *fq, int xon); ++ ++/** ++ * qman_query_fq - Queries FQD fields (via h/w query command) ++ * @fq: the frame queue object to be queried ++ * @fqd: storage for the queried FQD fields ++ */ ++int qman_query_fq(struct qman_fq *fq, struct qm_fqd *fqd); ++ ++/** ++ * qman_query_fq_np - Queries non-programmable FQD fields ++ * @fq: the frame queue object to be queried ++ * @np: storage for the queried FQD fields ++ */ ++int qman_query_fq_np(struct qman_fq *fq, struct qm_mcr_queryfq_np *np); ++ ++/** ++ * qman_query_wq - Queries work queue lengths ++ * @query_dedicated: If non-zero, query length of WQs in the channel dedicated ++ * to this software portal. Otherwise, query length of WQs in a ++ * channel specified in wq. ++ * @wq: storage for the queried WQs lengths. Also specified the channel to ++ * to query if query_dedicated is zero. ++ */ ++int qman_query_wq(u8 query_dedicated, struct qm_mcr_querywq *wq); ++ ++/** ++ * qman_volatile_dequeue - Issue a volatile dequeue command ++ * @fq: the frame queue object to dequeue from ++ * @flags: a bit-mask of QMAN_VOLATILE_FLAG_*** options ++ * @vdqcr: bit mask of QM_VDQCR_*** options, as per qm_dqrr_vdqcr_set() ++ * ++ * Attempts to lock access to the portal's VDQCR volatile dequeue functionality. ++ * The function will block and sleep if QMAN_VOLATILE_FLAG_WAIT is specified and ++ * the VDQCR is already in use, otherwise returns non-zero for failure. If ++ * QMAN_VOLATILE_FLAG_FINISH is specified, the function will only return once ++ * the VDQCR command has finished executing (ie. once the callback for the last ++ * DQRR entry resulting from the VDQCR command has been called). If not using ++ * the FINISH flag, completion can be determined either by detecting the ++ * presence of the QM_DQRR_STAT_UNSCHEDULED and QM_DQRR_STAT_DQCR_EXPIRED bits ++ * in the "stat" field of the "struct qm_dqrr_entry" passed to the FQ's dequeue ++ * callback, or by waiting for the QMAN_FQ_STATE_VDQCR bit to disappear from the ++ * "flags" retrieved from qman_fq_state(). ++ */ ++int qman_volatile_dequeue(struct qman_fq *fq, u32 flags, u32 vdqcr); ++ ++/** ++ * qman_enqueue - Enqueue a frame to a frame queue ++ * @fq: the frame queue object to enqueue to ++ * @fd: a descriptor of the frame to be enqueued ++ * @flags: bit-mask of QMAN_ENQUEUE_FLAG_*** options ++ * ++ * Fills an entry in the EQCR of portal @qm to enqueue the frame described by ++ * @fd. The descriptor details are copied from @fd to the EQCR entry, the 'pid' ++ * field is ignored. The return value is non-zero on error, such as ring full ++ * (and FLAG_WAIT not specified), congestion avoidance (FLAG_WATCH_CGR ++ * specified), etc. If the ring is full and FLAG_WAIT is specified, this ++ * function will block. If FLAG_INTERRUPT is set, the EQCI bit of the portal ++ * interrupt will assert when Qman consumes the EQCR entry (subject to "status ++ * disable", "enable", and "inhibit" registers). If FLAG_DCA is set, Qman will ++ * perform an implied "discrete consumption acknowledgement" on the dequeue ++ * ring's (DQRR) entry, at the ring index specified by the FLAG_DCA_IDX(x) ++ * macro. (As an alternative to issuing explicit DCA actions on DQRR entries, ++ * this implicit DCA can delay the release of a "held active" frame queue ++ * corresponding to a DQRR entry until Qman consumes the EQCR entry - providing ++ * order-preservation semantics in packet-forwarding scenarios.) If FLAG_DCA is ++ * set, then FLAG_DCA_PARK can also be set to imply that the DQRR consumption ++ * acknowledgement should "park request" the "held active" frame queue. Ie. ++ * when the portal eventually releases that frame queue, it will be left in the ++ * Parked state rather than Tentatively Scheduled or Truly Scheduled. If the ++ * portal is watching congestion groups, the QMAN_ENQUEUE_FLAG_WATCH_CGR flag ++ * is requested, and the FQ is a member of a congestion group, then this ++ * function returns -EAGAIN if the congestion group is currently congested. ++ * Note, this does not eliminate ERNs, as the async interface means we can be ++ * sending enqueue commands to an un-congested FQ that becomes congested before ++ * the enqueue commands are processed, but it does minimise needless thrashing ++ * of an already busy hardware resource by throttling many of the to-be-dropped ++ * enqueues "at the source". ++ */ ++int qman_enqueue(struct qman_fq *fq, const struct qm_fd *fd, u32 flags); ++ ++typedef int (*qman_cb_precommit) (void *arg); ++/** ++ * qman_enqueue_precommit - Enqueue a frame to a frame queue and call cb ++ * @fq: the frame queue object to enqueue to ++ * @fd: a descriptor of the frame to be enqueued ++ * @flags: bit-mask of QMAN_ENQUEUE_FLAG_*** options ++ * @cb: user supplied callback function to invoke before writing commit verb. ++ * @cb_arg: callback function argument ++ * ++ * This is similar to qman_enqueue except that it will invoke a user supplied ++ * callback function just before writng the commit verb. This is useful ++ * when the user want to do something *just before* enqueuing the request and ++ * the enqueue can't fail. ++ */ ++int qman_enqueue_precommit(struct qman_fq *fq, const struct qm_fd *fd, ++ u32 flags, qman_cb_precommit cb, void *cb_arg); ++ ++/** ++ * qman_enqueue_orp - Enqueue a frame to a frame queue using an ORP ++ * @fq: the frame queue object to enqueue to ++ * @fd: a descriptor of the frame to be enqueued ++ * @flags: bit-mask of QMAN_ENQUEUE_FLAG_*** options ++ * @orp: the frame queue object used as an order restoration point. ++ * @orp_seqnum: the sequence number of this frame in the order restoration path ++ * ++ * Similar to qman_enqueue(), but with the addition of an Order Restoration ++ * Point (@orp) and corresponding sequence number (@orp_seqnum) for this ++ * enqueue operation to employ order restoration. Each frame queue object acts ++ * as an Order Definition Point (ODP) by providing each frame dequeued from it ++ * with an incrementing sequence number, this value is generally ignored unless ++ * that sequence of dequeued frames will need order restoration later. Each ++ * frame queue object also encapsulates an Order Restoration Point (ORP), which ++ * is a re-assembly context for re-ordering frames relative to their sequence ++ * numbers as they are enqueued. The ORP does not have to be within the frame ++ * queue that receives the enqueued frame, in fact it is usually the frame ++ * queue from which the frames were originally dequeued. For the purposes of ++ * order restoration, multiple frames (or "fragments") can be enqueued for a ++ * single sequence number by setting the QMAN_ENQUEUE_FLAG_NLIS flag for all ++ * enqueues except the final fragment of a given sequence number. Ordering ++ * between sequence numbers is guaranteed, even if fragments of different ++ * sequence numbers are interlaced with one another. Fragments of the same ++ * sequence number will retain the order in which they are enqueued. If no ++ * enqueue is to performed, QMAN_ENQUEUE_FLAG_HOLE indicates that the given ++ * sequence number is to be "skipped" by the ORP logic (eg. if a frame has been ++ * dropped from a sequence), or QMAN_ENQUEUE_FLAG_NESN indicates that the given ++ * sequence number should become the ORP's "Next Expected Sequence Number". ++ * ++ * Side note: a frame queue object can be used purely as an ORP, without ++ * carrying any frames at all. Care should be taken not to deallocate a frame ++ * queue object that is being actively used as an ORP, as a future allocation ++ * of the frame queue object may start using the internal ORP before the ++ * previous use has finished. ++ */ ++int qman_enqueue_orp(struct qman_fq *fq, const struct qm_fd *fd, u32 flags, ++ struct qman_fq *orp, u16 orp_seqnum); ++ ++/** ++ * qman_alloc_fqid_range - Allocate a contiguous range of FQIDs ++ * @result: is set by the API to the base FQID of the allocated range ++ * @count: the number of FQIDs required ++ * @align: required alignment of the allocated range ++ * @partial: non-zero if the API can return fewer than @count FQIDs ++ * ++ * Returns the number of frame queues allocated, or a negative error code. If ++ * @partial is non zero, the allocation request may return a smaller range of ++ * FQs than requested (though alignment will be as requested). If @partial is ++ * zero, the return value will either be 'count' or negative. ++ */ ++int qman_alloc_fqid_range(u32 *result, u32 count, u32 align, int partial); ++static inline int qman_alloc_fqid(u32 *result) ++{ ++ int ret = qman_alloc_fqid_range(result, 1, 0, 0); ++ return (ret > 0) ? 0 : ret; ++} ++ ++/** ++ * qman_release_fqid_range - Release the specified range of frame queue IDs ++ * @fqid: the base FQID of the range to deallocate ++ * @count: the number of FQIDs in the range ++ * ++ * This function can also be used to seed the allocator with ranges of FQIDs ++ * that it can subsequently allocate from. ++ */ ++void qman_release_fqid_range(u32 fqid, unsigned int count); ++static inline void qman_release_fqid(u32 fqid) ++{ ++ qman_release_fqid_range(fqid, 1); ++} ++ ++void qman_seed_fqid_range(u32 fqid, unsigned int count); ++ ++ ++int qman_shutdown_fq(u32 fqid); ++ ++/** ++ * qman_reserve_fqid_range - Reserve the specified range of frame queue IDs ++ * @fqid: the base FQID of the range to deallocate ++ * @count: the number of FQIDs in the range ++ */ ++int qman_reserve_fqid_range(u32 fqid, unsigned int count); ++static inline int qman_reserve_fqid(u32 fqid) ++{ ++ return qman_reserve_fqid_range(fqid, 1); ++} ++ ++ /* Pool-channel management */ ++ /* ----------------------- */ ++/** ++ * qman_alloc_pool_range - Allocate a contiguous range of pool-channel IDs ++ * @result: is set by the API to the base pool-channel ID of the allocated range ++ * @count: the number of pool-channel IDs required ++ * @align: required alignment of the allocated range ++ * @partial: non-zero if the API can return fewer than @count ++ * ++ * Returns the number of pool-channel IDs allocated, or a negative error code. ++ * If @partial is non zero, the allocation request may return a smaller range of ++ * than requested (though alignment will be as requested). If @partial is zero, ++ * the return value will either be 'count' or negative. ++ */ ++int qman_alloc_pool_range(u32 *result, u32 count, u32 align, int partial); ++static inline int qman_alloc_pool(u32 *result) ++{ ++ int ret = qman_alloc_pool_range(result, 1, 0, 0); ++ return (ret > 0) ? 0 : ret; ++} ++ ++/** ++ * qman_release_pool_range - Release the specified range of pool-channel IDs ++ * @id: the base pool-channel ID of the range to deallocate ++ * @count: the number of pool-channel IDs in the range ++ */ ++void qman_release_pool_range(u32 id, unsigned int count); ++static inline void qman_release_pool(u32 id) ++{ ++ qman_release_pool_range(id, 1); ++} ++ ++/** ++ * qman_reserve_pool_range - Reserve the specified range of pool-channel IDs ++ * @id: the base pool-channel ID of the range to reserve ++ * @count: the number of pool-channel IDs in the range ++ */ ++int qman_reserve_pool_range(u32 id, unsigned int count); ++static inline int qman_reserve_pool(u32 id) ++{ ++ return qman_reserve_pool_range(id, 1); ++} ++ ++void qman_seed_pool_range(u32 id, unsigned int count); ++ ++ /* CGR management */ ++ /* -------------- */ ++/** ++ * qman_create_cgr - Register a congestion group object ++ * @cgr: the 'cgr' object, with fields filled in ++ * @flags: QMAN_CGR_FLAG_* values ++ * @opts: optional state of CGR settings ++ * ++ * Registers this object to receiving congestion entry/exit callbacks on the ++ * portal affine to the cpu portal on which this API is executed. If opts is ++ * NULL then only the callback (cgr->cb) function is registered. If @flags ++ * contains QMAN_CGR_FLAG_USE_INIT, then an init hw command (which will reset ++ * any unspecified parameters) will be used rather than a modify hw hardware ++ * (which only modifies the specified parameters). ++ */ ++int qman_create_cgr(struct qman_cgr *cgr, u32 flags, ++ struct qm_mcc_initcgr *opts); ++ ++/** ++ * qman_create_cgr_to_dcp - Register a congestion group object to DCP portal ++ * @cgr: the 'cgr' object, with fields filled in ++ * @flags: QMAN_CGR_FLAG_* values ++ * @dcp_portal: the DCP portal to which the cgr object is registered. ++ * @opts: optional state of CGR settings ++ * ++ */ ++int qman_create_cgr_to_dcp(struct qman_cgr *cgr, u32 flags, u16 dcp_portal, ++ struct qm_mcc_initcgr *opts); ++ ++/** ++ * qman_delete_cgr - Deregisters a congestion group object ++ * @cgr: the 'cgr' object to deregister ++ * ++ * "Unplugs" this CGR object from the portal affine to the cpu on which this API ++ * is executed. This must be excuted on the same affine portal on which it was ++ * created. ++ */ ++int qman_delete_cgr(struct qman_cgr *cgr); ++ ++/** ++ * qman_delete_cgr_safe - Deregisters a congestion group object from any CPU ++ * @cgr: the 'cgr' object to deregister ++ * ++ * This will select the proper CPU and run there qman_delete_cgr(). ++ */ ++void qman_delete_cgr_safe(struct qman_cgr *cgr); ++ ++/** ++ * qman_modify_cgr - Modify CGR fields ++ * @cgr: the 'cgr' object to modify ++ * @flags: QMAN_CGR_FLAG_* values ++ * @opts: the CGR-modification settings ++ * ++ * The @opts parameter comes from the low-level portal API, and can be NULL. ++ * Note that some fields and options within @opts may be ignored or overwritten ++ * by the driver, in particular the 'cgrid' field is ignored (this operation ++ * only affects the given CGR object). If @flags contains ++ * QMAN_CGR_FLAG_USE_INIT, then an init hw command (which will reset any ++ * unspecified parameters) will be used rather than a modify hw hardware (which ++ * only modifies the specified parameters). ++ */ ++int qman_modify_cgr(struct qman_cgr *cgr, u32 flags, ++ struct qm_mcc_initcgr *opts); ++ ++/** ++* qman_query_cgr - Queries CGR fields ++* @cgr: the 'cgr' object to query ++* @result: storage for the queried congestion group record ++*/ ++int qman_query_cgr(struct qman_cgr *cgr, struct qm_mcr_querycgr *result); ++ ++/** ++ * qman_query_congestion - Queries the state of all congestion groups ++ * @congestion: storage for the queried state of all congestion groups ++ */ ++int qman_query_congestion(struct qm_mcr_querycongestion *congestion); ++ ++/** ++ * qman_alloc_cgrid_range - Allocate a contiguous range of CGR IDs ++ * @result: is set by the API to the base CGR ID of the allocated range ++ * @count: the number of CGR IDs required ++ * @align: required alignment of the allocated range ++ * @partial: non-zero if the API can return fewer than @count ++ * ++ * Returns the number of CGR IDs allocated, or a negative error code. ++ * If @partial is non zero, the allocation request may return a smaller range of ++ * than requested (though alignment will be as requested). If @partial is zero, ++ * the return value will either be 'count' or negative. ++ */ ++int qman_alloc_cgrid_range(u32 *result, u32 count, u32 align, int partial); ++static inline int qman_alloc_cgrid(u32 *result) ++{ ++ int ret = qman_alloc_cgrid_range(result, 1, 0, 0); ++ return (ret > 0) ? 0 : ret; ++} ++ ++/** ++ * qman_release_cgrid_range - Release the specified range of CGR IDs ++ * @id: the base CGR ID of the range to deallocate ++ * @count: the number of CGR IDs in the range ++ */ ++void qman_release_cgrid_range(u32 id, unsigned int count); ++static inline void qman_release_cgrid(u32 id) ++{ ++ qman_release_cgrid_range(id, 1); ++} ++ ++/** ++ * qman_reserve_cgrid_range - Reserve the specified range of CGR ID ++ * @id: the base CGR ID of the range to reserve ++ * @count: the number of CGR IDs in the range ++ */ ++int qman_reserve_cgrid_range(u32 id, unsigned int count); ++static inline int qman_reserve_cgrid(u32 id) ++{ ++ return qman_reserve_cgrid_range(id, 1); ++} ++ ++void qman_seed_cgrid_range(u32 id, unsigned int count); ++ ++ ++ /* Helpers */ ++ /* ------- */ ++/** ++ * qman_poll_fq_for_init - Check if an FQ has been initialised from OOS ++ * @fqid: the FQID that will be initialised by other s/w ++ * ++ * In many situations, a FQID is provided for communication between s/w ++ * entities, and whilst the consumer is responsible for initialising and ++ * scheduling the FQ, the producer(s) generally create a wrapper FQ object using ++ * and only call qman_enqueue() (no FQ initialisation, scheduling, etc). Ie; ++ * qman_create_fq(..., QMAN_FQ_FLAG_NO_MODIFY, ...); ++ * However, data can not be enqueued to the FQ until it is initialised out of ++ * the OOS state - this function polls for that condition. It is particularly ++ * useful for users of IPC functions - each endpoint's Rx FQ is the other ++ * endpoint's Tx FQ, so each side can initialise and schedule their Rx FQ object ++ * and then use this API on the (NO_MODIFY) Tx FQ object in order to ++ * synchronise. The function returns zero for success, +1 if the FQ is still in ++ * the OOS state, or negative if there was an error. ++ */ ++static inline int qman_poll_fq_for_init(struct qman_fq *fq) ++{ ++ struct qm_mcr_queryfq_np np; ++ int err; ++ err = qman_query_fq_np(fq, &np); ++ if (err) ++ return err; ++ if ((np.state & QM_MCR_NP_STATE_MASK) == QM_MCR_NP_STATE_OOS) ++ return 1; ++ return 0; ++} ++ ++ /* -------------- */ ++ /* CEETM :: types */ ++ /* -------------- */ ++/** ++ * Token Rate Structure ++ * Shaping rates are based on a "credit" system and a pre-configured h/w ++ * internal timer. The following type represents a shaper "rate" parameter as a ++ * fractional number of "tokens". Here's how it works. This (fractional) number ++ * of tokens is added to the shaper's "credit" every time the h/w timer elapses ++ * (up to a limit which is set by another shaper parameter). Every time a frame ++ * is enqueued through a shaper, the shaper deducts as many tokens as there are ++ * bytes of data in the enqueued frame. A shaper will not allow itself to ++ * enqueue any frames if its token count is negative. As such; ++ * ++ * The rate at which data is enqueued is limited by the ++ * rate at which tokens are added. ++ * ++ * Therefore if the user knows the period between these h/w timer updates in ++ * seconds, they can calculate the maximum traffic rate of the shaper (in ++ * bytes-per-second) from the token rate. And vice versa, they can calculate ++ * the token rate to use in order to achieve a given traffic rate. ++ */ ++struct qm_ceetm_rate { ++ /* The token rate is; whole + (fraction/8192) */ ++ u32 whole:11; /* 0..2047 */ ++ u32 fraction:13; /* 0..8191 */ ++}; ++ ++struct qm_ceetm_weight_code { ++ /* The weight code is; 5 msbits + 3 lsbits */ ++ u8 y:5; ++ u8 x:3; ++}; ++ ++struct qm_ceetm { ++ unsigned int idx; ++ struct list_head sub_portals; ++ struct list_head lnis; ++ unsigned int sp_range[2]; ++ unsigned int lni_range[2]; ++}; ++ ++struct qm_ceetm_sp { ++ struct list_head node; ++ unsigned int idx; ++ unsigned int dcp_idx; ++ int is_claimed; ++ struct qm_ceetm_lni *lni; ++}; ++ ++/* Logical Network Interface */ ++struct qm_ceetm_lni { ++ struct list_head node; ++ unsigned int idx; ++ unsigned int dcp_idx; ++ int is_claimed; ++ struct qm_ceetm_sp *sp; ++ struct list_head channels; ++ int shaper_enable; ++ int shaper_couple; ++ int oal; ++ struct qm_ceetm_rate cr_token_rate; ++ struct qm_ceetm_rate er_token_rate; ++ u16 cr_token_bucket_limit; ++ u16 er_token_bucket_limit; ++}; ++ ++/* Class Queue Channel */ ++struct qm_ceetm_channel { ++ struct list_head node; ++ unsigned int idx; ++ unsigned int lni_idx; ++ unsigned int dcp_idx; ++ struct list_head class_queues; ++ struct list_head ccgs; ++ u8 shaper_enable; ++ u8 shaper_couple; ++ struct qm_ceetm_rate cr_token_rate; ++ struct qm_ceetm_rate er_token_rate; ++ u16 cr_token_bucket_limit; ++ u16 er_token_bucket_limit; ++}; ++ ++struct qm_ceetm_ccg; ++ ++/* This callback type is used when handling congestion entry/exit. The ++ * 'cb_ctx' value is the opaque value associated with ccg object. ++ * 'congested' is non-zero on congestion-entry, and zero on congestion-exit. ++ */ ++typedef void (*qman_cb_ccgr)(struct qm_ceetm_ccg *ccg, void *cb_ctx, ++ int congested); ++ ++/* Class Congestion Group */ ++struct qm_ceetm_ccg { ++ struct qm_ceetm_channel *parent; ++ struct list_head node; ++ struct list_head cb_node; ++ qman_cb_ccgr cb; ++ void *cb_ctx; ++ unsigned int idx; ++}; ++ ++/* Class Queue */ ++struct qm_ceetm_cq { ++ struct qm_ceetm_channel *parent; ++ struct qm_ceetm_ccg *ccg; ++ struct list_head node; ++ unsigned int idx; ++ int is_claimed; ++ struct list_head bound_lfqids; ++ struct list_head binding_node; ++}; ++ ++/* Logical Frame Queue */ ++struct qm_ceetm_lfq { ++ struct qm_ceetm_channel *parent; ++ struct list_head node; ++ unsigned int idx; ++ unsigned int dctidx; ++ u64 context_a; ++ u32 context_b; ++ qman_cb_mr ern; ++}; ++ ++/** ++ * qman_ceetm_bps2tokenrate - Given a desired rate 'bps' measured in bps ++ * (ie. bits-per-second), compute the 'token_rate' fraction that best ++ * approximates that rate. ++ * @bps: the desired shaper rate in bps. ++ * @token_rate: the output token rate computed with the given kbps. ++ * @rounding: dictates how to round if an exact conversion is not possible; if ++ * it is negative then 'token_rate' will round down to the highest value that ++ * does not exceed the desired rate, if it is positive then 'token_rate' will ++ * round up to the lowest value that is greater than or equal to the desired ++ * rate, and if it is zero then it will round to the nearest approximation, ++ * whether that be up or down. ++ * ++ * Return 0 for success, or -EINVAL if prescaler or qman clock is not available. ++ */ ++int qman_ceetm_bps2tokenrate(u64 bps, ++ struct qm_ceetm_rate *token_rate, ++ int rounding); ++ ++/** ++ * qman_ceetm_tokenrate2bps - Given a 'token_rate', compute the ++ * corresponding number of 'bps'. ++ * @token_rate: the input desired token_rate fraction. ++ * @bps: the output shaper rate in bps computed with the give token rate. ++ * @rounding: has the same semantics as the previous function. ++ * ++ * Return 0 for success, or -EINVAL if prescaler or qman clock is not available. ++ */ ++int qman_ceetm_tokenrate2bps(const struct qm_ceetm_rate *token_rate, ++ u64 *bps, ++ int rounding); ++ ++int qman_alloc_ceetm0_channel_range(u32 *result, u32 count, u32 align, ++ int partial); ++static inline int qman_alloc_ceetm0_channel(u32 *result) ++{ ++ int ret = qman_alloc_ceetm0_channel_range(result, 1, 0, 0); ++ return (ret > 0) ? 0 : ret; ++} ++void qman_release_ceetm0_channel_range(u32 channelid, u32 count); ++static inline void qman_release_ceetm0_channelid(u32 channelid) ++{ ++ qman_release_ceetm0_channel_range(channelid, 1); ++} ++ ++int qman_reserve_ceetm0_channel_range(u32 channelid, u32 count); ++static inline int qman_reserve_ceetm0_channelid(u32 channelid) ++{ ++ return qman_reserve_ceetm0_channel_range(channelid, 1); ++} ++ ++void qman_seed_ceetm0_channel_range(u32 channelid, u32 count); ++ ++ ++int qman_alloc_ceetm1_channel_range(u32 *result, u32 count, u32 align, ++ int partial); ++static inline int qman_alloc_ceetm1_channel(u32 *result) ++{ ++ int ret = qman_alloc_ceetm1_channel_range(result, 1, 0, 0); ++ return (ret > 0) ? 0 : ret; ++} ++void qman_release_ceetm1_channel_range(u32 channelid, u32 count); ++static inline void qman_release_ceetm1_channelid(u32 channelid) ++{ ++ qman_release_ceetm1_channel_range(channelid, 1); ++} ++int qman_reserve_ceetm1_channel_range(u32 channelid, u32 count); ++static inline int qman_reserve_ceetm1_channelid(u32 channelid) ++{ ++ return qman_reserve_ceetm1_channel_range(channelid, 1); ++} ++ ++void qman_seed_ceetm1_channel_range(u32 channelid, u32 count); ++ ++ ++int qman_alloc_ceetm0_lfqid_range(u32 *result, u32 count, u32 align, ++ int partial); ++static inline int qman_alloc_ceetm0_lfqid(u32 *result) ++{ ++ int ret = qman_alloc_ceetm0_lfqid_range(result, 1, 0, 0); ++ return (ret > 0) ? 0 : ret; ++} ++void qman_release_ceetm0_lfqid_range(u32 lfqid, u32 count); ++static inline void qman_release_ceetm0_lfqid(u32 lfqid) ++{ ++ qman_release_ceetm0_lfqid_range(lfqid, 1); ++} ++int qman_reserve_ceetm0_lfqid_range(u32 lfqid, u32 count); ++static inline int qman_reserve_ceetm0_lfqid(u32 lfqid) ++{ ++ return qman_reserve_ceetm0_lfqid_range(lfqid, 1); ++} ++ ++void qman_seed_ceetm0_lfqid_range(u32 lfqid, u32 count); ++ ++ ++int qman_alloc_ceetm1_lfqid_range(u32 *result, u32 count, u32 align, ++ int partial); ++static inline int qman_alloc_ceetm1_lfqid(u32 *result) ++{ ++ int ret = qman_alloc_ceetm1_lfqid_range(result, 1, 0, 0); ++ return (ret > 0) ? 0 : ret; ++} ++void qman_release_ceetm1_lfqid_range(u32 lfqid, u32 count); ++static inline void qman_release_ceetm1_lfqid(u32 lfqid) ++{ ++ qman_release_ceetm1_lfqid_range(lfqid, 1); ++} ++int qman_reserve_ceetm1_lfqid_range(u32 lfqid, u32 count); ++static inline int qman_reserve_ceetm1_lfqid(u32 lfqid) ++{ ++ return qman_reserve_ceetm1_lfqid_range(lfqid, 1); ++} ++ ++void qman_seed_ceetm1_lfqid_range(u32 lfqid, u32 count); ++ ++ ++ /* ----------------------------- */ ++ /* CEETM :: sub-portals */ ++ /* ----------------------------- */ ++ ++/** ++ * qman_ceetm_sp_claim - Claims the given sub-portal, provided it is available ++ * to us and configured for traffic-management. ++ * @sp: the returned sub-portal object, if successful. ++ * @dcp_id: specifies the desired Fman block (and thus the relevant CEETM ++ * instance), ++ * @sp_idx" is the desired sub-portal index from 0 to 15. ++ * ++ * Returns zero for success, or -ENODEV if the sub-portal is in use, or -EINVAL ++ * if the sp_idx is out of range. ++ * ++ * Note that if there are multiple driver domains (eg. a linux kernel versus ++ * user-space drivers in USDPAA, or multiple guests running under a hypervisor) ++ * then a sub-portal may be accessible by more than one instance of a qman ++ * driver and so it may be claimed multiple times. If this is the case, it is ++ * up to the system architect to prevent conflicting configuration actions ++ * coming from the different driver domains. The qman drivers do not have any ++ * behind-the-scenes coordination to prevent this from happening. ++ */ ++int qman_ceetm_sp_claim(struct qm_ceetm_sp **sp, ++ enum qm_dc_portal dcp_idx, ++ unsigned int sp_idx); ++ ++/** ++ * qman_ceetm_sp_release - Releases a previously claimed sub-portal. ++ * @sp: the sub-portal to be released. ++ * ++ * Returns 0 for success, or -EBUSY for failure if the dependencies are not ++ * released. ++ */ ++int qman_ceetm_sp_release(struct qm_ceetm_sp *sp); ++ ++ /* ----------------------------------- */ ++ /* CEETM :: logical network interfaces */ ++ /* ----------------------------------- */ ++ ++/** ++ * qman_ceetm_lni_claim - Claims an unclaimed LNI. ++ * @lni: the returned LNI object, if successful. ++ * @dcp_id: specifies the desired Fman block (and thus the relevant CEETM ++ * instance) ++ * @lni_idx: is the desired LNI index. ++ * ++ * Returns zero for success, or -EINVAL on failure, which will happen if the LNI ++ * is not available or has already been claimed (and not yet successfully ++ * released), or lni_dix is out of range. ++ * ++ * Note that there may be multiple driver domains (or instances) that need to ++ * transmit out the same LNI, so this claim is only guaranteeing exclusivity ++ * within the domain of the driver being called. See qman_ceetm_sp_claim() and ++ * qman_ceetm_sp_get_lni() for more information. ++ */ ++int qman_ceetm_lni_claim(struct qm_ceetm_lni **lni, ++ enum qm_dc_portal dcp_id, ++ unsigned int lni_idx); ++ ++/** ++ * qman_ceetm_lni_releaes - Releases a previously claimed LNI. ++ * @lni: the lni needs to be released. ++ * ++ * This will only succeed if all dependent objects have been released. ++ * Returns zero for success, or -EBUSY if the dependencies are not released. ++ */ ++int qman_ceetm_lni_release(struct qm_ceetm_lni *lni); ++ ++/** ++ * qman_ceetm_sp_set_lni ++ * qman_ceetm_sp_get_lni - Set/get the LNI that the sub-portal is currently ++ * mapped to. ++ * @sp: the given sub-portal. ++ * @lni(in "set"function): the LNI object which the sp will be mappaed to. ++ * @lni_idx(in "get" function): the LNI index which the sp is mapped to. ++ * ++ * Returns zero for success, or -EINVAL for the "set" function when this sp-lni ++ * mapping has been set, or configure mapping command returns error, and ++ * -EINVAL for "get" function when this sp-lni mapping is not set or the query ++ * mapping command returns error. ++ * ++ * This may be useful in situations where multiple driver domains have access ++ * to the same sub-portals in order to all be able to transmit out the same ++ * physical interface (perhaps they're on different IP addresses or VPNs, so ++ * Fman is splitting Rx traffic and here we need to converge Tx traffic). In ++ * that case, a control-plane is likely to use qman_ceetm_lni_claim() followed ++ * by qman_ceetm_sp_set_lni() to configure the sub-portal, and other domains ++ * are likely to use qman_ceetm_sp_get_lni() followed by qman_ceetm_lni_claim() ++ * in order to determine the LNI that the control-plane had assigned. This is ++ * why the "get" returns an index, whereas the "set" takes an (already claimed) ++ * LNI object. ++ */ ++int qman_ceetm_sp_set_lni(struct qm_ceetm_sp *sp, ++ struct qm_ceetm_lni *lni); ++int qman_ceetm_sp_get_lni(struct qm_ceetm_sp *sp, ++ unsigned int *lni_idx); ++ ++/** ++ * qman_ceetm_lni_enable_shaper ++ * qman_ceetm_lni_disable_shaper - Enables/disables shaping on the LNI. ++ * @lni: the given LNI. ++ * @coupled: indicates whether CR and ER are coupled. ++ * @oal: the overhead accounting length which is added to the actual length of ++ * each frame when performing shaper calculations. ++ * ++ * When the number of (unused) committed-rate tokens reach the committed-rate ++ * token limit, 'coupled' indicates whether surplus tokens should be added to ++ * the excess-rate token count (up to the excess-rate token limit). ++ * When LNI is claimed, the shaper is disabled by default. The enable function ++ * will turn on this shaper for this lni. ++ * Whenever a claimed LNI is first enabled for shaping, its committed and ++ * excess token rates and limits are zero, so will need to be changed to do ++ * anything useful. The shaper can subsequently be enabled/disabled without ++ * resetting the shaping parameters, but the shaping parameters will be reset ++ * when the LNI is released. ++ * ++ * Returns zero for success, or errno for "enable" function in the cases as: ++ * a) -EINVAL if the shaper is already enabled, ++ * b) -EIO if the configure shaper command returns error. ++ * For "disable" function, returns: ++ * a) -EINVAL if the shaper is has already disabled. ++ * b) -EIO if calling configure shaper command returns error. ++ */ ++int qman_ceetm_lni_enable_shaper(struct qm_ceetm_lni *lni, int coupled, ++ int oal); ++int qman_ceetm_lni_disable_shaper(struct qm_ceetm_lni *lni); ++ ++/** ++ * qman_ceetm_lni_is_shaper_enabled - Check LNI shaper status ++ * @lni: the give LNI ++ */ ++int qman_ceetm_lni_is_shaper_enabled(struct qm_ceetm_lni *lni); ++ ++/** ++ * qman_ceetm_lni_set_commit_rate ++ * qman_ceetm_lni_get_commit_rate ++ * qman_ceetm_lni_set_excess_rate ++ * qman_ceetm_lni_get_excess_rate - Set/get the shaper CR/ER token rate and ++ * token limit for the given LNI. ++ * @lni: the given LNI. ++ * @token_rate: the desired token rate for "set" fuction, or the token rate of ++ * the LNI queried by "get" function. ++ * @token_limit: the desired token bucket limit for "set" function, or the token ++ * limit of the given LNI queried by "get" function. ++ * ++ * Returns zero for success. The "set" function returns -EINVAL if the given ++ * LNI is unshapped or -EIO if the configure shaper command returns error. ++ * The "get" function returns -EINVAL if the token rate or the token limit is ++ * not set or the query command returns error. ++ */ ++int qman_ceetm_lni_set_commit_rate(struct qm_ceetm_lni *lni, ++ const struct qm_ceetm_rate *token_rate, ++ u16 token_limit); ++int qman_ceetm_lni_get_commit_rate(struct qm_ceetm_lni *lni, ++ struct qm_ceetm_rate *token_rate, ++ u16 *token_limit); ++int qman_ceetm_lni_set_excess_rate(struct qm_ceetm_lni *lni, ++ const struct qm_ceetm_rate *token_rate, ++ u16 token_limit); ++int qman_ceetm_lni_get_excess_rate(struct qm_ceetm_lni *lni, ++ struct qm_ceetm_rate *token_rate, ++ u16 *token_limit); ++/** ++ * qman_ceetm_lni_set_commit_rate_bps ++ * qman_ceetm_lni_get_commit_rate_bps ++ * qman_ceetm_lni_set_excess_rate_bps ++ * qman_ceetm_lni_get_excess_rate_bps - Set/get the shaper CR/ER rate ++ * and token limit for the given LNI. ++ * @lni: the given LNI. ++ * @bps: the desired shaping rate in bps for "set" fuction, or the shaping rate ++ * of the LNI queried by "get" function. ++ * @token_limit: the desired token bucket limit for "set" function, or the token ++ * limit of the given LNI queried by "get" function. ++ * ++ * Returns zero for success. The "set" function returns -EINVAL if the given ++ * LNI is unshapped or -EIO if the configure shaper command returns error. ++ * The "get" function returns -EINVAL if the token rate or the token limit is ++ * not set or the query command returns error. ++ */ ++int qman_ceetm_lni_set_commit_rate_bps(struct qm_ceetm_lni *lni, ++ u64 bps, ++ u16 token_limit); ++int qman_ceetm_lni_get_commit_rate_bps(struct qm_ceetm_lni *lni, ++ u64 *bps, u16 *token_limit); ++int qman_ceetm_lni_set_excess_rate_bps(struct qm_ceetm_lni *lni, ++ u64 bps, ++ u16 token_limit); ++int qman_ceetm_lni_get_excess_rate_bps(struct qm_ceetm_lni *lni, ++ u64 *bps, u16 *token_limit); ++ ++/** ++ * qman_ceetm_lni_set_tcfcc ++ * qman_ceetm_lni_get_tcfcc - Configure/query "Traffic Class Flow Control". ++ * @lni: the given LNI. ++ * @cq_level: is between 0 and 15, representing individual class queue levels ++ * (CQ0 to CQ7 for every channel) and grouped class queue levels (CQ8 to CQ15 ++ * for every channel). ++ * @traffic_class: is between 0 and 7 when associating a given class queue level ++ * to a traffic class, or -1 when disabling traffic class flow control for this ++ * class queue level. ++ * ++ * Return zero for success, or -EINVAL if the cq_level or traffic_class is out ++ * of range as indicated above, or -EIO if the configure/query tcfcc command ++ * returns error. ++ * ++ * Refer to the section of QMan CEETM traffic class flow control in the ++ * Reference Manual. ++ */ ++int qman_ceetm_lni_set_tcfcc(struct qm_ceetm_lni *lni, ++ unsigned int cq_level, ++ int traffic_class); ++int qman_ceetm_lni_get_tcfcc(struct qm_ceetm_lni *lni, ++ unsigned int cq_level, ++ int *traffic_class); ++ ++ /* ----------------------------- */ ++ /* CEETM :: class queue channels */ ++ /* ----------------------------- */ ++ ++/** ++ * qman_ceetm_channel_claim - Claims an unclaimed CQ channel that is mapped to ++ * the given LNI. ++ * @channel: the returned class queue channel object, if successful. ++ * @lni: the LNI that the channel belongs to. ++ * ++ * Channels are always initially "unshaped". ++ * ++ * Return zero for success, or -ENODEV if there is no channel available(all 32 ++ * channels are claimed) or -EINVAL if the channel mapping command returns ++ * error. ++ */ ++int qman_ceetm_channel_claim(struct qm_ceetm_channel **channel, ++ struct qm_ceetm_lni *lni); ++ ++/** ++ * qman_ceetm_channel_release - Releases a previously claimed CQ channel. ++ * @channel: the channel needs to be released. ++ * ++ * Returns zero for success, or -EBUSY if the dependencies are still in use. ++ * ++ * Note any shaping of the channel will be cleared to leave it in an unshaped ++ * state. ++ */ ++int qman_ceetm_channel_release(struct qm_ceetm_channel *channel); ++ ++/** ++ * qman_ceetm_channel_enable_shaper ++ * qman_ceetm_channel_disable_shaper - Enables/disables shaping on the channel. ++ * @channel: the given channel. ++ * @coupled: indicates whether surplus CR tokens should be added to the ++ * excess-rate token count (up to the excess-rate token limit) when the number ++ * of (unused) committed-rate tokens reach the committed_rate token limit. ++ * ++ * Whenever a claimed channel is first enabled for shaping, its committed and ++ * excess token rates and limits are zero, so will need to be changed to do ++ * anything useful. The shaper can subsequently be enabled/disabled without ++ * resetting the shaping parameters, but the shaping parameters will be reset ++ * when the channel is released. ++ * ++ * Return 0 for success, or -EINVAL for failure, in the case that the channel ++ * shaper has been enabled/disabled or the management command returns error. ++ */ ++int qman_ceetm_channel_enable_shaper(struct qm_ceetm_channel *channel, ++ int coupled); ++int qman_ceetm_channel_disable_shaper(struct qm_ceetm_channel *channel); ++ ++/** ++ * qman_ceetm_channel_is_shaper_enabled - Check channel shaper status. ++ * @channel: the give channel. ++ */ ++int qman_ceetm_channel_is_shaper_enabled(struct qm_ceetm_channel *channel); ++ ++/** ++ * qman_ceetm_channel_set_commit_rate ++ * qman_ceetm_channel_get_commit_rate ++ * qman_ceetm_channel_set_excess_rate ++ * qman_ceetm_channel_get_excess_rate - Set/get channel CR/ER shaper parameters. ++ * @channel: the given channel. ++ * @token_rate: the desired token rate for "set" function, or the queried token ++ * rate for "get" function. ++ * @token_limit: the desired token limit for "set" function, or the queried ++ * token limit for "get" function. ++ * ++ * Return zero for success. The "set" function returns -EINVAL if the channel ++ * is unshaped, or -EIO if the configure shapper command returns error. The ++ * "get" function returns -EINVAL if token rate of token limit is not set, or ++ * the query shaper command returns error. ++ */ ++int qman_ceetm_channel_set_commit_rate(struct qm_ceetm_channel *channel, ++ const struct qm_ceetm_rate *token_rate, ++ u16 token_limit); ++int qman_ceetm_channel_get_commit_rate(struct qm_ceetm_channel *channel, ++ struct qm_ceetm_rate *token_rate, ++ u16 *token_limit); ++int qman_ceetm_channel_set_excess_rate(struct qm_ceetm_channel *channel, ++ const struct qm_ceetm_rate *token_rate, ++ u16 token_limit); ++int qman_ceetm_channel_get_excess_rate(struct qm_ceetm_channel *channel, ++ struct qm_ceetm_rate *token_rate, ++ u16 *token_limit); ++/** ++ * qman_ceetm_channel_set_commit_rate_bps ++ * qman_ceetm_channel_get_commit_rate_bps ++ * qman_ceetm_channel_set_excess_rate_bps ++ * qman_ceetm_channel_get_excess_rate_bps - Set/get channel CR/ER shaper ++ * parameters. ++ * @channel: the given channel. ++ * @token_rate: the desired shaper rate in bps for "set" function, or the ++ * shaper rate in bps for "get" function. ++ * @token_limit: the desired token limit for "set" function, or the queried ++ * token limit for "get" function. ++ * ++ * Return zero for success. The "set" function returns -EINVAL if the channel ++ * is unshaped, or -EIO if the configure shapper command returns error. The ++ * "get" function returns -EINVAL if token rate of token limit is not set, or ++ * the query shaper command returns error. ++ */ ++int qman_ceetm_channel_set_commit_rate_bps(struct qm_ceetm_channel *channel, ++ u64 bps, u16 token_limit); ++int qman_ceetm_channel_get_commit_rate_bps(struct qm_ceetm_channel *channel, ++ u64 *bps, u16 *token_limit); ++int qman_ceetm_channel_set_excess_rate_bps(struct qm_ceetm_channel *channel, ++ u64 bps, u16 token_limit); ++int qman_ceetm_channel_get_excess_rate_bps(struct qm_ceetm_channel *channel, ++ u64 *bps, u16 *token_limit); ++ ++/** ++ * qman_ceetm_channel_set_weight ++ * qman_ceetm_channel_get_weight - Set/get the weight for unshaped channel ++ * @channel: the given channel. ++ * @token_limit: the desired token limit as the weight of the unshaped channel ++ * for "set" function, or the queried token limit for "get" function. ++ * ++ * The algorithm of unshaped fair queuing (uFQ) is used for unshaped channel. ++ * It allows the unshaped channels to be included in the CR time eligible list, ++ * and thus use the configured CR token limit value as their fair queuing ++ * weight. ++ * ++ * Return zero for success, or -EINVAL if the channel is a shaped channel or ++ * the management command returns error. ++ */ ++int qman_ceetm_channel_set_weight(struct qm_ceetm_channel *channel, ++ u16 token_limit); ++int qman_ceetm_channel_get_weight(struct qm_ceetm_channel *channel, ++ u16 *token_limit); ++ ++/** ++ * qman_ceetm_channel_set_group ++ * qman_ceetm_channel_get_group - Set/get the grouping of the class scheduler. ++ * @channel: the given channel. ++ * @group_b: indicates whether there is group B in this channel. ++ * @prio_a: the priority of group A. ++ * @prio_b: the priority of group B. ++ * ++ * There are 8 individual class queues (CQ0-CQ7), and 8 grouped class queues ++ * (CQ8-CQ15). If 'group_b' is zero, then all the grouped class queues are in ++ * group A, otherwise they are split into group A (CQ8-11) and group B ++ * (CQ12-C15). The individual class queues and the group(s) are in strict ++ * priority order relative to each other. Within the group(s), the scheduling ++ * is not strict priority order, but the result of scheduling within a group ++ * is in strict priority order relative to the other class queues in the ++ * channel. 'prio_a' and 'prio_b' control the priority order of the groups ++ * relative to the individual class queues, and take values from 0-7. Eg. if ++ * 'group_b' is non-zero, 'prio_a' is 2 and 'prio_b' is 6, then the strict ++ * priority order would be; ++ * CQ0, CQ1, CQ2, GROUPA, CQ3, CQ4, CQ5, CQ6, GROUPB, CQ7 ++ * ++ * Return 0 for success. For "set" function, returns -EINVAL if prio_a or ++ * prio_b are out of the range 0 - 7 (priority of group A or group B can not ++ * be 0, CQ0 is always the highest class queue in this channel.), or -EIO if ++ * the configure scheduler command returns error. For "get" function, return ++ * -EINVAL if the query scheduler command returns error. ++ */ ++int qman_ceetm_channel_set_group(struct qm_ceetm_channel *channel, ++ int group_b, ++ unsigned int prio_a, ++ unsigned int prio_b); ++int qman_ceetm_channel_get_group(struct qm_ceetm_channel *channel, ++ int *group_b, ++ unsigned int *prio_a, ++ unsigned int *prio_b); ++ ++/** ++ * qman_ceetm_channel_set_group_cr_eligibility ++ * qman_ceetm_channel_set_group_er_eligibility - Set channel group eligibility ++ * @channel: the given channel object ++ * @group_b: indicates whether there is group B in this channel. ++ * @cre: the commit rate eligibility, 1 for enable, 0 for disable. ++ * ++ * Return zero for success, or -EINVAL if eligibility setting fails. ++*/ ++int qman_ceetm_channel_set_group_cr_eligibility(struct qm_ceetm_channel ++ *channel, int group_b, int cre); ++int qman_ceetm_channel_set_group_er_eligibility(struct qm_ceetm_channel ++ *channel, int group_b, int ere); ++ ++/** ++ * qman_ceetm_channel_set_cq_cr_eligibility ++ * qman_ceetm_channel_set_cq_er_eligibility - Set channel cq eligibility ++ * @channel: the given channel object ++ * @idx: is from 0 to 7 (representing CQ0 to CQ7). ++ * @cre: the commit rate eligibility, 1 for enable, 0 for disable. ++ * ++ * Return zero for success, or -EINVAL if eligibility setting fails. ++*/ ++int qman_ceetm_channel_set_cq_cr_eligibility(struct qm_ceetm_channel *channel, ++ unsigned int idx, int cre); ++int qman_ceetm_channel_set_cq_er_eligibility(struct qm_ceetm_channel *channel, ++ unsigned int idx, int ere); ++ ++ /* --------------------- */ ++ /* CEETM :: class queues */ ++ /* --------------------- */ ++ ++/** ++ * qman_ceetm_cq_claim - Claims an individual class queue. ++ * @cq: the returned class queue object, if successful. ++ * @channel: the class queue channel. ++ * @idx: is from 0 to 7 (representing CQ0 to CQ7). ++ * @ccg: represents the class congestion group that this class queue should be ++ * subscribed to, or NULL if no congestion group membership is desired. ++ * ++ * Returns zero for success, or -EINVAL if @idx is out of range 0 - 7 or ++ * if this class queue has been claimed, or configure class queue command ++ * returns error, or returns -ENOMEM if allocating CQ memory fails. ++ */ ++int qman_ceetm_cq_claim(struct qm_ceetm_cq **cq, ++ struct qm_ceetm_channel *channel, ++ unsigned int idx, ++ struct qm_ceetm_ccg *ccg); ++ ++/** ++ * qman_ceetm_cq_claim_A - Claims a class queue group A. ++ * @cq: the returned class queue object, if successful. ++ * @channel: the class queue channel. ++ * @idx: is from 8 to 15 if only group A exits, otherwise, it is from 8 to 11. ++ * @ccg: represents the class congestion group that this class queue should be ++ * subscribed to, or NULL if no congestion group membership is desired. ++ * ++ * Return zero for success, or -EINVAL if @idx is out the range or if ++ * this class queue has been claimed or configure class queue command returns ++ * error, or returns -ENOMEM if allocating CQ memory fails. ++ */ ++int qman_ceetm_cq_claim_A(struct qm_ceetm_cq **cq, ++ struct qm_ceetm_channel *channel, ++ unsigned int idx, ++ struct qm_ceetm_ccg *ccg); ++ ++/** ++ * qman_ceetm_cq_claim_B - Claims a class queue group B. ++ * @cq: the returned class queue object, if successful. ++ * @channel: the class queue channel. ++ * @idx: is from 0 to 3 (CQ12 to CQ15). ++ * @ccg: represents the class congestion group that this class queue should be ++ * subscribed to, or NULL if no congestion group membership is desired. ++ * ++ * Return zero for success, or -EINVAL if @idx is out the range or if ++ * this class queue has been claimed or configure class queue command returns ++ * error, or returns -ENOMEM if allocating CQ memory fails. ++ */ ++int qman_ceetm_cq_claim_B(struct qm_ceetm_cq **cq, ++ struct qm_ceetm_channel *channel, ++ unsigned int idx, ++ struct qm_ceetm_ccg *ccg); ++ ++/** ++ * qman_ceetm_cq_release - Releases a previously claimed class queue. ++ * @cq: The class queue to be released. ++ * ++ * Return zero for success, or -EBUSY if the dependent objects (eg. logical ++ * FQIDs) have not been released. ++ */ ++int qman_ceetm_cq_release(struct qm_ceetm_cq *cq); ++ ++/** ++ * qman_ceetm_set_queue_weight ++ * qman_ceetm_get_queue_weight - Configure/query the weight of a grouped class ++ * queue. ++ * @cq: the given class queue. ++ * @weight_code: the desired weight code to set for the given class queue for ++ * "set" function or the queired weight code for "get" function. ++ * ++ * Grouped class queues have a default weight code of zero, which corresponds to ++ * a scheduler weighting of 1. This function can be used to modify a grouped ++ * class queue to another weight, (Use the helpers qman_ceetm_wbfs2ratio() ++ * and qman_ceetm_ratio2wbfs() to convert between these 'weight_code' values ++ * and the corresponding sharing weight.) ++ * ++ * Returns zero for success, or -EIO if the configure weight command returns ++ * error for "set" function, or -EINVAL if the query command returns ++ * error for "get" function. ++ * See section "CEETM Weighted Scheduling among Grouped Classes" in Reference ++ * Manual for weight and weight code. ++ */ ++int qman_ceetm_set_queue_weight(struct qm_ceetm_cq *cq, ++ struct qm_ceetm_weight_code *weight_code); ++int qman_ceetm_get_queue_weight(struct qm_ceetm_cq *cq, ++ struct qm_ceetm_weight_code *weight_code); ++ ++/** ++ * qman_ceetm_set_queue_weight_in_ratio ++ * qman_ceetm_get_queue_weight_in_ratio - Configure/query the weight of a ++ * grouped class queue. ++ * @cq: the given class queue. ++ * @ratio: the weight in ratio. It should be the real ratio number multiplied ++ * by 100 to get rid of fraction. ++ * ++ * Returns zero for success, or -EIO if the configure weight command returns ++ * error for "set" function, or -EINVAL if the query command returns ++ * error for "get" function. ++ */ ++int qman_ceetm_set_queue_weight_in_ratio(struct qm_ceetm_cq *cq, u32 ratio); ++int qman_ceetm_get_queue_weight_in_ratio(struct qm_ceetm_cq *cq, u32 *ratio); ++ ++/* Weights are encoded using a pseudo-exponential scheme. The weight codes 0, ++ * 32, 64, [...] correspond to weights of 1, 2, 4, [...]. The weights ++ * corresponding to intermediate weight codes are calculated using linear ++ * interpolation on the inverted values. Or put another way, the inverse weights ++ * for each 32nd weight code are 1, 1/2, 1/4, [...], and so the intervals ++ * between these are divided linearly into 32 intermediate values, the inverses ++ * of which form the remaining weight codes. ++ * ++ * The Weighted Bandwidth Fair Scheduling (WBFS) algorithm provides a form of ++ * scheduling within a group of class queues (group A or B). Weights are used to ++ * normalise the class queues to an underlying BFS algorithm where all class ++ * queues are assumed to require "equal bandwidth". So the weights referred to ++ * by the weight codes act as divisors on the size of frames being enqueued. Ie. ++ * one class queue in a group is assigned a weight of 2 whilst the other class ++ * queues in the group keep the default weight of 1, then the WBFS scheduler ++ * will effectively treat all frames enqueued on the weight-2 class queue as ++ * having half the number of bytes they really have. Ie. if all other things are ++ * equal, that class queue would get twice as much bytes-per-second bandwidth as ++ * the others. So weights should be chosen to provide bandwidth ratios between ++ * members of the same class queue group. These weights have no bearing on ++ * behaviour outside that group's WBFS mechanism though. ++ */ ++ ++/** ++ * qman_ceetm_wbfs2ratio - Given a weight code ('wbfs'), an accurate fractional ++ * representation of the corresponding weight is given (in order to not lose ++ * any precision). ++ * @weight_code: The given weight code in WBFS. ++ * @numerator: the numerator part of the weight computed by the weight code. ++ * @denominator: the denominator part of the weight computed by the weight code ++ * ++ * Returns zero for success or -EINVAL if the given weight code is illegal. ++ */ ++int qman_ceetm_wbfs2ratio(struct qm_ceetm_weight_code *weight_code, ++ u32 *numerator, ++ u32 *denominator); ++/** ++ * qman_ceetm_ratio2wbfs - Given a weight, find the nearest possible weight code ++ * If the user needs to know how close this is, convert the resulting weight ++ * code back to a weight and compare. ++ * @numerator: numerator part of the given weight. ++ * @denominator: denominator part of the given weight. ++ * @weight_code: the weight code computed from the given weight. ++ * ++ * Returns zero for success, or -ERANGE if "numerator/denominator" is outside ++ * the range of weights. ++ */ ++int qman_ceetm_ratio2wbfs(u32 numerator, ++ u32 denominator, ++ struct qm_ceetm_weight_code *weight_code, ++ int rounding); ++ ++#define QMAN_CEETM_FLAG_CLEAR_STATISTICS_COUNTER 0x1 ++/** ++ * qman_ceetm_cq_get_dequeue_statistics - Get the statistics provided by CEETM ++ * CQ counters. ++ * @cq: the given CQ object. ++ * @flags: indicates whether the statistics counter will be cleared after query. ++ * @frame_count: The number of the frames that have been counted since the ++ * counter was cleared last time. ++ * @byte_count: the number of bytes in all frames that have been counted. ++ * ++ * Return zero for success or -EINVAL if query statistics command returns error. ++ * ++ */ ++int qman_ceetm_cq_get_dequeue_statistics(struct qm_ceetm_cq *cq, u32 flags, ++ u64 *frame_count, u64 *byte_count); ++ ++/** ++ * qman_ceetm_drain_cq - drain the CQ till it is empty. ++ * @cq: the give CQ object. ++ * Return 0 for success or -EINVAL for unsuccessful command to empty CQ. ++ */ ++int qman_ceetm_drain_cq(struct qm_ceetm_cq *cq); ++ ++ /* ---------------------- */ ++ /* CEETM :: logical FQIDs */ ++ /* ---------------------- */ ++/** ++ * qman_ceetm_lfq_claim - Claims an unused logical FQID, associates it with ++ * the given class queue. ++ * @lfq: the returned lfq object, if successful. ++ * @cq: the class queue which needs to claim a LFQID. ++ * ++ * Return zero for success, or -ENODEV if no LFQID is available or -ENOMEM if ++ * allocating memory for lfq fails, or -EINVAL if configuring LFQMT fails. ++ */ ++int qman_ceetm_lfq_claim(struct qm_ceetm_lfq **lfq, ++ struct qm_ceetm_cq *cq); ++ ++/** ++ * qman_ceetm_lfq_release - Releases a previously claimed logical FQID. ++ * @lfq: the lfq to be released. ++ * ++ * Return zero for success. ++ */ ++int qman_ceetm_lfq_release(struct qm_ceetm_lfq *lfq); ++ ++/** ++ * qman_ceetm_lfq_set_context ++ * qman_ceetm_lfq_get_context - Set/get the context_a/context_b pair to the ++ * "dequeue context table" associated with the logical FQID. ++ * @lfq: the given logical FQ object. ++ * @context_a: contextA of the dequeue context. ++ * @context_b: contextB of the dequeue context. ++ * ++ * Returns zero for success, or -EINVAL if there is error to set/get the ++ * context pair. ++ */ ++int qman_ceetm_lfq_set_context(struct qm_ceetm_lfq *lfq, ++ u64 context_a, ++ u32 context_b); ++int qman_ceetm_lfq_get_context(struct qm_ceetm_lfq *lfq, ++ u64 *context_a, ++ u32 *context_b); ++ ++/** ++ * qman_ceetm_create_fq - Initialise a FQ object for the LFQ. ++ * @lfq: the given logic fq. ++ * @fq: the fq object created for the given logic fq. ++ * ++ * The FQ object can be used in qman_enqueue() and qman_enqueue_orp() APIs to ++ * target a logical FQID (and the class queue it is associated with). ++ * Note that this FQ object can only be used for enqueues, and ++ * in the case of qman_enqueue_orp() it can not be used as the 'orp' parameter, ++ * only as 'fq'. This FQ object can not (and shouldn't) be destroyed, it is only ++ * valid as long as the underlying 'lfq' remains claimed. It is the user's ++ * responsibility to ensure that the underlying 'lfq' is not released until any ++ * enqueues to this FQ object have completed. The only field the user needs to ++ * fill in is fq->cb.ern, as that enqueue rejection handler is the callback that ++ * could conceivably be called on this FQ object. This API can be called ++ * multiple times to create multiple FQ objects referring to the same logical ++ * FQID, and any enqueue rejections will respect the callback of the object that ++ * issued the enqueue (and will identify the object via the parameter passed to ++ * the callback too). There is no 'flags' parameter to this API as there is for ++ * qman_create_fq() - the created FQ object behaves as though qman_create_fq() ++ * had been called with the single flag QMAN_FQ_FLAG_NO_MODIFY. ++ * ++ * Returns 0 for success. ++ */ ++int qman_ceetm_create_fq(struct qm_ceetm_lfq *lfq, struct qman_fq *fq); ++ ++ /* -------------------------------- */ ++ /* CEETM :: class congestion groups */ ++ /* -------------------------------- */ ++ ++/** ++ * qman_ceetm_ccg_claim - Claims an unused CCG. ++ * @ccg: the returned CCG object, if successful. ++ * @channel: the given class queue channel ++ * @cscn: the callback function of this CCG. ++ * @cb_ctx: the corresponding context to be used used if state change ++ * notifications are later enabled for this CCG. ++ * ++ * The congestion group is local to the given class queue channel, so only ++ * class queues within the channel can be associated with that congestion group. ++ * The association of class queues to congestion groups occurs when the class ++ * queues are claimed, see qman_ceetm_cq_claim() and related functions. ++ * Congestion groups are in a "zero" state when initially claimed, and they are ++ * returned to that state when released. ++ * ++ * Return zero for success, or -EINVAL if no CCG in the channel is available. ++ */ ++int qman_ceetm_ccg_claim(struct qm_ceetm_ccg **ccg, ++ struct qm_ceetm_channel *channel, ++ unsigned int idx, ++ void (*cscn)(struct qm_ceetm_ccg *, ++ void *cb_ctx, ++ int congested), ++ void *cb_ctx); ++ ++/** ++ * qman_ceetm_ccg_release - Releases a previously claimed CCG. ++ * @ccg: the given ccg. ++ * ++ * Returns zero for success, or -EBUSY if the given ccg's dependent objects ++ * (class queues that are associated with the CCG) have not been released. ++ */ ++int qman_ceetm_ccg_release(struct qm_ceetm_ccg *ccg); ++ ++/* This struct is used to specify attributes for a CCG. The 'we_mask' field ++ * controls which CCG attributes are to be updated, and the remainder specify ++ * the values for those attributes. A CCG counts either frames or the bytes ++ * within those frames, but not both ('mode'). A CCG can optionally cause ++ * enqueues to be rejected, due to tail-drop or WRED, or both (they are ++ * independent options, 'td_en' and 'wr_en_g,wr_en_y,wr_en_r'). Tail-drop can be ++ * level-triggered due to a single threshold ('td_thres') or edge-triggered due ++ * to a "congestion state", but not both ('td_mode'). Congestion state has ++ * distinct entry and exit thresholds ('cs_thres_in' and 'cs_thres_out'), and ++ * notifications can be sent to software the CCG goes in to and out of this ++ * congested state ('cscn_en'). */ ++struct qm_ceetm_ccg_params { ++ /* Boolean fields together in a single bitfield struct */ ++ struct { ++ /* Whether to count bytes or frames. 1==frames */ ++ u8 mode:1; ++ /* En/disable tail-drop. 1==enable */ ++ u8 td_en:1; ++ /* Tail-drop on congestion-state or threshold. 1=threshold */ ++ u8 td_mode:1; ++ /* Generate congestion state change notifications. 1==enable */ ++ u8 cscn_en:1; ++ /* Enable WRED rejections (per colour). 1==enable */ ++ u8 wr_en_g:1; ++ u8 wr_en_y:1; ++ u8 wr_en_r:1; ++ } __packed; ++ /* Tail-drop threshold. See qm_cgr_thres_[gs]et64(). */ ++ struct qm_cgr_cs_thres td_thres; ++ /* Congestion state thresholds, for entry and exit. */ ++ struct qm_cgr_cs_thres cs_thres_in; ++ struct qm_cgr_cs_thres cs_thres_out; ++ /* Overhead accounting length. Per-packet "tax", from -128 to +127 */ ++ signed char oal; ++ /* Congestion state change notification for DCP portal, virtual CCGID*/ ++ /* WRED parameters. */ ++ struct qm_cgr_wr_parm wr_parm_g; ++ struct qm_cgr_wr_parm wr_parm_y; ++ struct qm_cgr_wr_parm wr_parm_r; ++}; ++/* Bits used in 'we_mask' to qman_ceetm_ccg_set(), controls which attributes of ++ * the CCGR are to be updated. */ ++#define QM_CCGR_WE_MODE 0x0001 /* mode (bytes/frames) */ ++#define QM_CCGR_WE_CS_THRES_IN 0x0002 /* congestion state entry threshold */ ++#define QM_CCGR_WE_TD_EN 0x0004 /* congestion state tail-drop enable */ ++#define QM_CCGR_WE_CSCN_TUPD 0x0008 /* CSCN target update */ ++#define QM_CCGR_WE_CSCN_EN 0x0010 /* congestion notification enable */ ++#define QM_CCGR_WE_WR_EN_R 0x0020 /* WRED enable - red */ ++#define QM_CCGR_WE_WR_EN_Y 0x0040 /* WRED enable - yellow */ ++#define QM_CCGR_WE_WR_EN_G 0x0080 /* WRED enable - green */ ++#define QM_CCGR_WE_WR_PARM_R 0x0100 /* WRED parameters - red */ ++#define QM_CCGR_WE_WR_PARM_Y 0x0200 /* WRED parameters - yellow */ ++#define QM_CCGR_WE_WR_PARM_G 0x0400 /* WRED parameters - green */ ++#define QM_CCGR_WE_OAL 0x0800 /* overhead accounting length */ ++#define QM_CCGR_WE_CS_THRES_OUT 0x1000 /* congestion state exit threshold */ ++#define QM_CCGR_WE_TD_THRES 0x2000 /* tail-drop threshold */ ++#define QM_CCGR_WE_TD_MODE 0x4000 /* tail-drop mode (state/threshold) */ ++#define QM_CCGR_WE_CDV 0x8000 /* cdv */ ++ ++/** ++ * qman_ceetm_ccg_set ++ * qman_ceetm_ccg_get - Configure/query a subset of CCG attributes. ++ * @ccg: the given CCG object. ++ * @we_mask: the write enable mask. ++ * @params: the parameters setting for this ccg ++ * ++ * Return 0 for success, or -EIO if configure ccg command returns error for ++ * "set" function, or -EINVAL if query ccg command returns error for "get" ++ * function. ++ */ ++int qman_ceetm_ccg_set(struct qm_ceetm_ccg *ccg, ++ u16 we_mask, ++ const struct qm_ceetm_ccg_params *params); ++int qman_ceetm_ccg_get(struct qm_ceetm_ccg *ccg, ++ struct qm_ceetm_ccg_params *params); ++ ++/** qman_ceetm_cscn_swp_set - Add or remove a software portal from the target ++ * mask. ++ * qman_ceetm_cscn_swp_get - Query whether a given software portal index is ++ * in the cscn target mask. ++ * @ccg: the give CCG object. ++ * @swp_idx: the index of the software portal. ++ * @cscn_enabled: 1: Set the swp to be cscn target. 0: remove the swp from ++ * the target mask. ++ * @we_mask: the write enable mask. ++ * @params: the parameters setting for this ccg ++ * ++ * Return 0 for success, or -EINVAL if command in set/get function fails. ++ */ ++int qman_ceetm_cscn_swp_set(struct qm_ceetm_ccg *ccg, ++ u16 swp_idx, ++ unsigned int cscn_enabled, ++ u16 we_mask, ++ const struct qm_ceetm_ccg_params *params); ++int qman_ceetm_cscn_swp_get(struct qm_ceetm_ccg *ccg, ++ u16 swp_idx, ++ unsigned int *cscn_enabled); ++ ++/** qman_ceetm_cscn_dcp_set - Add or remove a direct connect portal from the\ ++ * target mask. ++ * qman_ceetm_cscn_dcp_get - Query whether a given direct connect portal index ++ * is in the cscn target mask. ++ * @ccg: the give CCG object. ++ * @dcp_idx: the index of the direct connect portal. ++ * @vcgid: congestion state change notification for dcp portal, virtual CGID. ++ * @cscn_enabled: 1: Set the dcp to be cscn target. 0: remove the dcp from ++ * the target mask. ++ * @we_mask: the write enable mask. ++ * @params: the parameters setting for this ccg ++ * ++ * Return 0 for success, or -EINVAL if command in set/get function fails. ++ */ ++int qman_ceetm_cscn_dcp_set(struct qm_ceetm_ccg *ccg, ++ u16 dcp_idx, ++ u8 vcgid, ++ unsigned int cscn_enabled, ++ u16 we_mask, ++ const struct qm_ceetm_ccg_params *params); ++int qman_ceetm_cscn_dcp_get(struct qm_ceetm_ccg *ccg, ++ u16 dcp_idx, ++ u8 *vcgid, ++ unsigned int *cscn_enabled); ++ ++/** ++ * qman_ceetm_ccg_get_reject_statistics - Get the statistics provided by ++ * CEETM CCG counters. ++ * @ccg: the given CCG object. ++ * @flags: indicates whether the statistics counter will be cleared after query. ++ * @frame_count: The number of the frames that have been counted since the ++ * counter was cleared last time. ++ * @byte_count: the number of bytes in all frames that have been counted. ++ * ++ * Return zero for success or -EINVAL if query statistics command returns error. ++ * ++ */ ++int qman_ceetm_ccg_get_reject_statistics(struct qm_ceetm_ccg *ccg, u32 flags, ++ u64 *frame_count, u64 *byte_count); ++ ++/** ++ * qman_ceetm_query_lfqmt - Query the logical frame queue mapping table ++ * @lfqid: Logical Frame Queue ID ++ * @lfqmt_query: Results of the query command ++ * ++ * Returns zero for success or -EIO if the query command returns error. ++ * ++ */ ++int qman_ceetm_query_lfqmt(int lfqid, ++ struct qm_mcr_ceetm_lfqmt_query *lfqmt_query); ++ ++/** ++ * qman_ceetm_query_write_statistics - Query (and optionally write) statistics ++ * @cid: Target ID (CQID or CCGRID) ++ * @dcp_idx: CEETM portal ID ++ * @command_type: One of the following: ++ * 0 = Query dequeue statistics. CID carries the CQID to be queried. ++ * 1 = Query and clear dequeue statistics. CID carries the CQID to be queried ++ * 2 = Write dequeue statistics. CID carries the CQID to be written. ++ * 3 = Query reject statistics. CID carries the CCGRID to be queried. ++ * 4 = Query and clear reject statistics. CID carries the CCGRID to be queried ++ * 5 = Write reject statistics. CID carries the CCGRID to be written ++ * @frame_count: Frame count value to be written if this is a write command ++ * @byte_count: Bytes count value to be written if this is a write command ++ * ++ * Returns zero for success or -EIO if the query command returns error. ++ */ ++int qman_ceetm_query_write_statistics(u16 cid, enum qm_dc_portal dcp_idx, ++ u16 command_type, u64 frame_count, ++ u64 byte_count); ++ ++/** ++ * qman_set_wpm - Set waterfall power management ++ * ++ * @wpm_enable: boolean, 1 = enable wpm, 0 = disable wpm. ++ * ++ * Return 0 for success, return -ENODEV if QMan misc_cfg register is not ++ * accessible. ++ */ ++int qman_set_wpm(int wpm_enable); ++ ++/** ++ * qman_get_wpm - Query the waterfall power management setting ++ * ++ * @wpm_enable: boolean, 1 = enable wpm, 0 = disable wpm. ++ * ++ * Return 0 for success, return -ENODEV if QMan misc_cfg register is not ++ * accessible. ++ */ ++int qman_get_wpm(int *wpm_enable); ++ ++/* The below qman_p_***() variants might be called in a migration situation ++ * (e.g. cpu hotplug). They are used to continue accessing the portal that ++ * execution was affine to prior to migration. ++ * @qman_portal specifies which portal the APIs will use. ++*/ ++const struct qman_portal_config *qman_p_get_portal_config(struct qman_portal ++ *p); ++int qman_p_irqsource_add(struct qman_portal *p, u32 bits); ++int qman_p_irqsource_remove(struct qman_portal *p, u32 bits); ++int qman_p_poll_dqrr(struct qman_portal *p, unsigned int limit); ++u32 qman_p_poll_slow(struct qman_portal *p); ++void qman_p_poll(struct qman_portal *p); ++void qman_p_stop_dequeues(struct qman_portal *p); ++void qman_p_start_dequeues(struct qman_portal *p); ++void qman_p_static_dequeue_add(struct qman_portal *p, u32 pools); ++void qman_p_static_dequeue_del(struct qman_portal *p, u32 pools); ++u32 qman_p_static_dequeue_get(struct qman_portal *p); ++void qman_p_dca(struct qman_portal *p, struct qm_dqrr_entry *dq, ++ int park_request); ++int qman_p_volatile_dequeue(struct qman_portal *p, struct qman_fq *fq, ++ u32 flags __maybe_unused, u32 vdqcr); ++int qman_p_enqueue(struct qman_portal *p, struct qman_fq *fq, ++ const struct qm_fd *fd, u32 flags); ++int qman_p_enqueue_orp(struct qman_portal *p, struct qman_fq *fq, ++ const struct qm_fd *fd, u32 flags, ++ struct qman_fq *orp, u16 orp_seqnum); ++int qman_p_enqueue_precommit(struct qman_portal *p, struct qman_fq *fq, ++ const struct qm_fd *fd, u32 flags, ++ qman_cb_precommit cb, void *cb_arg); ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* FSL_QMAN_H */ +diff --git a/include/linux/fsl_usdpaa.h b/include/linux/fsl_usdpaa.h +new file mode 100644 +index 00000000..381853de +--- /dev/null ++++ b/include/linux/fsl_usdpaa.h +@@ -0,0 +1,372 @@ ++/* Copyright 2011-2012 Freescale Semiconductor, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++#ifndef FSL_USDPAA_H ++#define FSL_USDPAA_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include ++#include ++#include /* For "enum qm_channel" */ ++#include ++ ++#ifdef CONFIG_FSL_USDPAA ++ ++/******************************/ ++/* Allocation of resource IDs */ ++/******************************/ ++ ++/* This enum is used to distinguish between the type of underlying object being ++ * manipulated. */ ++enum usdpaa_id_type { ++ usdpaa_id_fqid, ++ usdpaa_id_bpid, ++ usdpaa_id_qpool, ++ usdpaa_id_cgrid, ++ usdpaa_id_ceetm0_lfqid, ++ usdpaa_id_ceetm0_channelid, ++ usdpaa_id_ceetm1_lfqid, ++ usdpaa_id_ceetm1_channelid, ++ usdpaa_id_max /* <-- not a valid type, represents the number of types */ ++}; ++#define USDPAA_IOCTL_MAGIC 'u' ++struct usdpaa_ioctl_id_alloc { ++ uint32_t base; /* Return value, the start of the allocated range */ ++ enum usdpaa_id_type id_type; /* what kind of resource(s) to allocate */ ++ uint32_t num; /* how many IDs to allocate (and return value) */ ++ uint32_t align; /* must be a power of 2, 0 is treated like 1 */ ++ int partial; /* whether to allow less than 'num' */ ++}; ++struct usdpaa_ioctl_id_release { ++ /* Input; */ ++ enum usdpaa_id_type id_type; ++ uint32_t base; ++ uint32_t num; ++}; ++struct usdpaa_ioctl_id_reserve { ++ enum usdpaa_id_type id_type; ++ uint32_t base; ++ uint32_t num; ++}; ++ ++ ++/* ioctl() commands */ ++#define USDPAA_IOCTL_ID_ALLOC \ ++ _IOWR(USDPAA_IOCTL_MAGIC, 0x01, struct usdpaa_ioctl_id_alloc) ++#define USDPAA_IOCTL_ID_RELEASE \ ++ _IOW(USDPAA_IOCTL_MAGIC, 0x02, struct usdpaa_ioctl_id_release) ++#define USDPAA_IOCTL_ID_RESERVE \ ++ _IOW(USDPAA_IOCTL_MAGIC, 0x0A, struct usdpaa_ioctl_id_reserve) ++ ++/**********************/ ++/* Mapping DMA memory */ ++/**********************/ ++ ++/* Maximum length for a map name, including NULL-terminator */ ++#define USDPAA_DMA_NAME_MAX 16 ++/* Flags for requesting DMA maps. Maps are private+unnamed or sharable+named. ++ * For a sharable and named map, specify _SHARED (whether creating one or ++ * binding to an existing one). If _SHARED is specified and _CREATE is not, then ++ * the mapping must already exist. If _SHARED and _CREATE are specified and the ++ * mapping doesn't already exist, it will be created. If _SHARED and _CREATE are ++ * specified and the mapping already exists, the mapping will fail unless _LAZY ++ * is specified. When mapping to a pre-existing sharable map, the length must be ++ * an exact match. Lengths must be a power-of-4 multiple of page size. ++ * ++ * Note that this does not actually map the memory to user-space, that is done ++ * by a subsequent mmap() using the page offset returned from this ioctl(). The ++ * ioctl() is what gives the process permission to do this, and a page-offset ++ * with which to do so. ++ */ ++#define USDPAA_DMA_FLAG_SHARE 0x01 ++#define USDPAA_DMA_FLAG_CREATE 0x02 ++#define USDPAA_DMA_FLAG_LAZY 0x04 ++#define USDPAA_DMA_FLAG_RDONLY 0x08 ++struct usdpaa_ioctl_dma_map { ++ /* Output parameters - virtual and physical addresses */ ++ void *ptr; ++ uint64_t phys_addr; ++ /* Input parameter, the length of the region to be created (or if ++ * mapping an existing region, this must match it). Must be a power-of-4 ++ * multiple of page size. */ ++ uint64_t len; ++ /* Input parameter, the USDPAA_DMA_FLAG_* settings. */ ++ uint32_t flags; ++ /* If _FLAG_SHARE is specified, the name of the region to be created (or ++ * of the existing mapping to use). */ ++ char name[USDPAA_DMA_NAME_MAX]; ++ /* If this ioctl() creates the mapping, this is an input parameter ++ * stating whether the region supports locking. If mapping an existing ++ * region, this is a return value indicating the same thing. */ ++ int has_locking; ++ /* In the case of a successful map with _CREATE and _LAZY, this return ++ * value indicates whether we created the mapped region or whether it ++ * already existed. */ ++ int did_create; ++}; ++ ++#ifdef CONFIG_COMPAT ++struct usdpaa_ioctl_dma_map_compat { ++ /* Output parameters - virtual and physical addresses */ ++ compat_uptr_t ptr; ++ uint64_t phys_addr; ++ /* Input parameter, the length of the region to be created (or if ++ * mapping an existing region, this must match it). Must be a power-of-4 ++ * multiple of page size. */ ++ uint64_t len; ++ /* Input parameter, the USDPAA_DMA_FLAG_* settings. */ ++ uint32_t flags; ++ /* If _FLAG_SHARE is specified, the name of the region to be created (or ++ * of the existing mapping to use). */ ++ char name[USDPAA_DMA_NAME_MAX]; ++ /* If this ioctl() creates the mapping, this is an input parameter ++ * stating whether the region supports locking. If mapping an existing ++ * region, this is a return value indicating the same thing. */ ++ int has_locking; ++ /* In the case of a successful map with _CREATE and _LAZY, this return ++ * value indicates whether we created the mapped region or whether it ++ * already existed. */ ++ int did_create; ++}; ++ ++#define USDPAA_IOCTL_DMA_MAP_COMPAT \ ++ _IOWR(USDPAA_IOCTL_MAGIC, 0x03, struct usdpaa_ioctl_dma_map_compat) ++#endif ++ ++ ++#define USDPAA_IOCTL_DMA_MAP \ ++ _IOWR(USDPAA_IOCTL_MAGIC, 0x03, struct usdpaa_ioctl_dma_map) ++/* munmap() does not remove the DMA map, just the user-space mapping to it. ++ * This ioctl will do both (though you can munmap() before calling the ioctl ++ * too). */ ++#define USDPAA_IOCTL_DMA_UNMAP \ ++ _IOW(USDPAA_IOCTL_MAGIC, 0x04, unsigned char) ++/* We implement a cross-process locking scheme per DMA map. Call this ioctl() ++ * with a mmap()'d address, and the process will (interruptible) sleep if the ++ * lock is already held by another process. Process destruction will ++ * automatically clean up any held locks. */ ++#define USDPAA_IOCTL_DMA_LOCK \ ++ _IOW(USDPAA_IOCTL_MAGIC, 0x05, unsigned char) ++#define USDPAA_IOCTL_DMA_UNLOCK \ ++ _IOW(USDPAA_IOCTL_MAGIC, 0x06, unsigned char) ++ ++/***************************************/ ++/* Mapping and using QMan/BMan portals */ ++/***************************************/ ++enum usdpaa_portal_type { ++ usdpaa_portal_qman, ++ usdpaa_portal_bman, ++}; ++ ++#define QBMAN_ANY_PORTAL_IDX 0xffffffff ++ ++struct usdpaa_ioctl_portal_map { ++ /* Input parameter, is a qman or bman portal required. */ ++ ++ enum usdpaa_portal_type type; ++ /* Specifes a specific portal index to map or QBMAN_ANY_PORTAL_IDX ++ for don't care. The portal index will be populated by the ++ driver when the ioctl() successfully completes */ ++ uint32_t index; ++ ++ /* Return value if the map succeeds, this gives the mapped ++ * cache-inhibited (cinh) and cache-enabled (cena) addresses. */ ++ struct usdpaa_portal_map { ++ void *cinh; ++ void *cena; ++ } addr; ++ /* Qman-specific return values */ ++ uint16_t channel; ++ uint32_t pools; ++}; ++ ++#ifdef CONFIG_COMPAT ++struct compat_usdpaa_ioctl_portal_map { ++ /* Input parameter, is a qman or bman portal required. */ ++ enum usdpaa_portal_type type; ++ /* Specifes a specific portal index to map or QBMAN_ANY_PORTAL_IDX ++ for don't care. The portal index will be populated by the ++ driver when the ioctl() successfully completes */ ++ uint32_t index; ++ /* Return value if the map succeeds, this gives the mapped ++ * cache-inhibited (cinh) and cache-enabled (cena) addresses. */ ++ struct usdpaa_portal_map_compat { ++ compat_uptr_t cinh; ++ compat_uptr_t cena; ++ } addr; ++ /* Qman-specific return values */ ++ uint16_t channel; ++ uint32_t pools; ++}; ++#define USDPAA_IOCTL_PORTAL_MAP_COMPAT \ ++ _IOWR(USDPAA_IOCTL_MAGIC, 0x07, struct compat_usdpaa_ioctl_portal_map) ++#define USDPAA_IOCTL_PORTAL_UNMAP_COMPAT \ ++ _IOW(USDPAA_IOCTL_MAGIC, 0x08, struct usdpaa_portal_map_compat) ++#endif ++ ++#define USDPAA_IOCTL_PORTAL_MAP \ ++ _IOWR(USDPAA_IOCTL_MAGIC, 0x07, struct usdpaa_ioctl_portal_map) ++#define USDPAA_IOCTL_PORTAL_UNMAP \ ++ _IOW(USDPAA_IOCTL_MAGIC, 0x08, struct usdpaa_portal_map) ++ ++struct usdpaa_ioctl_irq_map { ++ enum usdpaa_portal_type type; /* Type of portal to map */ ++ int fd; /* File descriptor that contains the portal */ ++ void *portal_cinh; /* Cache inhibited area to identify the portal */ ++}; ++ ++#define USDPAA_IOCTL_PORTAL_IRQ_MAP \ ++ _IOW(USDPAA_IOCTL_MAGIC, 0x09, struct usdpaa_ioctl_irq_map) ++ ++#ifdef CONFIG_COMPAT ++ ++struct compat_ioctl_irq_map { ++ enum usdpaa_portal_type type; /* Type of portal to map */ ++ compat_int_t fd; /* File descriptor that contains the portal */ ++ compat_uptr_t portal_cinh; /* Used identify the portal */}; ++ ++#define USDPAA_IOCTL_PORTAL_IRQ_MAP_COMPAT \ ++ _IOW(USDPAA_IOCTL_MAGIC, 0x09, struct compat_ioctl_irq_map) ++#endif ++ ++/* ioctl to query the amount of DMA memory used in the system */ ++struct usdpaa_ioctl_dma_used { ++ uint64_t free_bytes; ++ uint64_t total_bytes; ++}; ++#define USDPAA_IOCTL_DMA_USED \ ++ _IOR(USDPAA_IOCTL_MAGIC, 0x0B, struct usdpaa_ioctl_dma_used) ++ ++/* ioctl to allocate a raw portal */ ++struct usdpaa_ioctl_raw_portal { ++ /* inputs */ ++ enum usdpaa_portal_type type; /* Type of portal to allocate */ ++ ++ /* set to non zero to turn on stashing */ ++ uint8_t enable_stash; ++ /* Stashing attributes for the portal */ ++ uint32_t cpu; ++ uint32_t cache; ++ uint32_t window; ++ ++ /* Specifies the stash request queue this portal should use */ ++ uint8_t sdest; ++ ++ /* Specifes a specific portal index to map or QBMAN_ANY_PORTAL_IDX ++ * for don't care. The portal index will be populated by the ++ * driver when the ioctl() successfully completes */ ++ uint32_t index; ++ ++ /* outputs */ ++ uint64_t cinh; ++ uint64_t cena; ++}; ++ ++#define USDPAA_IOCTL_ALLOC_RAW_PORTAL \ ++ _IOWR(USDPAA_IOCTL_MAGIC, 0x0C, struct usdpaa_ioctl_raw_portal) ++ ++#define USDPAA_IOCTL_FREE_RAW_PORTAL \ ++ _IOR(USDPAA_IOCTL_MAGIC, 0x0D, struct usdpaa_ioctl_raw_portal) ++ ++#ifdef CONFIG_COMPAT ++ ++struct compat_ioctl_raw_portal { ++ /* inputs */ ++ enum usdpaa_portal_type type; /* Type of portal to allocate */ ++ ++ /* set to non zero to turn on stashing */ ++ uint8_t enable_stash; ++ /* Stashing attributes for the portal */ ++ uint32_t cpu; ++ uint32_t cache; ++ uint32_t window; ++ /* Specifies the stash request queue this portal should use */ ++ uint8_t sdest; ++ ++ /* Specifes a specific portal index to map or QBMAN_ANY_PORTAL_IDX ++ * for don't care. The portal index will be populated by the ++ * driver when the ioctl() successfully completes */ ++ uint32_t index; ++ ++ /* outputs */ ++ uint64_t cinh; ++ uint64_t cena; ++}; ++ ++#define USDPAA_IOCTL_ALLOC_RAW_PORTAL_COMPAT \ ++ _IOWR(USDPAA_IOCTL_MAGIC, 0x0C, struct compat_ioctl_raw_portal) ++ ++#define USDPAA_IOCTL_FREE_RAW_PORTAL_COMPAT \ ++ _IOR(USDPAA_IOCTL_MAGIC, 0x0D, struct compat_ioctl_raw_portal) ++ ++#endif ++ ++#ifdef __KERNEL__ ++ ++/* Early-boot hook */ ++int __init fsl_usdpaa_init_early(void); ++ ++/* Fault-handling in arch/powerpc/mm/mem.c gives USDPAA an opportunity to detect ++ * faults within its ranges via this hook. */ ++int usdpaa_test_fault(unsigned long pfn, u64 *phys_addr, u64 *size); ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* CONFIG_FSL_USDPAA */ ++ ++#ifdef __KERNEL__ ++/* This interface is needed in a few places and though it's not specific to ++ * USDPAA as such, creating a new header for it doesn't make any sense. The ++ * qbman kernel driver implements this interface and uses it as the backend for ++ * both the FQID and BPID allocators. The fsl_usdpaa driver also uses this ++ * interface for tracking per-process allocations handed out to user-space. */ ++struct dpa_alloc { ++ struct list_head free; ++ spinlock_t lock; ++ struct list_head used; ++}; ++#define DECLARE_DPA_ALLOC(name) \ ++ struct dpa_alloc name = { \ ++ .free = { \ ++ .prev = &name.free, \ ++ .next = &name.free \ ++ }, \ ++ .lock = __SPIN_LOCK_UNLOCKED(name.lock), \ ++ .used = { \ ++ .prev = &name.used, \ ++ .next = &name.used \ ++ } \ ++ } ++static inline void dpa_alloc_init(struct dpa_alloc *alloc) ++{ ++ INIT_LIST_HEAD(&alloc->free); ++ INIT_LIST_HEAD(&alloc->used); ++ spin_lock_init(&alloc->lock); ++} ++int dpa_alloc_new(struct dpa_alloc *alloc, u32 *result, u32 count, u32 align, ++ int partial); ++void dpa_alloc_free(struct dpa_alloc *alloc, u32 base_id, u32 count); ++void dpa_alloc_seed(struct dpa_alloc *alloc, u32 fqid, u32 count); ++ ++/* Like 'new' but specifies the desired range, returns -ENOMEM if the entire ++ * desired range is not available, or 0 for success. */ ++int dpa_alloc_reserve(struct dpa_alloc *alloc, u32 base_id, u32 count); ++/* Pops and returns contiguous ranges from the allocator. Returns -ENOMEM when ++ * 'alloc' is empty. */ ++int dpa_alloc_pop(struct dpa_alloc *alloc, u32 *result, u32 *count); ++/* Returns 1 if the specified id is alloced, 0 otherwise */ ++int dpa_alloc_check(struct dpa_alloc *list, u32 id); ++#endif /* __KERNEL__ */ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* FSL_USDPAA_H */ +diff --git a/include/uapi/linux/fmd/Kbuild b/include/uapi/linux/fmd/Kbuild +new file mode 100644 +index 00000000..56a20401 +--- /dev/null ++++ b/include/uapi/linux/fmd/Kbuild +@@ -0,0 +1,5 @@ ++header-y += integrations/ ++header-y += Peripherals/ ++ ++header-y += ioctls.h ++header-y += net_ioctls.h +diff --git a/include/uapi/linux/fmd/Peripherals/Kbuild b/include/uapi/linux/fmd/Peripherals/Kbuild +new file mode 100644 +index 00000000..43883efe +--- /dev/null ++++ b/include/uapi/linux/fmd/Peripherals/Kbuild +@@ -0,0 +1,4 @@ ++header-y += fm_ioctls.h ++header-y += fm_port_ioctls.h ++header-y += fm_pcd_ioctls.h ++header-y += fm_test_ioctls.h +diff --git a/include/uapi/linux/fmd/Peripherals/fm_ioctls.h b/include/uapi/linux/fmd/Peripherals/fm_ioctls.h +new file mode 100644 +index 00000000..e0c2dd31 +--- /dev/null ++++ b/include/uapi/linux/fmd/Peripherals/fm_ioctls.h +@@ -0,0 +1,628 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/**************************************************************************//** ++ @File fm_ioctls.h ++ ++ @Description FM Char device ioctls ++*//***************************************************************************/ ++#ifndef __FM_IOCTLS_H ++#define __FM_IOCTLS_H ++ ++ ++/**************************************************************************//** ++ @Group lnx_ioctl_FM_grp Frame Manager Linux IOCTL API ++ ++ @Description FM Linux ioctls definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Collection FM IOCTL device ('/dev') definitions ++*//***************************************************************************/ ++#define DEV_FM_NAME "fm" /**< Name of the FM chardev */ ++ ++#define DEV_FM_MINOR_BASE 0 ++#define DEV_FM_PCD_MINOR_BASE (DEV_FM_MINOR_BASE + 1) /*/dev/fmx-pcd */ ++#define DEV_FM_OH_PORTS_MINOR_BASE (DEV_FM_PCD_MINOR_BASE + 1) /*/dev/fmx-port-ohy */ ++#define DEV_FM_RX_PORTS_MINOR_BASE (DEV_FM_OH_PORTS_MINOR_BASE + FM_MAX_NUM_OF_OH_PORTS) /*/dev/fmx-port-rxy */ ++#define DEV_FM_TX_PORTS_MINOR_BASE (DEV_FM_RX_PORTS_MINOR_BASE + FM_MAX_NUM_OF_RX_PORTS) /*/dev/fmx-port-txy */ ++#define DEV_FM_MAX_MINORS (DEV_FM_TX_PORTS_MINOR_BASE + FM_MAX_NUM_OF_TX_PORTS) ++ ++#define FM_IOC_NUM(n) (n) ++#define FM_PCD_IOC_NUM(n) (n+20) ++#define FM_PORT_IOC_NUM(n) (n+70) ++/* @} */ ++ ++#define IOC_FM_MAX_NUM_OF_PORTS 64 ++ ++ ++/**************************************************************************//** ++ @Description Enum for defining port types ++ (must match enum e_FmPortType defined in fm_ext.h) ++*//***************************************************************************/ ++typedef enum ioc_fm_port_type { ++ e_IOC_FM_PORT_TYPE_OH_OFFLINE_PARSING = 0, /**< Offline parsing port */ ++ e_IOC_FM_PORT_TYPE_RX, /**< 1G Rx port */ ++ e_IOC_FM_PORT_TYPE_RX_10G, /**< 10G Rx port */ ++ e_IOC_FM_PORT_TYPE_TX, /**< 1G Tx port */ ++ e_IOC_FM_PORT_TYPE_TX_10G, /**< 10G Tx port */ ++ e_IOC_FM_PORT_TYPE_DUMMY ++} ioc_fm_port_type; ++ ++ ++/**************************************************************************//** ++ @Group lnx_ioctl_FM_lib_grp FM library ++ ++ @Description FM API functions, definitions and enums ++ The FM module is the main driver module and is a mandatory module ++ for FM driver users. Before any further module initialization, ++ this module must be initialized. ++ The FM is a "single-tone" module. It is responsible of the common ++ HW modules: FPM, DMA, common QMI, common BMI initializations and ++ run-time control routines. This module must be initialized always ++ when working with any of the FM modules. ++ NOTE - We assumes that the FML will be initialize only by core No. 0! ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description FM Exceptions ++*//***************************************************************************/ ++typedef enum ioc_fm_exceptions { ++ e_IOC_FM_EX_DMA_BUS_ERROR, /**< DMA bus error. */ ++ e_IOC_EX_DMA_READ_ECC, /**< Read Buffer ECC error (Valid for FM rev < 6)*/ ++ e_IOC_EX_DMA_SYSTEM_WRITE_ECC, /**< Write Buffer ECC error on system side (Valid for FM rev < 6)*/ ++ e_IOC_EX_DMA_FM_WRITE_ECC, /**< Write Buffer ECC error on FM side (Valid for FM rev < 6)*/ ++ e_IOC_EX_DMA_SINGLE_PORT_ECC, /**< Single Port ECC error on FM side (Valid for FM rev > 6)*/ ++ e_IOC_EX_FPM_STALL_ON_TASKS, /**< Stall of tasks on FPM */ ++ e_IOC_EX_FPM_SINGLE_ECC, /**< Single ECC on FPM. */ ++ e_IOC_EX_FPM_DOUBLE_ECC, /**< Double ECC error on FPM ram access */ ++ e_IOC_EX_QMI_SINGLE_ECC, /**< Single ECC on QMI. */ ++ e_IOC_EX_QMI_DOUBLE_ECC, /**< Double bit ECC occurred on QMI */ ++ e_IOC_EX_QMI_DEQ_FROM_UNKNOWN_PORTID,/**< Dequeue from unknown port id */ ++ e_IOC_EX_BMI_LIST_RAM_ECC, /**< Linked List RAM ECC error */ ++ e_IOC_EX_BMI_STORAGE_PROFILE_ECC, /**< Storage Profile ECC Error */ ++ e_IOC_EX_BMI_STATISTICS_RAM_ECC, /**< Statistics Count RAM ECC Error Enable */ ++ e_IOC_EX_BMI_DISPATCH_RAM_ECC, /**< Dispatch RAM ECC Error Enable */ ++ e_IOC_EX_IRAM_ECC, /**< Double bit ECC occurred on IRAM*/ ++ e_IOC_EX_MURAM_ECC /**< Double bit ECC occurred on MURAM*/ ++} ioc_fm_exceptions; ++ ++/**************************************************************************//** ++ @Group lnx_ioctl_FM_runtime_control_grp FM Runtime Control Unit ++ ++ @Description FM Runtime control unit API functions, definitions and enums. ++ The FM driver provides a set of control routines for each module. ++ These routines may only be called after the module was fully ++ initialized (both configuration and initialization routines were ++ called). They are typically used to get information from hardware ++ (status, counters/statistics, revision etc.), to modify a current ++ state or to force/enable a required action. Run-time control may ++ be called whenever necessary and as many times as needed. ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Collection General FM defines. ++ *//***************************************************************************/ ++#define IOC_FM_MAX_NUM_OF_VALID_PORTS (FM_MAX_NUM_OF_OH_PORTS + \ ++ FM_MAX_NUM_OF_1G_RX_PORTS + \ ++ FM_MAX_NUM_OF_10G_RX_PORTS + \ ++ FM_MAX_NUM_OF_1G_TX_PORTS + \ ++ FM_MAX_NUM_OF_10G_TX_PORTS) ++/* @} */ ++ ++/**************************************************************************//** ++ @Description Structure for Port bandwidth requirement. Port is identified ++ by type and relative id. ++ (must be identical to t_FmPortBandwidth defined in fm_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_port_bandwidth_t { ++ ioc_fm_port_type type; /**< FM port type */ ++ uint8_t relative_port_id; /**< Type relative port id */ ++ uint8_t bandwidth; /**< bandwidth - (in term of percents) */ ++} ioc_fm_port_bandwidth_t; ++ ++/**************************************************************************//** ++ @Description A Structure containing an array of Port bandwidth requirements. ++ The user should state the ports requiring bandwidth in terms of ++ percentage - i.e. all port's bandwidths in the array must add ++ up to 100. ++ (must be identical to t_FmPortsBandwidthParams defined in fm_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_port_bandwidth_params { ++ uint8_t num_of_ports; ++ /**< num of ports listed in the array below */ ++ ioc_fm_port_bandwidth_t ports_bandwidths[IOC_FM_MAX_NUM_OF_VALID_PORTS]; ++ /**< for each port, it's bandwidth (all port's ++ bandwidths must add up to 100.*/ ++} ioc_fm_port_bandwidth_params; ++ ++/**************************************************************************//** ++ @Description enum for defining FM counters ++*//***************************************************************************/ ++typedef enum ioc_fm_counters { ++ e_IOC_FM_COUNTERS_ENQ_TOTAL_FRAME, /**< QMI total enqueued frames counter */ ++ e_IOC_FM_COUNTERS_DEQ_TOTAL_FRAME, /**< QMI total dequeued frames counter */ ++ e_IOC_FM_COUNTERS_DEQ_0, /**< QMI 0 frames from QMan counter */ ++ e_IOC_FM_COUNTERS_DEQ_1, /**< QMI 1 frames from QMan counter */ ++ e_IOC_FM_COUNTERS_DEQ_2, /**< QMI 2 frames from QMan counter */ ++ e_IOC_FM_COUNTERS_DEQ_3, /**< QMI 3 frames from QMan counter */ ++ e_IOC_FM_COUNTERS_DEQ_FROM_DEFAULT, /**< QMI dequeue from default queue counter */ ++ e_IOC_FM_COUNTERS_DEQ_FROM_CONTEXT, /**< QMI dequeue from FQ context counter */ ++ e_IOC_FM_COUNTERS_DEQ_FROM_FD, /**< QMI dequeue from FD command field counter */ ++ e_IOC_FM_COUNTERS_DEQ_CONFIRM, /**< QMI dequeue confirm counter */ ++} ioc_fm_counters; ++ ++typedef struct ioc_fm_obj_t { ++ void *obj; ++} ioc_fm_obj_t; ++ ++/**************************************************************************//** ++ @Description A structure for returning revision information ++ (must match struct t_FmRevisionInfo declared in fm_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_revision_info_t { ++ uint8_t major; /**< Major revision */ ++ uint8_t minor; /**< Minor revision */ ++} ioc_fm_revision_info_t; ++ ++/**************************************************************************//** ++ @Description A structure for FM counters ++*//***************************************************************************/ ++typedef struct ioc_fm_counters_params_t { ++ ioc_fm_counters cnt; /**< The requested counter */ ++ uint32_t val; /**< The requested value to get/set from/into the counter */ ++} ioc_fm_counters_params_t; ++ ++typedef union ioc_fm_api_version_t { ++ struct { ++ uint8_t major; ++ uint8_t minor; ++ uint8_t respin; ++ uint8_t reserved; ++ } version; ++ uint32_t ver; ++} ioc_fm_api_version_t; ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Description A structure of information about each of the external ++ buffer pools used by a port or storage-profile. ++ (must be identical to t_FmExtPoolParams defined in fm_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_ext_pool_params { ++ uint8_t id; /**< External buffer pool id */ ++ uint16_t size; /**< External buffer pool buffer size */ ++} ioc_fm_ext_pool_params; ++ ++/**************************************************************************//** ++ @Description A structure for informing the driver about the external ++ buffer pools allocated in the BM and used by a port or a ++ storage-profile. ++ (must be identical to t_FmExtPools defined in fm_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_ext_pools { ++ uint8_t num_of_pools_used; /**< Number of pools use by this port */ ++ ioc_fm_ext_pool_params ext_buf_pool[FM_PORT_MAX_NUM_OF_EXT_POOLS]; ++ /**< Parameters for each port */ ++} ioc_fm_ext_pools; ++ ++typedef struct ioc_fm_vsp_params_t { ++ void *p_fm; /**< A handle to the FM object this VSP related to */ ++ ioc_fm_ext_pools ext_buf_pools; /**< Which external buffer pools are used ++ (up to FM_PORT_MAX_NUM_OF_EXT_POOLS), and their sizes. ++ parameter associated with Rx / OP port */ ++ uint16_t liodn_offset; /**< VSP's LIODN offset */ ++ struct { ++ ioc_fm_port_type port_type; /**< Port type */ ++ uint8_t port_id; /**< Port Id - relative to type */ ++ } port_params; ++ uint8_t relative_profile_id; /**< VSP Id - relative to VSP's range ++ defined in relevant FM object */ ++ void *id; /**< return value */ ++} ioc_fm_vsp_params_t; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++/**************************************************************************//** ++ @Description A structure for defining BM pool depletion criteria ++*//***************************************************************************/ ++typedef struct ioc_fm_buf_pool_depletion_t { ++ bool pools_grp_mode_enable; /**< select mode in which pause frames will be sent after ++ a number of pools (all together!) are depleted */ ++ uint8_t num_of_pools; /**< the number of depleted pools that will invoke ++ pause frames transmission. */ ++ bool pools_to_consider[BM_MAX_NUM_OF_POOLS]; ++ /**< For each pool, TRUE if it should be considered for ++ depletion (Note - this pool must be used by this port!). */ ++ bool single_pool_mode_enable; /**< select mode in which pause frames will be sent after ++ a single-pool is depleted; */ ++ bool pools_to_consider_for_single_mode[BM_MAX_NUM_OF_POOLS]; ++ /**< For each pool, TRUE if it should be considered for ++ depletion (Note - this pool must be used by this port!) */ ++#if (DPAA_VERSION >= 11) ++ bool pfc_priorities_en[FM_MAX_NUM_OF_PFC_PRIORITIES]; ++ /**< This field is used by the MAC as the Priority Enable Vector in the PFC frame ++ which is transmitted */ ++#endif /* (DPAA_VERSION >= 11) */ ++} ioc_fm_buf_pool_depletion_t; ++ ++#if (DPAA_VERSION >= 11) ++typedef struct ioc_fm_buf_pool_depletion_params_t { ++ void *p_fm_vsp; ++ ioc_fm_buf_pool_depletion_t fm_buf_pool_depletion; ++} ioc_fm_buf_pool_depletion_params_t; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++typedef struct ioc_fm_buffer_prefix_content_t { ++ uint16_t priv_data_size; /**< Number of bytes to be left at the beginning ++ of the external buffer; Note that the private-area will ++ start from the base of the buffer address. */ ++ bool pass_prs_result; /**< TRUE to pass the parse result to/from the FM; ++ User may use FM_PORT_GetBufferPrsResult() in order to ++ get the parser-result from a buffer. */ ++ bool pass_time_stamp; /**< TRUE to pass the timeStamp to/from the FM ++ User may use FM_PORT_GetBufferTimeStamp() in order to ++ get the parser-result from a buffer. */ ++ bool pass_hash_result; /**< TRUE to pass the KG hash result to/from the FM ++ User may use FM_PORT_GetBufferHashResult() in order to ++ get the parser-result from a buffer. */ ++ bool pass_all_other_pcd_info; /**< Add all other Internal-Context information: ++ AD, hash-result, key, etc. */ ++ uint16_t data_align; /**< 0 to use driver's default alignment [64], ++ other value for selecting a data alignment (must be a power of 2); ++ if write optimization is used, must be >= 16. */ ++ uint8_t manip_extra_space; /**< Maximum extra size needed (insertion-size minus removal-size); ++ Note that this field impacts the size of the buffer-prefix ++ (i.e. it pushes the data offset); ++ This field is irrelevant if DPAA_VERSION==10 */ ++} ioc_fm_buffer_prefix_content_t; ++ ++typedef struct ioc_fm_buffer_prefix_content_params_t { ++ void *p_fm_vsp; ++ ioc_fm_buffer_prefix_content_t fm_buffer_prefix_content; ++} ioc_fm_buffer_prefix_content_params_t; ++ ++#if (DPAA_VERSION >= 11) ++typedef struct ioc_fm_vsp_config_no_sg_params_t { ++ void *p_fm_vsp; ++ bool no_sg; ++} ioc_fm_vsp_config_no_sg_params_t; ++ ++typedef struct ioc_fm_vsp_prs_result_params_t { ++ void *p_fm_vsp; ++ void *p_data; ++} ioc_fm_vsp_prs_result_params_t; ++#endif ++ ++typedef struct fm_ctrl_mon_t { ++ uint8_t percent_cnt[2]; ++} fm_ctrl_mon_t; ++ ++typedef struct ioc_fm_ctrl_mon_counters_params_t { ++ uint8_t fm_ctrl_index; ++ fm_ctrl_mon_t *p_mon; ++} ioc_fm_ctrl_mon_counters_params_t; ++ ++/**************************************************************************//** ++ @Function FM_IOC_SET_PORTS_BANDWIDTH ++ ++ @Description Sets relative weights between ports when accessing common resources. ++ ++ @Param[in] ioc_fm_port_bandwidth_params Port bandwidth percentages, ++ their sum must equal 100. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++#define FM_IOC_SET_PORTS_BANDWIDTH _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(2), ioc_fm_port_bandwidth_params) ++ ++/**************************************************************************//** ++ @Function FM_IOC_GET_REVISION ++ ++ @Description Returns the FM revision ++ ++ @Param[out] ioc_fm_revision_info_t A structure of revision information parameters. ++ ++ @Return None. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++#define FM_IOC_GET_REVISION _IOR(FM_IOC_TYPE_BASE, FM_IOC_NUM(3), ioc_fm_revision_info_t) ++ ++/**************************************************************************//** ++ @Function FM_IOC_GET_COUNTER ++ ++ @Description Reads one of the FM counters. ++ ++ @Param[in,out] ioc_fm_counters_params_t The requested counter parameters. ++ ++ @Return Counter's current value. ++ ++ @Cautions Allowed only following FM_Init(). ++ Note that it is user's responsibilty to call this routine only ++ for enabled counters, and there will be no indication if a ++ disabled counter is accessed. ++*//***************************************************************************/ ++#define FM_IOC_GET_COUNTER _IOWR(FM_IOC_TYPE_BASE, FM_IOC_NUM(4), ioc_fm_counters_params_t) ++ ++/**************************************************************************//** ++ @Function FM_IOC_SET_COUNTER ++ ++ @Description Sets a value to an enabled counter. Use "0" to reset the counter. ++ ++ @Param[in] ioc_fm_counters_params_t The requested counter parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++#define FM_IOC_SET_COUNTER _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(5), ioc_fm_counters_params_t) ++ ++/**************************************************************************//** ++ @Function FM_IOC_FORCE_INTR ++ ++ @Description Causes an interrupt event on the requested source. ++ ++ @Param[in] ioc_fm_exceptions An exception to be forced. ++ ++ @Return E_OK on success; Error code if the exception is not enabled, ++ or is not able to create interrupt. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++#define FM_IOC_FORCE_INTR _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(6), ioc_fm_exceptions) ++ ++/**************************************************************************//** ++ @Function FM_IOC_GET_API_VERSION ++ ++ @Description Reads the FMD IOCTL API version. ++ ++ @Param[in,out] ioc_fm_api_version_t The requested counter parameters. ++ ++ @Return Version's value. ++*//***************************************************************************/ ++#define FM_IOC_GET_API_VERSION _IOR(FM_IOC_TYPE_BASE, FM_IOC_NUM(7), ioc_fm_api_version_t) ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Function FM_VSP_Config ++ ++ @Description Creates descriptor for the FM VSP module. ++ ++ The routine returns a handle (descriptor) to the FM VSP object. ++ This descriptor must be passed as first parameter to all other ++ FM VSP function calls. ++ ++ No actual initialization or configuration of FM hardware is ++ done by this routine. ++ ++@Param[in] p_FmVspParams Pointer to data structure of parameters ++ ++ @Retval Handle to FM VSP object, or NULL for Failure. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_IOC_VSP_CONFIG_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_IOC_NUM(8), ioc_compat_fm_vsp_params_t) ++#endif ++#define FM_IOC_VSP_CONFIG _IOWR(FM_IOC_TYPE_BASE, FM_IOC_NUM(8), ioc_fm_vsp_params_t) ++ ++/**************************************************************************//** ++ @Function FM_VSP_Init ++ ++ @Description Initializes the FM VSP module ++ ++ @Param[in] h_FmVsp - FM VSP module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_IOC_VSP_INIT_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(9), ioc_compat_fm_obj_t) ++#endif ++#define FM_IOC_VSP_INIT _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(9), ioc_fm_obj_t) ++ ++/**************************************************************************//** ++ @Function FM_VSP_Free ++ ++ @Description Frees all resources that were assigned to FM VSP module. ++ ++ Calling this routine invalidates the descriptor. ++ ++ @Param[in] h_FmVsp - FM VSP module descriptor ++ ++ @Return E_OK on success; Error code otherwise. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_IOC_VSP_FREE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(10), ioc_compat_fm_obj_t) ++#endif ++#define FM_IOC_VSP_FREE _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(10), ioc_fm_obj_t) ++ ++/**************************************************************************//** ++ @Function FM_VSP_ConfigPoolDepletion ++ ++ @Description Calling this routine enables pause frame generation depending on the ++ depletion status of BM pools. It also defines the conditions to activate ++ this functionality. By default, this functionality is disabled. ++ ++ @Param[in] ioc_fm_buf_pool_depletion_params_t A structure holding the required parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_IOC_VSP_CONFIG_POOL_DEPLETION_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(11), ioc_compat_fm_buf_pool_depletion_params_t) ++#endif ++#define FM_IOC_VSP_CONFIG_POOL_DEPLETION _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(11), ioc_fm_buf_pool_depletion_params_t) ++ ++/**************************************************************************//** ++ @Function FM_VSP_ConfigBufferPrefixContent ++ ++ @Description Defines the structure, size and content of the application buffer. ++ ++ The prefix will ++ In VSPs defined for Tx ports, if 'passPrsResult', the application ++ should set a value to their offsets in the prefix of ++ the FM will save the first 'privDataSize', than, ++ depending on 'passPrsResult' and 'passTimeStamp', copy parse result ++ and timeStamp, and the packet itself (in this order), to the ++ application buffer, and to offset. ++ ++ Calling this routine changes the buffer margins definitions ++ in the internal driver data base from its default ++ configuration: Data size: [DEFAULT_FM_SP_bufferPrefixContent_privDataSize] ++ Pass Parser result: [DEFAULT_FM_SP_bufferPrefixContent_passPrsResult]. ++ Pass timestamp: [DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp]. ++ ++ @Param[in] ioc_fm_buffer_prefix_content_params_t A structure holding the required parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_IOC_VSP_CONFIG_BUFFER_PREFIX_CONTENT_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(12), ioc_compat_fm_buffer_prefix_content_params_t) ++#endif ++#define FM_IOC_VSP_CONFIG_BUFFER_PREFIX_CONTENT _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(12), ioc_fm_buffer_prefix_content_params_t) ++ ++/**************************************************************************//** ++ @Function FM_VSP_ConfigNoScatherGather ++ ++ @Description Calling this routine changes the possibility to receive S/G frame ++ in the internal driver data base ++ from its default configuration: optimize = [DEFAULT_FM_SP_noScatherGather] ++ ++ @Param[in] ioc_fm_vsp_config_no_sg_params_t A structure holding the required parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_VSP_Config() and before FM_VSP_Init(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_IOC_VSP_CONFIG_NO_SG_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(13), ioc_compat_fm_vsp_config_no_sg_params_t) ++#endif ++#define FM_IOC_VSP_CONFIG_NO_SG _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(13), ioc_fm_vsp_config_no_sg_params_t) ++ ++/**************************************************************************//** ++ @Function FM_VSP_GetBufferPrsResult ++ ++ @Description Returns the pointer to the parse result in the data buffer. ++ In Rx ports this is relevant after reception, if parse ++ result is configured to be part of the data passed to the ++ application. For non Rx ports it may be used to get the pointer ++ of the area in the buffer where parse result should be ++ initialized - if so configured. ++ See FM_VSP_ConfigBufferPrefixContent for data buffer prefix ++ configuration. ++ ++ @Param[in] ioc_fm_vsp_prs_result_params_t A structure holding the required parameters. ++ ++ @Return Parse result pointer on success, NULL if parse result was not ++ configured for this port. ++ ++ @Cautions Allowed only following FM_VSP_Init(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_IOC_VSP_GET_BUFFER_PRS_RESULT_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_IOC_NUM(14), ioc_compat_fm_vsp_prs_result_params_t) ++#endif ++#define FM_IOC_VSP_GET_BUFFER_PRS_RESULT _IOWR(FM_IOC_TYPE_BASE, FM_IOC_NUM(14), ioc_fm_vsp_prs_result_params_t) ++#endif /* (DPAA_VERSION >= 11) */ ++ ++/**************************************************************************//** ++ @Function FM_CtrlMonStart ++ ++ @Description Start monitoring utilization of all available FM controllers. ++ ++ In order to obtain FM controllers utilization the following sequence ++ should be used: ++ -# FM_CtrlMonStart() ++ -# FM_CtrlMonStop() ++ -# FM_CtrlMonGetCounters() - issued for each FM controller ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++#define FM_IOC_CTRL_MON_START _IO(FM_IOC_TYPE_BASE, FM_IOC_NUM(15)) ++ ++ ++/**************************************************************************//** ++ @Function FM_CtrlMonStop ++ ++ @Description Stop monitoring utilization of all available FM controllers. ++ ++ In order to obtain FM controllers utilization the following sequence ++ should be used: ++ -# FM_CtrlMonStart() ++ -# FM_CtrlMonStop() ++ -# FM_CtrlMonGetCounters() - issued for each FM controller ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++#define FM_IOC_CTRL_MON_STOP _IO(FM_IOC_TYPE_BASE, FM_IOC_NUM(16)) ++ ++/**************************************************************************//** ++ @Function FM_CtrlMonGetCounters ++ ++ @Description Obtain FM controller utilization parameters. ++ ++ In order to obtain FM controllers utilization the following sequence ++ should be used: ++ -# FM_CtrlMonStart() ++ -# FM_CtrlMonStop() ++ -# FM_CtrlMonGetCounters() - issued for each FM controller ++ ++ @Param[in] ioc_fm_ctrl_mon_counters_params_t A structure holding the required parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_IOC_CTRL_MON_GET_COUNTERS_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(17), ioc_compat_fm_ctrl_mon_counters_params_t) ++#endif ++#define FM_IOC_CTRL_MON_GET_COUNTERS _IOW(FM_IOC_TYPE_BASE, FM_IOC_NUM(17), ioc_fm_ctrl_mon_counters_params_t) ++ ++/** @} */ /* end of lnx_ioctl_FM_runtime_control_grp group */ ++/** @} */ /* end of lnx_ioctl_FM_lib_grp group */ ++/** @} */ /* end of lnx_ioctl_FM_grp */ ++ ++#define FMD_API_VERSION_MAJOR 21 ++#define FMD_API_VERSION_MINOR 1 ++#define FMD_API_VERSION_RESPIN 0 ++ ++#endif /* __FM_IOCTLS_H */ +diff --git a/include/uapi/linux/fmd/Peripherals/fm_pcd_ioctls.h b/include/uapi/linux/fmd/Peripherals/fm_pcd_ioctls.h +new file mode 100644 +index 00000000..d13e878d +--- /dev/null ++++ b/include/uapi/linux/fmd/Peripherals/fm_pcd_ioctls.h +@@ -0,0 +1,3084 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/****************************************************************************** ++ @File fm_pcd_ioctls.h ++ ++ @Description FM PCD ... ++*//***************************************************************************/ ++#ifndef __FM_PCD_IOCTLS_H ++#define __FM_PCD_IOCTLS_H ++ ++#include "net_ioctls.h" ++#include "fm_ioctls.h" ++ ++ ++/**************************************************************************//** ++ ++ @Group lnx_ioctl_FM_grp Frame Manager Linux IOCTL API ++ ++ @Description Frame Manager Linux ioctls definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group lnx_ioctl_FM_PCD_grp FM PCD ++ ++ @Description Frame Manager PCD API functions, definitions and enums ++ ++ The FM PCD module is responsible for the initialization of all ++ global classifying FM modules. This includes the parser general and ++ common registers, the key generator global and common registers, ++ and the policer global and common registers. ++ In addition, the FM PCD SW module will initialize all required ++ key generator schemes, coarse classification flows, and policer ++ profiles. When an FM module is configured to work with one of these ++ entities, it will register to it using the FM PORT API. The PCD ++ module will manage the PCD resources - i.e. resource management of ++ KeyGen schemes, etc. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Collection General PCD defines ++*//***************************************************************************/ ++#define IOC_FM_PCD_MAX_NUM_OF_PRIVATE_HDRS 2 /**< Number of units/headers saved for user */ ++ ++#define IOC_FM_PCD_PRS_NUM_OF_HDRS 16 /**< Number of headers supported by HW parser */ ++#define IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS (32 - IOC_FM_PCD_MAX_NUM_OF_PRIVATE_HDRS) ++ /**< Number of distinction units is limited by ++ register size (32 bits) minus reserved bits ++ for private headers. */ ++#define IOC_FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS 4 /**< Maximum number of interchangeable headers ++ in a distinction unit */ ++#define IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS 8 /**< Total number of generic KeyGen registers */ ++#define IOC_FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY 35 /**< Max number allowed on any configuration; ++ For HW implementation reasons, in most ++ cases less than this will be allowed; The ++ driver will return an initialization error ++ if resource is unavailable. */ ++#define IOC_FM_PCD_KG_NUM_OF_EXTRACT_MASKS 4 /**< Total number of masks allowed on KeyGen extractions. */ ++#define IOC_FM_PCD_KG_NUM_OF_DEFAULT_GROUPS 16 /**< Number of default value logical groups */ ++ ++#define IOC_FM_PCD_PRS_NUM_OF_LABELS 32 /**< Maximum number of SW parser labels */ ++#define IOC_FM_PCD_SW_PRS_SIZE 0x00000800 /**< Total size of SW parser area */ ++ ++#define IOC_FM_PCD_MAX_MANIP_INSRT_TEMPLATE_SIZE 128 /**< Maximum size of insertion template for ++ insert manipulation */ ++ ++#if DPAA_VERSION >= 11 ++#define IOC_FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES 64 /**< Maximum possible entries for frame replicator group */ ++#endif /* DPAA_VERSION >= 11 */ ++/* @} */ ++ ++#ifdef FM_CAPWAP_SUPPORT ++#error "FM_CAPWAP_SUPPORT not implemented!" ++#endif ++ ++ ++/**************************************************************************//** ++ @Group lnx_ioctl_FM_PCD_init_grp FM PCD Initialization Unit ++ ++ @Description Frame Manager PCD Initialization Unit API ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description PCD counters ++ (must match enum e_FmPcdCounters defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_counters { ++ e_IOC_FM_PCD_KG_COUNTERS_TOTAL, /**< KeyGen counter */ ++ e_IOC_FM_PCD_PLCR_COUNTERS_RED, /**< Policer counter - counts the total number of RED packets that exit the Policer. */ ++ e_IOC_FM_PCD_PLCR_COUNTERS_YELLOW, /**< Policer counter - counts the total number of YELLOW packets that exit the Policer. */ ++ e_IOC_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED, /**< Policer counter - counts the number of packets that changed color to RED by the Policer; ++ This is a subset of e_IOC_FM_PCD_PLCR_COUNTERS_RED packet count, indicating active color changes. */ ++ e_IOC_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW, /**< Policer counter - counts the number of packets that changed color to YELLOW by the Policer; ++ This is a subset of e_IOC_FM_PCD_PLCR_COUNTERS_YELLOW packet count, indicating active color changes. */ ++ e_IOC_FM_PCD_PLCR_COUNTERS_TOTAL, /**< Policer counter - counts the total number of packets passed in the Policer. */ ++ e_IOC_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH, /**< Policer counter - counts the number of packets with length mismatch. */ ++ e_IOC_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH, /**< Parser counter - counts the number of times the parser block is dispatched. */ ++ e_IOC_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED, /**< Parser counter - counts the number of times L2 parse result is returned (including errors). */ ++ e_IOC_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED, /**< Parser counter - counts the number of times L3 parse result is returned (including errors). */ ++ e_IOC_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED, /**< Parser counter - counts the number of times L4 parse result is returned (including errors). */ ++ e_IOC_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED, /**< Parser counter - counts the number of times SHIM parse result is returned (including errors). */ ++ e_IOC_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter - counts the number of times L2 parse result is returned with errors. */ ++ e_IOC_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter - counts the number of times L3 parse result is returned with errors. */ ++ e_IOC_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter - counts the number of times L4 parse result is returned with errors. */ ++ e_IOC_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR, /**< Parser counter - counts the number of times SHIM parse result is returned with errors. */ ++ e_IOC_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES, /**< Parser counter - counts the number of cycles spent executing soft parser instruction (including stall cycles). */ ++ e_IOC_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES, /**< Parser counter - counts the number of cycles stalled waiting for parser internal memory reads while executing soft parser instruction. */ ++ e_IOC_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES, /**< Parser counter - counts the number of cycles spent executing hard parser (including stall cycles). */ ++ e_IOC_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES, /**< MURAM counter - counts the number of cycles while performing FMan Memory read. */ ++ e_IOC_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES, /**< MURAM counter - counts the number of cycles stalled while performing FMan Memory read. */ ++ e_IOC_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES, /**< MURAM counter - counts the number of cycles while performing FMan Memory write. */ ++ e_IOC_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES, /**< MURAM counter - counts the number of cycles stalled while performing FMan Memory write. */ ++ e_IOC_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES /**< FPM counter - counts the number of cycles stalled while performing a FPM Command. */ ++} ioc_fm_pcd_counters; ++ ++/**************************************************************************//** ++ @Description PCD interrupts ++ (must match enum e_FmPcdExceptions defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_exceptions { ++ e_IOC_FM_PCD_KG_EXCEPTION_DOUBLE_ECC, /**< KeyGen double-bit ECC error is detected on internal memory read access. */ ++ e_IOC_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW, /**< KeyGen scheme configuration error indicating a key size larger than 56 bytes. */ ++ e_IOC_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC, /**< Policer double-bit ECC error has been detected on PRAM read access. */ ++ e_IOC_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR, /**< Policer access to a non-initialized profile has been detected. */ ++ e_IOC_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE, /**< Policer RAM self-initialization complete */ ++ e_IOC_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE, /**< Policer atomic action complete */ ++ e_IOC_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC, /**< Parser double-bit ECC error */ ++ e_IOC_FM_PCD_PRS_EXCEPTION_SINGLE_ECC /**< Parser single-bit ECC error */ ++} ioc_fm_pcd_exceptions; ++ ++/** @} */ /* end of lnx_ioctl_FM_PCD_init_grp group */ ++ ++ ++/**************************************************************************//** ++ @Group lnx_ioctl_FM_PCD_Runtime_grp FM PCD Runtime Unit ++ ++ @Description Frame Manager PCD Runtime Unit ++ ++ The runtime control allows creation of PCD infrastructure modules ++ such as Network Environment Characteristics, Classification Plan ++ Groups and Coarse Classification Trees. ++ It also allows on-the-fly initialization, modification and removal ++ of PCD modules such as KeyGen schemes, coarse classification nodes ++ and Policer profiles. ++ ++ In order to explain the programming model of the PCD driver interface ++ a few terms should be explained, and will be used below. ++ - Distinction Header - One of the 16 protocols supported by the FM parser, ++ or one of the SHIM headers (1 or 2). May be a header with a special ++ option (see below). ++ - Interchangeable Headers Group - This is a group of Headers recognized ++ by either one of them. For example, if in a specific context the user ++ chooses to treat IPv4 and IPV6 in the same way, they may create an ++ interchangeable Headers Unit consisting of these 2 headers. ++ - A Distinction Unit - a Distinction Header or an Interchangeable Headers ++ Group. ++ - Header with special option - applies to Ethernet, MPLS, VLAN, IPv4 and ++ IPv6, includes multicast, broadcast and other protocol specific options. ++ In terms of hardware it relates to the options available in the classification ++ plan. ++ - Network Environment Characteristics - a set of Distinction Units that define ++ the total recognizable header selection for a certain environment. This is ++ NOT the list of all headers that will ever appear in a flow, but rather ++ everything that needs distinction in a flow, where distinction is made by KeyGen ++ schemes and coarse classification action descriptors. ++ ++ The PCD runtime modules initialization is done in stages. The first stage after ++ initializing the PCD module itself is to establish a Network Flows Environment ++ Definition. The application may choose to establish one or more such environments. ++ Later, when needed, the application will have to state, for some of its modules, ++ to which single environment it belongs. ++ ++ @{ ++*//***************************************************************************/ ++ ++ ++/**************************************************************************//** ++ @Description structure for FM counters ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_counters_params_t { ++ ioc_fm_pcd_counters cnt; /**< The requested counter */ ++ uint32_t val; /**< The requested value to get/set from/into the counter */ ++} ioc_fm_pcd_counters_params_t; ++ ++/**************************************************************************//** ++ @Description structure for FM exception definitios ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_exception_params_t { ++ ioc_fm_pcd_exceptions exception; /**< The requested exception */ ++ bool enable; /**< TRUE to enable interrupt, FALSE to mask it. */ ++} ioc_fm_pcd_exception_params_t; ++ ++/**************************************************************************//** ++ @Description A structure for SW parser labels ++ (must be identical to struct t_FmPcdPrsLabelParams defined in fm_pcd_ext.h) ++ *//***************************************************************************/ ++typedef struct ioc_fm_pcd_prs_label_params_t { ++ uint32_t instruction_offset; /**< SW parser label instruction offset (2 bytes ++ resolution), relative to Parser RAM. */ ++ ioc_net_header_type hdr; /**< The existence of this header will invoke ++ the SW parser code. */ ++ uint8_t index_per_hdr; /**< Normally 0, if more than one SW parser ++ attachments for the same header, use this ++ index to distinguish between them. */ ++} ioc_fm_pcd_prs_label_params_t; ++ ++/**************************************************************************//** ++ @Description A structure for SW parser ++ (Must match struct t_FmPcdPrsSwParams defined in fm_pcd_ext.h) ++ *//***************************************************************************/ ++typedef struct ioc_fm_pcd_prs_sw_params_t { ++ bool override; /**< FALSE to invoke a check that nothing else ++ was loaded to this address, including ++ internal patches. ++ TRUE to override any existing code.*/ ++ uint32_t size; /**< SW parser code size */ ++ uint16_t base; /**< SW parser base (in instruction counts! ++ must be larger than 0x20)*/ ++ uint8_t *p_code; /**< SW parser code */ ++ uint32_t sw_prs_data_params[IOC_FM_PCD_PRS_NUM_OF_HDRS]; ++ /**< SW parser data (parameters) */ ++ uint8_t num_of_labels; /**< Number of labels for SW parser. */ ++ ioc_fm_pcd_prs_label_params_t labels_table[IOC_FM_PCD_PRS_NUM_OF_LABELS]; ++ /**< SW parser labels table, ++ containing num_of_labels entries */ ++} ioc_fm_pcd_prs_sw_params_t; ++ ++/**************************************************************************//** ++ @Description A structure to set the a KeyGen default value ++ *//***************************************************************************/ ++typedef struct ioc_fm_pcd_kg_dflt_value_params_t { ++ uint8_t valueId; /**< 0,1 - one of 2 global default values */ ++ uint32_t value; /**< The requested default value */ ++} ioc_fm_pcd_kg_dflt_value_params_t; ++ ++ ++/**************************************************************************//** ++ @Function FM_PCD_Enable ++ ++ @Description This routine should be called after PCD is initialized for enabling all ++ PCD engines according to their existing configuration. ++ ++ @Return 0 on success; Error code otherwise. ++ ++ @Cautions Allowed only when PCD is disabled. ++*//***************************************************************************/ ++#define FM_PCD_IOC_ENABLE _IO(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(1)) ++ ++/**************************************************************************//** ++ @Function FM_PCD_Disable ++ ++ @Description This routine may be called when PCD is enabled in order to ++ disable all PCD engines. It may be called ++ only when none of the ports in the system are using the PCD. ++ ++ @Return 0 on success; Error code otherwise. ++ ++ @Cautions Allowed only when PCD is enabled. ++*//***************************************************************************/ ++#define FM_PCD_IOC_DISABLE _IO(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(2)) ++ ++ /**************************************************************************//** ++ @Function FM_PCD_PrsLoadSw ++ ++ @Description This routine may be called only when all ports in the ++ system are actively using the classification plan scheme. ++ In such cases it is recommended in order to save resources. ++ The driver automatically saves 8 classification plans for ++ ports that do NOT use the classification plan mechanism, to ++ avoid this (in order to save those entries) this routine may ++ be called. ++ ++ @Param[in] ioc_fm_pcd_prs_sw_params_t A pointer to the image of the software parser code. ++ ++ @Return 0 on success; Error code otherwise. ++ ++ @Cautions Allowed only when PCD is disabled. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_PRS_LOAD_SW_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(3), ioc_compat_fm_pcd_prs_sw_params_t) ++#endif ++#define FM_PCD_IOC_PRS_LOAD_SW _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(3), ioc_fm_pcd_prs_sw_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_KgSetDfltValue ++ ++ @Description Calling this routine sets a global default value to be used ++ by the KeyGen when parser does not recognize a required ++ field/header. ++ By default default values are 0. ++ ++ @Param[in] ioc_fm_pcd_kg_dflt_value_params_t A pointer to a structure with the relevant parameters ++ ++ @Return 0 on success; Error code otherwise. ++ ++ @Cautions Allowed only when PCD is disabled. ++*//***************************************************************************/ ++#define FM_PCD_IOC_KG_SET_DFLT_VALUE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(6), ioc_fm_pcd_kg_dflt_value_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_KgSetAdditionalDataAfterParsing ++ ++ @Description Calling this routine allows the keygen to access data past ++ the parser finishing point. ++ ++ @Param[in] uint8_t payload-offset; the number of bytes beyond the parser location. ++ ++ @Return 0 on success; Error code otherwise. ++ ++ @Cautions Allowed only when PCD is disabled. ++*//***************************************************************************/ ++#define FM_PCD_IOC_KG_SET_ADDITIONAL_DATA_AFTER_PARSING _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(7), uint8_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_SetException ++ ++ @Description Calling this routine enables/disables PCD interrupts. ++ ++ @Param[in] ioc_fm_pcd_exception_params_t Arguments struct with exception to be enabled/disabled. ++ ++ @Return 0 on success; Error code otherwise. ++*//***************************************************************************/ ++#define FM_PCD_IOC_SET_EXCEPTION _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(8), ioc_fm_pcd_exception_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_GetCounter ++ ++ @Description Reads one of the FM PCD counters. ++ ++ @Param[in,out] ioc_fm_pcd_counters_params_t The requested counter parameters. ++ ++ @Return 0 on success; Error code otherwise. ++ ++ @Cautions Note that it is user's responsibilty to call this routine only ++ for enabled counters, and there will be no indication if a ++ disabled counter is accessed. ++*//***************************************************************************/ ++#define FM_PCD_IOC_GET_COUNTER _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(9), ioc_fm_pcd_counters_params_t) ++ ++/**************************************************************************//** ++ ++ @Function FM_PCD_KgSchemeGetCounter ++ ++ @Description Reads scheme packet counter. ++ ++ @Param[in] h_Scheme scheme handle as returned by FM_PCD_KgSchemeSet(). ++ ++ @Return Counter's current value. ++ ++ @Cautions Allowed only following FM_PCD_Init() & FM_PCD_KgSchemeSet(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_KG_SCHEME_GET_CNTR_COMPAT _IOR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(4), ioc_compat_fm_pcd_kg_scheme_spc_t) ++#endif ++#define FM_PCD_IOC_KG_SCHEME_GET_CNTR _IOR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(4), ioc_fm_pcd_kg_scheme_spc_t) ++ ++#if 0 ++TODO: unused IOCTL ++/**************************************************************************//** ++ @Function FM_PCD_ModifyCounter ++ ++ @Description Writes a value to an enabled counter. Use "0" to reset the counter. ++ ++ @Param[in] ioc_fm_pcd_counters_params_t - The requested counter parameters. ++ ++ @Return 0 on success; Error code otherwise. ++*//***************************************************************************/ ++#define FM_PCD_IOC_MODIFY_COUNTER _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(10), ioc_fm_pcd_counters_params_t) ++#define FM_PCD_IOC_SET_COUNTER FM_PCD_IOC_MODIFY_COUNTER ++#endif ++ ++/**************************************************************************//** ++ @Function FM_PCD_ForceIntr ++ ++ @Description Causes an interrupt event on the requested source. ++ ++ @Param[in] ioc_fm_pcd_exceptions - An exception to be forced. ++ ++ @Return 0 on success; error code if the exception is not enabled, ++ or is not able to create interrupt. ++*//***************************************************************************/ ++#define FM_PCD_IOC_FORCE_INTR _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(11), ioc_fm_pcd_exceptions) ++ ++/**************************************************************************//** ++ @Collection Definitions of coarse classification parameters as required by KeyGen ++ (when coarse classification is the next engine after this scheme). ++*//***************************************************************************/ ++#define IOC_FM_PCD_MAX_NUM_OF_CC_TREES 8 ++#define IOC_FM_PCD_MAX_NUM_OF_CC_GROUPS 16 ++#define IOC_FM_PCD_MAX_NUM_OF_CC_UNITS 4 ++#define IOC_FM_PCD_MAX_NUM_OF_KEYS 256 ++#define IOC_FM_PCD_MAX_NUM_OF_FLOWS (4*KILOBYTE) ++#define IOC_FM_PCD_MAX_SIZE_OF_KEY 56 ++#define IOC_FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP 16 ++#define IOC_FM_PCD_LAST_KEY_INDEX 0xffff ++#define IOC_FM_PCD_MANIP_DSCP_VALUES 64 ++/* @} */ ++ ++/**************************************************************************//** ++ @Collection A set of definitions to allow protocol ++ special option description. ++*//***************************************************************************/ ++typedef uint32_t ioc_protocol_opt_t; /**< A general type to define a protocol option. */ ++ ++typedef ioc_protocol_opt_t ioc_eth_protocol_opt_t; /**< Ethernet protocol options. */ ++#define IOC_ETH_BROADCAST 0x80000000 /**< Ethernet Broadcast. */ ++#define IOC_ETH_MULTICAST 0x40000000 /**< Ethernet Multicast. */ ++ ++typedef ioc_protocol_opt_t ioc_vlan_protocol_opt_t; /**< Vlan protocol options. */ ++#define IOC_VLAN_STACKED 0x20000000 /**< Stacked VLAN. */ ++ ++typedef ioc_protocol_opt_t ioc_mpls_protocol_opt_t; /**< MPLS protocol options. */ ++#define IOC_MPLS_STACKED 0x10000000 /**< Stacked MPLS. */ ++ ++typedef ioc_protocol_opt_t ioc_ipv4_protocol_opt_t; /**< IPv4 protocol options. */ ++#define IOC_IPV4_BROADCAST_1 0x08000000 /**< IPv4 Broadcast. */ ++#define IOC_IPV4_MULTICAST_1 0x04000000 /**< IPv4 Multicast. */ ++#define IOC_IPV4_UNICAST_2 0x02000000 /**< Tunneled IPv4 - Unicast. */ ++#define IOC_IPV4_MULTICAST_BROADCAST_2 0x01000000 /**< Tunneled IPv4 - Broadcast/Multicast. */ ++ ++#define IOC_IPV4_FRAG_1 0x00000008 /**< IPV4 reassembly option. ++ IPV4 Reassembly manipulation requires network ++ environment with IPV4 header and IPV4_FRAG_1 option */ ++ ++typedef ioc_protocol_opt_t ioc_ipv6_protocol_opt_t; /**< IPv6 protocol options. */ ++#define IOC_IPV6_MULTICAST_1 0x00800000 /**< IPv6 Multicast. */ ++#define IOC_IPV6_UNICAST_2 0x00400000 /**< Tunneled IPv6 - Unicast. */ ++#define IOC_IPV6_MULTICAST_2 0x00200000 /**< Tunneled IPv6 - Multicast. */ ++ ++#define IOC_IPV6_FRAG_1 0x00000004 /**< IPV6 reassembly option. ++ IPV6 Reassembly manipulation requires network ++ environment with IPV6 header and IPV6_FRAG_1 option */ ++#if (DPAA_VERSION >= 11) ++typedef ioc_protocol_opt_t ioc_capwap_protocol_opt_t; /**< CAPWAP protocol options. */ ++#define CAPWAP_FRAG_1 0x00000008 /**< CAPWAP reassembly option. ++ CAPWAP Reassembly manipulation requires network ++ environment with CAPWAP header and CAPWAP_FRAG_1 option; ++ in case where fragment found, the fragment-extension offset ++ may be found at 'shim2' (in parser-result). */ ++#endif /* (DPAA_VERSION >= 11) */ ++ ++/* @} */ ++ ++#define IOC_FM_PCD_MANIP_MAX_HDR_SIZE 256 ++#define IOC_FM_PCD_MANIP_DSCP_TO_VLAN_TRANS 64 ++/**************************************************************************//** ++ @Collection A set of definitions to support Header Manipulation selection. ++*//***************************************************************************/ ++typedef uint32_t ioc_hdr_manip_flags_t; /**< A general type to define a HMan update command flags. */ ++ ++typedef ioc_hdr_manip_flags_t ioc_ipv4_hdr_manip_update_flags_t; /**< IPv4 protocol HMan update command flags. */ ++ ++#define IOC_HDR_MANIP_IPV4_TOS 0x80000000 /**< update TOS with the given value ('tos' field ++ of ioc_fm_pcd_manip_hdr_field_update_ipv4_t) */ ++#define IOC_HDR_MANIP_IPV4_ID 0x40000000 /**< update IP ID with the given value ('id' field ++ of ioc_fm_pcd_manip_hdr_field_update_ipv4_t) */ ++#define IOC_HDR_MANIP_IPV4_TTL 0x20000000 /**< Decrement TTL by 1 */ ++#define IOC_HDR_MANIP_IPV4_SRC 0x10000000 /**< update IP source address with the given value ++ ('src' field of ioc_fm_pcd_manip_hdr_field_update_ipv4_t) */ ++#define IOC_HDR_MANIP_IPV4_DST 0x08000000 /**< update IP destination address with the given value ++ ('dst' field of ioc_fm_pcd_manip_hdr_field_update_ipv4_t) */ ++ ++typedef ioc_hdr_manip_flags_t ioc_ipv6_hdr_manip_update_flags_t; /**< IPv6 protocol HMan update command flags. */ ++ ++#define IOC_HDR_MANIP_IPV6_TC 0x80000000 /**< update Traffic Class address with the given value ++ ('traffic_class' field of ioc_fm_pcd_manip_hdr_field_update_ipv6_t) */ ++#define IOC_HDR_MANIP_IPV6_HL 0x40000000 /**< Decrement Hop Limit by 1 */ ++#define IOC_HDR_MANIP_IPV6_SRC 0x20000000 /**< update IP source address with the given value ++ ('src' field of ioc_fm_pcd_manip_hdr_field_update_ipv6_t) */ ++#define IOC_HDR_MANIP_IPV6_DST 0x10000000 /**< update IP destination address with the given value ++ ('dst' field of ioc_fm_pcd_manip_hdr_field_update_ipv6_t) */ ++ ++typedef ioc_hdr_manip_flags_t ioc_tcp_udp_hdr_manip_update_flags_t;/**< TCP/UDP protocol HMan update command flags. */ ++ ++#define IOC_HDR_MANIP_TCP_UDP_SRC 0x80000000 /**< update TCP/UDP source address with the given value ++ ('src' field of ioc_fm_pcd_manip_hdr_field_update_tcp_udp_t) */ ++#define IOC_HDR_MANIP_TCP_UDP_DST 0x40000000 /**< update TCP/UDP destination address with the given value ++ ('dst' field of ioc_fm_pcd_manip_hdr_field_update_tcp_udp_t) */ ++#define IOC_HDR_MANIP_TCP_UDP_CHECKSUM 0x20000000 /**< update TCP/UDP checksum */ ++ ++/* @} */ ++ ++/**************************************************************************//** ++ @Description A type used for returning the order of the key extraction. ++ each value in this array represents the index of the extraction ++ command as defined by the user in the initialization extraction array. ++ The valid size of this array is the user define number of extractions ++ required (also marked by the second '0' in this array). ++*//***************************************************************************/ ++typedef uint8_t ioc_fm_pcd_kg_key_order_t [IOC_FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY]; ++ ++/**************************************************************************//** ++ @Description All PCD engines ++ (must match enum e_FmPcdEngine defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_engine { ++ e_IOC_FM_PCD_INVALID = 0, /**< Invalid PCD engine */ ++ e_IOC_FM_PCD_DONE, /**< No PCD Engine indicated */ ++ e_IOC_FM_PCD_KG, /**< KeyGen */ ++ e_IOC_FM_PCD_CC, /**< Coarse Classifier */ ++ e_IOC_FM_PCD_PLCR, /**< Policer */ ++ e_IOC_FM_PCD_PRS, /**< Parser */ ++#if DPAA_VERSION >= 11 ++ e_IOC_FM_PCD_FR, /**< Frame Replicator */ ++#endif /* DPAA_VERSION >= 11 */ ++ e_IOC_FM_PCD_HASH /**< Hash Table */ ++} ioc_fm_pcd_engine; ++ ++/**************************************************************************//** ++ @Description An enum for selecting extraction by header types ++ (Must match enum e_FmPcdExtractByHdrType defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_extract_by_hdr_type { ++ e_IOC_FM_PCD_EXTRACT_FROM_HDR, /**< Extract bytes from header */ ++ e_IOC_FM_PCD_EXTRACT_FROM_FIELD, /**< Extract bytes from header field */ ++ e_IOC_FM_PCD_EXTRACT_FULL_FIELD /**< Extract a full field */ ++} ioc_fm_pcd_extract_by_hdr_type; ++ ++/**************************************************************************//** ++ @Description An enum for selecting extraction source (when it is not the header) ++ (Must match enum e_FmPcdExtractFrom defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_extract_from { ++ e_IOC_FM_PCD_EXTRACT_FROM_FRAME_START, /**< KG & CC: Extract from beginning of frame */ ++ e_IOC_FM_PCD_EXTRACT_FROM_DFLT_VALUE, /**< KG only: Extract from a default value */ ++ e_IOC_FM_PCD_EXTRACT_FROM_CURR_END_OF_PARSE, /**< KG only: Extract from the point where parsing had finished */ ++ e_IOC_FM_PCD_EXTRACT_FROM_KEY, /**< CC only: Field where saved KEY */ ++ e_IOC_FM_PCD_EXTRACT_FROM_HASH, /**< CC only: Field where saved HASH */ ++ e_IOC_FM_PCD_EXTRACT_FROM_PARSE_RESULT, /**< KG & CC: Extract from the parser result */ ++ e_IOC_FM_PCD_EXTRACT_FROM_ENQ_FQID, /**< KG & CC: Extract from enqueue FQID */ ++ e_IOC_FM_PCD_EXTRACT_FROM_FLOW_ID /**< CC only: Field where saved Dequeue FQID */ ++} ioc_fm_pcd_extract_from; ++ ++/**************************************************************************//** ++ @Description An enum for selecting extraction type ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_extract_type { ++ e_IOC_FM_PCD_EXTRACT_BY_HDR, /**< Extract according to header */ ++ e_IOC_FM_PCD_EXTRACT_NON_HDR, /**< Extract from data that is not the header */ ++ e_IOC_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO /**< Extract private info as specified by user */ ++} ioc_fm_pcd_extract_type; ++ ++/**************************************************************************//** ++ @Description An enum for selecting a default ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_kg_extract_dflt_select { ++ e_IOC_FM_PCD_KG_DFLT_GBL_0, /**< Default selection is KG register 0 */ ++ e_IOC_FM_PCD_KG_DFLT_GBL_1, /**< Default selection is KG register 1 */ ++ e_IOC_FM_PCD_KG_DFLT_PRIVATE_0, /**< Default selection is a per scheme register 0 */ ++ e_IOC_FM_PCD_KG_DFLT_PRIVATE_1, /**< Default selection is a per scheme register 1 */ ++ e_IOC_FM_PCD_KG_DFLT_ILLEGAL /**< Illegal selection */ ++} ioc_fm_pcd_kg_extract_dflt_select; ++ ++/**************************************************************************//** ++ @Description Enumeration type defining all default groups - each group shares ++ a default value, one of four user-initialized values. ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_kg_known_fields_dflt_types { ++ e_IOC_FM_PCD_KG_MAC_ADDR, /**< MAC Address */ ++ e_IOC_FM_PCD_KG_TCI, /**< TCI field */ ++ e_IOC_FM_PCD_KG_ENET_TYPE, /**< ENET Type */ ++ e_IOC_FM_PCD_KG_PPP_SESSION_ID, /**< PPP Session id */ ++ e_IOC_FM_PCD_KG_PPP_PROTOCOL_ID, /**< PPP Protocol id */ ++ e_IOC_FM_PCD_KG_MPLS_LABEL, /**< MPLS label */ ++ e_IOC_FM_PCD_KG_IP_ADDR, /**< IP addr */ ++ e_IOC_FM_PCD_KG_PROTOCOL_TYPE, /**< Protocol type */ ++ e_IOC_FM_PCD_KG_IP_TOS_TC, /**< TOS or TC */ ++ e_IOC_FM_PCD_KG_IPV6_FLOW_LABEL, /**< IPV6 flow label */ ++ e_IOC_FM_PCD_KG_IPSEC_SPI, /**< IPSEC SPI */ ++ e_IOC_FM_PCD_KG_L4_PORT, /**< L4 Port */ ++ e_IOC_FM_PCD_KG_TCP_FLAG, /**< TCP Flag */ ++ e_IOC_FM_PCD_KG_GENERIC_FROM_DATA, /**< grouping implemented by SW, ++ any data extraction that is not the full ++ field described above */ ++ e_IOC_FM_PCD_KG_GENERIC_FROM_DATA_NO_V, /**< grouping implemented by SW, ++ any data extraction without validation */ ++ e_IOC_FM_PCD_KG_GENERIC_NOT_FROM_DATA /**< grouping implemented by SW, ++ extraction from parser result or ++ direct use of default value */ ++} ioc_fm_pcd_kg_known_fields_dflt_types; ++ ++/**************************************************************************//** ++ @Description Enumeration type for defining header index for scenarios with ++ multiple (tunneled) headers ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_hdr_index { ++ e_IOC_FM_PCD_HDR_INDEX_NONE = 0, /**< used when multiple headers not used, also ++ to specify regular IP (not tunneled). */ ++ e_IOC_FM_PCD_HDR_INDEX_1, /**< may be used for VLAN, MPLS, tunneled IP */ ++ e_IOC_FM_PCD_HDR_INDEX_2, /**< may be used for MPLS, tunneled IP */ ++ e_IOC_FM_PCD_HDR_INDEX_3, /**< may be used for MPLS */ ++ e_IOC_FM_PCD_HDR_INDEX_LAST = 0xFF /**< may be used for VLAN, MPLS */ ++} ioc_fm_pcd_hdr_index; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting the policer profile functional type ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_profile_type_selection { ++ e_IOC_FM_PCD_PLCR_PORT_PRIVATE, /**< Port dedicated profile */ ++ e_IOC_FM_PCD_PLCR_SHARED /**< Shared profile (shared within partition) */ ++} ioc_fm_pcd_profile_type_selection; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting the policer profile algorithm ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_plcr_algorithm_selection { ++ e_IOC_FM_PCD_PLCR_PASS_THROUGH, /**< Policer pass through */ ++ e_IOC_FM_PCD_PLCR_RFC_2698, /**< Policer algorithm RFC 2698 */ ++ e_IOC_FM_PCD_PLCR_RFC_4115 /**< Policer algorithm RFC 4115 */ ++} ioc_fm_pcd_plcr_algorithm_selection; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting a policer profile color mode ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_plcr_color_mode { ++ e_IOC_FM_PCD_PLCR_COLOR_BLIND, /**< Color blind */ ++ e_IOC_FM_PCD_PLCR_COLOR_AWARE /**< Color aware */ ++} ioc_fm_pcd_plcr_color_mode; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting a policer profile color ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_plcr_color { ++ e_IOC_FM_PCD_PLCR_GREEN, /**< Green */ ++ e_IOC_FM_PCD_PLCR_YELLOW, /**< Yellow */ ++ e_IOC_FM_PCD_PLCR_RED, /**< Red */ ++ e_IOC_FM_PCD_PLCR_OVERRIDE /**< Color override */ ++} ioc_fm_pcd_plcr_color; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting the policer profile packet frame length selector ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_plcr_frame_length_select { ++ e_IOC_FM_PCD_PLCR_L2_FRM_LEN, /**< L2 frame length */ ++ e_IOC_FM_PCD_PLCR_L3_FRM_LEN, /**< L3 frame length */ ++ e_IOC_FM_PCD_PLCR_L4_FRM_LEN, /**< L4 frame length */ ++ e_IOC_FM_PCD_PLCR_FULL_FRM_LEN /**< Full frame length */ ++} ioc_fm_pcd_plcr_frame_length_select; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting roll-back frame ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_plcr_roll_back_frame_select { ++ e_IOC_FM_PCD_PLCR_ROLLBACK_L2_FRM_LEN, /**< Rollback L2 frame length */ ++ e_IOC_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN /**< Rollback Full frame length */ ++} ioc_fm_pcd_plcr_roll_back_frame_select; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting the policer profile packet or byte mode ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_plcr_rate_mode { ++ e_IOC_FM_PCD_PLCR_BYTE_MODE, /**< Byte mode */ ++ e_IOC_FM_PCD_PLCR_PACKET_MODE /**< Packet mode */ ++} ioc_fm_pcd_plcr_rate_mode; ++ ++/**************************************************************************//** ++ @Description Enumeration type for defining action of frame ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_done_action { ++ e_IOC_FM_PCD_ENQ_FRAME = 0, /**< Enqueue frame */ ++ e_IOC_FM_PCD_DROP_FRAME /**< Drop frame */ ++} ioc_fm_pcd_done_action; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting the policer counter ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_plcr_profile_counters { ++ e_IOC_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER, /**< Green packets counter */ ++ e_IOC_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER, /**< Yellow packets counter */ ++ e_IOC_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER, /**< Red packets counter */ ++ e_IOC_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER, /**< Recolored yellow packets counter */ ++ e_IOC_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER /**< Recolored red packets counter */ ++} ioc_fm_pcd_plcr_profile_counters; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting the PCD action after extraction ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_action { ++ e_IOC_FM_PCD_ACTION_NONE, /**< NONE */ ++ e_IOC_FM_PCD_ACTION_EXACT_MATCH, /**< Exact match on the selected extraction*/ ++ e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP /**< Indexed lookup on the selected extraction*/ ++} ioc_fm_pcd_action; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of insert manipulation ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_manip_hdr_insrt_type { ++ e_IOC_FM_PCD_MANIP_INSRT_GENERIC, /**< Insert according to offset & size */ ++ e_IOC_FM_PCD_MANIP_INSRT_BY_HDR, /**< Insert according to protocol */ ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++ e_IOC_FM_PCD_MANIP_INSRT_BY_TEMPLATE /**< Insert template to start of frame */ ++#endif /* FM_CAPWAP_SUPPORT */ ++} ioc_fm_pcd_manip_hdr_insrt_type; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of remove manipulation ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_manip_hdr_rmv_type { ++ e_IOC_FM_PCD_MANIP_RMV_GENERIC, /**< Remove according to offset & size */ ++ e_IOC_FM_PCD_MANIP_RMV_BY_HDR /**< Remove according to offset & size */ ++} ioc_fm_pcd_manip_hdr_rmv_type; ++ ++/**************************************************************************//** ++ @Description An enum for selecting specific L2 fields removal ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_manip_hdr_rmv_specific_l2 { ++ e_IOC_FM_PCD_MANIP_HDR_RMV_ETHERNET, /**< Ethernet/802.3 MAC */ ++ e_IOC_FM_PCD_MANIP_HDR_RMV_STACKED_QTAGS, /**< stacked QTags */ ++ e_IOC_FM_PCD_MANIP_HDR_RMV_ETHERNET_AND_MPLS, /**< MPLS and Ethernet/802.3 MAC header until ++ the header which follows the MPLS header */ ++ e_IOC_FM_PCD_MANIP_HDR_RMV_MPLS /**< Remove MPLS header (Unlimited MPLS labels) */ ++} ioc_fm_pcd_manip_hdr_rmv_specific_l2; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting specific fields updates ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_manip_hdr_field_update_type { ++ e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN, /**< VLAN updates */ ++ e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4, /**< IPV4 updates */ ++ e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6, /**< IPV6 updates */ ++ e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP, /**< TCP_UDP updates */ ++} ioc_fm_pcd_manip_hdr_field_update_type; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting VLAN updates ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_manip_hdr_field_update_vlan { ++ e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_VPRI, /**< Replace VPri of outer most VLAN tag. */ ++ e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN /**< DSCP to VLAN priority bits translation */ ++} ioc_fm_pcd_manip_hdr_field_update_vlan; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting specific L2 fields removal ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_manip_hdr_insrt_specific_l2 { ++ e_IOC_FM_PCD_MANIP_HDR_INSRT_MPLS /**< Insert MPLS header (Unlimited MPLS labels) */ ++} ioc_fm_pcd_manip_hdr_insrt_specific_l2; ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Description Enumeration type for selecting QoS mapping mode ++ ++ Note: In all cases except 'e_FM_PCD_MANIP_HDR_QOS_MAPPING_NONE' ++ User should instruct the port to read the parser-result ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_manip_hdr_qos_mapping_mode { ++ e_IOC_FM_PCD_MANIP_HDR_QOS_MAPPING_NONE = 0, /**< No mapping, QoS field will not be changed */ ++ e_IOC_FM_PCD_MANIP_HDR_QOS_MAPPING_AS_IS, /**< QoS field will be overwritten by the last byte in the parser-result. */ ++} ioc_fm_pcd_manip_hdr_qos_mapping_mode; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting QoS source ++ ++ Note: In all cases except 'e_FM_PCD_MANIP_HDR_QOS_SRC_NONE' ++ User should left room for the parser-result on input/output buffer ++ and instruct the port to read/write the parser-result to the buffer (RPD should be set) ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_manip_hdr_qos_src { ++ e_IOC_FM_PCD_MANIP_HDR_QOS_SRC_NONE = 0, /**< TODO */ ++ e_IOC_FM_PCD_MANIP_HDR_QOS_SRC_USER_DEFINED, /**< QoS will be taken from the last byte in the parser-result. */ ++} ioc_fm_pcd_manip_hdr_qos_src; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of header insertion ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_manip_hdr_insrt_by_hdr_type { ++ e_IOC_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2, /**< Specific L2 fields insertion */ ++#if (DPAA_VERSION >= 11) ++ e_IOC_FM_PCD_MANIP_INSRT_BY_HDR_IP, /**< IP insertion */ ++ e_IOC_FM_PCD_MANIP_INSRT_BY_HDR_UDP, /**< UDP insertion */ ++ e_IOC_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE, /**< UDP lite insertion */ ++ e_IOC_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP /**< CAPWAP insertion */ ++#endif /* (DPAA_VERSION >= 11) */ ++} ioc_fm_pcd_manip_hdr_insrt_by_hdr_type; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting specific custom command ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_manip_hdr_custom_type { ++ e_IOC_FM_PCD_MANIP_HDR_CUSTOM_IP_REPLACE, /**< Replace IPv4/IPv6 */ ++} ioc_fm_pcd_manip_hdr_custom_type; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting specific custom command ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_manip_hdr_custom_ip_replace { ++ e_IOC_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV4_BY_IPV6, /**< Replace IPv4 by IPv6 */ ++ e_IOC_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4 /**< Replace IPv6 by IPv4 */ ++} ioc_fm_pcd_manip_hdr_custom_ip_replace; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of header removal ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_manip_hdr_rmv_by_hdr_type { ++ e_IOC_FM_PCD_MANIP_RMV_BY_HDR_SPECIFIC_L2 = 0, /**< Specific L2 fields removal */ ++#if (DPAA_VERSION >= 11) ++ e_IOC_FM_PCD_MANIP_RMV_BY_HDR_CAPWAP, /**< CAPWAP removal */ ++#endif /* (DPAA_VERSION >= 11) */ ++#if (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) ++ e_IOC_FM_PCD_MANIP_RMV_BY_HDR_FROM_START, /**< Locate from data that is not the header */ ++#endif /* (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ ++} ioc_fm_pcd_manip_hdr_rmv_by_hdr_type; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of timeout mode ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_manip_reassem_time_out_mode { ++ e_IOC_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAMES, /**< Limits the time of the reassembly process ++ from the first fragment to the last */ ++ e_IOC_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAG /**< Limits the time of receiving the fragment */ ++} ioc_fm_pcd_manip_reassem_time_out_mode; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of WaysNumber mode ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_manip_reassem_ways_number { ++ e_IOC_FM_PCD_MANIP_ONE_WAY_HASH = 1, /**< One way hash */ ++ e_IOC_FM_PCD_MANIP_TWO_WAYS_HASH, /**< Two ways hash */ ++ e_IOC_FM_PCD_MANIP_THREE_WAYS_HASH, /**< Three ways hash */ ++ e_IOC_FM_PCD_MANIP_FOUR_WAYS_HASH, /**< Four ways hash */ ++ e_IOC_FM_PCD_MANIP_FIVE_WAYS_HASH, /**< Five ways hash */ ++ e_IOC_FM_PCD_MANIP_SIX_WAYS_HASH, /**< Six ways hash */ ++ e_IOC_FM_PCD_MANIP_SEVEN_WAYS_HASH, /**< Seven ways hash */ ++ e_IOC_FM_PCD_MANIP_EIGHT_WAYS_HASH /**< Eight ways hash */ ++} ioc_fm_pcd_manip_reassem_ways_number; ++ ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of statistics mode ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_stats { ++ e_IOC_FM_PCD_STATS_PER_FLOWID = 0 /**< Flow ID is used as index for getting statistics */ ++} ioc_fm_pcd_stats; ++#endif ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting manipulation type ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_manip_type { ++ e_IOC_FM_PCD_MANIP_HDR = 0, /**< Header manipulation */ ++ e_IOC_FM_PCD_MANIP_REASSEM, /**< Reassembly */ ++ e_IOC_FM_PCD_MANIP_FRAG, /**< Fragmentation */ ++ e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD /**< Special Offloading */ ++} ioc_fm_pcd_manip_type; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of statistics mode ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_cc_stats_mode { ++ e_IOC_FM_PCD_CC_STATS_MODE_NONE = 0, /**< No statistics support */ ++ e_IOC_FM_PCD_CC_STATS_MODE_FRAME, /**< Frame count statistics */ ++ e_IOC_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME, /**< Byte and frame count statistics */ ++#if (DPAA_VERSION >= 11) ++ e_IOC_FM_PCD_CC_STATS_MODE_RMON, /**< Byte and frame length range count statistics */ ++#endif /* (DPAA_VERSION >= 11) */ ++} ioc_fm_pcd_cc_stats_mode; ++ ++/**************************************************************************//** ++ @Description Enumeration type for determining the action in case an IP packet ++ is larger than MTU but its DF (Don't Fragment) bit is set. ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_manip_dont_frag_action { ++ e_IOC_FM_PCD_MANIP_DISCARD_PACKET = 0, /**< Discard packet */ ++ e_IOC_FM_PCD_MANIP_ENQ_TO_ERR_Q_OR_DISCARD_PACKET = e_IOC_FM_PCD_MANIP_DISCARD_PACKET, ++ /**< Obsolete, cannot enqueue to error queue; ++ In practice, selects to discard packets; ++ Will be removed in the future */ ++ e_IOC_FM_PCD_MANIP_FRAGMENT_PACKECT, /**< Fragment packet and continue normal processing */ ++ e_IOC_FM_PCD_MANIP_CONTINUE_WITHOUT_FRAG /**< Continue normal processing without fragmenting the packet */ ++} ioc_fm_pcd_manip_dont_frag_action; ++ ++/**************************************************************************//** ++ @Description Enumeration type for selecting type of special offload manipulation ++*//***************************************************************************/ ++typedef enum ioc_fm_pcd_manip_special_offload_type { ++ e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC, /**< IPSec offload manipulation */ ++#if (DPAA_VERSION >= 11) ++ e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD_CAPWAP /**< CAPWAP offload manipulation */ ++#endif /* (DPAA_VERSION >= 11) */ ++} ioc_fm_pcd_manip_special_offload_type; ++ ++/**************************************************************************//** ++ @Description A union of protocol dependent special options ++ (Must match union u_FmPcdHdrProtocolOpt defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef union ioc_fm_pcd_hdr_protocol_opt_u { ++ ioc_eth_protocol_opt_t eth_opt; /**< Ethernet options */ ++ ioc_vlan_protocol_opt_t vlan_opt; /**< Vlan options */ ++ ioc_mpls_protocol_opt_t mpls_opt; /**< MPLS options */ ++ ioc_ipv4_protocol_opt_t ipv4_opt; /**< IPv4 options */ ++ ioc_ipv6_protocol_opt_t ipv6_opt; /**< IPv6 options */ ++#if (DPAA_VERSION >= 11) ++ ioc_capwap_protocol_opt_t capwap_opt; /**< CAPWAP options */ ++#endif /* (DPAA_VERSION >= 11) */ ++} ioc_fm_pcd_hdr_protocol_opt_u; ++ ++/**************************************************************************//** ++ @Description A union holding all known protocol fields ++*//***************************************************************************/ ++typedef union ioc_fm_pcd_fields_u { ++ ioc_header_field_eth_t eth; /**< Ethernet */ ++ ioc_header_field_vlan_t vlan; /**< VLAN */ ++ ioc_header_field_llc_snap_t llc_snap; /**< LLC SNAP */ ++ ioc_header_field_pppoe_t pppoe; /**< PPPoE */ ++ ioc_header_field_mpls_t mpls; /**< MPLS */ ++ ioc_header_field_ip_t ip; /**< IP */ ++ ioc_header_field_ipv4_t ipv4; /**< IPv4 */ ++ ioc_header_field_ipv6_t ipv6; /**< IPv6 */ ++ ioc_header_field_udp_t udp; /**< UDP */ ++ ioc_header_field_udp_lite_t udp_lite; /**< UDP_Lite */ ++ ioc_header_field_tcp_t tcp; /**< TCP */ ++ ioc_header_field_sctp_t sctp; /**< SCTP */ ++ ioc_header_field_dccp_t dccp; /**< DCCP */ ++ ioc_header_field_gre_t gre; /**< GRE */ ++ ioc_header_field_minencap_t minencap; /**< Minimal Encapsulation */ ++ ioc_header_field_ipsec_ah_t ipsec_ah; /**< IPSec AH */ ++ ioc_header_field_ipsec_esp_t ipsec_esp; /**< IPSec ESP */ ++ ioc_header_field_udp_encap_esp_t udp_encap_esp; /**< UDP Encapsulation ESP */ ++} ioc_fm_pcd_fields_u; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header extraction for key generation ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_from_hdr_t { ++ uint8_t size; /**< Size in byte */ ++ uint8_t offset; /**< Byte offset */ ++} ioc_fm_pcd_from_hdr_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining field extraction for key generation ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_from_field_t { ++ ioc_fm_pcd_fields_u field; /**< Field selection */ ++ uint8_t size; /**< Size in byte */ ++ uint8_t offset; /**< Byte offset */ ++} ioc_fm_pcd_from_field_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining a single network environment unit ++ A distinction unit should be defined if it will later be used ++ by one or more PCD engines to distinguish between flows. ++ (Must match struct t_FmPcdDistinctionUnit defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_distinction_unit_t { ++ struct { ++ ioc_net_header_type hdr; /**< One of the headers supported by the FM */ ++ ioc_fm_pcd_hdr_protocol_opt_u opt; /**< Select only one option! */ ++ } hdrs[IOC_FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS]; ++} ioc_fm_pcd_distinction_unit_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining all different distinction units supported ++ by a specific PCD Network Environment Characteristics module. ++ ++ Each unit represent a protocol or a group of protocols that may ++ be used later by the different PCD engines to distinguish between flows. ++ (Must match struct t_FmPcdNetEnvParams defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_net_env_params_t { ++ uint8_t num_of_distinction_units;/**< Number of different units to be identified */ ++ ioc_fm_pcd_distinction_unit_t units[IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; ++ /**< An array of num_of_distinction_units of the ++ different units to be identified */ ++ void *id; /**< Output parameter; Returns the net-env Id to be used */ ++} ioc_fm_pcd_net_env_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining a single extraction action when ++ creating a key ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_extract_entry_t { ++ ioc_fm_pcd_extract_type type; /**< Extraction type select */ ++ union { ++ struct { ++ ioc_net_header_type hdr; /**< Header selection */ ++ bool ignore_protocol_validation; ++ /**< Ignore protocol validation */ ++ ioc_fm_pcd_hdr_index hdr_index; /**< Relevant only for MPLS, VLAN and tunneled ++ IP. Otherwise should be cleared.*/ ++ ioc_fm_pcd_extract_by_hdr_type type; /**< Header extraction type select */ ++ union { ++ ioc_fm_pcd_from_hdr_t from_hdr; /**< Extract bytes from header parameters */ ++ ioc_fm_pcd_from_field_t from_field; /**< Extract bytes from field parameters */ ++ ioc_fm_pcd_fields_u full_field; /**< Extract full field parameters */ ++ } extract_by_hdr_type; ++ } extract_by_hdr; /**< Used when type = e_IOC_FM_PCD_KG_EXTRACT_BY_HDR */ ++ struct { ++ ioc_fm_pcd_extract_from src; /**< Non-header extraction source */ ++ ioc_fm_pcd_action action; /**< Relevant for CC Only */ ++ uint16_t ic_indx_mask; /**< Relevant only for CC when ++ action = e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP; ++ Note that the number of bits that are set within ++ this mask must be log2 of the CC-node 'num_of_keys'. ++ Note that the mask cannot be set on the lower bits. */ ++ uint8_t offset; /**< Byte offset */ ++ uint8_t size; /**< Size in bytes */ ++ } extract_non_hdr; /**< Used when type = e_IOC_FM_PCD_KG_EXTRACT_NON_HDR */ ++ } extract_params; ++} ioc_fm_pcd_extract_entry_t; ++ ++/**************************************************************************//** ++ @Description A structure for defining masks for each extracted ++ field in the key. ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_kg_extract_mask_t { ++ uint8_t extract_array_index; /**< Index in the extraction array, as initialized by user */ ++ uint8_t offset; /**< Byte offset */ ++ uint8_t mask; /**< A byte mask (selected bits will be ignored) */ ++} ioc_fm_pcd_kg_extract_mask_t; ++ ++/**************************************************************************//** ++ @Description A structure for defining default selection per groups ++ of fields ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_kg_extract_dflt_t { ++ ioc_fm_pcd_kg_known_fields_dflt_types type; /**< Default type select*/ ++ ioc_fm_pcd_kg_extract_dflt_select dflt_select; /**< Default register select */ ++} ioc_fm_pcd_kg_extract_dflt_t; ++ ++ ++/**************************************************************************//** ++ @Description A structure for defining all parameters needed for ++ generation a key and using a hash function ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_kg_key_extract_and_hash_params_t { ++ uint32_t private_dflt0; /**< Scheme default register 0 */ ++ uint32_t private_dflt1; /**< Scheme default register 1 */ ++ uint8_t num_of_used_extracts; /**< defines the valid size of the following array */ ++ ioc_fm_pcd_extract_entry_t extract_array [IOC_FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY]; ++ /**< An array of extraction definitions. */ ++ uint8_t num_of_used_dflts; /**< defines the valid size of the following array */ ++ ioc_fm_pcd_kg_extract_dflt_t dflts[IOC_FM_PCD_KG_NUM_OF_DEFAULT_GROUPS]; ++ /**< For each extraction used in this scheme, specify the required ++ default register to be used when header is not found. ++ types not specified in this array will get undefined value. */ ++ uint8_t num_of_used_masks; /**< Defines the valid size of the following array */ ++ ioc_fm_pcd_kg_extract_mask_t masks[IOC_FM_PCD_KG_NUM_OF_EXTRACT_MASKS]; ++ uint8_t hash_shift; /**< Hash result right shift. ++ Selects the 24 bits out of the 64 hash result. ++ 0 means using the 24 LSB's, otherwise use the ++ 24 LSB's after shifting right.*/ ++ uint32_t hash_distribution_num_of_fqids; /**< must be > 1 and a power of 2. Represents the range ++ of queues for the key and hash functionality */ ++ uint8_t hash_distribution_fqids_shift; /**< selects the FQID bits that will be effected by the hash */ ++ bool symmetric_hash; /**< TRUE to generate the same hash for frames with swapped source and ++ destination fields on all layers; If TRUE, driver will check that for ++ all layers, if SRC extraction is selected, DST extraction must also be ++ selected, and vice versa. */ ++} ioc_fm_pcd_kg_key_extract_and_hash_params_t; ++ ++/**************************************************************************//** ++ @Description A structure of parameters for defining a single ++ Qid mask (extracted OR). ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_kg_extracted_or_params_t { ++ ioc_fm_pcd_extract_type type; /**< Extraction type select */ ++ union { ++ struct { /**< used when type = e_IOC_FM_PCD_KG_EXTRACT_BY_HDR */ ++ ioc_net_header_type hdr; ++ ioc_fm_pcd_hdr_index hdr_index; /**< Relevant only for MPLS, VLAN and tunneled ++ IP. Otherwise should be cleared.*/ ++ bool ignore_protocol_validation; ++ ++ } extract_by_hdr; ++ ioc_fm_pcd_extract_from src; /**< used when type = e_IOC_FM_PCD_KG_EXTRACT_NON_HDR */ ++ } extract_params; ++ uint8_t extraction_offset; /**< Offset for extraction */ ++ ioc_fm_pcd_kg_extract_dflt_select dflt_value; /**< Select register from which extraction is taken if ++ field not found */ ++ uint8_t mask; /**< Mask LSB byte of extraction (specified bits are ignored) */ ++ uint8_t bit_offset_in_fqid; /**< 0-31, Selects which bits of the 24 FQID bits to effect using ++ the extracted byte; Assume byte is placed as the 8 MSB's in ++ a 32 bit word where the lower bits ++ are the FQID; i.e if bitOffsetInFqid=1 than its LSB ++ will effect the FQID MSB, if bitOffsetInFqid=24 than the ++ extracted byte will effect the 8 LSB's of the FQID, ++ if bitOffsetInFqid=31 than the byte's MSB will effect ++ the FQID's LSB; 0 means - no effect on FQID; ++ Note that one, and only one of ++ bitOffsetInFqid or bitOffsetInPlcrProfile must be set (i.e, ++ extracted byte must effect either FQID or Policer profile).*/ ++ uint8_t bit_offset_in_plcr_profile; ++ /**< 0-15, Selects which bits of the 8 policer profile id bits to ++ effect using the extracted byte; Assume byte is placed ++ as the 8 MSB's in a 16 bit word where the lower bits ++ are the policer profile id; i.e if bitOffsetInPlcrProfile=1 ++ than its LSB will effect the profile MSB, if bitOffsetInFqid=8 ++ than the extracted byte will effect the whole policer profile id, ++ if bitOffsetInFqid=15 than the byte's MSB will effect ++ the Policer Profile id's LSB; ++ 0 means - no effect on policer profile; Note that one, and only one of ++ bitOffsetInFqid or bitOffsetInPlcrProfile must be set (i.e, ++ extracted byte must effect either FQID or Policer profile).*/ ++} ioc_fm_pcd_kg_extracted_or_params_t; ++ ++/**************************************************************************//** ++ @Description A structure for configuring scheme counter ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_kg_scheme_counter_t { ++ bool update; /**< FALSE to keep the current counter state ++ and continue from that point, TRUE to update/reset ++ the counter when the scheme is written. */ ++ uint32_t value; /**< If update=TRUE, this value will be written into the ++ counter; clear this field to reset the counter. */ ++} ioc_fm_pcd_kg_scheme_counter_t; ++ ++ ++/**************************************************************************//** ++ @Description A structure for retrieving FMKG_SE_SPC ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_kg_scheme_spc_t { ++ uint32_t val; /**< return value */ ++ void *id; /**< scheme handle */ ++} ioc_fm_pcd_kg_scheme_spc_t; ++ ++/**************************************************************************//** ++ @Description A structure for defining policer profile parameters as required by keygen ++ (when policer is the next engine after this scheme). ++ (Must match struct t_FmPcdKgPlcrProfile defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_kg_plcr_profile_t { ++ bool shared_profile; /**< TRUE if this profile is shared between ports ++ (i.e. managed by master partition) May not be TRUE ++ if profile is after Coarse Classification*/ ++ bool direct; /**< If TRUE, direct_relative_profile_id only selects the profile ++ id, if FALSE fqid_offset_relative_profile_id_base is used ++ together with fqid_offset_shift and num_of_profiles ++ parameters, to define a range of profiles from ++ which the KeyGen result will determine the ++ destination policer profile. */ ++ union { ++ uint16_t direct_relative_profile_id; /**< Used if 'direct' is TRUE, to select policer profile. ++ This parameter should indicate the policer profile offset within the port's ++ policer profiles or SHARED window. */ ++ struct { ++ uint8_t fqid_offset_shift; /**< Shift of KG results without the qid base */ ++ uint8_t fqid_offset_relative_profile_id_base; ++ /**< OR of KG results without the qid base ++ This parameter should indicate the policer profile ++ offset within the port's policer profiles window ++ or SHARED window depends on shared_profile */ ++ uint8_t num_of_profiles; /**< Range of profiles starting at base */ ++ } indirect_profile; /**< Indirect profile parameters */ ++ } profile_select; /**< Direct/indirect profile selection and parameters */ ++} ioc_fm_pcd_kg_plcr_profile_t; ++ ++#if DPAA_VERSION >= 11 ++/**************************************************************************//** ++ @Description Parameters for configuring a storage profile for a KeyGen scheme. ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_kg_storage_profile_t { ++ bool direct; /**< If TRUE, directRelativeProfileId only selects the ++ profile id; ++ If FALSE, fqidOffsetRelativeProfileIdBase is used ++ together with fqidOffsetShift and numOfProfiles ++ parameters to define a range of profiles from which ++ the KeyGen result will determine the destination ++ storage profile. */ ++ union { ++ uint16_t direct_relative_profileId; /**< Used when 'direct' is TRUE, to select a storage profile; ++ should indicate the storage profile offset within the ++ port's storage profiles window. */ ++ struct { ++ uint8_t fqid_offset_shift; /**< Shift of KeyGen results without the FQID base */ ++ uint8_t fqid_offset_relative_profile_id_base; ++ /**< OR of KeyGen results without the FQID base; ++ should indicate the policer profile offset within the ++ port's storage profiles window. */ ++ uint8_t num_of_profiles; /**< Range of profiles starting at base. */ ++ } indirect_profile; /**< Indirect profile parameters. */ ++ } profile_select; /**< Direct/indirect profile selection and parameters. */ ++} ioc_fm_pcd_kg_storage_profile_t; ++#endif /* DPAA_VERSION >= 11 */ ++ ++/**************************************************************************//** ++ @Description Parameters for defining CC as the next engine after KeyGen ++ (Must match struct t_FmPcdKgCc defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_kg_cc_t { ++ void *tree_id; /**< CC Tree id */ ++ uint8_t grp_id; /**< CC group id within the CC tree */ ++ bool plcr_next; /**< TRUE if after CC, in case of data frame, ++ policing is required. */ ++ bool bypass_plcr_profile_generation; ++ /**< TRUE to bypass KeyGen policer profile generation; ++ selected profile is the one set at port initialization. */ ++ ioc_fm_pcd_kg_plcr_profile_t plcr_profile; /**< Valid only if plcr_next = TRUE and ++ bypass_plcr_profile_generation = FALSE */ ++} ioc_fm_pcd_kg_cc_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining initializing a KeyGen scheme ++ (Must match struct t_FmPcdKgSchemeParams defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_kg_scheme_params_t { ++ bool modify; /**< TRUE to change an existing scheme */ ++ union { ++ uint8_t relative_scheme_id; ++ /**< if modify=FALSE: partition-relative scheme id */ ++ void *scheme_id; /**< if modify=TRUE: the id of an existing scheme */ ++ } scm_id; ++ bool always_direct; /**< This scheme is reached only directly, i.e. no need ++ for match vector; KeyGen will ignore it when matching */ ++ struct { /**< HL relevant only if always_direct=FALSE */ ++ void *net_env_id; /**< The id of the Network Environment as returned ++ by FM_PCD_NetEnvCharacteristicsSet() */ ++ uint8_t num_of_distinction_units; ++ /**< Number of NetEnv units listed in unit_ids array */ ++ uint8_t unit_ids[IOC_FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; ++ /**< Indexes as passed to SetNetEnvCharacteristics (?) array */ ++ } net_env_params; ++ bool use_hash; /**< use the KG Hash functionality */ ++ ioc_fm_pcd_kg_key_extract_and_hash_params_t key_extract_and_hash_params; ++ /**< used only if useHash = TRUE */ ++ bool bypass_fqid_generation; ++ /**< Normally - FALSE, TRUE to avoid FQID update in the IC; ++ In such a case FQID after KG will be the default FQID ++ defined for the relevant port, or the FQID defined by CC ++ in cases where CC was the previous engine. */ ++ uint32_t base_fqid; /**< Base FQID; Relevant only if bypass_fqid_generation = FALSE; ++ If hash is used and an even distribution is expected ++ according to hash_distribution_num_of_fqids, base_fqid must be aligned to ++ hash_distribution_num_of_fqids. */ ++ uint8_t num_of_used_extracted_ors; ++ /**< Number of FQID masks listed in extracted_ors array*/ ++ ioc_fm_pcd_kg_extracted_or_params_t extracted_ors[IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS]; ++ /**< IOC_FM_PCD_KG_NUM_OF_GENERIC_REGS ++ registers are shared between qid_masks ++ functionality and some of the extraction ++ actions; Normally only some will be used ++ for qid_mask. Driver will return error if ++ resource is full at initialization time. */ ++#if DPAA_VERSION >= 11 ++ bool override_storage_profile; ++ /**< TRUE if KeyGen override previously decided storage profile */ ++ ioc_fm_pcd_kg_storage_profile_t storage_profile;/**< Used when override_storage_profile=TRUE */ ++#endif /* DPAA_VERSION >= 11 */ ++ ioc_fm_pcd_engine next_engine; /**< may be BMI, PLCR or CC */ ++ union { /**< depends on nextEngine */ ++ ioc_fm_pcd_done_action done_action; /**< Used when next engine is BMI (done) */ ++ ioc_fm_pcd_kg_plcr_profile_t plcr_profile; /**< Used when next engine is PLCR */ ++ ioc_fm_pcd_kg_cc_t cc; /**< Used when next engine is CC */ ++ } kg_next_engine_params; ++ ioc_fm_pcd_kg_scheme_counter_t scheme_counter; /**< A structure of parameters for updating ++ the scheme counter */ ++ void *id; /**< Returns the scheme Id to be used */ ++} ioc_fm_pcd_kg_scheme_params_t; ++ ++/**************************************************************************//** ++ @Collection ++*//***************************************************************************/ ++#if DPAA_VERSION >= 11 ++#define IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR 10 /* Maximal supported number of frame length ranges */ ++#define IOC_FM_PCD_CC_STATS_FLR_SIZE 2 /* Size in bytes of a frame length range limit */ ++#endif /* DPAA_VERSION >= 11 */ ++#define IOC_FM_PCD_CC_STATS_FLR_COUNT_SIZE 4 /* Size in bytes of a frame length range counter */ ++/* @} */ ++ ++/**************************************************************************//** ++ @Description Parameters for defining CC as the next engine after a CC node. ++ (Must match struct t_FmPcdCcNextCcParams defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_cc_next_cc_params_t { ++ void *cc_node_id; /**< Id of the next CC node */ ++} ioc_fm_pcd_cc_next_cc_params_t; ++ ++#if DPAA_VERSION >= 11 ++/**************************************************************************//** ++ @Description A structure for defining Frame Replicator as the next engine after a CC node. ++ (Must match struct t_FmPcdCcNextFrParams defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_cc_next_fr_params_t { ++ void* frm_replic_id; /**< The id of the next frame replicator group */ ++} ioc_fm_pcd_cc_next_fr_params_t; ++#endif /* DPAA_VERSION >= 11 */ ++ ++/**************************************************************************//** ++ @Description A structure for defining PLCR params when PLCR is the ++ next engine after a CC node ++ (Must match struct t_FmPcdCcNextPlcrParams defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_cc_next_plcr_params_t { ++ bool override_params; /**< TRUE if CC override previously decided parameters*/ ++ bool shared_profile; /**< Relevant only if overrideParams=TRUE: ++ TRUE if this profile is shared between ports */ ++ uint16_t new_relative_profile_id; /**< Relevant only if overrideParams=TRUE: ++ (otherwise profile id is taken from keygen); ++ This parameter should indicate the policer ++ profile offset within the port's ++ policer profiles or from SHARED window.*/ ++ uint32_t new_fqid; /**< Relevant only if overrideParams=TRUE: ++ FQID for enquing the frame; ++ In earlier chips if policer next engine is KEYGEN, ++ this parameter can be 0, because the KEYGEN always decides ++ the enqueue FQID.*/ ++#if DPAA_VERSION >= 11 ++ uint8_t new_relative_storage_profile_id; ++ /**< Indicates the relative storage profile offset within ++ the port's storage profiles window; ++ Relevant only if the port was configured with VSP. */ ++#endif /* DPAA_VERSION >= 11 */ ++} ioc_fm_pcd_cc_next_plcr_params_t; ++ ++/**************************************************************************//** ++ @Description A structure for defining enqueue params when BMI is the ++ next engine after a CC node ++ (Must match struct t_FmPcdCcNextEnqueueParams defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_cc_next_enqueue_params_t { ++ ioc_fm_pcd_done_action action; /**< Action - when next engine is BMI (done) */ ++ bool override_fqid; /**< TRUE if CC override previously decided fqid and vspid, ++ relevant if action = e_IOC_FM_PCD_ENQ_FRAME */ ++ uint32_t new_fqid; /**< Valid if overrideFqid=TRUE, FQID for enqueuing the frame ++ (otherwise FQID is taken from KeyGen), ++ relevant if action = e_IOC_FM_PCD_ENQ_FRAME*/ ++#if DPAA_VERSION >= 11 ++ uint8_t new_relative_storage_profile_id; ++ /**< Valid if override_fqid=TRUE, Indicates the relative virtual ++ storage profile offset within the port's storage profiles ++ window; Relevant only if the port was configured with VSP. */ ++#endif /* DPAA_VERSION >= 11 */ ++ ++} ioc_fm_pcd_cc_next_enqueue_params_t; ++ ++/**************************************************************************//** ++ @Description A structure for defining KG params when KG is the next engine after a CC node ++ (Must match struct t_FmPcdCcNextKgParams defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_cc_next_kg_params_t { ++ bool override_fqid; /**< TRUE if CC override previously decided fqid and vspid, ++ Note - this parameters are irrelevant for earlier chips */ ++ uint32_t new_fqid; /**< Valid if overrideFqid=TRUE, FQID for enqueuing the frame ++ (otherwise FQID is taken from KeyGen), ++ Note - this parameters are irrelevant for earlier chips */ ++#if DPAA_VERSION >= 11 ++ uint8_t new_relative_storage_profile_id; ++ /**< Valid if override_fqid=TRUE, Indicates the relative virtual ++ storage profile offset within the port's storage profiles ++ window; Relevant only if the port was configured with VSP. */ ++#endif /* DPAA_VERSION >= 11 */ ++ void *p_direct_scheme; /**< Direct scheme id to go to. */ ++} ioc_fm_pcd_cc_next_kg_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining the next engine after a CC node. ++ (Must match struct t_FmPcdCcNextEngineParams defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_cc_next_engine_params_t { ++ ioc_fm_pcd_engine next_engine; /**< User has to initialize parameters ++ according to nextEngine definition */ ++ union { ++ ioc_fm_pcd_cc_next_cc_params_t cc_params; /**< Parameters in case next engine is CC */ ++ ioc_fm_pcd_cc_next_plcr_params_t plcr_params; /**< Parameters in case next engine is PLCR */ ++ ioc_fm_pcd_cc_next_enqueue_params_t enqueue_params; /**< Parameters in case next engine is BMI */ ++ ioc_fm_pcd_cc_next_kg_params_t kg_params; /**< Parameters in case next engine is KG */ ++#if DPAA_VERSION >= 11 ++ ioc_fm_pcd_cc_next_fr_params_t fr_params; /**< Parameters in case next engine is FR */ ++#endif /* DPAA_VERSION >= 11 */ ++ } params; /**< Union used for all the next-engine parameters options */ ++ void *manip_id; /**< Handle to Manipulation object. ++ Relevant if next engine is of type result ++ (e_IOC_FM_PCD_PLCR, e_IOC_FM_PCD_KG, e_IOC_FM_PCD_DONE) */ ++ bool statistics_en; /**< If TRUE, statistics counters are incremented ++ for each frame passing through this ++ Coarse Classification entry. */ ++} ioc_fm_pcd_cc_next_engine_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining a single CC key ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_cc_key_params_t { ++ uint8_t *p_key; /**< pointer to the key of the size defined in key_size */ ++ uint8_t *p_mask; /**< pointer to the Mask per key of the size defined ++ in keySize. p_key and p_mask (if defined) has to be ++ of the same size defined in the key_size */ ++ ioc_fm_pcd_cc_next_engine_params_t cc_next_engine_params; ++ /**< parameters for the next for the defined Key in p_key */ ++ ++} ioc_fm_pcd_cc_key_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining CC keys parameters ++ The driver supports two methods for CC node allocation: dynamic and static. ++ Static mode was created in order to prevent runtime alloc/free ++ of FMan memory (MURAM), which may cause fragmentation; in this mode, ++ the driver automatically allocates the memory according to ++ 'max_num_of_keys' parameter. The driver calculates the maximal memory ++ size that may be used for this CC-Node taking into consideration ++ 'mask_support' and 'statistics_mode' parameters. ++ When 'action' = e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP in the extraction ++ parameters of this node, 'max_num_of_keys' must be equal to 'num_of_keys'. ++ In dynamic mode, 'max_num_of_keys' must be zero. At initialization, ++ all required structures are allocated according to 'num_of_keys' ++ parameter. During runtime modification, these structures are ++ re-allocated according to the updated number of keys. ++ ++ Please note that 'action' and 'ic_indx_mask' mentioned in the ++ specific parameter explanations are passed in the extraction ++ parameters of the node (fields of extractccparams.extractnonhdr). ++*//***************************************************************************/ ++typedef struct ioc_keys_params_t { ++ uint16_t max_num_of_keys;/**< Maximum number of keys that will (ever) be used in this CC-Node; ++ A value of zero may be used for dynamic memory allocation. */ ++ bool mask_support; /**< This parameter is relevant only if a node is initialized with ++ action = e_IOC_FM_PCD_ACTION_EXACT_MATCH and max_num_of_keys > 0; ++ Should be TRUE to reserve table memory for key masks, even if ++ initial keys do not contain masks, or if the node was initialized ++ as 'empty' (without keys); this will allow user to add keys with ++ masks at runtime. */ ++ ioc_fm_pcd_cc_stats_mode statistics_mode;/**< Determines the supported statistics mode for all node's keys. ++ To enable statistics gathering, statistics should be enabled per ++ every key, using 'statistics_en' in next engine parameters structure ++ of that key; ++ If 'max_num_of_keys' is set, all required structures will be ++ preallocated for all keys. */ ++#if (DPAA_VERSION >= 11) ++ uint16_t frame_length_ranges[IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR]; ++ /**< Relevant only for 'RMON' statistics mode ++ (this feature is supported only on B4860 device); ++ Holds a list of programmable thresholds. For each received frame, ++ its length in bytes is examined against these range thresholds and ++ the appropriate counter is incremented by 1. For example, to belong ++ to range i, the following should hold: ++ range i-1 threshold < frame length <= range i threshold ++ Each range threshold must be larger then its preceding range ++ threshold. Last range threshold must be 0xFFFF. */ ++#endif /* (DPAA_VERSION >= 11) */ ++ uint16_t num_of_keys; /**< Number of initial keys; ++ Note that in case of 'action' = e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP, ++ this field should be power-of-2 of the number of bits that are ++ set in 'ic_indx_mask'. */ ++ uint8_t key_size; /**< Size of key - for extraction of type FULL_FIELD, 'key_size' has ++ to be the standard size of the selected key; For other extraction ++ types, 'key_size' has to be as size of extraction; When 'action' = ++ e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP, 'keySize' must be 2. */ ++ ioc_fm_pcd_cc_key_params_t key_params[IOC_FM_PCD_MAX_NUM_OF_KEYS]; ++ /**< An array with 'num_of_keys' entries, each entry specifies the ++ corresponding key parameters; ++ When 'action' = e_IOC_FM_PCD_ACTION_EXACT_MATCH, this value must not ++ exceed 255 (IOC_FM_PCD_MAX_NUM_OF_KEYS-1) as the last entry is saved ++ for the 'miss' entry. */ ++ ioc_fm_pcd_cc_next_engine_params_t cc_next_engine_params_for_miss; ++ /**< Parameters for defining the next engine when a key is not matched; ++ Not relevant if action = e_IOC_FM_PCD_ACTION_INDEXED_LOOKUP. */ ++} ioc_keys_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining a CC node ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_cc_node_params_t { ++ ioc_fm_pcd_extract_entry_t extract_cc_params; /**< Extraction parameters */ ++ ioc_keys_params_t keys_params; /**< Keys definition matching the selected extraction */ ++ void *id; /**< Output parameter; returns the CC node Id to be used */ ++} ioc_fm_pcd_cc_node_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining a hash table ++ (Must match struct t_FmPcdHashTableParams defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_hash_table_params_t { ++ uint16_t max_num_of_keys; /**< Maximum Number Of Keys that will (ever) be used in this Hash-table */ ++ ioc_fm_pcd_cc_stats_mode statistics_mode; /**< If not e_IOC_FM_PCD_CC_STATS_MODE_NONE, the required structures for the ++ requested statistics mode will be allocated according to max_num_of_keys. */ ++ uint8_t kg_hash_shift; /**< KG-Hash-shift as it was configured in the KG-scheme ++ that leads to this hash-table. */ ++ uint16_t hash_res_mask; /**< Mask that will be used on the hash-result; ++ The number-of-sets for this hash will be calculated ++ as (2^(number of bits set in 'hash_res_mask')); ++ The 4 lower bits must be cleared. */ ++ uint8_t hash_shift; /**< Byte offset from the beginning of the KeyGen hash result to the ++ 2-bytes to be used as hash index. */ ++ uint8_t match_key_size; /**< Size of the exact match keys held by the hash buckets */ ++ ++ ioc_fm_pcd_cc_next_engine_params_t cc_next_engine_params_for_miss; ++ /**< Parameters for defining the next engine when a key is not matched */ ++ void *id; ++} ioc_fm_pcd_hash_table_params_t; ++ ++/**************************************************************************//** ++ @Description A structure with the arguments for the FM_PCD_HashTableAddKey ioctl() call ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_hash_table_add_key_params_t { ++ void *p_hash_tbl; ++ uint8_t key_size; ++ ioc_fm_pcd_cc_key_params_t key_params; ++} ioc_fm_pcd_hash_table_add_key_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining a CC tree group. ++ ++ This structure defines a CC group in terms of NetEnv units ++ and the action to be taken in each case. The unit_ids list must ++ be given in order from low to high indices. ++ ++ ioc_fm_pcd_cc_next_engine_params_t is a list of 2^num_of_distinction_units ++ structures where each defines the next action to be taken for ++ each units combination. for example: ++ num_of_distinction_units = 2 ++ unit_ids = {1,3} ++ next_engine_per_entries_in_grp[0] = ioc_fm_pcd_cc_next_engine_params_t for the case that ++ unit 1 - not found; unit 3 - not found; ++ next_engine_per_entries_in_grp[1] = ioc_fm_pcd_cc_next_engine_params_t for the case that ++ unit 1 - not found; unit 3 - found; ++ next_engine_per_entries_in_grp[2] = ioc_fm_pcd_cc_next_engine_params_t for the case that ++ unit 1 - found; unit 3 - not found; ++ next_engine_per_entries_in_grp[3] = ioc_fm_pcd_cc_next_engine_params_t for the case that ++ unit 1 - found; unit 3 - found; ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_cc_grp_params_t { ++ uint8_t num_of_distinction_units; /**< Up to 4 */ ++ uint8_t unit_ids [IOC_FM_PCD_MAX_NUM_OF_CC_UNITS]; ++ /**< Indexes of the units as defined in ++ FM_PCD_NetEnvCharacteristicsSet() */ ++ ioc_fm_pcd_cc_next_engine_params_t next_engine_per_entries_in_grp[IOC_FM_PCD_MAX_NUM_OF_CC_ENTRIES_IN_GRP]; ++ /**< Maximum entries per group is 16 */ ++} ioc_fm_pcd_cc_grp_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining the CC tree groups ++ (Must match struct t_FmPcdCcTreeParams defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_cc_tree_params_t { ++ void *net_env_id; /**< Id of the Network Environment as returned ++ by FM_PCD_NetEnvCharacteristicsSet() */ ++ uint8_t num_of_groups; /**< Number of CC groups within the CC tree */ ++ ioc_fm_pcd_cc_grp_params_t fm_pcd_cc_group_params [IOC_FM_PCD_MAX_NUM_OF_CC_GROUPS]; ++ /**< Parameters for each group. */ ++ void *id; /**< Output parameter; Returns the tree Id to be used */ ++} ioc_fm_pcd_cc_tree_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining policer byte rate ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_plcr_byte_rate_mode_param_t { ++ ioc_fm_pcd_plcr_frame_length_select frame_length_selection; /**< Frame length selection */ ++ ioc_fm_pcd_plcr_roll_back_frame_select roll_back_frame_selection; /**< relevant option only e_IOC_FM_PCD_PLCR_L2_FRM_LEN, ++ e_IOC_FM_PCD_PLCR_FULL_FRM_LEN */ ++} ioc_fm_pcd_plcr_byte_rate_mode_param_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining the policer profile (based on ++ RFC-2698 or RFC-4115 attributes). ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_plcr_non_passthrough_alg_param_t { ++ ioc_fm_pcd_plcr_rate_mode rate_mode; /**< Byte / Packet */ ++ ioc_fm_pcd_plcr_byte_rate_mode_param_t byte_mode_param; /**< Valid for Byte NULL for Packet */ ++ uint32_t committed_info_rate; /**< KBits/Sec or Packets/Sec */ ++ uint32_t committed_burst_size; /**< KBits or Packets */ ++ uint32_t peak_or_excess_info_rate; /**< KBits/Sec or Packets/Sec */ ++ uint32_t peak_or_excess_burst_size; /**< KBits or Packets */ ++} ioc_fm_pcd_plcr_non_passthrough_alg_param_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining the next engine after policer ++*//***************************************************************************/ ++typedef union ioc_fm_pcd_plcr_next_engine_params_u { ++ ioc_fm_pcd_done_action action; /**< Action - when next engine is BMI (done) */ ++ void *p_profile; /**< Policer profile handle - used when next engine ++ is PLCR, must be a SHARED profile */ ++ void *p_direct_scheme; /**< Direct scheme select - when next engine is Keygen */ ++} ioc_fm_pcd_plcr_next_engine_params_u; ++ ++typedef struct ioc_fm_pcd_port_params_t { ++ ioc_fm_port_type port_type; /**< Type of port for this profile */ ++ uint8_t port_id; /**< FM-Port id of port for this profile */ ++} ioc_fm_pcd_port_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining the policer profile entry ++ (Must match struct t_FmPcdPlcrProfileParams defined in fm_pcd_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_plcr_profile_params_t { ++ bool modify; /**< TRUE to change an existing profile */ ++ union { ++ struct { ++ ioc_fm_pcd_profile_type_selection profile_type; /**< Type of policer profile */ ++ ioc_fm_pcd_port_params_t *p_fm_port; /**< Relevant for per-port profiles only */ ++ uint16_t relative_profile_id; /**< Profile id - relative to shared group or to port */ ++ } new_params; /**< Use it when modify = FALSE */ ++ void *p_profile; /**< A handle to a profile - use it when modify=TRUE */ ++ } profile_select; ++ ioc_fm_pcd_plcr_algorithm_selection alg_selection; /**< Profile Algorithm PASS_THROUGH, RFC_2698, RFC_4115 */ ++ ioc_fm_pcd_plcr_color_mode color_mode; /**< COLOR_BLIND, COLOR_AWARE */ ++ ++ union { ++ ioc_fm_pcd_plcr_color dflt_color; /**< For Color-Blind Pass-Through mode; the policer will re-color ++ any incoming packet with the default value. */ ++ ioc_fm_pcd_plcr_color override; /**< For Color-Aware modes; the profile response to a ++ pre-color value of 2'b11. */ ++ } color; ++ ++ ioc_fm_pcd_plcr_non_passthrough_alg_param_t non_passthrough_alg_param; /**< RFC2698 or RFC4115 parameters */ ++ ++ ioc_fm_pcd_engine next_engine_on_green; /**< Next engine for green-colored frames */ ++ ioc_fm_pcd_plcr_next_engine_params_u params_on_green; /**< Next engine parameters for green-colored frames */ ++ ++ ioc_fm_pcd_engine next_engine_on_yellow; /**< Next engine for yellow-colored frames */ ++ ioc_fm_pcd_plcr_next_engine_params_u params_on_yellow; /**< Next engine parameters for yellow-colored frames */ ++ ++ ioc_fm_pcd_engine next_engine_on_red; /**< Next engine for red-colored frames */ ++ ioc_fm_pcd_plcr_next_engine_params_u params_on_red; /**< Next engine parameters for red-colored frames */ ++ ++ bool trap_profile_on_flow_A; /**< Obsolete - do not use */ ++ bool trap_profile_on_flow_B; /**< Obsolete - do not use */ ++ bool trap_profile_on_flow_C; /**< Obsolete - do not use */ ++ ++ void *id; /**< output parameter; Returns the profile Id to be used */ ++} ioc_fm_pcd_plcr_profile_params_t; ++ ++/**************************************************************************//** ++ @Description A structure for modifying CC tree next engine ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_cc_tree_modify_next_engine_params_t { ++ void *id; /**< CC tree Id to be used */ ++ uint8_t grp_indx; /**< A Group index in the tree */ ++ uint8_t indx; /**< Entry index in the group defined by grp_index */ ++ ioc_fm_pcd_cc_next_engine_params_t cc_next_engine_params; ++ /**< Parameters for the next for the defined Key in the p_Key */ ++} ioc_fm_pcd_cc_tree_modify_next_engine_params_t; ++ ++/**************************************************************************//** ++ @Description A structure for modifying CC node next engine ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_cc_node_modify_next_engine_params_t { ++ void *id; /**< CC node Id to be used */ ++ uint16_t key_indx; /**< Key index for Next Engine Params modifications; ++ NOTE: This parameter is IGNORED for miss-key! */ ++ uint8_t key_size; /**< Key size of added key */ ++ ioc_fm_pcd_cc_next_engine_params_t cc_next_engine_params; ++ /**< parameters for the next for the defined Key in the p_Key */ ++} ioc_fm_pcd_cc_node_modify_next_engine_params_t; ++ ++/**************************************************************************//** ++ @Description A structure for remove CC node key ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_cc_node_remove_key_params_t { ++ void *id; /**< CC node Id to be used */ ++ uint16_t key_indx; /**< Key index for Next Engine Params modifications; ++ NOTE: This parameter is IGNORED for miss-key! */ ++} ioc_fm_pcd_cc_node_remove_key_params_t; ++ ++/**************************************************************************//** ++ @Description A structure for modifying CC node key and next engine ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t { ++ void *id; /**< CC node Id to be used */ ++ uint16_t key_indx; /**< Key index for Next Engine Params modifications; ++ NOTE: This parameter is IGNORED for miss-key! */ ++ uint8_t key_size; /**< Key size of added key */ ++ ioc_fm_pcd_cc_key_params_t key_params; /**< it's array with numOfKeys entries each entry in ++ the array of the type ioc_fm_pcd_cc_key_params_t */ ++} ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t; ++ ++/**************************************************************************//** ++ @Description A structure for modifying CC node key ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_cc_node_modify_key_params_t { ++ void *id; /**< CC node Id to be used */ ++ uint16_t key_indx; /**< Key index for Next Engine Params modifications; ++ NOTE: This parameter is IGNORED for miss-key! */ ++ uint8_t key_size; /**< Key size of added key */ ++ uint8_t *p_key; /**< Pointer to the key of the size defined in key_size */ ++ uint8_t *p_mask; /**< Pointer to the Mask per key of the size defined ++ in keySize. p_Key and p_Mask (if defined) have to be ++ of the same size as defined in the key_size */ ++} ioc_fm_pcd_cc_node_modify_key_params_t; ++ ++/**************************************************************************//** ++ @Description A structure with the arguments for the FM_PCD_HashTableRemoveKey ioctl() call ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_hash_table_remove_key_params_t { ++ void *p_hash_tbl; /**< The id of the hash table */ ++ uint8_t key_size; /**< The size of the key to remove */ ++ uint8_t *p_key; /**< Pointer to the key to remove */ ++} ioc_fm_pcd_hash_table_remove_key_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for selecting a location for requested manipulation ++*//***************************************************************************/ ++typedef struct ioc_fm_manip_hdr_info_t { ++ ioc_net_header_type hdr; /**< Header selection */ ++ ioc_fm_pcd_hdr_index hdr_index; /**< Relevant only for MPLS, VLAN and tunneled IP. Otherwise should be cleared. */ ++ bool by_field; /**< TRUE if the location of manipulation is according to some field in the specific header*/ ++ ioc_fm_pcd_fields_u full_field; /**< Relevant only when by_field = TRUE: Extract field */ ++} ioc_fm_manip_hdr_info_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header removal by header type ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_rmv_by_hdr_params_t { ++ ioc_fm_pcd_manip_hdr_rmv_by_hdr_type type; /**< Selection of header removal location */ ++ union { ++#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) ++ struct { ++ bool include;/**< If FALSE, remove until the specified header (not including the header); ++ If TRUE, remove also the specified header. */ ++ ioc_fm_manip_hdr_info_t hdr_info; ++ } from_start_by_hdr; /**< Relevant when type = e_IOC_FM_PCD_MANIP_RMV_BY_HDR_FROM_START */ ++#endif /* FM_CAPWAP_SUPPORT */ ++#if (DPAA_VERSION >= 11) ++ ioc_fm_manip_hdr_info_t hdr_info; /**< Relevant when type = e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START */ ++#endif /* (DPAA_VERSION >= 11) */ ++ ioc_fm_pcd_manip_hdr_rmv_specific_l2 specific_l2;/**< Relevant when type = e_IOC_FM_PCD_MANIP_BY_HDR_SPECIFIC_L2; ++ Defines which L2 headers to remove. */ ++ } u; ++} ioc_fm_pcd_manip_hdr_rmv_by_hdr_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for configuring IP fragmentation manipulation ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_frag_ip_params_t { ++ uint16_t size_for_fragmentation; /**< If length of the frame is greater than this value, ++ IP fragmentation will be executed.*/ ++#if DPAA_VERSION == 10 ++ uint8_t scratch_bpid; /**< Absolute buffer pool id according to BM configuration.*/ ++#endif /* DPAA_VERSION == 10 */ ++ bool sg_bpid_en; /**< Enable a dedicated buffer pool id for the Scatter/Gather buffer allocation; ++ If disabled, the Scatter/Gather buffer will be allocated from the same pool as the ++ received frame's buffer. */ ++ uint8_t sg_bpid; /**< Scatter/Gather buffer pool id; ++ This parameter is relevant when 'sg_bpid_en=TRUE'; ++ Same LIODN number is used for these buffers as for the received frames buffers, so buffers ++ of this pool need to be allocated in the same memory area as the received buffers. ++ If the received buffers arrive from different sources, the Scatter/Gather BP id should be ++ mutual to all these sources. */ ++ ioc_fm_pcd_manip_dont_frag_action dont_frag_action; /**< Dont Fragment Action - If an IP packet is larger ++ than MTU and its DF bit is set, then this field will ++ determine the action to be taken.*/ ++} ioc_fm_pcd_manip_frag_ip_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for configuring IP reassembly manipulation. ++ ++ This is a common structure for both IPv4 and IPv6 reassembly ++ manipulation. For reassembly of both IPv4 and IPv6, make sure to ++ set the 'hdr' field in ioc_fm_pcd_manip_reassem_params_t to IOC_HEADER_TYPE_IPv6. ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_reassem_ip_params_t { ++ uint8_t relative_scheme_id[2]; /**< Partition relative scheme id: ++ relativeSchemeId[0] - Relative scheme ID for IPV4 Reassembly manipulation; ++ relativeSchemeId[1] - Relative scheme ID for IPV6 Reassembly manipulation; ++ NOTE: The following comment is relevant only for FMAN v2 devices: ++ Relative scheme ID for IPv4/IPv6 Reassembly manipulation must be smaller than ++ the user schemes id to ensure that the reassembly's schemes will be first match. ++ The remaining schemes, if defined, should have higher relative scheme ID. */ ++#if DPAA_VERSION >= 11 ++ uint32_t non_consistent_sp_fqid; /**< In case that other fragments of the frame corresponds to different storage ++ profile than the opening fragment (Non-Consistent-SP state) ++ then one of two possible scenarios occurs: ++ if 'nonConsistentSpFqid != 0', the reassembled frame will be enqueued to ++ this fqid, otherwise a 'Non Consistent SP' bit will be set in the FD[status].*/ ++#else ++ uint8_t sg_bpid; /**< Buffer pool id for the S/G frame created by the reassembly process */ ++#endif /* DPAA_VERSION >= 11 */ ++ uint8_t data_mem_id; /**< Memory partition ID for the IPR's external tables structure */ ++ uint16_t data_liodn_offset; /**< LIODN offset for access the IPR's external tables structure. */ ++ uint16_t min_frag_size[2]; /**< Minimum fragment size: ++ minFragSize[0] - for ipv4, minFragSize[1] - for ipv6 */ ++ ioc_fm_pcd_manip_reassem_ways_number num_of_frames_per_hash_entry[2]; ++ /**< Number of frames per hash entry needed for reassembly process: ++ numOfFramesPerHashEntry[0] - for ipv4 (max value is e_IOC_FM_PCD_MANIP_EIGHT_WAYS_HASH); ++ numOfFramesPerHashEntry[1] - for ipv6 (max value is e_IOC_FM_PCD_MANIP_SIX_WAYS_HASH). */ ++ uint16_t max_num_frames_in_process;/**< Number of frames which can be processed by Reassembly in the same time; ++ Must be power of 2; ++ In the case numOfFramesPerHashEntry == e_IOC_FM_PCD_MANIP_FOUR_WAYS_HASH, ++ maxNumFramesInProcess has to be in the range of 4 - 512; ++ In the case numOfFramesPerHashEntry == e_IOC_FM_PCD_MANIP_EIGHT_WAYS_HASH, ++ maxNumFramesInProcess has to be in the range of 8 - 2048. */ ++ ioc_fm_pcd_manip_reassem_time_out_mode time_out_mode; /**< Expiration delay initialized by Reassembly process */ ++ uint32_t fqid_for_time_out_frames;/**< FQID in which time out frames will enqueue during Time Out Process */ ++ uint32_t timeout_threshold_for_reassm_process; ++ /**< Represents the time interval in microseconds which defines ++ if opened frame (at least one fragment was processed but not all the fragments)is found as too old*/ ++} ioc_fm_pcd_manip_reassem_ip_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining IPSEC manipulation ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_special_offload_ipsec_params_t { ++ bool decryption; /**< TRUE if being used in decryption direction; ++ FALSE if being used in encryption direction. */ ++ bool ecn_copy; /**< TRUE to copy the ECN bits from inner/outer to outer/inner ++ (direction depends on the 'decryption' field). */ ++ bool dscp_copy; /**< TRUE to copy the DSCP bits from inner/outer to outer/inner ++ (direction depends on the 'decryption' field). */ ++ bool variable_ip_hdr_len; /**< TRUE for supporting variable IP header length in decryption. */ ++ bool variable_ip_version; /**< TRUE for supporting both IP version on the same SA in encryption */ ++ uint8_t outer_ip_hdr_len; /**< If 'variable_ip_version == TRUE' than this field must be set to non-zero value; ++ It is specifies the length of the outer IP header that was configured in the ++ corresponding SA. */ ++ uint16_t arw_size; /**< if <> '0' then will perform ARW check for this SA; ++ The value must be a multiplication of 16 */ ++ void *arw_addr; /**< if arwSize <> '0' then this field must be set to non-zero value; ++ MUST be allocated from FMAN's MURAM that the post-sec op-port belong ++ Must be 4B aligned. Required MURAM size is '(NEXT_POWER_OF_2(arwSize+32))/8+4' Bytes */ ++} ioc_fm_pcd_manip_special_offload_ipsec_params_t; ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Description Parameters for configuring CAPWAP fragmentation manipulation ++ ++ Restrictions: ++ - Maximum number of fragments per frame is 16. ++ - Transmit confirmation is not supported. ++ - Fragmentation nodes must be set as the last PCD action (i.e. the ++ corresponding CC node key must have next engine set to e_FM_PCD_DONE). ++ - Only BMan buffers shall be used for frames to be fragmented. ++ - NOTE: The following comment is relevant only for FMAN v3 devices: IPF ++ does not support VSP. Therefore, on the same port where we have IPF we ++ cannot support VSP. ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_frag_capwap_params_t { ++ uint16_t size_for_fragmentation; /**< If length of the frame is greater than this value, ++ CAPWAP fragmentation will be executed.*/ ++ bool sg_bpid_en; /**< Enable a dedicated buffer pool id for the Scatter/Gather buffer allocation; ++ If disabled, the Scatter/Gather buffer will be allocated from the same pool as the ++ received frame's buffer. */ ++ uint8_t sg_bpid; /**< Scatter/Gather buffer pool id; ++ This parameters is relevant when 'sgBpidEn=TRUE'; ++ Same LIODN number is used for these buffers as for the received frames buffers, so buffers ++ of this pool need to be allocated in the same memory area as the received buffers. ++ If the received buffers arrive from different sources, the Scatter/Gather BP id should be ++ mutual to all these sources. */ ++ bool compress_mode_en; /**< CAPWAP Header Options Compress Enable mode; ++ When this mode is enabled then only the first fragment include the CAPWAP header options ++ field (if user provides it in the input frame) and all other fragments exclude the CAPWAP ++ options field (CAPWAP header is updated accordingly).*/ ++} ioc_fm_pcd_manip_frag_capwap_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for configuring CAPWAP reassembly manipulation. ++ ++ Restrictions: ++ - Application must define one scheme to catch the reassembled frames. ++ - Maximum number of fragments per frame is 16. ++ ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_reassem_capwap_params_t { ++ uint8_t relative_scheme_id; /**< Partition relative scheme id; ++ NOTE: this id must be smaller than the user schemes id to ensure that the reassembly scheme will be first match; ++ Rest schemes, if defined, should have higher relative scheme ID. */ ++ uint8_t data_mem_id; /**< Memory partition ID for the IPR's external tables structure */ ++ uint16_t data_liodn_offset; /**< LIODN offset for access the IPR's external tables structure. */ ++ uint16_t max_reassembled_frame_length;/**< The maximum CAPWAP reassembled frame length in bytes; ++ If maxReassembledFrameLength == 0, any successful reassembled frame length is ++ considered as a valid length; ++ if maxReassembledFrameLength > 0, a successful reassembled frame which its length ++ exceeds this value is considered as an error frame (FD status[CRE] bit is set). */ ++ ioc_fm_pcd_manip_reassem_ways_number num_of_frames_per_hash_entry; ++ /**< Number of frames per hash entry needed for reassembly process */ ++ uint16_t max_num_frames_in_process; /**< Number of frames which can be processed by reassembly in the same time; ++ Must be power of 2; ++ In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_FOUR_WAYS_HASH, ++ maxNumFramesInProcess has to be in the range of 4 - 512; ++ In the case numOfFramesPerHashEntry == e_FM_PCD_MANIP_EIGHT_WAYS_HASH, ++ maxNumFramesInProcess has to be in the range of 8 - 2048. */ ++ ioc_fm_pcd_manip_reassem_time_out_mode time_out_mode; /**< Expiration delay initialized by Reassembly process */ ++ uint32_t fqid_for_time_out_frames; /**< FQID in which time out frames will enqueue during Time Out Process; ++ Recommended value for this field is 0; in this way timed-out frames will be discarded */ ++ uint32_t timeout_threshold_for_reassm_process; ++ /**< Represents the time interval in microseconds which defines ++ if opened frame (at least one fragment was processed but not all the fragments)is found as too old*/ ++} ioc_fm_pcd_manip_reassem_capwap_params_t; ++ ++/**************************************************************************//** ++ @Description structure for defining CAPWAP manipulation ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_special_offload_capwap_params_t { ++ bool dtls; /**< TRUE if continue to SEC DTLS encryption */ ++ ioc_fm_pcd_manip_hdr_qos_src qos_src; /**< TODO */ ++} ioc_fm_pcd_manip_special_offload_capwap_params_t; ++ ++#endif /* (DPAA_VERSION >= 11) */ ++ ++/**************************************************************************//** ++ @Description Parameters for defining special offload manipulation ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_special_offload_params_t { ++ ioc_fm_pcd_manip_special_offload_type type; /**< Type of special offload manipulation */ ++ union ++ { ++ ioc_fm_pcd_manip_special_offload_ipsec_params_t ipsec; /**< Parameters for IPSec; Relevant when ++ type = e_IOC_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC */ ++ ++#if (DPAA_VERSION >= 11) ++ ioc_fm_pcd_manip_special_offload_capwap_params_t capwap; /**< Parameters for CAPWAP; Relevant when ++ type = e_FM_PCD_MANIP_SPECIAL_OFFLOAD_CAPWAP */ ++#endif /* (DPAA_VERSION >= 11) */ ++ } u; ++} ioc_fm_pcd_manip_special_offload_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining generic removal manipulation ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_rmv_generic_params_t { ++ uint8_t offset; /**< Offset from beginning of header to the start ++ location of the removal */ ++ uint8_t size; /**< Size of removed section */ ++} ioc_fm_pcd_manip_hdr_rmv_generic_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining insertion manipulation ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_insrt_t { ++ uint8_t size; /**< size of inserted section */ ++ uint8_t *p_data; /**< data to be inserted */ ++} ioc_fm_pcd_manip_hdr_insrt_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining generic insertion manipulation ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_insrt_generic_params_t { ++ uint8_t offset; /**< Offset from beginning of header to the start ++ location of the insertion */ ++ uint8_t size; /**< Size of inserted section */ ++ bool replace; /**< TRUE to override (replace) existing data at ++ 'offset', FALSE to insert */ ++ uint8_t *p_data; /**< Pointer to data to be inserted */ ++} ioc_fm_pcd_manip_hdr_insrt_generic_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header manipulation VLAN DSCP To Vpri translation ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_field_update_vlan_dscp_to_vpri_t { ++ uint8_t dscp_to_vpri_table[IOC_FM_PCD_MANIP_DSCP_TO_VLAN_TRANS]; ++ /**< A table of VPri values for each DSCP value; ++ The index is the D_SCP value (0-0x3F) and the ++ value is the corresponding VPRI (0-15). */ ++ uint8_t vpri_def_val; /**< 0-7, Relevant only if if update_type = ++ e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN, ++ this field is the Q Tag default value if the ++ IP header is not found. */ ++} ioc_fm_pcd_manip_hdr_field_update_vlan_dscp_to_vpri_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header manipulation VLAN fields updates ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_field_update_vlan_t { ++ ioc_fm_pcd_manip_hdr_field_update_vlan update_type; /**< Selects VLAN update type */ ++ union { ++ uint8_t vpri; /**< 0-7, Relevant only if If update_type = ++ e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_PRI, this ++ is the new VLAN pri. */ ++ ioc_fm_pcd_manip_hdr_field_update_vlan_dscp_to_vpri_t dscp_to_vpri; ++ /**< Parameters structure, Relevant only if update_type = ++ e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN. */ ++ } u; ++} ioc_fm_pcd_manip_hdr_field_update_vlan_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header manipulation IPV4 fields updates ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_field_update_ipv4_t { ++ ioc_ipv4_hdr_manip_update_flags_t valid_updates; /**< ORed flag, selecting the required updates */ ++ uint8_t tos; /**< 8 bit New TOS; Relevant if valid_updates contains ++ IOC_HDR_MANIP_IPV4_TOS */ ++ uint16_t id; /**< 16 bit New IP ID; Relevant only if valid_updates ++ contains IOC_HDR_MANIP_IPV4_ID */ ++ uint32_t src; /**< 32 bit New IP SRC; Relevant only if valid_updates ++ contains IOC_HDR_MANIP_IPV4_SRC */ ++ uint32_t dst; /**< 32 bit New IP DST; Relevant only if valid_updates ++ contains IOC_HDR_MANIP_IPV4_DST */ ++} ioc_fm_pcd_manip_hdr_field_update_ipv4_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header manipulation IPV6 fields updates ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_field_update_ipv6_t { ++ ioc_ipv6_hdr_manip_update_flags_t valid_updates; /**< ORed flag, selecting the required updates */ ++ uint8_t traffic_class; /**< 8 bit New Traffic Class; Relevant if valid_updates contains ++ IOC_HDR_MANIP_IPV6_TC */ ++ uint8_t src[IOC_NET_HEADER_FIELD_IPv6_ADDR_SIZE]; ++ /**< 16 byte new IP SRC; Relevant only if valid_updates ++ contains IOC_HDR_MANIP_IPV6_SRC */ ++ uint8_t dst[IOC_NET_HEADER_FIELD_IPv6_ADDR_SIZE]; ++ /**< 16 byte new IP DST; Relevant only if valid_updates ++ contains IOC_HDR_MANIP_IPV6_DST */ ++} ioc_fm_pcd_manip_hdr_field_update_ipv6_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header manipulation TCP/UDP fields updates ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_field_update_tcp_udp_t { ++ ioc_tcp_udp_hdr_manip_update_flags_t valid_updates; /**< ORed flag, selecting the required updates */ ++ uint16_t src; /**< 16 bit New TCP/UDP SRC; Relevant only if valid_updates ++ contains IOC_HDR_MANIP_TCP_UDP_SRC */ ++ uint16_t dst; /**< 16 bit New TCP/UDP DST; Relevant only if valid_updates ++ contains IOC_HDR_MANIP_TCP_UDP_DST */ ++} ioc_fm_pcd_manip_hdr_field_update_tcp_udp_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header manipulation fields updates ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_field_update_params_t { ++ ioc_fm_pcd_manip_hdr_field_update_type type; /**< Type of header field update manipulation */ ++ union { ++ ioc_fm_pcd_manip_hdr_field_update_vlan_t vlan; /**< Parameters for VLAN update. Relevant when ++ type = e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN */ ++ ioc_fm_pcd_manip_hdr_field_update_ipv4_t ipv4; /**< Parameters for IPv4 update. Relevant when ++ type = e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4 */ ++ ioc_fm_pcd_manip_hdr_field_update_ipv6_t ipv6; /**< Parameters for IPv6 update. Relevant when ++ type = e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6 */ ++ ioc_fm_pcd_manip_hdr_field_update_tcp_udp_t tcp_udp;/**< Parameters for TCP/UDP update. Relevant when ++ type = e_IOC_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP */ ++ } u; ++} ioc_fm_pcd_manip_hdr_field_update_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining custom header manipulation for IP replacement ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_custom_ip_hdr_replace_t { ++ ioc_fm_pcd_manip_hdr_custom_ip_replace replace_type; /**< Selects replace update type */ ++ bool dec_ttl_hl; /**< Decrement TTL (IPV4) or Hop limit (IPV6) by 1 */ ++ bool update_ipv4_id; /**< Relevant when replace_type = ++ e_IOC_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4 */ ++ uint16_t id; /**< 16 bit New IP ID; Relevant only if ++ update_ipv4_id = TRUE */ ++ uint8_t hdr_size; /**< The size of the new IP header */ ++ uint8_t hdr[IOC_FM_PCD_MANIP_MAX_HDR_SIZE]; ++ /**< The new IP header */ ++} ioc_fm_pcd_manip_hdr_custom_ip_hdr_replace_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining custom header manipulation ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_custom_params_t { ++ ioc_fm_pcd_manip_hdr_custom_type type; /**< Type of header field update manipulation */ ++ union { ++ ioc_fm_pcd_manip_hdr_custom_ip_hdr_replace_t ip_hdr_replace; ++ /**< Parameters IP header replacement */ ++ } u; ++} ioc_fm_pcd_manip_hdr_custom_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining specific L2 insertion manipulation ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_insrt_specific_l2_params_t { ++ ioc_fm_pcd_manip_hdr_insrt_specific_l2 specific_l2; /**< Selects which L2 headers to insert */ ++ bool update; /**< TRUE to update MPLS header */ ++ uint8_t size; /**< size of inserted section */ ++ uint8_t *p_data; /**< data to be inserted */ ++} ioc_fm_pcd_manip_hdr_insrt_specific_l2_params_t; ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Description Parameters for defining IP insertion manipulation ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_insrt_ip_params_t { ++ bool calc_l4_checksum; /**< Calculate L4 checksum. */ ++ ioc_fm_pcd_manip_hdr_qos_mapping_mode mapping_mode; /**< TODO */ ++ uint8_t last_pid_offset; /**< the offset of the last Protocol within ++ the inserted header */ ++ uint16_t id; /**< 16 bit New IP ID */ ++ bool dont_frag_overwrite; ++ /**< IPv4 only. DF is overwritten with the hash-result next-to-last byte. ++ * This byte is configured to be overwritten when RPD is set. */ ++ uint8_t last_dst_offset; ++ /**< IPv6 only. if routing extension exist, user should set the offset of the destination address ++ * in order to calculate UDP checksum pseudo header; ++ * Otherwise set it to '0'. */ ++ ioc_fm_pcd_manip_hdr_insrt_t insrt; /**< size and data to be inserted. */ ++} ioc_fm_pcd_manip_hdr_insrt_ip_params_t; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++/**************************************************************************//** ++ @Description Parameters for defining header insertion manipulation by header type ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_insrt_by_hdr_params_t { ++ ioc_fm_pcd_manip_hdr_insrt_by_hdr_type type; /**< Selects manipulation type */ ++ union { ++ ioc_fm_pcd_manip_hdr_insrt_specific_l2_params_t specific_l2_params; ++ /**< Used when type = e_IOC_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2: ++ Selects which L2 headers to remove */ ++#if (DPAA_VERSION >= 11) ++ ioc_fm_pcd_manip_hdr_insrt_ip_params_t ip_params; /**< Used when type = e_FM_PCD_MANIP_INSRT_BY_HDR_IP */ ++ ioc_fm_pcd_manip_hdr_insrt_t insrt; /**< Used when type is one of e_FM_PCD_MANIP_INSRT_BY_HDR_UDP, ++ e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE, or ++ e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP */ ++#endif /* (DPAA_VERSION >= 11) */ ++ } u; ++} ioc_fm_pcd_manip_hdr_insrt_by_hdr_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header insertion manipulation ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_insrt_params_t { ++ ioc_fm_pcd_manip_hdr_insrt_type type; /**< Type of insertion manipulation */ ++ union { ++ ioc_fm_pcd_manip_hdr_insrt_by_hdr_params_t by_hdr; /**< Parameters for defining header insertion manipulation by header type, ++ relevant if 'type' = e_IOC_FM_PCD_MANIP_INSRT_BY_HDR */ ++ ioc_fm_pcd_manip_hdr_insrt_generic_params_t generic;/**< Parameters for defining generic header insertion manipulation, ++ relevant if type = e_IOC_FM_PCD_MANIP_INSRT_GENERIC */ ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++ ioc_fm_pcd_manip_hdr_insrt_by_template_params_t by_template; ++ /**< Parameters for defining header insertion manipulation by template, ++ relevant if 'type' = e_IOC_FM_PCD_MANIP_INSRT_BY_TEMPLATE */ ++#endif /* FM_CAPWAP_SUPPORT */ ++ } u; ++} ioc_fm_pcd_manip_hdr_insrt_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header removal manipulation ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_rmv_params_t { ++ ioc_fm_pcd_manip_hdr_rmv_type type; /**< Type of header removal manipulation */ ++ union { ++ ioc_fm_pcd_manip_hdr_rmv_by_hdr_params_t by_hdr; /**< Parameters for defining header removal manipulation by header type, ++ relevant if type = e_IOC_FM_PCD_MANIP_RMV_BY_HDR */ ++ ioc_fm_pcd_manip_hdr_rmv_generic_params_t generic; /**< Parameters for defining generic header removal manipulation, ++ relevant if type = e_IOC_FM_PCD_MANIP_RMV_GENERIC */ ++ } u; ++} ioc_fm_pcd_manip_hdr_rmv_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining header manipulation node ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_hdr_params_t { ++ bool rmv; /**< TRUE, to define removal manipulation */ ++ ioc_fm_pcd_manip_hdr_rmv_params_t rmv_params; /**< Parameters for removal manipulation, relevant if 'rmv' = TRUE */ ++ ++ bool insrt; /**< TRUE, to define insertion manipulation */ ++ ioc_fm_pcd_manip_hdr_insrt_params_t insrt_params; /**< Parameters for insertion manipulation, relevant if 'insrt' = TRUE */ ++ ++ bool field_update; /**< TRUE, to define field update manipulation */ ++ ioc_fm_pcd_manip_hdr_field_update_params_t field_update_params; /**< Parameters for field update manipulation, relevant if 'fieldUpdate' = TRUE */ ++ ++ bool custom; /**< TRUE, to define custom manipulation */ ++ ioc_fm_pcd_manip_hdr_custom_params_t custom_params; /**< Parameters for custom manipulation, relevant if 'custom' = TRUE */ ++ ++ bool dont_parse_after_manip;/**< FALSE to activate the parser a second time after ++ completing the manipulation on the frame */ ++} ioc_fm_pcd_manip_hdr_params_t; ++ ++ ++/**************************************************************************//** ++ @Description structure for defining fragmentation manipulation ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_frag_params_t { ++ ioc_net_header_type hdr; /**< Header selection */ ++ union { ++#if (DPAA_VERSION >= 11) ++ ioc_fm_pcd_manip_frag_capwap_params_t capwap_frag; /**< Parameters for defining CAPWAP fragmentation, ++ relevant if 'hdr' = HEADER_TYPE_CAPWAP */ ++#endif /* (DPAA_VERSION >= 11) */ ++ ioc_fm_pcd_manip_frag_ip_params_t ip_frag; /**< Parameters for defining IP fragmentation, ++ relevant if 'hdr' = HEADER_TYPE_Ipv4 or HEADER_TYPE_Ipv6 */ ++ } u; ++} ioc_fm_pcd_manip_frag_params_t; ++ ++/**************************************************************************//** ++ @Description structure for defining reassemble manipulation ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_reassem_params_t { ++ ioc_net_header_type hdr; /**< Header selection */ ++ union { ++#if (DPAA_VERSION >= 11) ++ ioc_fm_pcd_manip_reassem_capwap_params_t capwap_reassem; /**< Parameters for defining CAPWAP reassembly, ++ relevant if 'hdr' = HEADER_TYPE_CAPWAP */ ++#endif /* (DPAA_VERSION >= 11) */ ++ ioc_fm_pcd_manip_reassem_ip_params_t ip_reassem; /**< Parameters for defining IP reassembly, ++ relevant if 'hdr' = HEADER_TYPE_Ipv4 or HEADER_TYPE_Ipv6 */ ++ } u; ++} ioc_fm_pcd_manip_reassem_params_t; ++ ++/**************************************************************************//** ++ @Description Parameters for defining a manipulation node ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_params_t { ++ ioc_fm_pcd_manip_type type; /**< Selects type of manipulation node */ ++ union { ++ ioc_fm_pcd_manip_hdr_params_t hdr; /**< Parameters for defining header manipulation node */ ++ ioc_fm_pcd_manip_reassem_params_t reassem;/**< Parameters for defining reassembly manipulation node */ ++ ioc_fm_pcd_manip_frag_params_t frag; /**< Parameters for defining fragmentation manipulation node */ ++ ioc_fm_pcd_manip_special_offload_params_t special_offload;/**< Parameters for defining special offload manipulation node */ ++ } u; ++ void *p_next_manip;/**< Handle to another (previously defined) manipulation node; ++ Allows concatenation of manipulation actions ++ This parameter is optional and may be NULL. */ ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++ bool frag_or_reasm;/**< TRUE, if defined fragmentation/reassembly manipulation */ ++ ioc_fm_pcd_manip_frag_or_reasm_params_t frag_or_reasm_params;/**< Parameters for fragmentation/reassembly manipulation, ++ relevant if frag_or_reasm = TRUE */ ++#endif /* FM_CAPWAP_SUPPORT */ ++ void *id; ++} ioc_fm_pcd_manip_params_t; ++ ++/**************************************************************************//** ++ @Description Structure for retrieving IP reassembly statistics ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_reassem_ip_stats_t { ++ /* common counters for both IPv4 and IPv6 */ ++ uint32_t timeout; /**< Counts the number of TimeOut occurrences */ ++ uint32_t rfd_pool_busy; /**< Counts the number of failed attempts to allocate ++ a Reassembly Frame Descriptor */ ++ uint32_t internal_buffer_busy; /**< Counts the number of times an internal buffer busy occurred */ ++ uint32_t external_buffer_busy; /**< Counts the number of times external buffer busy occurred */ ++ uint32_t sg_fragments; /**< Counts the number of Scatter/Gather fragments */ ++ uint32_t dma_semaphore_depletion; /**< Counts the number of failed attempts to allocate a DMA semaphore */ ++#if (DPAA_VERSION >= 11) ++ uint32_t non_consistent_sp; /**< Counts the number of Non Consistent Storage Profile events for ++ successfully reassembled frames */ ++#endif /* (DPAA_VERSION >= 11) */ ++struct { ++ uint32_t successfully_reassembled; /**< Counts the number of successfully reassembled frames */ ++ uint32_t valid_fragments; /**< Counts the total number of valid fragments that ++ have been processed for all frames */ ++ uint32_t processed_fragments; /**< Counts the number of processed fragments ++ (valid and error fragments) for all frames */ ++ uint32_t malformed_fragments; /**< Counts the number of malformed fragments processed for all frames */ ++ uint32_t discarded_fragments; /**< Counts the number of fragments discarded by the reassembly process */ ++ uint32_t auto_learn_busy; /**< Counts the number of times a busy condition occurs when attempting ++ to access an IP-Reassembly Automatic Learning Hash set */ ++ uint32_t more_than16fragments; /**< Counts the fragment occurrences in which the number of fragments-per-frame ++ exceeds 16 */ ++ } specific_hdr_statistics[2]; /**< slot '0' is for IPv4, slot '1' is for IPv6 */ ++} ioc_fm_pcd_manip_reassem_ip_stats_t; ++ ++/**************************************************************************//** ++ @Description Structure for retrieving IP fragmentation statistics ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_frag_ip_stats_t { ++ uint32_t total_frames; /**< Number of frames that passed through the manipulation node */ ++ uint32_t fragmented_frames; /**< Number of frames that were fragmented */ ++ uint32_t generated_fragments; /**< Number of fragments that were generated */ ++} ioc_fm_pcd_manip_frag_ip_stats_t; ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Description Structure for retrieving CAPWAP reassembly statistics ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_reassem_capwap_stats_t { ++ uint32_t timeout; /**< Counts the number of timeout occurrences */ ++ uint32_t rfd_pool_busy; /**< Counts the number of failed attempts to allocate ++ a Reassembly Frame Descriptor */ ++ uint32_t internal_buffer_busy; /**< Counts the number of times an internal buffer busy occurred */ ++ uint32_t external_buffer_busy; /**< Counts the number of times external buffer busy occurred */ ++ uint32_t sg_fragments; /**< Counts the number of Scatter/Gather fragments */ ++ uint32_t dma_semaphore_depletion; /**< Counts the number of failed attempts to allocate a DMA semaphore */ ++ uint32_t successfully_reassembled; /**< Counts the number of successfully reassembled frames */ ++ uint32_t valid_fragments; /**< Counts the total number of valid fragments that ++ have been processed for all frames */ ++ uint32_t processed_fragments; /**< Counts the number of processed fragments ++ (valid and error fragments) for all frames */ ++ uint32_t malformed_fragments; /**< Counts the number of malformed fragments processed for all frames */ ++ uint32_t autoLearn_busy; /**< Counts the number of times a busy condition occurs when attempting ++ to access an Reassembly Automatic Learning Hash set */ ++ uint32_t discarded_fragments; /**< Counts the number of fragments discarded by the reassembly process */ ++ uint32_t more_than16fragments; /**< Counts the fragment occurrences in which the number of fragments-per-frame ++ exceeds 16 */ ++ uint32_t exceed_max_reassembly_frame_len;/**< ounts the number of times that a successful reassembled frame ++ length exceeds MaxReassembledFrameLength value */ ++} ioc_fm_pcd_manip_reassem_capwap_stats_t; ++ ++/**************************************************************************//** ++ @Description Structure for retrieving CAPWAP fragmentation statistics ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_frag_capwap_stats_t { ++ uint32_t total_frames; /**< Number of frames that passed through the manipulation node */ ++ uint32_t fragmented_frames; /**< Number of frames that were fragmented */ ++ uint32_t generated_fragments; /**< Number of fragments that were generated */ ++#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) ++ uint8_t sg_allocation_failure; /**< Number of allocation failure of s/g buffers */ ++#endif /* (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) */ ++} ioc_fm_pcd_manip_frag_capwap_stats_t; ++#endif /* (DPAA_VERSION >= 11) */ ++ ++/**************************************************************************//** ++ @Description Structure for retrieving reassembly statistics ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_reassem_stats_t { ++ union { ++ ioc_fm_pcd_manip_reassem_ip_stats_t ip_reassem; /**< Structure for IP reassembly statistics */ ++#if (DPAA_VERSION >= 11) ++ ioc_fm_pcd_manip_reassem_capwap_stats_t capwap_reassem; /**< Structure for CAPWAP reassembly statistics */ ++#endif /* (DPAA_VERSION >= 11) */ ++ } u; ++} ioc_fm_pcd_manip_reassem_stats_t; ++ ++/**************************************************************************//** ++ @Description structure for retrieving fragmentation statistics ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_frag_stats_t { ++ union { ++ ioc_fm_pcd_manip_frag_ip_stats_t ip_frag; /**< Structure for IP fragmentation statistics */ ++#if (DPAA_VERSION >= 11) ++ ioc_fm_pcd_manip_frag_capwap_stats_t capwap_frag; /**< Structure for CAPWAP fragmentation statistics */ ++#endif /* (DPAA_VERSION >= 11) */ ++ } u; ++} ioc_fm_pcd_manip_frag_stats_t; ++ ++/**************************************************************************//** ++ @Description structure for defining manipulation statistics ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_stats_t { ++ union { ++ ioc_fm_pcd_manip_reassem_stats_t reassem; /**< Structure for reassembly statistics */ ++ ioc_fm_pcd_manip_frag_stats_t frag; /**< Structure for fragmentation statistics */ ++ } u; ++} ioc_fm_pcd_manip_stats_t; ++ ++/**************************************************************************//** ++ @Description Parameters for acquiring manipulation statistics ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_manip_get_stats_t { ++ void *id; ++ ioc_fm_pcd_manip_stats_t stats; ++} ioc_fm_pcd_manip_get_stats_t; ++ ++#if DPAA_VERSION >= 11 ++/**************************************************************************//** ++ @Description Parameters for defining frame replicator group and its members ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_frm_replic_group_params_t { ++ uint8_t max_num_of_entries; /**< Maximal number of members in the group - must be at least two */ ++ uint8_t num_of_entries; /**< Number of members in the group - must be at least 1 */ ++ ioc_fm_pcd_cc_next_engine_params_t next_engine_params[IOC_FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES]; ++ /**< Array of members' parameters */ ++ void *id; ++} ioc_fm_pcd_frm_replic_group_params_t; ++ ++typedef struct ioc_fm_pcd_frm_replic_member_t { ++ void *h_replic_group; ++ uint16_t member_index; ++} ioc_fm_pcd_frm_replic_member_t; ++ ++typedef struct ioc_fm_pcd_frm_replic_member_params_t { ++ ioc_fm_pcd_frm_replic_member_t member; ++ ioc_fm_pcd_cc_next_engine_params_t next_engine_params; ++} ioc_fm_pcd_frm_replic_member_params_t; ++#endif /* DPAA_VERSION >= 11 */ ++ ++ ++typedef struct ioc_fm_pcd_cc_key_statistics_t { ++ uint32_t byte_count; /**< This counter reflects byte count of frames that ++ were matched by this key. */ ++ uint32_t frame_count; /**< This counter reflects count of frames that ++ were matched by this key. */ ++#if (DPAA_VERSION >= 11) ++ uint32_t frame_length_range_count[IOC_FM_PCD_CC_STATS_MAX_NUM_OF_FLR]; ++ /**< These counters reflect how many frames matched ++ this key in 'RMON' statistics mode: ++ Each counter holds the number of frames of a ++ specific frames length range, according to the ++ ranges provided at initialization. */ ++#endif /* (DPAA_VERSION >= 11) */ ++} ioc_fm_pcd_cc_key_statistics_t; ++ ++ ++typedef struct ioc_fm_pcd_cc_tbl_get_stats_t { ++ void *id; ++ uint16_t key_index; ++ ioc_fm_pcd_cc_key_statistics_t statistics; ++} ioc_fm_pcd_cc_tbl_get_stats_t; ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableGetKeyStatistics ++ ++ @Description This routine may be used to get statistics counters of specific key ++ in a CC Node. ++ ++ If 'e_FM_PCD_CC_STATS_MODE_FRAME' and ++ 'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node, ++ these counters reflect how many frames passed that were matched ++ this key; The total frames count will be returned in the counter ++ of the first range (as only one frame length range was defined). ++ If 'e_FM_PCD_CC_STATS_MODE_RMON' was set for this node, the total ++ frame count will be separated to frame length counters, based on ++ provided frame length ranges. ++ ++ @Param[in] h_CcNode A handle to the node ++ @Param[in] keyIndex Key index for adding ++ @Param[out] p_KeyStatistics Key statistics counters ++ ++ @Return The specific key statistics. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet(). ++*//***************************************************************************/ ++ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_MATCH_TABLE_GET_KEY_STAT_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(12), ioc_compat_fm_pcd_cc_tbl_get_stats_t) ++#endif ++#define FM_PCD_IOC_MATCH_TABLE_GET_KEY_STAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(12), ioc_fm_pcd_cc_tbl_get_stats_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableGetMissStatistics ++ ++ @Description This routine may be used to get statistics counters of miss entry ++ in a CC Node. ++ ++ If 'e_FM_PCD_CC_STATS_MODE_FRAME' and ++ 'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node, ++ these counters reflect how many frames were not matched to any ++ existing key and therefore passed through the miss entry; The ++ total frames count will be returned in the counter of the ++ first range (as only one frame length range was defined). ++ ++ @Param[in] h_CcNode A handle to the node ++ @Param[out] p_MissStatistics Statistics counters for 'miss' ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet(). ++*//***************************************************************************/ ++ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_MATCH_TABLE_GET_MISS_STAT_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(13), ioc_compat_fm_pcd_cc_tbl_get_stats_t) ++#endif ++#define FM_PCD_IOC_MATCH_TABLE_GET_MISS_STAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(13), ioc_fm_pcd_cc_tbl_get_stats_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_HashTableGetMissStatistics ++ ++ @Description This routine may be used to get statistics counters of 'miss' ++ entry of the a hash table. ++ ++ If 'e_FM_PCD_CC_STATS_MODE_FRAME' and ++ 'e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME' were set for this node, ++ these counters reflect how many frames were not matched to any ++ existing key and therefore passed through the miss entry; ++ ++ @Param[in] h_HashTbl A handle to a hash table ++ @Param[out] p_MissStatistics Statistics counters for 'miss' ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_HashTableSet(). ++*//***************************************************************************/ ++ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_HASH_TABLE_GET_MISS_STAT_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(14), ioc_compat_fm_pcd_cc_tbl_get_stats_t) ++#endif ++#define FM_PCD_IOC_HASH_TABLE_GET_MISS_STAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(14), ioc_fm_pcd_cc_tbl_get_stats_t) ++ ++ ++/**************************************************************************//** ++ @Function FM_PCD_NetEnvCharacteristicsSet ++ ++ @Description Define a set of Network Environment Characteristics. ++ ++ When setting an environment it is important to understand its ++ application. It is not meant to describe the flows that will run ++ on the ports using this environment, but what the user means TO DO ++ with the PCD mechanisms in order to parse-classify-distribute those ++ frames. ++ By specifying a distinction unit, the user means it would use that option ++ for distinction between frames at either a KeyGen scheme or a coarse ++ classification action descriptor. Using interchangeable headers to define a ++ unit means that the user is indifferent to which of the interchangeable ++ headers is present in the frame, and wants the distinction to be based ++ on the presence of either one of them. ++ ++ Depending on context, there are limitations to the use of environments. A ++ port using the PCD functionality is bound to an environment. Some or even ++ all ports may share an environment but also an environment per port is ++ possible. When initializing a scheme, a classification plan group (see below), ++ or a coarse classification tree, one of the initialized environments must be ++ stated and related to. When a port is bound to a scheme, a classification ++ plan group, or a coarse classification tree, it MUST be bound to the same ++ environment. ++ ++ The different PCD modules, may relate (for flows definition) ONLY on ++ distinction units as defined by their environment. When initializing a ++ scheme for example, it may not choose to select IPV4 as a match for ++ recognizing flows unless it was defined in the relating environment. In ++ fact, to guide the user through the configuration of the PCD, each module's ++ characterization in terms of flows is not done using protocol names, but using ++ environment indexes. ++ ++ In terms of HW implementation, the list of distinction units sets the LCV vectors ++ and later used for match vector, classification plan vectors and coarse classification ++ indexing. ++ ++ @Param[in,out] ioc_fm_pcd_net_env_params_t A structure defining the distiction units for this configuration. ++ ++ @Return 0 on success; Error code otherwise. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_NET_ENV_CHARACTERISTICS_SET_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(20), ioc_compat_fm_pcd_net_env_params_t) ++#endif ++#define FM_PCD_IOC_NET_ENV_CHARACTERISTICS_SET _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(20), ioc_fm_pcd_net_env_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_NetEnvCharacteristicsDelete ++ ++ @Description Deletes a set of Network Environment Charecteristics. ++ ++ @Param[in] ioc_fm_obj_t - The id of a Network Environment object. ++ ++ @Return 0 on success; Error code otherwise. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_NET_ENV_CHARACTERISTICS_DELETE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(21), ioc_compat_fm_obj_t) ++#endif ++#define FM_PCD_IOC_NET_ENV_CHARACTERISTICS_DELETE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(21), ioc_fm_obj_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_KgSchemeSet ++ ++ @Description Initializing or modifying and enabling a scheme for the KeyGen. ++ This routine should be called for adding or modifying a scheme. ++ When a scheme needs modifying, the API requires that it will be ++ rewritten. In such a case 'modify' should be TRUE. If the ++ routine is called for a valid scheme and 'modify' is FALSE, ++ it will return error. ++ ++ @Param[in,out] ioc_fm_pcd_kg_scheme_params_t A structure of parameters for defining the scheme ++ ++ @Return 0 on success; Error code otherwise. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_KG_SCHEME_SET_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(24), ioc_compat_fm_pcd_kg_scheme_params_t) ++#endif ++#define FM_PCD_IOC_KG_SCHEME_SET _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(24), ioc_fm_pcd_kg_scheme_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_KgSchemeDelete ++ ++ @Description Deleting an initialized scheme. ++ ++ @Param[in] ioc_fm_obj_t scheme id as initalized by application at FM_PCD_IOC_KG_SET_SCHEME ++ ++ @Return 0 on success; Error code otherwise. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_KG_SCHEME_DELETE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(25), ioc_compat_fm_obj_t) ++#endif ++#define FM_PCD_IOC_KG_SCHEME_DELETE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(25), ioc_fm_obj_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_CcRootBuild ++ ++ @Description This routine must be called to define a complete coarse ++ classification tree. This is the way to define coarse ++ classification to a certain flow - the KeyGen schemes ++ may point only to trees defined in this way. ++ ++ @Param[in,out] ioc_fm_pcd_cc_tree_params_t A structure of parameters to define the tree. ++ ++ @Return 0 on success; Error code otherwise. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_CC_ROOT_BUILD_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(26), compat_uptr_t) ++#endif ++#define FM_PCD_IOC_CC_ROOT_BUILD _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(26), void *) /* workaround ...*/ ++ ++/**************************************************************************//** ++ @Function FM_PCD_CcRootDelete ++ ++ @Description Deleting a built tree. ++ ++ @Param[in] ioc_fm_obj_t - The id of a CC tree. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_CC_ROOT_DELETE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(27), ioc_compat_fm_obj_t) ++#endif ++#define FM_PCD_IOC_CC_ROOT_DELETE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(27), ioc_fm_obj_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableSet ++ ++ @Description This routine should be called for each CC (coarse classification) ++ node. The whole CC tree should be built bottom up so that each ++ node points to already defined nodes. p_NodeId returns the node ++ Id to be used by other nodes. ++ ++ @Param[in,out] ioc_fm_pcd_cc_node_params_t A structure for defining the CC node params ++ ++ @Return 0 on success; Error code otherwise. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_MATCH_TABLE_SET_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(28), compat_uptr_t) ++#endif ++#define FM_PCD_IOC_MATCH_TABLE_SET _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(28), void *) /* workaround ...*/ ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableDelete ++ ++ @Description Deleting a built node. ++ ++ @Param[in] ioc_fm_obj_t - The id of a CC node. ++ ++ @Return 0 on success; Error code otherwise. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_MATCH_TABLE_DELETE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(29), ioc_compat_fm_obj_t) ++#endif ++#define FM_PCD_IOC_MATCH_TABLE_DELETE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(29), ioc_fm_obj_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_CcRootModifyNextEngine ++ ++ @Description Modify the Next Engine Parameters in the entry of the tree. ++ ++ @Param[in] ioc_fm_pcd_cc_tree_modify_next_engine_params_t - Pointer to a structure with the relevant parameters ++ ++ @Return 0 on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_CcRootBuild(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_CC_ROOT_MODIFY_NEXT_ENGINE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(30), ioc_compat_fm_pcd_cc_tree_modify_next_engine_params_t) ++#endif ++#define FM_PCD_IOC_CC_ROOT_MODIFY_NEXT_ENGINE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(30), ioc_fm_pcd_cc_tree_modify_next_engine_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableModifyNextEngine ++ ++ @Description Modify the Next Engine Parameters in the relevant key entry of the node. ++ ++ @Param[in] ioc_fm_pcd_cc_node_modify_next_engine_params_t A pointer to a structure with the relevant parameters ++ ++ @Return 0 on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_MATCH_TABLE_MODIFY_NEXT_ENGINE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(31), ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t) ++#endif ++#define FM_PCD_IOC_MATCH_TABLE_MODIFY_NEXT_ENGINE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(31), ioc_fm_pcd_cc_node_modify_next_engine_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableModifyMissNextEngine ++ ++ @Description Modify the Next Engine Parameters of the Miss key case of the node. ++ ++ @Param[in] ioc_fm_pcd_cc_node_modify_next_engine_params_t - Pointer to a structure with the relevant parameters ++ ++ @Return 0 on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_MATCH_TABLE_MODIFY_MISS_NEXT_ENGINE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(32), ioc_compat_fm_pcd_cc_node_modify_next_engine_params_t) ++#endif ++#define FM_PCD_IOC_MATCH_TABLE_MODIFY_MISS_NEXT_ENGINE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(32), ioc_fm_pcd_cc_node_modify_next_engine_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableRemoveKey ++ ++ @Description Remove the key (including next engine parameters of this key) ++ defined by the index of the relevant node. ++ ++ @Param[in] ioc_fm_pcd_cc_node_remove_key_params_t A pointer to a structure with the relevant parameters ++ ++ @Return 0 on success; Error code otherwise. ++ ++ @Cautions Allowed only after FM_PCD_MatchTableSet() has been called for this ++ node and for all of the nodes that lead to it. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_MATCH_TABLE_REMOVE_KEY_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(33), ioc_compat_fm_pcd_cc_node_remove_key_params_t) ++#endif ++#define FM_PCD_IOC_MATCH_TABLE_REMOVE_KEY _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(33), ioc_fm_pcd_cc_node_remove_key_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableAddKey ++ ++ @Description Add the key (including next engine parameters of this key in the ++ index defined by the keyIndex. Note that 'FM_PCD_LAST_KEY_INDEX' ++ may be used when the user doesn't care about the position of the ++ key in the table - in that case, the key will be automatically ++ added by the driver in the last available entry. ++ ++ @Param[in] ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t A pointer to a structure with the relevant parameters ++ ++ @Return 0 on success; Error code otherwise. ++ ++ @Cautions Allowed only after FM_PCD_MatchTableSet() has been called for this ++ node and for all of the nodes that lead to it. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_MATCH_TABLE_ADD_KEY_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(34), ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t) ++#endif ++#define FM_PCD_IOC_MATCH_TABLE_ADD_KEY _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(34), ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableModifyKeyAndNextEngine ++ ++ @Description Modify the key and Next Engine Parameters of this key in the index defined by key_index. ++ ++ @Param[in] ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t A pointer to a structure with the relevant parameters ++ ++ @Return 0 on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_MatchTableSet() not only of the relevnt node but also ++ the node that points to this node ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_AND_NEXT_ENGINE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(35), ioc_compat_fm_pcd_cc_node_modify_key_and_next_engine_params_t) ++#endif ++#define FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_AND_NEXT_ENGINE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(35), ioc_fm_pcd_cc_node_modify_key_and_next_engine_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_MatchTableModifyKey ++ ++ @Description Modify the key at the index defined by key_index. ++ ++ @Param[in] ioc_fm_pcd_cc_node_modify_key_params_t - Pointer to a structure with the relevant parameters ++ ++ @Return 0 on success; Error code otherwise. ++ ++ @Cautions Allowed only after FM_PCD_MatchTableSet() has been called for this ++ node and for all of the nodes that lead to it. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(36), ioc_compat_fm_pcd_cc_node_modify_key_params_t) ++#endif ++#define FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(36), ioc_fm_pcd_cc_node_modify_key_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_HashTableSet ++ ++ @Description This routine initializes a hash table structure. ++ KeyGen hash result determines the hash bucket. ++ Next, KeyGen key is compared against all keys of this ++ bucket (exact match). ++ Number of sets (number of buckets) of the hash equals to the ++ number of 1-s in 'hash_res_mask' in the provided parameters. ++ Number of hash table ways is then calculated by dividing ++ 'max_num_of_keys' equally between the hash sets. This is the maximal ++ number of keys that a hash bucket may hold. ++ The hash table is initialized empty and keys may be ++ added to it following the initialization. Keys masks are not ++ supported in current hash table implementation. ++ The initialized hash table can be integrated as a node in a ++ CC tree. ++ ++ @Param[in,out] ioc_fm_pcd_hash_table_params_t - Pointer to a structure with the relevant parameters ++ ++ @Return 0 on success; Error code otherwise. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_HASH_TABLE_SET_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(37), ioc_compat_fm_pcd_hash_table_params_t) ++#endif ++#define FM_PCD_IOC_HASH_TABLE_SET _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(37), ioc_fm_pcd_hash_table_params_t) ++ ++ ++/**************************************************************************//** ++ @Function FM_PCD_HashTableDelete ++ ++ @Description This routine deletes the provided hash table and released all ++ its allocated resources. ++ ++ @Param[in] ioc_fm_obj_t - The ID of a hash table. ++ ++ @Return 0 on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_HashTableSet(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_HASH_TABLE_DELETE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(37), ioc_compat_fm_obj_t) ++#endif ++#define FM_PCD_IOC_HASH_TABLE_DELETE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(37), ioc_fm_obj_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_HashTableAddKey ++ ++ @Description This routine adds the provided key (including next engine ++ parameters of this key) to the hash table. ++ The key is added as the last key of the bucket that it is ++ mapped to. ++ ++ @Param[in] ioc_fm_pcd_hash_table_add_key_params_t - Pointer to a structure with the relevant parameters ++ ++ @Return 0 on success; error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_HashTableSet(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_HASH_TABLE_ADD_KEY_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(39), ioc_compat_fm_pcd_hash_table_add_key_params_t) ++#endif ++#define FM_PCD_IOC_HASH_TABLE_ADD_KEY _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(39), ioc_fm_pcd_hash_table_add_key_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_HashTableRemoveKey ++ ++ @Description This routine removes the requested key (including next engine ++ parameters of this key) from the hash table. ++ ++ @Param[in] ioc_fm_pcd_hash_table_remove_key_params_t - Pointer to a structure with the relevant parameters ++ ++ @Return 0 on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_HashTableSet(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_HASH_TABLE_REMOVE_KEY_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(40), ioc_compat_fm_pcd_hash_table_remove_key_params_t) ++#endif ++#define FM_PCD_IOC_HASH_TABLE_REMOVE_KEY _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(40), ioc_fm_pcd_hash_table_remove_key_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_PlcrProfileSet ++ ++ @Description Sets a profile entry in the policer profile table. ++ The routine overrides any existing value. ++ ++ @Param[in,out] ioc_fm_pcd_plcr_profile_params_t A structure of parameters for defining a ++ policer profile entry. ++ ++ @Return 0 on success; Error code otherwise. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_PLCR_PROFILE_SET_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(41), ioc_compat_fm_pcd_plcr_profile_params_t) ++#endif ++#define FM_PCD_IOC_PLCR_PROFILE_SET _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(41), ioc_fm_pcd_plcr_profile_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_PlcrProfileDelete ++ ++ @Description Delete a profile entry in the policer profile table. ++ The routine set entry to invalid. ++ ++ @Param[in] ioc_fm_obj_t The id of a policer profile. ++ ++ @Return 0 on success; Error code otherwise. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_PLCR_PROFILE_DELETE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(41), ioc_compat_fm_obj_t) ++#endif ++#define FM_PCD_IOC_PLCR_PROFILE_DELETE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(41), ioc_fm_obj_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_ManipNodeSet ++ ++ @Description This routine should be called for defining a manipulation ++ node. A manipulation node must be defined before the CC node ++ that precedes it. ++ ++ @Param[in] ioc_fm_pcd_manip_params_t - A structure of parameters defining the manipulation ++ ++ @Return A handle to the initialized object on success; NULL code otherwise. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_MANIP_NODE_SET_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(43), ioc_compat_fm_pcd_manip_params_t) ++#endif ++#define FM_PCD_IOC_MANIP_NODE_SET _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(43), ioc_fm_pcd_manip_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_ManipNodeReplace ++ ++ @Description Change existing manipulation node to be according to new requirement. ++ (Here, it's implemented as a variant of the same IOCTL as for ++ FM_PCD_ManipNodeSet(), and one that when called, the 'id' member ++ in its 'ioc_fm_pcd_manip_params_t' argument is set to contain ++ the manip node's handle) ++ ++ @Param[in] ioc_fm_pcd_manip_params_t - A structure of parameters defining the manipulation ++ ++ @Return 0 on success; error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_ManipNodeSet(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_MANIP_NODE_REPLACE_COMPAT FM_PCD_IOC_MANIP_NODE_SET_COMPAT ++#endif ++#define FM_PCD_IOC_MANIP_NODE_REPLACE FM_PCD_IOC_MANIP_NODE_SET ++ ++/**************************************************************************//** ++ @Function FM_PCD_ManipNodeDelete ++ ++ @Description Delete an existing manipulation node. ++ ++ @Param[in] ioc_fm_obj_t The id of the manipulation node to delete. ++ ++ @Return 0 on success; error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_ManipNodeSet(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_MANIP_NODE_DELETE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(44), ioc_compat_fm_obj_t) ++#endif ++#define FM_PCD_IOC_MANIP_NODE_DELETE _IOW(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(44), ioc_fm_obj_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_ManipGetStatistics ++ ++ @Description Retrieve the manipulation statistics. ++ ++ @Param[in] h_ManipNode A handle to a manipulation node. ++ @Param[out] p_FmPcdManipStats A structure for retrieving the manipulation statistics ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_ManipNodeSet(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_MANIP_GET_STATS_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(50), ioc_compat_fm_pcd_manip_get_stats_t) ++#endif ++#define FM_PCD_IOC_MANIP_GET_STATS _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(50), ioc_fm_pcd_manip_get_stats_t) ++ ++/**************************************************************************//** ++@Function FM_PCD_SetAdvancedOffloadSupport ++ ++@Description This routine must be called in order to support the following features: ++ IP-fragmentation, IP-reassembly, IPsec, Header-manipulation, frame-replicator. ++ ++@Param[in] h_FmPcd FM PCD module descriptor. ++ ++@Return 0 on success; error code otherwise. ++ ++@Cautions Allowed only when PCD is disabled. ++*//***************************************************************************/ ++#define FM_PCD_IOC_SET_ADVANCED_OFFLOAD_SUPPORT _IO(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(45)) ++ ++#if (DPAA_VERSION >= 11) ++/**************************************************************************//** ++ @Function FM_PCD_FrmReplicSetGroup ++ ++ @Description Initialize a Frame Replicator group. ++ ++ @Param[in] h_FmPcd FM PCD module descriptor. ++ @Param[in] p_FrmReplicGroupParam A structure of parameters for the initialization of ++ the frame replicator group. ++ ++ @Return A handle to the initialized object on success; NULL code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_Init(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_FRM_REPLIC_GROUP_SET_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(46), ioc_compat_fm_pcd_frm_replic_group_params_t) ++#endif ++#define FM_PCD_IOC_FRM_REPLIC_GROUP_SET _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(46), ioc_fm_pcd_frm_replic_group_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_FrmReplicDeleteGroup ++ ++ @Description Delete a Frame Replicator group. ++ ++ @Param[in] h_FrmReplicGroup A handle to the frame replicator group. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_FrmReplicSetGroup(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_FRM_REPLIC_GROUP_DELETE_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(47), ioc_compat_fm_obj_t) ++#endif ++#define FM_PCD_IOC_FRM_REPLIC_GROUP_DELETE _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(47), ioc_fm_obj_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_FrmReplicAddMember ++ ++ @Description Add the member in the index defined by the memberIndex. ++ ++ @Param[in] h_FrmReplicGroup A handle to the frame replicator group. ++ @Param[in] memberIndex member index for adding. ++ @Param[in] p_MemberParams A pointer to the new member parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_FrmReplicSetGroup() of this group. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_FRM_REPLIC_MEMBER_ADD_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(48), ioc_compat_fm_pcd_frm_replic_member_params_t) ++#endif ++#define FM_PCD_IOC_FRM_REPLIC_MEMBER_ADD _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(48), ioc_fm_pcd_frm_replic_member_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PCD_FrmReplicRemoveMember ++ ++ @Description Remove the member defined by the index from the relevant group. ++ ++ @Param[in] h_FrmReplicGroup A handle to the frame replicator group. ++ @Param[in] memberIndex member index for removing. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PCD_FrmReplicSetGroup() of this group. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_FRM_REPLIC_MEMBER_REMOVE_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(49), ioc_compat_fm_pcd_frm_replic_member_t) ++#endif ++#define FM_PCD_IOC_FRM_REPLIC_MEMBER_REMOVE _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(49), ioc_fm_pcd_frm_replic_member_t) ++ ++#endif ++ ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++/**************************************************************************//** ++ @Function FM_PCD_StatisticsSetNode ++ ++ @Description This routine should be called for defining a statistics node. ++ ++ @Param[in,out] ioc_fm_pcd_stats_params_t A structure of parameters defining the statistics ++ ++ @Return 0 on success; Error code otherwise. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_STATISTICS_SET_NODE_COMPAT _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(45), void *) ++#endif ++#define FM_PCD_IOC_STATISTICS_SET_NODE _IOWR(FM_IOC_TYPE_BASE, FM_PCD_IOC_NUM(45), void *) ++ ++#endif /* FM_CAPWAP_SUPPORT */ ++ ++#ifdef NCSW_BACKWARD_COMPATIBLE_API ++#if defined(CONFIG_COMPAT) ++#define FM_PCD_IOC_SET_NET_ENV_CHARACTERISTICS_COMPAT \ ++ FM_PCD_IOC_NET_ENV_CHARACTERISTICS_SET_COMPAT ++#define FM_PCD_IOC_DELETE_NET_ENV_CHARACTERISTICS_COMPAT \ ++ FM_PCD_IOC_NET_ENV_CHARACTERISTICS_DELETE_COMPAT ++#define FM_PCD_IOC_KG_SET_SCHEME_COMPAT FM_PCD_IOC_KG_SCHEME_SET_COMPAT ++#define FM_PCD_IOC_KG_DEL_SCHEME_COMPAT FM_PCD_IOC_KG_SCHEME_DELETE_COMPAT ++#define FM_PCD_IOC_CC_BUILD_TREE_COMPAT FM_PCD_IOC_CC_ROOT_BUILD_COMPAT ++#define FM_PCD_IOC_CC_DELETE_TREE_COMPAT FM_PCD_IOC_CC_ROOT_DELETE_COMPAT ++#define FM_PCD_IOC_CC_DELETE_NODE_COMPAT FM_PCD_IOC_MATCH_TABLE_DELETE_COMPAT ++#define FM_PCD_IOC_CC_TREE_MODIFY_NEXT_ENGINE_COMPAT \ ++ FM_PCD_IOC_CC_ROOT_MODIFY_NEXT_ENGINE_COMPAT ++#define FM_PCD_IOC_CC_NODE_MODIFY_NEXT_ENGINE_COMPAT \ ++ FM_PCD_IOC_MATCH_TABLE_MODIFY_NEXT_ENGINE_COMPAT ++#define FM_PCD_IOC_CC_NODE_MODIFY_MISS_NEXT_ENGINE_COMPAT \ ++ FM_PCD_IOC_MATCH_TABLE_MODIFY_MISS_NEXT_ENGINE_COMPAT ++#define FM_PCD_IOC_CC_NODE_REMOVE_KEY_COMPAT FM_PCD_IOC_MATCH_TABLE_REMOVE_KEY_COMPAT ++#define FM_PCD_IOC_CC_NODE_ADD_KEY_COMPAT FM_PCD_IOC_MATCH_TABLE_ADD_KEY_COMPAT ++#define FM_PCD_IOC_CC_NODE_MODIFY_KEY_AND_NEXT_ENGINE_COMPAT \ ++ FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_AND_NEXT_ENGINE_COMPAT ++#define FM_PCD_IOC_CC_NODE_MODIFY_KEY_COMPAT FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_COMPAT ++#define FM_PCD_IOC_PLCR_SET_PROFILE_COMPAT FM_PCD_IOC_PLCR_PROFILE_SET_COMPAT ++#define FM_PCD_IOC_PLCR_DEL_PROFILE_COMPAT FM_PCD_IOC_PLCR_PROFILE_DELETE_COMPAT ++#define FM_PCD_IOC_MANIP_SET_NODE_COMPAT FM_PCD_IOC_MANIP_NODE_SET_COMPAT ++#define FM_PCD_IOC_MANIP_DELETE_NODE_COMPAT FM_PCD_IOC_MANIP_NODE_DELETE_COMPAT ++#endif ++#define FM_PCD_IOC_SET_NET_ENV_CHARACTERISTICS FM_PCD_IOC_NET_ENV_CHARACTERISTICS_SET ++#define FM_PCD_IOC_DELETE_NET_ENV_CHARACTERISTICS \ ++ FM_PCD_IOC_NET_ENV_CHARACTERISTICS_DELETE ++#define FM_PCD_IOC_KG_SET_SCHEME FM_PCD_IOC_KG_SCHEME_SET ++#define FM_PCD_IOC_KG_DEL_SCHEME FM_PCD_IOC_KG_SCHEME_DELETE ++#define FM_PCD_IOC_CC_BUILD_TREE FM_PCD_IOC_CC_ROOT_BUILD ++#define FM_PCD_IOC_CC_DELETE_TREE FM_PCD_IOC_CC_ROOT_DELETE ++#define FM_PCD_IOC_CC_DELETE_NODE FM_PCD_IOC_MATCH_TABLE_DELETE ++#define FM_PCD_IOC_CC_TREE_MODIFY_NEXT_ENGINE FM_PCD_IOC_CC_ROOT_MODIFY_NEXT_ENGINE ++#define FM_PCD_IOC_CC_NODE_MODIFY_NEXT_ENGINE FM_PCD_IOC_MATCH_TABLE_MODIFY_NEXT_ENGINE ++#define FM_PCD_IOC_CC_NODE_MODIFY_MISS_NEXT_ENGINE \ ++ FM_PCD_IOC_MATCH_TABLE_MODIFY_MISS_NEXT_ENGINE ++#define FM_PCD_IOC_CC_NODE_REMOVE_KEY FM_PCD_IOC_MATCH_TABLE_REMOVE_KEY ++#define FM_PCD_IOC_CC_NODE_ADD_KEY FM_PCD_IOC_MATCH_TABLE_ADD_KEY ++#define FM_PCD_IOC_CC_NODE_MODIFY_KEY_AND_NEXT_ENGINE \ ++ FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY_AND_NEXT_ENGINE ++#define FM_PCD_IOC_CC_NODE_MODIFY_KEY FM_PCD_IOC_MATCH_TABLE_MODIFY_KEY ++#define FM_PCD_IOC_PLCR_SET_PROFILE FM_PCD_IOC_PLCR_PROFILE_SET ++#define FM_PCD_IOC_PLCR_DEL_PROFILE FM_PCD_IOC_PLCR_PROFILE_DELETE ++#define FM_PCD_IOC_MANIP_SET_NODE FM_PCD_IOC_MANIP_NODE_SET ++#define FM_PCD_IOC_MANIP_DELETE_NODE FM_PCD_IOC_MANIP_NODE_DELETE ++#endif /* NCSW_BACKWARD_COMPATIBLE_API */ ++ ++#endif /* __FM_PCD_IOCTLS_H */ ++/** @} */ /* end of lnx_ioctl_FM_PCD_Runtime_grp group */ ++/** @} */ /* end of lnx_ioctl_FM_PCD_grp group */ ++/** @} */ /* end of lnx_ioctl_FM_grp group */ +diff --git a/include/uapi/linux/fmd/Peripherals/fm_port_ioctls.h b/include/uapi/linux/fmd/Peripherals/fm_port_ioctls.h +new file mode 100644 +index 00000000..a2f61107 +--- /dev/null ++++ b/include/uapi/linux/fmd/Peripherals/fm_port_ioctls.h +@@ -0,0 +1,948 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/****************************************************************************** ++ @File fm_port_ioctls.h ++ ++ @Description FM Port routines ++*//***************************************************************************/ ++#ifndef __FM_PORT_IOCTLS_H ++#define __FM_PORT_IOCTLS_H ++ ++#include "enet_ext.h" ++#include "net_ioctls.h" ++#include "fm_ioctls.h" ++#include "fm_pcd_ioctls.h" ++ ++ ++/**************************************************************************//** ++ ++ @Group lnx_ioctl_FM_grp Frame Manager Linux IOCTL API ++ ++ @Description FM Linux ioctls definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Group lnx_ioctl_FM_PORT_grp FM Port ++ ++ @Description FM Port API ++ ++ The FM uses a general module called "port" to represent a Tx port ++ (MAC), an Rx port (MAC), offline parsing flow or host command ++ flow. There may be up to 17 (may change) ports in an FM - 5 Tx ++ ports (4 for the 1G MACs, 1 for the 10G MAC), 5 Rx Ports, and 7 ++ Host command/Offline parsing ports. The SW driver manages these ++ ports as sub-modules of the FM, i.e. after an FM is initialized, ++ its ports may be initialized and operated upon. ++ ++ The port is initialized aware of its type, but other functions on ++ a port may be indifferent to its type. When necessary, the driver ++ verifies coherency and returns error if applicable. ++ ++ On initialization, user specifies the port type and it's index ++ (relative to the port's type). Host command and Offline parsing ++ ports share the same id range, I.e user may not initialized host ++ command port 0 and offline parsing port 0. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description An enum for defining port PCD modes. ++ (Must match enum e_FmPortPcdSupport defined in fm_port_ext.h) ++ ++ This enum defines the superset of PCD engines support - i.e. not ++ all engines have to be used, but all have to be enabled. The real ++ flow of a specific frame depends on the PCD configuration and the ++ frame headers and payload. ++ Note: the first engine and the first engine after the parser (if ++ exists) should be in order, the order is important as it will ++ define the flow of the port. However, as for the rest engines ++ (the ones that follows), the order is not important anymore as ++ it is defined by the PCD graph itself. ++*//***************************************************************************/ ++typedef enum ioc_fm_port_pcd_support { ++ e_IOC_FM_PORT_PCD_SUPPORT_NONE = 0 /**< BMI to BMI, PCD is not used */ ++ , e_IOC_FM_PORT_PCD_SUPPORT_PRS_ONLY /**< Use only Parser */ ++ , e_IOC_FM_PORT_PCD_SUPPORT_PLCR_ONLY /**< Use only Policer */ ++ , e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR /**< Use Parser and Policer */ ++ , e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG /**< Use Parser and Keygen */ ++ , e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC /**< Use Parser, Keygen and Coarse Classification */ ++ , e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR ++ /**< Use all PCD engines */ ++ , e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR /**< Use Parser, Keygen and Policer */ ++ , e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_CC /**< Use Parser and Coarse Classification */ ++ , e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_CC_AND_PLCR /**< Use Parser and Coarse Classification and Policer */ ++ , e_IOC_FM_PORT_PCD_SUPPORT_CC_ONLY /**< Use only Coarse Classification */ ++#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) ++ , e_IOC_FM_PORT_PCD_SUPPORT_CC_AND_KG /**< Use Coarse Classification,and Keygen */ ++ , e_IOC_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR /**< Use Coarse Classification, Keygen and Policer */ ++#endif /* FM_CAPWAP_SUPPORT */ ++} ioc_fm_port_pcd_support; ++ ++ ++/**************************************************************************//** ++ @Collection FM Frame error ++*//***************************************************************************/ ++typedef uint32_t ioc_fm_port_frame_err_select_t; /**< typedef for defining Frame Descriptor errors */ ++ ++/* @} */ ++ ++ ++/**************************************************************************//** ++ @Description An enum for defining Dual Tx rate limiting scale. ++ (Must match e_FmPortDualRateLimiterScaleDown defined in fm_port_ext.h) ++*//***************************************************************************/ ++typedef enum ioc_fm_port_dual_rate_limiter_scale_down { ++ e_IOC_FM_PORT_DUAL_RATE_LIMITER_NONE = 0, /**< Use only single rate limiter */ ++ e_IOC_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_2, /**< Divide high rate limiter by 2 */ ++ e_IOC_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_4, /**< Divide high rate limiter by 4 */ ++ e_IOC_FM_PORT_DUAL_RATE_LIMITER_SCALE_DOWN_BY_8 /**< Divide high rate limiter by 8 */ ++} ioc_fm_port_dual_rate_limiter_scale_down; ++ ++/**************************************************************************//** ++ @Description A structure for defining Tx rate limiting ++ (Must match struct t_FmPortRateLimit defined in fm_port_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_port_rate_limit_t { ++ uint16_t max_burst_size; /**< in KBytes for Tx ports, in frames ++ for offline parsing ports. (note that ++ for early chips burst size is ++ rounded up to a multiply of 1000 frames).*/ ++ uint32_t rate_limit; /**< in Kb/sec for Tx ports, in frame/sec for ++ offline parsing ports. Rate limit refers to ++ data rate (rather than line rate). */ ++ ioc_fm_port_dual_rate_limiter_scale_down rate_limit_divider; /**< For offline parsing ports only. Not-valid ++ for some earlier chip revisions */ ++} ioc_fm_port_rate_limit_t; ++ ++ ++ ++/**************************************************************************//** ++ @Group lnx_ioctl_FM_PORT_runtime_control_grp FM Port Runtime Control Unit ++ ++ @Description FM Port Runtime control unit API functions, definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description An enum for defining FM Port counters. ++ (Must match enum e_FmPortCounters defined in fm_port_ext.h) ++*//***************************************************************************/ ++typedef enum ioc_fm_port_counters { ++ e_IOC_FM_PORT_COUNTERS_CYCLE, /**< BMI performance counter */ ++ e_IOC_FM_PORT_COUNTERS_TASK_UTIL, /**< BMI performance counter */ ++ e_IOC_FM_PORT_COUNTERS_QUEUE_UTIL, /**< BMI performance counter */ ++ e_IOC_FM_PORT_COUNTERS_DMA_UTIL, /**< BMI performance counter */ ++ e_IOC_FM_PORT_COUNTERS_FIFO_UTIL, /**< BMI performance counter */ ++ e_IOC_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION, /**< BMI Rx only performance counter */ ++ e_IOC_FM_PORT_COUNTERS_FRAME, /**< BMI statistics counter */ ++ e_IOC_FM_PORT_COUNTERS_DISCARD_FRAME, /**< BMI statistics counter */ ++ e_IOC_FM_PORT_COUNTERS_DEALLOC_BUF, /**< BMI deallocate buffer statistics counter */ ++ e_IOC_FM_PORT_COUNTERS_RX_BAD_FRAME, /**< BMI Rx only statistics counter */ ++ e_IOC_FM_PORT_COUNTERS_RX_LARGE_FRAME, /**< BMI Rx only statistics counter */ ++ e_IOC_FM_PORT_COUNTERS_RX_FILTER_FRAME, /**< BMI Rx & OP only statistics counter */ ++ e_IOC_FM_PORT_COUNTERS_RX_LIST_DMA_ERR, /**< BMI Rx, OP & HC only statistics counter */ ++ e_IOC_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD, /**< BMI Rx, OP & HC statistics counter */ ++ e_IOC_FM_PORT_COUNTERS_PREPARE_TO_ENQUEUE_COUNTER, /**< BMI Rx, OP & HC only statistics counter */ ++ e_IOC_FM_PORT_COUNTERS_WRED_DISCARD, /**< BMI OP & HC only statistics counter */ ++ e_IOC_FM_PORT_COUNTERS_LENGTH_ERR, /**< BMI non-Rx statistics counter */ ++ e_IOC_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT, /**< BMI non-Rx statistics counter */ ++ e_IOC_FM_PORT_COUNTERS_DEQ_TOTAL, /**< QMI total QM dequeues counter */ ++ e_IOC_FM_PORT_COUNTERS_ENQ_TOTAL, /**< QMI total QM enqueues counter */ ++ e_IOC_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT, /**< QMI counter */ ++ e_IOC_FM_PORT_COUNTERS_DEQ_CONFIRM /**< QMI counter */ ++} ioc_fm_port_counters; ++ ++typedef struct ioc_fm_port_bmi_stats_t { ++ uint32_t cnt_cycle; ++ uint32_t cnt_task_util; ++ uint32_t cnt_queue_util; ++ uint32_t cnt_dma_util; ++ uint32_t cnt_fifo_util; ++ uint32_t cnt_rx_pause_activation; ++ uint32_t cnt_frame; ++ uint32_t cnt_discard_frame; ++ uint32_t cnt_dealloc_buf; ++ uint32_t cnt_rx_bad_frame; ++ uint32_t cnt_rx_large_frame; ++ uint32_t cnt_rx_filter_frame; ++ uint32_t cnt_rx_list_dma_err; ++ uint32_t cnt_rx_out_of_buffers_discard; ++ uint32_t cnt_wred_discard; ++ uint32_t cnt_length_err; ++ uint32_t cnt_unsupported_format; ++} ioc_fm_port_bmi_stats_t; ++ ++/**************************************************************************//** ++ @Description Structure for Port id parameters. ++ (Description may be inaccurate; ++ must match struct t_FmPortCongestionGrps defined in fm_port_ext.h) ++ ++ Fields commented 'IN' are passed by the port module to be used ++ by the FM module. ++ Fields commented 'OUT' will be filled by FM before returning to port. ++*//***************************************************************************/ ++typedef struct ioc_fm_port_congestion_groups_t { ++ uint16_t num_of_congestion_grps_to_consider; /**< The number of required congestion groups ++ to define the size of the following array */ ++ uint8_t congestion_grps_to_consider [FM_PORT_NUM_OF_CONGESTION_GRPS]; ++ /**< An array of CG indexes; ++ Note that the size of the array should be ++ 'num_of_congestion_grps_to_consider'. */ ++#if DPAA_VERSION >= 11 ++ bool pfc_priorities_enable[FM_PORT_NUM_OF_CONGESTION_GRPS][FM_MAX_NUM_OF_PFC_PRIORITIES]; ++ /**< A matrix that represents the map between the CG ids ++ defined in 'congestion_grps_to_consider' to the priorities ++ mapping array. */ ++#endif /* DPAA_VERSION >= 11 */ ++} ioc_fm_port_congestion_groups_t; ++ ++ ++ ++/**************************************************************************//** ++ @Function FM_PORT_Disable ++ ++ @Description Gracefully disable an FM port. The port will not start new tasks after all ++ tasks associated with the port are terminated. ++ ++ @Return 0 on success; error code otherwise. ++ ++ @Cautions This is a blocking routine, it returns after port is ++ gracefully stopped, i.e. the port will not except new frames, ++ but it will finish all frames or tasks which were already began ++*//***************************************************************************/ ++#define FM_PORT_IOC_DISABLE _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(1)) ++ ++/**************************************************************************//** ++ @Function FM_PORT_Enable ++ ++ @Description A runtime routine provided to allow disable/enable of port. ++ ++ @Return 0 on success; error code otherwise. ++*//***************************************************************************/ ++#define FM_PORT_IOC_ENABLE _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(2)) ++ ++/**************************************************************************//** ++ @Function FM_PORT_SetRateLimit ++ ++ @Description Calling this routine enables rate limit algorithm. ++ By default, this functionality is disabled. ++ Note that rate-limit mechanism uses the FM time stamp. ++ The selected rate limit specified here would be ++ rounded DOWN to the nearest 16M. ++ ++ May be used for Tx and offline parsing ports only ++ ++ @Param[in] ioc_fm_port_rate_limit A structure of rate limit parameters ++ ++ @Return 0 on success; error code otherwise. ++*//***************************************************************************/ ++#define FM_PORT_IOC_SET_RATE_LIMIT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(3), ioc_fm_port_rate_limit_t) ++ ++/**************************************************************************//** ++ @Function FM_PORT_DeleteRateLimit ++ ++ @Description Calling this routine disables the previously enabled rate limit. ++ ++ May be used for Tx and offline parsing ports only ++ ++ @Return 0 on success; error code otherwise. ++*//***************************************************************************/ ++#define FM_PORT_IOC_DELETE_RATE_LIMIT _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(5)) ++#define FM_PORT_IOC_REMOVE_RATE_LIMIT FM_PORT_IOC_DELETE_RATE_LIMIT ++ ++ ++/**************************************************************************//** ++ @Function FM_PORT_AddCongestionGrps ++ ++ @Description This routine effects the corresponding Tx port. ++ It should be called in order to enable pause ++ frame transmission in case of congestion in one or more ++ of the congestion groups relevant to this port. ++ Each call to this routine may add one or more congestion ++ groups to be considered relevant to this port. ++ ++ May be used for Rx, or RX+OP ports only (depending on chip) ++ ++ @Param[in] ioc_fm_port_congestion_groups_t - A pointer to an array of ++ congestion group ids to consider. ++ ++ @Return 0 on success; error code otherwise. ++*//***************************************************************************/ ++#define FM_PORT_IOC_ADD_CONGESTION_GRPS _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(34), ioc_fm_port_congestion_groups_t) ++ ++/**************************************************************************//** ++ @Function FM_PORT_RemoveCongestionGrps ++ ++ @Description This routine effects the corresponding Tx port. It should be ++ called when congestion groups were ++ defined for this port and are no longer relevant, or pause ++ frames transmitting is not required on their behalf. ++ Each call to this routine may remove one or more congestion ++ groups to be considered relevant to this port. ++ ++ May be used for Rx, or RX+OP ports only (depending on chip) ++ ++ @Param[in] ioc_fm_port_congestion_groups_t - A pointer to an array of ++ congestion group ids to consider. ++ ++ @Return 0 on success; error code otherwise. ++*//***************************************************************************/ ++#define FM_PORT_IOC_REMOVE_CONGESTION_GRPS _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(35), ioc_fm_port_congestion_groups_t) ++ ++/**************************************************************************//** ++ @Function FM_PORT_SetErrorsRoute ++ ++ @Description Errors selected for this routine will cause a frame with that error ++ to be enqueued to error queue. ++ Errors not selected for this routine will cause a frame with that error ++ to be enqueued to the one of the other port queues. ++ By default all errors are defined to be enqueued to error queue. ++ Errors that were configured to be discarded (at initialization) ++ may not be selected here. ++ ++ May be used for Rx and offline parsing ports only ++ ++ @Param[in] ioc_fm_port_frame_err_select_t A list of errors to enqueue to error queue ++ ++ @Return 0 on success; error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++ (szbs001: How is it possible to have one function that needs to be ++ called BEFORE FM_PORT_Init() implemented as an ioctl, ++ which will ALWAYS be called AFTER the FM_PORT_Init() ++ for that port!?!?!?!???!?!??!?!?) ++*//***************************************************************************/ ++#define FM_PORT_IOC_SET_ERRORS_ROUTE _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(4), ioc_fm_port_frame_err_select_t) ++ ++ ++/**************************************************************************//** ++ @Group lnx_ioctl_FM_PORT_pcd_runtime_control_grp FM Port PCD Runtime Control Unit ++ ++ @Description FM Port PCD Runtime control unit API functions, definitions and enums. ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description A structure defining the KG scheme after the parser. ++ (Must match struct t_FmPcdKgSchemeSelect defined in fm_port_ext.h) ++ ++ This is relevant only to change scheme selection mode - from ++ direct to indirect and vice versa, or when the scheme is selected directly, ++ to select the scheme id. ++ ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_kg_scheme_select_t { ++ bool direct; /**< TRUE to use 'scheme_id' directly, FALSE to use LCV.*/ ++ void *scheme_id; /**< Relevant for 'direct'=TRUE only. ++ 'scheme_id' selects the scheme after parser. */ ++} ioc_fm_pcd_kg_scheme_select_t; ++ ++/**************************************************************************//** ++ @Description Scheme IDs structure ++ (Must match struct t_FmPcdPortSchemesParams defined in fm_port_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_port_schemes_params_t { ++ uint8_t num_of_schemes; /**< Number of schemes for port to be bound to. */ ++ void *scheme_ids[FM_PCD_KG_NUM_OF_SCHEMES]; /**< Array of 'num_of_schemes' schemes for the ++ port to be bound to */ ++} ioc_fm_pcd_port_schemes_params_t; ++ ++/**************************************************************************//** ++ @Description A union for defining port protocol parameters for parser ++ (Must match union u_FmPcdHdrPrsOpts defined in fm_port_ext.h) ++*//***************************************************************************/ ++typedef union ioc_fm_pcd_hdr_prs_opts_u { ++ /* MPLS */ ++ struct { ++ bool label_interpretation_enable;/**< When this bit is set, the last MPLS label will be ++ interpreted as described in HW spec table. When the bit ++ is cleared, the parser will advance to MPLS next parse */ ++ ioc_net_header_type next_parse; /**< must be equal or higher than IPv4 */ ++ } mpls_prs_options; ++ ++ /* VLAN */ ++ struct { ++ uint16_t tag_protocol_id1; /**< User defined Tag Protocol Identifier, to be recognized ++ on VLAN TAG on top of 0x8100 and 0x88A8 */ ++ uint16_t tag_protocol_id2; /**< User defined Tag Protocol Identifier, to be recognized ++ on VLAN TAG on top of 0x8100 and 0x88A8 */ ++ } vlan_prs_options; ++ ++ /* PPP */ ++ struct{ ++ bool enable_mtu_check; /**< Check validity of MTU according to RFC2516 */ ++ } pppoe_prs_options; ++ ++ /* IPV6 */ ++ struct { ++ bool routing_hdr_disable; /**< Disable routing header */ ++ } ipv6_prs_options; ++ ++ /* UDP */ ++ struct { ++ bool pad_ignore_checksum; /**< TRUE to ignore pad in checksum */ ++ } udp_prs_options; ++ ++ /* TCP */ ++ struct { ++ bool pad_ignore_checksum; /**< TRUE to ignore pad in checksum */ ++ } tcp_prs_options; ++} ioc_fm_pcd_hdr_prs_opts_u; ++ ++/**************************************************************************//** ++ @Description A structure for defining each header for the parser ++ (must match struct t_FmPcdPrsAdditionalHdrParams defined in fm_port_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_prs_additional_hdr_params_t { ++ ioc_net_header_type hdr; /**< Selected header */ ++ bool err_disable; /**< TRUE to disable error indication */ ++ bool soft_prs_enable; /**< Enable jump to SW parser when this ++ header is recognized by the HW parser. */ ++ uint8_t index_per_hdr; /**< Normally 0, if more than one sw parser ++ attachments exists for the same header, ++ (in the main sw parser code) use this ++ index to distinguish between them. */ ++ bool use_prs_opts; /**< TRUE to use parser options. */ ++ ioc_fm_pcd_hdr_prs_opts_u prs_opts; /**< A unuion according to header type, ++ defining the parser options selected.*/ ++} ioc_fm_pcd_prs_additional_hdr_params_t; ++ ++/**************************************************************************//** ++ @Description A structure for defining port PCD parameters ++ (Must match t_FmPortPcdPrsParams defined in fm_port_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_port_pcd_prs_params_t { ++ uint8_t prs_res_priv_info; /**< The private info provides a method of inserting ++ port information into the parser result. This information ++ may be extracted by KeyGen and be used for frames ++ distribution when a per-port distinction is required, ++ it may also be used as a port logical id for analyzing ++ incoming frames. */ ++ uint8_t parsing_offset; /**< Number of bytes from begining of packet to start parsing */ ++ ioc_net_header_type first_prs_hdr; /**< The type of the first header axpected at 'parsing_offset' */ ++ bool include_in_prs_statistics; /**< TRUE to include this port in the parser statistics */ ++ uint8_t num_of_hdrs_with_additional_params; ++ /**< Normally 0, some headers may get special parameters */ ++ ioc_fm_pcd_prs_additional_hdr_params_t additional_params[IOC_FM_PCD_PRS_NUM_OF_HDRS]; ++ /**< 'num_of_hdrs_with_additional_params' structures ++ additional parameters for each header that requires them */ ++ bool set_vlan_tpid1; /**< TRUE to configure user selection of Ethertype to ++ indicate a VLAN tag (in addition to the TPID values ++ 0x8100 and 0x88A8). */ ++ uint16_t vlan_tpid1; /**< extra tag to use if set_vlan_tpid1=TRUE. */ ++ bool set_vlan_tpid2; /**< TRUE to configure user selection of Ethertype to ++ indicate a VLAN tag (in addition to the TPID values ++ 0x8100 and 0x88A8). */ ++ uint16_t vlan_tpid2; /**< extra tag to use if set_vlan_tpid1=TRUE. */ ++} ioc_fm_port_pcd_prs_params_t; ++ ++/**************************************************************************//** ++ @Description A structure for defining coarse alassification parameters ++ (Must match t_FmPortPcdCcParams defined in fm_port_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_port_pcd_cc_params_t { ++ void *cc_tree_id; /**< CC tree id */ ++} ioc_fm_port_pcd_cc_params_t; ++ ++/**************************************************************************//** ++ @Description A structure for defining keygen parameters ++ (Must match t_FmPortPcdKgParams defined in fm_port_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_port_pcd_kg_params_t { ++ uint8_t num_of_schemes; /**< Number of schemes for port to be bound to. */ ++ void *scheme_ids[FM_PCD_KG_NUM_OF_SCHEMES]; ++ /**< Array of 'num_of_schemes' schemes for the ++ port to be bound to */ ++ bool direct_scheme; /**< TRUE for going from parser to a specific scheme, ++ regardless of parser result */ ++ void *direct_scheme_id; /**< Scheme id, as returned by FM_PCD_KgSetScheme; ++ relevant only if direct=TRUE. */ ++} ioc_fm_port_pcd_kg_params_t; ++ ++/**************************************************************************//** ++ @Description A structure for defining policer parameters ++ (Must match t_FmPortPcdPlcrParams defined in fm_port_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_port_pcd_plcr_params_t { ++ void *plcr_profile_id; /**< Selected profile handle; ++ relevant in one of the following cases: ++ e_IOC_FM_PORT_PCD_SUPPORT_PLCR_ONLY or ++ e_IOC_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR were selected, ++ or if any flow uses a KG scheme where policer ++ profile is not generated (bypass_plcr_profile_generation selected) */ ++} ioc_fm_port_pcd_plcr_params_t; ++ ++/**************************************************************************//** ++ @Description A structure for defining port PCD parameters ++ (Must match struct t_FmPortPcdParams defined in fm_port_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_port_pcd_params_t { ++ ioc_fm_port_pcd_support pcd_support; /**< Relevant for Rx and offline ports only. ++ Describes the active PCD engines for this port. */ ++ void *net_env_id; /**< HL Unused in PLCR only mode */ ++ ioc_fm_port_pcd_prs_params_t *p_prs_params; /**< Parser parameters for this port */ ++ ioc_fm_port_pcd_cc_params_t *p_cc_params; /**< Coarse classification parameters for this port */ ++ ioc_fm_port_pcd_kg_params_t *p_kg_params; /**< Keygen parameters for this port */ ++ ioc_fm_port_pcd_plcr_params_t *p_plcr_params; /**< Policer parameters for this port */ ++ void *p_ip_reassembly_manip;/**< IP Reassembly manipulation */ ++#if (DPAA_VERSION >= 11) ++ void *p_capwap_reassembly_manip;/**< CAPWAP Reassembly manipulation */ ++#endif /* (DPAA_VERSION >= 11) */ ++} ioc_fm_port_pcd_params_t; ++ ++/**************************************************************************//** ++ @Description A structure for defining the Parser starting point ++ (Must match struct t_FmPcdPrsStart defined in fm_port_ext.h) ++*//***************************************************************************/ ++typedef struct ioc_fm_pcd_prs_start_t { ++ uint8_t parsing_offset; /**< Number of bytes from begining of packet to ++ start parsing */ ++ ioc_net_header_type first_prs_hdr; /**< The type of the first header axpected at ++ 'parsing_offset' */ ++} ioc_fm_pcd_prs_start_t; ++ ++ ++/**************************************************************************//** ++ @Description FQID parameters structure ++*//***************************************************************************/ ++typedef struct ioc_fm_port_pcd_fqids_params_t { ++ uint32_t num_fqids; /**< Number of fqids to be allocated for the port */ ++ uint8_t alignment; /**< Alignment required for this port */ ++ uint32_t base_fqid; /**< output parameter - the base fqid */ ++} ioc_fm_port_pcd_fqids_params_t; ++ ++ ++/**************************************************************************//** ++ @Function FM_PORT_IOC_ALLOC_PCD_FQIDS ++ ++ @Description Allocates FQID's ++ ++ May be used for Rx and offline parsing ports only ++ ++ @Param[in,out] ioc_fm_port_pcd_fqids_params_t Parameters for allocating FQID's ++ ++ @Return 0 on success; error code otherwise. ++*//***************************************************************************/ ++#define FM_PORT_IOC_ALLOC_PCD_FQIDS _IOWR(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(19), ioc_fm_port_pcd_fqids_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PORT_IOC_FREE_PCD_FQIDS ++ ++ @Description Frees previously-allocated FQIDs ++ ++ May be used for Rx and offline parsing ports only ++ ++ @Param[in] uint32_t Base FQID of previously allocated range. ++ ++ @Return 0 on success; error code otherwise. ++*//***************************************************************************/ ++#define FM_PORT_IOC_FREE_PCD_FQIDS _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(19), uint32_t) ++ ++ ++/**************************************************************************//** ++ @Function FM_PORT_SetPCD ++ ++ @Description Calling this routine defines the port's PCD configuration. ++ It changes it from its default configuration which is PCD ++ disabled (BMI to BMI) and configures it according to the passed ++ parameters. ++ ++ May be used for Rx and offline parsing ports only ++ ++ @Param[in] ioc_fm_port_pcd_params_t A Structure of parameters defining the port's PCD ++ configuration. ++ ++ @Return 0 on success; error code otherwise. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PORT_IOC_SET_PCD_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(20), ioc_compat_fm_port_pcd_params_t) ++#endif ++#define FM_PORT_IOC_SET_PCD _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(20), ioc_fm_port_pcd_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PORT_DeletePCD ++ ++ @Description Calling this routine releases the port's PCD configuration. ++ The port returns to its default configuration which is PCD ++ disabled (BMI to BMI) and all PCD configuration is removed. ++ ++ May be used for Rx and offline parsing ports which are ++ in PCD mode only ++ ++ @Return 0 on success; error code otherwise. ++*//***************************************************************************/ ++#define FM_PORT_IOC_DELETE_PCD _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(21)) ++ ++/**************************************************************************//** ++ @Function FM_PORT_AttachPCD ++ ++ @Description This routine may be called after FM_PORT_DetachPCD was called, ++ to return to the originally configured PCD support flow. ++ The couple of routines are used to allow PCD configuration changes ++ that demand that PCD will not be used while changes take place. ++ ++ May be used for Rx and offline parsing ports which are ++ in PCD mode only ++ ++ @Return 0 on success; error code otherwise. ++*//***************************************************************************/ ++#define FM_PORT_IOC_ATTACH_PCD _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(23)) ++ ++/**************************************************************************//** ++ @Function FM_PORT_DetachPCD ++ ++ @Description Calling this routine detaches the port from its PCD functionality. ++ The port returns to its default flow which is BMI to BMI. ++ ++ May be used for Rx and offline parsing ports which are ++ in PCD mode only ++ ++ @Return 0 on success; error code otherwise. ++*//***************************************************************************/ ++#define FM_PORT_IOC_DETACH_PCD _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(22)) ++ ++/**************************************************************************//** ++ @Function FM_PORT_PcdPlcrAllocProfiles ++ ++ @Description This routine may be called only for ports that use the Policer in ++ order to allocate private policer profiles. ++ ++ @Param[in] uint16_t The number of required policer profiles ++ ++ @Return 0 on success; error code otherwise. ++ ++ @Cautions Allowed before FM_PORT_SetPCD() only. ++*//***************************************************************************/ ++#define FM_PORT_IOC_PCD_PLCR_ALLOC_PROFILES _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(24), uint16_t) ++ ++/**************************************************************************//** ++ @Function FM_PORT_PcdPlcrFreeProfiles ++ ++ @Description This routine should be called for freeing private policer profiles. ++ ++ @Return 0 on success; error code otherwise. ++ ++ @Cautions Allowed before FM_PORT_SetPCD() only. ++*//***************************************************************************/ ++#define FM_PORT_IOC_PCD_PLCR_FREE_PROFILES _IO(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(25)) ++ ++/**************************************************************************//** ++ @Function FM_PORT_PcdKgModifyInitialScheme ++ ++ @Description This routine may be called only for ports that use the keygen in ++ order to change the initial scheme frame should be routed to. ++ The change may be of a scheme id (in case of direct mode), ++ from direct to indirect, or from indirect to direct - specifying the scheme id. ++ ++ @Param[in] ioc_fm_pcd_kg_scheme_select_t A structure of parameters for defining whether ++ a scheme is direct/indirect, and if direct - scheme id. ++ ++ @Return 0 on success; error code otherwise. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PORT_IOC_PCD_KG_MODIFY_INITIAL_SCHEME_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(26), ioc_compat_fm_pcd_kg_scheme_select_t) ++#endif ++#define FM_PORT_IOC_PCD_KG_MODIFY_INITIAL_SCHEME _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(26), ioc_fm_pcd_kg_scheme_select_t) ++ ++/**************************************************************************//** ++ @Function FM_PORT_PcdPlcrModifyInitialProfile ++ ++ @Description This routine may be called for ports with flows ++ e_IOC_FM_PCD_SUPPORT_PLCR_ONLY or e_IOC_FM_PCD_SUPPORT_PRS_AND_PLCR only, ++ to change the initial Policer profile frame should be routed to. ++ The change may be of a profile and/or absolute/direct mode selection. ++ ++ @Param[in] ioc_fm_obj_t Policer profile Id as returned from FM_PCD_PlcrSetProfile. ++ ++ @Return 0 on success; error code otherwise. ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PORT_IOC_PCD_PLCR_MODIFY_INITIAL_PROFILE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(27), ioc_compat_fm_obj_t) ++#endif ++#define FM_PORT_IOC_PCD_PLCR_MODIFY_INITIAL_PROFILE _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(27), ioc_fm_obj_t) ++ ++/**************************************************************************//** ++ @Function FM_PORT_PcdCcModifyTree ++ ++ @Description This routine may be called to change this port connection to ++ a pre-initializes coarse classification Tree. ++ ++ @Param[in] ioc_fm_obj_t Id of new coarse classification tree selected for this port. ++ ++ @Return 0 on success; error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_SetPCD() and FM_PORT_DetachPCD() ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PORT_IOC_PCD_CC_MODIFY_TREE_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(28), ioc_compat_fm_obj_t) ++#endif ++#define FM_PORT_IOC_PCD_CC_MODIFY_TREE _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(28), ioc_fm_obj_t) ++ ++/**************************************************************************//** ++ @Function FM_PORT_PcdKgBindSchemes ++ ++ @Description These routines may be called for modifying the binding of ports ++ to schemes. The scheme itself is not added, ++ just this specific port starts using it. ++ ++ @Param[in] ioc_fm_pcd_port_schemes_params_t Schemes parameters structre ++ ++ @Return 0 on success; error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_SetPCD(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PORT_IOC_PCD_KG_BIND_SCHEMES_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(30), ioc_compat_fm_pcd_port_schemes_params_t) ++#endif ++#define FM_PORT_IOC_PCD_KG_BIND_SCHEMES _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(30), ioc_fm_pcd_port_schemes_params_t) ++ ++/**************************************************************************//** ++ @Function FM_PORT_PcdKgUnbindSchemes ++ ++ @Description These routines may be called for modifying the binding of ports ++ to schemes. The scheme itself is not removed or invalidated, ++ just this specific port stops using it. ++ ++ @Param[in] ioc_fm_pcd_port_schemes_params_t Schemes parameters structre ++ ++ @Return 0 on success; error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_SetPCD(). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PORT_IOC_PCD_KG_UNBIND_SCHEMES_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(31), ioc_compat_fm_pcd_port_schemes_params_t) ++#endif ++#define FM_PORT_IOC_PCD_KG_UNBIND_SCHEMES _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(31), ioc_fm_pcd_port_schemes_params_t) ++ ++typedef struct ioc_fm_port_mac_addr_params_t { ++ uint8_t addr[ENET_NUM_OCTETS_PER_ADDRESS]; ++} ioc_fm_port_mac_addr_params_t; ++ ++/**************************************************************************//** ++ @Function FM_MAC_AddHashMacAddr ++ ++ @Description Add an Address to the hash table. This is for filter purpose only. ++ ++ @Param[in] ioc_fm_port_mac_addr_params_t - Ethernet Mac address ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Init(). It is a filter only address. ++ @Cautions Some address need to be filtered out in upper FM blocks. ++*//***************************************************************************/ ++#define FM_PORT_IOC_ADD_RX_HASH_MAC_ADDR _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(36), ioc_fm_port_mac_addr_params_t) ++ ++/**************************************************************************//** ++ @Function FM_MAC_RemoveHashMacAddr ++ ++ @Description Delete an Address to the hash table. This is for filter purpose only. ++ ++ @Param[in] ioc_fm_port_mac_addr_params_t - Ethernet Mac address ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Init(). ++*//***************************************************************************/ ++#define FM_PORT_IOC_REMOVE_RX_HASH_MAC_ADDR _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(37), ioc_fm_port_mac_addr_params_t) ++ ++typedef struct ioc_fm_port_tx_pause_frames_params_t { ++ uint8_t priority; ++ uint16_t pause_time; ++ uint16_t thresh_time; ++} ioc_fm_port_tx_pause_frames_params_t; ++ ++/**************************************************************************//** ++ @Function FM_MAC_SetTxPauseFrames ++ ++ @Description Enable/Disable transmission of Pause-Frames. ++ The routine changes the default configuration: ++ pause-time - [0xf000] ++ threshold-time - [0] ++ ++ @Param[in] ioc_fm_port_tx_pause_frames_params_t A structure holding the required parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_MAC_Init(). ++ PFC is supported only on new mEMAC; i.e. in MACs that don't have ++ PFC support (10G-MAC and dTSEC), user should use 'FM_MAC_NO_PFC' ++ in the 'priority' field. ++*//***************************************************************************/ ++#define FM_PORT_IOC_SET_TX_PAUSE_FRAMES _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(40), ioc_fm_port_tx_pause_frames_params_t) ++ ++typedef struct ioc_fm_port_mac_statistics_t { ++ /* RMON */ ++ uint64_t e_stat_pkts_64; /**< r-10G tr-DT 64 byte frame counter */ ++ uint64_t e_stat_pkts_65_to_127; /**< r-10G 65 to 127 byte frame counter */ ++ uint64_t e_stat_pkts_128_to_255; /**< r-10G 128 to 255 byte frame counter */ ++ uint64_t e_stat_pkts_256_to_511; /**< r-10G 256 to 511 byte frame counter */ ++ uint64_t e_stat_pkts_512_to_1023; /**< r-10G 512 to 1023 byte frame counter */ ++ uint64_t e_stat_pkts_1024_to_1518; /**< r-10G 1024 to 1518 byte frame counter */ ++ uint64_t e_stat_pkts_1519_to_1522; /**< r-10G 1519 to 1522 byte good frame count */ ++ /* */ ++ uint64_t e_stat_fragments; /**< Total number of packets that were less than 64 octets long with a wrong CRC.*/ ++ uint64_t e_stat_jabbers; /**< Total number of packets longer than valid maximum length octets */ ++ uint64_t e_stat_drop_events; /**< number of dropped packets due to internal errors of the MAC Client (during recieve). */ ++ uint64_t e_stat_CRC_align_errors; /**< Incremented when frames of correct length but with CRC error are received.*/ ++ uint64_t e_stat_undersize_pkts; /**< Incremented for frames under 64 bytes with a valid FCS and otherwise well formed; ++ This count does not include range length errors */ ++ uint64_t e_stat_oversize_pkts; /**< Incremented for frames which exceed 1518 (non VLAN) or 1522 (VLAN) and contains ++ a valid FCS and otherwise well formed */ ++ /* Pause */ ++ uint64_t te_stat_pause; /**< Pause MAC Control received */ ++ uint64_t re_stat_pause; /**< Pause MAC Control sent */ ++ /* MIB II */ ++ uint64_t if_in_octets; /**< Total number of byte received. */ ++ uint64_t if_in_pkts; /**< Total number of packets received.*/ ++ uint64_t if_in_ucast_pkts; /**< Total number of unicast frame received; ++ NOTE: this counter is not supported on dTSEC MAC */ ++ uint64_t if_in_mcast_pkts; /**< Total number of multicast frame received*/ ++ uint64_t if_in_bcast_pkts; /**< Total number of broadcast frame received */ ++ uint64_t if_in_discards; /**< Frames received, but discarded due to problems within the MAC RX. */ ++ uint64_t if_in_errors; /**< Number of frames received with error: ++ - FIFO Overflow Error ++ - CRC Error ++ - Frame Too Long Error ++ - Alignment Error ++ - The dedicated Error Code (0xfe, not a code error) was received */ ++ uint64_t if_out_octets; /**< Total number of byte sent. */ ++ uint64_t if_out_pkts; /**< Total number of packets sent .*/ ++ uint64_t if_out_ucast_pkts; /**< Total number of unicast frame sent; ++ NOTE: this counter is not supported on dTSEC MAC */ ++ uint64_t if_out_mcast_pkts; /**< Total number of multicast frame sent */ ++ uint64_t if_out_bcast_pkts; /**< Total number of multicast frame sent */ ++ uint64_t if_out_discards; /**< Frames received, but discarded due to problems within the MAC TX N/A!.*/ ++ uint64_t if_out_errors; /**< Number of frames transmitted with error: ++ - FIFO Overflow Error ++ - FIFO Underflow Error ++ - Other */ ++} ioc_fm_port_mac_statistics_t; ++ ++/**************************************************************************//** ++ @Function FM_MAC_GetStatistics ++ ++ @Description get all MAC statistics counters ++ ++ @Param[out] ioc_fm_port_mac_statistics_t A structure holding the statistics ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_Init(). ++*//***************************************************************************/ ++#define FM_PORT_IOC_GET_MAC_STATISTICS _IOR(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(41), ioc_fm_port_mac_statistics_t) ++ ++/**************************************************************************//** ++ @Function FM_PORT_ConfigBufferPrefixContent ++ ++ @Description Defines the structure, size and content of the application buffer. ++ The prefix will ++ In Tx ports, if 'passPrsResult', the application ++ should set a value to their offsets in the prefix of ++ the FM will save the first 'privDataSize', than, ++ depending on 'passPrsResult' and 'passTimeStamp', copy parse result ++ and timeStamp, and the packet itself (in this order), to the ++ application buffer, and to offset. ++ Calling this routine changes the buffer margins definitions ++ in the internal driver data base from its default ++ configuration: Data size: [DEFAULT_FM_SP_bufferPrefixContent_privDataSize] ++ Pass Parser result: [DEFAULT_FM_SP_bufferPrefixContent_passPrsResult]. ++ Pass timestamp: [DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp]. ++ ++ May be used for all ports ++ ++ @Param[in] ioc_fm_buffer_prefix_content_t A structure holding the required parameters. ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Config() and before FM_PORT_Init(). ++*//***************************************************************************/ ++#define FM_PORT_IOC_CONFIG_BUFFER_PREFIX_CONTENT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(39), ioc_fm_buffer_prefix_content_t) ++ ++#if (DPAA_VERSION >= 11) ++typedef struct ioc_fm_port_vsp_alloc_params_t { ++ uint8_t num_of_profiles; /**< Number of Virtual Storage Profiles */ ++ uint8_t dflt_relative_id; /**< The default Virtual-Storage-Profile-id dedicated to Rx/OP port ++ The same default Virtual-Storage-Profile-id will be for coupled Tx port ++ if relevant function called for Rx port */ ++ void *p_fm_tx_port; /**< Handle to coupled Tx Port; not relevant for OP port. */ ++}ioc_fm_port_vsp_alloc_params_t; ++ ++/**************************************************************************//** ++ @Function FM_PORT_VSPAlloc ++ ++ @Description This routine allocated VSPs per port and forces the port to work ++ in VSP mode. Note that the port is initialized by default with the ++ physical-storage-profile only. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[in] p_Params A structure of parameters for allocation VSP's per port ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(), and before FM_PORT_SetPCD() ++ and also before FM_PORT_Enable() (i.e. the port should be disabled). ++*//***************************************************************************/ ++#if defined(CONFIG_COMPAT) ++#define FM_PORT_IOC_VSP_ALLOC_COMPAT _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(38), ioc_compat_fm_port_vsp_alloc_params_t) ++#endif ++#define FM_PORT_IOC_VSP_ALLOC _IOW(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(38), ioc_fm_port_vsp_alloc_params_t) ++#endif /* (DPAA_VERSION >= 11) */ ++ ++/**************************************************************************//** ++ @Function FM_PORT_GetBmiCounters ++ ++ @Description Read port's BMI stat counters and place them into ++ a designated structure of counters. ++ ++ @Param[in] h_FmPort A handle to a FM Port module. ++ @Param[out] p_BmiStats counters structure ++ ++ @Return E_OK on success; Error code otherwise. ++ ++ @Cautions Allowed only following FM_PORT_Init(). ++*//***************************************************************************/ ++ ++#define FM_PORT_IOC_GET_BMI_COUNTERS _IOR(FM_IOC_TYPE_BASE, FM_PORT_IOC_NUM(42), ioc_fm_port_bmi_stats_t) ++ ++ ++/** @} */ /* end of lnx_ioctl_FM_PORT_pcd_runtime_control_grp group */ ++/** @} */ /* end of lnx_ioctl_FM_PORT_runtime_control_grp group */ ++ ++/** @} */ /* end of lnx_ioctl_FM_PORT_grp group */ ++/** @} */ /* end of lnx_ioctl_FM_grp group */ ++#endif /* __FM_PORT_IOCTLS_H */ +diff --git a/include/uapi/linux/fmd/Peripherals/fm_test_ioctls.h b/include/uapi/linux/fmd/Peripherals/fm_test_ioctls.h +new file mode 100644 +index 00000000..207ed1eb +--- /dev/null ++++ b/include/uapi/linux/fmd/Peripherals/fm_test_ioctls.h +@@ -0,0 +1,208 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/**************************************************************************//** ++ @File fm_test_ioctls.h ++ ++ @Description FM Char device ioctls ++*//***************************************************************************/ ++#ifndef __FM_TEST_IOCTLS_H ++#define __FM_TEST_IOCTLS_H ++ ++#include "ioctls.h" ++ ++ ++/**************************************************************************//** ++ @Group lnx_ioctl_FMT_grp Frame Manager Test Linux IOCTL API ++ ++ @Description FM-Test Linux ioctls definitions and enums ++ ++ @{ ++*//***************************************************************************/ ++ ++#define IOC_FMT_MAX_NUM_OF_PORTS 26 ++ ++/**************************************************************************//** ++ @Collection TEST Parameters ++*//***************************************************************************/ ++/**************************************************************************//** ++ @Description: Name of the FM-Test chardev ++*//***************************************************************************/ ++#define DEV_FM_TEST_NAME "fm-test-port" ++ ++#define DEV_FM_TEST_PORTS_MINOR_BASE 0 ++#define DEV_FM_TEST_MAX_MINORS (DEV_FM_TEST_PORTS_MINOR_BASE + IOC_FMT_MAX_NUM_OF_PORTS) ++ ++#define FMT_PORT_IOC_NUM(n) n ++/* @} */ ++ ++/**************************************************************************//** ++ @Group lnx_ioctl_FMT_lib_grp FM-Test library ++ ++ @Description TODO ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description TODO ++*//***************************************************************************/ ++typedef uint8_t ioc_fmt_xxx_t; ++ ++#define FM_PRS_MAX 32 ++#define FM_TIME_STAMP_MAX 8 ++ ++/**************************************************************************//** ++ @Description FM Port buffer content description ++*//***************************************************************************/ ++typedef struct ioc_fmt_buff_context_t { ++ void *p_user_priv; ++ uint8_t fm_prs_res[FM_PRS_MAX]; ++ uint8_t fm_time_stamp[FM_TIME_STAMP_MAX]; ++} ioc_fmt_buff_context_t; ++ ++#if defined(__KERNEL__) && defined(CONFIG_COMPAT) ++typedef struct ioc_fmt_compat_buff_context_t { ++ compat_uptr_t p_user_priv; ++ uint8_t fm_prs_res[FM_PRS_MAX]; ++ uint8_t fm_time_stamp[FM_TIME_STAMP_MAX]; ++} ioc_fmt_compat_buff_context_t; ++#endif ++ ++/**************************************************************************//** ++ @Description Buffer descriptor ++*//***************************************************************************/ ++typedef struct ioc_fmt_buff_desc_t { ++ uint32_t qid; ++ void *p_data; ++ uint32_t size; ++ uint32_t status; ++ ioc_fmt_buff_context_t buff_context; ++} ioc_fmt_buff_desc_t; ++ ++#if defined(__KERNEL__) && defined(CONFIG_COMPAT) ++typedef struct ioc_fmt_compat_buff_desc_t { ++ uint32_t qid; ++ compat_uptr_t p_data; ++ uint32_t size; ++ uint32_t status; ++ ioc_fmt_compat_buff_context_t buff_context; ++} ioc_fmt_compat_buff_desc_t; ++#endif ++ ++/**************************************************************************//** ++ @Group lnx_ioctl_FMT_runtime_control_grp FM-Test Runtime Control Unit ++ ++ @Description TODO ++ @{ ++*//***************************************************************************/ ++ ++/** @} */ /* end of lnx_ioctl_FMT_runtime_control_grp group */ ++ ++ ++/**************************************************************************//** ++ @Group lnx_ioctl_FMTP_lib_grp FM-Port-Test library ++ ++ @Description TODO ++ ++ @{ ++*//***************************************************************************/ ++ ++/**************************************************************************//** ++ @Description FM-Test FM port type ++*//***************************************************************************/ ++typedef enum ioc_fmt_port_type { ++ e_IOC_FMT_PORT_T_RXTX, /**< Standard port */ ++ e_IOC_FMT_PORT_T_OP, /**< Offline-parsing port */ ++} ioc_fmt_port_type; ++ ++/**************************************************************************//** ++ @Description TODO ++*//***************************************************************************/ ++typedef struct ioc_fmt_port_param_t { ++ uint8_t fm_id; ++ ioc_fmt_port_type fm_port_type; ++ uint8_t fm_port_id; ++ uint32_t num_tx_queues; ++} ioc_fmt_port_param_t; ++ ++ ++/**************************************************************************//** ++ @Function FMT_PORT_IOC_INIT ++ ++ @Description TODO ++ ++ @Param[in] ioc_fmt_port_param_t TODO ++ ++ @Cautions Allowed only after the FM equivalent port is already initialized. ++*//***************************************************************************/ ++#define FMT_PORT_IOC_INIT _IOW(FMT_IOC_TYPE_BASE, FMT_PORT_IOC_NUM(0), ioc_fmt_port_param_t) ++ ++/**************************************************************************//** ++ @Function FMT_PORT_IOC_SET_DIAG_MODE ++ ++ @Description TODO ++ ++ @Param[in] ioc_diag_mode TODO ++ ++ @Cautions Allowed only following FMT_PORT_IOC_INIT(). ++*//***************************************************************************/ ++#define FMT_PORT_IOC_SET_DIAG_MODE _IOW(FMT_IOC_TYPE_BASE, FMT_PORT_IOC_NUM(1), ioc_diag_mode) ++ ++/**************************************************************************//** ++ @Function FMT_PORT_IOC_SET_IP_HEADER_MANIP ++ ++ @Description Set IP header manipulations for this port. ++ ++ @Param[in] int 1 to enable; 0 to disable ++ ++ @Cautions Allowed only following FMT_PORT_IOC_INIT(). ++*//***************************************************************************/ ++#define FMT_PORT_IOC_SET_IP_HEADER_MANIP _IOW(FMT_IOC_TYPE_BASE, FMT_PORT_IOC_NUM(2), int) ++ ++/**************************************************************************//** ++ @Function FMT_PORT_IOC_SET_DPAECHO_MODE ++ ++ @Description Set DPA in echo mode - all frame are sent back. ++ ++ @Param[in] int 1 to enable; 0 to disable ++ ++ @Cautions Allowed only following FMT_PORT_IOC_INIT(). ++*//***************************************************************************/ ++#define FMT_PORT_IOC_SET_DPAECHO_MODE _IOW(FMT_IOC_TYPE_BASE, FMT_PORT_IOC_NUM(3), int) ++ ++/** @} */ /* end of lnx_ioctl_FMTP_lib_grp group */ ++/** @} */ /* end of lnx_ioctl_FMT_lib_grp group */ ++/** @} */ /* end of lnx_ioctl_FMT_grp */ ++ ++ ++#endif /* __FM_TEST_IOCTLS_H */ +diff --git a/include/uapi/linux/fmd/integrations/Kbuild b/include/uapi/linux/fmd/integrations/Kbuild +new file mode 100644 +index 00000000..e548d676 +--- /dev/null ++++ b/include/uapi/linux/fmd/integrations/Kbuild +@@ -0,0 +1 @@ ++header-y += integration_ioctls.h +diff --git a/include/uapi/linux/fmd/integrations/integration_ioctls.h b/include/uapi/linux/fmd/integrations/integration_ioctls.h +new file mode 100644 +index 00000000..61d696e2 +--- /dev/null ++++ b/include/uapi/linux/fmd/integrations/integration_ioctls.h +@@ -0,0 +1,56 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/**************************************************************************//** ++ @File integration_ioctls.h ++ ++ @Description External header file for Integration unit routines. ++*//***************************************************************************/ ++ ++#ifndef __INTG_IOCTLS_H ++#define __INTG_IOCTLS_H ++ ++ ++#define FM_IOC_TYPE_BASE (NCSW_IOC_TYPE_BASE+1) ++#define FMT_IOC_TYPE_BASE (NCSW_IOC_TYPE_BASE+3) ++ ++/*#define FM_IOCTL_DBG*/ ++ ++#if defined(FM_IOCTL_DBG) ++ #define _fm_ioctl_dbg(format, arg...) \ ++ printk("fm ioctl [%s:%u](cpu:%u) - " format, \ ++ __func__, __LINE__, smp_processor_id(), ##arg) ++#else ++# define _fm_ioctl_dbg(arg...) ++#endif ++ ++#endif /* __INTG_IOCTLS_H */ +diff --git a/include/uapi/linux/fmd/ioctls.h b/include/uapi/linux/fmd/ioctls.h +new file mode 100644 +index 00000000..4f36cb05 +--- /dev/null ++++ b/include/uapi/linux/fmd/ioctls.h +@@ -0,0 +1,96 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/**************************************************************************//** ++ @File ioctls.h ++ ++ @Description Structures and definitions for Command Relay Ioctls ++*//***************************************************************************/ ++ ++#ifndef __IOCTLS_H__ ++#define __IOCTLS_H__ ++ ++#include ++ ++#include "integration_ioctls.h" ++ ++ ++/**************************************************************************//** ++ @Group lnx_ioctl_ncsw_grp NetCommSw Linux User-Space (IOCTL) API ++ @{ ++*//***************************************************************************/ ++ ++#define NCSW_IOC_TYPE_BASE 0xe0 /**< defines the IOCTL type for all ++ the NCSW Linux module commands */ ++ ++ ++/**************************************************************************//** ++ @Description IOCTL Memory allocation types. ++*//***************************************************************************/ ++typedef enum ioc_mem_type { ++ e_IOC_MEM_INVALID = 0x00000000, /**< Invalid memory type (error) */ ++ e_IOC_MEM_CACHABLE_SYS = 0x00000001, /**< Primary DDR, cacheable segment */ ++ e_IOC_MEM_NOCACHE_SYS = 0x00000004, /**< Primary DDR, non-cacheable segment */ ++ e_IOC_MEM_SECONDARY = 0x00000002, /**< Either secondary DDR or SDRAM */ ++ e_IOC_MEM_PRAM = 0x00000008 /**< Multi-user RAM identifier */ ++} ioc_mem_type; ++ ++/**************************************************************************//** ++ @Description Enumeration (bit flags) of communication modes (Transmit, ++ receive or both). ++*//***************************************************************************/ ++typedef enum ioc_comm_mode { ++ e_IOC_COMM_MODE_NONE = 0 /**< No transmit/receive communication */ ++ , e_IOC_COMM_MODE_RX = 1 /**< Only receive communication */ ++ , e_IOC_COMM_MODE_TX = 2 /**< Only transmit communication */ ++ , e_IOC_COMM_MODE_RX_AND_TX = 3 /**< Both transmit and receive communication */ ++} ioc_comm_mode; ++ ++/**************************************************************************//** ++ @Description General Diagnostic Mode ++*//***************************************************************************/ ++typedef enum ioc_diag_mode ++{ ++ e_IOC_DIAG_MODE_NONE = 0, ++ e_IOC_DIAG_MODE_CTRL_LOOPBACK, /**< loopback in the controller; E.g. MAC, TDM, etc. */ ++ e_IOC_DIAG_MODE_CHIP_LOOPBACK, /**< loopback in the chip but not in controller; ++ E.g. IO-pins, SerDes, etc. */ ++ e_IOC_DIAG_MODE_PHY_LOOPBACK, /**< loopback in the external PHY */ ++ e_IOC_DIAG_MODE_LINE_LOOPBACK, /**< loopback in the external line */ ++ e_IOC_DIAG_MODE_CTRL_ECHO, /**< */ ++ e_IOC_DIAG_MODE_PHY_ECHO /**< */ ++} ioc_diag_mode; ++ ++/** @} */ /* end of lnx_ioctl_ncsw_grp */ ++ ++ ++#endif /* __IOCTLS_H__ */ +diff --git a/include/uapi/linux/fmd/net_ioctls.h b/include/uapi/linux/fmd/net_ioctls.h +new file mode 100644 +index 00000000..c99d64cf +--- /dev/null ++++ b/include/uapi/linux/fmd/net_ioctls.h +@@ -0,0 +1,430 @@ ++/* Copyright (c) 2008-2012 Freescale Semiconductor, Inc. ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++ ++/**************************************************************************//** ++ @File net_ioctls.h ++ ++ @Description This file contains common and general netcomm headers definitions. ++*//***************************************************************************/ ++#ifndef __NET_IOCTLS_H ++#define __NET_IOCTLS_H ++ ++#include "ioctls.h" ++ ++ ++typedef uint8_t ioc_header_field_ppp_t; ++ ++#define IOC_NET_HEADER_FIELD_PPP_PID (1) ++#define IOC_NET_HEADER_FIELD_PPP_COMPRESSED (IOC_NET_HEADER_FIELD_PPP_PID << 1) ++#define IOC_NET_HEADER_FIELD_PPP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_PPP_PID << 2) - 1) ++ ++ ++typedef uint8_t ioc_header_field_pppoe_t; ++ ++#define IOC_NET_HEADER_FIELD_PPPoE_VER (1) ++#define IOC_NET_HEADER_FIELD_PPPoE_TYPE (IOC_NET_HEADER_FIELD_PPPoE_VER << 1) ++#define IOC_NET_HEADER_FIELD_PPPoE_CODE (IOC_NET_HEADER_FIELD_PPPoE_VER << 2) ++#define IOC_NET_HEADER_FIELD_PPPoE_SID (IOC_NET_HEADER_FIELD_PPPoE_VER << 3) ++#define IOC_NET_HEADER_FIELD_PPPoE_LEN (IOC_NET_HEADER_FIELD_PPPoE_VER << 4) ++#define IOC_NET_HEADER_FIELD_PPPoE_SESSION (IOC_NET_HEADER_FIELD_PPPoE_VER << 5) ++#define IOC_NET_HEADER_FIELD_PPPoE_PID (IOC_NET_HEADER_FIELD_PPPoE_VER << 6) ++#define IOC_NET_HEADER_FIELD_PPPoE_ALL_FIELDS ((IOC_NET_HEADER_FIELD_PPPoE_VER << 7) - 1) ++ ++#define IOC_NET_HEADER_FIELD_PPPMUX_PID (1) ++#define IOC_NET_HEADER_FIELD_PPPMUX_CKSUM (IOC_NET_HEADER_FIELD_PPPMUX_PID << 1) ++#define IOC_NET_HEADER_FIELD_PPPMUX_COMPRESSED (IOC_NET_HEADER_FIELD_PPPMUX_PID << 2) ++#define IOC_NET_HEADER_FIELD_PPPMUX_ALL_FIELDS ((IOC_NET_HEADER_FIELD_PPPMUX_PID << 3) - 1) ++ ++#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF (1) ++#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_LXT (IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 1) ++#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_LEN (IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 2) ++#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PID (IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 3) ++#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_USE_PID (IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 4) ++#define IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_ALL_FIELDS ((IOC_NET_HEADER_FIELD_PPPMUX_SUBFRAME_PFF << 5) - 1) ++ ++ ++typedef uint8_t ioc_header_field_eth_t; ++ ++#define IOC_NET_HEADER_FIELD_ETH_DA (1) ++#define IOC_NET_HEADER_FIELD_ETH_SA (IOC_NET_HEADER_FIELD_ETH_DA << 1) ++#define IOC_NET_HEADER_FIELD_ETH_LENGTH (IOC_NET_HEADER_FIELD_ETH_DA << 2) ++#define IOC_NET_HEADER_FIELD_ETH_TYPE (IOC_NET_HEADER_FIELD_ETH_DA << 3) ++#define IOC_NET_HEADER_FIELD_ETH_FINAL_CKSUM (IOC_NET_HEADER_FIELD_ETH_DA << 4) ++#define IOC_NET_HEADER_FIELD_ETH_PADDING (IOC_NET_HEADER_FIELD_ETH_DA << 5) ++#define IOC_NET_HEADER_FIELD_ETH_ALL_FIELDS ((IOC_NET_HEADER_FIELD_ETH_DA << 6) - 1) ++ ++#define IOC_NET_HEADER_FIELD_ETH_ADDR_SIZE 6 ++ ++typedef uint16_t ioc_header_field_ip_t; ++ ++#define IOC_NET_HEADER_FIELD_IP_VER (1) ++#define IOC_NET_HEADER_FIELD_IP_DSCP (IOC_NET_HEADER_FIELD_IP_VER << 2) ++#define IOC_NET_HEADER_FIELD_IP_ECN (IOC_NET_HEADER_FIELD_IP_VER << 3) ++#define IOC_NET_HEADER_FIELD_IP_PROTO (IOC_NET_HEADER_FIELD_IP_VER << 4) ++ ++#define IOC_NET_HEADER_FIELD_IP_PROTO_SIZE 1 ++ ++typedef uint16_t ioc_header_field_ipv4_t; ++ ++#define IOC_NET_HEADER_FIELD_IPv4_VER (1) ++#define IOC_NET_HEADER_FIELD_IPv4_HDR_LEN (IOC_NET_HEADER_FIELD_IPv4_VER << 1) ++#define IOC_NET_HEADER_FIELD_IPv4_TOS (IOC_NET_HEADER_FIELD_IPv4_VER << 2) ++#define IOC_NET_HEADER_FIELD_IPv4_TOTAL_LEN (IOC_NET_HEADER_FIELD_IPv4_VER << 3) ++#define IOC_NET_HEADER_FIELD_IPv4_ID (IOC_NET_HEADER_FIELD_IPv4_VER << 4) ++#define IOC_NET_HEADER_FIELD_IPv4_FLAG_D (IOC_NET_HEADER_FIELD_IPv4_VER << 5) ++#define IOC_NET_HEADER_FIELD_IPv4_FLAG_M (IOC_NET_HEADER_FIELD_IPv4_VER << 6) ++#define IOC_NET_HEADER_FIELD_IPv4_OFFSET (IOC_NET_HEADER_FIELD_IPv4_VER << 7) ++#define IOC_NET_HEADER_FIELD_IPv4_TTL (IOC_NET_HEADER_FIELD_IPv4_VER << 8) ++#define IOC_NET_HEADER_FIELD_IPv4_PROTO (IOC_NET_HEADER_FIELD_IPv4_VER << 9) ++#define IOC_NET_HEADER_FIELD_IPv4_CKSUM (IOC_NET_HEADER_FIELD_IPv4_VER << 10) ++#define IOC_NET_HEADER_FIELD_IPv4_SRC_IP (IOC_NET_HEADER_FIELD_IPv4_VER << 11) ++#define IOC_NET_HEADER_FIELD_IPv4_DST_IP (IOC_NET_HEADER_FIELD_IPv4_VER << 12) ++#define IOC_NET_HEADER_FIELD_IPv4_OPTS (IOC_NET_HEADER_FIELD_IPv4_VER << 13) ++#define IOC_NET_HEADER_FIELD_IPv4_OPTS_COUNT (IOC_NET_HEADER_FIELD_IPv4_VER << 14) ++#define IOC_NET_HEADER_FIELD_IPv4_ALL_FIELDS ((IOC_NET_HEADER_FIELD_IPv4_VER << 15) - 1) ++ ++#define IOC_NET_HEADER_FIELD_IPv4_ADDR_SIZE 4 ++#define IOC_NET_HEADER_FIELD_IPv4_PROTO_SIZE 1 ++ ++ ++typedef uint8_t ioc_header_field_ipv6_t; ++ ++#define IOC_NET_HEADER_FIELD_IPv6_VER (1) ++#define IOC_NET_HEADER_FIELD_IPv6_TC (IOC_NET_HEADER_FIELD_IPv6_VER << 1) ++#define IOC_NET_HEADER_FIELD_IPv6_SRC_IP (IOC_NET_HEADER_FIELD_IPv6_VER << 2) ++#define IOC_NET_HEADER_FIELD_IPv6_DST_IP (IOC_NET_HEADER_FIELD_IPv6_VER << 3) ++#define IOC_NET_HEADER_FIELD_IPv6_NEXT_HDR (IOC_NET_HEADER_FIELD_IPv6_VER << 4) ++#define IOC_NET_HEADER_FIELD_IPv6_FL (IOC_NET_HEADER_FIELD_IPv6_VER << 5) ++#define IOC_NET_HEADER_FIELD_IPv6_HOP_LIMIT (IOC_NET_HEADER_FIELD_IPv6_VER << 6) ++#define IOC_NET_HEADER_FIELD_IPv6_ALL_FIELDS ((IOC_NET_HEADER_FIELD_IPv6_VER << 7) - 1) ++ ++#define IOC_NET_HEADER_FIELD_IPv6_ADDR_SIZE 16 ++#define IOC_NET_HEADER_FIELD_IPv6_NEXT_HDR_SIZE 1 ++ ++#define IOC_NET_HEADER_FIELD_ICMP_TYPE (1) ++#define IOC_NET_HEADER_FIELD_ICMP_CODE (IOC_NET_HEADER_FIELD_ICMP_TYPE << 1) ++#define IOC_NET_HEADER_FIELD_ICMP_CKSUM (IOC_NET_HEADER_FIELD_ICMP_TYPE << 2) ++#define IOC_NET_HEADER_FIELD_ICMP_ID (IOC_NET_HEADER_FIELD_ICMP_TYPE << 3) ++#define IOC_NET_HEADER_FIELD_ICMP_SQ_NUM (IOC_NET_HEADER_FIELD_ICMP_TYPE << 4) ++#define IOC_NET_HEADER_FIELD_ICMP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_ICMP_TYPE << 5) - 1) ++ ++#define IOC_NET_HEADER_FIELD_ICMP_CODE_SIZE 1 ++#define IOC_NET_HEADER_FIELD_ICMP_TYPE_SIZE 1 ++ ++#define IOC_NET_HEADER_FIELD_IGMP_VERSION (1) ++#define IOC_NET_HEADER_FIELD_IGMP_TYPE (IOC_NET_HEADER_FIELD_IGMP_VERSION << 1) ++#define IOC_NET_HEADER_FIELD_IGMP_CKSUM (IOC_NET_HEADER_FIELD_IGMP_VERSION << 2) ++#define IOC_NET_HEADER_FIELD_IGMP_DATA (IOC_NET_HEADER_FIELD_IGMP_VERSION << 3) ++#define IOC_NET_HEADER_FIELD_IGMP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_IGMP_VERSION << 4) - 1) ++ ++ ++typedef uint16_t ioc_header_field_tcp_t; ++ ++#define IOC_NET_HEADER_FIELD_TCP_PORT_SRC (1) ++#define IOC_NET_HEADER_FIELD_TCP_PORT_DST (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 1) ++#define IOC_NET_HEADER_FIELD_TCP_SEQ (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 2) ++#define IOC_NET_HEADER_FIELD_TCP_ACK (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 3) ++#define IOC_NET_HEADER_FIELD_TCP_OFFSET (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 4) ++#define IOC_NET_HEADER_FIELD_TCP_FLAGS (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 5) ++#define IOC_NET_HEADER_FIELD_TCP_WINDOW (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 6) ++#define IOC_NET_HEADER_FIELD_TCP_CKSUM (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 7) ++#define IOC_NET_HEADER_FIELD_TCP_URGPTR (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 8) ++#define IOC_NET_HEADER_FIELD_TCP_OPTS (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 9) ++#define IOC_NET_HEADER_FIELD_TCP_OPTS_COUNT (IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 10) ++#define IOC_NET_HEADER_FIELD_TCP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_TCP_PORT_SRC << 11) - 1) ++ ++#define IOC_NET_HEADER_FIELD_TCP_PORT_SIZE 2 ++ ++ ++typedef uint8_t ioc_header_field_sctp_t; ++ ++#define IOC_NET_HEADER_FIELD_SCTP_PORT_SRC (1) ++#define IOC_NET_HEADER_FIELD_SCTP_PORT_DST (IOC_NET_HEADER_FIELD_SCTP_PORT_SRC << 1) ++#define IOC_NET_HEADER_FIELD_SCTP_VER_TAG (IOC_NET_HEADER_FIELD_SCTP_PORT_SRC << 2) ++#define IOC_NET_HEADER_FIELD_SCTP_CKSUM (IOC_NET_HEADER_FIELD_SCTP_PORT_SRC << 3) ++#define IOC_NET_HEADER_FIELD_SCTP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_SCTP_PORT_SRC << 4) - 1) ++ ++#define IOC_NET_HEADER_FIELD_SCTP_PORT_SIZE 2 ++ ++typedef uint8_t ioc_header_field_dccp_t; ++ ++#define IOC_NET_HEADER_FIELD_DCCP_PORT_SRC (1) ++#define IOC_NET_HEADER_FIELD_DCCP_PORT_DST (IOC_NET_HEADER_FIELD_DCCP_PORT_SRC << 1) ++#define IOC_NET_HEADER_FIELD_DCCP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_DCCP_PORT_SRC << 2) - 1) ++ ++#define IOC_NET_HEADER_FIELD_DCCP_PORT_SIZE 2 ++ ++ ++typedef uint8_t ioc_header_field_udp_t; ++ ++#define IOC_NET_HEADER_FIELD_UDP_PORT_SRC (1) ++#define IOC_NET_HEADER_FIELD_UDP_PORT_DST (IOC_NET_HEADER_FIELD_UDP_PORT_SRC << 1) ++#define IOC_NET_HEADER_FIELD_UDP_LEN (IOC_NET_HEADER_FIELD_UDP_PORT_SRC << 2) ++#define IOC_NET_HEADER_FIELD_UDP_CKSUM (IOC_NET_HEADER_FIELD_UDP_PORT_SRC << 3) ++#define IOC_NET_HEADER_FIELD_UDP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_UDP_PORT_SRC << 4) - 1) ++ ++#define IOC_NET_HEADER_FIELD_UDP_PORT_SIZE 2 ++ ++typedef uint8_t ioc_header_field_udp_lite_t; ++ ++#define IOC_NET_HEADER_FIELD_UDP_LITE_PORT_SRC (1) ++#define IOC_NET_HEADER_FIELD_UDP_LITE_PORT_DST (IOC_NET_HEADER_FIELD_UDP_LITE_PORT_SRC << 1) ++#define IOC_NET_HEADER_FIELD_UDP_LITE_ALL_FIELDS ((IOC_NET_HEADER_FIELD_UDP_LITE_PORT_SRC << 2) - 1) ++ ++#define IOC_NET_HEADER_FIELD_UDP_LITE_PORT_SIZE 2 ++ ++typedef uint8_t ioc_header_field_udp_encap_esp_t; ++ ++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC (1) ++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST (IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 1) ++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN (IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 2) ++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM (IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 3) ++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI (IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 4) ++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM (IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 5) ++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC << 6) - 1) ++ ++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SIZE 2 ++#define IOC_NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI_SIZE 4 ++ ++#define IOC_NET_HEADER_FIELD_IPHC_CID (1) ++#define IOC_NET_HEADER_FIELD_IPHC_CID_TYPE (IOC_NET_HEADER_FIELD_IPHC_CID << 1) ++#define IOC_NET_HEADER_FIELD_IPHC_HCINDEX (IOC_NET_HEADER_FIELD_IPHC_CID << 2) ++#define IOC_NET_HEADER_FIELD_IPHC_GEN (IOC_NET_HEADER_FIELD_IPHC_CID << 3) ++#define IOC_NET_HEADER_FIELD_IPHC_D_BIT (IOC_NET_HEADER_FIELD_IPHC_CID << 4) ++#define IOC_NET_HEADER_FIELD_IPHC_ALL_FIELDS ((IOC_NET_HEADER_FIELD_IPHC_CID << 5) - 1) ++ ++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE (1) ++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_FLAGS (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 1) ++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_LENGTH (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 2) ++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TSN (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 3) ++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_STREAM_ID (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 4) ++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_STREAM_SQN (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 5) ++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_PAYLOAD_PID (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 6) ++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_UNORDERED (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 7) ++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_BEGGINING (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 8) ++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_END (IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 9) ++#define IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_ALL_FIELDS ((IOC_NET_HEADER_FIELD_SCTP_CHUNK_DATA_TYPE << 10) - 1) ++ ++#define IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT (1) ++#define IOC_NET_HEADER_FIELD_L2TPv2_LENGTH_BIT (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 1) ++#define IOC_NET_HEADER_FIELD_L2TPv2_SEQUENCE_BIT (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 2) ++#define IOC_NET_HEADER_FIELD_L2TPv2_OFFSET_BIT (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 3) ++#define IOC_NET_HEADER_FIELD_L2TPv2_PRIORITY_BIT (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 4) ++#define IOC_NET_HEADER_FIELD_L2TPv2_VERSION (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 5) ++#define IOC_NET_HEADER_FIELD_L2TPv2_LEN (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 6) ++#define IOC_NET_HEADER_FIELD_L2TPv2_TUNNEL_ID (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 7) ++#define IOC_NET_HEADER_FIELD_L2TPv2_SESSION_ID (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 8) ++#define IOC_NET_HEADER_FIELD_L2TPv2_NS (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 9) ++#define IOC_NET_HEADER_FIELD_L2TPv2_NR (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 10) ++#define IOC_NET_HEADER_FIELD_L2TPv2_OFFSET_SIZE (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 11) ++#define IOC_NET_HEADER_FIELD_L2TPv2_FIRST_BYTE (IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 12) ++#define IOC_NET_HEADER_FIELD_L2TPv2_ALL_FIELDS ((IOC_NET_HEADER_FIELD_L2TPv2_TYPE_BIT << 13) - 1) ++ ++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT (1) ++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_LENGTH_BIT (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 1) ++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_SEQUENCE_BIT (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 2) ++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_VERSION (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 3) ++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_LENGTH (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 4) ++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_CONTROL (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 5) ++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_SENT (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 6) ++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_RECV (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 7) ++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_FIRST_BYTE (IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 8) ++#define IOC_NET_HEADER_FIELD_L2TPv3_CTRL_ALL_FIELDS ((IOC_NET_HEADER_FIELD_L2TPv3_CTRL_TYPE_BIT << 9) - 1) ++ ++#define IOC_NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT (1) ++#define IOC_NET_HEADER_FIELD_L2TPv3_SESS_VERSION (IOC_NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 1) ++#define IOC_NET_HEADER_FIELD_L2TPv3_SESS_ID (IOC_NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 2) ++#define IOC_NET_HEADER_FIELD_L2TPv3_SESS_COOKIE (IOC_NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 3) ++#define IOC_NET_HEADER_FIELD_L2TPv3_SESS_ALL_FIELDS ((IOC_NET_HEADER_FIELD_L2TPv3_SESS_TYPE_BIT << 4) - 1) ++ ++ ++typedef uint8_t ioc_header_field_vlan_t; ++ ++#define IOC_NET_HEADER_FIELD_VLAN_VPRI (1) ++#define IOC_NET_HEADER_FIELD_VLAN_CFI (IOC_NET_HEADER_FIELD_VLAN_VPRI << 1) ++#define IOC_NET_HEADER_FIELD_VLAN_VID (IOC_NET_HEADER_FIELD_VLAN_VPRI << 2) ++#define IOC_NET_HEADER_FIELD_VLAN_LENGTH (IOC_NET_HEADER_FIELD_VLAN_VPRI << 3) ++#define IOC_NET_HEADER_FIELD_VLAN_TYPE (IOC_NET_HEADER_FIELD_VLAN_VPRI << 4) ++#define IOC_NET_HEADER_FIELD_VLAN_ALL_FIELDS ((IOC_NET_HEADER_FIELD_VLAN_VPRI << 5) - 1) ++ ++#define IOC_NET_HEADER_FIELD_VLAN_TCI (IOC_NET_HEADER_FIELD_VLAN_VPRI | \ ++ IOC_NET_HEADER_FIELD_VLAN_CFI | \ ++ IOC_NET_HEADER_FIELD_VLAN_VID) ++ ++ ++typedef uint8_t ioc_header_field_llc_t; ++ ++#define IOC_NET_HEADER_FIELD_LLC_DSAP (1) ++#define IOC_NET_HEADER_FIELD_LLC_SSAP (IOC_NET_HEADER_FIELD_LLC_DSAP << 1) ++#define IOC_NET_HEADER_FIELD_LLC_CTRL (IOC_NET_HEADER_FIELD_LLC_DSAP << 2) ++#define IOC_NET_HEADER_FIELD_LLC_ALL_FIELDS ((IOC_NET_HEADER_FIELD_LLC_DSAP << 3) - 1) ++ ++#define IOC_NET_HEADER_FIELD_NLPID_NLPID (1) ++#define IOC_NET_HEADER_FIELD_NLPID_ALL_FIELDS ((IOC_NET_HEADER_FIELD_NLPID_NLPID << 1) - 1) ++ ++ ++typedef uint8_t ioc_header_field_snap_t; ++ ++#define IOC_NET_HEADER_FIELD_SNAP_OUI (1) ++#define IOC_NET_HEADER_FIELD_SNAP_PID (IOC_NET_HEADER_FIELD_SNAP_OUI << 1) ++#define IOC_NET_HEADER_FIELD_SNAP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_SNAP_OUI << 2) - 1) ++ ++ ++typedef uint8_t ioc_header_field_llc_snap_t; ++ ++#define IOC_NET_HEADER_FIELD_LLC_SNAP_TYPE (1) ++#define IOC_NET_HEADER_FIELD_LLC_SNAP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_LLC_SNAP_TYPE << 1) - 1) ++ ++#define IOC_NET_HEADER_FIELD_ARP_HTYPE (1) ++#define IOC_NET_HEADER_FIELD_ARP_PTYPE (IOC_NET_HEADER_FIELD_ARP_HTYPE << 1) ++#define IOC_NET_HEADER_FIELD_ARP_HLEN (IOC_NET_HEADER_FIELD_ARP_HTYPE << 2) ++#define IOC_NET_HEADER_FIELD_ARP_PLEN (IOC_NET_HEADER_FIELD_ARP_HTYPE << 3) ++#define IOC_NET_HEADER_FIELD_ARP_OPER (IOC_NET_HEADER_FIELD_ARP_HTYPE << 4) ++#define IOC_NET_HEADER_FIELD_ARP_SHA (IOC_NET_HEADER_FIELD_ARP_HTYPE << 5) ++#define IOC_NET_HEADER_FIELD_ARP_SPA (IOC_NET_HEADER_FIELD_ARP_HTYPE << 6) ++#define IOC_NET_HEADER_FIELD_ARP_THA (IOC_NET_HEADER_FIELD_ARP_HTYPE << 7) ++#define IOC_NET_HEADER_FIELD_ARP_TPA (IOC_NET_HEADER_FIELD_ARP_HTYPE << 8) ++#define IOC_NET_HEADER_FIELD_ARP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_ARP_HTYPE << 9) - 1) ++ ++#define IOC_NET_HEADER_FIELD_RFC2684_LLC (1) ++#define IOC_NET_HEADER_FIELD_RFC2684_NLPID (IOC_NET_HEADER_FIELD_RFC2684_LLC << 1) ++#define IOC_NET_HEADER_FIELD_RFC2684_OUI (IOC_NET_HEADER_FIELD_RFC2684_LLC << 2) ++#define IOC_NET_HEADER_FIELD_RFC2684_PID (IOC_NET_HEADER_FIELD_RFC2684_LLC << 3) ++#define IOC_NET_HEADER_FIELD_RFC2684_VPN_OUI (IOC_NET_HEADER_FIELD_RFC2684_LLC << 4) ++#define IOC_NET_HEADER_FIELD_RFC2684_VPN_IDX (IOC_NET_HEADER_FIELD_RFC2684_LLC << 5) ++#define IOC_NET_HEADER_FIELD_RFC2684_ALL_FIELDS ((IOC_NET_HEADER_FIELD_RFC2684_LLC << 6) - 1) ++ ++#define IOC_NET_HEADER_FIELD_USER_DEFINED_SRCPORT (1) ++#define IOC_NET_HEADER_FIELD_USER_DEFINED_PCDID (IOC_NET_HEADER_FIELD_USER_DEFINED_SRCPORT << 1) ++#define IOC_NET_HEADER_FIELD_USER_DEFINED_ALL_FIELDS ((IOC_NET_HEADER_FIELD_USER_DEFINED_SRCPORT << 2) - 1) ++ ++#define IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER (1) ++#define IOC_NET_HEADER_FIELD_PAYLOAD_SIZE (IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 1) ++#define IOC_NET_HEADER_FIELD_MAX_FRM_SIZE (IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 2) ++#define IOC_NET_HEADER_FIELD_MIN_FRM_SIZE (IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 3) ++#define IOC_NET_HEADER_FIELD_PAYLOAD_TYPE (IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 4) ++#define IOC_NET_HEADER_FIELD_FRAME_SIZE (IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 5) ++#define IOC_NET_HEADER_FIELD_PAYLOAD_ALL_FIELDS ((IOC_NET_HEADER_FIELD_PAYLOAD_BUFFER << 6) - 1) ++ ++ ++typedef uint8_t ioc_header_field_gre_t; ++ ++#define IOC_NET_HEADER_FIELD_GRE_TYPE (1) ++#define IOC_NET_HEADER_FIELD_GRE_ALL_FIELDS ((IOC_NET_HEADER_FIELD_GRE_TYPE << 1) - 1) ++ ++ ++typedef uint8_t ioc_header_field_minencap_t; ++ ++#define IOC_NET_HEADER_FIELD_MINENCAP_SRC_IP (1) ++#define IOC_NET_HEADER_FIELD_MINENCAP_DST_IP (IOC_NET_HEADER_FIELD_MINENCAP_SRC_IP << 1) ++#define IOC_NET_HEADER_FIELD_MINENCAP_TYPE (IOC_NET_HEADER_FIELD_MINENCAP_SRC_IP << 2) ++#define IOC_NET_HEADER_FIELD_MINENCAP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_MINENCAP_SRC_IP << 3) - 1) ++ ++ ++typedef uint8_t ioc_header_field_ipsec_ah_t; ++ ++#define IOC_NET_HEADER_FIELD_IPSEC_AH_SPI (1) ++#define IOC_NET_HEADER_FIELD_IPSEC_AH_NH (IOC_NET_HEADER_FIELD_IPSEC_AH_SPI << 1) ++#define IOC_NET_HEADER_FIELD_IPSEC_AH_ALL_FIELDS ((IOC_NET_HEADER_FIELD_IPSEC_AH_SPI << 2) - 1) ++ ++ ++typedef uint8_t ioc_header_field_ipsec_esp_t; ++ ++#define IOC_NET_HEADER_FIELD_IPSEC_ESP_SPI (1) ++#define IOC_NET_HEADER_FIELD_IPSEC_ESP_SEQUENCE_NUM (IOC_NET_HEADER_FIELD_IPSEC_ESP_SPI << 1) ++#define IOC_NET_HEADER_FIELD_IPSEC_ESP_ALL_FIELDS ((IOC_NET_HEADER_FIELD_IPSEC_ESP_SPI << 2) - 1) ++ ++#define IOC_NET_HEADER_FIELD_IPSEC_ESP_SPI_SIZE 4 ++ ++ ++typedef uint8_t ioc_header_field_mpls_t; ++ ++#define IOC_NET_HEADER_FIELD_MPLS_LABEL_STACK (1) ++#define IOC_NET_HEADER_FIELD_MPLS_LABEL_STACK_ALL_FIELDS ((IOC_NET_HEADER_FIELD_MPLS_LABEL_STACK << 1) - 1) ++ ++ ++typedef uint8_t ioc_header_field_macsec_t; ++ ++#define IOC_NET_HEADER_FIELD_MACSEC_SECTAG (1) ++#define IOC_NET_HEADER_FIELD_MACSEC_ALL_FIELDS ((IOC_NET_HEADER_FIELD_MACSEC_SECTAG << 1) - 1) ++ ++ ++typedef enum { ++ e_IOC_NET_HEADER_TYPE_NONE = 0, ++ e_IOC_NET_HEADER_TYPE_PAYLOAD, ++ e_IOC_NET_HEADER_TYPE_ETH, ++ e_IOC_NET_HEADER_TYPE_VLAN, ++ e_IOC_NET_HEADER_TYPE_IPv4, ++ e_IOC_NET_HEADER_TYPE_IPv6, ++ e_IOC_NET_HEADER_TYPE_IP, ++ e_IOC_NET_HEADER_TYPE_TCP, ++ e_IOC_NET_HEADER_TYPE_UDP, ++ e_IOC_NET_HEADER_TYPE_UDP_LITE, ++ e_IOC_NET_HEADER_TYPE_IPHC, ++ e_IOC_NET_HEADER_TYPE_SCTP, ++ e_IOC_NET_HEADER_TYPE_SCTP_CHUNK_DATA, ++ e_IOC_NET_HEADER_TYPE_PPPoE, ++ e_IOC_NET_HEADER_TYPE_PPP, ++ e_IOC_NET_HEADER_TYPE_PPPMUX, ++ e_IOC_NET_HEADER_TYPE_PPPMUX_SUBFRAME, ++ e_IOC_NET_HEADER_TYPE_L2TPv2, ++ e_IOC_NET_HEADER_TYPE_L2TPv3_CTRL, ++ e_IOC_NET_HEADER_TYPE_L2TPv3_SESS, ++ e_IOC_NET_HEADER_TYPE_LLC, ++ e_IOC_NET_HEADER_TYPE_LLC_SNAP, ++ e_IOC_NET_HEADER_TYPE_NLPID, ++ e_IOC_NET_HEADER_TYPE_SNAP, ++ e_IOC_NET_HEADER_TYPE_MPLS, ++ e_IOC_NET_HEADER_TYPE_IPSEC_AH, ++ e_IOC_NET_HEADER_TYPE_IPSEC_ESP, ++ e_IOC_NET_HEADER_TYPE_UDP_ENCAP_ESP, /* RFC 3948 */ ++ e_IOC_NET_HEADER_TYPE_MACSEC, ++ e_IOC_NET_HEADER_TYPE_GRE, ++ e_IOC_NET_HEADER_TYPE_MINENCAP, ++ e_IOC_NET_HEADER_TYPE_DCCP, ++ e_IOC_NET_HEADER_TYPE_ICMP, ++ e_IOC_NET_HEADER_TYPE_IGMP, ++ e_IOC_NET_HEADER_TYPE_ARP, ++ e_IOC_NET_HEADER_TYPE_CAPWAP, ++ e_IOC_NET_HEADER_TYPE_CAPWAP_DTLS, ++ e_IOC_NET_HEADER_TYPE_RFC2684, ++ e_IOC_NET_HEADER_TYPE_USER_DEFINED_L2, ++ e_IOC_NET_HEADER_TYPE_USER_DEFINED_L3, ++ e_IOC_NET_HEADER_TYPE_USER_DEFINED_L4, ++ e_IOC_NET_HEADER_TYPE_USER_DEFINED_SHIM1, ++ e_IOC_NET_HEADER_TYPE_USER_DEFINED_SHIM2, ++ e_IOC_NET_MAX_HEADER_TYPE_COUNT ++} ioc_net_header_type; ++ ++ ++#endif /* __NET_IOCTLS_H */ +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/702-pci-support-layerscape.patch b/target/linux/layerscape/patches-4.9/702-pci-support-layerscape.patch new file mode 100644 index 0000000000..c3dcd73b60 --- /dev/null +++ b/target/linux/layerscape/patches-4.9/702-pci-support-layerscape.patch @@ -0,0 +1,2062 @@ +From c4813da334b0c31e9c55eea015f1e898e84ff45b Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 11:04:10 +0800 +Subject: [PATCH] pci: support layerscape + +This is a integrated patch for layerscape pcie support. + +Signed-off-by: Po Liu +Signed-off-by: Liu Gang +Signed-off-by: Minghuan Lian +Signed-off-by: hongbo.wang +Signed-off-by: Bjorn Helgaas +Signed-off-by: Hou Zhiqiang +Signed-off-by: Mingkai Hu +Signed-off-by: Christoph Hellwig +Signed-off-by: Yangbo Lu +--- + drivers/irqchip/irq-ls-scfg-msi.c | 256 +++++++-- + drivers/pci/host/Makefile | 2 +- + drivers/pci/host/pci-layerscape-ep-debugfs.c | 758 +++++++++++++++++++++++++++ + drivers/pci/host/pci-layerscape-ep.c | 309 +++++++++++ + drivers/pci/host/pci-layerscape-ep.h | 115 ++++ + drivers/pci/host/pci-layerscape.c | 37 +- + drivers/pci/host/pcie-designware.c | 6 + + drivers/pci/host/pcie-designware.h | 1 + + drivers/pci/pcie/portdrv_core.c | 181 +++---- + include/linux/pci.h | 1 + + 10 files changed, 1518 insertions(+), 148 deletions(-) + create mode 100644 drivers/pci/host/pci-layerscape-ep-debugfs.c + create mode 100644 drivers/pci/host/pci-layerscape-ep.c + create mode 100644 drivers/pci/host/pci-layerscape-ep.h + +diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c +index 02cca74c..119f4ef0 100644 +--- a/drivers/irqchip/irq-ls-scfg-msi.c ++++ b/drivers/irqchip/irq-ls-scfg-msi.c +@@ -17,13 +17,32 @@ + #include + #include + #include ++#include + #include + #include + #include + +-#define MSI_MAX_IRQS 32 +-#define MSI_IBS_SHIFT 3 +-#define MSIR 4 ++#define MSI_IRQS_PER_MSIR 32 ++#define MSI_MSIR_OFFSET 4 ++ ++#define MSI_LS1043V1_1_IRQS_PER_MSIR 8 ++#define MSI_LS1043V1_1_MSIR_OFFSET 0x10 ++ ++struct ls_scfg_msi_cfg { ++ u32 ibs_shift; /* Shift of interrupt bit select */ ++ u32 msir_irqs; /* The irq number per MSIR */ ++ u32 msir_base; /* The base address of MSIR */ ++}; ++ ++struct ls_scfg_msir { ++ struct ls_scfg_msi *msi_data; ++ unsigned int index; ++ unsigned int gic_irq; ++ unsigned int bit_start; ++ unsigned int bit_end; ++ unsigned int srs; /* Shared interrupt register select */ ++ void __iomem *reg; ++}; + + struct ls_scfg_msi { + spinlock_t lock; +@@ -32,8 +51,11 @@ struct ls_scfg_msi { + struct irq_domain *msi_domain; + void __iomem *regs; + phys_addr_t msiir_addr; +- int irq; +- DECLARE_BITMAP(used, MSI_MAX_IRQS); ++ struct ls_scfg_msi_cfg *cfg; ++ u32 msir_num; ++ struct ls_scfg_msir *msir; ++ u32 irqs_num; ++ unsigned long *used; + }; + + static struct irq_chip ls_scfg_msi_irq_chip = { +@@ -49,19 +71,56 @@ static struct msi_domain_info ls_scfg_msi_domain_info = { + .chip = &ls_scfg_msi_irq_chip, + }; + ++static int msi_affinity_flag = 1; ++ ++static int __init early_parse_ls_scfg_msi(char *p) ++{ ++ if (p && strncmp(p, "no-affinity", 11) == 0) ++ msi_affinity_flag = 0; ++ else ++ msi_affinity_flag = 1; ++ ++ return 0; ++} ++early_param("lsmsi", early_parse_ls_scfg_msi); ++ + static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg) + { + struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(data); + + msg->address_hi = upper_32_bits(msi_data->msiir_addr); + msg->address_lo = lower_32_bits(msi_data->msiir_addr); +- msg->data = data->hwirq << MSI_IBS_SHIFT; ++ msg->data = data->hwirq; ++ ++ if (msi_affinity_flag) ++ msg->data |= cpumask_first(data->common->affinity); + } + + static int ls_scfg_msi_set_affinity(struct irq_data *irq_data, + const struct cpumask *mask, bool force) + { +- return -EINVAL; ++ struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(irq_data); ++ u32 cpu; ++ ++ if (!msi_affinity_flag) ++ return -EINVAL; ++ ++ if (!force) ++ cpu = cpumask_any_and(mask, cpu_online_mask); ++ else ++ cpu = cpumask_first(mask); ++ ++ if (cpu >= msi_data->msir_num) ++ return -EINVAL; ++ ++ if (msi_data->msir[cpu].gic_irq <= 0) { ++ pr_warn("cannot bind the irq to cpu%d\n", cpu); ++ return -EINVAL; ++ } ++ ++ cpumask_copy(irq_data->common->affinity, mask); ++ ++ return IRQ_SET_MASK_OK; + } + + static struct irq_chip ls_scfg_msi_parent_chip = { +@@ -81,8 +140,8 @@ static int ls_scfg_msi_domain_irq_alloc(struct irq_domain *domain, + WARN_ON(nr_irqs != 1); + + spin_lock(&msi_data->lock); +- pos = find_first_zero_bit(msi_data->used, MSI_MAX_IRQS); +- if (pos < MSI_MAX_IRQS) ++ pos = find_first_zero_bit(msi_data->used, msi_data->irqs_num); ++ if (pos < msi_data->irqs_num) + __set_bit(pos, msi_data->used); + else + err = -ENOSPC; +@@ -106,7 +165,7 @@ static void ls_scfg_msi_domain_irq_free(struct irq_domain *domain, + int pos; + + pos = d->hwirq; +- if (pos < 0 || pos >= MSI_MAX_IRQS) { ++ if (pos < 0 || pos >= msi_data->irqs_num) { + pr_err("failed to teardown msi. Invalid hwirq %d\n", pos); + return; + } +@@ -123,15 +182,22 @@ static const struct irq_domain_ops ls_scfg_msi_domain_ops = { + + static void ls_scfg_msi_irq_handler(struct irq_desc *desc) + { +- struct ls_scfg_msi *msi_data = irq_desc_get_handler_data(desc); ++ struct ls_scfg_msir *msir = irq_desc_get_handler_data(desc); ++ struct ls_scfg_msi *msi_data = msir->msi_data; + unsigned long val; +- int pos, virq; ++ int pos, size, virq, hwirq; + + chained_irq_enter(irq_desc_get_chip(desc), desc); + +- val = ioread32be(msi_data->regs + MSIR); +- for_each_set_bit(pos, &val, MSI_MAX_IRQS) { +- virq = irq_find_mapping(msi_data->parent, (31 - pos)); ++ val = ioread32be(msir->reg); ++ ++ pos = msir->bit_start; ++ size = msir->bit_end + 1; ++ ++ for_each_set_bit_from(pos, &val, size) { ++ hwirq = ((msir->bit_end - pos) << msi_data->cfg->ibs_shift) | ++ msir->srs; ++ virq = irq_find_mapping(msi_data->parent, hwirq); + if (virq) + generic_handle_irq(virq); + } +@@ -143,7 +209,7 @@ static int ls_scfg_msi_domains_init(struct ls_scfg_msi *msi_data) + { + /* Initialize MSI domain parent */ + msi_data->parent = irq_domain_add_linear(NULL, +- MSI_MAX_IRQS, ++ msi_data->irqs_num, + &ls_scfg_msi_domain_ops, + msi_data); + if (!msi_data->parent) { +@@ -164,16 +230,117 @@ static int ls_scfg_msi_domains_init(struct ls_scfg_msi *msi_data) + return 0; + } + ++static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index) ++{ ++ struct ls_scfg_msir *msir; ++ int virq, i, hwirq; ++ ++ virq = platform_get_irq(msi_data->pdev, index); ++ if (virq <= 0) ++ return -ENODEV; ++ ++ msir = &msi_data->msir[index]; ++ msir->index = index; ++ msir->msi_data = msi_data; ++ msir->gic_irq = virq; ++ msir->reg = msi_data->regs + msi_data->cfg->msir_base + 4 * index; ++ ++ if (msi_data->cfg->msir_irqs == MSI_LS1043V1_1_IRQS_PER_MSIR) { ++ msir->bit_start = 32 - ((msir->index + 1) * ++ MSI_LS1043V1_1_IRQS_PER_MSIR); ++ msir->bit_end = msir->bit_start + ++ MSI_LS1043V1_1_IRQS_PER_MSIR - 1; ++ } else { ++ msir->bit_start = 0; ++ msir->bit_end = msi_data->cfg->msir_irqs - 1; ++ } ++ ++ irq_set_chained_handler_and_data(msir->gic_irq, ++ ls_scfg_msi_irq_handler, ++ msir); ++ ++ if (msi_affinity_flag) { ++ /* Associate MSIR interrupt to the cpu */ ++ irq_set_affinity(msir->gic_irq, get_cpu_mask(index)); ++ msir->srs = 0; /* This value is determined by the CPU */ ++ } else ++ msir->srs = index; ++ ++ /* Release the hwirqs corresponding to this MSIR */ ++ if (!msi_affinity_flag || msir->index == 0) { ++ for (i = 0; i < msi_data->cfg->msir_irqs; i++) { ++ hwirq = i << msi_data->cfg->ibs_shift | msir->index; ++ bitmap_clear(msi_data->used, hwirq, 1); ++ } ++ } ++ ++ return 0; ++} ++ ++static int ls_scfg_msi_teardown_hwirq(struct ls_scfg_msir *msir) ++{ ++ struct ls_scfg_msi *msi_data = msir->msi_data; ++ int i, hwirq; ++ ++ if (msir->gic_irq > 0) ++ irq_set_chained_handler_and_data(msir->gic_irq, NULL, NULL); ++ ++ for (i = 0; i < msi_data->cfg->msir_irqs; i++) { ++ hwirq = i << msi_data->cfg->ibs_shift | msir->index; ++ bitmap_set(msi_data->used, hwirq, 1); ++ } ++ ++ return 0; ++} ++ ++static struct ls_scfg_msi_cfg ls1021_msi_cfg = { ++ .ibs_shift = 3, ++ .msir_irqs = MSI_IRQS_PER_MSIR, ++ .msir_base = MSI_MSIR_OFFSET, ++}; ++ ++static struct ls_scfg_msi_cfg ls1046_msi_cfg = { ++ .ibs_shift = 2, ++ .msir_irqs = MSI_IRQS_PER_MSIR, ++ .msir_base = MSI_MSIR_OFFSET, ++}; ++ ++static struct ls_scfg_msi_cfg ls1043_v1_1_msi_cfg = { ++ .ibs_shift = 2, ++ .msir_irqs = MSI_LS1043V1_1_IRQS_PER_MSIR, ++ .msir_base = MSI_LS1043V1_1_MSIR_OFFSET, ++}; ++ ++static const struct of_device_id ls_scfg_msi_id[] = { ++ /* The following two misspelled compatibles are obsolete */ ++ { .compatible = "fsl,1s1021a-msi", .data = &ls1021_msi_cfg}, ++ { .compatible = "fsl,1s1043a-msi", .data = &ls1021_msi_cfg}, ++ ++ { .compatible = "fsl,ls1021a-msi", .data = &ls1021_msi_cfg }, ++ { .compatible = "fsl,ls1043a-msi", .data = &ls1021_msi_cfg }, ++ { .compatible = "fsl,ls1043a-v1.1-msi", .data = &ls1043_v1_1_msi_cfg }, ++ { .compatible = "fsl,ls1046a-msi", .data = &ls1046_msi_cfg }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, ls_scfg_msi_id); ++ + static int ls_scfg_msi_probe(struct platform_device *pdev) + { ++ const struct of_device_id *match; + struct ls_scfg_msi *msi_data; + struct resource *res; +- int ret; ++ int i, ret; ++ ++ match = of_match_device(ls_scfg_msi_id, &pdev->dev); ++ if (!match) ++ return -ENODEV; + + msi_data = devm_kzalloc(&pdev->dev, sizeof(*msi_data), GFP_KERNEL); + if (!msi_data) + return -ENOMEM; + ++ msi_data->cfg = (struct ls_scfg_msi_cfg *) match->data; ++ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + msi_data->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(msi_data->regs)) { +@@ -182,23 +349,48 @@ static int ls_scfg_msi_probe(struct platform_device *pdev) + } + msi_data->msiir_addr = res->start; + +- msi_data->irq = platform_get_irq(pdev, 0); +- if (msi_data->irq <= 0) { +- dev_err(&pdev->dev, "failed to get MSI irq\n"); +- return -ENODEV; +- } +- + msi_data->pdev = pdev; + spin_lock_init(&msi_data->lock); + ++ msi_data->irqs_num = MSI_IRQS_PER_MSIR * ++ (1 << msi_data->cfg->ibs_shift); ++ msi_data->used = devm_kcalloc(&pdev->dev, ++ BITS_TO_LONGS(msi_data->irqs_num), ++ sizeof(*msi_data->used), ++ GFP_KERNEL); ++ if (!msi_data->used) ++ return -ENOMEM; ++ /* ++ * Reserve all the hwirqs ++ * The available hwirqs will be released in ls1_msi_setup_hwirq() ++ */ ++ bitmap_set(msi_data->used, 0, msi_data->irqs_num); ++ ++ msi_data->msir_num = of_irq_count(pdev->dev.of_node); ++ ++ if (msi_affinity_flag) { ++ u32 cpu_num; ++ ++ cpu_num = num_possible_cpus(); ++ if (msi_data->msir_num >= cpu_num) ++ msi_data->msir_num = cpu_num; ++ else ++ msi_affinity_flag = 0; ++ } ++ ++ msi_data->msir = devm_kcalloc(&pdev->dev, msi_data->msir_num, ++ sizeof(*msi_data->msir), ++ GFP_KERNEL); ++ if (!msi_data->msir) ++ return -ENOMEM; ++ ++ for (i = 0; i < msi_data->msir_num; i++) ++ ls_scfg_msi_setup_hwirq(msi_data, i); ++ + ret = ls_scfg_msi_domains_init(msi_data); + if (ret) + return ret; + +- irq_set_chained_handler_and_data(msi_data->irq, +- ls_scfg_msi_irq_handler, +- msi_data); +- + platform_set_drvdata(pdev, msi_data); + + return 0; +@@ -207,8 +399,10 @@ static int ls_scfg_msi_probe(struct platform_device *pdev) + static int ls_scfg_msi_remove(struct platform_device *pdev) + { + struct ls_scfg_msi *msi_data = platform_get_drvdata(pdev); ++ int i; + +- irq_set_chained_handler_and_data(msi_data->irq, NULL, NULL); ++ for (i = 0; i < msi_data->msir_num; i++) ++ ls_scfg_msi_teardown_hwirq(&msi_data->msir[i]); + + irq_domain_remove(msi_data->msi_domain); + irq_domain_remove(msi_data->parent); +@@ -218,12 +412,6 @@ static int ls_scfg_msi_remove(struct platform_device *pdev) + return 0; + } + +-static const struct of_device_id ls_scfg_msi_id[] = { +- { .compatible = "fsl,1s1021a-msi", }, +- { .compatible = "fsl,1s1043a-msi", }, +- {}, +-}; +- + static struct platform_driver ls_scfg_msi_driver = { + .driver = { + .name = "ls-scfg-msi", +diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile +index 084cb498..88e87704 100644 +--- a/drivers/pci/host/Makefile ++++ b/drivers/pci/host/Makefile +@@ -17,7 +17,7 @@ obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o + obj-$(CONFIG_PCIE_XILINX_NWL) += pcie-xilinx-nwl.o + obj-$(CONFIG_PCI_XGENE) += pci-xgene.o + obj-$(CONFIG_PCI_XGENE_MSI) += pci-xgene-msi.o +-obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o ++obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o pci-layerscape-ep.o pci-layerscape-ep-debugfs.o + obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o + obj-$(CONFIG_PCIE_IPROC) += pcie-iproc.o + obj-$(CONFIG_PCIE_IPROC_MSI) += pcie-iproc-msi.o +diff --git a/drivers/pci/host/pci-layerscape-ep-debugfs.c b/drivers/pci/host/pci-layerscape-ep-debugfs.c +new file mode 100644 +index 00000000..5f4870ba +--- /dev/null ++++ b/drivers/pci/host/pci-layerscape-ep-debugfs.c +@@ -0,0 +1,758 @@ ++/* ++ * PCIe Endpoint driver for Freescale Layerscape SoCs ++ * ++ * Copyright (C) 2015 Freescale Semiconductor. ++ * ++ * Author: Minghuan Lian ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "pci-layerscape-ep.h" ++ ++#define PCIE_ATU_INDEX3 (0x3 << 0) ++#define PCIE_ATU_INDEX2 (0x2 << 0) ++#define PCIE_ATU_INDEX1 (0x1 << 0) ++#define PCIE_ATU_INDEX0 (0x0 << 0) ++ ++#define PCIE_BAR0_SIZE (4 * 1024) /* 4K */ ++#define PCIE_BAR1_SIZE (8 * 1024) /* 8K for MSIX */ ++#define PCIE_BAR2_SIZE (4 * 1024) /* 4K */ ++#define PCIE_BAR4_SIZE (1 * 1024 * 1024) /* 1M */ ++#define PCIE_MSI_OB_SIZE (4 * 1024) /* 4K */ ++ ++#define PCIE_MSI_MSG_ADDR_OFF 0x54 ++#define PCIE_MSI_MSG_DATA_OFF 0x5c ++ ++enum test_type { ++ TEST_TYPE_DMA, ++ TEST_TYPE_MEMCPY ++}; ++ ++enum test_dirt { ++ TEST_DIRT_READ, ++ TEST_DIRT_WRITE ++}; ++ ++enum test_status { ++ TEST_IDLE, ++ TEST_BUSY ++}; ++ ++struct ls_ep_test { ++ struct ls_ep_dev *ep; ++ void __iomem *cfg; ++ void __iomem *buf; ++ void __iomem *out; ++ void __iomem *msi; ++ dma_addr_t cfg_addr; ++ dma_addr_t buf_addr; ++ dma_addr_t out_addr; ++ dma_addr_t bus_addr; ++ dma_addr_t msi_addr; ++ u64 msi_msg_addr; ++ u16 msi_msg_data; ++ struct task_struct *thread; ++ spinlock_t lock; ++ struct completion done; ++ u32 len; ++ int loop; ++ char data; ++ enum test_dirt dirt; ++ enum test_type type; ++ enum test_status status; ++ u64 result; /* Mbps */ ++ char cmd[256]; ++}; ++ ++static int ls_pcie_ep_trigger_msi(struct ls_ep_test *test) ++{ ++ if (!test->msi) ++ return -EINVAL; ++ ++ iowrite32(test->msi_msg_data, test->msi); ++ ++ return 0; ++} ++ ++static int ls_pcie_ep_test_try_run(struct ls_ep_test *test) ++{ ++ int ret; ++ ++ spin_lock(&test->lock); ++ if (test->status == TEST_IDLE) { ++ test->status = TEST_BUSY; ++ ret = 0; ++ } else ++ ret = -EBUSY; ++ spin_unlock(&test->lock); ++ ++ return ret; ++} ++ ++static void ls_pcie_ep_test_done(struct ls_ep_test *test) ++{ ++ spin_lock(&test->lock); ++ test->status = TEST_IDLE; ++ spin_unlock(&test->lock); ++} ++ ++static void ls_pcie_ep_test_dma_cb(void *arg) ++{ ++ struct ls_ep_test *test = arg; ++ ++ complete(&test->done); ++} ++ ++static int ls_pcie_ep_test_dma(struct ls_ep_test *test) ++{ ++ dma_cap_mask_t mask; ++ struct dma_chan *chan; ++ struct dma_device *dma_dev; ++ dma_addr_t src, dst; ++ enum dma_data_direction direction; ++ enum dma_ctrl_flags dma_flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; ++ struct timespec start, end, period; ++ int i = 0; ++ ++ dma_cap_zero(mask); ++ dma_cap_set(DMA_MEMCPY, mask); ++ ++ chan = dma_request_channel(mask, NULL, test); ++ if (!chan) { ++ pr_err("failed to request dma channel\n"); ++ return -EINVAL; ++ } ++ ++ memset(test->buf, test->data, test->len); ++ ++ if (test->dirt == TEST_DIRT_WRITE) { ++ src = test->buf_addr; ++ dst = test->out_addr; ++ direction = DMA_TO_DEVICE; ++ } else { ++ src = test->out_addr; ++ dst = test->buf_addr; ++ direction = DMA_FROM_DEVICE; ++ } ++ ++ dma_dev = chan->device; ++ dma_flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; ++ ++ dma_sync_single_for_device(&test->ep->dev, test->buf_addr, ++ test->len, direction); ++ ++ set_freezable(); ++ ++ getrawmonotonic(&start); ++ while (!kthread_should_stop() && (i < test->loop)) { ++ struct dma_async_tx_descriptor *dma_desc; ++ dma_cookie_t dma_cookie = {0}; ++ unsigned long tmo; ++ int status; ++ ++ init_completion(&test->done); ++ ++ dma_desc = dma_dev->device_prep_dma_memcpy(chan, ++ dst, src, ++ test->len, ++ dma_flags); ++ if (!dma_desc) { ++ pr_err("DMA desc constr failed...\n"); ++ goto _err; ++ } ++ ++ dma_desc->callback = ls_pcie_ep_test_dma_cb; ++ dma_desc->callback_param = test; ++ dma_cookie = dmaengine_submit(dma_desc); ++ ++ if (dma_submit_error(dma_cookie)) { ++ pr_err("DMA submit error....\n"); ++ goto _err; ++ } ++ ++ /* Trigger the transaction */ ++ dma_async_issue_pending(chan); ++ ++ tmo = wait_for_completion_timeout(&test->done, ++ msecs_to_jiffies(5 * test->len)); ++ if (tmo == 0) { ++ pr_err("Self-test copy timed out, disabling\n"); ++ goto _err; ++ } ++ ++ status = dma_async_is_tx_complete(chan, dma_cookie, ++ NULL, NULL); ++ if (status != DMA_COMPLETE) { ++ pr_err("got completion callback, but status is %s\n", ++ status == DMA_ERROR ? "error" : "in progress"); ++ goto _err; ++ } ++ ++ i++; ++ } ++ ++ getrawmonotonic(&end); ++ period = timespec_sub(end, start); ++ test->result = test->len * 8ULL * i * 1000; ++ do_div(test->result, period.tv_sec * 1000 * 1000 * 1000 + period.tv_nsec); ++ dma_release_channel(chan); ++ ++ return 0; ++ ++_err: ++ dma_release_channel(chan); ++ test->result = 0; ++ return -EINVAL; ++} ++ ++static int ls_pcie_ep_test_cpy(struct ls_ep_test *test) ++{ ++ void *dst, *src; ++ struct timespec start, end, period; ++ int i = 0; ++ ++ memset(test->buf, test->data, test->len); ++ ++ if (test->dirt == TEST_DIRT_WRITE) { ++ dst = test->out; ++ src = test->buf; ++ } else { ++ dst = test->buf; ++ src = test->out; ++ } ++ ++ getrawmonotonic(&start); ++ while (!kthread_should_stop() && i < test->loop) { ++ memcpy(dst, src, test->len); ++ i++; ++ } ++ getrawmonotonic(&end); ++ ++ period = timespec_sub(end, start); ++ test->result = test->len * 8ULL * i * 1000; ++ do_div(test->result, period.tv_sec * 1000 * 1000 * 1000 + period.tv_nsec); ++ ++ return 0; ++} ++ ++int ls_pcie_ep_test_thread(void *arg) ++{ ++ int ret; ++ ++ struct ls_ep_test *test = arg; ++ ++ if (test->type == TEST_TYPE_DMA) ++ ret = ls_pcie_ep_test_dma(test); ++ else ++ ret = ls_pcie_ep_test_cpy(test); ++ ++ if (ret) { ++ pr_err("\n%s \ttest failed\n", ++ test->cmd); ++ test->result = 0; ++ } else ++ pr_err("\n%s \tthroughput:%lluMbps\n", ++ test->cmd, test->result); ++ ++ ls_pcie_ep_test_done(test); ++ ++ ls_pcie_ep_trigger_msi(test); ++ ++ do_exit(0); ++} ++ ++static int ls_pcie_ep_free_test(struct ls_ep_dev *ep) ++{ ++ struct ls_ep_test *test = ep->driver_data; ++ ++ if (!test) ++ return 0; ++ ++ if (test->status == TEST_BUSY) { ++ kthread_stop(test->thread); ++ dev_info(&ep->dev, ++ "test is running please wait and run again\n"); ++ return -EBUSY; ++ } ++ ++ if (test->buf) ++ free_pages((unsigned long)test->buf, ++ get_order(PCIE_BAR4_SIZE)); ++ ++ if (test->cfg) ++ free_pages((unsigned long)test->cfg, ++ get_order(PCIE_BAR2_SIZE)); ++ ++ if (test->out) ++ iounmap(test->out); ++ ++ kfree(test); ++ ep->driver_data = NULL; ++ ++ return 0; ++} ++ ++static int ls_pcie_ep_init_test(struct ls_ep_dev *ep, u64 bus_addr) ++{ ++ struct ls_pcie *pcie = ep->pcie; ++ struct ls_ep_test *test = ep->driver_data; ++ int err; ++ ++ if (test) { ++ dev_info(&ep->dev, ++ "Please use 'free' to remove the exiting test\n"); ++ return -EBUSY; ++ } ++ ++ test = kzalloc(sizeof(*test), GFP_KERNEL); ++ if (!test) ++ return -ENOMEM; ++ ep->driver_data = test; ++ test->ep = ep; ++ spin_lock_init(&test->lock); ++ test->status = TEST_IDLE; ++ ++ test->buf = dma_alloc_coherent(pcie->dev, get_order(PCIE_BAR4_SIZE), ++ &test->buf_addr, ++ GFP_KERNEL); ++ if (!test->buf) { ++ dev_info(&ep->dev, "failed to get mem for bar4\n"); ++ err = -ENOMEM; ++ goto _err; ++ } ++ ++ test->cfg = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, ++ get_order(PCIE_BAR2_SIZE)); ++ if (!test->cfg) { ++ dev_info(&ep->dev, "failed to get mem for bar4\n"); ++ err = -ENOMEM; ++ goto _err; ++ } ++ test->cfg_addr = virt_to_phys(test->cfg); ++ ++ test->out_addr = pcie->out_base; ++ test->out = ioremap(test->out_addr, PCIE_BAR4_SIZE); ++ if (!test->out) { ++ dev_info(&ep->dev, "failed to map out\n"); ++ err = -ENOMEM; ++ goto _err; ++ } ++ ++ test->bus_addr = bus_addr; ++ ++ test->msi_addr = test->out_addr + PCIE_BAR4_SIZE; ++ test->msi = ioremap(test->msi_addr, PCIE_MSI_OB_SIZE); ++ if (!test->msi) ++ dev_info(&ep->dev, "failed to map MSI outbound region\n"); ++ ++ test->msi_msg_addr = ioread32(pcie->dbi + PCIE_MSI_MSG_ADDR_OFF) | ++ (((u64)ioread32(pcie->dbi + PCIE_MSI_MSG_ADDR_OFF + 4)) << 32); ++ test->msi_msg_data = ioread16(pcie->dbi + PCIE_MSI_MSG_DATA_OFF); ++ ++ ls_pcie_ep_dev_cfg_enable(ep); ++ ++ /* outbound iATU for memory */ ++ ls_pcie_iatu_outbound_set(pcie, 0, PCIE_ATU_TYPE_MEM, ++ test->out_addr, bus_addr, PCIE_BAR4_SIZE); ++ /* outbound iATU for MSI */ ++ ls_pcie_iatu_outbound_set(pcie, 1, PCIE_ATU_TYPE_MEM, ++ test->msi_addr, test->msi_msg_addr, ++ PCIE_MSI_OB_SIZE); ++ ++ /* ATU 0 : INBOUND : map BAR0 */ ++ ls_pcie_iatu_inbound_set(pcie, 0, 0, test->cfg_addr); ++ /* ATU 2 : INBOUND : map BAR2 */ ++ ls_pcie_iatu_inbound_set(pcie, 2, 2, test->cfg_addr); ++ /* ATU 3 : INBOUND : map BAR4 */ ++ ls_pcie_iatu_inbound_set(pcie, 3, 4, test->buf_addr); ++ ++ return 0; ++ ++_err: ++ ls_pcie_ep_free_test(ep); ++ return err; ++} ++ ++static int ls_pcie_ep_start_test(struct ls_ep_dev *ep, char *cmd) ++{ ++ struct ls_ep_test *test = ep->driver_data; ++ enum test_type type; ++ enum test_dirt dirt; ++ u32 cnt, len, loop; ++ unsigned int data; ++ char dirt_str[2]; ++ int ret; ++ ++ if (strncmp(cmd, "dma", 3) == 0) ++ type = TEST_TYPE_DMA; ++ else ++ type = TEST_TYPE_MEMCPY; ++ ++ cnt = sscanf(&cmd[4], "%1s %u %u %x", dirt_str, &len, &loop, &data); ++ if (cnt != 4) { ++ dev_info(&ep->dev, "format error %s", cmd); ++ dev_info(&ep->dev, "dma/cpy \n"); ++ return -EINVAL; ++ } ++ ++ if (strncmp(dirt_str, "r", 1) == 0) ++ dirt = TEST_DIRT_READ; ++ else ++ dirt = TEST_DIRT_WRITE; ++ ++ if (len > PCIE_BAR4_SIZE) { ++ dev_err(&ep->dev, "max len is %d", PCIE_BAR4_SIZE); ++ return -EINVAL; ++ } ++ ++ if (!test) { ++ dev_err(&ep->dev, "Please first run init command\n"); ++ return -EINVAL; ++ } ++ ++ if (ls_pcie_ep_test_try_run(test)) { ++ dev_err(&ep->dev, "There is already a test running\n"); ++ return -EINVAL; ++ } ++ ++ test->len = len; ++ test->loop = loop; ++ test->type = type; ++ test->data = (char)data; ++ test->dirt = dirt; ++ strcpy(test->cmd, cmd); ++ test->thread = kthread_run(ls_pcie_ep_test_thread, test, ++ "pcie ep test"); ++ if (IS_ERR(test->thread)) { ++ dev_err(&ep->dev, "fork failed for pcie ep test\n"); ++ ls_pcie_ep_test_done(test); ++ ret = PTR_ERR(test->thread); ++ } ++ ++ return ret; ++} ++ ++ ++/** ++ * ls_pcie_reg_ops_read - read for regs data ++ * @filp: the opened file ++ * @buffer: where to write the data for the user to read ++ * @count: the size of the user's buffer ++ * @ppos: file position offset ++ **/ ++static ssize_t ls_pcie_ep_dbg_regs_read(struct file *filp, char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct ls_ep_dev *ep = filp->private_data; ++ struct ls_pcie *pcie = ep->pcie; ++ char *buf; ++ int desc = 0, i, len; ++ ++ buf = kmalloc(4 * 1024, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ ls_pcie_ep_dev_cfg_enable(ep); ++ ++ desc += sprintf(buf + desc, "%s", "reg info:"); ++ for (i = 0; i < 0x200; i += 4) { ++ if (i % 16 == 0) ++ desc += sprintf(buf + desc, "\n%08x:", i); ++ desc += sprintf(buf + desc, " %08x", readl(pcie->dbi + i)); ++ } ++ ++ desc += sprintf(buf + desc, "\n%s", "outbound iATU info:\n"); ++ for (i = 0; i < 6; i++) { ++ writel(PCIE_ATU_REGION_OUTBOUND | i, ++ pcie->dbi + PCIE_ATU_VIEWPORT); ++ desc += sprintf(buf + desc, "iATU%d", i); ++ desc += sprintf(buf + desc, "\tLOWER PHYS 0x%08x\n", ++ readl(pcie->dbi + PCIE_ATU_LOWER_BASE)); ++ desc += sprintf(buf + desc, "\tUPPER PHYS 0x%08x\n", ++ readl(pcie->dbi + PCIE_ATU_UPPER_BASE)); ++ desc += sprintf(buf + desc, "\tLOWER BUS 0x%08x\n", ++ readl(pcie->dbi + PCIE_ATU_LOWER_TARGET)); ++ desc += sprintf(buf + desc, "\tUPPER BUS 0x%08x\n", ++ readl(pcie->dbi + PCIE_ATU_UPPER_TARGET)); ++ desc += sprintf(buf + desc, "\tLIMIT 0x%08x\n", ++ readl(pcie->dbi + PCIE_ATU_LIMIT)); ++ desc += sprintf(buf + desc, "\tCR1 0x%08x\n", ++ readl(pcie->dbi + PCIE_ATU_CR1)); ++ desc += sprintf(buf + desc, "\tCR2 0x%08x\n", ++ readl(pcie->dbi + PCIE_ATU_CR2)); ++ } ++ ++ desc += sprintf(buf + desc, "\n%s", "inbound iATU info:\n"); ++ for (i = 0; i < 6; i++) { ++ writel(PCIE_ATU_REGION_INBOUND | i, ++ pcie->dbi + PCIE_ATU_VIEWPORT); ++ desc += sprintf(buf + desc, "iATU%d", i); ++ desc += sprintf(buf + desc, "\tLOWER BUS 0x%08x\n", ++ readl(pcie->dbi + PCIE_ATU_LOWER_BASE)); ++ desc += sprintf(buf + desc, "\tUPPER BUSs 0x%08x\n", ++ readl(pcie->dbi + PCIE_ATU_UPPER_BASE)); ++ desc += sprintf(buf + desc, "\tLOWER PHYS 0x%08x\n", ++ readl(pcie->dbi + PCIE_ATU_LOWER_TARGET)); ++ desc += sprintf(buf + desc, "\tUPPER PHYS 0x%08x\n", ++ readl(pcie->dbi + PCIE_ATU_UPPER_TARGET)); ++ desc += sprintf(buf + desc, "\tLIMIT 0x%08x\n", ++ readl(pcie->dbi + PCIE_ATU_LIMIT)); ++ desc += sprintf(buf + desc, "\tCR1 0x%08x\n", ++ readl(pcie->dbi + PCIE_ATU_CR1)); ++ desc += sprintf(buf + desc, "\tCR2 0x%08x\n", ++ readl(pcie->dbi + PCIE_ATU_CR2)); ++ } ++ ++ len = simple_read_from_buffer(buffer, count, ppos, buf, desc); ++ kfree(buf); ++ ++ return len; ++} ++ ++/** ++ * ls_pcie_ep_dbg_regs_write - write into regs datum ++ * @filp: the opened file ++ * @buffer: where to find the user's data ++ * @count: the length of the user's data ++ * @ppos: file position offset ++ **/ ++static ssize_t ls_pcie_ep_dbg_regs_write(struct file *filp, ++ const char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct ls_ep_dev *ep = filp->private_data; ++ struct ls_pcie *pcie = ep->pcie; ++ char buf[256]; ++ ++ if (count >= sizeof(buf)) ++ return -ENOSPC; ++ ++ memset(buf, 0, sizeof(buf)); ++ ++ if (copy_from_user(buf, buffer, count)) ++ return -EFAULT; ++ ++ ls_pcie_ep_dev_cfg_enable(ep); ++ ++ if (strncmp(buf, "reg", 3) == 0) { ++ u32 reg, value; ++ int cnt; ++ ++ cnt = sscanf(&buf[3], "%x %x", ®, &value); ++ if (cnt == 2) { ++ writel(value, pcie->dbi + reg); ++ value = readl(pcie->dbi + reg); ++ dev_info(&ep->dev, "reg 0x%08x: 0x%08x\n", ++ reg, value); ++ } else { ++ dev_info(&ep->dev, "reg \n"); ++ } ++ } else if (strncmp(buf, "atu", 3) == 0) { ++ /* to do */ ++ dev_info(&ep->dev, " Not support atu command\n"); ++ } else { ++ dev_info(&ep->dev, "Unknown command %s\n", buf); ++ dev_info(&ep->dev, "Available commands:\n"); ++ dev_info(&ep->dev, " reg \n"); ++ } ++ ++ return count; ++} ++ ++static const struct file_operations ls_pcie_ep_dbg_regs_fops = { ++ .owner = THIS_MODULE, ++ .open = simple_open, ++ .read = ls_pcie_ep_dbg_regs_read, ++ .write = ls_pcie_ep_dbg_regs_write, ++}; ++ ++static ssize_t ls_pcie_ep_dbg_test_read(struct file *filp, ++ char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct ls_ep_dev *ep = filp->private_data; ++ struct ls_ep_test *test = ep->driver_data; ++ char buf[512]; ++ int desc = 0, len; ++ ++ if (!test) { ++ dev_info(&ep->dev, " there is NO test\n"); ++ return 0; ++ } ++ ++ if (test->status != TEST_IDLE) { ++ dev_info(&ep->dev, "test %s is running\n", test->cmd); ++ return 0; ++ } ++ ++ desc = sprintf(buf, "MSI ADDR:0x%llx MSI DATA:0x%x\n", ++ test->msi_msg_addr, test->msi_msg_data); ++ ++ desc += sprintf(buf + desc, "%s throughput:%lluMbps\n", ++ test->cmd, test->result); ++ ++ len = simple_read_from_buffer(buffer, count, ppos, ++ buf, desc); ++ ++ return len; ++} ++ ++static ssize_t ls_pcie_ep_dbg_test_write(struct file *filp, ++ const char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct ls_ep_dev *ep = filp->private_data; ++ char buf[256]; ++ ++ if (count >= sizeof(buf)) ++ return -ENOSPC; ++ ++ memset(buf, 0, sizeof(buf)); ++ ++ if (copy_from_user(buf, buffer, count)) ++ return -EFAULT; ++ ++ if (strncmp(buf, "init", 4) == 0) { ++ int i = 4; ++ u64 bus_addr; ++ ++ while (buf[i] == ' ') ++ i++; ++ ++ if (kstrtou64(&buf[i], 0, &bus_addr)) ++ dev_info(&ep->dev, "command: init \n"); ++ else { ++ if (ls_pcie_ep_init_test(ep, bus_addr)) ++ dev_info(&ep->dev, "failed to init test\n"); ++ } ++ } else if (strncmp(buf, "free", 4) == 0) ++ ls_pcie_ep_free_test(ep); ++ else if (strncmp(buf, "dma", 3) == 0 || ++ strncmp(buf, "cpy", 3) == 0) ++ ls_pcie_ep_start_test(ep, buf); ++ else { ++ dev_info(&ep->dev, "Unknown command: %s\n", buf); ++ dev_info(&ep->dev, "Available commands:\n"); ++ dev_info(&ep->dev, "\tinit \n"); ++ dev_info(&ep->dev, "\t \n"); ++ dev_info(&ep->dev, "\tfree\n"); ++ } ++ ++ return count; ++} ++ ++static const struct file_operations ls_pcie_ep_dbg_test_fops = { ++ .owner = THIS_MODULE, ++ .open = simple_open, ++ .read = ls_pcie_ep_dbg_test_read, ++ .write = ls_pcie_ep_dbg_test_write, ++}; ++ ++static ssize_t ls_pcie_ep_dbg_dump_read(struct file *filp, ++ char __user *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct ls_ep_dev *ep = filp->private_data; ++ struct ls_ep_test *test = ep->driver_data; ++ char *buf; ++ int desc = 0, i, len; ++ ++ buf = kmalloc(4 * 1024, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ if (!test) { ++ dev_info(&ep->dev, " there is NO test\n"); ++ kfree(buf); ++ return 0; ++ } ++ ++ desc += sprintf(buf + desc, "%s", "dump info:"); ++ for (i = 0; i < 256; i += 4) { ++ if (i % 16 == 0) ++ desc += sprintf(buf + desc, "\n%08x:", i); ++ desc += sprintf(buf + desc, " %08x", readl(test->buf + i)); ++ } ++ ++ desc += sprintf(buf + desc, "\n"); ++ len = simple_read_from_buffer(buffer, count, ppos, buf, desc); ++ ++ kfree(buf); ++ ++ return len; ++} ++ ++static const struct file_operations ls_pcie_ep_dbg_dump_fops = { ++ .owner = THIS_MODULE, ++ .open = simple_open, ++ .read = ls_pcie_ep_dbg_dump_read, ++}; ++ ++static int ls_pcie_ep_dev_dbgfs_init(struct ls_ep_dev *ep) ++{ ++ struct ls_pcie *pcie = ep->pcie; ++ struct dentry *pfile; ++ ++ ls_pcie_ep_dev_cfg_enable(ep); ++ ++ ep->dir = debugfs_create_dir(dev_name(&ep->dev), pcie->dir); ++ if (!ep->dir) ++ return -ENOMEM; ++ ++ pfile = debugfs_create_file("regs", 0600, ep->dir, ep, ++ &ls_pcie_ep_dbg_regs_fops); ++ if (!pfile) ++ dev_info(&ep->dev, "debugfs regs for failed\n"); ++ ++ pfile = debugfs_create_file("test", 0600, ep->dir, ep, ++ &ls_pcie_ep_dbg_test_fops); ++ if (!pfile) ++ dev_info(&ep->dev, "debugfs test for failed\n"); ++ ++ pfile = debugfs_create_file("dump", 0600, ep->dir, ep, ++ &ls_pcie_ep_dbg_dump_fops); ++ if (!pfile) ++ dev_info(&ep->dev, "debugfs dump for failed\n"); ++ ++ return 0; ++} ++ ++int ls_pcie_ep_dbgfs_init(struct ls_pcie *pcie) ++{ ++ struct ls_ep_dev *ep; ++ ++ pcie->dir = debugfs_create_dir(dev_name(pcie->dev), NULL); ++ if (!pcie->dir) ++ return -ENOMEM; ++ ++ list_for_each_entry(ep, &pcie->ep_list, node) ++ ls_pcie_ep_dev_dbgfs_init(ep); ++ ++ return 0; ++} ++ ++int ls_pcie_ep_dbgfs_remove(struct ls_pcie *pcie) ++{ ++ debugfs_remove_recursive(pcie->dir); ++ return 0; ++} ++ ++MODULE_AUTHOR("Minghuan Lian "); ++MODULE_DESCRIPTION("Freescale Layerscape PCIe EP controller driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/pci/host/pci-layerscape-ep.c b/drivers/pci/host/pci-layerscape-ep.c +new file mode 100644 +index 00000000..8f1cca6e +--- /dev/null ++++ b/drivers/pci/host/pci-layerscape-ep.c +@@ -0,0 +1,309 @@ ++/* ++ * PCIe Endpoint driver for Freescale Layerscape SoCs ++ * ++ * Copyright (C) 2015 Freescale Semiconductor. ++ * ++ * Author: Minghuan Lian ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "pci-layerscape-ep.h" ++ ++struct ls_ep_dev * ++ls_pci_ep_find(struct ls_pcie *pcie, int dev_id) ++{ ++ struct ls_ep_dev *ep; ++ ++ list_for_each_entry(ep, &pcie->ep_list, node) { ++ if (ep->dev_id == dev_id) ++ return ep; ++ } ++ ++ return NULL; ++} ++ ++static void ls_pcie_try_cfg2(struct ls_pcie *pcie, int pf, int vf) ++{ ++ if (pcie->sriov) ++ writel(PCIE_LCTRL0_VAL(pf, vf), ++ pcie->dbi + PCIE_LUT_BASE + PCIE_LUT_LCTRL0); ++} ++ ++static bool ls_pcie_is_bridge(struct ls_pcie *pcie) ++{ ++ u32 header_type = 0; ++ ++ header_type = readl(pcie->dbi + (PCI_HEADER_TYPE & ~0x3)); ++ header_type = (header_type >> 16) & 0x7f; ++ ++ return header_type == PCI_HEADER_TYPE_BRIDGE; ++} ++ ++void ls_pcie_iatu_outbound_set(struct ls_pcie *pcie, int idx, int type, ++ u64 cpu_addr, u64 pci_addr, u32 size) ++{ ++ writel(PCIE_ATU_REGION_OUTBOUND | idx, ++ pcie->dbi + PCIE_ATU_VIEWPORT); ++ writel(lower_32_bits(cpu_addr), ++ pcie->dbi + PCIE_ATU_LOWER_BASE); ++ writel(upper_32_bits(cpu_addr), ++ pcie->dbi + PCIE_ATU_UPPER_BASE); ++ writel(lower_32_bits(cpu_addr + size - 1), ++ pcie->dbi + PCIE_ATU_LIMIT); ++ writel(lower_32_bits(pci_addr), ++ pcie->dbi + PCIE_ATU_LOWER_TARGET); ++ writel(upper_32_bits(pci_addr), ++ pcie->dbi + PCIE_ATU_UPPER_TARGET); ++ writel(type, pcie->dbi + PCIE_ATU_CR1); ++ writel(PCIE_ATU_ENABLE, pcie->dbi + PCIE_ATU_CR2); ++} ++ ++/* Use bar match mode and MEM type as default */ ++void ls_pcie_iatu_inbound_set(struct ls_pcie *pcie, int idx, ++ int bar, u64 phys) ++{ ++ writel(PCIE_ATU_REGION_INBOUND | idx, pcie->dbi + PCIE_ATU_VIEWPORT); ++ writel((u32)phys, pcie->dbi + PCIE_ATU_LOWER_TARGET); ++ writel(phys >> 32, pcie->dbi + PCIE_ATU_UPPER_TARGET); ++ writel(PCIE_ATU_TYPE_MEM, pcie->dbi + PCIE_ATU_CR1); ++ writel(PCIE_ATU_ENABLE | PCIE_ATU_BAR_MODE_ENABLE | ++ PCIE_ATU_BAR_NUM(bar), pcie->dbi + PCIE_ATU_CR2); ++} ++ ++void ls_pcie_ep_dev_cfg_enable(struct ls_ep_dev *ep) ++{ ++ ls_pcie_try_cfg2(ep->pcie, ep->pf_idx, ep->vf_idx); ++} ++ ++void ls_pcie_ep_setup_bar(void *bar_base, int bar, u32 size) ++{ ++ if (size < 4 * 1024) ++ return; ++ ++ switch (bar) { ++ case 0: ++ writel(size - 1, bar_base + PCI_BASE_ADDRESS_0); ++ break; ++ case 1: ++ writel(size - 1, bar_base + PCI_BASE_ADDRESS_1); ++ break; ++ case 2: ++ writel(size - 1, bar_base + PCI_BASE_ADDRESS_2); ++ writel(0, bar_base + PCI_BASE_ADDRESS_3); ++ break; ++ case 4: ++ writel(size - 1, bar_base + PCI_BASE_ADDRESS_4); ++ writel(0, bar_base + PCI_BASE_ADDRESS_5); ++ break; ++ default: ++ break; ++ } ++} ++ ++void ls_pcie_ep_dev_setup_bar(struct ls_ep_dev *ep, int bar, u32 size) ++{ ++ struct ls_pcie *pcie = ep->pcie; ++ void *bar_base; ++ ++ if (size < 4 * 1024) ++ return; ++ ++ if (pcie->sriov) ++ bar_base = pcie->dbi; ++ else ++ bar_base = pcie->dbi + PCIE_NO_SRIOV_BAR_BASE; ++ ++ ls_pcie_ep_dev_cfg_enable(ep); ++ ls_pcie_ep_setup_bar(bar_base, bar, size); ++} ++ ++static int ls_pcie_ep_dev_init(struct ls_pcie *pcie, int pf_idx, int vf_idx) ++{ ++ struct ls_ep_dev *ep; ++ ++ ep = devm_kzalloc(pcie->dev, sizeof(*ep), GFP_KERNEL); ++ if (!ep) ++ return -ENOMEM; ++ ++ ep->pcie = pcie; ++ ep->pf_idx = pf_idx; ++ ep->vf_idx = vf_idx; ++ if (vf_idx) ++ ep->dev_id = pf_idx + 4 + 4 * (vf_idx - 1); ++ else ++ ep->dev_id = pf_idx; ++ ++ if (ep->vf_idx) ++ dev_set_name(&ep->dev, "pf%d-vf%d", ++ ep->pf_idx, ++ ep->vf_idx); ++ else ++ dev_set_name(&ep->dev, "pf%d", ++ ep->pf_idx); ++ ++ list_add_tail(&ep->node, &pcie->ep_list); ++ ++ return 0; ++} ++ ++static int ls_pcie_ep_init(struct ls_pcie *pcie) ++{ ++ u32 sriov_header; ++ int pf, vf, i, j; ++ ++ sriov_header = readl(pcie->dbi + PCIE_SRIOV_POS); ++ ++ if (PCI_EXT_CAP_ID(sriov_header) == PCI_EXT_CAP_ID_SRIOV) { ++ pcie->sriov = PCIE_SRIOV_POS; ++ pf = PCIE_PF_NUM; ++ vf = PCIE_VF_NUM; ++ } else { ++ pcie->sriov = 0; ++ pf = 1; ++ vf = 0; ++ } ++ ++ for (i = 0; i < pf; i++) { ++ for (j = 0; j <= vf; j++) ++ ls_pcie_ep_dev_init(pcie, i, j); ++ } ++ ++ return 0; ++} ++ ++static struct ls_pcie_ep_drvdata ls1043_drvdata = { ++ .lut_offset = 0x10000, ++ .ltssm_shift = 24, ++ .lut_dbg = 0x7fc, ++}; ++ ++static struct ls_pcie_ep_drvdata ls1046_drvdata = { ++ .lut_offset = 0x80000, ++ .ltssm_shift = 24, ++ .lut_dbg = 0x407fc, ++}; ++ ++static struct ls_pcie_ep_drvdata ls2080_drvdata = { ++ .lut_offset = 0x80000, ++ .ltssm_shift = 0, ++ .lut_dbg = 0x7fc, ++}; ++ ++static const struct of_device_id ls_pcie_ep_of_match[] = { ++ { .compatible = "fsl,ls1021a-pcie", }, ++ { .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata }, ++ { .compatible = "fsl,ls1046a-pcie", .data = &ls1046_drvdata }, ++ { .compatible = "fsl,ls2080a-pcie", .data = &ls2080_drvdata }, ++ { .compatible = "fsl,ls2085a-pcie", .data = &ls2080_drvdata }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, ls_pcie_ep_of_match); ++ ++static int ls_pcie_ep_probe(struct platform_device *pdev) ++{ ++ struct ls_pcie *pcie; ++ struct resource *dbi_base, *cfg_res; ++ const struct of_device_id *match; ++ int ret; ++ ++ match = of_match_device(ls_pcie_ep_of_match, &pdev->dev); ++ if (!match) ++ return -ENODEV; ++ ++ pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); ++ if (!pcie) ++ return -ENOMEM; ++ ++ pcie->dev = &pdev->dev; ++ INIT_LIST_HEAD(&pcie->ep_list); ++ ++ dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); ++ pcie->dbi = devm_ioremap_resource(&pdev->dev, dbi_base); ++ if (IS_ERR(pcie->dbi)) { ++ dev_err(&pdev->dev, "missing *regs* space\n"); ++ return PTR_ERR(pcie->dbi); ++ } ++ ++ pcie->drvdata = match->data; ++ pcie->lut = pcie->dbi + pcie->drvdata->lut_offset; ++ ++ if (ls_pcie_is_bridge(pcie)) ++ return -ENODEV; ++ ++ dev_info(pcie->dev, "in EP mode\n"); ++ ++ cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); ++ if (cfg_res) ++ pcie->out_base = cfg_res->start; ++ else { ++ dev_err(&pdev->dev, "missing *config* space\n"); ++ return -ENODEV; ++ } ++ ++ ret = ls_pcie_ep_init(pcie); ++ if (ret) ++ return ret; ++ ++ ls_pcie_ep_dbgfs_init(pcie); ++ ++ platform_set_drvdata(pdev, pcie); ++ ++ return 0; ++} ++ ++static int ls_pcie_ep_dev_remove(struct ls_ep_dev *ep) ++{ ++ list_del(&ep->node); ++ ++ return 0; ++} ++ ++static int ls_pcie_ep_remove(struct platform_device *pdev) ++{ ++ struct ls_pcie *pcie = platform_get_drvdata(pdev); ++ struct ls_ep_dev *ep, *tmp; ++ ++ if (!pcie) ++ return 0; ++ ++ ls_pcie_ep_dbgfs_remove(pcie); ++ ++ list_for_each_entry_safe(ep, tmp, &pcie->ep_list, node) ++ ls_pcie_ep_dev_remove(ep); ++ ++ return 0; ++} ++ ++static struct platform_driver ls_pcie_ep_driver = { ++ .driver = { ++ .name = "ls-pcie-ep", ++ .owner = THIS_MODULE, ++ .of_match_table = ls_pcie_ep_of_match, ++ }, ++ .probe = ls_pcie_ep_probe, ++ .remove = ls_pcie_ep_remove, ++}; ++ ++module_platform_driver(ls_pcie_ep_driver); ++ ++MODULE_AUTHOR("Minghuan Lian "); ++MODULE_DESCRIPTION("Freescale Layerscape PCIe EP driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/pci/host/pci-layerscape-ep.h b/drivers/pci/host/pci-layerscape-ep.h +new file mode 100644 +index 00000000..990c0ff5 +--- /dev/null ++++ b/drivers/pci/host/pci-layerscape-ep.h +@@ -0,0 +1,115 @@ ++/* ++ * PCIe Endpoint driver for Freescale Layerscape SoCs ++ * ++ * Copyright (C) 2015 Freescale Semiconductor. ++ * ++ * Author: Minghuan Lian ++ * ++ * 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 _PCIE_LAYERSCAPE_EP_H ++#define _PCIE_LAYERSCAPE_EP_H ++ ++#include ++ ++/* Synopsis specific PCIE configuration registers */ ++#define PCIE_ATU_VIEWPORT 0x900 ++#define PCIE_ATU_REGION_INBOUND (0x1 << 31) ++#define PCIE_ATU_REGION_OUTBOUND (0x0 << 31) ++#define PCIE_ATU_REGION_INDEX3 (0x3 << 0) ++#define PCIE_ATU_REGION_INDEX2 (0x2 << 0) ++#define PCIE_ATU_REGION_INDEX1 (0x1 << 0) ++#define PCIE_ATU_REGION_INDEX0 (0x0 << 0) ++#define PCIE_ATU_CR1 0x904 ++#define PCIE_ATU_TYPE_MEM (0x0 << 0) ++#define PCIE_ATU_TYPE_IO (0x2 << 0) ++#define PCIE_ATU_TYPE_CFG0 (0x4 << 0) ++#define PCIE_ATU_TYPE_CFG1 (0x5 << 0) ++#define PCIE_ATU_CR2 0x908 ++#define PCIE_ATU_ENABLE (0x1 << 31) ++#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30) ++#define PCIE_ATU_LOWER_BASE 0x90C ++#define PCIE_ATU_UPPER_BASE 0x910 ++#define PCIE_ATU_LIMIT 0x914 ++#define PCIE_ATU_LOWER_TARGET 0x918 ++#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24) ++#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19) ++#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16) ++#define PCIE_ATU_UPPER_TARGET 0x91C ++ ++/* PEX internal configuration registers */ ++#define PCIE_DBI_RO_WR_EN 0x8bc /* DBI Read-Only Write Enable Register */ ++ ++/* PEX LUT registers */ ++#define PCIE_LUT_BASE 0x80000 ++#define PCIE_LUT_DBG 0x7FC /* PEX LUT Debug register */ ++ ++#define PCIE_LUT_LCTRL0 0x7F8 ++ ++#define PCIE_ATU_BAR_NUM(bar) ((bar) << 8) ++#define PCIE_LCTRL0_CFG2_ENABLE (1 << 31) ++#define PCIE_LCTRL0_VF(vf) ((vf) << 22) ++#define PCIE_LCTRL0_PF(pf) ((pf) << 16) ++#define PCIE_LCTRL0_VF_ACTIVE (1 << 21) ++#define PCIE_LCTRL0_VAL(pf, vf) (PCIE_LCTRL0_PF(pf) | \ ++ PCIE_LCTRL0_VF(vf) | \ ++ ((vf) == 0 ? 0 : PCIE_LCTRL0_VF_ACTIVE) | \ ++ PCIE_LCTRL0_CFG2_ENABLE) ++ ++#define PCIE_NO_SRIOV_BAR_BASE 0x1000 ++ ++#define PCIE_SRIOV_POS 0x178 ++#define PCIE_PF_NUM 2 ++#define PCIE_VF_NUM 64 ++ ++struct ls_pcie_ep_drvdata { ++ u32 lut_offset; ++ u32 ltssm_shift; ++ u32 lut_dbg; ++}; ++ ++struct ls_pcie { ++ struct list_head ep_list; ++ struct device *dev; ++ struct dentry *dir; ++ const struct ls_pcie_ep_drvdata *drvdata; ++ void __iomem *dbi; ++ void __iomem *lut; ++ phys_addr_t out_base; ++ int sriov; ++ int index; ++}; ++ ++struct ls_ep_dev { ++ struct list_head node; ++ struct ls_pcie *pcie; ++ struct device dev; ++ struct dentry *dir; ++ int pf_idx; ++ int vf_idx; ++ int dev_id; ++ void *driver_data; ++}; ++ ++struct ls_ep_dev *ls_pci_ep_find(struct ls_pcie *pcie, int dev_id); ++ ++void ls_pcie_iatu_outbound_set(struct ls_pcie *pcie, int idx, int type, ++ u64 cpu_addr, u64 pci_addr, u32 size); ++ ++/* Use bar match mode and MEM type as default */ ++void ls_pcie_iatu_inbound_set(struct ls_pcie *pcie, int idx, ++ int bar, u64 phys); ++ ++void ls_pcie_ep_dev_setup_bar(struct ls_ep_dev *ep, int bar, u32 size); ++ ++ ++void ls_pcie_ep_dev_cfg_enable(struct ls_ep_dev *ep); ++ ++int ls_pcie_ep_dbgfs_init(struct ls_pcie *pcie); ++int ls_pcie_ep_dbgfs_remove(struct ls_pcie *pcie); ++ ++#endif /* _PCIE_LAYERSCAPE_EP_H */ +diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c +index 65370799..4713b872 100644 +--- a/drivers/pci/host/pci-layerscape.c ++++ b/drivers/pci/host/pci-layerscape.c +@@ -35,12 +35,14 @@ + #define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */ + #define PCIE_DBI_RO_WR_EN 0x8bc /* DBI Read-Only Write Enable Register */ + +-/* PEX LUT registers */ +-#define PCIE_LUT_DBG 0x7FC /* PEX LUT Debug Register */ ++#define PCIE_IATU_NUM 6 ++ ++static void ls_pcie_host_init(struct pcie_port *pp); + + struct ls_pcie_drvdata { + u32 lut_offset; + u32 ltssm_shift; ++ u32 lut_dbg; + struct pcie_host_ops *ops; + }; + +@@ -86,6 +88,14 @@ static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie) + iowrite32(val, pcie->pp.dbi_base + PCIE_STRFMR1); + } + ++static void ls_pcie_disable_outbound_atus(struct ls_pcie *pcie) ++{ ++ int i; ++ ++ for (i = 0; i < PCIE_IATU_NUM; i++) ++ dw_pcie_disable_outbound_atu(&pcie->pp, i); ++} ++ + static int ls1021_pcie_link_up(struct pcie_port *pp) + { + u32 state; +@@ -134,7 +144,7 @@ static int ls_pcie_link_up(struct pcie_port *pp) + struct ls_pcie *pcie = to_ls_pcie(pp); + u32 state; + +- state = (ioread32(pcie->lut + PCIE_LUT_DBG) >> ++ state = (ioread32(pcie->lut + pcie->drvdata->lut_dbg) >> + pcie->drvdata->ltssm_shift) & + LTSSM_STATE_MASK; + +@@ -153,6 +163,9 @@ static void ls_pcie_host_init(struct pcie_port *pp) + ls_pcie_clear_multifunction(pcie); + ls_pcie_drop_msg_tlp(pcie); + iowrite32(0, pcie->pp.dbi_base + PCIE_DBI_RO_WR_EN); ++ ++ ls_pcie_disable_outbound_atus(pcie); ++ dw_pcie_setup_rc(pp); + } + + static int ls_pcie_msi_host_init(struct pcie_port *pp, +@@ -196,20 +209,38 @@ static struct ls_pcie_drvdata ls1021_drvdata = { + static struct ls_pcie_drvdata ls1043_drvdata = { + .lut_offset = 0x10000, + .ltssm_shift = 24, ++ .lut_dbg = 0x7fc, ++ .ops = &ls_pcie_host_ops, ++}; ++ ++static struct ls_pcie_drvdata ls1046_drvdata = { ++ .lut_offset = 0x80000, ++ .ltssm_shift = 24, ++ .lut_dbg = 0x407fc, + .ops = &ls_pcie_host_ops, + }; + + static struct ls_pcie_drvdata ls2080_drvdata = { + .lut_offset = 0x80000, + .ltssm_shift = 0, ++ .lut_dbg = 0x7fc, ++ .ops = &ls_pcie_host_ops, ++}; ++ ++static struct ls_pcie_drvdata ls2088_drvdata = { ++ .lut_offset = 0x80000, ++ .ltssm_shift = 0, ++ .lut_dbg = 0x407fc, + .ops = &ls_pcie_host_ops, + }; + + static const struct of_device_id ls_pcie_of_match[] = { + { .compatible = "fsl,ls1021a-pcie", .data = &ls1021_drvdata }, + { .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata }, ++ { .compatible = "fsl,ls1046a-pcie", .data = &ls1046_drvdata }, + { .compatible = "fsl,ls2080a-pcie", .data = &ls2080_drvdata }, + { .compatible = "fsl,ls2085a-pcie", .data = &ls2080_drvdata }, ++ { .compatible = "fsl,ls2088a-pcie", .data = &ls2088_drvdata }, + { }, + }; + +diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c +index af8f6e92..2358e049 100644 +--- a/drivers/pci/host/pcie-designware.c ++++ b/drivers/pci/host/pcie-designware.c +@@ -478,6 +478,12 @@ int dw_pcie_wait_for_link(struct pcie_port *pp) + return -ETIMEDOUT; + } + ++void dw_pcie_disable_outbound_atu(struct pcie_port *pp, int index) ++{ ++ dw_pcie_writel_rc(pp, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_OUTBOUND | index); ++ dw_pcie_writel_rc(pp, PCIE_ATU_CR2, 0); ++} ++ + int dw_pcie_link_up(struct pcie_port *pp) + { + u32 val; +diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h +index a567ea28..4e6672b2 100644 +--- a/drivers/pci/host/pcie-designware.h ++++ b/drivers/pci/host/pcie-designware.h +@@ -82,5 +82,6 @@ int dw_pcie_wait_for_link(struct pcie_port *pp); + int dw_pcie_link_up(struct pcie_port *pp); + void dw_pcie_setup_rc(struct pcie_port *pp); + int dw_pcie_host_init(struct pcie_port *pp); ++void dw_pcie_disable_outbound_atu(struct pcie_port *pp, int index); + + #endif /* _PCIE_DESIGNWARE_H */ +diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c +index e9270b40..1bad877a 100644 +--- a/drivers/pci/pcie/portdrv_core.c ++++ b/drivers/pci/pcie/portdrv_core.c +@@ -44,52 +44,30 @@ static void release_pcie_device(struct device *dev) + } + + /** +- * pcie_port_msix_add_entry - add entry to given array of MSI-X entries +- * @entries: Array of MSI-X entries +- * @new_entry: Index of the entry to add to the array +- * @nr_entries: Number of entries already in the array ++ * pcibios_check_service_irqs - check irqs in the device tree ++ * @dev: PCI Express port to handle ++ * @irqs: Array of irqs to populate ++ * @mask: Bitmask of port capabilities returned by get_port_device_capability() ++ * ++ * Return value: 0 means no service irqs in the device tree + * +- * Return value: Position of the added entry in the array + */ +-static int pcie_port_msix_add_entry( +- struct msix_entry *entries, int new_entry, int nr_entries) ++int __weak pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask) + { +- int j; +- +- for (j = 0; j < nr_entries; j++) +- if (entries[j].entry == new_entry) +- return j; +- +- entries[j].entry = new_entry; +- return j; ++ return 0; + } + + /** + * pcie_port_enable_msix - try to set up MSI-X as interrupt mode for given port + * @dev: PCI Express port to handle +- * @vectors: Array of interrupt vectors to populate ++ * @irqs: Array of interrupt vectors to populate + * @mask: Bitmask of port capabilities returned by get_port_device_capability() + * + * Return value: 0 on success, error code on failure + */ +-static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask) ++static int pcie_port_enable_msix(struct pci_dev *dev, int *irqs, int mask) + { +- struct msix_entry *msix_entries; +- int idx[PCIE_PORT_DEVICE_MAXSERVICES]; +- int nr_entries, status, pos, i, nvec; +- u16 reg16; +- u32 reg32; +- +- nr_entries = pci_msix_vec_count(dev); +- if (nr_entries < 0) +- return nr_entries; +- BUG_ON(!nr_entries); +- if (nr_entries > PCIE_PORT_MAX_MSIX_ENTRIES) +- nr_entries = PCIE_PORT_MAX_MSIX_ENTRIES; +- +- msix_entries = kzalloc(sizeof(*msix_entries) * nr_entries, GFP_KERNEL); +- if (!msix_entries) +- return -ENOMEM; ++ int nr_entries, entry, nvec = 0; + + /* + * Allocate as many entries as the port wants, so that we can check +@@ -97,20 +75,13 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask) + * equal to the number of entries this port actually uses, we'll happily + * go through without any tricks. + */ +- for (i = 0; i < nr_entries; i++) +- msix_entries[i].entry = i; +- +- status = pci_enable_msix_exact(dev, msix_entries, nr_entries); +- if (status) +- goto Exit; +- +- for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) +- idx[i] = -1; +- status = -EIO; +- nvec = 0; ++ nr_entries = pci_alloc_irq_vectors(dev, 1, PCIE_PORT_MAX_MSIX_ENTRIES, ++ PCI_IRQ_MSIX); ++ if (nr_entries < 0) ++ return nr_entries; + + if (mask & (PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP)) { +- int entry; ++ u16 reg16; + + /* + * The code below follows the PCI Express Base Specification 2.0 +@@ -125,18 +96,16 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask) + pcie_capability_read_word(dev, PCI_EXP_FLAGS, ®16); + entry = (reg16 & PCI_EXP_FLAGS_IRQ) >> 9; + if (entry >= nr_entries) +- goto Error; ++ goto out_free_irqs; + +- i = pcie_port_msix_add_entry(msix_entries, entry, nvec); +- if (i == nvec) +- nvec++; ++ irqs[PCIE_PORT_SERVICE_PME_SHIFT] = pci_irq_vector(dev, entry); ++ irqs[PCIE_PORT_SERVICE_HP_SHIFT] = pci_irq_vector(dev, entry); + +- idx[PCIE_PORT_SERVICE_PME_SHIFT] = i; +- idx[PCIE_PORT_SERVICE_HP_SHIFT] = i; ++ nvec = max(nvec, entry + 1); + } + + if (mask & PCIE_PORT_SERVICE_AER) { +- int entry; ++ u32 reg32, pos; + + /* + * The code below follows Section 7.10.10 of the PCI Express +@@ -151,13 +120,11 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask) + pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, ®32); + entry = reg32 >> 27; + if (entry >= nr_entries) +- goto Error; ++ goto out_free_irqs; + +- i = pcie_port_msix_add_entry(msix_entries, entry, nvec); +- if (i == nvec) +- nvec++; ++ irqs[PCIE_PORT_SERVICE_AER_SHIFT] = pci_irq_vector(dev, entry); + +- idx[PCIE_PORT_SERVICE_AER_SHIFT] = i; ++ nvec = max(nvec, entry + 1); + } + + /* +@@ -165,41 +132,54 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask) + * what we have. Otherwise, the port has some extra entries not for the + * services we know and we need to work around that. + */ +- if (nvec == nr_entries) { +- status = 0; +- } else { ++ if (nvec != nr_entries) { + /* Drop the temporary MSI-X setup */ +- pci_disable_msix(dev); ++ pci_free_irq_vectors(dev); + + /* Now allocate the MSI-X vectors for real */ +- status = pci_enable_msix_exact(dev, msix_entries, nvec); +- if (status) +- goto Exit; ++ nr_entries = pci_alloc_irq_vectors(dev, nvec, nvec, ++ PCI_IRQ_MSIX); ++ if (nr_entries < 0) ++ return nr_entries; + } + +- for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) +- vectors[i] = idx[i] >= 0 ? msix_entries[idx[i]].vector : -1; +- +- Exit: +- kfree(msix_entries); +- return status; ++ return 0; + +- Error: +- pci_disable_msix(dev); +- goto Exit; ++out_free_irqs: ++ pci_free_irq_vectors(dev); ++ return -EIO; + } + + /** +- * init_service_irqs - initialize irqs for PCI Express port services ++ * pcie_init_service_irqs - initialize irqs for PCI Express port services + * @dev: PCI Express port to handle + * @irqs: Array of irqs to populate + * @mask: Bitmask of port capabilities returned by get_port_device_capability() + * + * Return value: Interrupt mode associated with the port + */ +-static int init_service_irqs(struct pci_dev *dev, int *irqs, int mask) ++static int pcie_init_service_irqs(struct pci_dev *dev, int *irqs, int mask) + { +- int i, irq = -1; ++ unsigned flags = PCI_IRQ_LEGACY | PCI_IRQ_MSI; ++ int ret, i; ++ int irq = -1; ++ ++ for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) ++ irqs[i] = -1; ++ ++ /* Check if some platforms owns independent irq pins for AER/PME etc. ++ * Some platforms may own independent AER/PME interrupts and set ++ * them in the device tree file. ++ */ ++ ret = pcibios_check_service_irqs(dev, irqs, mask); ++ if (ret) { ++ if (dev->irq) ++ irq = dev->irq; ++ for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) ++ if (irqs[i] == -1 && i != PCIE_PORT_SERVICE_VC_SHIFT) ++ irqs[i] = irq; ++ return 0; ++ } + + /* + * If MSI cannot be used for PCIe PME or hotplug, we have to use +@@ -207,41 +187,25 @@ static int init_service_irqs(struct pci_dev *dev, int *irqs, int mask) + */ + if (((mask & PCIE_PORT_SERVICE_PME) && pcie_pme_no_msi()) || + ((mask & PCIE_PORT_SERVICE_HP) && pciehp_no_msi())) { +- if (dev->irq) +- irq = dev->irq; +- goto no_msi; ++ flags &= ~PCI_IRQ_MSI; ++ } else { ++ /* Try to use MSI-X if supported */ ++ if (!pcie_port_enable_msix(dev, irqs, mask)) ++ return 0; + } + +- /* Try to use MSI-X if supported */ +- if (!pcie_port_enable_msix(dev, irqs, mask)) +- return 0; +- +- /* +- * We're not going to use MSI-X, so try MSI and fall back to INTx. +- * If neither MSI/MSI-X nor INTx available, try other interrupt. On +- * some platforms, root port doesn't support MSI/MSI-X/INTx in RC mode. +- */ +- if (!pci_enable_msi(dev) || dev->irq) +- irq = dev->irq; ++ ret = pci_alloc_irq_vectors(dev, 1, 1, flags); ++ if (ret < 0) ++ return -ENODEV; + +- no_msi: +- for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) +- irqs[i] = irq; +- irqs[PCIE_PORT_SERVICE_VC_SHIFT] = -1; ++ for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { ++ if (i != PCIE_PORT_SERVICE_VC_SHIFT) ++ irqs[i] = pci_irq_vector(dev, 0); ++ } + +- if (irq < 0) +- return -ENODEV; + return 0; + } + +-static void cleanup_service_irqs(struct pci_dev *dev) +-{ +- if (dev->msix_enabled) +- pci_disable_msix(dev); +- else if (dev->msi_enabled) +- pci_disable_msi(dev); +-} +- + /** + * get_port_device_capability - discover capabilities of a PCI Express port + * @dev: PCI Express port to examine +@@ -378,7 +342,7 @@ int pcie_port_device_register(struct pci_dev *dev) + * that can be used in the absence of irqs. Allow them to determine + * if that is to be used. + */ +- status = init_service_irqs(dev, irqs, capabilities); ++ status = pcie_init_service_irqs(dev, irqs, capabilities); + if (status) { + capabilities &= PCIE_PORT_SERVICE_VC | PCIE_PORT_SERVICE_HP; + if (!capabilities) +@@ -401,7 +365,7 @@ int pcie_port_device_register(struct pci_dev *dev) + return 0; + + error_cleanup_irqs: +- cleanup_service_irqs(dev); ++ pci_free_irq_vectors(dev); + error_disable: + pci_disable_device(dev); + return status; +@@ -469,7 +433,7 @@ static int remove_iter(struct device *dev, void *data) + void pcie_port_device_remove(struct pci_dev *dev) + { + device_for_each_child(&dev->dev, NULL, remove_iter); +- cleanup_service_irqs(dev); ++ pci_free_irq_vectors(dev); + pci_disable_device(dev); + } + +@@ -499,7 +463,6 @@ static int pcie_port_probe_service(struct device *dev) + if (status) + return status; + +- dev_printk(KERN_DEBUG, dev, "service driver %s loaded\n", driver->name); + get_device(dev); + return 0; + } +@@ -524,8 +487,6 @@ static int pcie_port_remove_service(struct device *dev) + pciedev = to_pcie_device(dev); + driver = to_service_driver(dev->driver); + if (driver && driver->remove) { +- dev_printk(KERN_DEBUG, dev, "unloading service driver %s\n", +- driver->name); + driver->remove(pciedev); + put_device(dev); + } +diff --git a/include/linux/pci.h b/include/linux/pci.h +index 1b711796..6738d816 100644 +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -1823,6 +1823,7 @@ void pcibios_release_device(struct pci_dev *dev); + void pcibios_penalize_isa_irq(int irq, int active); + int pcibios_alloc_irq(struct pci_dev *dev); + void pcibios_free_irq(struct pci_dev *dev); ++int pcibios_check_service_irqs(struct pci_dev *dev, int *irqs, int mask); + + #ifdef CONFIG_HIBERNATE_CALLBACKS + extern struct dev_pm_ops pcibios_pm_ops; +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/703-phy-support-layerscape.patch b/target/linux/layerscape/patches-4.9/703-phy-support-layerscape.patch new file mode 100644 index 0000000000..0e8e3695f3 --- /dev/null +++ b/target/linux/layerscape/patches-4.9/703-phy-support-layerscape.patch @@ -0,0 +1,1776 @@ +From be07319b9897738a4ab1501880b7dd9be26eba66 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 11:54:28 +0800 +Subject: [PATCH] phy: support layerscape + +This is a integrated patch for layerscape mdio-phy support. + +Signed-off-by: Bogdan Purcareata +Signed-off-by: Zhang Ying-22455 +Signed-off-by: costi +Signed-off-by: Madalin Bucur +Signed-off-by: Shaohui Xie +Signed-off-by: Florian Fainelli +Signed-off-by: Yangbo Lu +--- + drivers/net/phy/Kconfig | 11 + + drivers/net/phy/Makefile | 2 + + drivers/net/phy/aquantia.c | 28 + + drivers/net/phy/cortina.c | 118 ++++ + drivers/net/phy/fsl_backplane.c | 1358 +++++++++++++++++++++++++++++++++++++++ + drivers/net/phy/phy.c | 23 +- + drivers/net/phy/phy_device.c | 6 +- + drivers/net/phy/swphy.c | 1 + + include/linux/phy.h | 4 + + 9 files changed, 1544 insertions(+), 7 deletions(-) + create mode 100644 drivers/net/phy/cortina.c + create mode 100644 drivers/net/phy/fsl_backplane.c + +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index 30a3a2f5..3521c1ac 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -89,6 +89,12 @@ config MDIO_BUS_MUX_MMIOREG + config MDIO_CAVIUM + tristate + ++config MDIO_FSL_BACKPLANE ++ tristate "Support for backplane on Freescale XFI interface" ++ depends on OF_MDIO ++ help ++ This module provides a driver for Freescale XFI's backplane. ++ + config MDIO_GPIO + tristate "GPIO lib-based bitbanged MDIO buses" + depends on MDIO_BITBANG && GPIOLIB +@@ -298,6 +304,11 @@ config CICADA_PHY + ---help--- + Currently supports the cis8204 + ++config CORTINA_PHY ++ tristate "Cortina EDC CDR 10G Ethernet PHY" ++ ---help--- ++ Currently supports the CS4340 phy. ++ + config DAVICOM_PHY + tristate "Davicom PHYs" + ---help--- +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index 93a68fcd..ef3ec265 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -30,6 +30,7 @@ obj-$(CONFIG_MDIO_BUS_MUX_BCM_IPROC) += mdio-mux-bcm-iproc.o + obj-$(CONFIG_MDIO_BUS_MUX_GPIO) += mdio-mux-gpio.o + obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o + obj-$(CONFIG_MDIO_CAVIUM) += mdio-cavium.o ++obj-$(CONFIG_MDIO_FSL_BACKPLANE) += fsl_backplane.o + obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o + obj-$(CONFIG_MDIO_HISI_FEMAC) += mdio-hisi-femac.o + obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o +@@ -48,6 +49,7 @@ obj-$(CONFIG_BCM_CYGNUS_PHY) += bcm-cygnus.o + obj-$(CONFIG_BCM_NET_PHYLIB) += bcm-phy-lib.o + obj-$(CONFIG_BROADCOM_PHY) += broadcom.o + obj-$(CONFIG_CICADA_PHY) += cicada.o ++obj-$(CONFIG_CORTINA_PHY) += cortina.o + obj-$(CONFIG_DAVICOM_PHY) += davicom.o + obj-$(CONFIG_DP83640_PHY) += dp83640.o + obj-$(CONFIG_DP83848_PHY) += dp83848.o +diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c +index 09b0b0aa..e8ae50e1 100644 +--- a/drivers/net/phy/aquantia.c ++++ b/drivers/net/phy/aquantia.c +@@ -21,6 +21,8 @@ + #define PHY_ID_AQ1202 0x03a1b445 + #define PHY_ID_AQ2104 0x03a1b460 + #define PHY_ID_AQR105 0x03a1b4a2 ++#define PHY_ID_AQR106 0x03a1b4d0 ++#define PHY_ID_AQR107 0x03a1b4e0 + #define PHY_ID_AQR405 0x03a1b4b0 + + #define PHY_AQUANTIA_FEATURES (SUPPORTED_10000baseT_Full | \ +@@ -153,6 +155,30 @@ static struct phy_driver aquantia_driver[] = { + .ack_interrupt = aquantia_ack_interrupt, + .read_status = aquantia_read_status, + }, ++{ ++ .phy_id = PHY_ID_AQR106, ++ .phy_id_mask = 0xfffffff0, ++ .name = "Aquantia AQR106", ++ .features = PHY_AQUANTIA_FEATURES, ++ .flags = PHY_HAS_INTERRUPT, ++ .aneg_done = aquantia_aneg_done, ++ .config_aneg = aquantia_config_aneg, ++ .config_intr = aquantia_config_intr, ++ .ack_interrupt = aquantia_ack_interrupt, ++ .read_status = aquantia_read_status, ++}, ++{ ++ .phy_id = PHY_ID_AQR107, ++ .phy_id_mask = 0xfffffff0, ++ .name = "Aquantia AQR107", ++ .features = PHY_AQUANTIA_FEATURES, ++ .flags = PHY_HAS_INTERRUPT, ++ .aneg_done = aquantia_aneg_done, ++ .config_aneg = aquantia_config_aneg, ++ .config_intr = aquantia_config_intr, ++ .ack_interrupt = aquantia_ack_interrupt, ++ .read_status = aquantia_read_status, ++}, + { + .phy_id = PHY_ID_AQR405, + .phy_id_mask = 0xfffffff0, +@@ -173,6 +199,8 @@ static struct mdio_device_id __maybe_unused aquantia_tbl[] = { + { PHY_ID_AQ1202, 0xfffffff0 }, + { PHY_ID_AQ2104, 0xfffffff0 }, + { PHY_ID_AQR105, 0xfffffff0 }, ++ { PHY_ID_AQR106, 0xfffffff0 }, ++ { PHY_ID_AQR107, 0xfffffff0 }, + { PHY_ID_AQR405, 0xfffffff0 }, + { } + }; +diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c +new file mode 100644 +index 00000000..72f4228a +--- /dev/null ++++ b/drivers/net/phy/cortina.c +@@ -0,0 +1,118 @@ ++/* ++ * Copyright 2017 NXP ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * CORTINA is a registered trademark of Cortina Systems, Inc. ++ * ++ */ ++#include ++#include ++ ++#define PHY_ID_CS4340 0x13e51002 ++ ++#define VILLA_GLOBAL_CHIP_ID_LSB 0x0 ++#define VILLA_GLOBAL_CHIP_ID_MSB 0x1 ++ ++#define VILLA_GLOBAL_GPIO_1_INTS 0x017 ++ ++static int cortina_read_reg(struct phy_device *phydev, u16 regnum) ++{ ++ return mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, ++ MII_ADDR_C45 | regnum); ++} ++ ++static int cortina_config_aneg(struct phy_device *phydev) ++{ ++ phydev->supported = SUPPORTED_10000baseT_Full; ++ phydev->advertising = SUPPORTED_10000baseT_Full; ++ ++ return 0; ++} ++ ++static int cortina_read_status(struct phy_device *phydev) ++{ ++ int gpio_int_status, ret = 0; ++ ++ gpio_int_status = cortina_read_reg(phydev, VILLA_GLOBAL_GPIO_1_INTS); ++ if (gpio_int_status < 0) { ++ ret = gpio_int_status; ++ goto err; ++ } ++ ++ if (gpio_int_status & 0x8) { ++ /* up when edc_convergedS set */ ++ phydev->speed = SPEED_10000; ++ phydev->duplex = DUPLEX_FULL; ++ phydev->link = 1; ++ } else { ++ phydev->link = 0; ++ } ++ ++err: ++ return ret; ++} ++ ++static int cortina_soft_reset(struct phy_device *phydev) ++{ ++ return 0; ++} ++ ++static int cortina_probe(struct phy_device *phydev) ++{ ++ u32 phy_id = 0; ++ int id_lsb = 0, id_msb = 0; ++ ++ /* Read device id from phy registers. */ ++ id_lsb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_LSB); ++ if (id_lsb < 0) ++ return -ENXIO; ++ ++ phy_id = id_lsb << 16; ++ ++ id_msb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_MSB); ++ if (id_msb < 0) ++ return -ENXIO; ++ ++ phy_id |= id_msb; ++ ++ /* Make sure the device tree binding matched the driver with the ++ * right device. ++ */ ++ if (phy_id != phydev->drv->phy_id) { ++ phydev_err(phydev, "Error matching phy with %s driver\n", ++ phydev->drv->name); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static struct phy_driver cortina_driver[] = { ++{ ++ .phy_id = PHY_ID_CS4340, ++ .phy_id_mask = 0xffffffff, ++ .name = "Cortina CS4340", ++ .config_aneg = cortina_config_aneg, ++ .read_status = cortina_read_status, ++ .soft_reset = cortina_soft_reset, ++ .probe = cortina_probe, ++}, ++}; ++ ++module_phy_driver(cortina_driver); ++ ++static struct mdio_device_id __maybe_unused cortina_tbl[] = { ++ { PHY_ID_CS4340, 0xffffffff}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(mdio, cortina_tbl); +diff --git a/drivers/net/phy/fsl_backplane.c b/drivers/net/phy/fsl_backplane.c +new file mode 100644 +index 00000000..76865261 +--- /dev/null ++++ b/drivers/net/phy/fsl_backplane.c +@@ -0,0 +1,1358 @@ ++/* Freescale backplane driver. ++ * Author: Shaohui Xie ++ * ++ * Copyright 2015 Freescale Semiconductor, Inc. ++ * ++ * Licensed under the GPL-2 or later. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* XFI PCS Device Identifier */ ++#define FSL_PCS_PHY_ID 0x0083e400 ++ ++/* Freescale KR PMD registers */ ++#define FSL_KR_PMD_CTRL 0x96 ++#define FSL_KR_PMD_STATUS 0x97 ++#define FSL_KR_LP_CU 0x98 ++#define FSL_KR_LP_STATUS 0x99 ++#define FSL_KR_LD_CU 0x9a ++#define FSL_KR_LD_STATUS 0x9b ++ ++/* Freescale KR PMD defines */ ++#define PMD_RESET 0x1 ++#define PMD_STATUS_SUP_STAT 0x4 ++#define PMD_STATUS_FRAME_LOCK 0x2 ++#define TRAIN_EN 0x3 ++#define TRAIN_DISABLE 0x1 ++#define RX_STAT 0x1 ++ ++#define FSL_KR_RX_LINK_STAT_MASK 0x1000 ++#define FSL_XFI_PCS_10GR_SR1 0x20 ++ ++/* Freescale KX PCS mode register */ ++#define FSL_PCS_IF_MODE 0x8014 ++ ++/* Freescale KX PCS mode register init value */ ++#define IF_MODE_INIT 0x8 ++ ++/* Freescale KX/KR AN registers */ ++#define FSL_AN_AD1 0x11 ++#define FSL_AN_BP_STAT 0x30 ++ ++/* Freescale KX/KR AN registers defines */ ++#define AN_CTRL_INIT 0x1200 ++#define KX_AN_AD1_INIT 0x25 ++#define KR_AN_AD1_INIT 0x85 ++#define AN_LNK_UP_MASK 0x4 ++#define KR_AN_MASK 0x8 ++#define TRAIN_FAIL 0x8 ++ ++/* C(-1) */ ++#define BIN_M1 0 ++/* C(1) */ ++#define BIN_LONG 1 ++#define BIN_M1_SEL 6 ++#define BIN_Long_SEL 7 ++#define CDR_SEL_MASK 0x00070000 ++#define BIN_SNAPSHOT_NUM 5 ++#define BIN_M1_THRESHOLD 3 ++#define BIN_LONG_THRESHOLD 2 ++ ++#define PRE_COE_SHIFT 22 ++#define POST_COE_SHIFT 16 ++#define ZERO_COE_SHIFT 8 ++ ++#define PRE_COE_MAX 0x0 ++#define PRE_COE_MIN 0x8 ++#define POST_COE_MAX 0x0 ++#define POST_COE_MIN 0x10 ++#define ZERO_COE_MAX 0x30 ++#define ZERO_COE_MIN 0x0 ++ ++#define TECR0_INIT 0x24200000 ++#define RATIO_PREQ 0x3 ++#define RATIO_PST1Q 0xd ++#define RATIO_EQ 0x20 ++ ++#define GCR0_RESET_MASK 0x600000 ++#define GCR1_SNP_START_MASK 0x00000040 ++#define GCR1_CTL_SNP_START_MASK 0x00002000 ++#define GCR1_REIDL_TH_MASK 0x00700000 ++#define GCR1_REIDL_EX_SEL_MASK 0x000c0000 ++#define GCR1_REIDL_ET_MAS_MASK 0x00004000 ++#define TECR0_AMP_RED_MASK 0x0000003f ++ ++#define RECR1_CTL_SNP_DONE_MASK 0x00000002 ++#define RECR1_SNP_DONE_MASK 0x00000004 ++#define TCSR1_SNP_DATA_MASK 0x0000ffc0 ++#define TCSR1_SNP_DATA_SHIFT 6 ++#define TCSR1_EQ_SNPBIN_SIGN_MASK 0x100 ++ ++#define RECR1_GAINK2_MASK 0x0f000000 ++#define RECR1_GAINK2_SHIFT 24 ++#define RECR1_GAINK3_MASK 0x000f0000 ++#define RECR1_GAINK3_SHIFT 16 ++#define RECR1_OFFSET_MASK 0x00003f80 ++#define RECR1_OFFSET_SHIFT 7 ++#define RECR1_BLW_MASK 0x00000f80 ++#define RECR1_BLW_SHIFT 7 ++#define EYE_CTRL_SHIFT 12 ++#define BASE_WAND_SHIFT 10 ++ ++#define XGKR_TIMEOUT 1050 ++ ++#define INCREMENT 1 ++#define DECREMENT 2 ++#define TIMEOUT_LONG 3 ++#define TIMEOUT_M1 3 ++ ++#define RX_READY_MASK 0x8000 ++#define PRESET_MASK 0x2000 ++#define INIT_MASK 0x1000 ++#define COP1_MASK 0x30 ++#define COP1_SHIFT 4 ++#define COZ_MASK 0xc ++#define COZ_SHIFT 2 ++#define COM1_MASK 0x3 ++#define COM1_SHIFT 0 ++#define REQUEST_MASK 0x3f ++#define LD_ALL_MASK (PRESET_MASK | INIT_MASK | \ ++ COP1_MASK | COZ_MASK | COM1_MASK) ++ ++#define NEW_ALGORITHM_TRAIN_TX ++#ifdef NEW_ALGORITHM_TRAIN_TX ++#define FORCE_INC_COP1_NUMBER 0 ++#define FORCE_INC_COM1_NUMBER 1 ++#endif ++ ++#define VAL_INVALID 0xff ++ ++static const u32 preq_table[] = {0x0, 0x1, 0x3, 0x5, ++ 0x7, 0x9, 0xb, 0xc, VAL_INVALID}; ++static const u32 pst1q_table[] = {0x0, 0x1, 0x3, 0x5, 0x7, ++ 0x9, 0xb, 0xd, 0xf, 0x10, VAL_INVALID}; ++ ++enum backplane_mode { ++ PHY_BACKPLANE_1000BASE_KX, ++ PHY_BACKPLANE_10GBASE_KR, ++ PHY_BACKPLANE_INVAL ++}; ++ ++enum coe_filed { ++ COE_COP1, ++ COE_COZ, ++ COE_COM ++}; ++ ++enum coe_update { ++ COE_NOTUPDATED, ++ COE_UPDATED, ++ COE_MIN, ++ COE_MAX, ++ COE_INV ++}; ++ ++enum train_state { ++ DETECTING_LP, ++ TRAINED, ++}; ++ ++struct per_lane_ctrl_status { ++ __be32 gcr0; /* 0x.000 - General Control Register 0 */ ++ __be32 gcr1; /* 0x.004 - General Control Register 1 */ ++ __be32 gcr2; /* 0x.008 - General Control Register 2 */ ++ __be32 resv1; /* 0x.00C - Reserved */ ++ __be32 recr0; /* 0x.010 - Receive Equalization Control Register 0 */ ++ __be32 recr1; /* 0x.014 - Receive Equalization Control Register 1 */ ++ __be32 tecr0; /* 0x.018 - Transmit Equalization Control Register 0 */ ++ __be32 resv2; /* 0x.01C - Reserved */ ++ __be32 tlcr0; /* 0x.020 - TTL Control Register 0 */ ++ __be32 tlcr1; /* 0x.024 - TTL Control Register 1 */ ++ __be32 tlcr2; /* 0x.028 - TTL Control Register 2 */ ++ __be32 tlcr3; /* 0x.02C - TTL Control Register 3 */ ++ __be32 tcsr0; /* 0x.030 - Test Control/Status Register 0 */ ++ __be32 tcsr1; /* 0x.034 - Test Control/Status Register 1 */ ++ __be32 tcsr2; /* 0x.038 - Test Control/Status Register 2 */ ++ __be32 tcsr3; /* 0x.03C - Test Control/Status Register 3 */ ++}; ++ ++struct tx_condition { ++ bool bin_m1_late_early; ++ bool bin_long_late_early; ++ bool bin_m1_stop; ++ bool bin_long_stop; ++ bool tx_complete; ++ bool sent_init; ++ int m1_min_max_cnt; ++ int long_min_max_cnt; ++#ifdef NEW_ALGORITHM_TRAIN_TX ++ int pre_inc; ++ int post_inc; ++#endif ++}; ++ ++struct fsl_xgkr_inst { ++ void *reg_base; ++ struct phy_device *phydev; ++ struct tx_condition tx_c; ++ struct delayed_work xgkr_wk; ++ enum train_state state; ++ u32 ld_update; ++ u32 ld_status; ++ u32 ratio_preq; ++ u32 ratio_pst1q; ++ u32 adpt_eq; ++}; ++ ++static void tx_condition_init(struct tx_condition *tx_c) ++{ ++ tx_c->bin_m1_late_early = true; ++ tx_c->bin_long_late_early = false; ++ tx_c->bin_m1_stop = false; ++ tx_c->bin_long_stop = false; ++ tx_c->tx_complete = false; ++ tx_c->sent_init = false; ++ tx_c->m1_min_max_cnt = 0; ++ tx_c->long_min_max_cnt = 0; ++#ifdef NEW_ALGORITHM_TRAIN_TX ++ tx_c->pre_inc = FORCE_INC_COM1_NUMBER; ++ tx_c->post_inc = FORCE_INC_COP1_NUMBER; ++#endif ++} ++ ++void tune_tecr0(struct fsl_xgkr_inst *inst) ++{ ++ struct per_lane_ctrl_status *reg_base = inst->reg_base; ++ u32 val; ++ ++ val = TECR0_INIT | ++ inst->adpt_eq << ZERO_COE_SHIFT | ++ inst->ratio_preq << PRE_COE_SHIFT | ++ inst->ratio_pst1q << POST_COE_SHIFT; ++ ++ /* reset the lane */ ++ iowrite32(ioread32(®_base->gcr0) & ~GCR0_RESET_MASK, ++ ®_base->gcr0); ++ udelay(1); ++ iowrite32(val, ®_base->tecr0); ++ udelay(1); ++ /* unreset the lane */ ++ iowrite32(ioread32(®_base->gcr0) | GCR0_RESET_MASK, ++ ®_base->gcr0); ++ udelay(1); ++} ++ ++static void start_lt(struct phy_device *phydev) ++{ ++ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, FSL_KR_PMD_CTRL, TRAIN_EN); ++} ++ ++static void stop_lt(struct phy_device *phydev) ++{ ++ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, FSL_KR_PMD_CTRL, TRAIN_DISABLE); ++} ++ ++static void reset_gcr0(struct fsl_xgkr_inst *inst) ++{ ++ struct per_lane_ctrl_status *reg_base = inst->reg_base; ++ ++ iowrite32(ioread32(®_base->gcr0) & ~GCR0_RESET_MASK, ++ ®_base->gcr0); ++ udelay(1); ++ iowrite32(ioread32(®_base->gcr0) | GCR0_RESET_MASK, ++ ®_base->gcr0); ++ udelay(1); ++} ++ ++void lane_set_1gkx(void *reg) ++{ ++ struct per_lane_ctrl_status *reg_base = reg; ++ u32 val; ++ ++ /* reset the lane */ ++ iowrite32(ioread32(®_base->gcr0) & ~GCR0_RESET_MASK, ++ ®_base->gcr0); ++ udelay(1); ++ ++ /* set gcr1 for 1GKX */ ++ val = ioread32(®_base->gcr1); ++ val &= ~(GCR1_REIDL_TH_MASK | GCR1_REIDL_EX_SEL_MASK | ++ GCR1_REIDL_ET_MAS_MASK); ++ iowrite32(val, ®_base->gcr1); ++ udelay(1); ++ ++ /* set tecr0 for 1GKX */ ++ val = ioread32(®_base->tecr0); ++ val &= ~TECR0_AMP_RED_MASK; ++ iowrite32(val, ®_base->tecr0); ++ udelay(1); ++ ++ /* unreset the lane */ ++ iowrite32(ioread32(®_base->gcr0) | GCR0_RESET_MASK, ++ ®_base->gcr0); ++ udelay(1); ++} ++ ++static void reset_lt(struct phy_device *phydev) ++{ ++ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, PMD_RESET); ++ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, FSL_KR_PMD_CTRL, TRAIN_DISABLE); ++ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, FSL_KR_LD_CU, 0); ++ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, FSL_KR_LD_STATUS, 0); ++ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, FSL_KR_PMD_STATUS, 0); ++ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, FSL_KR_LP_CU, 0); ++ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, FSL_KR_LP_STATUS, 0); ++} ++ ++static void start_xgkr_state_machine(struct delayed_work *work) ++{ ++ queue_delayed_work(system_power_efficient_wq, work, ++ msecs_to_jiffies(XGKR_TIMEOUT)); ++} ++ ++static void start_xgkr_an(struct phy_device *phydev) ++{ ++ struct fsl_xgkr_inst *inst; ++ ++ reset_lt(phydev); ++ phy_write_mmd(phydev, MDIO_MMD_AN, FSL_AN_AD1, KR_AN_AD1_INIT); ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, AN_CTRL_INIT); ++ ++ inst = phydev->priv; ++ ++ /* start state machine*/ ++ start_xgkr_state_machine(&inst->xgkr_wk); ++} ++ ++static void start_1gkx_an(struct phy_device *phydev) ++{ ++ phy_write_mmd(phydev, MDIO_MMD_PCS, FSL_PCS_IF_MODE, IF_MODE_INIT); ++ phy_write_mmd(phydev, MDIO_MMD_AN, FSL_AN_AD1, KX_AN_AD1_INIT); ++ phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); ++ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, AN_CTRL_INIT); ++} ++ ++static void ld_coe_status(struct fsl_xgkr_inst *inst) ++{ ++ phy_write_mmd(inst->phydev, MDIO_MMD_PMAPMD, ++ FSL_KR_LD_STATUS, inst->ld_status); ++} ++ ++static void ld_coe_update(struct fsl_xgkr_inst *inst) ++{ ++ dev_dbg(&inst->phydev->mdio.dev, "sending request: %x\n", inst->ld_update); ++ phy_write_mmd(inst->phydev, MDIO_MMD_PMAPMD, ++ FSL_KR_LD_CU, inst->ld_update); ++} ++ ++static void init_inst(struct fsl_xgkr_inst *inst, int reset) ++{ ++ if (reset) { ++ inst->ratio_preq = RATIO_PREQ; ++ inst->ratio_pst1q = RATIO_PST1Q; ++ inst->adpt_eq = RATIO_EQ; ++ tune_tecr0(inst); ++ } ++ ++ tx_condition_init(&inst->tx_c); ++ inst->state = DETECTING_LP; ++ inst->ld_status &= RX_READY_MASK; ++ ld_coe_status(inst); ++ inst->ld_update = 0; ++ inst->ld_status &= ~RX_READY_MASK; ++ ld_coe_status(inst); ++} ++ ++#ifdef NEW_ALGORITHM_TRAIN_TX ++static int get_median_gaink2(u32 *reg) ++{ ++ int gaink2_snap_shot[BIN_SNAPSHOT_NUM]; ++ u32 rx_eq_snp; ++ struct per_lane_ctrl_status *reg_base; ++ int timeout; ++ int i, j, tmp, pos; ++ ++ reg_base = (struct per_lane_ctrl_status *)reg; ++ ++ for (i = 0; i < BIN_SNAPSHOT_NUM; i++) { ++ /* wait RECR1_CTL_SNP_DONE_MASK has cleared */ ++ timeout = 100; ++ while (ioread32(®_base->recr1) & ++ RECR1_CTL_SNP_DONE_MASK) { ++ udelay(1); ++ timeout--; ++ if (timeout == 0) ++ break; ++ } ++ ++ /* start snap shot */ ++ iowrite32((ioread32(®_base->gcr1) | ++ GCR1_CTL_SNP_START_MASK), ++ ®_base->gcr1); ++ ++ /* wait for SNP done */ ++ timeout = 100; ++ while (!(ioread32(®_base->recr1) & ++ RECR1_CTL_SNP_DONE_MASK)) { ++ udelay(1); ++ timeout--; ++ if (timeout == 0) ++ break; ++ } ++ ++ /* read and save the snap shot */ ++ rx_eq_snp = ioread32(®_base->recr1); ++ gaink2_snap_shot[i] = (rx_eq_snp & RECR1_GAINK2_MASK) >> ++ RECR1_GAINK2_SHIFT; ++ ++ /* terminate the snap shot by setting GCR1[REQ_CTL_SNP] */ ++ iowrite32((ioread32(®_base->gcr1) & ++ ~GCR1_CTL_SNP_START_MASK), ++ ®_base->gcr1); ++ } ++ ++ /* get median of the 5 snap shot */ ++ for (i = 0; i < BIN_SNAPSHOT_NUM - 1; i++) { ++ tmp = gaink2_snap_shot[i]; ++ pos = i; ++ for (j = i + 1; j < BIN_SNAPSHOT_NUM; j++) { ++ if (gaink2_snap_shot[j] < tmp) { ++ tmp = gaink2_snap_shot[j]; ++ pos = j; ++ } ++ } ++ ++ gaink2_snap_shot[pos] = gaink2_snap_shot[i]; ++ gaink2_snap_shot[i] = tmp; ++ } ++ ++ return gaink2_snap_shot[2]; ++} ++#endif ++ ++static bool is_bin_early(int bin_sel, void *reg) ++{ ++ bool early = false; ++ int bin_snap_shot[BIN_SNAPSHOT_NUM]; ++ int i, negative_count = 0; ++ struct per_lane_ctrl_status *reg_base = reg; ++ int timeout; ++ ++ for (i = 0; i < BIN_SNAPSHOT_NUM; i++) { ++ /* wait RECR1_SNP_DONE_MASK has cleared */ ++ timeout = 100; ++ while ((ioread32(®_base->recr1) & RECR1_SNP_DONE_MASK)) { ++ udelay(1); ++ timeout--; ++ if (timeout == 0) ++ break; ++ } ++ ++ /* set TCSR1[CDR_SEL] to BinM1/BinLong */ ++ if (bin_sel == BIN_M1) { ++ iowrite32((ioread32(®_base->tcsr1) & ++ ~CDR_SEL_MASK) | BIN_M1_SEL, ++ ®_base->tcsr1); ++ } else { ++ iowrite32((ioread32(®_base->tcsr1) & ++ ~CDR_SEL_MASK) | BIN_Long_SEL, ++ ®_base->tcsr1); ++ } ++ ++ /* start snap shot */ ++ iowrite32(ioread32(®_base->gcr1) | GCR1_SNP_START_MASK, ++ ®_base->gcr1); ++ ++ /* wait for SNP done */ ++ timeout = 100; ++ while (!(ioread32(®_base->recr1) & RECR1_SNP_DONE_MASK)) { ++ udelay(1); ++ timeout--; ++ if (timeout == 0) ++ break; ++ } ++ ++ /* read and save the snap shot */ ++ bin_snap_shot[i] = (ioread32(®_base->tcsr1) & ++ TCSR1_SNP_DATA_MASK) >> TCSR1_SNP_DATA_SHIFT; ++ if (bin_snap_shot[i] & TCSR1_EQ_SNPBIN_SIGN_MASK) ++ negative_count++; ++ ++ /* terminate the snap shot by setting GCR1[REQ_CTL_SNP] */ ++ iowrite32(ioread32(®_base->gcr1) & ~GCR1_SNP_START_MASK, ++ ®_base->gcr1); ++ } ++ ++ if (((bin_sel == BIN_M1) && (negative_count > BIN_M1_THRESHOLD)) || ++ ((bin_sel == BIN_LONG && (negative_count > BIN_LONG_THRESHOLD)))) { ++ early = true; ++ } ++ ++ return early; ++} ++ ++static void train_tx(struct fsl_xgkr_inst *inst) ++{ ++ struct phy_device *phydev = inst->phydev; ++ struct tx_condition *tx_c = &inst->tx_c; ++ bool bin_m1_early, bin_long_early; ++ u32 lp_status, old_ld_update; ++ u32 status_cop1, status_coz, status_com1; ++ u32 req_cop1, req_coz, req_com1, req_preset, req_init; ++ u32 temp; ++#ifdef NEW_ALGORITHM_TRAIN_TX ++ u32 median_gaink2; ++#endif ++ ++recheck: ++ if (tx_c->bin_long_stop && tx_c->bin_m1_stop) { ++ tx_c->tx_complete = true; ++ inst->ld_status |= RX_READY_MASK; ++ ld_coe_status(inst); ++ /* tell LP we are ready */ ++ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, ++ FSL_KR_PMD_STATUS, RX_STAT); ++ return; ++ } ++ ++ /* We start by checking the current LP status. If we got any responses, ++ * we can clear up the appropriate update request so that the ++ * subsequent code may easily issue new update requests if needed. ++ */ ++ lp_status = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, FSL_KR_LP_STATUS) & ++ REQUEST_MASK; ++ status_cop1 = (lp_status & COP1_MASK) >> COP1_SHIFT; ++ status_coz = (lp_status & COZ_MASK) >> COZ_SHIFT; ++ status_com1 = (lp_status & COM1_MASK) >> COM1_SHIFT; ++ ++ old_ld_update = inst->ld_update; ++ req_cop1 = (old_ld_update & COP1_MASK) >> COP1_SHIFT; ++ req_coz = (old_ld_update & COZ_MASK) >> COZ_SHIFT; ++ req_com1 = (old_ld_update & COM1_MASK) >> COM1_SHIFT; ++ req_preset = old_ld_update & PRESET_MASK; ++ req_init = old_ld_update & INIT_MASK; ++ ++ /* IEEE802.3-2008, 72.6.10.2.3.1 ++ * We may clear PRESET when all coefficients show UPDATED or MAX. ++ */ ++ if (req_preset) { ++ if ((status_cop1 == COE_UPDATED || status_cop1 == COE_MAX) && ++ (status_coz == COE_UPDATED || status_coz == COE_MAX) && ++ (status_com1 == COE_UPDATED || status_com1 == COE_MAX)) { ++ inst->ld_update &= ~PRESET_MASK; ++ } ++ } ++ ++ /* IEEE802.3-2008, 72.6.10.2.3.2 ++ * We may clear INITIALIZE when no coefficients show NOT UPDATED. ++ */ ++ if (req_init) { ++ if (status_cop1 != COE_NOTUPDATED && ++ status_coz != COE_NOTUPDATED && ++ status_com1 != COE_NOTUPDATED) { ++ inst->ld_update &= ~INIT_MASK; ++ } ++ } ++ ++ /* IEEE802.3-2008, 72.6.10.2.3.2 ++ * we send initialize to the other side to ensure default settings ++ * for the LP. Naturally, we should do this only once. ++ */ ++ if (!tx_c->sent_init) { ++ if (!lp_status && !(old_ld_update & (LD_ALL_MASK))) { ++ inst->ld_update = INIT_MASK; ++ tx_c->sent_init = true; ++ } ++ } ++ ++ /* IEEE802.3-2008, 72.6.10.2.3.3 ++ * We set coefficient requests to HOLD when we get the information ++ * about any updates On clearing our prior response, we also update ++ * our internal status. ++ */ ++ if (status_cop1 != COE_NOTUPDATED) { ++ if (req_cop1) { ++ inst->ld_update &= ~COP1_MASK; ++#ifdef NEW_ALGORITHM_TRAIN_TX ++ if (tx_c->post_inc) { ++ if (req_cop1 == INCREMENT && ++ status_cop1 == COE_MAX) { ++ tx_c->post_inc = 0; ++ tx_c->bin_long_stop = true; ++ tx_c->bin_m1_stop = true; ++ } else { ++ tx_c->post_inc -= 1; ++ } ++ ++ ld_coe_update(inst); ++ goto recheck; ++ } ++#endif ++ if ((req_cop1 == DECREMENT && status_cop1 == COE_MIN) || ++ (req_cop1 == INCREMENT && status_cop1 == COE_MAX)) { ++ dev_dbg(&inst->phydev->mdio.dev, "COP1 hit limit %s", ++ (status_cop1 == COE_MIN) ? ++ "DEC MIN" : "INC MAX"); ++ tx_c->long_min_max_cnt++; ++ if (tx_c->long_min_max_cnt >= TIMEOUT_LONG) { ++ tx_c->bin_long_stop = true; ++ ld_coe_update(inst); ++ goto recheck; ++ } ++ } ++ } ++ } ++ ++ if (status_coz != COE_NOTUPDATED) { ++ if (req_coz) ++ inst->ld_update &= ~COZ_MASK; ++ } ++ ++ if (status_com1 != COE_NOTUPDATED) { ++ if (req_com1) { ++ inst->ld_update &= ~COM1_MASK; ++#ifdef NEW_ALGORITHM_TRAIN_TX ++ if (tx_c->pre_inc) { ++ if (req_com1 == INCREMENT && ++ status_com1 == COE_MAX) ++ tx_c->pre_inc = 0; ++ else ++ tx_c->pre_inc -= 1; ++ ++ ld_coe_update(inst); ++ goto recheck; ++ } ++#endif ++ /* Stop If we have reached the limit for a parameter. */ ++ if ((req_com1 == DECREMENT && status_com1 == COE_MIN) || ++ (req_com1 == INCREMENT && status_com1 == COE_MAX)) { ++ dev_dbg(&inst->phydev->mdio.dev, "COM1 hit limit %s", ++ (status_com1 == COE_MIN) ? ++ "DEC MIN" : "INC MAX"); ++ tx_c->m1_min_max_cnt++; ++ if (tx_c->m1_min_max_cnt >= TIMEOUT_M1) { ++ tx_c->bin_m1_stop = true; ++ ld_coe_update(inst); ++ goto recheck; ++ } ++ } ++ } ++ } ++ ++ if (old_ld_update != inst->ld_update) { ++ ld_coe_update(inst); ++ /* Redo these status checks and updates until we have no more ++ * changes, to speed up the overall process. ++ */ ++ goto recheck; ++ } ++ ++ /* Do nothing if we have pending request. */ ++ if ((req_coz || req_com1 || req_cop1)) ++ return; ++ else if (lp_status) ++ /* No pending request but LP status was not reverted to ++ * not updated. ++ */ ++ return; ++ ++#ifdef NEW_ALGORITHM_TRAIN_TX ++ if (!(inst->ld_update & (PRESET_MASK | INIT_MASK))) { ++ if (tx_c->pre_inc) { ++ inst->ld_update = INCREMENT << COM1_SHIFT; ++ ld_coe_update(inst); ++ return; ++ } ++ ++ if (status_cop1 != COE_MAX) { ++ median_gaink2 = get_median_gaink2(inst->reg_base); ++ if (median_gaink2 == 0xf) { ++ tx_c->post_inc = 1; ++ } else { ++ /* Gaink2 median lower than "F" */ ++ tx_c->bin_m1_stop = true; ++ tx_c->bin_long_stop = true; ++ goto recheck; ++ } ++ } else { ++ /* C1 MAX */ ++ tx_c->bin_m1_stop = true; ++ tx_c->bin_long_stop = true; ++ goto recheck; ++ } ++ ++ if (tx_c->post_inc) { ++ inst->ld_update = INCREMENT << COP1_SHIFT; ++ ld_coe_update(inst); ++ return; ++ } ++ } ++#endif ++ ++ /* snapshot and select bin */ ++ bin_m1_early = is_bin_early(BIN_M1, inst->reg_base); ++ bin_long_early = is_bin_early(BIN_LONG, inst->reg_base); ++ ++ if (!tx_c->bin_m1_stop && !tx_c->bin_m1_late_early && bin_m1_early) { ++ tx_c->bin_m1_stop = true; ++ goto recheck; ++ } ++ ++ if (!tx_c->bin_long_stop && ++ tx_c->bin_long_late_early && !bin_long_early) { ++ tx_c->bin_long_stop = true; ++ goto recheck; ++ } ++ ++ /* IEEE802.3-2008, 72.6.10.2.3.3 ++ * We only request coefficient updates when no PRESET/INITIALIZE is ++ * pending. We also only request coefficient updates when the ++ * corresponding status is NOT UPDATED and nothing is pending. ++ */ ++ if (!(inst->ld_update & (PRESET_MASK | INIT_MASK))) { ++ if (!tx_c->bin_long_stop) { ++ /* BinM1 correction means changing COM1 */ ++ if (!status_com1 && !(inst->ld_update & COM1_MASK)) { ++ /* Avoid BinM1Late by requesting an ++ * immediate decrement. ++ */ ++ if (!bin_m1_early) { ++ /* request decrement c(-1) */ ++ temp = DECREMENT << COM1_SHIFT; ++ inst->ld_update = temp; ++ ld_coe_update(inst); ++ tx_c->bin_m1_late_early = bin_m1_early; ++ return; ++ } ++ } ++ ++ /* BinLong correction means changing COP1 */ ++ if (!status_cop1 && !(inst->ld_update & COP1_MASK)) { ++ /* Locate BinLong transition point (if any) ++ * while avoiding BinM1Late. ++ */ ++ if (bin_long_early) { ++ /* request increment c(1) */ ++ temp = INCREMENT << COP1_SHIFT; ++ inst->ld_update = temp; ++ } else { ++ /* request decrement c(1) */ ++ temp = DECREMENT << COP1_SHIFT; ++ inst->ld_update = temp; ++ } ++ ++ ld_coe_update(inst); ++ tx_c->bin_long_late_early = bin_long_early; ++ } ++ /* We try to finish BinLong before we do BinM1 */ ++ return; ++ } ++ ++ if (!tx_c->bin_m1_stop) { ++ /* BinM1 correction means changing COM1 */ ++ if (!status_com1 && !(inst->ld_update & COM1_MASK)) { ++ /* Locate BinM1 transition point (if any) */ ++ if (bin_m1_early) { ++ /* request increment c(-1) */ ++ temp = INCREMENT << COM1_SHIFT; ++ inst->ld_update = temp; ++ } else { ++ /* request decrement c(-1) */ ++ temp = DECREMENT << COM1_SHIFT; ++ inst->ld_update = temp; ++ } ++ ++ ld_coe_update(inst); ++ tx_c->bin_m1_late_early = bin_m1_early; ++ } ++ } ++ } ++} ++ ++static int is_link_up(struct phy_device *phydev) ++{ ++ int val; ++ ++ phy_read_mmd(phydev, MDIO_MMD_PCS, FSL_XFI_PCS_10GR_SR1); ++ val = phy_read_mmd(phydev, MDIO_MMD_PCS, FSL_XFI_PCS_10GR_SR1); ++ ++ return (val & FSL_KR_RX_LINK_STAT_MASK) ? 1 : 0; ++} ++ ++static int is_link_training_fail(struct phy_device *phydev) ++{ ++ int val; ++ int timeout = 100; ++ ++ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, FSL_KR_PMD_STATUS); ++ if (!(val & TRAIN_FAIL) && (val & RX_STAT)) { ++ /* check LNK_STAT for sure */ ++ while (timeout--) { ++ if (is_link_up(phydev)) ++ return 0; ++ ++ usleep_range(100, 500); ++ } ++ } ++ ++ return 1; ++} ++ ++static int check_rx(struct phy_device *phydev) ++{ ++ return phy_read_mmd(phydev, MDIO_MMD_PMAPMD, FSL_KR_LP_STATUS) & ++ RX_READY_MASK; ++} ++ ++/* Coefficient values have hardware restrictions */ ++static int is_ld_valid(struct fsl_xgkr_inst *inst) ++{ ++ u32 ratio_pst1q = inst->ratio_pst1q; ++ u32 adpt_eq = inst->adpt_eq; ++ u32 ratio_preq = inst->ratio_preq; ++ ++ if ((ratio_pst1q + adpt_eq + ratio_preq) > 48) ++ return 0; ++ ++ if (((ratio_pst1q + adpt_eq + ratio_preq) * 4) >= ++ ((adpt_eq - ratio_pst1q - ratio_preq) * 17)) ++ return 0; ++ ++ if (ratio_preq > ratio_pst1q) ++ return 0; ++ ++ if (ratio_preq > 8) ++ return 0; ++ ++ if (adpt_eq < 26) ++ return 0; ++ ++ if (ratio_pst1q > 16) ++ return 0; ++ ++ return 1; ++} ++ ++static int is_value_allowed(const u32 *val_table, u32 val) ++{ ++ int i; ++ ++ for (i = 0;; i++) { ++ if (*(val_table + i) == VAL_INVALID) ++ return 0; ++ if (*(val_table + i) == val) ++ return 1; ++ } ++} ++ ++static int inc_dec(struct fsl_xgkr_inst *inst, int field, int request) ++{ ++ u32 ld_limit[3], ld_coe[3], step[3]; ++ ++ ld_coe[0] = inst->ratio_pst1q; ++ ld_coe[1] = inst->adpt_eq; ++ ld_coe[2] = inst->ratio_preq; ++ ++ /* Information specific to the Freescale SerDes for 10GBase-KR: ++ * Incrementing C(+1) means *decrementing* RATIO_PST1Q ++ * Incrementing C(0) means incrementing ADPT_EQ ++ * Incrementing C(-1) means *decrementing* RATIO_PREQ ++ */ ++ step[0] = -1; ++ step[1] = 1; ++ step[2] = -1; ++ ++ switch (request) { ++ case INCREMENT: ++ ld_limit[0] = POST_COE_MAX; ++ ld_limit[1] = ZERO_COE_MAX; ++ ld_limit[2] = PRE_COE_MAX; ++ if (ld_coe[field] != ld_limit[field]) ++ ld_coe[field] += step[field]; ++ else ++ /* MAX */ ++ return 2; ++ break; ++ case DECREMENT: ++ ld_limit[0] = POST_COE_MIN; ++ ld_limit[1] = ZERO_COE_MIN; ++ ld_limit[2] = PRE_COE_MIN; ++ if (ld_coe[field] != ld_limit[field]) ++ ld_coe[field] -= step[field]; ++ else ++ /* MIN */ ++ return 1; ++ break; ++ default: ++ break; ++ } ++ ++ if (is_ld_valid(inst)) { ++ /* accept new ld */ ++ inst->ratio_pst1q = ld_coe[0]; ++ inst->adpt_eq = ld_coe[1]; ++ inst->ratio_preq = ld_coe[2]; ++ /* only some values for preq and pst1q can be used. ++ * for preq: 0x0, 0x1, 0x3, 0x5, 0x7, 0x9, 0xb, 0xc. ++ * for pst1q: 0x0, 0x1, 0x3, 0x5, 0x7, 0x9, 0xb, 0xd, 0xf, 0x10. ++ */ ++ if (!is_value_allowed((const u32 *)&preq_table, ld_coe[2])) { ++ dev_dbg(&inst->phydev->mdio.dev, ++ "preq skipped value: %d\n", ld_coe[2]); ++ return 0; ++ } ++ ++ if (!is_value_allowed((const u32 *)&pst1q_table, ld_coe[0])) { ++ dev_dbg(&inst->phydev->mdio.dev, ++ "pst1q skipped value: %d\n", ld_coe[0]); ++ return 0; ++ } ++ ++ tune_tecr0(inst); ++ } else { ++ if (request == DECREMENT) ++ /* MIN */ ++ return 1; ++ if (request == INCREMENT) ++ /* MAX */ ++ return 2; ++ } ++ ++ return 0; ++} ++ ++static void min_max_updated(struct fsl_xgkr_inst *inst, int field, int new_ld) ++{ ++ u32 ld_coe[] = {COE_UPDATED, COE_MIN, COE_MAX}; ++ u32 mask, val; ++ ++ switch (field) { ++ case COE_COP1: ++ mask = COP1_MASK; ++ val = ld_coe[new_ld] << COP1_SHIFT; ++ break; ++ case COE_COZ: ++ mask = COZ_MASK; ++ val = ld_coe[new_ld] << COZ_SHIFT; ++ break; ++ case COE_COM: ++ mask = COM1_MASK; ++ val = ld_coe[new_ld] << COM1_SHIFT; ++ break; ++ default: ++ return; ++ } ++ ++ inst->ld_status &= ~mask; ++ inst->ld_status |= val; ++} ++ ++static void check_request(struct fsl_xgkr_inst *inst, int request) ++{ ++ int cop1_req, coz_req, com_req; ++ int old_status, new_ld_sta; ++ ++ cop1_req = (request & COP1_MASK) >> COP1_SHIFT; ++ coz_req = (request & COZ_MASK) >> COZ_SHIFT; ++ com_req = (request & COM1_MASK) >> COM1_SHIFT; ++ ++ /* IEEE802.3-2008, 72.6.10.2.5 ++ * Ensure we only act on INCREMENT/DECREMENT when we are in NOT UPDATED ++ */ ++ old_status = inst->ld_status; ++ ++ if (cop1_req && !(inst->ld_status & COP1_MASK)) { ++ new_ld_sta = inc_dec(inst, COE_COP1, cop1_req); ++ min_max_updated(inst, COE_COP1, new_ld_sta); ++ } ++ ++ if (coz_req && !(inst->ld_status & COZ_MASK)) { ++ new_ld_sta = inc_dec(inst, COE_COZ, coz_req); ++ min_max_updated(inst, COE_COZ, new_ld_sta); ++ } ++ ++ if (com_req && !(inst->ld_status & COM1_MASK)) { ++ new_ld_sta = inc_dec(inst, COE_COM, com_req); ++ min_max_updated(inst, COE_COM, new_ld_sta); ++ } ++ ++ if (old_status != inst->ld_status) ++ ld_coe_status(inst); ++} ++ ++static void preset(struct fsl_xgkr_inst *inst) ++{ ++ /* These are all MAX values from the IEEE802.3 perspective. */ ++ inst->ratio_pst1q = POST_COE_MAX; ++ inst->adpt_eq = ZERO_COE_MAX; ++ inst->ratio_preq = PRE_COE_MAX; ++ ++ tune_tecr0(inst); ++ inst->ld_status &= ~(COP1_MASK | COZ_MASK | COM1_MASK); ++ inst->ld_status |= COE_MAX << COP1_SHIFT | ++ COE_MAX << COZ_SHIFT | ++ COE_MAX << COM1_SHIFT; ++ ld_coe_status(inst); ++} ++ ++static void initialize(struct fsl_xgkr_inst *inst) ++{ ++ inst->ratio_preq = RATIO_PREQ; ++ inst->ratio_pst1q = RATIO_PST1Q; ++ inst->adpt_eq = RATIO_EQ; ++ ++ tune_tecr0(inst); ++ inst->ld_status &= ~(COP1_MASK | COZ_MASK | COM1_MASK); ++ inst->ld_status |= COE_UPDATED << COP1_SHIFT | ++ COE_UPDATED << COZ_SHIFT | ++ COE_UPDATED << COM1_SHIFT; ++ ld_coe_status(inst); ++} ++ ++static void train_rx(struct fsl_xgkr_inst *inst) ++{ ++ struct phy_device *phydev = inst->phydev; ++ int request, old_ld_status; ++ ++ /* get request from LP */ ++ request = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, FSL_KR_LP_CU) & ++ (LD_ALL_MASK); ++ old_ld_status = inst->ld_status; ++ ++ /* IEEE802.3-2008, 72.6.10.2.5 ++ * Ensure we always go to NOT UDPATED for status reporting in ++ * response to HOLD requests. ++ * IEEE802.3-2008, 72.6.10.2.3.1/2 ++ * ... but only if PRESET/INITIALIZE are not active to ensure ++ * we keep status until they are released. ++ */ ++ if (!(request & (PRESET_MASK | INIT_MASK))) { ++ if (!(request & COP1_MASK)) ++ inst->ld_status &= ~COP1_MASK; ++ ++ if (!(request & COZ_MASK)) ++ inst->ld_status &= ~COZ_MASK; ++ ++ if (!(request & COM1_MASK)) ++ inst->ld_status &= ~COM1_MASK; ++ ++ if (old_ld_status != inst->ld_status) ++ ld_coe_status(inst); ++ } ++ ++ /* As soon as the LP shows ready, no need to do any more updates. */ ++ if (check_rx(phydev)) { ++ /* LP receiver is ready */ ++ if (inst->ld_status & (COP1_MASK | COZ_MASK | COM1_MASK)) { ++ inst->ld_status &= ~(COP1_MASK | COZ_MASK | COM1_MASK); ++ ld_coe_status(inst); ++ } ++ } else { ++ /* IEEE802.3-2008, 72.6.10.2.3.1/2 ++ * only act on PRESET/INITIALIZE if all status is NOT UPDATED. ++ */ ++ if (request & (PRESET_MASK | INIT_MASK)) { ++ if (!(inst->ld_status & ++ (COP1_MASK | COZ_MASK | COM1_MASK))) { ++ if (request & PRESET_MASK) ++ preset(inst); ++ ++ if (request & INIT_MASK) ++ initialize(inst); ++ } ++ } ++ ++ /* LP Coefficient are not in HOLD */ ++ if (request & REQUEST_MASK) ++ check_request(inst, request & REQUEST_MASK); ++ } ++} ++ ++static void xgkr_start_train(struct phy_device *phydev) ++{ ++ struct fsl_xgkr_inst *inst = phydev->priv; ++ struct tx_condition *tx_c = &inst->tx_c; ++ int val = 0, i; ++ int lt_state; ++ unsigned long dead_line; ++ int rx_ok, tx_ok; ++ ++ init_inst(inst, 0); ++ start_lt(phydev); ++ ++ for (i = 0; i < 2;) { ++ dead_line = jiffies + msecs_to_jiffies(500); ++ while (time_before(jiffies, dead_line)) { ++ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, ++ FSL_KR_PMD_STATUS); ++ if (val & TRAIN_FAIL) { ++ /* LT failed already, reset lane to avoid ++ * it run into hanging, then start LT again. ++ */ ++ reset_gcr0(inst); ++ start_lt(phydev); ++ } else if ((val & PMD_STATUS_SUP_STAT) && ++ (val & PMD_STATUS_FRAME_LOCK)) ++ break; ++ usleep_range(100, 500); ++ } ++ ++ if (!((val & PMD_STATUS_FRAME_LOCK) && ++ (val & PMD_STATUS_SUP_STAT))) { ++ i++; ++ continue; ++ } ++ ++ /* init process */ ++ rx_ok = false; ++ tx_ok = false; ++ /* the LT should be finished in 500ms, failed or OK. */ ++ dead_line = jiffies + msecs_to_jiffies(500); ++ ++ while (time_before(jiffies, dead_line)) { ++ /* check if the LT is already failed */ ++ lt_state = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, ++ FSL_KR_PMD_STATUS); ++ if (lt_state & TRAIN_FAIL) { ++ reset_gcr0(inst); ++ break; ++ } ++ ++ rx_ok = check_rx(phydev); ++ tx_ok = tx_c->tx_complete; ++ ++ if (rx_ok && tx_ok) ++ break; ++ ++ if (!rx_ok) ++ train_rx(inst); ++ ++ if (!tx_ok) ++ train_tx(inst); ++ ++ usleep_range(100, 500); ++ } ++ ++ i++; ++ /* check LT result */ ++ if (is_link_training_fail(phydev)) { ++ init_inst(inst, 0); ++ continue; ++ } else { ++ stop_lt(phydev); ++ inst->state = TRAINED; ++ break; ++ } ++ } ++} ++ ++static void xgkr_state_machine(struct work_struct *work) ++{ ++ struct delayed_work *dwork = to_delayed_work(work); ++ struct fsl_xgkr_inst *inst = container_of(dwork, ++ struct fsl_xgkr_inst, ++ xgkr_wk); ++ struct phy_device *phydev = inst->phydev; ++ int an_state; ++ bool needs_train = false; ++ ++ mutex_lock(&phydev->lock); ++ ++ switch (inst->state) { ++ case DETECTING_LP: ++ phy_read_mmd(phydev, MDIO_MMD_AN, FSL_AN_BP_STAT); ++ an_state = phy_read_mmd(phydev, MDIO_MMD_AN, FSL_AN_BP_STAT); ++ if ((an_state & KR_AN_MASK)) ++ needs_train = true; ++ break; ++ case TRAINED: ++ if (!is_link_up(phydev)) { ++ dev_info(&phydev->mdio.dev, ++ "Detect hotplug, restart training\n"); ++ init_inst(inst, 1); ++ start_xgkr_an(phydev); ++ inst->state = DETECTING_LP; ++ } ++ break; ++ } ++ ++ if (needs_train) ++ xgkr_start_train(phydev); ++ ++ mutex_unlock(&phydev->lock); ++ queue_delayed_work(system_power_efficient_wq, &inst->xgkr_wk, ++ msecs_to_jiffies(XGKR_TIMEOUT)); ++} ++ ++static int fsl_backplane_probe(struct phy_device *phydev) ++{ ++ struct fsl_xgkr_inst *xgkr_inst; ++ struct device_node *phy_node, *lane_node; ++ struct resource res_lane; ++ const char *bm; ++ int ret; ++ int bp_mode; ++ u32 lane[2]; ++ ++ phy_node = phydev->mdio.dev.of_node; ++ bp_mode = of_property_read_string(phy_node, "backplane-mode", &bm); ++ if (bp_mode < 0) ++ return 0; ++ ++ if (!strcasecmp(bm, "1000base-kx")) { ++ bp_mode = PHY_BACKPLANE_1000BASE_KX; ++ } else if (!strcasecmp(bm, "10gbase-kr")) { ++ bp_mode = PHY_BACKPLANE_10GBASE_KR; ++ } else { ++ dev_err(&phydev->mdio.dev, "Unknown backplane-mode\n"); ++ return -EINVAL; ++ } ++ ++ lane_node = of_parse_phandle(phy_node, "fsl,lane-handle", 0); ++ if (!lane_node) { ++ dev_err(&phydev->mdio.dev, "parse fsl,lane-handle failed\n"); ++ return -EINVAL; ++ } ++ ++ ret = of_address_to_resource(lane_node, 0, &res_lane); ++ if (ret) { ++ dev_err(&phydev->mdio.dev, "could not obtain memory map\n"); ++ return ret; ++ } ++ ++ of_node_put(lane_node); ++ ret = of_property_read_u32_array(phy_node, "fsl,lane-reg", ++ (u32 *)&lane, 2); ++ if (ret) { ++ dev_err(&phydev->mdio.dev, "could not get fsl,lane-reg\n"); ++ return -EINVAL; ++ } ++ ++ phydev->priv = devm_ioremap_nocache(&phydev->mdio.dev, ++ res_lane.start + lane[0], ++ lane[1]); ++ if (!phydev->priv) { ++ dev_err(&phydev->mdio.dev, "ioremap_nocache failed\n"); ++ return -ENOMEM; ++ } ++ ++ if (bp_mode == PHY_BACKPLANE_1000BASE_KX) { ++ phydev->speed = SPEED_1000; ++ /* configure the lane for 1000BASE-KX */ ++ lane_set_1gkx(phydev->priv); ++ return 0; ++ } ++ ++ xgkr_inst = devm_kzalloc(&phydev->mdio.dev, ++ sizeof(*xgkr_inst), GFP_KERNEL); ++ if (!xgkr_inst) ++ return -ENOMEM; ++ ++ xgkr_inst->reg_base = phydev->priv; ++ xgkr_inst->phydev = phydev; ++ phydev->priv = xgkr_inst; ++ ++ if (bp_mode == PHY_BACKPLANE_10GBASE_KR) { ++ phydev->speed = SPEED_10000; ++ INIT_DELAYED_WORK(&xgkr_inst->xgkr_wk, xgkr_state_machine); ++ } ++ ++ return 0; ++} ++ ++static int fsl_backplane_aneg_done(struct phy_device *phydev) ++{ ++ return 1; ++} ++ ++static int fsl_backplane_config_aneg(struct phy_device *phydev) ++{ ++ if (phydev->speed == SPEED_10000) { ++ phydev->supported |= SUPPORTED_10000baseKR_Full; ++ start_xgkr_an(phydev); ++ } else if (phydev->speed == SPEED_1000) { ++ phydev->supported |= SUPPORTED_1000baseKX_Full; ++ start_1gkx_an(phydev); ++ } ++ ++ phydev->advertising = phydev->supported; ++ phydev->duplex = 1; ++ ++ return 0; ++} ++ ++static int fsl_backplane_suspend(struct phy_device *phydev) ++{ ++ if (phydev->speed == SPEED_10000) { ++ struct fsl_xgkr_inst *xgkr_inst = phydev->priv; ++ ++ cancel_delayed_work_sync(&xgkr_inst->xgkr_wk); ++ } ++ return 0; ++} ++ ++static int fsl_backplane_resume(struct phy_device *phydev) ++{ ++ if (phydev->speed == SPEED_10000) { ++ struct fsl_xgkr_inst *xgkr_inst = phydev->priv; ++ ++ init_inst(xgkr_inst, 1); ++ queue_delayed_work(system_power_efficient_wq, ++ &xgkr_inst->xgkr_wk, ++ msecs_to_jiffies(XGKR_TIMEOUT)); ++ } ++ return 0; ++} ++ ++static int fsl_backplane_read_status(struct phy_device *phydev) ++{ ++ if (is_link_up(phydev)) ++ phydev->link = 1; ++ else ++ phydev->link = 0; ++ ++ return 0; ++} ++ ++static struct phy_driver fsl_backplane_driver[] = { ++ { ++ .phy_id = FSL_PCS_PHY_ID, ++ .name = "Freescale Backplane", ++ .phy_id_mask = 0xffffffff, ++ .features = SUPPORTED_Backplane | SUPPORTED_Autoneg | ++ SUPPORTED_MII, ++ .probe = fsl_backplane_probe, ++ .aneg_done = fsl_backplane_aneg_done, ++ .config_aneg = fsl_backplane_config_aneg, ++ .read_status = fsl_backplane_read_status, ++ .suspend = fsl_backplane_suspend, ++ .resume = fsl_backplane_resume, ++ }, ++}; ++ ++module_phy_driver(fsl_backplane_driver); ++ ++static struct mdio_device_id __maybe_unused freescale_tbl[] = { ++ { FSL_PCS_PHY_ID, 0xffffffff }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(mdio, freescale_tbl); ++ ++MODULE_DESCRIPTION("Freescale Backplane driver"); ++MODULE_AUTHOR("Shaohui Xie "); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c +index f3e64a89..42cdd5b7 100644 +--- a/drivers/net/phy/phy.c ++++ b/drivers/net/phy/phy.c +@@ -585,7 +585,7 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd) + return 0; + + case SIOCSHWTSTAMP: +- if (phydev->drv->hwtstamp) ++ if (phydev->drv && phydev->drv->hwtstamp) + return phydev->drv->hwtstamp(phydev, ifr); + /* fall through */ + +@@ -610,6 +610,9 @@ static int phy_start_aneg_priv(struct phy_device *phydev, bool sync) + bool trigger = 0; + int err; + ++ if (!phydev->drv) ++ return -EIO; ++ + mutex_lock(&phydev->lock); + + if (AUTONEG_DISABLE == phydev->autoneg) +@@ -1009,7 +1012,7 @@ void phy_state_machine(struct work_struct *work) + + old_state = phydev->state; + +- if (phydev->drv->link_change_notify) ++ if (phydev->drv && phydev->drv->link_change_notify) + phydev->drv->link_change_notify(phydev); + + switch (phydev->state) { +@@ -1311,6 +1314,9 @@ EXPORT_SYMBOL(phy_write_mmd_indirect); + */ + int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) + { ++ if (!phydev->drv) ++ return -EIO; ++ + /* According to 802.3az,the EEE is supported only in full duplex-mode. + * Also EEE feature is active when core is operating with MII, GMII + * or RGMII (all kinds). Internal PHYs are also allowed to proceed and +@@ -1388,6 +1394,9 @@ EXPORT_SYMBOL(phy_init_eee); + */ + int phy_get_eee_err(struct phy_device *phydev) + { ++ if (!phydev->drv) ++ return -EIO; ++ + return phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_WK_ERR, MDIO_MMD_PCS); + } + EXPORT_SYMBOL(phy_get_eee_err); +@@ -1404,6 +1413,9 @@ int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_eee *data) + { + int val; + ++ if (!phydev->drv) ++ return -EIO; ++ + /* Get Supported EEE */ + val = phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_ABLE, MDIO_MMD_PCS); + if (val < 0) +@@ -1437,6 +1449,9 @@ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data) + { + int val = ethtool_adv_to_mmd_eee_adv_t(data->advertised); + ++ if (!phydev->drv) ++ return -EIO; ++ + /* Mask prohibited EEE modes */ + val &= ~phydev->eee_broken_modes; + +@@ -1448,7 +1463,7 @@ EXPORT_SYMBOL(phy_ethtool_set_eee); + + int phy_ethtool_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) + { +- if (phydev->drv->set_wol) ++ if (phydev->drv && phydev->drv->set_wol) + return phydev->drv->set_wol(phydev, wol); + + return -EOPNOTSUPP; +@@ -1457,7 +1472,7 @@ EXPORT_SYMBOL(phy_ethtool_set_wol); + + void phy_ethtool_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) + { +- if (phydev->drv->get_wol) ++ if (phydev->drv && phydev->drv->get_wol) + phydev->drv->get_wol(phydev, wol); + } + EXPORT_SYMBOL(phy_ethtool_get_wol); +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 5fdc491e..039f9664 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -1046,7 +1046,7 @@ int phy_suspend(struct phy_device *phydev) + if (wol.wolopts) + return -EBUSY; + +- if (phydrv->suspend) ++ if (phydev->drv && phydrv->suspend) + ret = phydrv->suspend(phydev); + + if (ret) +@@ -1063,7 +1063,7 @@ int phy_resume(struct phy_device *phydev) + struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver); + int ret = 0; + +- if (phydrv->resume) ++ if (phydev->drv && phydrv->resume) + ret = phydrv->resume(phydev); + + if (ret) +@@ -1726,7 +1726,7 @@ static int phy_remove(struct device *dev) + phydev->state = PHY_DOWN; + mutex_unlock(&phydev->lock); + +- if (phydev->drv->remove) ++ if (phydev->drv && phydev->drv->remove) + phydev->drv->remove(phydev); + phydev->drv = NULL; + +diff --git a/drivers/net/phy/swphy.c b/drivers/net/phy/swphy.c +index 34f58f23..52ddddbe 100644 +--- a/drivers/net/phy/swphy.c ++++ b/drivers/net/phy/swphy.c +@@ -77,6 +77,7 @@ static const struct swmii_regs duplex[] = { + static int swphy_decode_speed(int speed) + { + switch (speed) { ++ case 10000: + case 1000: + return SWMII_SPEED_1000; + case 100: +diff --git a/include/linux/phy.h b/include/linux/phy.h +index 850c8b51..5f253f1a 100644 +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -81,6 +81,7 @@ typedef enum { + PHY_INTERFACE_MODE_MOCA, + PHY_INTERFACE_MODE_QSGMII, + PHY_INTERFACE_MODE_TRGMII, ++ PHY_INTERFACE_MODE_SGMII_2500, + PHY_INTERFACE_MODE_MAX, + } phy_interface_t; + +@@ -784,6 +785,9 @@ int phy_stop_interrupts(struct phy_device *phydev); + + static inline int phy_read_status(struct phy_device *phydev) + { ++ if (!phydev->drv) ++ return -EIO; ++ + return phydev->drv->read_status(phydev); + } + +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/704-fsl-mc-layerscape-support.patch b/target/linux/layerscape/patches-4.9/704-fsl-mc-layerscape-support.patch new file mode 100644 index 0000000000..eab1e656d2 --- /dev/null +++ b/target/linux/layerscape/patches-4.9/704-fsl-mc-layerscape-support.patch @@ -0,0 +1,11518 @@ +From 464b4d9b8282e0f1e5040e4914505f91ce4d3750 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 12:06:25 +0800 +Subject: [PATCH] fsl-mc: layerscape support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is a integrated patch for layerscape mc-bus support. + +Signed-off-by: Stuart Yoder +Signed-off-by: Bharat Bhushan +Signed-off-by: Arnd Bergmann +Signed-off-by: Laurentiu Tudor +Signed-off-by: Roy Pledge +Signed-off-by: Shiva Kerdel +Signed-off-by: Nipun Gupta +Signed-off-by: Ioana Ciornei +Signed-off-by: Horia Geantă +Signed-off-by: Yangbo Lu +--- + drivers/staging/fsl-mc/bus/Kconfig | 41 +- + drivers/staging/fsl-mc/bus/Makefile | 10 +- + drivers/staging/fsl-mc/bus/dpbp-cmd.h | 80 ++ + drivers/staging/fsl-mc/bus/dpbp.c | 450 +-------- + drivers/staging/fsl-mc/bus/dpcon-cmd.h | 85 ++ + drivers/staging/fsl-mc/bus/dpcon.c | 317 ++++++ + drivers/staging/fsl-mc/bus/dpio/Makefile | 11 + + .../{include/dpcon-cmd.h => bus/dpio/dpio-cmd.h} | 73 +- + drivers/staging/fsl-mc/bus/dpio/dpio-driver.c | 296 ++++++ + drivers/staging/fsl-mc/bus/dpio/dpio-driver.txt | 135 +++ + drivers/staging/fsl-mc/bus/dpio/dpio-service.c | 689 +++++++++++++ + drivers/staging/fsl-mc/bus/dpio/dpio.c | 224 +++++ + drivers/staging/fsl-mc/bus/dpio/dpio.h | 109 ++ + drivers/staging/fsl-mc/bus/dpio/qbman-portal.c | 1049 ++++++++++++++++++++ + drivers/staging/fsl-mc/bus/dpio/qbman-portal.h | 662 ++++++++++++ + drivers/staging/fsl-mc/bus/dpio/qbman_debug.c | 853 ++++++++++++++++ + drivers/staging/fsl-mc/bus/dpio/qbman_debug.h | 136 +++ + drivers/staging/fsl-mc/bus/dpio/qbman_private.h | 171 ++++ + drivers/staging/fsl-mc/bus/dpmcp-cmd.h | 112 +-- + drivers/staging/fsl-mc/bus/dpmcp.c | 374 +------ + drivers/staging/fsl-mc/bus/dpmcp.h | 127 +-- + drivers/staging/fsl-mc/bus/dpmng-cmd.h | 14 +- + drivers/staging/fsl-mc/bus/dpmng.c | 37 +- + drivers/staging/fsl-mc/bus/dprc-cmd.h | 82 +- + drivers/staging/fsl-mc/bus/dprc-driver.c | 38 +- + drivers/staging/fsl-mc/bus/dprc.c | 629 +----------- + drivers/staging/fsl-mc/bus/fsl-mc-allocator.c | 78 +- + drivers/staging/fsl-mc/bus/fsl-mc-bus.c | 318 +++--- + drivers/staging/fsl-mc/bus/fsl-mc-iommu.c | 104 ++ + drivers/staging/fsl-mc/bus/fsl-mc-msi.c | 3 +- + drivers/staging/fsl-mc/bus/fsl-mc-private.h | 6 +- + .../staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c | 11 +- + drivers/staging/fsl-mc/bus/mc-io.c | 4 +- + drivers/staging/fsl-mc/bus/mc-ioctl.h | 22 + + drivers/staging/fsl-mc/bus/mc-restool.c | 405 ++++++++ + drivers/staging/fsl-mc/bus/mc-sys.c | 14 +- + drivers/staging/fsl-mc/include/dpaa2-fd.h | 706 +++++++++++++ + drivers/staging/fsl-mc/include/dpaa2-global.h | 202 ++++ + drivers/staging/fsl-mc/include/dpaa2-io.h | 190 ++++ + drivers/staging/fsl-mc/include/dpbp-cmd.h | 185 ---- + drivers/staging/fsl-mc/include/dpbp.h | 158 +-- + drivers/staging/fsl-mc/include/dpcon.h | 115 +++ + drivers/staging/fsl-mc/include/dpmng.h | 16 +- + drivers/staging/fsl-mc/include/dpopr.h | 110 ++ + drivers/staging/fsl-mc/include/dprc.h | 470 +++------ + drivers/staging/fsl-mc/include/mc-bus.h | 7 +- + drivers/staging/fsl-mc/include/mc-cmd.h | 44 +- + drivers/staging/fsl-mc/include/mc-sys.h | 3 +- + drivers/staging/fsl-mc/include/mc.h | 17 +- + 49 files changed, 7380 insertions(+), 2612 deletions(-) + create mode 100644 drivers/staging/fsl-mc/bus/dpbp-cmd.h + create mode 100644 drivers/staging/fsl-mc/bus/dpcon-cmd.h + create mode 100644 drivers/staging/fsl-mc/bus/dpcon.c + create mode 100644 drivers/staging/fsl-mc/bus/dpio/Makefile + rename drivers/staging/fsl-mc/{include/dpcon-cmd.h => bus/dpio/dpio-cmd.h} (64%) + create mode 100644 drivers/staging/fsl-mc/bus/dpio/dpio-driver.c + create mode 100644 drivers/staging/fsl-mc/bus/dpio/dpio-driver.txt + create mode 100644 drivers/staging/fsl-mc/bus/dpio/dpio-service.c + create mode 100644 drivers/staging/fsl-mc/bus/dpio/dpio.c + create mode 100644 drivers/staging/fsl-mc/bus/dpio/dpio.h + create mode 100644 drivers/staging/fsl-mc/bus/dpio/qbman-portal.c + create mode 100644 drivers/staging/fsl-mc/bus/dpio/qbman-portal.h + create mode 100644 drivers/staging/fsl-mc/bus/dpio/qbman_debug.c + create mode 100644 drivers/staging/fsl-mc/bus/dpio/qbman_debug.h + create mode 100644 drivers/staging/fsl-mc/bus/dpio/qbman_private.h + create mode 100644 drivers/staging/fsl-mc/bus/fsl-mc-iommu.c + create mode 100644 drivers/staging/fsl-mc/bus/mc-ioctl.h + create mode 100644 drivers/staging/fsl-mc/bus/mc-restool.c + create mode 100644 drivers/staging/fsl-mc/include/dpaa2-fd.h + create mode 100644 drivers/staging/fsl-mc/include/dpaa2-global.h + create mode 100644 drivers/staging/fsl-mc/include/dpaa2-io.h + delete mode 100644 drivers/staging/fsl-mc/include/dpbp-cmd.h + create mode 100644 drivers/staging/fsl-mc/include/dpcon.h + create mode 100644 drivers/staging/fsl-mc/include/dpopr.h + +diff --git a/drivers/staging/fsl-mc/bus/Kconfig b/drivers/staging/fsl-mc/bus/Kconfig +index 1f959339..67847c0e 100644 +--- a/drivers/staging/fsl-mc/bus/Kconfig ++++ b/drivers/staging/fsl-mc/bus/Kconfig +@@ -1,25 +1,40 @@ + # +-# Freescale Management Complex (MC) bus drivers ++# DPAA2 fsl-mc bus + # +-# Copyright (C) 2014 Freescale Semiconductor, Inc. ++# Copyright (C) 2014-2016 Freescale Semiconductor, Inc. + # + # This file is released under the GPLv2 + # + + config FSL_MC_BUS +- bool "Freescale Management Complex (MC) bus driver" +- depends on OF && ARM64 ++ bool "QorIQ DPAA2 fsl-mc bus driver" ++ depends on OF && ARCH_LAYERSCAPE + select GENERIC_MSI_IRQ_DOMAIN + help +- Driver to enable the bus infrastructure for the Freescale +- QorIQ Management Complex (fsl-mc). The fsl-mc is a hardware +- module of the QorIQ LS2 SoCs, that does resource management +- for hardware building-blocks in the SoC that can be used +- to dynamically create networking hardware objects such as +- network interfaces (NICs), crypto accelerator instances, +- or L2 switches. ++ Driver to enable the bus infrastructure for the QorIQ DPAA2 ++ architecture. The fsl-mc bus driver handles discovery of ++ DPAA2 objects (which are represented as Linux devices) and ++ binding objects to drivers. + +- Only enable this option when building the kernel for +- Freescale QorQIQ LS2xxxx SoCs. ++config FSL_MC_DPIO ++ tristate "QorIQ DPAA2 DPIO driver" ++ depends on FSL_MC_BUS ++ help ++ Driver for the DPAA2 DPIO object. A DPIO provides queue and ++ buffer management facilities for software to interact with ++ other DPAA2 objects. This driver does not expose the DPIO ++ objects individually, but groups them under a service layer ++ API. + ++config FSL_QBMAN_DEBUG ++ tristate "Freescale QBMAN Debug APIs" ++ depends on FSL_MC_DPIO ++ help ++ QBMan debug assistant APIs. + ++config FSL_MC_RESTOOL ++ tristate "Freescale Management Complex (MC) restool driver" ++ depends on FSL_MC_BUS ++ help ++ Driver that provides kernel support for the Freescale Management ++ Complex resource manager user-space tool. +diff --git a/drivers/staging/fsl-mc/bus/Makefile b/drivers/staging/fsl-mc/bus/Makefile +index 38716fd5..e7e2239c 100644 +--- a/drivers/staging/fsl-mc/bus/Makefile ++++ b/drivers/staging/fsl-mc/bus/Makefile +@@ -17,4 +17,12 @@ mc-bus-driver-objs := fsl-mc-bus.o \ + fsl-mc-msi.o \ + irq-gic-v3-its-fsl-mc-msi.o \ + dpmcp.o \ +- dpbp.o ++ dpbp.o \ ++ dpcon.o \ ++ fsl-mc-iommu.o ++ ++# MC DPIO driver ++obj-$(CONFIG_FSL_MC_DPIO) += dpio/ ++ ++# MC restool kernel support ++obj-$(CONFIG_FSL_MC_RESTOOL) += mc-restool.o +diff --git a/drivers/staging/fsl-mc/bus/dpbp-cmd.h b/drivers/staging/fsl-mc/bus/dpbp-cmd.h +new file mode 100644 +index 00000000..8aa65452 +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/dpbp-cmd.h +@@ -0,0 +1,80 @@ ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef _FSL_DPBP_CMD_H ++#define _FSL_DPBP_CMD_H ++ ++/* DPBP Version */ ++#define DPBP_VER_MAJOR 3 ++#define DPBP_VER_MINOR 2 ++ ++/* Command versioning */ ++#define DPBP_CMD_BASE_VERSION 1 ++#define DPBP_CMD_ID_OFFSET 4 ++ ++#define DPBP_CMD(id) ((id << DPBP_CMD_ID_OFFSET) | DPBP_CMD_BASE_VERSION) ++ ++/* Command IDs */ ++#define DPBP_CMDID_CLOSE DPBP_CMD(0x800) ++#define DPBP_CMDID_OPEN DPBP_CMD(0x804) ++#define DPBP_CMDID_GET_API_VERSION DPBP_CMD(0xa04) ++ ++#define DPBP_CMDID_ENABLE DPBP_CMD(0x002) ++#define DPBP_CMDID_DISABLE DPBP_CMD(0x003) ++#define DPBP_CMDID_GET_ATTR DPBP_CMD(0x004) ++#define DPBP_CMDID_RESET DPBP_CMD(0x005) ++#define DPBP_CMDID_IS_ENABLED DPBP_CMD(0x006) ++ ++struct dpbp_cmd_open { ++ __le32 dpbp_id; ++}; ++ ++struct dpbp_cmd_destroy { ++ __le32 object_id; ++}; ++ ++#define DPBP_ENABLE 0x1 ++ ++struct dpbp_rsp_is_enabled { ++ u8 enabled; ++}; ++ ++struct dpbp_rsp_get_attributes { ++ /* response word 0 */ ++ __le16 pad; ++ __le16 bpid; ++ __le32 id; ++ /* response word 1 */ ++ __le16 version_major; ++ __le16 version_minor; ++}; ++ ++#endif /* _FSL_DPBP_CMD_H */ +diff --git a/drivers/staging/fsl-mc/bus/dpbp.c b/drivers/staging/fsl-mc/bus/dpbp.c +index 5d4cd812..d9e450a6 100644 +--- a/drivers/staging/fsl-mc/bus/dpbp.c ++++ b/drivers/staging/fsl-mc/bus/dpbp.c +@@ -1,4 +1,5 @@ +-/* Copyright 2013-2016 Freescale Semiconductor Inc. ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -11,7 +12,6 @@ + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * +- * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any +@@ -32,7 +32,8 @@ + #include "../include/mc-sys.h" + #include "../include/mc-cmd.h" + #include "../include/dpbp.h" +-#include "../include/dpbp-cmd.h" ++ ++#include "dpbp-cmd.h" + + /** + * dpbp_open() - Open a control session for the specified object. +@@ -104,74 +105,6 @@ int dpbp_close(struct fsl_mc_io *mc_io, + } + EXPORT_SYMBOL(dpbp_close); + +-/** +- * dpbp_create() - Create the DPBP object. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @cfg: Configuration structure +- * @token: Returned token; use in subsequent API calls +- * +- * Create the DPBP object, allocate required resources and +- * perform required initialization. +- * +- * The object can be created either by declaring it in the +- * DPL file, or by calling this function. +- * This function returns a unique authentication token, +- * associated with the specific object ID and the specific MC +- * portal; this token must be used in all subsequent calls to +- * this specific object. For objects that are created using the +- * DPL file, call dpbp_open function to get an authentication +- * token first. +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpbp_create(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- const struct dpbp_cfg *cfg, +- u16 *token) +-{ +- struct mc_command cmd = { 0 }; +- int err; +- +- (void)(cfg); /* unused */ +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_CREATE, +- cmd_flags, 0); +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- *token = mc_cmd_hdr_read_token(&cmd); +- +- return 0; +-} +- +-/** +- * dpbp_destroy() - Destroy the DPBP object and release all its resources. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPBP object +- * +- * Return: '0' on Success; error code otherwise. +- */ +-int dpbp_destroy(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token) +-{ +- struct mc_command cmd = { 0 }; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_DESTROY, +- cmd_flags, token); +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- + /** + * dpbp_enable() - Enable the DPBP. + * @mc_io: Pointer to MC portal's I/O object +@@ -250,6 +183,7 @@ int dpbp_is_enabled(struct fsl_mc_io *mc_io, + + return 0; + } ++EXPORT_SYMBOL(dpbp_is_enabled); + + /** + * dpbp_reset() - Reset the DPBP, returns the object to initial state. +@@ -272,310 +206,7 @@ int dpbp_reset(struct fsl_mc_io *mc_io, + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); + } +- +-/** +- * dpbp_set_irq() - Set IRQ information for the DPBP to trigger an interrupt. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPBP object +- * @irq_index: Identifies the interrupt index to configure +- * @irq_cfg: IRQ configuration +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpbp_set_irq(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- struct dpbp_irq_cfg *irq_cfg) +-{ +- struct mc_command cmd = { 0 }; +- struct dpbp_cmd_set_irq *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_SET_IRQ, +- cmd_flags, token); +- cmd_params = (struct dpbp_cmd_set_irq *)cmd.params; +- cmd_params->irq_index = irq_index; +- cmd_params->irq_val = cpu_to_le32(irq_cfg->val); +- cmd_params->irq_addr = cpu_to_le64(irq_cfg->addr); +- cmd_params->irq_num = cpu_to_le32(irq_cfg->irq_num); +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** +- * dpbp_get_irq() - Get IRQ information from the DPBP. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPBP object +- * @irq_index: The interrupt index to configure +- * @type: Interrupt type: 0 represents message interrupt +- * type (both irq_addr and irq_val are valid) +- * @irq_cfg: IRQ attributes +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpbp_get_irq(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- int *type, +- struct dpbp_irq_cfg *irq_cfg) +-{ +- struct mc_command cmd = { 0 }; +- struct dpbp_cmd_get_irq *cmd_params; +- struct dpbp_rsp_get_irq *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_IRQ, +- cmd_flags, token); +- cmd_params = (struct dpbp_cmd_get_irq *)cmd.params; +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dpbp_rsp_get_irq *)cmd.params; +- irq_cfg->val = le32_to_cpu(rsp_params->irq_val); +- irq_cfg->addr = le64_to_cpu(rsp_params->irq_addr); +- irq_cfg->irq_num = le32_to_cpu(rsp_params->irq_num); +- *type = le32_to_cpu(rsp_params->type); +- +- return 0; +-} +- +-/** +- * dpbp_set_irq_enable() - Set overall interrupt state. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPBP object +- * @irq_index: The interrupt index to configure +- * @en: Interrupt state - enable = 1, disable = 0 +- * +- * Allows GPP software to control when interrupts are generated. +- * Each interrupt can have up to 32 causes. The enable/disable control's the +- * overall interrupt state. if the interrupt is disabled no causes will cause +- * an interrupt. +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpbp_set_irq_enable(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u8 en) +-{ +- struct mc_command cmd = { 0 }; +- struct dpbp_cmd_set_irq_enable *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_SET_IRQ_ENABLE, +- cmd_flags, token); +- cmd_params = (struct dpbp_cmd_set_irq_enable *)cmd.params; +- cmd_params->enable = en & DPBP_ENABLE; +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** +- * dpbp_get_irq_enable() - Get overall interrupt state +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPBP object +- * @irq_index: The interrupt index to configure +- * @en: Returned interrupt state - enable = 1, disable = 0 +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpbp_get_irq_enable(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u8 *en) +-{ +- struct mc_command cmd = { 0 }; +- struct dpbp_cmd_get_irq_enable *cmd_params; +- struct dpbp_rsp_get_irq_enable *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_IRQ_ENABLE, +- cmd_flags, token); +- cmd_params = (struct dpbp_cmd_get_irq_enable *)cmd.params; +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dpbp_rsp_get_irq_enable *)cmd.params; +- *en = rsp_params->enabled & DPBP_ENABLE; +- return 0; +-} +- +-/** +- * dpbp_set_irq_mask() - Set interrupt mask. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPBP object +- * @irq_index: The interrupt index to configure +- * @mask: Event mask to trigger interrupt; +- * each bit: +- * 0 = ignore event +- * 1 = consider event for asserting IRQ +- * +- * Every interrupt can have up to 32 causes and the interrupt model supports +- * masking/unmasking each cause independently +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpbp_set_irq_mask(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 mask) +-{ +- struct mc_command cmd = { 0 }; +- struct dpbp_cmd_set_irq_mask *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_SET_IRQ_MASK, +- cmd_flags, token); +- cmd_params = (struct dpbp_cmd_set_irq_mask *)cmd.params; +- cmd_params->mask = cpu_to_le32(mask); +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** +- * dpbp_get_irq_mask() - Get interrupt mask. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPBP object +- * @irq_index: The interrupt index to configure +- * @mask: Returned event mask to trigger interrupt +- * +- * Every interrupt can have up to 32 causes and the interrupt model supports +- * masking/unmasking each cause independently +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpbp_get_irq_mask(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 *mask) +-{ +- struct mc_command cmd = { 0 }; +- struct dpbp_cmd_get_irq_mask *cmd_params; +- struct dpbp_rsp_get_irq_mask *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_IRQ_MASK, +- cmd_flags, token); +- cmd_params = (struct dpbp_cmd_get_irq_mask *)cmd.params; +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dpbp_rsp_get_irq_mask *)cmd.params; +- *mask = le32_to_cpu(rsp_params->mask); +- +- return 0; +-} +- +-/** +- * dpbp_get_irq_status() - Get the current status of any pending interrupts. +- * +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPBP object +- * @irq_index: The interrupt index to configure +- * @status: Returned interrupts status - one bit per cause: +- * 0 = no interrupt pending +- * 1 = interrupt pending +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpbp_get_irq_status(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 *status) +-{ +- struct mc_command cmd = { 0 }; +- struct dpbp_cmd_get_irq_status *cmd_params; +- struct dpbp_rsp_get_irq_status *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_IRQ_STATUS, +- cmd_flags, token); +- cmd_params = (struct dpbp_cmd_get_irq_status *)cmd.params; +- cmd_params->status = cpu_to_le32(*status); +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dpbp_rsp_get_irq_status *)cmd.params; +- *status = le32_to_cpu(rsp_params->status); +- +- return 0; +-} +- +-/** +- * dpbp_clear_irq_status() - Clear a pending interrupt's status +- * +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPBP object +- * @irq_index: The interrupt index to configure +- * @status: Bits to clear (W1C) - one bit per cause: +- * 0 = don't change +- * 1 = clear status bit +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpbp_clear_irq_status(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 status) +-{ +- struct mc_command cmd = { 0 }; +- struct dpbp_cmd_clear_irq_status *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_CLEAR_IRQ_STATUS, +- cmd_flags, token); +- cmd_params = (struct dpbp_cmd_clear_irq_status *)cmd.params; +- cmd_params->status = cpu_to_le32(status); +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} ++EXPORT_SYMBOL(dpbp_reset); + + /** + * dpbp_get_attributes - Retrieve DPBP attributes. +@@ -609,83 +240,40 @@ int dpbp_get_attributes(struct fsl_mc_io *mc_io, + rsp_params = (struct dpbp_rsp_get_attributes *)cmd.params; + attr->bpid = le16_to_cpu(rsp_params->bpid); + attr->id = le32_to_cpu(rsp_params->id); +- attr->version.major = le16_to_cpu(rsp_params->version_major); +- attr->version.minor = le16_to_cpu(rsp_params->version_minor); + + return 0; + } + EXPORT_SYMBOL(dpbp_get_attributes); + + /** +- * dpbp_set_notifications() - Set notifications towards software +- * @mc_io: Pointer to MC portal's I/O object ++ * dpbp_get_api_version - Get Data Path Buffer Pool API version ++ * @mc_io: Pointer to Mc portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPBP object +- * @cfg: notifications configuration ++ * @major_ver: Major version of Buffer Pool API ++ * @minor_ver: Minor version of Buffer Pool API + * + * Return: '0' on Success; Error code otherwise. + */ +-int dpbp_set_notifications(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- struct dpbp_notification_cfg *cfg) ++int dpbp_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver) + { + struct mc_command cmd = { 0 }; +- struct dpbp_cmd_set_notifications *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_SET_NOTIFICATIONS, +- cmd_flags, token); +- cmd_params = (struct dpbp_cmd_set_notifications *)cmd.params; +- cmd_params->depletion_entry = cpu_to_le32(cfg->depletion_entry); +- cmd_params->depletion_exit = cpu_to_le32(cfg->depletion_exit); +- cmd_params->surplus_entry = cpu_to_le32(cfg->surplus_entry); +- cmd_params->surplus_exit = cpu_to_le32(cfg->surplus_exit); +- cmd_params->options = cpu_to_le16(cfg->options); +- cmd_params->message_ctx = cpu_to_le64(cfg->message_ctx); +- cmd_params->message_iova = cpu_to_le64(cfg->message_iova); +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** +- * dpbp_get_notifications() - Get the notifications configuration +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPBP object +- * @cfg: notifications configuration +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpbp_get_notifications(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- struct dpbp_notification_cfg *cfg) +-{ +- struct mc_command cmd = { 0 }; +- struct dpbp_rsp_get_notifications *rsp_params; + int err; + + /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_NOTIFICATIONS, +- cmd_flags, +- token); ++ cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_API_VERSION, ++ cmd_flags, 0); + +- /* send command to mc*/ ++ /* send command to mc */ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ +- rsp_params = (struct dpbp_rsp_get_notifications *)cmd.params; +- cfg->depletion_entry = le32_to_cpu(rsp_params->depletion_entry); +- cfg->depletion_exit = le32_to_cpu(rsp_params->depletion_exit); +- cfg->surplus_entry = le32_to_cpu(rsp_params->surplus_entry); +- cfg->surplus_exit = le32_to_cpu(rsp_params->surplus_exit); +- cfg->options = le16_to_cpu(rsp_params->options); +- cfg->message_ctx = le64_to_cpu(rsp_params->message_ctx); +- cfg->message_iova = le64_to_cpu(rsp_params->message_iova); ++ mc_cmd_read_api_version(&cmd, major_ver, minor_ver); + + return 0; + } ++EXPORT_SYMBOL(dpbp_get_api_version); +diff --git a/drivers/staging/fsl-mc/bus/dpcon-cmd.h b/drivers/staging/fsl-mc/bus/dpcon-cmd.h +new file mode 100644 +index 00000000..2bb66988 +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/dpcon-cmd.h +@@ -0,0 +1,85 @@ ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef _FSL_DPCON_CMD_H ++#define _FSL_DPCON_CMD_H ++ ++/* DPCON Version */ ++#define DPCON_VER_MAJOR 3 ++#define DPCON_VER_MINOR 2 ++ ++/* Command versioning */ ++#define DPCON_CMD_BASE_VERSION 1 ++#define DPCON_CMD_ID_OFFSET 4 ++ ++#define DPCON_CMD(id) (((id) << DPCON_CMD_ID_OFFSET) | DPCON_CMD_BASE_VERSION) ++ ++/* Command IDs */ ++#define DPCON_CMDID_CLOSE DPCON_CMD(0x800) ++#define DPCON_CMDID_OPEN DPCON_CMD(0x808) ++#define DPCON_CMDID_GET_API_VERSION DPCON_CMD(0xa08) ++ ++#define DPCON_CMDID_ENABLE DPCON_CMD(0x002) ++#define DPCON_CMDID_DISABLE DPCON_CMD(0x003) ++#define DPCON_CMDID_GET_ATTR DPCON_CMD(0x004) ++#define DPCON_CMDID_RESET DPCON_CMD(0x005) ++#define DPCON_CMDID_IS_ENABLED DPCON_CMD(0x006) ++ ++#define DPCON_CMDID_SET_NOTIFICATION DPCON_CMD(0x100) ++ ++struct dpcon_cmd_open { ++ __le32 dpcon_id; ++}; ++ ++#define DPCON_ENABLE 1 ++ ++struct dpcon_rsp_is_enabled { ++ u8 enabled; ++}; ++ ++struct dpcon_rsp_get_attr { ++ /* response word 0 */ ++ __le32 id; ++ __le16 qbman_ch_id; ++ u8 num_priorities; ++ u8 pad; ++}; ++ ++struct dpcon_cmd_set_notification { ++ /* cmd word 0 */ ++ __le32 dpio_id; ++ u8 priority; ++ u8 pad[3]; ++ /* cmd word 1 */ ++ __le64 user_ctx; ++}; ++ ++#endif /* _FSL_DPCON_CMD_H */ +diff --git a/drivers/staging/fsl-mc/bus/dpcon.c b/drivers/staging/fsl-mc/bus/dpcon.c +new file mode 100644 +index 00000000..eb713578 +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/dpcon.c +@@ -0,0 +1,317 @@ ++/* Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#include "../include/mc-sys.h" ++#include "../include/mc-cmd.h" ++#include "../include/dpcon.h" ++ ++#include "dpcon-cmd.h" ++ ++/** ++ * dpcon_open() - Open a control session for the specified object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @dpcon_id: DPCON unique ID ++ * @token: Returned token; use in subsequent API calls ++ * ++ * This function can be used to open a control session for an ++ * already created object; an object may have been declared in ++ * the DPL or by calling the dpcon_create() function. ++ * This function returns a unique authentication token, ++ * associated with the specific object ID and the specific MC ++ * portal; this token must be used in all subsequent commands for ++ * this specific object. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpcon_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpcon_id, ++ u16 *token) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpcon_cmd_open *dpcon_cmd; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPCON_CMDID_OPEN, ++ cmd_flags, ++ 0); ++ dpcon_cmd = (struct dpcon_cmd_open *)cmd.params; ++ dpcon_cmd->dpcon_id = cpu_to_le32(dpcon_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *token = mc_cmd_hdr_read_token(&cmd); ++ ++ return 0; ++} ++EXPORT_SYMBOL(dpcon_open); ++ ++/** ++ * dpcon_close() - Close the control session of the object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPCON object ++ * ++ * After this function is called, no further operations are ++ * allowed on the object without opening a new control session. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpcon_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPCON_CMDID_CLOSE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++EXPORT_SYMBOL(dpcon_close); ++ ++/** ++ * dpcon_enable() - Enable the DPCON ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPCON object ++ * ++ * Return: '0' on Success; Error code otherwise ++ */ ++int dpcon_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPCON_CMDID_ENABLE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++EXPORT_SYMBOL(dpcon_enable); ++ ++/** ++ * dpcon_disable() - Disable the DPCON ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPCON object ++ * ++ * Return: '0' on Success; Error code otherwise ++ */ ++int dpcon_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPCON_CMDID_DISABLE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++EXPORT_SYMBOL(dpcon_disable); ++ ++/** ++ * dpcon_is_enabled() - Check if the DPCON is enabled. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPCON object ++ * @en: Returns '1' if object is enabled; '0' otherwise ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpcon_is_enabled(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int *en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpcon_rsp_is_enabled *dpcon_rsp; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPCON_CMDID_IS_ENABLED, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ dpcon_rsp = (struct dpcon_rsp_is_enabled *)cmd.params; ++ *en = dpcon_rsp->enabled & DPCON_ENABLE; ++ ++ return 0; ++} ++EXPORT_SYMBOL(dpcon_is_enabled); ++ ++/** ++ * dpcon_reset() - Reset the DPCON, returns the object to initial state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPCON object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpcon_reset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPCON_CMDID_RESET, ++ cmd_flags, token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++EXPORT_SYMBOL(dpcon_reset); ++ ++/** ++ * dpcon_get_attributes() - Retrieve DPCON attributes. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPCON object ++ * @attr: Object's attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpcon_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpcon_attr *attr) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpcon_rsp_get_attr *dpcon_rsp; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPCON_CMDID_GET_ATTR, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ dpcon_rsp = (struct dpcon_rsp_get_attr *)cmd.params; ++ attr->id = le32_to_cpu(dpcon_rsp->id); ++ attr->qbman_ch_id = le16_to_cpu(dpcon_rsp->qbman_ch_id); ++ attr->num_priorities = dpcon_rsp->num_priorities; ++ ++ return 0; ++} ++EXPORT_SYMBOL(dpcon_get_attributes); ++ ++/** ++ * dpcon_set_notification() - Set DPCON notification destination ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPCON object ++ * @cfg: Notification parameters ++ * ++ * Return: '0' on Success; Error code otherwise ++ */ ++int dpcon_set_notification(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpcon_notification_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpcon_cmd_set_notification *dpcon_cmd; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPCON_CMDID_SET_NOTIFICATION, ++ cmd_flags, ++ token); ++ dpcon_cmd = (struct dpcon_cmd_set_notification *)cmd.params; ++ dpcon_cmd->dpio_id = cpu_to_le32(cfg->dpio_id); ++ dpcon_cmd->priority = cfg->priority; ++ dpcon_cmd->user_ctx = cpu_to_le64(cfg->user_ctx); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++EXPORT_SYMBOL(dpcon_set_notification); ++ ++/** ++ * dpcon_get_api_version - Get Data Path Concentrator API version ++ * @mc_io: Pointer to MC portal's DPCON object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @major_ver: Major version of DPCON API ++ * @minor_ver: Minor version of DPCON API ++ * ++ * Return: '0' on Success; Error code otherwise ++ */ ++int dpcon_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver) ++{ ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPCON_CMDID_GET_API_VERSION, ++ cmd_flags, 0); ++ ++ /* send command to mc */ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ mc_cmd_read_api_version(&cmd, major_ver, minor_ver); ++ ++ return 0; ++} ++EXPORT_SYMBOL(dpcon_get_api_version); +diff --git a/drivers/staging/fsl-mc/bus/dpio/Makefile b/drivers/staging/fsl-mc/bus/dpio/Makefile +new file mode 100644 +index 00000000..1c28794e +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/dpio/Makefile +@@ -0,0 +1,11 @@ ++# ++# QorIQ DPAA2 DPIO driver ++# ++ ++subdir-ccflags-y := -Werror ++ ++obj-$(CONFIG_FSL_MC_DPIO) += fsl-mc-dpio.o ++ ++fsl-mc-dpio-objs := dpio.o qbman-portal.o dpio-service.o dpio-driver.o ++ ++obj-$(CONFIG_FSL_QBMAN_DEBUG) += qbman_debug.o +diff --git a/drivers/staging/fsl-mc/include/dpcon-cmd.h b/drivers/staging/fsl-mc/bus/dpio/dpio-cmd.h +similarity index 64% +rename from drivers/staging/fsl-mc/include/dpcon-cmd.h +rename to drivers/staging/fsl-mc/bus/dpio/dpio-cmd.h +index 536b2ef1..b2dc6e76 100644 +--- a/drivers/staging/fsl-mc/include/dpcon-cmd.h ++++ b/drivers/staging/fsl-mc/bus/dpio/dpio-cmd.h +@@ -1,4 +1,6 @@ +-/* Copyright 2013-2015 Freescale Semiconductor Inc. ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. ++ * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -11,7 +13,6 @@ + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * +- * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any +@@ -29,34 +30,46 @@ + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +-#ifndef _FSL_DPCON_CMD_H +-#define _FSL_DPCON_CMD_H ++#ifndef _FSL_DPIO_CMD_H ++#define _FSL_DPIO_CMD_H ++ ++/* DPIO Version */ ++#define DPIO_VER_MAJOR 4 ++#define DPIO_VER_MINOR 2 ++ ++/* Command Versioning */ ++ ++#define DPIO_CMD_ID_OFFSET 4 ++#define DPIO_CMD_BASE_VERSION 1 + +-/* DPCON Version */ +-#define DPCON_VER_MAJOR 2 +-#define DPCON_VER_MINOR 1 ++#define DPIO_CMD(id) (((id) << DPIO_CMD_ID_OFFSET) | DPIO_CMD_BASE_VERSION) + + /* Command IDs */ +-#define DPCON_CMDID_CLOSE 0x800 +-#define DPCON_CMDID_OPEN 0x808 +-#define DPCON_CMDID_CREATE 0x908 +-#define DPCON_CMDID_DESTROY 0x900 +- +-#define DPCON_CMDID_ENABLE 0x002 +-#define DPCON_CMDID_DISABLE 0x003 +-#define DPCON_CMDID_GET_ATTR 0x004 +-#define DPCON_CMDID_RESET 0x005 +-#define DPCON_CMDID_IS_ENABLED 0x006 +- +-#define DPCON_CMDID_SET_IRQ 0x010 +-#define DPCON_CMDID_GET_IRQ 0x011 +-#define DPCON_CMDID_SET_IRQ_ENABLE 0x012 +-#define DPCON_CMDID_GET_IRQ_ENABLE 0x013 +-#define DPCON_CMDID_SET_IRQ_MASK 0x014 +-#define DPCON_CMDID_GET_IRQ_MASK 0x015 +-#define DPCON_CMDID_GET_IRQ_STATUS 0x016 +-#define DPCON_CMDID_CLEAR_IRQ_STATUS 0x017 +- +-#define DPCON_CMDID_SET_NOTIFICATION 0x100 +- +-#endif /* _FSL_DPCON_CMD_H */ ++#define DPIO_CMDID_CLOSE DPIO_CMD(0x800) ++#define DPIO_CMDID_OPEN DPIO_CMD(0x803) ++#define DPIO_CMDID_GET_API_VERSION DPIO_CMD(0xa03) ++#define DPIO_CMDID_ENABLE DPIO_CMD(0x002) ++#define DPIO_CMDID_DISABLE DPIO_CMD(0x003) ++#define DPIO_CMDID_GET_ATTR DPIO_CMD(0x004) ++ ++struct dpio_cmd_open { ++ __le32 dpio_id; ++}; ++ ++#define DPIO_CHANNEL_MODE_MASK 0x3 ++ ++struct dpio_rsp_get_attr { ++ /* cmd word 0 */ ++ __le32 id; ++ __le16 qbman_portal_id; ++ u8 num_priorities; ++ u8 channel_mode; ++ /* cmd word 1 */ ++ __le64 qbman_portal_ce_addr; ++ /* cmd word 2 */ ++ __le64 qbman_portal_ci_addr; ++ /* cmd word 3 */ ++ __le32 qbman_version; ++}; ++ ++#endif /* _FSL_DPIO_CMD_H */ +diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio-driver.c b/drivers/staging/fsl-mc/bus/dpio/dpio-driver.c +new file mode 100644 +index 00000000..8c8244a1 +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/dpio/dpio-driver.c +@@ -0,0 +1,296 @@ ++/* ++ * Copyright 2014-2016 Freescale Semiconductor Inc. ++ * Copyright 2016 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../../include/mc.h" ++#include "../../include/dpaa2-io.h" ++ ++#include "qbman-portal.h" ++#include "dpio.h" ++#include "dpio-cmd.h" ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("Freescale Semiconductor, Inc"); ++MODULE_DESCRIPTION("DPIO Driver"); ++ ++struct dpio_priv { ++ struct dpaa2_io *io; ++}; ++ ++static irqreturn_t dpio_irq_handler(int irq_num, void *arg) ++{ ++ struct device *dev = (struct device *)arg; ++ struct dpio_priv *priv = dev_get_drvdata(dev); ++ ++ return dpaa2_io_irq(priv->io); ++} ++ ++static void unregister_dpio_irq_handlers(struct fsl_mc_device *dpio_dev) ++{ ++ struct fsl_mc_device_irq *irq; ++ ++ irq = dpio_dev->irqs[0]; ++ ++ /* clear the affinity hint */ ++ irq_set_affinity_hint(irq->msi_desc->irq, NULL); ++} ++ ++static int register_dpio_irq_handlers(struct fsl_mc_device *dpio_dev, int cpu) ++{ ++ struct dpio_priv *priv; ++ int error; ++ struct fsl_mc_device_irq *irq; ++ cpumask_t mask; ++ ++ priv = dev_get_drvdata(&dpio_dev->dev); ++ ++ irq = dpio_dev->irqs[0]; ++ error = devm_request_irq(&dpio_dev->dev, ++ irq->msi_desc->irq, ++ dpio_irq_handler, ++ 0, ++ dev_name(&dpio_dev->dev), ++ &dpio_dev->dev); ++ if (error < 0) { ++ dev_err(&dpio_dev->dev, ++ "devm_request_irq() failed: %d\n", ++ error); ++ return error; ++ } ++ ++ /* set the affinity hint */ ++ cpumask_clear(&mask); ++ cpumask_set_cpu(cpu, &mask); ++ if (irq_set_affinity_hint(irq->msi_desc->irq, &mask)) ++ dev_err(&dpio_dev->dev, ++ "irq_set_affinity failed irq %d cpu %d\n", ++ irq->msi_desc->irq, cpu); ++ ++ return 0; ++} ++ ++static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev) ++{ ++ struct dpio_attr dpio_attrs; ++ struct dpaa2_io_desc desc; ++ struct dpio_priv *priv; ++ int err = -ENOMEM; ++ struct device *dev = &dpio_dev->dev; ++ static int next_cpu = -1; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ goto err_priv_alloc; ++ ++ dev_set_drvdata(dev, priv); ++ ++ err = fsl_mc_portal_allocate(dpio_dev, 0, &dpio_dev->mc_io); ++ if (err) { ++ dev_dbg(dev, "MC portal allocation failed\n"); ++ err = -EPROBE_DEFER; ++ goto err_mcportal; ++ } ++ ++ err = dpio_open(dpio_dev->mc_io, 0, dpio_dev->obj_desc.id, ++ &dpio_dev->mc_handle); ++ if (err) { ++ dev_err(dev, "dpio_open() failed\n"); ++ goto err_open; ++ } ++ ++ err = dpio_get_attributes(dpio_dev->mc_io, 0, dpio_dev->mc_handle, ++ &dpio_attrs); ++ if (err) { ++ dev_err(dev, "dpio_get_attributes() failed %d\n", err); ++ goto err_get_attr; ++ } ++ desc.qman_version = dpio_attrs.qbman_version; ++ ++ err = dpio_enable(dpio_dev->mc_io, 0, dpio_dev->mc_handle); ++ if (err) { ++ dev_err(dev, "dpio_enable() failed %d\n", err); ++ goto err_get_attr; ++ } ++ ++ /* initialize DPIO descriptor */ ++ desc.receives_notifications = dpio_attrs.num_priorities ? 1 : 0; ++ desc.has_8prio = dpio_attrs.num_priorities == 8 ? 1 : 0; ++ desc.dpio_id = dpio_dev->obj_desc.id; ++ ++ /* get the cpu to use for the affinity hint */ ++ if (next_cpu == -1) ++ next_cpu = cpumask_first(cpu_online_mask); ++ else ++ next_cpu = cpumask_next(next_cpu, cpu_online_mask); ++ ++ if (!cpu_possible(next_cpu)) { ++ dev_err(dev, "probe failed. Number of DPIOs exceeds NR_CPUS.\n"); ++ err = -ERANGE; ++ goto err_allocate_irqs; ++ } ++ desc.cpu = next_cpu; ++ ++ /* ++ * Set the CENA regs to be the cache enabled area of the portal to ++ * achieve the best performance. ++ */ ++ desc.regs_cena = ioremap_cache_ns(dpio_dev->regions[0].start, ++ resource_size(&dpio_dev->regions[0])); ++ desc.regs_cinh = ioremap(dpio_dev->regions[1].start, ++ resource_size(&dpio_dev->regions[1])); ++ ++ err = fsl_mc_allocate_irqs(dpio_dev); ++ if (err) { ++ dev_err(dev, "fsl_mc_allocate_irqs failed. err=%d\n", err); ++ goto err_allocate_irqs; ++ } ++ ++ err = register_dpio_irq_handlers(dpio_dev, desc.cpu); ++ if (err) ++ goto err_register_dpio_irq; ++ ++ priv->io = dpaa2_io_create(&desc); ++ if (!priv->io) { ++ dev_err(dev, "dpaa2_io_create failed\n"); ++ goto err_dpaa2_io_create; ++ } ++ ++ dev_info(dev, "probed\n"); ++ dev_dbg(dev, " receives_notifications = %d\n", ++ desc.receives_notifications); ++ dpio_close(dpio_dev->mc_io, 0, dpio_dev->mc_handle); ++ fsl_mc_portal_free(dpio_dev->mc_io); ++ ++ return 0; ++ ++err_dpaa2_io_create: ++ unregister_dpio_irq_handlers(dpio_dev); ++err_register_dpio_irq: ++ fsl_mc_free_irqs(dpio_dev); ++err_allocate_irqs: ++ dpio_disable(dpio_dev->mc_io, 0, dpio_dev->mc_handle); ++err_get_attr: ++ dpio_close(dpio_dev->mc_io, 0, dpio_dev->mc_handle); ++err_open: ++ fsl_mc_portal_free(dpio_dev->mc_io); ++err_mcportal: ++ dev_set_drvdata(dev, NULL); ++err_priv_alloc: ++ return err; ++} ++ ++/* Tear down interrupts for a given DPIO object */ ++static void dpio_teardown_irqs(struct fsl_mc_device *dpio_dev) ++{ ++ unregister_dpio_irq_handlers(dpio_dev); ++ fsl_mc_free_irqs(dpio_dev); ++} ++ ++static int dpaa2_dpio_remove(struct fsl_mc_device *dpio_dev) ++{ ++ struct device *dev; ++ struct dpio_priv *priv; ++ int err; ++ ++ dev = &dpio_dev->dev; ++ priv = dev_get_drvdata(dev); ++ ++ dpaa2_io_down(priv->io); ++ ++ dpio_teardown_irqs(dpio_dev); ++ ++ err = fsl_mc_portal_allocate(dpio_dev, 0, &dpio_dev->mc_io); ++ if (err) { ++ dev_err(dev, "MC portal allocation failed\n"); ++ goto err_mcportal; ++ } ++ ++ err = dpio_open(dpio_dev->mc_io, 0, dpio_dev->obj_desc.id, ++ &dpio_dev->mc_handle); ++ if (err) { ++ dev_err(dev, "dpio_open() failed\n"); ++ goto err_open; ++ } ++ ++ dpio_disable(dpio_dev->mc_io, 0, dpio_dev->mc_handle); ++ ++ dpio_close(dpio_dev->mc_io, 0, dpio_dev->mc_handle); ++ ++ fsl_mc_portal_free(dpio_dev->mc_io); ++ ++ dev_set_drvdata(dev, NULL); ++ ++ return 0; ++ ++err_open: ++ fsl_mc_portal_free(dpio_dev->mc_io); ++err_mcportal: ++ return err; ++} ++ ++static const struct fsl_mc_device_id dpaa2_dpio_match_id_table[] = { ++ { ++ .vendor = FSL_MC_VENDOR_FREESCALE, ++ .obj_type = "dpio", ++ }, ++ { .vendor = 0x0 } ++}; ++ ++static struct fsl_mc_driver dpaa2_dpio_driver = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = dpaa2_dpio_probe, ++ .remove = dpaa2_dpio_remove, ++ .match_id_table = dpaa2_dpio_match_id_table ++}; ++ ++static int dpio_driver_init(void) ++{ ++ return fsl_mc_driver_register(&dpaa2_dpio_driver); ++} ++ ++static void dpio_driver_exit(void) ++{ ++ fsl_mc_driver_unregister(&dpaa2_dpio_driver); ++} ++module_init(dpio_driver_init); ++module_exit(dpio_driver_exit); +diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio-driver.txt b/drivers/staging/fsl-mc/bus/dpio/dpio-driver.txt +new file mode 100644 +index 00000000..0ba67716 +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/dpio/dpio-driver.txt +@@ -0,0 +1,135 @@ ++Copyright 2016 NXP ++ ++Introduction ++------------ ++ ++A DPAA2 DPIO (Data Path I/O) is a hardware object that provides ++interfaces to enqueue and dequeue frames to/from network interfaces ++and other accelerators. A DPIO also provides hardware buffer ++pool management for network interfaces. ++ ++This document provides an overview the Linux DPIO driver, its ++subcomponents, and its APIs. ++ ++See Documentation/dpaa2/overview.txt for a general overview of DPAA2 ++and the general DPAA2 driver architecture in Linux. ++ ++Driver Overview ++--------------- ++ ++The DPIO driver is bound to DPIO objects discovered on the fsl-mc bus and ++provides services that: ++ A) allow other drivers, such as the Ethernet driver, to enqueue and dequeue ++ frames for their respective objects ++ B) allow drivers to register callbacks for data availability notifications ++ when data becomes available on a queue or channel ++ C) allow drivers to manage hardware buffer pools ++ ++The Linux DPIO driver consists of 3 primary components-- ++ DPIO object driver-- fsl-mc driver that manages the DPIO object ++ DPIO service-- provides APIs to other Linux drivers for services ++ QBman portal interface-- sends portal commands, gets responses ++ ++ fsl-mc other ++ bus drivers ++ | | ++ +---+----+ +------+-----+ ++ |DPIO obj| |DPIO service| ++ | driver |---| (DPIO) | ++ +--------+ +------+-----+ ++ | ++ +------+-----+ ++ | QBman | ++ | portal i/f | ++ +------------+ ++ | ++ hardware ++ ++The diagram below shows how the DPIO driver components fit with the other ++DPAA2 Linux driver components: ++ +------------+ ++ | OS Network | ++ | Stack | ++ +------------+ +------------+ ++ | Allocator |. . . . . . . | Ethernet | ++ |(DPMCP,DPBP)| | (DPNI) | ++ +-.----------+ +---+---+----+ ++ . . ^ | ++ . . | | dequeue> ++ +-------------+ . | | ++ | DPRC driver | . +--------+ +------------+ ++ | (DPRC) | . . |DPIO obj| |DPIO service| ++ +----------+--+ | driver |-| (DPIO) | ++ | +--------+ +------+-----+ ++ | +------|-----+ ++ | | QBman | ++ +----+--------------+ | portal i/f | ++ | MC-bus driver | +------------+ ++ | | | ++ | /soc/fsl-mc | | ++ +-------------------+ | ++ | ++ =========================================|=========|======================== ++ +-+--DPIO---|-----------+ ++ | | | ++ | QBman Portal | ++ +-----------------------+ ++ ++ ============================================================================ ++ ++ ++DPIO Object Driver (dpio-driver.c) ++---------------------------------- ++ ++ The dpio-driver component registers with the fsl-mc bus to handle objects of ++ type "dpio". The implementation of probe() handles basic initialization ++ of the DPIO including mapping of the DPIO regions (the QBman SW portal) ++ and initializing interrupts and registering irq handlers. The dpio-driver ++ registers the probed DPIO with dpio-service. ++ ++DPIO service (dpio-service.c, dpaa2-io.h) ++------------------------------------------ ++ ++ The dpio service component provides queuing, notification, and buffers ++ management services to DPAA2 drivers, such as the Ethernet driver. A system ++ will typically allocate 1 DPIO object per CPU to allow queuing operations ++ to happen simultaneously across all CPUs. ++ ++ Notification handling ++ dpaa2_io_service_register() ++ dpaa2_io_service_deregister() ++ dpaa2_io_service_rearm() ++ ++ Queuing ++ dpaa2_io_service_pull_fq() ++ dpaa2_io_service_pull_channel() ++ dpaa2_io_service_enqueue_fq() ++ dpaa2_io_service_enqueue_qd() ++ dpaa2_io_store_create() ++ dpaa2_io_store_destroy() ++ dpaa2_io_store_next() ++ ++ Buffer pool management ++ dpaa2_io_service_release() ++ dpaa2_io_service_acquire() ++ ++QBman portal interface (qbman-portal.c) ++--------------------------------------- ++ ++ The qbman-portal component provides APIs to do the low level hardware ++ bit twiddling for operations such as: ++ -initializing Qman software portals ++ -building and sending portal commands ++ -portal interrupt configuration and processing ++ ++ The qbman-portal APIs are not public to other drivers, and are ++ only used by dpio-service. ++ ++Other (dpaa2-fd.h, dpaa2-global.h) ++---------------------------------- ++ ++ Frame descriptor and scatter-gather definitions and the APIs used to ++ manipulate them are defined in dpaa2-fd.h. ++ ++ Dequeue result struct and parsing APIs are defined in dpaa2-global.h. +diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio-service.c b/drivers/staging/fsl-mc/bus/dpio/dpio-service.c +new file mode 100644 +index 00000000..46c32a67 +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/dpio/dpio-service.c +@@ -0,0 +1,689 @@ ++/* ++ * Copyright 2014-2016 Freescale Semiconductor Inc. ++ * Copyright 2016 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++#include ++#include "../../include/mc.h" ++#include "../../include/dpaa2-io.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "dpio.h" ++#include "qbman-portal.h" ++#include "qbman_debug.h" ++ ++struct dpaa2_io { ++ atomic_t refs; ++ struct dpaa2_io_desc dpio_desc; ++ struct qbman_swp_desc swp_desc; ++ struct qbman_swp *swp; ++ struct list_head node; ++ /* protect against multiple management commands */ ++ spinlock_t lock_mgmt_cmd; ++ /* protect notifications list */ ++ spinlock_t lock_notifications; ++ struct list_head notifications; ++}; ++ ++struct dpaa2_io_store { ++ unsigned int max; ++ dma_addr_t paddr; ++ struct dpaa2_dq *vaddr; ++ void *alloced_addr; /* unaligned value from kmalloc() */ ++ unsigned int idx; /* position of the next-to-be-returned entry */ ++ struct qbman_swp *swp; /* portal used to issue VDQCR */ ++ struct device *dev; /* device used for DMA mapping */ ++}; ++ ++/* keep a per cpu array of DPIOs for fast access */ ++static struct dpaa2_io *dpio_by_cpu[NR_CPUS]; ++static struct list_head dpio_list = LIST_HEAD_INIT(dpio_list); ++static DEFINE_SPINLOCK(dpio_list_lock); ++ ++static inline struct dpaa2_io *service_select_by_cpu(struct dpaa2_io *d, ++ int cpu) ++{ ++ if (d) ++ return d; ++ ++ if (unlikely(cpu >= num_possible_cpus())) ++ return NULL; ++ ++ /* ++ * If cpu == -1, choose the current cpu, with no guarantees about ++ * potentially being migrated away. ++ */ ++ if (unlikely(cpu < 0)) ++ cpu = smp_processor_id(); ++ ++ /* If a specific cpu was requested, pick it up immediately */ ++ return dpio_by_cpu[cpu]; ++} ++ ++static inline struct dpaa2_io *service_select(struct dpaa2_io *d) ++{ ++ if (d) ++ return d; ++ ++ spin_lock(&dpio_list_lock); ++ d = list_entry(dpio_list.next, struct dpaa2_io, node); ++ list_del(&d->node); ++ list_add_tail(&d->node, &dpio_list); ++ spin_unlock(&dpio_list_lock); ++ ++ return d; ++} ++ ++/** ++ * dpaa2_io_create() - create a dpaa2_io object. ++ * @desc: the dpaa2_io descriptor ++ * ++ * Activates a "struct dpaa2_io" corresponding to the given config of an actual ++ * DPIO object. ++ * ++ * Return a valid dpaa2_io object for success, or NULL for failure. ++ */ ++struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc) ++{ ++ struct dpaa2_io *obj = kmalloc(sizeof(*obj), GFP_KERNEL); ++ ++ if (!obj) ++ return NULL; ++ ++ /* check if CPU is out of range (-1 means any cpu) */ ++ if (desc->cpu >= num_possible_cpus()) { ++ kfree(obj); ++ return NULL; ++ } ++ ++ atomic_set(&obj->refs, 1); ++ obj->dpio_desc = *desc; ++ obj->swp_desc.cena_bar = obj->dpio_desc.regs_cena; ++ obj->swp_desc.cinh_bar = obj->dpio_desc.regs_cinh; ++ obj->swp_desc.qman_version = obj->dpio_desc.qman_version; ++ obj->swp = qbman_swp_init(&obj->swp_desc); ++ ++ if (!obj->swp) { ++ kfree(obj); ++ return NULL; ++ } ++ ++ INIT_LIST_HEAD(&obj->node); ++ spin_lock_init(&obj->lock_mgmt_cmd); ++ spin_lock_init(&obj->lock_notifications); ++ INIT_LIST_HEAD(&obj->notifications); ++ ++ /* For now only enable DQRR interrupts */ ++ qbman_swp_interrupt_set_trigger(obj->swp, ++ QBMAN_SWP_INTERRUPT_DQRI); ++ qbman_swp_interrupt_clear_status(obj->swp, 0xffffffff); ++ if (obj->dpio_desc.receives_notifications) ++ qbman_swp_push_set(obj->swp, 0, 1); ++ ++ spin_lock(&dpio_list_lock); ++ list_add_tail(&obj->node, &dpio_list); ++ if (desc->cpu >= 0 && !dpio_by_cpu[desc->cpu]) ++ dpio_by_cpu[desc->cpu] = obj; ++ spin_unlock(&dpio_list_lock); ++ ++ return obj; ++} ++EXPORT_SYMBOL(dpaa2_io_create); ++ ++/** ++ * dpaa2_io_down() - release the dpaa2_io object. ++ * @d: the dpaa2_io object to be released. ++ * ++ * The "struct dpaa2_io" type can represent an individual DPIO object (as ++ * described by "struct dpaa2_io_desc") or an instance of a "DPIO service", ++ * which can be used to group/encapsulate multiple DPIO objects. In all cases, ++ * each handle obtained should be released using this function. ++ */ ++void dpaa2_io_down(struct dpaa2_io *d) ++{ ++ if (!atomic_dec_and_test(&d->refs)) ++ return; ++ kfree(d); ++} ++EXPORT_SYMBOL(dpaa2_io_down); ++ ++#define DPAA_POLL_MAX 32 ++ ++/** ++ * dpaa2_io_irq() - ISR for DPIO interrupts ++ * ++ * @obj: the given DPIO object. ++ * ++ * Return IRQ_HANDLED for success or IRQ_NONE if there ++ * were no pending interrupts. ++ */ ++irqreturn_t dpaa2_io_irq(struct dpaa2_io *obj) ++{ ++ const struct dpaa2_dq *dq; ++ int max = 0; ++ struct qbman_swp *swp; ++ u32 status; ++ ++ swp = obj->swp; ++ status = qbman_swp_interrupt_read_status(swp); ++ if (!status) ++ return IRQ_NONE; ++ ++ dq = qbman_swp_dqrr_next(swp); ++ while (dq) { ++ if (qbman_result_is_SCN(dq)) { ++ struct dpaa2_io_notification_ctx *ctx; ++ u64 q64; ++ ++ q64 = qbman_result_SCN_ctx(dq); ++ ctx = (void *)q64; ++ ctx->cb(ctx); ++ } else { ++ pr_crit("fsl-mc-dpio: Unrecognised/ignored DQRR entry\n"); ++ } ++ qbman_swp_dqrr_consume(swp, dq); ++ ++max; ++ if (max > DPAA_POLL_MAX) ++ goto done; ++ dq = qbman_swp_dqrr_next(swp); ++ } ++done: ++ qbman_swp_interrupt_clear_status(swp, status); ++ qbman_swp_interrupt_set_inhibit(swp, 0); ++ return IRQ_HANDLED; ++} ++EXPORT_SYMBOL(dpaa2_io_irq); ++ ++/** ++ * dpaa2_io_service_register() - Prepare for servicing of FQDAN or CDAN ++ * notifications on the given DPIO service. ++ * @d: the given DPIO service. ++ * @ctx: the notification context. ++ * ++ * The caller should make the MC command to attach a DPAA2 object to ++ * a DPIO after this function completes successfully. In that way: ++ * (a) The DPIO service is "ready" to handle a notification arrival ++ * (which might happen before the "attach" command to MC has ++ * returned control of execution back to the caller) ++ * (b) The DPIO service can provide back to the caller the 'dpio_id' and ++ * 'qman64' parameters that it should pass along in the MC command ++ * in order for the object to be configured to produce the right ++ * notification fields to the DPIO service. ++ * ++ * Return 0 for success, or -ENODEV for failure. ++ */ ++int dpaa2_io_service_register(struct dpaa2_io *d, ++ struct dpaa2_io_notification_ctx *ctx) ++{ ++ unsigned long irqflags; ++ ++ d = service_select_by_cpu(d, ctx->desired_cpu); ++ if (!d) ++ return -ENODEV; ++ ++ ctx->dpio_id = d->dpio_desc.dpio_id; ++ ctx->qman64 = (u64)ctx; ++ ctx->dpio_private = d; ++ spin_lock_irqsave(&d->lock_notifications, irqflags); ++ list_add(&ctx->node, &d->notifications); ++ spin_unlock_irqrestore(&d->lock_notifications, irqflags); ++ ++ /* Enable the generation of CDAN notifications */ ++ if (ctx->is_cdan) ++ qbman_swp_CDAN_set_context_enable(d->swp, ++ (u16)ctx->id, ++ ctx->qman64); ++ return 0; ++} ++EXPORT_SYMBOL(dpaa2_io_service_register); ++ ++/** ++ * dpaa2_io_service_deregister - The opposite of 'register'. ++ * @service: the given DPIO service. ++ * @ctx: the notification context. ++ * ++ * This function should be called only after sending the MC command to ++ * to detach the notification-producing device from the DPIO. ++ */ ++void dpaa2_io_service_deregister(struct dpaa2_io *service, ++ struct dpaa2_io_notification_ctx *ctx) ++{ ++ struct dpaa2_io *d = ctx->dpio_private; ++ unsigned long irqflags; ++ ++ if (ctx->is_cdan) ++ qbman_swp_CDAN_disable(d->swp, (u16)ctx->id); ++ ++ spin_lock_irqsave(&d->lock_notifications, irqflags); ++ list_del(&ctx->node); ++ spin_unlock_irqrestore(&d->lock_notifications, irqflags); ++} ++EXPORT_SYMBOL(dpaa2_io_service_deregister); ++ ++/** ++ * dpaa2_io_service_rearm() - Rearm the notification for the given DPIO service. ++ * @d: the given DPIO service. ++ * @ctx: the notification context. ++ * ++ * Once a FQDAN/CDAN has been produced, the corresponding FQ/channel is ++ * considered "disarmed". Ie. the user can issue pull dequeue operations on that ++ * traffic source for as long as it likes. Eventually it may wish to "rearm" ++ * that source to allow it to produce another FQDAN/CDAN, that's what this ++ * function achieves. ++ * ++ * Return 0 for success. ++ */ ++int dpaa2_io_service_rearm(struct dpaa2_io *d, ++ struct dpaa2_io_notification_ctx *ctx) ++{ ++ unsigned long irqflags; ++ int err; ++ ++ d = service_select_by_cpu(d, ctx->desired_cpu); ++ if (!unlikely(d)) ++ return -ENODEV; ++ ++ spin_lock_irqsave(&d->lock_mgmt_cmd, irqflags); ++ if (ctx->is_cdan) ++ err = qbman_swp_CDAN_enable(d->swp, (u16)ctx->id); ++ else ++ err = qbman_swp_fq_schedule(d->swp, ctx->id); ++ spin_unlock_irqrestore(&d->lock_mgmt_cmd, irqflags); ++ ++ return err; ++} ++EXPORT_SYMBOL(dpaa2_io_service_rearm); ++ ++/** ++ * dpaa2_io_service_pull_fq() - pull dequeue functions from a fq. ++ * @d: the given DPIO service. ++ * @fqid: the given frame queue id. ++ * @s: the dpaa2_io_store object for the result. ++ * ++ * Return 0 for success, or error code for failure. ++ */ ++int dpaa2_io_service_pull_fq(struct dpaa2_io *d, u32 fqid, ++ struct dpaa2_io_store *s) ++{ ++ struct qbman_pull_desc pd; ++ int err; ++ ++ qbman_pull_desc_clear(&pd); ++ qbman_pull_desc_set_storage(&pd, s->vaddr, s->paddr, 1); ++ qbman_pull_desc_set_numframes(&pd, (u8)s->max); ++ qbman_pull_desc_set_fq(&pd, fqid); ++ ++ d = service_select(d); ++ if (!d) ++ return -ENODEV; ++ s->swp = d->swp; ++ err = qbman_swp_pull(d->swp, &pd); ++ if (err) ++ s->swp = NULL; ++ ++ return err; ++} ++EXPORT_SYMBOL(dpaa2_io_service_pull_fq); ++ ++/** ++ * dpaa2_io_service_pull_channel() - pull dequeue functions from a channel. ++ * @d: the given DPIO service. ++ * @channelid: the given channel id. ++ * @s: the dpaa2_io_store object for the result. ++ * ++ * Return 0 for success, or error code for failure. ++ */ ++int dpaa2_io_service_pull_channel(struct dpaa2_io *d, u32 channelid, ++ struct dpaa2_io_store *s) ++{ ++ struct qbman_pull_desc pd; ++ int err; ++ ++ qbman_pull_desc_clear(&pd); ++ qbman_pull_desc_set_storage(&pd, s->vaddr, s->paddr, 1); ++ qbman_pull_desc_set_numframes(&pd, (u8)s->max); ++ qbman_pull_desc_set_channel(&pd, channelid, qbman_pull_type_prio); ++ ++ d = service_select(d); ++ if (!d) ++ return -ENODEV; ++ ++ s->swp = d->swp; ++ err = qbman_swp_pull(d->swp, &pd); ++ if (err) ++ s->swp = NULL; ++ ++ return err; ++} ++EXPORT_SYMBOL(dpaa2_io_service_pull_channel); ++ ++/** ++ * dpaa2_io_service_enqueue_fq() - Enqueue a frame to a frame queue. ++ * @d: the given DPIO service. ++ * @fqid: the given frame queue id. ++ * @fd: the frame descriptor which is enqueued. ++ * ++ * Return 0 for successful enqueue, -EBUSY if the enqueue ring is not ready, ++ * or -ENODEV if there is no dpio service. ++ */ ++int dpaa2_io_service_enqueue_fq(struct dpaa2_io *d, ++ u32 fqid, ++ const struct dpaa2_fd *fd) ++{ ++ struct qbman_eq_desc ed; ++ ++ d = service_select(d); ++ if (!d) ++ return -ENODEV; ++ ++ qbman_eq_desc_clear(&ed); ++ qbman_eq_desc_set_no_orp(&ed, 0); ++ qbman_eq_desc_set_fq(&ed, fqid); ++ ++ return qbman_swp_enqueue(d->swp, &ed, fd); ++} ++EXPORT_SYMBOL(dpaa2_io_service_enqueue_fq); ++ ++/** ++ * dpaa2_io_service_enqueue_qd() - Enqueue a frame to a QD. ++ * @d: the given DPIO service. ++ * @qdid: the given queuing destination id. ++ * @prio: the given queuing priority. ++ * @qdbin: the given queuing destination bin. ++ * @fd: the frame descriptor which is enqueued. ++ * ++ * Return 0 for successful enqueue, or -EBUSY if the enqueue ring is not ready, ++ * or -ENODEV if there is no dpio service. ++ */ ++int dpaa2_io_service_enqueue_qd(struct dpaa2_io *d, ++ u32 qdid, u8 prio, u16 qdbin, ++ const struct dpaa2_fd *fd) ++{ ++ struct qbman_eq_desc ed; ++ ++ d = service_select(d); ++ if (!d) ++ return -ENODEV; ++ ++ qbman_eq_desc_clear(&ed); ++ qbman_eq_desc_set_no_orp(&ed, 0); ++ qbman_eq_desc_set_qd(&ed, qdid, qdbin, prio); ++ ++ return qbman_swp_enqueue(d->swp, &ed, fd); ++} ++EXPORT_SYMBOL(dpaa2_io_service_enqueue_qd); ++ ++/** ++ * dpaa2_io_service_release() - Release buffers to a buffer pool. ++ * @d: the given DPIO object. ++ * @bpid: the buffer pool id. ++ * @buffers: the buffers to be released. ++ * @num_buffers: the number of the buffers to be released. ++ * ++ * Return 0 for success, and negative error code for failure. ++ */ ++int dpaa2_io_service_release(struct dpaa2_io *d, ++ u32 bpid, ++ const u64 *buffers, ++ unsigned int num_buffers) ++{ ++ struct qbman_release_desc rd; ++ ++ d = service_select(d); ++ if (!d) ++ return -ENODEV; ++ ++ qbman_release_desc_clear(&rd); ++ qbman_release_desc_set_bpid(&rd, bpid); ++ ++ return qbman_swp_release(d->swp, &rd, buffers, num_buffers); ++} ++EXPORT_SYMBOL(dpaa2_io_service_release); ++ ++/** ++ * dpaa2_io_service_acquire() - Acquire buffers from a buffer pool. ++ * @d: the given DPIO object. ++ * @bpid: the buffer pool id. ++ * @buffers: the buffer addresses for acquired buffers. ++ * @num_buffers: the expected number of the buffers to acquire. ++ * ++ * Return a negative error code if the command failed, otherwise it returns ++ * the number of buffers acquired, which may be less than the number requested. ++ * Eg. if the buffer pool is empty, this will return zero. ++ */ ++int dpaa2_io_service_acquire(struct dpaa2_io *d, ++ u32 bpid, ++ u64 *buffers, ++ unsigned int num_buffers) ++{ ++ unsigned long irqflags; ++ int err; ++ ++ d = service_select(d); ++ if (!d) ++ return -ENODEV; ++ ++ spin_lock_irqsave(&d->lock_mgmt_cmd, irqflags); ++ err = qbman_swp_acquire(d->swp, bpid, buffers, num_buffers); ++ spin_unlock_irqrestore(&d->lock_mgmt_cmd, irqflags); ++ ++ return err; ++} ++EXPORT_SYMBOL(dpaa2_io_service_acquire); ++ ++/* ++ * 'Stores' are reusable memory blocks for holding dequeue results, and to ++ * assist with parsing those results. ++ */ ++ ++/** ++ * dpaa2_io_store_create() - Create the dma memory storage for dequeue result. ++ * @max_frames: the maximum number of dequeued result for frames, must be <= 16. ++ * @dev: the device to allow mapping/unmapping the DMAable region. ++ * ++ * The size of the storage is "max_frames*sizeof(struct dpaa2_dq)". ++ * The 'dpaa2_io_store' returned is a DPIO service managed object. ++ * ++ * Return pointer to dpaa2_io_store struct for successfuly created storage ++ * memory, or NULL on error. ++ */ ++struct dpaa2_io_store *dpaa2_io_store_create(unsigned int max_frames, ++ struct device *dev) ++{ ++ struct dpaa2_io_store *ret; ++ size_t size; ++ ++ if (!max_frames || (max_frames > 16)) ++ return NULL; ++ ++ ret = kmalloc(sizeof(*ret), GFP_KERNEL); ++ if (!ret) ++ return NULL; ++ ++ ret->max = max_frames; ++ size = max_frames * sizeof(struct dpaa2_dq) + 64; ++ ret->alloced_addr = kzalloc(size, GFP_KERNEL); ++ if (!ret->alloced_addr) { ++ kfree(ret); ++ return NULL; ++ } ++ ++ ret->vaddr = PTR_ALIGN(ret->alloced_addr, 64); ++ ret->paddr = dma_map_single(dev, ret->vaddr, ++ sizeof(struct dpaa2_dq) * max_frames, ++ DMA_FROM_DEVICE); ++ if (dma_mapping_error(dev, ret->paddr)) { ++ kfree(ret->alloced_addr); ++ kfree(ret); ++ return NULL; ++ } ++ ++ ret->idx = 0; ++ ret->dev = dev; ++ ++ return ret; ++} ++EXPORT_SYMBOL(dpaa2_io_store_create); ++ ++/** ++ * dpaa2_io_store_destroy() - Frees the dma memory storage for dequeue ++ * result. ++ * @s: the storage memory to be destroyed. ++ */ ++void dpaa2_io_store_destroy(struct dpaa2_io_store *s) ++{ ++ dma_unmap_single(s->dev, s->paddr, sizeof(struct dpaa2_dq) * s->max, ++ DMA_FROM_DEVICE); ++ kfree(s->alloced_addr); ++ kfree(s); ++} ++EXPORT_SYMBOL(dpaa2_io_store_destroy); ++ ++/** ++ * dpaa2_io_store_next() - Determine when the next dequeue result is available. ++ * @s: the dpaa2_io_store object. ++ * @is_last: indicate whether this is the last frame in the pull command. ++ * ++ * When an object driver performs dequeues to a dpaa2_io_store, this function ++ * can be used to determine when the next frame result is available. Once ++ * this function returns non-NULL, a subsequent call to it will try to find ++ * the next dequeue result. ++ * ++ * Note that if a pull-dequeue has a NULL result because the target FQ/channel ++ * was empty, then this function will also return NULL (rather than expecting ++ * the caller to always check for this. As such, "is_last" can be used to ++ * differentiate between "end-of-empty-dequeue" and "still-waiting". ++ * ++ * Return dequeue result for a valid dequeue result, or NULL for empty dequeue. ++ */ ++struct dpaa2_dq *dpaa2_io_store_next(struct dpaa2_io_store *s, int *is_last) ++{ ++ int match; ++ struct dpaa2_dq *ret = &s->vaddr[s->idx]; ++ ++ match = qbman_result_has_new_result(s->swp, ret); ++ if (!match) { ++ *is_last = 0; ++ return NULL; ++ } ++ ++ s->idx++; ++ ++ if (dpaa2_dq_is_pull_complete(ret)) { ++ *is_last = 1; ++ s->idx = 0; ++ /* ++ * If we get an empty dequeue result to terminate a zero-results ++ * vdqcr, return NULL to the caller rather than expecting him to ++ * check non-NULL results every time. ++ */ ++ if (!(dpaa2_dq_flags(ret) & DPAA2_DQ_STAT_VALIDFRAME)) ++ ret = NULL; ++ } else { ++ *is_last = 0; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL(dpaa2_io_store_next); ++ ++#ifdef CONFIG_FSL_QBMAN_DEBUG ++/** ++ * dpaa2_io_query_fq_count() - Get the frame and byte count for a given fq. ++ * @d: the given DPIO object. ++ * @fqid: the id of frame queue to be queried. ++ * @fcnt: the queried frame count. ++ * @bcnt: the queried byte count. ++ * ++ * Knowing the FQ count at run-time can be useful in debugging situations. ++ * The instantaneous frame- and byte-count are hereby returned. ++ * ++ * Return 0 for a successful query, and negative error code if query fails. ++ */ ++int dpaa2_io_query_fq_count(struct dpaa2_io *d, uint32_t fqid, ++ u32 *fcnt, u32 *bcnt) ++{ ++ struct qbman_attr state; ++ struct qbman_swp *swp; ++ unsigned long irqflags; ++ int ret; ++ ++ d = service_select(d); ++ if (!d) ++ return -ENODEV; ++ ++ swp = d->swp; ++ spin_lock_irqsave(&d->lock_mgmt_cmd, irqflags); ++ ret = qbman_fq_query_state(swp, fqid, &state); ++ spin_unlock_irqrestore(&d->lock_mgmt_cmd, irqflags); ++ if (ret) ++ return ret; ++ *fcnt = qbman_fq_state_frame_count(&state); ++ *bcnt = qbman_fq_state_byte_count(&state); ++ ++ return 0; ++} ++EXPORT_SYMBOL(dpaa2_io_query_fq_count); ++ ++/** ++ * dpaa2_io_query_bp_count() - Query the number of buffers currenty in a ++ * buffer pool. ++ * @d: the given DPIO object. ++ * @bpid: the index of buffer pool to be queried. ++ * @num: the queried number of buffers in the buffer pool. ++ * ++ * Return 0 for a sucessful query, and negative error code if query fails. ++ */ ++int dpaa2_io_query_bp_count(struct dpaa2_io *d, uint32_t bpid, u32 *num) ++{ ++ struct qbman_attr state; ++ struct qbman_swp *swp; ++ unsigned long irqflags; ++ int ret; ++ ++ d = service_select(d); ++ if (!d) ++ return -ENODEV; ++ ++ swp = d->swp; ++ spin_lock_irqsave(&d->lock_mgmt_cmd, irqflags); ++ ret = qbman_bp_query(swp, bpid, &state); ++ spin_unlock_irqrestore(&d->lock_mgmt_cmd, irqflags); ++ if (ret) ++ return ret; ++ *num = qbman_bp_info_num_free_bufs(&state); ++ return 0; ++} ++EXPORT_SYMBOL(dpaa2_io_query_bp_count); ++#endif +diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio.c b/drivers/staging/fsl-mc/bus/dpio/dpio.c +new file mode 100644 +index 00000000..d81e0232 +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/dpio/dpio.c +@@ -0,0 +1,224 @@ ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. ++ * Copyright 2016 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#include "../../include/mc-sys.h" ++#include "../../include/mc-cmd.h" ++ ++#include "dpio.h" ++#include "dpio-cmd.h" ++ ++/* ++ * Data Path I/O Portal API ++ * Contains initialization APIs and runtime control APIs for DPIO ++ */ ++ ++/** ++ * dpio_open() - Open a control session for the specified object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @dpio_id: DPIO unique ID ++ * @token: Returned token; use in subsequent API calls ++ * ++ * This function can be used to open a control session for an ++ * already created object; an object may have been declared in ++ * the DPL or by calling the dpio_create() function. ++ * This function returns a unique authentication token, ++ * associated with the specific object ID and the specific MC ++ * portal; this token must be used in all subsequent commands for ++ * this specific object. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpio_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpio_id, ++ u16 *token) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpio_cmd_open *dpio_cmd; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPIO_CMDID_OPEN, ++ cmd_flags, ++ 0); ++ dpio_cmd = (struct dpio_cmd_open *)cmd.params; ++ dpio_cmd->dpio_id = cpu_to_le32(dpio_id); ++ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *token = mc_cmd_hdr_read_token(&cmd); ++ ++ return 0; ++} ++ ++/** ++ * dpio_close() - Close the control session of the object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPIO object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpio_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPIO_CMDID_CLOSE, ++ cmd_flags, ++ token); ++ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpio_enable() - Enable the DPIO, allow I/O portal operations. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPIO object ++ * ++ * Return: '0' on Success; Error code otherwise ++ */ ++int dpio_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPIO_CMDID_ENABLE, ++ cmd_flags, ++ token); ++ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpio_disable() - Disable the DPIO, stop any I/O portal operation. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPIO object ++ * ++ * Return: '0' on Success; Error code otherwise ++ */ ++int dpio_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPIO_CMDID_DISABLE, ++ cmd_flags, ++ token); ++ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpio_get_attributes() - Retrieve DPIO attributes ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPIO object ++ * @attr: Returned object's attributes ++ * ++ * Return: '0' on Success; Error code otherwise ++ */ ++int dpio_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpio_attr *attr) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpio_rsp_get_attr *dpio_rsp; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPIO_CMDID_GET_ATTR, ++ cmd_flags, ++ token); ++ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ dpio_rsp = (struct dpio_rsp_get_attr *)cmd.params; ++ attr->id = le32_to_cpu(dpio_rsp->id); ++ attr->qbman_portal_id = le16_to_cpu(dpio_rsp->qbman_portal_id); ++ attr->num_priorities = dpio_rsp->num_priorities; ++ attr->channel_mode = dpio_rsp->channel_mode & DPIO_CHANNEL_MODE_MASK; ++ attr->qbman_portal_ce_offset = ++ le64_to_cpu(dpio_rsp->qbman_portal_ce_addr); ++ attr->qbman_portal_ci_offset = ++ le64_to_cpu(dpio_rsp->qbman_portal_ci_addr); ++ attr->qbman_version = le32_to_cpu(dpio_rsp->qbman_version); ++ ++ return 0; ++} ++ ++/** ++ * dpio_get_api_version - Get Data Path I/O API version ++ * @mc_io: Pointer to MC portal's DPIO object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @major_ver: Major version of DPIO API ++ * @minor_ver: Minor version of DPIO API ++ * ++ * Return: '0' on Success; Error code otherwise ++ */ ++int dpio_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver) ++{ ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPIO_CMDID_GET_API_VERSION, ++ cmd_flags, 0); ++ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ mc_cmd_read_api_version(&cmd, major_ver, minor_ver); ++ ++ return 0; ++} +diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio.h b/drivers/staging/fsl-mc/bus/dpio/dpio.h +new file mode 100644 +index 00000000..ced1103d +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/dpio/dpio.h +@@ -0,0 +1,109 @@ ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. ++ * Copyright 2016 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef __FSL_DPIO_H ++#define __FSL_DPIO_H ++ ++struct fsl_mc_io; ++ ++int dpio_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpio_id, ++ u16 *token); ++ ++int dpio_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++/** ++ * enum dpio_channel_mode - DPIO notification channel mode ++ * @DPIO_NO_CHANNEL: No support for notification channel ++ * @DPIO_LOCAL_CHANNEL: Notifications on data availability can be received by a ++ * dedicated channel in the DPIO; user should point the queue's ++ * destination in the relevant interface to this DPIO ++ */ ++enum dpio_channel_mode { ++ DPIO_NO_CHANNEL = 0, ++ DPIO_LOCAL_CHANNEL = 1, ++}; ++ ++/** ++ * struct dpio_cfg - Structure representing DPIO configuration ++ * @channel_mode: Notification channel mode ++ * @num_priorities: Number of priorities for the notification channel (1-8); ++ * relevant only if 'channel_mode = DPIO_LOCAL_CHANNEL' ++ */ ++struct dpio_cfg { ++ enum dpio_channel_mode channel_mode; ++ u8 num_priorities; ++}; ++ ++int dpio_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpio_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++/** ++ * struct dpio_attr - Structure representing DPIO attributes ++ * @id: DPIO object ID ++ * @qbman_portal_ce_offset: offset of the software portal cache-enabled area ++ * @qbman_portal_ci_offset: offset of the software portal cache-inhibited area ++ * @qbman_portal_id: Software portal ID ++ * @channel_mode: Notification channel mode ++ * @num_priorities: Number of priorities for the notification channel (1-8); ++ * relevant only if 'channel_mode = DPIO_LOCAL_CHANNEL' ++ * @qbman_version: QBMAN version ++ */ ++struct dpio_attr { ++ int id; ++ u64 qbman_portal_ce_offset; ++ u64 qbman_portal_ci_offset; ++ u16 qbman_portal_id; ++ enum dpio_channel_mode channel_mode; ++ u8 num_priorities; ++ u32 qbman_version; ++}; ++ ++int dpio_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpio_attr *attr); ++ ++int dpio_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver); ++ ++#endif /* __FSL_DPIO_H */ +diff --git a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c b/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c +new file mode 100644 +index 00000000..e14fb65b +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c +@@ -0,0 +1,1049 @@ ++/* ++ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. ++ * Copyright 2016 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++#include "../../include/dpaa2-global.h" ++ ++#include "qbman-portal.h" ++ ++struct qb_attr_code code_generic_verb = QB_CODE(0, 0, 7); ++struct qb_attr_code code_generic_rslt = QB_CODE(0, 8, 8); ++ ++#define QMAN_REV_4000 0x04000000 ++#define QMAN_REV_4100 0x04010000 ++#define QMAN_REV_4101 0x04010001 ++#define QMAN_REV_MASK 0xffff0000 ++ ++/* All QBMan command and result structures use this "valid bit" encoding */ ++#define QB_VALID_BIT ((u32)0x80) ++ ++/* QBMan portal management command codes */ ++#define QBMAN_MC_ACQUIRE 0x30 ++#define QBMAN_WQCHAN_CONFIGURE 0x46 ++ ++/* CINH register offsets */ ++#define QBMAN_CINH_SWP_EQAR 0x8c0 ++#define QBMAN_CINH_SWP_DQPI 0xa00 ++#define QBMAN_CINH_SWP_DCAP 0xac0 ++#define QBMAN_CINH_SWP_SDQCR 0xb00 ++#define QBMAN_CINH_SWP_RAR 0xcc0 ++#define QBMAN_CINH_SWP_ISR 0xe00 ++#define QBMAN_CINH_SWP_IER 0xe40 ++#define QBMAN_CINH_SWP_ISDR 0xe80 ++#define QBMAN_CINH_SWP_IIR 0xec0 ++ ++/* CENA register offsets */ ++#define QBMAN_CENA_SWP_EQCR(n) (0x000 + ((u32)(n) << 6)) ++#define QBMAN_CENA_SWP_DQRR(n) (0x200 + ((u32)(n) << 6)) ++#define QBMAN_CENA_SWP_RCR(n) (0x400 + ((u32)(n) << 6)) ++#define QBMAN_CENA_SWP_CR 0x600 ++#define QBMAN_CENA_SWP_RR(vb) (0x700 + ((u32)(vb) >> 1)) ++#define QBMAN_CENA_SWP_VDQCR 0x780 ++ ++/* Reverse mapping of QBMAN_CENA_SWP_DQRR() */ ++#define QBMAN_IDX_FROM_DQRR(p) (((unsigned long)(p) & 0x1ff) >> 6) ++ ++/* Define token used to determine if response written to memory is valid */ ++#define QMAN_DQ_TOKEN_VALID 1 ++ ++/* SDQCR attribute codes */ ++#define QB_SDQCR_FC_SHIFT 29 ++#define QB_SDQCR_FC_MASK 0x1 ++#define QB_SDQCR_DCT_SHIFT 24 ++#define QB_SDQCR_DCT_MASK 0x3 ++#define QB_SDQCR_TOK_SHIFT 16 ++#define QB_SDQCR_TOK_MASK 0xff ++#define QB_SDQCR_SRC_SHIFT 0 ++#define QB_SDQCR_SRC_MASK 0xffff ++ ++/* opaque token for static dequeues */ ++#define QMAN_SDQCR_TOKEN 0xbb ++ ++enum qbman_sdqcr_dct { ++ qbman_sdqcr_dct_null = 0, ++ qbman_sdqcr_dct_prio_ics, ++ qbman_sdqcr_dct_active_ics, ++ qbman_sdqcr_dct_active ++}; ++ ++enum qbman_sdqcr_fc { ++ qbman_sdqcr_fc_one = 0, ++ qbman_sdqcr_fc_up_to_3 = 1 ++}; ++ ++#define dccvac(p) { asm volatile("dc cvac, %0;" : : "r" (p) : "memory"); } ++#define dcivac(p) { asm volatile("dc ivac, %0" : : "r"(p) : "memory"); } ++static inline void qbman_inval_prefetch(struct qbman_swp *p, uint32_t offset) ++{ ++ dcivac(p->addr_cena + offset); ++ prefetch(p->addr_cena + offset); ++} ++ ++/* Portal Access */ ++ ++static inline u32 qbman_read_register(struct qbman_swp *p, u32 offset) ++{ ++ return readl_relaxed(p->addr_cinh + offset); ++} ++ ++static inline void qbman_write_register(struct qbman_swp *p, u32 offset, ++ u32 value) ++{ ++ writel_relaxed(value, p->addr_cinh + offset); ++} ++ ++static inline void *qbman_get_cmd(struct qbman_swp *p, u32 offset) ++{ ++ return p->addr_cena + offset; ++} ++ ++#define QBMAN_CINH_SWP_CFG 0xd00 ++ ++#define SWP_CFG_DQRR_MF_SHIFT 20 ++#define SWP_CFG_EST_SHIFT 16 ++#define SWP_CFG_WN_SHIFT 14 ++#define SWP_CFG_RPM_SHIFT 12 ++#define SWP_CFG_DCM_SHIFT 10 ++#define SWP_CFG_EPM_SHIFT 8 ++#define SWP_CFG_SD_SHIFT 5 ++#define SWP_CFG_SP_SHIFT 4 ++#define SWP_CFG_SE_SHIFT 3 ++#define SWP_CFG_DP_SHIFT 2 ++#define SWP_CFG_DE_SHIFT 1 ++#define SWP_CFG_EP_SHIFT 0 ++ ++static inline u32 qbman_set_swp_cfg(u8 max_fill, u8 wn, u8 est, u8 rpm, u8 dcm, ++ u8 epm, int sd, int sp, int se, ++ int dp, int de, int ep) ++{ ++ return cpu_to_le32 (max_fill << SWP_CFG_DQRR_MF_SHIFT | ++ est << SWP_CFG_EST_SHIFT | ++ wn << SWP_CFG_WN_SHIFT | ++ rpm << SWP_CFG_RPM_SHIFT | ++ dcm << SWP_CFG_DCM_SHIFT | ++ epm << SWP_CFG_EPM_SHIFT | ++ sd << SWP_CFG_SD_SHIFT | ++ sp << SWP_CFG_SP_SHIFT | ++ se << SWP_CFG_SE_SHIFT | ++ dp << SWP_CFG_DP_SHIFT | ++ de << SWP_CFG_DE_SHIFT | ++ ep << SWP_CFG_EP_SHIFT); ++} ++ ++/** ++ * qbman_swp_init() - Create a functional object representing the given ++ * QBMan portal descriptor. ++ * @d: the given qbman swp descriptor ++ * ++ * Return qbman_swp portal for success, NULL if the object cannot ++ * be created. ++ */ ++struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d) ++{ ++ struct qbman_swp *p = kmalloc(sizeof(*p), GFP_KERNEL); ++ u32 reg; ++ ++ if (!p) ++ return NULL; ++ p->desc = d; ++ p->mc.valid_bit = QB_VALID_BIT; ++ p->sdq = 0; ++ p->sdq |= qbman_sdqcr_dct_prio_ics << QB_SDQCR_DCT_SHIFT; ++ p->sdq |= qbman_sdqcr_fc_up_to_3 << QB_SDQCR_FC_SHIFT; ++ p->sdq |= QMAN_SDQCR_TOKEN << QB_SDQCR_TOK_SHIFT; ++ ++ atomic_set(&p->vdq.available, 1); ++ p->vdq.valid_bit = QB_VALID_BIT; ++ p->dqrr.next_idx = 0; ++ p->dqrr.valid_bit = QB_VALID_BIT; ++ ++ if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_4100) { ++ p->dqrr.dqrr_size = 4; ++ p->dqrr.reset_bug = 1; ++ } else { ++ p->dqrr.dqrr_size = 8; ++ p->dqrr.reset_bug = 0; ++ } ++ ++ p->addr_cena = d->cena_bar; ++ p->addr_cinh = d->cinh_bar; ++ ++ reg = qbman_set_swp_cfg(p->dqrr.dqrr_size, ++ 0, /* Writes cacheable */ ++ 0, /* EQCR_CI stashing threshold */ ++ 3, /* RPM: Valid bit mode, RCR in array mode */ ++ 2, /* DCM: Discrete consumption ack mode */ ++ 3, /* EPM: Valid bit mode, EQCR in array mode */ ++ 0, /* mem stashing drop enable == FALSE */ ++ 1, /* mem stashing priority == TRUE */ ++ 0, /* mem stashing enable == FALSE */ ++ 1, /* dequeue stashing priority == TRUE */ ++ 0, /* dequeue stashing enable == FALSE */ ++ 0); /* EQCR_CI stashing priority == FALSE */ ++ ++ qbman_write_register(p, QBMAN_CINH_SWP_CFG, reg); ++ reg = qbman_read_register(p, QBMAN_CINH_SWP_CFG); ++ if (!reg) { ++ pr_err("qbman: the portal is not enabled!\n"); ++ return NULL; ++ } ++ ++ /* ++ * SDQCR needs to be initialized to 0 when no channels are ++ * being dequeued from or else the QMan HW will indicate an ++ * error. The values that were calculated above will be ++ * applied when dequeues from a specific channel are enabled. ++ */ ++ qbman_write_register(p, QBMAN_CINH_SWP_SDQCR, 0); ++ return p; ++} ++ ++/** ++ * qbman_swp_finish() - Create and destroy a functional object representing ++ * the given QBMan portal descriptor. ++ * @p: the qbman_swp object to be destroyed ++ */ ++void qbman_swp_finish(struct qbman_swp *p) ++{ ++ kfree(p); ++} ++ ++/** ++ * qbman_swp_interrupt_read_status() ++ * @p: the given software portal ++ * ++ * Return the value in the SWP_ISR register. ++ */ ++u32 qbman_swp_interrupt_read_status(struct qbman_swp *p) ++{ ++ return qbman_read_register(p, QBMAN_CINH_SWP_ISR); ++} ++ ++/** ++ * qbman_swp_interrupt_clear_status() ++ * @p: the given software portal ++ * @mask: The mask to clear in SWP_ISR register ++ */ ++void qbman_swp_interrupt_clear_status(struct qbman_swp *p, u32 mask) ++{ ++ qbman_write_register(p, QBMAN_CINH_SWP_ISR, mask); ++} ++ ++/** ++ * qbman_swp_interrupt_get_trigger() - read interrupt enable register ++ * @p: the given software portal ++ * ++ * Return the value in the SWP_IER register. ++ */ ++u32 qbman_swp_interrupt_get_trigger(struct qbman_swp *p) ++{ ++ return qbman_read_register(p, QBMAN_CINH_SWP_IER); ++} ++ ++/** ++ * qbman_swp_interrupt_set_trigger() - enable interrupts for a swp ++ * @p: the given software portal ++ * @mask: The mask of bits to enable in SWP_IER ++ */ ++void qbman_swp_interrupt_set_trigger(struct qbman_swp *p, u32 mask) ++{ ++ qbman_write_register(p, QBMAN_CINH_SWP_IER, mask); ++} ++ ++/** ++ * qbman_swp_interrupt_get_inhibit() - read interrupt mask register ++ * @p: the given software portal object ++ * ++ * Return the value in the SWP_IIR register. ++ */ ++int qbman_swp_interrupt_get_inhibit(struct qbman_swp *p) ++{ ++ return qbman_read_register(p, QBMAN_CINH_SWP_IIR); ++} ++ ++/** ++ * qbman_swp_interrupt_set_inhibit() - write interrupt mask register ++ * @p: the given software portal object ++ * @mask: The mask to set in SWP_IIR register ++ */ ++void qbman_swp_interrupt_set_inhibit(struct qbman_swp *p, int inhibit) ++{ ++ qbman_write_register(p, QBMAN_CINH_SWP_IIR, inhibit ? 0xffffffff : 0); ++} ++ ++/* ++ * Different management commands all use this common base layer of code to issue ++ * commands and poll for results. ++ */ ++ ++/* ++ * Returns a pointer to where the caller should fill in their management command ++ * (caller should ignore the verb byte) ++ */ ++void *qbman_swp_mc_start(struct qbman_swp *p) ++{ ++ return qbman_get_cmd(p, QBMAN_CENA_SWP_CR); ++} ++ ++/* ++ * Commits merges in the caller-supplied command verb (which should not include ++ * the valid-bit) and submits the command to hardware ++ */ ++void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, u8 cmd_verb) ++{ ++ u8 *v = cmd; ++ ++ dma_wmb(); ++ *v = cmd_verb | p->mc.valid_bit; ++ dccvac(cmd); ++} ++ ++/* ++ * Checks for a completed response (returns non-NULL if only if the response ++ * is complete). ++ */ ++void *qbman_swp_mc_result(struct qbman_swp *p) ++{ ++ u32 *ret, verb; ++ ++ qbman_inval_prefetch(p, QBMAN_CENA_SWP_RR(p->mc.valid_bit)); ++ ret = qbman_get_cmd(p, QBMAN_CENA_SWP_RR(p->mc.valid_bit)); ++ ++ /* Remove the valid-bit - command completed if the rest is non-zero */ ++ verb = ret[0] & ~QB_VALID_BIT; ++ if (!verb) ++ return NULL; ++ p->mc.valid_bit ^= QB_VALID_BIT; ++ return ret; ++} ++ ++#define QB_ENQUEUE_CMD_OPTIONS_SHIFT 0 ++enum qb_enqueue_commands { ++ enqueue_empty = 0, ++ enqueue_response_always = 1, ++ enqueue_rejects_to_fq = 2 ++}; ++ ++#define QB_ENQUEUE_CMD_ORP_ENABLE_SHIFT 2 ++#define QB_ENQUEUE_CMD_IRQ_ON_DISPATCH_SHIFT 3 ++#define QB_ENQUEUE_CMD_TARGET_TYPE_SHIFT 4 ++ ++/** ++ * qbman_eq_desc_clear() - Clear the contents of a descriptor to ++ * default/starting state. ++ */ ++void qbman_eq_desc_clear(struct qbman_eq_desc *d) ++{ ++ memset(d, 0, sizeof(*d)); ++} ++ ++/** ++ * qbman_eq_desc_set_no_orp() - Set enqueue descriptor without orp ++ * @d: the enqueue descriptor. ++ * @response_success: 1 = enqueue with response always; 0 = enqueue with ++ * rejections returned on a FQ. ++ */ ++void qbman_eq_desc_set_no_orp(struct qbman_eq_desc *d, int respond_success) ++{ ++ d->verb &= ~(1 << QB_ENQUEUE_CMD_ORP_ENABLE_SHIFT); ++ if (respond_success) ++ d->verb |= enqueue_response_always; ++ else ++ d->verb |= enqueue_rejects_to_fq; ++} ++ ++/* ++ * Exactly one of the following descriptor "targets" should be set. (Calling any ++ * one of these will replace the effect of any prior call to one of these.) ++ * -enqueue to a frame queue ++ * -enqueue to a queuing destination ++ */ ++ ++/** ++ * qbman_eq_desc_set_fq() - set the FQ for the enqueue command ++ * @d: the enqueue descriptor ++ * @fqid: the id of the frame queue to be enqueued ++ */ ++void qbman_eq_desc_set_fq(struct qbman_eq_desc *d, u32 fqid) ++{ ++ d->verb &= ~(1 << QB_ENQUEUE_CMD_TARGET_TYPE_SHIFT); ++ d->tgtid = cpu_to_le32(fqid); ++} ++ ++/** ++ * qbman_eq_desc_set_qd() - Set Queuing Destination for the enqueue command ++ * @d: the enqueue descriptor ++ * @qdid: the id of the queuing destination to be enqueued ++ * @qd_bin: the queuing destination bin ++ * @qd_prio: the queuing destination priority ++ */ ++void qbman_eq_desc_set_qd(struct qbman_eq_desc *d, u32 qdid, ++ u32 qd_bin, u32 qd_prio) ++{ ++ d->verb |= 1 << QB_ENQUEUE_CMD_TARGET_TYPE_SHIFT; ++ d->tgtid = cpu_to_le32(qdid); ++ d->qdbin = cpu_to_le16(qd_bin); ++ d->qpri = qd_prio; ++} ++ ++#define EQAR_IDX(eqar) ((eqar) & 0x7) ++#define EQAR_VB(eqar) ((eqar) & 0x80) ++#define EQAR_SUCCESS(eqar) ((eqar) & 0x100) ++ ++/** ++ * qbman_swp_enqueue() - Issue an enqueue command ++ * @s: the software portal used for enqueue ++ * @d: the enqueue descriptor ++ * @fd: the frame descriptor to be enqueued ++ * ++ * Please note that 'fd' should only be NULL if the "action" of the ++ * descriptor is "orp_hole" or "orp_nesn". ++ * ++ * Return 0 for successful enqueue, -EBUSY if the EQCR is not ready. ++ */ ++int qbman_swp_enqueue(struct qbman_swp *s, const struct qbman_eq_desc *d, ++ const struct dpaa2_fd *fd) ++{ ++ struct qbman_eq_desc *p; ++ u32 eqar = qbman_read_register(s, QBMAN_CINH_SWP_EQAR); ++ ++ if (!EQAR_SUCCESS(eqar)) ++ return -EBUSY; ++ ++ p = qbman_get_cmd(s, QBMAN_CENA_SWP_EQCR(EQAR_IDX(eqar))); ++ memcpy(&p->dca, &d->dca, 31); ++ memcpy(&p->fd, fd, sizeof(*fd)); ++ ++ /* Set the verb byte, have to substitute in the valid-bit */ ++ dma_wmb(); ++ p->verb = d->verb | EQAR_VB(eqar); ++ dccvac(p); ++ ++ return 0; ++} ++ ++/* Static (push) dequeue */ ++ ++/** ++ * qbman_swp_push_get() - Get the push dequeue setup ++ * @p: the software portal object ++ * @channel_idx: the channel index to query ++ * @enabled: returned boolean to show whether the push dequeue is enabled ++ * for the given channel ++ */ ++void qbman_swp_push_get(struct qbman_swp *s, u8 channel_idx, int *enabled) ++{ ++ u16 src = (s->sdq >> QB_SDQCR_SRC_SHIFT) & QB_SDQCR_SRC_MASK; ++ ++ WARN_ON(channel_idx > 15); ++ *enabled = src | (1 << channel_idx); ++} ++ ++/** ++ * qbman_swp_push_set() - Enable or disable push dequeue ++ * @p: the software portal object ++ * @channel_idx: the channel index (0 to 15) ++ * @enable: enable or disable push dequeue ++ */ ++void qbman_swp_push_set(struct qbman_swp *s, u8 channel_idx, int enable) ++{ ++ u16 dqsrc; ++ ++ WARN_ON(channel_idx > 15); ++ if (enable) ++ s->sdq |= 1 << channel_idx; ++ else ++ s->sdq &= ~(1 << channel_idx); ++ ++ /* Read make the complete src map. If no channels are enabled ++ * the SDQCR must be 0 or else QMan will assert errors ++ */ ++ dqsrc = (s->sdq >> QB_SDQCR_SRC_SHIFT) & QB_SDQCR_SRC_MASK; ++ if (dqsrc != 0) ++ qbman_write_register(s, QBMAN_CINH_SWP_SDQCR, s->sdq); ++ else ++ qbman_write_register(s, QBMAN_CINH_SWP_SDQCR, 0); ++} ++ ++#define QB_VDQCR_VERB_DCT_SHIFT 0 ++#define QB_VDQCR_VERB_DT_SHIFT 2 ++#define QB_VDQCR_VERB_RLS_SHIFT 4 ++#define QB_VDQCR_VERB_WAE_SHIFT 5 ++ ++enum qb_pull_dt_e { ++ qb_pull_dt_channel, ++ qb_pull_dt_workqueue, ++ qb_pull_dt_framequeue ++}; ++ ++/** ++ * qbman_pull_desc_clear() - Clear the contents of a descriptor to ++ * default/starting state ++ * @d: the pull dequeue descriptor to be cleared ++ */ ++void qbman_pull_desc_clear(struct qbman_pull_desc *d) ++{ ++ memset(d, 0, sizeof(*d)); ++} ++ ++/** ++ * qbman_pull_desc_set_storage()- Set the pull dequeue storage ++ * @d: the pull dequeue descriptor to be set ++ * @storage: the pointer of the memory to store the dequeue result ++ * @storage_phys: the physical address of the storage memory ++ * @stash: to indicate whether write allocate is enabled ++ * ++ * If not called, or if called with 'storage' as NULL, the result pull dequeues ++ * will produce results to DQRR. If 'storage' is non-NULL, then results are ++ * produced to the given memory location (using the DMA address which ++ * the caller provides in 'storage_phys'), and 'stash' controls whether or not ++ * those writes to main-memory express a cache-warming attribute. ++ */ ++void qbman_pull_desc_set_storage(struct qbman_pull_desc *d, ++ struct dpaa2_dq *storage, ++ dma_addr_t storage_phys, ++ int stash) ++{ ++ /* save the virtual address */ ++ d->rsp_addr_virt = (u64)storage; ++ ++ if (!storage) { ++ d->verb &= ~(1 << QB_VDQCR_VERB_RLS_SHIFT); ++ return; ++ } ++ d->verb |= 1 << QB_VDQCR_VERB_RLS_SHIFT; ++ if (stash) ++ d->verb |= 1 << QB_VDQCR_VERB_WAE_SHIFT; ++ else ++ d->verb &= ~(1 << QB_VDQCR_VERB_WAE_SHIFT); ++ ++ d->rsp_addr = cpu_to_le64(storage_phys); ++} ++ ++/** ++ * qbman_pull_desc_set_numframes() - Set the number of frames to be dequeued ++ * @d: the pull dequeue descriptor to be set ++ * @numframes: number of frames to be set, must be between 1 and 16, inclusive ++ */ ++void qbman_pull_desc_set_numframes(struct qbman_pull_desc *d, u8 numframes) ++{ ++ d->numf = numframes - 1; ++} ++ ++void qbman_pull_desc_set_token(struct qbman_pull_desc *d, u8 token) ++{ ++ d->tok = token; ++} ++ ++/* ++ * Exactly one of the following descriptor "actions" should be set. (Calling any ++ * one of these will replace the effect of any prior call to one of these.) ++ * - pull dequeue from the given frame queue (FQ) ++ * - pull dequeue from any FQ in the given work queue (WQ) ++ * - pull dequeue from any FQ in any WQ in the given channel ++ */ ++ ++/** ++ * qbman_pull_desc_set_fq() - Set fqid from which the dequeue command dequeues ++ * @fqid: the frame queue index of the given FQ ++ */ ++void qbman_pull_desc_set_fq(struct qbman_pull_desc *d, u32 fqid) ++{ ++ d->verb |= 1 << QB_VDQCR_VERB_DCT_SHIFT; ++ d->verb |= qb_pull_dt_framequeue << QB_VDQCR_VERB_DT_SHIFT; ++ d->dq_src = cpu_to_le32(fqid); ++} ++ ++/** ++ * qbman_pull_desc_set_wq() - Set wqid from which the dequeue command dequeues ++ * @wqid: composed of channel id and wqid within the channel ++ * @dct: the dequeue command type ++ */ ++void qbman_pull_desc_set_wq(struct qbman_pull_desc *d, u32 wqid, ++ enum qbman_pull_type_e dct) ++{ ++ d->verb |= dct << QB_VDQCR_VERB_DCT_SHIFT; ++ d->verb |= qb_pull_dt_workqueue << QB_VDQCR_VERB_DT_SHIFT; ++ d->dq_src = cpu_to_le32(wqid); ++} ++ ++/** ++ * qbman_pull_desc_set_channel() - Set channelid from which the dequeue command ++ * dequeues ++ * @chid: the channel id to be dequeued ++ * @dct: the dequeue command type ++ */ ++void qbman_pull_desc_set_channel(struct qbman_pull_desc *d, u32 chid, ++ enum qbman_pull_type_e dct) ++{ ++ d->verb |= dct << QB_VDQCR_VERB_DCT_SHIFT; ++ d->verb |= qb_pull_dt_channel << QB_VDQCR_VERB_DT_SHIFT; ++ d->dq_src = cpu_to_le32(chid); ++} ++ ++/** ++ * qbman_swp_pull() - Issue the pull dequeue command ++ * @s: the software portal object ++ * @d: the software portal descriptor which has been configured with ++ * the set of qbman_pull_desc_set_*() calls ++ * ++ * Return 0 for success, and -EBUSY if the software portal is not ready ++ * to do pull dequeue. ++ */ ++int qbman_swp_pull(struct qbman_swp *s, struct qbman_pull_desc *d) ++{ ++ struct qbman_pull_desc *p; ++ ++ if (!atomic_dec_and_test(&s->vdq.available)) { ++ atomic_inc(&s->vdq.available); ++ return -EBUSY; ++ } ++ s->vdq.storage = (void *)d->rsp_addr_virt; ++ p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR); ++ p->numf = d->numf; ++ p->tok = QMAN_DQ_TOKEN_VALID; ++ p->dq_src = d->dq_src; ++ p->rsp_addr = d->rsp_addr; ++ p->rsp_addr_virt = d->rsp_addr_virt; ++ dma_wmb(); ++ ++ /* Set the verb byte, have to substitute in the valid-bit */ ++ p->verb = d->verb | s->vdq.valid_bit; ++ s->vdq.valid_bit ^= QB_VALID_BIT; ++ dccvac(p); ++ ++ return 0; ++} ++ ++#define QMAN_DQRR_PI_MASK 0xf ++ ++/** ++ * qbman_swp_dqrr_next() - Get an valid DQRR entry ++ * @s: the software portal object ++ * ++ * Return NULL if there are no unconsumed DQRR entries. Return a DQRR entry ++ * only once, so repeated calls can return a sequence of DQRR entries, without ++ * requiring they be consumed immediately or in any particular order. ++ */ ++const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s) ++{ ++ u32 verb; ++ u32 response_verb; ++ u32 flags; ++ struct dpaa2_dq *p; ++ ++ /* Before using valid-bit to detect if something is there, we have to ++ * handle the case of the DQRR reset bug... ++ */ ++ if (unlikely(s->dqrr.reset_bug)) { ++ /* ++ * We pick up new entries by cache-inhibited producer index, ++ * which means that a non-coherent mapping would require us to ++ * invalidate and read *only* once that PI has indicated that ++ * there's an entry here. The first trip around the DQRR ring ++ * will be much less efficient than all subsequent trips around ++ * it... ++ */ ++ u8 pi = qbman_read_register(s, QBMAN_CINH_SWP_DQPI) & ++ QMAN_DQRR_PI_MASK; ++ ++ /* there are new entries if pi != next_idx */ ++ if (pi == s->dqrr.next_idx) ++ return NULL; ++ ++ /* ++ * if next_idx is/was the last ring index, and 'pi' is ++ * different, we can disable the workaround as all the ring ++ * entries have now been DMA'd to so valid-bit checking is ++ * repaired. Note: this logic needs to be based on next_idx ++ * (which increments one at a time), rather than on pi (which ++ * can burst and wrap-around between our snapshots of it). ++ */ ++ if (s->dqrr.next_idx == (s->dqrr.dqrr_size - 1)) { ++ pr_debug("next_idx=%d, pi=%d, clear reset bug\n", ++ s->dqrr.next_idx, pi); ++ s->dqrr.reset_bug = 0; ++ } ++ qbman_inval_prefetch(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)); ++ } ++ ++ p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)); ++ verb = p->dq.verb; ++ ++ /* ++ * If the valid-bit isn't of the expected polarity, nothing there. Note, ++ * in the DQRR reset bug workaround, we shouldn't need to skip these ++ * check, because we've already determined that a new entry is available ++ * and we've invalidated the cacheline before reading it, so the ++ * valid-bit behaviour is repaired and should tell us what we already ++ * knew from reading PI. ++ */ ++ if ((verb & QB_VALID_BIT) != s->dqrr.valid_bit) { ++ qbman_inval_prefetch(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)); ++ return NULL; ++ } ++ /* ++ * There's something there. Move "next_idx" attention to the next ring ++ * entry (and prefetch it) before returning what we found. ++ */ ++ s->dqrr.next_idx++; ++ s->dqrr.next_idx &= s->dqrr.dqrr_size - 1; /* Wrap around */ ++ if (!s->dqrr.next_idx) ++ s->dqrr.valid_bit ^= QB_VALID_BIT; ++ ++ /* ++ * If this is the final response to a volatile dequeue command ++ * indicate that the vdq is available ++ */ ++ flags = p->dq.stat; ++ response_verb = verb & QBMAN_RESULT_MASK; ++ if ((response_verb == QBMAN_RESULT_DQ) && ++ (flags & DPAA2_DQ_STAT_VOLATILE) && ++ (flags & DPAA2_DQ_STAT_EXPIRED)) ++ atomic_inc(&s->vdq.available); ++ ++ qbman_inval_prefetch(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)); ++ ++ return p; ++} ++ ++/** ++ * qbman_swp_dqrr_consume() - Consume DQRR entries previously returned from ++ * qbman_swp_dqrr_next(). ++ * @s: the software portal object ++ * @dq: the DQRR entry to be consumed ++ */ ++void qbman_swp_dqrr_consume(struct qbman_swp *s, const struct dpaa2_dq *dq) ++{ ++ qbman_write_register(s, QBMAN_CINH_SWP_DCAP, QBMAN_IDX_FROM_DQRR(dq)); ++} ++ ++/** ++ * qbman_result_has_new_result() - Check and get the dequeue response from the ++ * dq storage memory set in pull dequeue command ++ * @s: the software portal object ++ * @dq: the dequeue result read from the memory ++ * ++ * Return 1 for getting a valid dequeue result, or 0 for not getting a valid ++ * dequeue result. ++ * ++ * Only used for user-provided storage of dequeue results, not DQRR. For ++ * efficiency purposes, the driver will perform any required endianness ++ * conversion to ensure that the user's dequeue result storage is in host-endian ++ * format. As such, once the user has called qbman_result_has_new_result() and ++ * been returned a valid dequeue result, they should not call it again on ++ * the same memory location (except of course if another dequeue command has ++ * been executed to produce a new result to that location). ++ */ ++int qbman_result_has_new_result(struct qbman_swp *s, const struct dpaa2_dq *dq) ++{ ++ if (dq->dq.tok != QMAN_DQ_TOKEN_VALID) ++ return 0; ++ ++ /* ++ * Set token to be 0 so we will detect change back to 1 ++ * next time the looping is traversed. Const is cast away here ++ * as we want users to treat the dequeue responses as read only. ++ */ ++ ((struct dpaa2_dq *)dq)->dq.tok = 0; ++ ++ /* ++ * Determine whether VDQCR is available based on whether the ++ * current result is sitting in the first storage location of ++ * the busy command. ++ */ ++ if (s->vdq.storage == dq) { ++ s->vdq.storage = NULL; ++ atomic_inc(&s->vdq.available); ++ } ++ ++ return 1; ++} ++ ++/** ++ * qbman_release_desc_clear() - Clear the contents of a descriptor to ++ * default/starting state. ++ */ ++void qbman_release_desc_clear(struct qbman_release_desc *d) ++{ ++ memset(d, 0, sizeof(*d)); ++ d->verb = 1 << 5; /* Release Command Valid */ ++} ++ ++/** ++ * qbman_release_desc_set_bpid() - Set the ID of the buffer pool to release to ++ */ ++void qbman_release_desc_set_bpid(struct qbman_release_desc *d, u16 bpid) ++{ ++ d->bpid = cpu_to_le16(bpid); ++} ++ ++/** ++ * qbman_release_desc_set_rcdi() - Determines whether or not the portal's RCDI ++ * interrupt source should be asserted after the release command is completed. ++ */ ++void qbman_release_desc_set_rcdi(struct qbman_release_desc *d, int enable) ++{ ++ if (enable) ++ d->verb |= 1 << 6; ++ else ++ d->verb &= ~(1 << 6); ++} ++ ++#define RAR_IDX(rar) ((rar) & 0x7) ++#define RAR_VB(rar) ((rar) & 0x80) ++#define RAR_SUCCESS(rar) ((rar) & 0x100) ++ ++/** ++ * qbman_swp_release() - Issue a buffer release command ++ * @s: the software portal object ++ * @d: the release descriptor ++ * @buffers: a pointer pointing to the buffer address to be released ++ * @num_buffers: number of buffers to be released, must be less than 8 ++ * ++ * Return 0 for success, -EBUSY if the release command ring is not ready. ++ */ ++int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d, ++ const u64 *buffers, unsigned int num_buffers) ++{ ++ int i; ++ struct qbman_release_desc *p; ++ u32 rar; ++ ++ if (!num_buffers || (num_buffers > 7)) ++ return -EINVAL; ++ ++ rar = qbman_read_register(s, QBMAN_CINH_SWP_RAR); ++ if (!RAR_SUCCESS(rar)) ++ return -EBUSY; ++ ++ /* Start the release command */ ++ p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR(RAR_IDX(rar))); ++ /* Copy the caller's buffer pointers to the command */ ++ for (i = 0; i < num_buffers; i++) ++ p->buf[i] = cpu_to_le64(buffers[i]); ++ p->bpid = d->bpid; ++ ++ /* ++ * Set the verb byte, have to substitute in the valid-bit and the number ++ * of buffers. ++ */ ++ dma_wmb(); ++ p->verb = d->verb | RAR_VB(rar) | num_buffers; ++ dccvac(p); ++ ++ return 0; ++} ++ ++struct qbman_acquire_desc { ++ u8 verb; ++ u8 reserved; ++ u16 bpid; ++ u8 num; ++ u8 reserved2[59]; ++}; ++ ++struct qbman_acquire_rslt { ++ u8 verb; ++ u8 rslt; ++ u16 reserved; ++ u8 num; ++ u8 reserved2[3]; ++ u64 buf[7]; ++}; ++ ++/** ++ * qbman_swp_acquire() - Issue a buffer acquire command ++ * @s: the software portal object ++ * @bpid: the buffer pool index ++ * @buffers: a pointer pointing to the acquired buffer addresses ++ * @num_buffers: number of buffers to be acquired, must be less than 8 ++ * ++ * Return 0 for success, or negative error code if the acquire command ++ * fails. ++ */ ++int qbman_swp_acquire(struct qbman_swp *s, u16 bpid, u64 *buffers, ++ unsigned int num_buffers) ++{ ++ struct qbman_acquire_desc *p; ++ struct qbman_acquire_rslt *r; ++ int i; ++ ++ if (!num_buffers || (num_buffers > 7)) ++ return -EINVAL; ++ ++ /* Start the management command */ ++ p = qbman_swp_mc_start(s); ++ ++ if (!p) ++ return -EBUSY; ++ ++ /* Encode the caller-provided attributes */ ++ p->bpid = cpu_to_le16(bpid); ++ p->num = num_buffers; ++ ++ /* Complete the management command */ ++ r = qbman_swp_mc_complete(s, p, QBMAN_MC_ACQUIRE); ++ if (unlikely(!r)) { ++ pr_err("qbman: acquire from BPID %d failed, no response\n", ++ bpid); ++ return -EIO; ++ } ++ ++ /* Decode the outcome */ ++ WARN_ON((r->verb & 0x7f) != QBMAN_MC_ACQUIRE); ++ ++ /* Determine success or failure */ ++ if (unlikely(r->rslt != QBMAN_MC_RSLT_OK)) { ++ pr_err("qbman: acquire from BPID 0x%x failed, code=0x%02x\n", ++ bpid, r->rslt); ++ return -EIO; ++ } ++ ++ WARN_ON(r->num > num_buffers); ++ ++ /* Copy the acquired buffers to the caller's array */ ++ for (i = 0; i < r->num; i++) ++ buffers[i] = le64_to_cpu(r->buf[i]); ++ ++ return (int)r->num; ++} ++ ++struct qbman_alt_fq_state_desc { ++ u8 verb; ++ u8 reserved[3]; ++ u32 fqid; ++ u8 reserved2[56]; ++}; ++ ++struct qbman_alt_fq_state_rslt { ++ u8 verb; ++ u8 rslt; ++ u8 reserved[62]; ++}; ++ ++#define ALT_FQ_FQID_MASK 0x00FFFFFF ++ ++int qbman_swp_alt_fq_state(struct qbman_swp *s, u32 fqid, ++ u8 alt_fq_verb) ++{ ++ struct qbman_alt_fq_state_desc *p; ++ struct qbman_alt_fq_state_rslt *r; ++ ++ /* Start the management command */ ++ p = qbman_swp_mc_start(s); ++ if (!p) ++ return -EBUSY; ++ ++ p->fqid = cpu_to_le32(fqid) & ALT_FQ_FQID_MASK; ++ ++ /* Complete the management command */ ++ r = qbman_swp_mc_complete(s, p, alt_fq_verb); ++ if (unlikely(!r)) { ++ pr_err("qbman: mgmt cmd failed, no response (verb=0x%x)\n", ++ alt_fq_verb); ++ return -EIO; ++ } ++ ++ /* Decode the outcome */ ++ WARN_ON((r->verb & QBMAN_RESULT_MASK) != alt_fq_verb); ++ ++ /* Determine success or failure */ ++ if (unlikely(r->rslt != QBMAN_MC_RSLT_OK)) { ++ pr_err("qbman: ALT FQID %d failed: verb = 0x%08x code = 0x%02x\n", ++ fqid, r->verb, r->rslt); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++struct qbman_cdan_ctrl_desc { ++ u8 verb; ++ u8 reserved; ++ u16 ch; ++ u8 we; ++ u8 ctrl; ++ u16 reserved2; ++ u64 cdan_ctx; ++ u8 reserved3[48]; ++ ++}; ++ ++struct qbman_cdan_ctrl_rslt { ++ u8 verb; ++ u8 rslt; ++ u16 ch; ++ u8 reserved[60]; ++}; ++ ++int qbman_swp_CDAN_set(struct qbman_swp *s, u16 channelid, ++ u8 we_mask, u8 cdan_en, ++ u64 ctx) ++{ ++ struct qbman_cdan_ctrl_desc *p = NULL; ++ struct qbman_cdan_ctrl_rslt *r = NULL; ++ ++ /* Start the management command */ ++ p = qbman_swp_mc_start(s); ++ if (!p) ++ return -EBUSY; ++ ++ /* Encode the caller-provided attributes */ ++ p->ch = cpu_to_le16(channelid); ++ p->we = we_mask; ++ if (cdan_en) ++ p->ctrl = 1; ++ else ++ p->ctrl = 0; ++ p->cdan_ctx = cpu_to_le64(ctx); ++ ++ /* Complete the management command */ ++ r = qbman_swp_mc_complete(s, p, QBMAN_WQCHAN_CONFIGURE); ++ if (unlikely(!r)) { ++ pr_err("qbman: wqchan config failed, no response\n"); ++ return -EIO; ++ } ++ ++ WARN_ON((r->verb & 0x7f) != QBMAN_WQCHAN_CONFIGURE); ++ ++ /* Determine success or failure */ ++ if (unlikely(r->rslt != QBMAN_MC_RSLT_OK)) { ++ pr_err("qbman: CDAN cQID %d failed: code = 0x%02x\n", ++ channelid, r->rslt); ++ return -EIO; ++ } ++ ++ return 0; ++} +diff --git a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.h b/drivers/staging/fsl-mc/bus/dpio/qbman-portal.h +new file mode 100644 +index 00000000..4254034c +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/dpio/qbman-portal.h +@@ -0,0 +1,662 @@ ++/* ++ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. ++ * Copyright 2016 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef __FSL_QBMAN_PORTAL_H ++#define __FSL_QBMAN_PORTAL_H ++ ++#include "qbman_private.h" ++#include "../../include/dpaa2-fd.h" ++ ++struct dpaa2_dq; ++struct qbman_swp; ++ ++/* qbman software portal descriptor structure */ ++struct qbman_swp_desc { ++ void *cena_bar; /* Cache-enabled portal base address */ ++ void *cinh_bar; /* Cache-inhibited portal base address */ ++ u32 qman_version; ++}; ++ ++#define QBMAN_SWP_INTERRUPT_EQRI 0x01 ++#define QBMAN_SWP_INTERRUPT_EQDI 0x02 ++#define QBMAN_SWP_INTERRUPT_DQRI 0x04 ++#define QBMAN_SWP_INTERRUPT_RCRI 0x08 ++#define QBMAN_SWP_INTERRUPT_RCDI 0x10 ++#define QBMAN_SWP_INTERRUPT_VDCI 0x20 ++ ++/* the structure for pull dequeue descriptor */ ++struct qbman_pull_desc { ++ u8 verb; ++ u8 numf; ++ u8 tok; ++ u8 reserved; ++ u32 dq_src; ++ u64 rsp_addr; ++ u64 rsp_addr_virt; ++ u8 padding[40]; ++}; ++ ++enum qbman_pull_type_e { ++ /* dequeue with priority precedence, respect intra-class scheduling */ ++ qbman_pull_type_prio = 1, ++ /* dequeue with active FQ precedence, respect ICS */ ++ qbman_pull_type_active, ++ /* dequeue with active FQ precedence, no ICS */ ++ qbman_pull_type_active_noics ++}; ++ ++/* Definitions for parsing dequeue entries */ ++#define QBMAN_RESULT_MASK 0x7f ++#define QBMAN_RESULT_DQ 0x60 ++#define QBMAN_RESULT_FQRN 0x21 ++#define QBMAN_RESULT_FQRNI 0x22 ++#define QBMAN_RESULT_FQPN 0x24 ++#define QBMAN_RESULT_FQDAN 0x25 ++#define QBMAN_RESULT_CDAN 0x26 ++#define QBMAN_RESULT_CSCN_MEM 0x27 ++#define QBMAN_RESULT_CGCU 0x28 ++#define QBMAN_RESULT_BPSCN 0x29 ++#define QBMAN_RESULT_CSCN_WQ 0x2a ++ ++/* QBMan FQ management command codes */ ++#define QBMAN_FQ_SCHEDULE 0x48 ++#define QBMAN_FQ_FORCE 0x49 ++#define QBMAN_FQ_XON 0x4d ++#define QBMAN_FQ_XOFF 0x4e ++ ++/* structure of enqueue descriptor */ ++struct qbman_eq_desc { ++ u8 verb; ++ u8 dca; ++ u16 seqnum; ++ u16 orpid; ++ u16 reserved1; ++ u32 tgtid; ++ u32 tag; ++ u16 qdbin; ++ u8 qpri; ++ u8 reserved[3]; ++ u8 wae; ++ u8 rspid; ++ u64 rsp_addr; ++ u8 fd[32]; ++}; ++ ++/* buffer release descriptor */ ++struct qbman_release_desc { ++ u8 verb; ++ u8 reserved; ++ u16 bpid; ++ u32 reserved2; ++ u64 buf[7]; ++}; ++ ++/* Management command result codes */ ++#define QBMAN_MC_RSLT_OK 0xf0 ++ ++#define CODE_CDAN_WE_EN 0x1 ++#define CODE_CDAN_WE_CTX 0x4 ++ ++/* portal data structure */ ++struct qbman_swp { ++ const struct qbman_swp_desc *desc; ++ void __iomem *addr_cena; ++ void __iomem *addr_cinh; ++ ++ /* Management commands */ ++ struct { ++ u32 valid_bit; /* 0x00 or 0x80 */ ++ } mc; ++ ++ /* Push dequeues */ ++ u32 sdq; ++ ++ /* Volatile dequeues */ ++ struct { ++ atomic_t available; /* indicates if a command can be sent */ ++ u32 valid_bit; /* 0x00 or 0x80 */ ++ struct dpaa2_dq *storage; /* NULL if DQRR */ ++ } vdq; ++ ++ /* DQRR */ ++ struct { ++ u32 next_idx; ++ u32 valid_bit; ++ u8 dqrr_size; ++ int reset_bug; /* indicates dqrr reset workaround is needed */ ++ } dqrr; ++}; ++ ++struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d); ++void qbman_swp_finish(struct qbman_swp *p); ++u32 qbman_swp_interrupt_read_status(struct qbman_swp *p); ++void qbman_swp_interrupt_clear_status(struct qbman_swp *p, u32 mask); ++u32 qbman_swp_interrupt_get_trigger(struct qbman_swp *p); ++void qbman_swp_interrupt_set_trigger(struct qbman_swp *p, u32 mask); ++int qbman_swp_interrupt_get_inhibit(struct qbman_swp *p); ++void qbman_swp_interrupt_set_inhibit(struct qbman_swp *p, int inhibit); ++ ++void qbman_swp_push_get(struct qbman_swp *p, u8 channel_idx, int *enabled); ++void qbman_swp_push_set(struct qbman_swp *p, u8 channel_idx, int enable); ++ ++void qbman_pull_desc_clear(struct qbman_pull_desc *d); ++void qbman_pull_desc_set_storage(struct qbman_pull_desc *d, ++ struct dpaa2_dq *storage, ++ dma_addr_t storage_phys, ++ int stash); ++void qbman_pull_desc_set_numframes(struct qbman_pull_desc *d, u8 numframes); ++void qbman_pull_desc_set_fq(struct qbman_pull_desc *d, u32 fqid); ++void qbman_pull_desc_set_wq(struct qbman_pull_desc *d, u32 wqid, ++ enum qbman_pull_type_e dct); ++void qbman_pull_desc_set_channel(struct qbman_pull_desc *d, u32 chid, ++ enum qbman_pull_type_e dct); ++ ++int qbman_swp_pull(struct qbman_swp *p, struct qbman_pull_desc *d); ++ ++const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s); ++void qbman_swp_dqrr_consume(struct qbman_swp *s, const struct dpaa2_dq *dq); ++ ++int qbman_result_has_new_result(struct qbman_swp *p, const struct dpaa2_dq *dq); ++ ++void qbman_eq_desc_clear(struct qbman_eq_desc *d); ++void qbman_eq_desc_set_no_orp(struct qbman_eq_desc *d, int respond_success); ++void qbman_eq_desc_set_token(struct qbman_eq_desc *d, u8 token); ++void qbman_eq_desc_set_fq(struct qbman_eq_desc *d, u32 fqid); ++void qbman_eq_desc_set_qd(struct qbman_eq_desc *d, u32 qdid, ++ u32 qd_bin, u32 qd_prio); ++ ++int qbman_swp_enqueue(struct qbman_swp *p, const struct qbman_eq_desc *d, ++ const struct dpaa2_fd *fd); ++ ++void qbman_release_desc_clear(struct qbman_release_desc *d); ++void qbman_release_desc_set_bpid(struct qbman_release_desc *d, u16 bpid); ++void qbman_release_desc_set_rcdi(struct qbman_release_desc *d, int enable); ++ ++int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d, ++ const u64 *buffers, unsigned int num_buffers); ++int qbman_swp_acquire(struct qbman_swp *s, u16 bpid, u64 *buffers, ++ unsigned int num_buffers); ++int qbman_swp_alt_fq_state(struct qbman_swp *s, u32 fqid, ++ u8 alt_fq_verb); ++int qbman_swp_CDAN_set(struct qbman_swp *s, u16 channelid, ++ u8 we_mask, u8 cdan_en, ++ u64 ctx); ++ ++void *qbman_swp_mc_start(struct qbman_swp *p); ++void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, u8 cmd_verb); ++void *qbman_swp_mc_result(struct qbman_swp *p); ++ ++/** ++ * qbman_result_is_DQ() - check if the dequeue result is a dequeue response ++ * @dq: the dequeue result to be checked ++ * ++ * DQRR entries may contain non-dequeue results, ie. notifications ++ */ ++static inline int qbman_result_is_DQ(const struct dpaa2_dq *dq) ++{ ++ return ((dq->dq.verb & QBMAN_RESULT_MASK) == QBMAN_RESULT_DQ); ++} ++ ++/** ++ * qbman_result_is_SCN() - Check the dequeue result is notification or not ++ * @dq: the dequeue result to be checked ++ * ++ */ ++static inline int qbman_result_is_SCN(const struct dpaa2_dq *dq) ++{ ++ return !qbman_result_is_DQ(dq); ++} ++ ++/* FQ Data Availability */ ++static inline int qbman_result_is_FQDAN(const struct dpaa2_dq *dq) ++{ ++ return ((dq->dq.verb & QBMAN_RESULT_MASK) == QBMAN_RESULT_FQDAN); ++} ++ ++/* Channel Data Availability */ ++static inline int qbman_result_is_CDAN(const struct dpaa2_dq *dq) ++{ ++ return ((dq->dq.verb & QBMAN_RESULT_MASK) == QBMAN_RESULT_CDAN); ++} ++ ++/* Congestion State Change */ ++static inline int qbman_result_is_CSCN(const struct dpaa2_dq *dq) ++{ ++ return ((dq->dq.verb & QBMAN_RESULT_MASK) == QBMAN_RESULT_CSCN_WQ); ++} ++ ++/* Buffer Pool State Change */ ++static inline int qbman_result_is_BPSCN(const struct dpaa2_dq *dq) ++{ ++ return ((dq->dq.verb & QBMAN_RESULT_MASK) == QBMAN_RESULT_BPSCN); ++} ++ ++/* Congestion Group Count Update */ ++static inline int qbman_result_is_CGCU(const struct dpaa2_dq *dq) ++{ ++ return ((dq->dq.verb & QBMAN_RESULT_MASK) == QBMAN_RESULT_CGCU); ++} ++ ++/* Retirement */ ++static inline int qbman_result_is_FQRN(const struct dpaa2_dq *dq) ++{ ++ return ((dq->dq.verb & QBMAN_RESULT_MASK) == QBMAN_RESULT_FQRN); ++} ++ ++/* Retirement Immediate */ ++static inline int qbman_result_is_FQRNI(const struct dpaa2_dq *dq) ++{ ++ return ((dq->dq.verb & QBMAN_RESULT_MASK) == QBMAN_RESULT_FQRNI); ++} ++ ++ /* Park */ ++static inline int qbman_result_is_FQPN(const struct dpaa2_dq *dq) ++{ ++ return ((dq->dq.verb & QBMAN_RESULT_MASK) == QBMAN_RESULT_FQPN); ++} ++ ++/** ++ * qbman_result_SCN_state() - Get the state field in State-change notification ++ */ ++static inline u8 qbman_result_SCN_state(const struct dpaa2_dq *scn) ++{ ++ return scn->scn.state; ++} ++ ++#define SCN_RID_MASK 0x00FFFFFF ++ ++/** ++ * qbman_result_SCN_rid() - Get the resource id in State-change notification ++ */ ++static inline u32 qbman_result_SCN_rid(const struct dpaa2_dq *scn) ++{ ++ return le32_to_cpu(scn->scn.rid_tok) & SCN_RID_MASK; ++} ++ ++/** ++ * qbman_result_SCN_ctx() - Get the context data in State-change notification ++ */ ++static inline u64 qbman_result_SCN_ctx(const struct dpaa2_dq *scn) ++{ ++ return le64_to_cpu(scn->scn.ctx); ++} ++ ++/** ++ * qbman_swp_fq_schedule() - Move the fq to the scheduled state ++ * @s: the software portal object ++ * @fqid: the index of frame queue to be scheduled ++ * ++ * There are a couple of different ways that a FQ can end up parked state, ++ * This schedules it. ++ * ++ * Return 0 for success, or negative error code for failure. ++ */ ++static inline int qbman_swp_fq_schedule(struct qbman_swp *s, u32 fqid) ++{ ++ return qbman_swp_alt_fq_state(s, fqid, QBMAN_FQ_SCHEDULE); ++} ++ ++/** ++ * qbman_swp_fq_force() - Force the FQ to fully scheduled state ++ * @s: the software portal object ++ * @fqid: the index of frame queue to be forced ++ * ++ * Force eligible will force a tentatively-scheduled FQ to be fully-scheduled ++ * and thus be available for selection by any channel-dequeuing behaviour (push ++ * or pull). If the FQ is subsequently "dequeued" from the channel and is still ++ * empty at the time this happens, the resulting dq_entry will have no FD. ++ * (qbman_result_DQ_fd() will return NULL.) ++ * ++ * Return 0 for success, or negative error code for failure. ++ */ ++static inline int qbman_swp_fq_force(struct qbman_swp *s, u32 fqid) ++{ ++ return qbman_swp_alt_fq_state(s, fqid, QBMAN_FQ_FORCE); ++} ++ ++/** ++ * qbman_swp_fq_xon() - sets FQ flow-control to XON ++ * @s: the software portal object ++ * @fqid: the index of frame queue ++ * ++ * This setting doesn't affect enqueues to the FQ, just dequeues. ++ * ++ * Return 0 for success, or negative error code for failure. ++ */ ++static inline int qbman_swp_fq_xon(struct qbman_swp *s, u32 fqid) ++{ ++ return qbman_swp_alt_fq_state(s, fqid, QBMAN_FQ_XON); ++} ++ ++/** ++ * qbman_swp_fq_xoff() - sets FQ flow-control to XOFF ++ * @s: the software portal object ++ * @fqid: the index of frame queue ++ * ++ * This setting doesn't affect enqueues to the FQ, just dequeues. ++ * XOFF FQs will remain in the tenatively-scheduled state, even when ++ * non-empty, meaning they won't be selected for scheduled dequeuing. ++ * If a FQ is changed to XOFF after it had already become truly-scheduled ++ * to a channel, and a pull dequeue of that channel occurs that selects ++ * that FQ for dequeuing, then the resulting dq_entry will have no FD. ++ * (qbman_result_DQ_fd() will return NULL.) ++ * ++ * Return 0 for success, or negative error code for failure. ++ */ ++static inline int qbman_swp_fq_xoff(struct qbman_swp *s, u32 fqid) ++{ ++ return qbman_swp_alt_fq_state(s, fqid, QBMAN_FQ_XOFF); ++} ++ ++/* If the user has been allocated a channel object that is going to generate ++ * CDANs to another channel, then the qbman_swp_CDAN* functions will be ++ * necessary. ++ * ++ * CDAN-enabled channels only generate a single CDAN notification, after which ++ * they need to be reenabled before they'll generate another. The idea is ++ * that pull dequeuing will occur in reaction to the CDAN, followed by a ++ * reenable step. Each function generates a distinct command to hardware, so a ++ * combination function is provided if the user wishes to modify the "context" ++ * (which shows up in each CDAN message) each time they reenable, as a single ++ * command to hardware. ++ */ ++ ++/** ++ * qbman_swp_CDAN_set_context() - Set CDAN context ++ * @s: the software portal object ++ * @channelid: the channel index ++ * @ctx: the context to be set in CDAN ++ * ++ * Return 0 for success, or negative error code for failure. ++ */ ++static inline int qbman_swp_CDAN_set_context(struct qbman_swp *s, u16 channelid, ++ u64 ctx) ++{ ++ return qbman_swp_CDAN_set(s, channelid, ++ CODE_CDAN_WE_CTX, ++ 0, ctx); ++} ++ ++/** ++ * qbman_swp_CDAN_enable() - Enable CDAN for the channel ++ * @s: the software portal object ++ * @channelid: the index of the channel to generate CDAN ++ * ++ * Return 0 for success, or negative error code for failure. ++ */ ++static inline int qbman_swp_CDAN_enable(struct qbman_swp *s, u16 channelid) ++{ ++ return qbman_swp_CDAN_set(s, channelid, ++ CODE_CDAN_WE_EN, ++ 1, 0); ++} ++ ++/** ++ * qbman_swp_CDAN_disable() - disable CDAN for the channel ++ * @s: the software portal object ++ * @channelid: the index of the channel to generate CDAN ++ * ++ * Return 0 for success, or negative error code for failure. ++ */ ++static inline int qbman_swp_CDAN_disable(struct qbman_swp *s, u16 channelid) ++{ ++ return qbman_swp_CDAN_set(s, channelid, ++ CODE_CDAN_WE_EN, ++ 0, 0); ++} ++ ++/** ++ * qbman_swp_CDAN_set_context_enable() - Set CDAN contest and enable CDAN ++ * @s: the software portal object ++ * @channelid: the index of the channel to generate CDAN ++ * @ctx:i the context set in CDAN ++ * ++ * Return 0 for success, or negative error code for failure. ++ */ ++static inline int qbman_swp_CDAN_set_context_enable(struct qbman_swp *s, ++ u16 channelid, ++ u64 ctx) ++{ ++ return qbman_swp_CDAN_set(s, channelid, ++ CODE_CDAN_WE_EN | CODE_CDAN_WE_CTX, ++ 1, ctx); ++} ++ ++/* Wraps up submit + poll-for-result */ ++static inline void *qbman_swp_mc_complete(struct qbman_swp *swp, void *cmd, ++ u8 cmd_verb) ++{ ++ int loopvar = 1000; ++ ++ qbman_swp_mc_submit(swp, cmd, cmd_verb); ++ ++ do { ++ cmd = qbman_swp_mc_result(swp); ++ } while (!cmd && loopvar--); ++ ++ WARN_ON(!loopvar); ++ ++ return cmd; ++} ++ ++/* ------------ */ ++/* qb_attr_code */ ++/* ------------ */ ++ ++/* This struct locates a sub-field within a QBMan portal (CENA) cacheline which ++ * is either serving as a configuration command or a query result. The ++ * representation is inherently little-endian, as the indexing of the words is ++ * itself little-endian in nature and layerscape is little endian for anything ++ * that crosses a word boundary too (64-bit fields are the obvious examples). ++ */ ++struct qb_attr_code { ++ unsigned int word; /* which u32[] array member encodes the field */ ++ unsigned int lsoffset; /* encoding offset from ls-bit */ ++ unsigned int width; /* encoding width. (bool must be 1.) */ ++}; ++ ++/* Some pre-defined codes */ ++extern struct qb_attr_code code_generic_verb; ++extern struct qb_attr_code code_generic_rslt; ++ ++/* Macros to define codes */ ++#define QB_CODE(a, b, c) { a, b, c} ++#define QB_CODE_NULL \ ++ QB_CODE((unsigned int)-1, (unsigned int)-1, (unsigned int)-1) ++ ++/* Rotate a code "ms", meaning that it moves from less-significant bytes to ++ * more-significant, from less-significant words to more-significant, etc. The ++ * "ls" version does the inverse, from more-significant towards ++ * less-significant. ++ */ ++static inline void qb_attr_code_rotate_ms(struct qb_attr_code *code, ++ unsigned int bits) ++{ ++ code->lsoffset += bits; ++ while (code->lsoffset > 31) { ++ code->word++; ++ code->lsoffset -= 32; ++ } ++} ++ ++static inline void qb_attr_code_rotate_ls(struct qb_attr_code *code, ++ unsigned int bits) ++{ ++ /* Don't be fooled, this trick should work because the types are ++ * unsigned. So the case that interests the while loop (the rotate has ++ * gone too far and the word count needs to compensate for it), is ++ * manifested when lsoffset is negative. But that equates to a really ++ * large unsigned value, starting with lots of "F"s. As such, we can ++ * continue adding 32 back to it until it wraps back round above zero, ++ * to a value of 31 or less... ++ */ ++ code->lsoffset -= bits; ++ while (code->lsoffset > 31) { ++ code->word--; ++ code->lsoffset += 32; ++ } ++} ++ ++/* Implement a loop of code rotations until 'expr' evaluates to FALSE (0). */ ++#define qb_attr_code_for_ms(code, bits, expr) \ ++ for (; expr; qb_attr_code_rotate_ms(code, bits)) ++#define qb_attr_code_for_ls(code, bits, expr) \ ++ for (; expr; qb_attr_code_rotate_ls(code, bits)) ++ ++static inline void word_copy(void *d, const void *s, unsigned int cnt) ++{ ++ u32 *dd = d; ++ const u32 *ss = s; ++ ++ while (cnt--) ++ *(dd++) = *(ss++); ++} ++ ++/* ++ * Currently, the CENA support code expects each 32-bit word to be written in ++ * host order, and these are converted to hardware (little-endian) order on ++ * command submission. However, 64-bit quantities are must be written (and read) ++ * as two 32-bit words with the least-significant word first, irrespective of ++ * host endianness. ++ */ ++static inline void u64_to_le32_copy(void *d, const u64 *s, ++ unsigned int cnt) ++{ ++ u32 *dd = d; ++ const u32 *ss = (const u32 *)s; ++ ++ while (cnt--) { ++ /* ++ * TBD: the toolchain was choking on the use of 64-bit types up ++ * until recently so this works entirely with 32-bit variables. ++ * When 64-bit types become usable again, investigate better ++ * ways of doing this. ++ */ ++#if defined(__BIG_ENDIAN) ++ *(dd++) = ss[1]; ++ *(dd++) = ss[0]; ++ ss += 2; ++#else ++ *(dd++) = *(ss++); ++ *(dd++) = *(ss++); ++#endif ++ } ++} ++ ++static inline void u64_from_le32_copy(u64 *d, const void *s, ++ unsigned int cnt) ++{ ++ const u32 *ss = s; ++ u32 *dd = (u32 *)d; ++ ++ while (cnt--) { ++#if defined(__BIG_ENDIAN) ++ dd[1] = *(ss++); ++ dd[0] = *(ss++); ++ dd += 2; ++#else ++ *(dd++) = *(ss++); ++ *(dd++) = *(ss++); ++#endif ++ } ++} ++ ++/* decode a field from a cacheline */ ++static inline u32 qb_attr_code_decode(const struct qb_attr_code *code, ++ const u32 *cacheline) ++{ ++ return d32_u32(code->lsoffset, code->width, cacheline[code->word]); ++} ++ ++static inline u64 qb_attr_code_decode_64(const struct qb_attr_code *code, ++ const u64 *cacheline) ++{ ++ u64 res; ++ ++ u64_from_le32_copy(&res, &cacheline[code->word / 2], 1); ++ return res; ++} ++ ++/* encode a field to a cacheline */ ++static inline void qb_attr_code_encode(const struct qb_attr_code *code, ++ u32 *cacheline, u32 val) ++{ ++ cacheline[code->word] = ++ r32_u32(code->lsoffset, code->width, cacheline[code->word]) ++ | e32_u32(code->lsoffset, code->width, val); ++} ++ ++static inline void qb_attr_code_encode_64(const struct qb_attr_code *code, ++ u64 *cacheline, u64 val) ++{ ++ u64_to_le32_copy(&cacheline[code->word / 2], &val, 1); ++} ++ ++/* Small-width signed values (two's-complement) will decode into medium-width ++ * positives. (Eg. for an 8-bit signed field, which stores values from -128 to ++ * +127, a setting of -7 would appear to decode to the 32-bit unsigned value ++ * 249. Likewise -120 would decode as 136.) This function allows the caller to ++ * "re-sign" such fields to 32-bit signed. (Eg. -7, which was 249 with an 8-bit ++ * encoding, will become 0xfffffff9 if you cast the return value to u32). ++ */ ++static inline int32_t qb_attr_code_makesigned(const struct qb_attr_code *code, ++ u32 val) ++{ ++ WARN_ON(val >= (1 << code->width)); ++ /* If the high bit was set, it was encoding a negative */ ++ if (val >= (1 << (code->width - 1))) ++ return (int32_t)0 - (int32_t)(((u32)1 << code->width) - ++ val); ++ /* Otherwise, it was encoding a positive */ ++ return (int32_t)val; ++} ++ ++/* ---------------------- */ ++/* Descriptors/cachelines */ ++/* ---------------------- */ ++ ++/* To avoid needless dynamic allocation, the driver API often gives the caller ++ * a "descriptor" type that the caller can instantiate however they like. ++ * Ultimately though, it is just a cacheline of binary storage (or something ++ * smaller when it is known that the descriptor doesn't need all 64 bytes) for ++ * holding pre-formatted pieces of hardware commands. The performance-critical ++ * code can then copy these descriptors directly into hardware command ++ * registers more efficiently than trying to construct/format commands ++ * on-the-fly. The API user sees the descriptor as an array of 32-bit words in ++ * order for the compiler to know its size, but the internal details are not ++ * exposed. The following macro is used within the driver for converting *any* ++ * descriptor pointer to a usable array pointer. The use of a macro (instead of ++ * an inline) is necessary to work with different descriptor types and to work ++ * correctly with const and non-const inputs (and similarly-qualified outputs). ++ */ ++#define qb_cl(d) (&(d)->dont_manipulate_directly[0]) ++ ++#endif /* __FSL_QBMAN_PORTAL_H */ +diff --git a/drivers/staging/fsl-mc/bus/dpio/qbman_debug.c b/drivers/staging/fsl-mc/bus/dpio/qbman_debug.c +new file mode 100644 +index 00000000..1c77fa6a +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/dpio/qbman_debug.c +@@ -0,0 +1,853 @@ ++/* Copyright (C) 2015 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++ ++#include "../../include/dpaa2-global.h" ++#include "qbman-portal.h" ++#include "qbman_debug.h" ++ ++/* QBMan portal management command code */ ++#define QBMAN_BP_QUERY 0x32 ++#define QBMAN_FQ_QUERY 0x44 ++#define QBMAN_FQ_QUERY_NP 0x45 ++#define QBMAN_CGR_QUERY 0x51 ++#define QBMAN_WRED_QUERY 0x54 ++#define QBMAN_CGR_STAT_QUERY 0x55 ++#define QBMAN_CGR_STAT_QUERY_CLR 0x56 ++ ++enum qbman_attr_usage_e { ++ qbman_attr_usage_fq, ++ qbman_attr_usage_bpool, ++ qbman_attr_usage_cgr, ++}; ++ ++struct int_qbman_attr { ++ u32 words[32]; ++ enum qbman_attr_usage_e usage; ++}; ++ ++#define attr_type_set(a, e) \ ++{ \ ++ struct qbman_attr *__attr = a; \ ++ enum qbman_attr_usage_e __usage = e; \ ++ ((struct int_qbman_attr *)__attr)->usage = __usage; \ ++} ++ ++#define ATTR32(d) (&(d)->dont_manipulate_directly[0]) ++#define ATTR32_1(d) (&(d)->dont_manipulate_directly[16]) ++ ++static struct qb_attr_code code_bp_bpid = QB_CODE(0, 16, 16); ++static struct qb_attr_code code_bp_bdi = QB_CODE(1, 16, 1); ++static struct qb_attr_code code_bp_va = QB_CODE(1, 17, 1); ++static struct qb_attr_code code_bp_wae = QB_CODE(1, 18, 1); ++static struct qb_attr_code code_bp_swdet = QB_CODE(4, 0, 16); ++static struct qb_attr_code code_bp_swdxt = QB_CODE(4, 16, 16); ++static struct qb_attr_code code_bp_hwdet = QB_CODE(5, 0, 16); ++static struct qb_attr_code code_bp_hwdxt = QB_CODE(5, 16, 16); ++static struct qb_attr_code code_bp_swset = QB_CODE(6, 0, 16); ++static struct qb_attr_code code_bp_swsxt = QB_CODE(6, 16, 16); ++static struct qb_attr_code code_bp_vbpid = QB_CODE(7, 0, 14); ++static struct qb_attr_code code_bp_icid = QB_CODE(7, 16, 15); ++static struct qb_attr_code code_bp_pl = QB_CODE(7, 31, 1); ++static struct qb_attr_code code_bp_bpscn_addr_lo = QB_CODE(8, 0, 32); ++static struct qb_attr_code code_bp_bpscn_addr_hi = QB_CODE(9, 0, 32); ++static struct qb_attr_code code_bp_bpscn_ctx_lo = QB_CODE(10, 0, 32); ++static struct qb_attr_code code_bp_bpscn_ctx_hi = QB_CODE(11, 0, 32); ++static struct qb_attr_code code_bp_hw_targ = QB_CODE(12, 0, 16); ++static struct qb_attr_code code_bp_state = QB_CODE(1, 24, 3); ++static struct qb_attr_code code_bp_fill = QB_CODE(2, 0, 32); ++static struct qb_attr_code code_bp_hdptr = QB_CODE(3, 0, 32); ++static struct qb_attr_code code_bp_sdcnt = QB_CODE(13, 0, 8); ++static struct qb_attr_code code_bp_hdcnt = QB_CODE(13, 1, 8); ++static struct qb_attr_code code_bp_sscnt = QB_CODE(13, 2, 8); ++ ++void qbman_bp_attr_clear(struct qbman_attr *a) ++{ ++ memset(a, 0, sizeof(*a)); ++ attr_type_set(a, qbman_attr_usage_bpool); ++} ++ ++int qbman_bp_query(struct qbman_swp *s, u32 bpid, ++ struct qbman_attr *a) ++{ ++ u32 *p; ++ u32 verb, rslt; ++ u32 *attr = ATTR32(a); ++ ++ qbman_bp_attr_clear(a); ++ ++ /* Start the management command */ ++ p = qbman_swp_mc_start(s); ++ if (!p) ++ return -EBUSY; ++ ++ /* Encode the caller-provided attributes */ ++ qb_attr_code_encode(&code_bp_bpid, p, bpid); ++ ++ /* Complete the management command */ ++ p = qbman_swp_mc_complete(s, p, QBMAN_BP_QUERY); ++ ++ /* Decode the outcome */ ++ verb = qb_attr_code_decode(&code_generic_verb, p); ++ rslt = qb_attr_code_decode(&code_generic_rslt, p); ++ WARN_ON(verb != QBMAN_BP_QUERY); ++ ++ /* Determine success or failure */ ++ if (unlikely(rslt != QBMAN_MC_RSLT_OK)) { ++ pr_err("Query of BPID 0x%x failed, code=0x%02x\n", bpid, rslt); ++ return -EIO; ++ } ++ ++ /* For the query, word[0] of the result contains only the ++ * verb/rslt fields, so skip word[0]. ++ */ ++ word_copy(&attr[1], &p[1], 15); ++ return 0; ++} ++ ++void qbman_bp_attr_get_bdi(struct qbman_attr *a, int *bdi, int *va, int *wae) ++{ ++ u32 *p = ATTR32(a); ++ ++ *bdi = !!qb_attr_code_decode(&code_bp_bdi, p); ++ *va = !!qb_attr_code_decode(&code_bp_va, p); ++ *wae = !!qb_attr_code_decode(&code_bp_wae, p); ++} ++ ++static u32 qbman_bp_thresh_to_value(u32 val) ++{ ++ return (val & 0xff) << ((val & 0xf00) >> 8); ++} ++ ++void qbman_bp_attr_get_swdet(struct qbman_attr *a, u32 *swdet) ++{ ++ u32 *p = ATTR32(a); ++ ++ *swdet = qbman_bp_thresh_to_value(qb_attr_code_decode(&code_bp_swdet, ++ p)); ++} ++ ++void qbman_bp_attr_get_swdxt(struct qbman_attr *a, u32 *swdxt) ++{ ++ u32 *p = ATTR32(a); ++ ++ *swdxt = qbman_bp_thresh_to_value(qb_attr_code_decode(&code_bp_swdxt, ++ p)); ++} ++ ++void qbman_bp_attr_get_hwdet(struct qbman_attr *a, u32 *hwdet) ++{ ++ u32 *p = ATTR32(a); ++ ++ *hwdet = qbman_bp_thresh_to_value(qb_attr_code_decode(&code_bp_hwdet, ++ p)); ++} ++ ++void qbman_bp_attr_get_hwdxt(struct qbman_attr *a, u32 *hwdxt) ++{ ++ u32 *p = ATTR32(a); ++ ++ *hwdxt = qbman_bp_thresh_to_value(qb_attr_code_decode(&code_bp_hwdxt, ++ p)); ++} ++ ++void qbman_bp_attr_get_swset(struct qbman_attr *a, u32 *swset) ++{ ++ u32 *p = ATTR32(a); ++ ++ *swset = qbman_bp_thresh_to_value(qb_attr_code_decode(&code_bp_swset, ++ p)); ++} ++ ++void qbman_bp_attr_get_swsxt(struct qbman_attr *a, u32 *swsxt) ++{ ++ u32 *p = ATTR32(a); ++ ++ *swsxt = qbman_bp_thresh_to_value(qb_attr_code_decode(&code_bp_swsxt, ++ p)); ++} ++ ++void qbman_bp_attr_get_vbpid(struct qbman_attr *a, u32 *vbpid) ++{ ++ u32 *p = ATTR32(a); ++ ++ *vbpid = qb_attr_code_decode(&code_bp_vbpid, p); ++} ++ ++void qbman_bp_attr_get_icid(struct qbman_attr *a, u32 *icid, int *pl) ++{ ++ u32 *p = ATTR32(a); ++ ++ *icid = qb_attr_code_decode(&code_bp_icid, p); ++ *pl = !!qb_attr_code_decode(&code_bp_pl, p); ++} ++ ++void qbman_bp_attr_get_bpscn_addr(struct qbman_attr *a, u64 *bpscn_addr) ++{ ++ u32 *p = ATTR32(a); ++ ++ *bpscn_addr = ((u64)qb_attr_code_decode(&code_bp_bpscn_addr_hi, ++ p) << 32) | ++ (u64)qb_attr_code_decode(&code_bp_bpscn_addr_lo, ++ p); ++} ++ ++void qbman_bp_attr_get_bpscn_ctx(struct qbman_attr *a, u64 *bpscn_ctx) ++{ ++ u32 *p = ATTR32(a); ++ ++ *bpscn_ctx = ((u64)qb_attr_code_decode(&code_bp_bpscn_ctx_hi, p) ++ << 32) | ++ (u64)qb_attr_code_decode(&code_bp_bpscn_ctx_lo, ++ p); ++} ++ ++void qbman_bp_attr_get_hw_targ(struct qbman_attr *a, u32 *hw_targ) ++{ ++ u32 *p = ATTR32(a); ++ ++ *hw_targ = qb_attr_code_decode(&code_bp_hw_targ, p); ++} ++ ++int qbman_bp_info_has_free_bufs(struct qbman_attr *a) ++{ ++ u32 *p = ATTR32(a); ++ ++ return !(int)(qb_attr_code_decode(&code_bp_state, p) & 0x1); ++} ++ ++int qbman_bp_info_is_depleted(struct qbman_attr *a) ++{ ++ u32 *p = ATTR32(a); ++ ++ return (int)(qb_attr_code_decode(&code_bp_state, p) & 0x2); ++} ++ ++int qbman_bp_info_is_surplus(struct qbman_attr *a) ++{ ++ u32 *p = ATTR32(a); ++ ++ return (int)(qb_attr_code_decode(&code_bp_state, p) & 0x4); ++} ++ ++u32 qbman_bp_info_num_free_bufs(struct qbman_attr *a) ++{ ++ u32 *p = ATTR32(a); ++ ++ return qb_attr_code_decode(&code_bp_fill, p); ++} ++ ++u32 qbman_bp_info_hdptr(struct qbman_attr *a) ++{ ++ u32 *p = ATTR32(a); ++ ++ return qb_attr_code_decode(&code_bp_hdptr, p); ++} ++ ++u32 qbman_bp_info_sdcnt(struct qbman_attr *a) ++{ ++ u32 *p = ATTR32(a); ++ ++ return qb_attr_code_decode(&code_bp_sdcnt, p); ++} ++ ++u32 qbman_bp_info_hdcnt(struct qbman_attr *a) ++{ ++ u32 *p = ATTR32(a); ++ ++ return qb_attr_code_decode(&code_bp_hdcnt, p); ++} ++ ++u32 qbman_bp_info_sscnt(struct qbman_attr *a) ++{ ++ u32 *p = ATTR32(a); ++ ++ return qb_attr_code_decode(&code_bp_sscnt, p); ++} ++ ++static struct qb_attr_code code_fq_fqid = QB_CODE(1, 0, 24); ++static struct qb_attr_code code_fq_cgrid = QB_CODE(2, 16, 16); ++static struct qb_attr_code code_fq_destwq = QB_CODE(3, 0, 15); ++static struct qb_attr_code code_fq_fqctrl = QB_CODE(3, 24, 8); ++static struct qb_attr_code code_fq_icscred = QB_CODE(4, 0, 15); ++static struct qb_attr_code code_fq_tdthresh = QB_CODE(4, 16, 13); ++static struct qb_attr_code code_fq_oa_len = QB_CODE(5, 0, 12); ++static struct qb_attr_code code_fq_oa_ics = QB_CODE(5, 14, 1); ++static struct qb_attr_code code_fq_oa_cgr = QB_CODE(5, 15, 1); ++static struct qb_attr_code code_fq_mctl_bdi = QB_CODE(5, 24, 1); ++static struct qb_attr_code code_fq_mctl_ff = QB_CODE(5, 25, 1); ++static struct qb_attr_code code_fq_mctl_va = QB_CODE(5, 26, 1); ++static struct qb_attr_code code_fq_mctl_ps = QB_CODE(5, 27, 1); ++static struct qb_attr_code code_fq_ctx_lower32 = QB_CODE(6, 0, 32); ++static struct qb_attr_code code_fq_ctx_upper32 = QB_CODE(7, 0, 32); ++static struct qb_attr_code code_fq_icid = QB_CODE(8, 0, 15); ++static struct qb_attr_code code_fq_pl = QB_CODE(8, 15, 1); ++static struct qb_attr_code code_fq_vfqid = QB_CODE(9, 0, 24); ++static struct qb_attr_code code_fq_erfqid = QB_CODE(10, 0, 24); ++ ++void qbman_fq_attr_clear(struct qbman_attr *a) ++{ ++ memset(a, 0, sizeof(*a)); ++ attr_type_set(a, qbman_attr_usage_fq); ++} ++ ++/* FQ query function for programmable fields */ ++int qbman_fq_query(struct qbman_swp *s, u32 fqid, struct qbman_attr *desc) ++{ ++ u32 *p; ++ u32 verb, rslt; ++ u32 *d = ATTR32(desc); ++ ++ qbman_fq_attr_clear(desc); ++ ++ p = qbman_swp_mc_start(s); ++ if (!p) ++ return -EBUSY; ++ qb_attr_code_encode(&code_fq_fqid, p, fqid); ++ p = qbman_swp_mc_complete(s, p, QBMAN_FQ_QUERY); ++ ++ /* Decode the outcome */ ++ verb = qb_attr_code_decode(&code_generic_verb, p); ++ rslt = qb_attr_code_decode(&code_generic_rslt, p); ++ WARN_ON(verb != QBMAN_FQ_QUERY); ++ ++ /* Determine success or failure */ ++ if (unlikely(rslt != QBMAN_MC_RSLT_OK)) { ++ pr_err("Query of FQID 0x%x failed, code=0x%02x\n", ++ fqid, rslt); ++ return -EIO; ++ } ++ /* ++ * For the configure, word[0] of the command contains only the WE-mask. ++ * For the query, word[0] of the result contains only the verb/rslt ++ * fields. Skip word[0] in the latter case. ++ */ ++ word_copy(&d[1], &p[1], 15); ++ return 0; ++} ++ ++void qbman_fq_attr_get_fqctrl(struct qbman_attr *d, u32 *fqctrl) ++{ ++ u32 *p = ATTR32(d); ++ ++ *fqctrl = qb_attr_code_decode(&code_fq_fqctrl, p); ++} ++ ++void qbman_fq_attr_get_cgrid(struct qbman_attr *d, u32 *cgrid) ++{ ++ u32 *p = ATTR32(d); ++ ++ *cgrid = qb_attr_code_decode(&code_fq_cgrid, p); ++} ++ ++void qbman_fq_attr_get_destwq(struct qbman_attr *d, u32 *destwq) ++{ ++ u32 *p = ATTR32(d); ++ ++ *destwq = qb_attr_code_decode(&code_fq_destwq, p); ++} ++ ++void qbman_fq_attr_get_icscred(struct qbman_attr *d, u32 *icscred) ++{ ++ u32 *p = ATTR32(d); ++ ++ *icscred = qb_attr_code_decode(&code_fq_icscred, p); ++} ++ ++static struct qb_attr_code code_tdthresh_exp = QB_CODE(0, 0, 5); ++static struct qb_attr_code code_tdthresh_mant = QB_CODE(0, 5, 8); ++static u32 qbman_thresh_to_value(u32 val) ++{ ++ u32 m, e; ++ ++ m = qb_attr_code_decode(&code_tdthresh_mant, &val); ++ e = qb_attr_code_decode(&code_tdthresh_exp, &val); ++ return m << e; ++} ++ ++void qbman_fq_attr_get_tdthresh(struct qbman_attr *d, u32 *tdthresh) ++{ ++ u32 *p = ATTR32(d); ++ ++ *tdthresh = qbman_thresh_to_value(qb_attr_code_decode(&code_fq_tdthresh, ++ p)); ++} ++ ++void qbman_fq_attr_get_oa(struct qbman_attr *d, ++ int *oa_ics, int *oa_cgr, int32_t *oa_len) ++{ ++ u32 *p = ATTR32(d); ++ ++ *oa_ics = !!qb_attr_code_decode(&code_fq_oa_ics, p); ++ *oa_cgr = !!qb_attr_code_decode(&code_fq_oa_cgr, p); ++ *oa_len = qb_attr_code_makesigned(&code_fq_oa_len, ++ qb_attr_code_decode(&code_fq_oa_len, p)); ++} ++ ++void qbman_fq_attr_get_mctl(struct qbman_attr *d, ++ int *bdi, int *ff, int *va, int *ps) ++{ ++ u32 *p = ATTR32(d); ++ ++ *bdi = !!qb_attr_code_decode(&code_fq_mctl_bdi, p); ++ *ff = !!qb_attr_code_decode(&code_fq_mctl_ff, p); ++ *va = !!qb_attr_code_decode(&code_fq_mctl_va, p); ++ *ps = !!qb_attr_code_decode(&code_fq_mctl_ps, p); ++} ++ ++void qbman_fq_attr_get_ctx(struct qbman_attr *d, u32 *hi, u32 *lo) ++{ ++ u32 *p = ATTR32(d); ++ ++ *hi = qb_attr_code_decode(&code_fq_ctx_upper32, p); ++ *lo = qb_attr_code_decode(&code_fq_ctx_lower32, p); ++} ++ ++void qbman_fq_attr_get_icid(struct qbman_attr *d, u32 *icid, int *pl) ++{ ++ u32 *p = ATTR32(d); ++ ++ *icid = qb_attr_code_decode(&code_fq_icid, p); ++ *pl = !!qb_attr_code_decode(&code_fq_pl, p); ++} ++ ++void qbman_fq_attr_get_vfqid(struct qbman_attr *d, u32 *vfqid) ++{ ++ u32 *p = ATTR32(d); ++ ++ *vfqid = qb_attr_code_decode(&code_fq_vfqid, p); ++} ++ ++void qbman_fq_attr_get_erfqid(struct qbman_attr *d, u32 *erfqid) ++{ ++ u32 *p = ATTR32(d); ++ ++ *erfqid = qb_attr_code_decode(&code_fq_erfqid, p); ++} ++ ++/* Query FQ Non-Programmalbe Fields */ ++static struct qb_attr_code code_fq_np_state = QB_CODE(0, 16, 3); ++static struct qb_attr_code code_fq_np_fe = QB_CODE(0, 19, 1); ++static struct qb_attr_code code_fq_np_x = QB_CODE(0, 20, 1); ++static struct qb_attr_code code_fq_np_r = QB_CODE(0, 21, 1); ++static struct qb_attr_code code_fq_np_oe = QB_CODE(0, 22, 1); ++static struct qb_attr_code code_fq_np_frm_cnt = QB_CODE(6, 0, 24); ++static struct qb_attr_code code_fq_np_byte_cnt = QB_CODE(7, 0, 32); ++ ++int qbman_fq_query_state(struct qbman_swp *s, u32 fqid, ++ struct qbman_attr *state) ++{ ++ u32 *p; ++ u32 verb, rslt; ++ u32 *d = ATTR32(state); ++ ++ qbman_fq_attr_clear(state); ++ ++ p = qbman_swp_mc_start(s); ++ if (!p) ++ return -EBUSY; ++ qb_attr_code_encode(&code_fq_fqid, p, fqid); ++ p = qbman_swp_mc_complete(s, p, QBMAN_FQ_QUERY_NP); ++ ++ /* Decode the outcome */ ++ verb = qb_attr_code_decode(&code_generic_verb, p); ++ rslt = qb_attr_code_decode(&code_generic_rslt, p); ++ WARN_ON(verb != QBMAN_FQ_QUERY_NP); ++ ++ /* Determine success or failure */ ++ if (unlikely(rslt != QBMAN_MC_RSLT_OK)) { ++ pr_err("Query NP fields of FQID 0x%x failed, code=0x%02x\n", ++ fqid, rslt); ++ return -EIO; ++ } ++ word_copy(&d[0], &p[0], 16); ++ return 0; ++} ++ ++u32 qbman_fq_state_schedstate(const struct qbman_attr *state) ++{ ++ const u32 *p = ATTR32(state); ++ ++ return qb_attr_code_decode(&code_fq_np_state, p); ++} ++ ++int qbman_fq_state_force_eligible(const struct qbman_attr *state) ++{ ++ const u32 *p = ATTR32(state); ++ ++ return !!qb_attr_code_decode(&code_fq_np_fe, p); ++} ++ ++int qbman_fq_state_xoff(const struct qbman_attr *state) ++{ ++ const u32 *p = ATTR32(state); ++ ++ return !!qb_attr_code_decode(&code_fq_np_x, p); ++} ++ ++int qbman_fq_state_retirement_pending(const struct qbman_attr *state) ++{ ++ const u32 *p = ATTR32(state); ++ ++ return !!qb_attr_code_decode(&code_fq_np_r, p); ++} ++ ++int qbman_fq_state_overflow_error(const struct qbman_attr *state) ++{ ++ const u32 *p = ATTR32(state); ++ ++ return !!qb_attr_code_decode(&code_fq_np_oe, p); ++} ++ ++u32 qbman_fq_state_frame_count(const struct qbman_attr *state) ++{ ++ const u32 *p = ATTR32(state); ++ ++ return qb_attr_code_decode(&code_fq_np_frm_cnt, p); ++} ++ ++u32 qbman_fq_state_byte_count(const struct qbman_attr *state) ++{ ++ const u32 *p = ATTR32(state); ++ ++ return qb_attr_code_decode(&code_fq_np_byte_cnt, p); ++} ++ ++/* Query CGR */ ++static struct qb_attr_code code_cgr_cgid = QB_CODE(0, 16, 16); ++static struct qb_attr_code code_cgr_cscn_wq_en_enter = QB_CODE(2, 0, 1); ++static struct qb_attr_code code_cgr_cscn_wq_en_exit = QB_CODE(2, 1, 1); ++static struct qb_attr_code code_cgr_cscn_wq_icd = QB_CODE(2, 2, 1); ++static struct qb_attr_code code_cgr_mode = QB_CODE(3, 16, 2); ++static struct qb_attr_code code_cgr_rej_cnt_mode = QB_CODE(3, 18, 1); ++static struct qb_attr_code code_cgr_cscn_bdi = QB_CODE(3, 19, 1); ++static struct qb_attr_code code_cgr_cscn_wr_en_enter = QB_CODE(3, 24, 1); ++static struct qb_attr_code code_cgr_cscn_wr_en_exit = QB_CODE(3, 25, 1); ++static struct qb_attr_code code_cgr_cg_wr_ae = QB_CODE(3, 26, 1); ++static struct qb_attr_code code_cgr_cscn_dcp_en = QB_CODE(3, 27, 1); ++static struct qb_attr_code code_cgr_cg_wr_va = QB_CODE(3, 28, 1); ++static struct qb_attr_code code_cgr_i_cnt_wr_en = QB_CODE(4, 0, 1); ++static struct qb_attr_code code_cgr_i_cnt_wr_bnd = QB_CODE(4, 1, 5); ++static struct qb_attr_code code_cgr_td_en = QB_CODE(4, 8, 1); ++static struct qb_attr_code code_cgr_cs_thres = QB_CODE(4, 16, 13); ++static struct qb_attr_code code_cgr_cs_thres_x = QB_CODE(5, 0, 13); ++static struct qb_attr_code code_cgr_td_thres = QB_CODE(5, 16, 13); ++static struct qb_attr_code code_cgr_cscn_tdcp = QB_CODE(6, 0, 16); ++static struct qb_attr_code code_cgr_cscn_wqid = QB_CODE(6, 16, 16); ++static struct qb_attr_code code_cgr_cscn_vcgid = QB_CODE(7, 0, 16); ++static struct qb_attr_code code_cgr_cg_icid = QB_CODE(7, 16, 15); ++static struct qb_attr_code code_cgr_cg_pl = QB_CODE(7, 31, 1); ++static struct qb_attr_code code_cgr_cg_wr_addr_lo = QB_CODE(8, 0, 32); ++static struct qb_attr_code code_cgr_cg_wr_addr_hi = QB_CODE(9, 0, 32); ++static struct qb_attr_code code_cgr_cscn_ctx_lo = QB_CODE(10, 0, 32); ++static struct qb_attr_code code_cgr_cscn_ctx_hi = QB_CODE(11, 0, 32); ++ ++void qbman_cgr_attr_clear(struct qbman_attr *a) ++{ ++ memset(a, 0, sizeof(*a)); ++ attr_type_set(a, qbman_attr_usage_cgr); ++} ++ ++int qbman_cgr_query(struct qbman_swp *s, u32 cgid, struct qbman_attr *attr) ++{ ++ u32 *p; ++ u32 verb, rslt; ++ u32 *d[2]; ++ int i; ++ u32 query_verb; ++ ++ d[0] = ATTR32(attr); ++ d[1] = ATTR32_1(attr); ++ ++ qbman_cgr_attr_clear(attr); ++ ++ for (i = 0; i < 2; i++) { ++ p = qbman_swp_mc_start(s); ++ if (!p) ++ return -EBUSY; ++ query_verb = i ? QBMAN_WRED_QUERY : QBMAN_CGR_QUERY; ++ ++ qb_attr_code_encode(&code_cgr_cgid, p, cgid); ++ p = qbman_swp_mc_complete(s, p, p[0] | query_verb); ++ ++ /* Decode the outcome */ ++ verb = qb_attr_code_decode(&code_generic_verb, p); ++ rslt = qb_attr_code_decode(&code_generic_rslt, p); ++ WARN_ON(verb != query_verb); ++ ++ /* Determine success or failure */ ++ if (unlikely(rslt != QBMAN_MC_RSLT_OK)) { ++ pr_err("Query CGID 0x%x failed,", cgid); ++ pr_err(" verb=0x%02x, code=0x%02x\n", verb, rslt); ++ return -EIO; ++ } ++ /* For the configure, word[0] of the command contains only the ++ * verb/cgid. For the query, word[0] of the result contains ++ * only the verb/rslt fields. Skip word[0] in the latter case. ++ */ ++ word_copy(&d[i][1], &p[1], 15); ++ } ++ return 0; ++} ++ ++void qbman_cgr_attr_get_ctl1(struct qbman_attr *d, int *cscn_wq_en_enter, ++ int *cscn_wq_en_exit, int *cscn_wq_icd) ++ { ++ u32 *p = ATTR32(d); ++ *cscn_wq_en_enter = !!qb_attr_code_decode(&code_cgr_cscn_wq_en_enter, ++ p); ++ *cscn_wq_en_exit = !!qb_attr_code_decode(&code_cgr_cscn_wq_en_exit, p); ++ *cscn_wq_icd = !!qb_attr_code_decode(&code_cgr_cscn_wq_icd, p); ++} ++ ++void qbman_cgr_attr_get_mode(struct qbman_attr *d, u32 *mode, ++ int *rej_cnt_mode, int *cscn_bdi) ++{ ++ u32 *p = ATTR32(d); ++ *mode = qb_attr_code_decode(&code_cgr_mode, p); ++ *rej_cnt_mode = !!qb_attr_code_decode(&code_cgr_rej_cnt_mode, p); ++ *cscn_bdi = !!qb_attr_code_decode(&code_cgr_cscn_bdi, p); ++} ++ ++void qbman_cgr_attr_get_ctl2(struct qbman_attr *d, int *cscn_wr_en_enter, ++ int *cscn_wr_en_exit, int *cg_wr_ae, ++ int *cscn_dcp_en, int *cg_wr_va) ++{ ++ u32 *p = ATTR32(d); ++ *cscn_wr_en_enter = !!qb_attr_code_decode(&code_cgr_cscn_wr_en_enter, ++ p); ++ *cscn_wr_en_exit = !!qb_attr_code_decode(&code_cgr_cscn_wr_en_exit, p); ++ *cg_wr_ae = !!qb_attr_code_decode(&code_cgr_cg_wr_ae, p); ++ *cscn_dcp_en = !!qb_attr_code_decode(&code_cgr_cscn_dcp_en, p); ++ *cg_wr_va = !!qb_attr_code_decode(&code_cgr_cg_wr_va, p); ++} ++ ++void qbman_cgr_attr_get_iwc(struct qbman_attr *d, int *i_cnt_wr_en, ++ u32 *i_cnt_wr_bnd) ++{ ++ u32 *p = ATTR32(d); ++ *i_cnt_wr_en = !!qb_attr_code_decode(&code_cgr_i_cnt_wr_en, p); ++ *i_cnt_wr_bnd = qb_attr_code_decode(&code_cgr_i_cnt_wr_bnd, p); ++} ++ ++void qbman_cgr_attr_get_tdc(struct qbman_attr *d, int *td_en) ++{ ++ u32 *p = ATTR32(d); ++ *td_en = !!qb_attr_code_decode(&code_cgr_td_en, p); ++} ++ ++void qbman_cgr_attr_get_cs_thres(struct qbman_attr *d, u32 *cs_thres) ++{ ++ u32 *p = ATTR32(d); ++ *cs_thres = qbman_thresh_to_value(qb_attr_code_decode( ++ &code_cgr_cs_thres, p)); ++} ++ ++void qbman_cgr_attr_get_cs_thres_x(struct qbman_attr *d, ++ u32 *cs_thres_x) ++{ ++ u32 *p = ATTR32(d); ++ *cs_thres_x = qbman_thresh_to_value(qb_attr_code_decode( ++ &code_cgr_cs_thres_x, p)); ++} ++ ++void qbman_cgr_attr_get_td_thres(struct qbman_attr *d, u32 *td_thres) ++{ ++ u32 *p = ATTR32(d); ++ *td_thres = qbman_thresh_to_value(qb_attr_code_decode( ++ &code_cgr_td_thres, p)); ++} ++ ++void qbman_cgr_attr_get_cscn_tdcp(struct qbman_attr *d, u32 *cscn_tdcp) ++{ ++ u32 *p = ATTR32(d); ++ *cscn_tdcp = qb_attr_code_decode(&code_cgr_cscn_tdcp, p); ++} ++ ++void qbman_cgr_attr_get_cscn_wqid(struct qbman_attr *d, u32 *cscn_wqid) ++{ ++ u32 *p = ATTR32(d); ++ *cscn_wqid = qb_attr_code_decode(&code_cgr_cscn_wqid, p); ++} ++ ++void qbman_cgr_attr_get_cscn_vcgid(struct qbman_attr *d, ++ u32 *cscn_vcgid) ++{ ++ u32 *p = ATTR32(d); ++ *cscn_vcgid = qb_attr_code_decode(&code_cgr_cscn_vcgid, p); ++} ++ ++void qbman_cgr_attr_get_cg_icid(struct qbman_attr *d, u32 *icid, ++ int *pl) ++{ ++ u32 *p = ATTR32(d); ++ *icid = qb_attr_code_decode(&code_cgr_cg_icid, p); ++ *pl = !!qb_attr_code_decode(&code_cgr_cg_pl, p); ++} ++ ++void qbman_cgr_attr_get_cg_wr_addr(struct qbman_attr *d, ++ u64 *cg_wr_addr) ++{ ++ u32 *p = ATTR32(d); ++ *cg_wr_addr = ((u64)qb_attr_code_decode(&code_cgr_cg_wr_addr_hi, ++ p) << 32) | ++ (u64)qb_attr_code_decode(&code_cgr_cg_wr_addr_lo, ++ p); ++} ++ ++void qbman_cgr_attr_get_cscn_ctx(struct qbman_attr *d, u64 *cscn_ctx) ++{ ++ u32 *p = ATTR32(d); ++ *cscn_ctx = ((u64)qb_attr_code_decode(&code_cgr_cscn_ctx_hi, p) ++ << 32) | ++ (u64)qb_attr_code_decode(&code_cgr_cscn_ctx_lo, p); ++} ++ ++#define WRED_EDP_WORD(n) (18 + (n) / 4) ++#define WRED_EDP_OFFSET(n) (8 * ((n) % 4)) ++#define WRED_PARM_DP_WORD(n) ((n) + 20) ++#define WRED_WE_EDP(n) (16 + (n) * 2) ++#define WRED_WE_PARM_DP(n) (17 + (n) * 2) ++void qbman_cgr_attr_wred_get_edp(struct qbman_attr *d, u32 idx, ++ int *edp) ++{ ++ u32 *p = ATTR32(d); ++ struct qb_attr_code code_wred_edp = QB_CODE(WRED_EDP_WORD(idx), ++ WRED_EDP_OFFSET(idx), 8); ++ *edp = (int)qb_attr_code_decode(&code_wred_edp, p); ++} ++ ++void qbman_cgr_attr_wred_dp_decompose(u32 dp, u64 *minth, ++ u64 *maxth, u8 *maxp) ++{ ++ u8 ma, mn, step_i, step_s, pn; ++ ++ ma = (u8)(dp >> 24); ++ mn = (u8)(dp >> 19) & 0x1f; ++ step_i = (u8)(dp >> 11); ++ step_s = (u8)(dp >> 6) & 0x1f; ++ pn = (u8)dp & 0x3f; ++ ++ *maxp = ((pn << 2) * 100) / 256; ++ ++ if (mn == 0) ++ *maxth = ma; ++ else ++ *maxth = ((ma + 256) * (1 << (mn - 1))); ++ ++ if (step_s == 0) ++ *minth = *maxth - step_i; ++ else ++ *minth = *maxth - (256 + step_i) * (1 << (step_s - 1)); ++} ++ ++void qbman_cgr_attr_wred_get_parm_dp(struct qbman_attr *d, u32 idx, ++ u32 *dp) ++{ ++ u32 *p = ATTR32(d); ++ struct qb_attr_code code_wred_parm_dp = QB_CODE(WRED_PARM_DP_WORD(idx), ++ 0, 8); ++ *dp = qb_attr_code_decode(&code_wred_parm_dp, p); ++} ++ ++/* Query CGR/CCGR/CQ statistics */ ++static struct qb_attr_code code_cgr_stat_ct = QB_CODE(4, 0, 32); ++static struct qb_attr_code code_cgr_stat_frame_cnt_lo = QB_CODE(4, 0, 32); ++static struct qb_attr_code code_cgr_stat_frame_cnt_hi = QB_CODE(5, 0, 8); ++static struct qb_attr_code code_cgr_stat_byte_cnt_lo = QB_CODE(6, 0, 32); ++static struct qb_attr_code code_cgr_stat_byte_cnt_hi = QB_CODE(7, 0, 16); ++static int qbman_cgr_statistics_query(struct qbman_swp *s, u32 cgid, ++ int clear, u32 command_type, ++ u64 *frame_cnt, u64 *byte_cnt) ++{ ++ u32 *p; ++ u32 verb, rslt; ++ u32 query_verb; ++ u32 hi, lo; ++ ++ p = qbman_swp_mc_start(s); ++ if (!p) ++ return -EBUSY; ++ ++ qb_attr_code_encode(&code_cgr_cgid, p, cgid); ++ if (command_type < 2) ++ qb_attr_code_encode(&code_cgr_stat_ct, p, command_type); ++ query_verb = clear ? ++ QBMAN_CGR_STAT_QUERY_CLR : QBMAN_CGR_STAT_QUERY; ++ p = qbman_swp_mc_complete(s, p, p[0] | query_verb); ++ ++ /* Decode the outcome */ ++ verb = qb_attr_code_decode(&code_generic_verb, p); ++ rslt = qb_attr_code_decode(&code_generic_rslt, p); ++ WARN_ON(verb != query_verb); ++ ++ /* Determine success or failure */ ++ if (unlikely(rslt != QBMAN_MC_RSLT_OK)) { ++ pr_err("Query statistics of CGID 0x%x failed,", cgid); ++ pr_err(" verb=0x%02x code=0x%02x\n", verb, rslt); ++ return -EIO; ++ } ++ ++ if (*frame_cnt) { ++ hi = qb_attr_code_decode(&code_cgr_stat_frame_cnt_hi, p); ++ lo = qb_attr_code_decode(&code_cgr_stat_frame_cnt_lo, p); ++ *frame_cnt = ((u64)hi << 32) | (u64)lo; ++ } ++ if (*byte_cnt) { ++ hi = qb_attr_code_decode(&code_cgr_stat_byte_cnt_hi, p); ++ lo = qb_attr_code_decode(&code_cgr_stat_byte_cnt_lo, p); ++ *byte_cnt = ((u64)hi << 32) | (u64)lo; ++ } ++ ++ return 0; ++} ++ ++int qbman_cgr_reject_statistics(struct qbman_swp *s, u32 cgid, int clear, ++ u64 *frame_cnt, u64 *byte_cnt) ++{ ++ return qbman_cgr_statistics_query(s, cgid, clear, 0xff, ++ frame_cnt, byte_cnt); ++} ++ ++int qbman_ccgr_reject_statistics(struct qbman_swp *s, u32 cgid, int clear, ++ u64 *frame_cnt, u64 *byte_cnt) ++{ ++ return qbman_cgr_statistics_query(s, cgid, clear, 1, ++ frame_cnt, byte_cnt); ++} ++ ++int qbman_cq_dequeue_statistics(struct qbman_swp *s, u32 cgid, int clear, ++ u64 *frame_cnt, u64 *byte_cnt) ++{ ++ return qbman_cgr_statistics_query(s, cgid, clear, 0, ++ frame_cnt, byte_cnt); ++} +diff --git a/drivers/staging/fsl-mc/bus/dpio/qbman_debug.h b/drivers/staging/fsl-mc/bus/dpio/qbman_debug.h +new file mode 100644 +index 00000000..0a247a49 +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/dpio/qbman_debug.h +@@ -0,0 +1,136 @@ ++/* Copyright (C) 2015 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++struct qbman_attr { ++ u32 dont_manipulate_directly[40]; ++}; ++ ++/* Buffer pool query commands */ ++int qbman_bp_query(struct qbman_swp *s, u32 bpid, ++ struct qbman_attr *a); ++void qbman_bp_attr_get_bdi(struct qbman_attr *a, int *bdi, int *va, int *wae); ++void qbman_bp_attr_get_swdet(struct qbman_attr *a, u32 *swdet); ++void qbman_bp_attr_get_swdxt(struct qbman_attr *a, u32 *swdxt); ++void qbman_bp_attr_get_hwdet(struct qbman_attr *a, u32 *hwdet); ++void qbman_bp_attr_get_hwdxt(struct qbman_attr *a, u32 *hwdxt); ++void qbman_bp_attr_get_swset(struct qbman_attr *a, u32 *swset); ++void qbman_bp_attr_get_swsxt(struct qbman_attr *a, u32 *swsxt); ++void qbman_bp_attr_get_vbpid(struct qbman_attr *a, u32 *vbpid); ++void qbman_bp_attr_get_icid(struct qbman_attr *a, u32 *icid, int *pl); ++void qbman_bp_attr_get_bpscn_addr(struct qbman_attr *a, u64 *bpscn_addr); ++void qbman_bp_attr_get_bpscn_ctx(struct qbman_attr *a, u64 *bpscn_ctx); ++void qbman_bp_attr_get_hw_targ(struct qbman_attr *a, u32 *hw_targ); ++int qbman_bp_info_has_free_bufs(struct qbman_attr *a); ++int qbman_bp_info_is_depleted(struct qbman_attr *a); ++int qbman_bp_info_is_surplus(struct qbman_attr *a); ++u32 qbman_bp_info_num_free_bufs(struct qbman_attr *a); ++u32 qbman_bp_info_hdptr(struct qbman_attr *a); ++u32 qbman_bp_info_sdcnt(struct qbman_attr *a); ++u32 qbman_bp_info_hdcnt(struct qbman_attr *a); ++u32 qbman_bp_info_sscnt(struct qbman_attr *a); ++ ++/* FQ query function for programmable fields */ ++int qbman_fq_query(struct qbman_swp *s, u32 fqid, ++ struct qbman_attr *desc); ++void qbman_fq_attr_get_fqctrl(struct qbman_attr *d, u32 *fqctrl); ++void qbman_fq_attr_get_cgrid(struct qbman_attr *d, u32 *cgrid); ++void qbman_fq_attr_get_destwq(struct qbman_attr *d, u32 *destwq); ++void qbman_fq_attr_get_icscred(struct qbman_attr *d, u32 *icscred); ++void qbman_fq_attr_get_tdthresh(struct qbman_attr *d, u32 *tdthresh); ++void qbman_fq_attr_get_oa(struct qbman_attr *d, ++ int *oa_ics, int *oa_cgr, int32_t *oa_len); ++void qbman_fq_attr_get_mctl(struct qbman_attr *d, ++ int *bdi, int *ff, int *va, int *ps); ++void qbman_fq_attr_get_ctx(struct qbman_attr *d, u32 *hi, u32 *lo); ++void qbman_fq_attr_get_icid(struct qbman_attr *d, u32 *icid, int *pl); ++void qbman_fq_attr_get_vfqid(struct qbman_attr *d, u32 *vfqid); ++void qbman_fq_attr_get_erfqid(struct qbman_attr *d, u32 *erfqid); ++ ++/* FQ query command for non-programmable fields*/ ++enum qbman_fq_schedstate_e { ++ qbman_fq_schedstate_oos = 0, ++ qbman_fq_schedstate_retired, ++ qbman_fq_schedstate_tentatively_scheduled, ++ qbman_fq_schedstate_truly_scheduled, ++ qbman_fq_schedstate_parked, ++ qbman_fq_schedstate_held_active, ++}; ++ ++int qbman_fq_query_state(struct qbman_swp *s, u32 fqid, ++ struct qbman_attr *state); ++u32 qbman_fq_state_schedstate(const struct qbman_attr *state); ++int qbman_fq_state_force_eligible(const struct qbman_attr *state); ++int qbman_fq_state_xoff(const struct qbman_attr *state); ++int qbman_fq_state_retirement_pending(const struct qbman_attr *state); ++int qbman_fq_state_overflow_error(const struct qbman_attr *state); ++u32 qbman_fq_state_frame_count(const struct qbman_attr *state); ++u32 qbman_fq_state_byte_count(const struct qbman_attr *state); ++ ++/* CGR query */ ++int qbman_cgr_query(struct qbman_swp *s, u32 cgid, ++ struct qbman_attr *attr); ++void qbman_cgr_attr_get_ctl1(struct qbman_attr *d, int *cscn_wq_en_enter, ++ int *cscn_wq_en_exit, int *cscn_wq_icd); ++void qbman_cgr_attr_get_mode(struct qbman_attr *d, u32 *mode, ++ int *rej_cnt_mode, int *cscn_bdi); ++void qbman_cgr_attr_get_ctl2(struct qbman_attr *d, int *cscn_wr_en_enter, ++ int *cscn_wr_en_exit, int *cg_wr_ae, ++ int *cscn_dcp_en, int *cg_wr_va); ++void qbman_cgr_attr_get_iwc(struct qbman_attr *d, int *i_cnt_wr_en, ++ u32 *i_cnt_wr_bnd); ++void qbman_cgr_attr_get_tdc(struct qbman_attr *d, int *td_en); ++void qbman_cgr_attr_get_cs_thres(struct qbman_attr *d, u32 *cs_thres); ++void qbman_cgr_attr_get_cs_thres_x(struct qbman_attr *d, ++ u32 *cs_thres_x); ++void qbman_cgr_attr_get_td_thres(struct qbman_attr *d, u32 *td_thres); ++void qbman_cgr_attr_get_cscn_tdcp(struct qbman_attr *d, u32 *cscn_tdcp); ++void qbman_cgr_attr_get_cscn_wqid(struct qbman_attr *d, u32 *cscn_wqid); ++void qbman_cgr_attr_get_cscn_vcgid(struct qbman_attr *d, ++ u32 *cscn_vcgid); ++void qbman_cgr_attr_get_cg_icid(struct qbman_attr *d, u32 *icid, ++ int *pl); ++void qbman_cgr_attr_get_cg_wr_addr(struct qbman_attr *d, ++ u64 *cg_wr_addr); ++void qbman_cgr_attr_get_cscn_ctx(struct qbman_attr *d, u64 *cscn_ctx); ++void qbman_cgr_attr_wred_get_edp(struct qbman_attr *d, u32 idx, ++ int *edp); ++void qbman_cgr_attr_wred_dp_decompose(u32 dp, u64 *minth, ++ u64 *maxth, u8 *maxp); ++void qbman_cgr_attr_wred_get_parm_dp(struct qbman_attr *d, u32 idx, ++ u32 *dp); ++ ++/* CGR/CCGR/CQ statistics query */ ++int qbman_cgr_reject_statistics(struct qbman_swp *s, u32 cgid, int clear, ++ u64 *frame_cnt, u64 *byte_cnt); ++int qbman_ccgr_reject_statistics(struct qbman_swp *s, u32 cgid, int clear, ++ u64 *frame_cnt, u64 *byte_cnt); ++int qbman_cq_dequeue_statistics(struct qbman_swp *s, u32 cgid, int clear, ++ u64 *frame_cnt, u64 *byte_cnt); +diff --git a/drivers/staging/fsl-mc/bus/dpio/qbman_private.h b/drivers/staging/fsl-mc/bus/dpio/qbman_private.h +new file mode 100644 +index 00000000..98a64be2 +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/dpio/qbman_private.h +@@ -0,0 +1,171 @@ ++/* Copyright (C) 2014 Freescale Semiconductor, Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* Perform extra checking */ ++#define QBMAN_CHECKING ++ ++/* To maximise the amount of logic that is common between the Linux driver and ++ * other targets (such as the embedded MC firmware), we pivot here between the ++ * inclusion of two platform-specific headers. ++ * ++ * The first, qbman_sys_decl.h, includes any and all required system headers as ++ * well as providing any definitions for the purposes of compatibility. The ++ * second, qbman_sys.h, is where platform-specific routines go. ++ * ++ * The point of the split is that the platform-independent code (including this ++ * header) may depend on platform-specific declarations, yet other ++ * platform-specific routines may depend on platform-independent definitions. ++ */ ++ ++#define QMAN_REV_4000 0x04000000 ++#define QMAN_REV_4100 0x04010000 ++#define QMAN_REV_4101 0x04010001 ++ ++/* When things go wrong, it is a convenient trick to insert a few FOO() ++ * statements in the code to trace progress. TODO: remove this once we are ++ * hacking the code less actively. ++ */ ++#define FOO() fsl_os_print("FOO: %s:%d\n", __FILE__, __LINE__) ++ ++/* Any time there is a register interface which we poll on, this provides a ++ * "break after x iterations" scheme for it. It's handy for debugging, eg. ++ * where you don't want millions of lines of log output from a polling loop ++ * that won't, because such things tend to drown out the earlier log output ++ * that might explain what caused the problem. (NB: put ";" after each macro!) ++ * TODO: we should probably remove this once we're done sanitising the ++ * simulator... ++ */ ++#define DBG_POLL_START(loopvar) (loopvar = 1000) ++#define DBG_POLL_CHECK(loopvar) \ ++ do {if (!((loopvar)--)) WARN_ON(1); } while (0) ++ ++/* For CCSR or portal-CINH registers that contain fields at arbitrary offsets ++ * and widths, these macro-generated encode/decode/isolate/remove inlines can ++ * be used. ++ * ++ * Eg. to "d"ecode a 14-bit field out of a register (into a "u16" type), ++ * where the field is located 3 bits "up" from the least-significant bit of the ++ * register (ie. the field location within the 32-bit register corresponds to a ++ * mask of 0x0001fff8), you would do; ++ * u16 field = d32_u16(3, 14, reg_value); ++ * ++ * Or to "e"ncode a 1-bit boolean value (input type is "int", zero is FALSE, ++ * non-zero is TRUE, so must convert all non-zero inputs to 1, hence the "!!" ++ * operator) into a register at bit location 0x00080000 (19 bits "in" from the ++ * LS bit), do; ++ * reg_value |= e32_int(19, 1, !!field); ++ * ++ * If you wish to read-modify-write a register, such that you leave the 14-bit ++ * field as-is but have all other fields set to zero, then "i"solate the 14-bit ++ * value using; ++ * reg_value = i32_u16(3, 14, reg_value); ++ * ++ * Alternatively, you could "r"emove the 1-bit boolean field (setting it to ++ * zero) but leaving all other fields as-is; ++ * reg_val = r32_int(19, 1, reg_value); ++ * ++ */ ++#define MAKE_MASK32(width) (width == 32 ? 0xffffffff : \ ++ (u32)((1 << width) - 1)) ++#define DECLARE_CODEC32(t) \ ++static inline u32 e32_##t(u32 lsoffset, u32 width, t val) \ ++{ \ ++ WARN_ON(width > (sizeof(t) * 8)); \ ++ return ((u32)val & MAKE_MASK32(width)) << lsoffset; \ ++} \ ++static inline t d32_##t(u32 lsoffset, u32 width, u32 val) \ ++{ \ ++ WARN_ON(width > (sizeof(t) * 8)); \ ++ return (t)((val >> lsoffset) & MAKE_MASK32(width)); \ ++} \ ++static inline u32 i32_##t(u32 lsoffset, u32 width, \ ++ u32 val) \ ++{ \ ++ WARN_ON(width > (sizeof(t) * 8)); \ ++ return e32_##t(lsoffset, width, d32_##t(lsoffset, width, val)); \ ++} \ ++static inline u32 r32_##t(u32 lsoffset, u32 width, \ ++ u32 val) \ ++{ \ ++ WARN_ON(width > (sizeof(t) * 8)); \ ++ return ~(MAKE_MASK32(width) << lsoffset) & val; \ ++} ++DECLARE_CODEC32(u32) ++DECLARE_CODEC32(u16) ++DECLARE_CODEC32(u8) ++DECLARE_CODEC32(int) ++ ++ /*********************/ ++ /* Debugging assists */ ++ /*********************/ ++ ++static inline void __hexdump(unsigned long start, unsigned long end, ++ unsigned long p, size_t sz, ++ const unsigned char *c) ++{ ++ while (start < end) { ++ unsigned int pos = 0; ++ char buf[64]; ++ int nl = 0; ++ ++ pos += sprintf(buf + pos, "%08lx: ", start); ++ do { ++ if ((start < p) || (start >= (p + sz))) ++ pos += sprintf(buf + pos, ".."); ++ else ++ pos += sprintf(buf + pos, "%02x", *(c++)); ++ if (!(++start & 15)) { ++ buf[pos++] = '\n'; ++ nl = 1; ++ } else { ++ nl = 0; ++ if (!(start & 1)) ++ buf[pos++] = ' '; ++ if (!(start & 3)) ++ buf[pos++] = ' '; ++ } ++ } while (start & 15); ++ if (!nl) ++ buf[pos++] = '\n'; ++ buf[pos] = '\0'; ++ pr_info("%s", buf); ++ } ++} ++ ++static inline void hexdump(const void *ptr, size_t sz) ++{ ++ unsigned long p = (unsigned long)ptr; ++ unsigned long start = p & ~15ul; ++ unsigned long end = (p + sz + 15) & ~15ul; ++ const unsigned char *c = ptr; ++ ++ __hexdump(start, end, p, sz, c); ++} +diff --git a/drivers/staging/fsl-mc/bus/dpmcp-cmd.h b/drivers/staging/fsl-mc/bus/dpmcp-cmd.h +index d098a6d8..384a13d0 100644 +--- a/drivers/staging/fsl-mc/bus/dpmcp-cmd.h ++++ b/drivers/staging/fsl-mc/bus/dpmcp-cmd.h +@@ -1,4 +1,5 @@ +-/* Copyright 2013-2016 Freescale Semiconductor Inc. ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -11,7 +12,6 @@ + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * +- * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any +@@ -33,108 +33,24 @@ + #define _FSL_DPMCP_CMD_H + + /* Minimal supported DPMCP Version */ +-#define DPMCP_MIN_VER_MAJOR 3 +-#define DPMCP_MIN_VER_MINOR 0 ++#define DPMCP_MIN_VER_MAJOR 3 ++#define DPMCP_MIN_VER_MINOR 0 + +-/* Command IDs */ +-#define DPMCP_CMDID_CLOSE 0x800 +-#define DPMCP_CMDID_OPEN 0x80b +-#define DPMCP_CMDID_CREATE 0x90b +-#define DPMCP_CMDID_DESTROY 0x900 ++/* Command versioning */ ++#define DPMCP_CMD_BASE_VERSION 1 ++#define DPMCP_CMD_ID_OFFSET 4 + +-#define DPMCP_CMDID_GET_ATTR 0x004 +-#define DPMCP_CMDID_RESET 0x005 ++#define DPMCP_CMD(id) ((id << DPMCP_CMD_ID_OFFSET) | DPMCP_CMD_BASE_VERSION) ++ ++/* Command IDs */ ++#define DPMCP_CMDID_CLOSE DPMCP_CMD(0x800) ++#define DPMCP_CMDID_OPEN DPMCP_CMD(0x80b) ++#define DPMCP_CMDID_GET_API_VERSION DPMCP_CMD(0xa0b) + +-#define DPMCP_CMDID_SET_IRQ 0x010 +-#define DPMCP_CMDID_GET_IRQ 0x011 +-#define DPMCP_CMDID_SET_IRQ_ENABLE 0x012 +-#define DPMCP_CMDID_GET_IRQ_ENABLE 0x013 +-#define DPMCP_CMDID_SET_IRQ_MASK 0x014 +-#define DPMCP_CMDID_GET_IRQ_MASK 0x015 +-#define DPMCP_CMDID_GET_IRQ_STATUS 0x016 ++#define DPMCP_CMDID_RESET DPMCP_CMD(0x005) + + struct dpmcp_cmd_open { + __le32 dpmcp_id; + }; + +-struct dpmcp_cmd_create { +- __le32 portal_id; +-}; +- +-struct dpmcp_cmd_set_irq { +- /* cmd word 0 */ +- u8 irq_index; +- u8 pad[3]; +- __le32 irq_val; +- /* cmd word 1 */ +- __le64 irq_addr; +- /* cmd word 2 */ +- __le32 irq_num; +-}; +- +-struct dpmcp_cmd_get_irq { +- __le32 pad; +- u8 irq_index; +-}; +- +-struct dpmcp_rsp_get_irq { +- /* cmd word 0 */ +- __le32 irq_val; +- __le32 pad; +- /* cmd word 1 */ +- __le64 irq_paddr; +- /* cmd word 2 */ +- __le32 irq_num; +- __le32 type; +-}; +- +-#define DPMCP_ENABLE 0x1 +- +-struct dpmcp_cmd_set_irq_enable { +- u8 enable; +- u8 pad[3]; +- u8 irq_index; +-}; +- +-struct dpmcp_cmd_get_irq_enable { +- __le32 pad; +- u8 irq_index; +-}; +- +-struct dpmcp_rsp_get_irq_enable { +- u8 enabled; +-}; +- +-struct dpmcp_cmd_set_irq_mask { +- __le32 mask; +- u8 irq_index; +-}; +- +-struct dpmcp_cmd_get_irq_mask { +- __le32 pad; +- u8 irq_index; +-}; +- +-struct dpmcp_rsp_get_irq_mask { +- __le32 mask; +-}; +- +-struct dpmcp_cmd_get_irq_status { +- __le32 status; +- u8 irq_index; +-}; +- +-struct dpmcp_rsp_get_irq_status { +- __le32 status; +-}; +- +-struct dpmcp_rsp_get_attributes { +- /* response word 0 */ +- __le32 pad; +- __le32 id; +- /* response word 1 */ +- __le16 version_major; +- __le16 version_minor; +-}; +- + #endif /* _FSL_DPMCP_CMD_H */ +diff --git a/drivers/staging/fsl-mc/bus/dpmcp.c b/drivers/staging/fsl-mc/bus/dpmcp.c +index 55766f78..ad4c8b43 100644 +--- a/drivers/staging/fsl-mc/bus/dpmcp.c ++++ b/drivers/staging/fsl-mc/bus/dpmcp.c +@@ -1,4 +1,5 @@ +-/* Copyright 2013-2016 Freescale Semiconductor Inc. ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -11,7 +12,6 @@ + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * +- * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any +@@ -103,76 +103,6 @@ int dpmcp_close(struct fsl_mc_io *mc_io, + return mc_send_command(mc_io, &cmd); + } + +-/** +- * dpmcp_create() - Create the DPMCP object. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @cfg: Configuration structure +- * @token: Returned token; use in subsequent API calls +- * +- * Create the DPMCP object, allocate required resources and +- * perform required initialization. +- * +- * The object can be created either by declaring it in the +- * DPL file, or by calling this function. +- * This function returns a unique authentication token, +- * associated with the specific object ID and the specific MC +- * portal; this token must be used in all subsequent calls to +- * this specific object. For objects that are created using the +- * DPL file, call dpmcp_open function to get an authentication +- * token first. +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpmcp_create(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- const struct dpmcp_cfg *cfg, +- u16 *token) +-{ +- struct mc_command cmd = { 0 }; +- struct dpmcp_cmd_create *cmd_params; +- +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_CREATE, +- cmd_flags, 0); +- cmd_params = (struct dpmcp_cmd_create *)cmd.params; +- cmd_params->portal_id = cpu_to_le32(cfg->portal_id); +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- *token = mc_cmd_hdr_read_token(&cmd); +- +- return 0; +-} +- +-/** +- * dpmcp_destroy() - Destroy the DPMCP object and release all its resources. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPMCP object +- * +- * Return: '0' on Success; error code otherwise. +- */ +-int dpmcp_destroy(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token) +-{ +- struct mc_command cmd = { 0 }; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_DESTROY, +- cmd_flags, token); +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- + /** + * dpmcp_reset() - Reset the DPMCP, returns the object to initial state. + * @mc_io: Pointer to MC portal's I/O object +@@ -196,309 +126,33 @@ int dpmcp_reset(struct fsl_mc_io *mc_io, + } + + /** +- * dpmcp_set_irq() - Set IRQ information for the DPMCP to trigger an interrupt. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPMCP object +- * @irq_index: Identifies the interrupt index to configure +- * @irq_cfg: IRQ configuration +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpmcp_set_irq(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- struct dpmcp_irq_cfg *irq_cfg) +-{ +- struct mc_command cmd = { 0 }; +- struct dpmcp_cmd_set_irq *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_SET_IRQ, +- cmd_flags, token); +- cmd_params = (struct dpmcp_cmd_set_irq *)cmd.params; +- cmd_params->irq_index = irq_index; +- cmd_params->irq_val = cpu_to_le32(irq_cfg->val); +- cmd_params->irq_addr = cpu_to_le64(irq_cfg->paddr); +- cmd_params->irq_num = cpu_to_le32(irq_cfg->irq_num); +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** +- * dpmcp_get_irq() - Get IRQ information from the DPMCP. +- * @mc_io: Pointer to MC portal's I/O object ++ * dpmcp_get_api_version - Get Data Path Management Command Portal API version ++ * @mc_io: Pointer to Mc portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPMCP object +- * @irq_index: The interrupt index to configure +- * @type: Interrupt type: 0 represents message interrupt +- * type (both irq_addr and irq_val are valid) +- * @irq_cfg: IRQ attributes ++ * @major_ver: Major version of Data Path Management Command Portal API ++ * @minor_ver: Minor version of Data Path Management Command Portal API + * + * Return: '0' on Success; Error code otherwise. + */ +-int dpmcp_get_irq(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- int *type, +- struct dpmcp_irq_cfg *irq_cfg) ++int dpmcp_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver) + { + struct mc_command cmd = { 0 }; +- struct dpmcp_cmd_get_irq *cmd_params; +- struct dpmcp_rsp_get_irq *rsp_params; + int err; + + /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_IRQ, +- cmd_flags, token); +- cmd_params = (struct dpmcp_cmd_get_irq *)cmd.params; +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dpmcp_rsp_get_irq *)cmd.params; +- irq_cfg->val = le32_to_cpu(rsp_params->irq_val); +- irq_cfg->paddr = le64_to_cpu(rsp_params->irq_paddr); +- irq_cfg->irq_num = le32_to_cpu(rsp_params->irq_num); +- *type = le32_to_cpu(rsp_params->type); +- return 0; +-} +- +-/** +- * dpmcp_set_irq_enable() - Set overall interrupt state. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPMCP object +- * @irq_index: The interrupt index to configure +- * @en: Interrupt state - enable = 1, disable = 0 +- * +- * Allows GPP software to control when interrupts are generated. +- * Each interrupt can have up to 32 causes. The enable/disable control's the +- * overall interrupt state. if the interrupt is disabled no causes will cause +- * an interrupt. +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpmcp_set_irq_enable(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u8 en) +-{ +- struct mc_command cmd = { 0 }; +- struct dpmcp_cmd_set_irq_enable *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_SET_IRQ_ENABLE, +- cmd_flags, token); +- cmd_params = (struct dpmcp_cmd_set_irq_enable *)cmd.params; +- cmd_params->enable = en & DPMCP_ENABLE; +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** +- * dpmcp_get_irq_enable() - Get overall interrupt state +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPMCP object +- * @irq_index: The interrupt index to configure +- * @en: Returned interrupt state - enable = 1, disable = 0 +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpmcp_get_irq_enable(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u8 *en) +-{ +- struct mc_command cmd = { 0 }; +- struct dpmcp_cmd_get_irq_enable *cmd_params; +- struct dpmcp_rsp_get_irq_enable *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_IRQ_ENABLE, +- cmd_flags, token); +- cmd_params = (struct dpmcp_cmd_get_irq_enable *)cmd.params; +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dpmcp_rsp_get_irq_enable *)cmd.params; +- *en = rsp_params->enabled & DPMCP_ENABLE; +- return 0; +-} +- +-/** +- * dpmcp_set_irq_mask() - Set interrupt mask. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPMCP object +- * @irq_index: The interrupt index to configure +- * @mask: Event mask to trigger interrupt; +- * each bit: +- * 0 = ignore event +- * 1 = consider event for asserting IRQ +- * +- * Every interrupt can have up to 32 causes and the interrupt model supports +- * masking/unmasking each cause independently +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpmcp_set_irq_mask(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 mask) +-{ +- struct mc_command cmd = { 0 }; +- struct dpmcp_cmd_set_irq_mask *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_SET_IRQ_MASK, +- cmd_flags, token); +- cmd_params = (struct dpmcp_cmd_set_irq_mask *)cmd.params; +- cmd_params->mask = cpu_to_le32(mask); +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** +- * dpmcp_get_irq_mask() - Get interrupt mask. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPMCP object +- * @irq_index: The interrupt index to configure +- * @mask: Returned event mask to trigger interrupt +- * +- * Every interrupt can have up to 32 causes and the interrupt model supports +- * masking/unmasking each cause independently +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpmcp_get_irq_mask(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 *mask) +-{ +- struct mc_command cmd = { 0 }; +- struct dpmcp_cmd_get_irq_mask *cmd_params; +- struct dpmcp_rsp_get_irq_mask *rsp_params; +- +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_IRQ_MASK, +- cmd_flags, token); +- cmd_params = (struct dpmcp_cmd_get_irq_mask *)cmd.params; +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dpmcp_rsp_get_irq_mask *)cmd.params; +- *mask = le32_to_cpu(rsp_params->mask); +- +- return 0; +-} +- +-/** +- * dpmcp_get_irq_status() - Get the current status of any pending interrupts. +- * +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPMCP object +- * @irq_index: The interrupt index to configure +- * @status: Returned interrupts status - one bit per cause: +- * 0 = no interrupt pending +- * 1 = interrupt pending +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpmcp_get_irq_status(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 *status) +-{ +- struct mc_command cmd = { 0 }; +- struct dpmcp_cmd_get_irq_status *cmd_params; +- struct dpmcp_rsp_get_irq_status *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_IRQ_STATUS, +- cmd_flags, token); +- cmd_params = (struct dpmcp_cmd_get_irq_status *)cmd.params; +- cmd_params->status = cpu_to_le32(*status); +- cmd_params->irq_index = irq_index; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dpmcp_rsp_get_irq_status *)cmd.params; +- *status = le32_to_cpu(rsp_params->status); +- +- return 0; +-} +- +-/** +- * dpmcp_get_attributes - Retrieve DPMCP attributes. +- * +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPMCP object +- * @attr: Returned object's attributes +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpmcp_get_attributes(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- struct dpmcp_attr *attr) +-{ +- struct mc_command cmd = { 0 }; +- struct dpmcp_rsp_get_attributes *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_ATTR, +- cmd_flags, token); ++ cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_API_VERSION, ++ cmd_flags, 0); + +- /* send command to mc*/ ++ /* send command to mc */ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ +- rsp_params = (struct dpmcp_rsp_get_attributes *)cmd.params; +- attr->id = le32_to_cpu(rsp_params->id); +- attr->version.major = le16_to_cpu(rsp_params->version_major); +- attr->version.minor = le16_to_cpu(rsp_params->version_minor); ++ mc_cmd_read_api_version(&cmd, major_ver, minor_ver); + + return 0; + } +diff --git a/drivers/staging/fsl-mc/bus/dpmcp.h b/drivers/staging/fsl-mc/bus/dpmcp.h +index fe79d4d9..f616031e 100644 +--- a/drivers/staging/fsl-mc/bus/dpmcp.h ++++ b/drivers/staging/fsl-mc/bus/dpmcp.h +@@ -1,4 +1,5 @@ +-/* Copyright 2013-2015 Freescale Semiconductor Inc. ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -11,7 +12,6 @@ + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * +- * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any +@@ -32,128 +32,29 @@ + #ifndef __FSL_DPMCP_H + #define __FSL_DPMCP_H + +-/* Data Path Management Command Portal API ++/* ++ * Data Path Management Command Portal API + * Contains initialization APIs and runtime control APIs for DPMCP + */ + + struct fsl_mc_io; + + int dpmcp_open(struct fsl_mc_io *mc_io, +- uint32_t cmd_flags, ++ u32 cmd_flags, + int dpmcp_id, +- uint16_t *token); +- +-/* Get portal ID from pool */ +-#define DPMCP_GET_PORTAL_ID_FROM_POOL (-1) ++ u16 *token); + + int dpmcp_close(struct fsl_mc_io *mc_io, +- uint32_t cmd_flags, +- uint16_t token); +- +-/** +- * struct dpmcp_cfg - Structure representing DPMCP configuration +- * @portal_id: Portal ID; 'DPMCP_GET_PORTAL_ID_FROM_POOL' to get the portal ID +- * from pool +- */ +-struct dpmcp_cfg { +- int portal_id; +-}; +- +-int dpmcp_create(struct fsl_mc_io *mc_io, +- uint32_t cmd_flags, +- const struct dpmcp_cfg *cfg, +- uint16_t *token); ++ u32 cmd_flags, ++ u16 token); + +-int dpmcp_destroy(struct fsl_mc_io *mc_io, +- uint32_t cmd_flags, +- uint16_t token); ++int dpmcp_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver); + + int dpmcp_reset(struct fsl_mc_io *mc_io, +- uint32_t cmd_flags, +- uint16_t token); +- +-/* IRQ */ +-/* IRQ Index */ +-#define DPMCP_IRQ_INDEX 0 +-/* irq event - Indicates that the link state changed */ +-#define DPMCP_IRQ_EVENT_CMD_DONE 0x00000001 +- +-/** +- * struct dpmcp_irq_cfg - IRQ configuration +- * @paddr: Address that must be written to signal a message-based interrupt +- * @val: Value to write into irq_addr address +- * @irq_num: A user defined number associated with this IRQ +- */ +-struct dpmcp_irq_cfg { +- uint64_t paddr; +- uint32_t val; +- int irq_num; +-}; +- +-int dpmcp_set_irq(struct fsl_mc_io *mc_io, +- uint32_t cmd_flags, +- uint16_t token, +- uint8_t irq_index, +- struct dpmcp_irq_cfg *irq_cfg); +- +-int dpmcp_get_irq(struct fsl_mc_io *mc_io, +- uint32_t cmd_flags, +- uint16_t token, +- uint8_t irq_index, +- int *type, +- struct dpmcp_irq_cfg *irq_cfg); +- +-int dpmcp_set_irq_enable(struct fsl_mc_io *mc_io, +- uint32_t cmd_flags, +- uint16_t token, +- uint8_t irq_index, +- uint8_t en); +- +-int dpmcp_get_irq_enable(struct fsl_mc_io *mc_io, +- uint32_t cmd_flags, +- uint16_t token, +- uint8_t irq_index, +- uint8_t *en); +- +-int dpmcp_set_irq_mask(struct fsl_mc_io *mc_io, +- uint32_t cmd_flags, +- uint16_t token, +- uint8_t irq_index, +- uint32_t mask); +- +-int dpmcp_get_irq_mask(struct fsl_mc_io *mc_io, +- uint32_t cmd_flags, +- uint16_t token, +- uint8_t irq_index, +- uint32_t *mask); +- +-int dpmcp_get_irq_status(struct fsl_mc_io *mc_io, +- uint32_t cmd_flags, +- uint16_t token, +- uint8_t irq_index, +- uint32_t *status); +- +-/** +- * struct dpmcp_attr - Structure representing DPMCP attributes +- * @id: DPMCP object ID +- * @version: DPMCP version +- */ +-struct dpmcp_attr { +- int id; +- /** +- * struct version - Structure representing DPMCP version +- * @major: DPMCP major version +- * @minor: DPMCP minor version +- */ +- struct { +- uint16_t major; +- uint16_t minor; +- } version; +-}; +- +-int dpmcp_get_attributes(struct fsl_mc_io *mc_io, +- uint32_t cmd_flags, +- uint16_t token, +- struct dpmcp_attr *attr); ++ u32 cmd_flags, ++ u16 token); + + #endif /* __FSL_DPMCP_H */ +diff --git a/drivers/staging/fsl-mc/bus/dpmng-cmd.h b/drivers/staging/fsl-mc/bus/dpmng-cmd.h +index a7b77d58..cdddfb80 100644 +--- a/drivers/staging/fsl-mc/bus/dpmng-cmd.h ++++ b/drivers/staging/fsl-mc/bus/dpmng-cmd.h +@@ -12,7 +12,6 @@ + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * +- * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any +@@ -41,13 +40,14 @@ + #ifndef __FSL_DPMNG_CMD_H + #define __FSL_DPMNG_CMD_H + +-/* Command IDs */ +-#define DPMNG_CMDID_GET_CONT_ID 0x830 +-#define DPMNG_CMDID_GET_VERSION 0x831 ++/* Command versioning */ ++#define DPMNG_CMD_BASE_VERSION 1 ++#define DPMNG_CMD_ID_OFFSET 4 + +-struct dpmng_rsp_get_container_id { +- __le32 container_id; +-}; ++#define DPMNG_CMD(id) ((id << DPMNG_CMD_ID_OFFSET) | DPMNG_CMD_BASE_VERSION) ++ ++/* Command IDs */ ++#define DPMNG_CMDID_GET_VERSION DPMNG_CMD(0x831) + + struct dpmng_rsp_get_version { + __le32 revision; +diff --git a/drivers/staging/fsl-mc/bus/dpmng.c b/drivers/staging/fsl-mc/bus/dpmng.c +index 96b1d677..ad5d5bbe 100644 +--- a/drivers/staging/fsl-mc/bus/dpmng.c ++++ b/drivers/staging/fsl-mc/bus/dpmng.c +@@ -1,4 +1,5 @@ +-/* Copyright 2013-2016 Freescale Semiconductor Inc. ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -11,7 +12,6 @@ + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * +- * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any +@@ -72,36 +72,3 @@ int mc_get_version(struct fsl_mc_io *mc_io, + } + EXPORT_SYMBOL(mc_get_version); + +-/** +- * dpmng_get_container_id() - Get container ID associated with a given portal. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @container_id: Requested container ID +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dpmng_get_container_id(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- int *container_id) +-{ +- struct mc_command cmd = { 0 }; +- struct dpmng_rsp_get_container_id *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPMNG_CMDID_GET_CONT_ID, +- cmd_flags, +- 0); +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dpmng_rsp_get_container_id *)cmd.params; +- *container_id = le32_to_cpu(rsp_params->container_id); +- +- return 0; +-} +- +diff --git a/drivers/staging/fsl-mc/bus/dprc-cmd.h b/drivers/staging/fsl-mc/bus/dprc-cmd.h +index 009d6567..b7d8c345 100644 +--- a/drivers/staging/fsl-mc/bus/dprc-cmd.h ++++ b/drivers/staging/fsl-mc/bus/dprc-cmd.h +@@ -12,7 +12,6 @@ + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * +- * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any +@@ -42,48 +41,39 @@ + #define _FSL_DPRC_CMD_H + + /* Minimal supported DPRC Version */ +-#define DPRC_MIN_VER_MAJOR 5 ++#define DPRC_MIN_VER_MAJOR 6 + #define DPRC_MIN_VER_MINOR 0 + ++/* Command versioning */ ++#define DPRC_CMD_BASE_VERSION 1 ++#define DPRC_CMD_ID_OFFSET 4 ++ ++#define DPRC_CMD(id) ((id << DPRC_CMD_ID_OFFSET) | DPRC_CMD_BASE_VERSION) ++ + /* Command IDs */ +-#define DPRC_CMDID_CLOSE 0x800 +-#define DPRC_CMDID_OPEN 0x805 +-#define DPRC_CMDID_CREATE 0x905 +- +-#define DPRC_CMDID_GET_ATTR 0x004 +-#define DPRC_CMDID_RESET_CONT 0x005 +- +-#define DPRC_CMDID_SET_IRQ 0x010 +-#define DPRC_CMDID_GET_IRQ 0x011 +-#define DPRC_CMDID_SET_IRQ_ENABLE 0x012 +-#define DPRC_CMDID_GET_IRQ_ENABLE 0x013 +-#define DPRC_CMDID_SET_IRQ_MASK 0x014 +-#define DPRC_CMDID_GET_IRQ_MASK 0x015 +-#define DPRC_CMDID_GET_IRQ_STATUS 0x016 +-#define DPRC_CMDID_CLEAR_IRQ_STATUS 0x017 +- +-#define DPRC_CMDID_CREATE_CONT 0x151 +-#define DPRC_CMDID_DESTROY_CONT 0x152 +-#define DPRC_CMDID_SET_RES_QUOTA 0x155 +-#define DPRC_CMDID_GET_RES_QUOTA 0x156 +-#define DPRC_CMDID_ASSIGN 0x157 +-#define DPRC_CMDID_UNASSIGN 0x158 +-#define DPRC_CMDID_GET_OBJ_COUNT 0x159 +-#define DPRC_CMDID_GET_OBJ 0x15A +-#define DPRC_CMDID_GET_RES_COUNT 0x15B +-#define DPRC_CMDID_GET_RES_IDS 0x15C +-#define DPRC_CMDID_GET_OBJ_REG 0x15E +-#define DPRC_CMDID_SET_OBJ_IRQ 0x15F +-#define DPRC_CMDID_GET_OBJ_IRQ 0x160 +-#define DPRC_CMDID_SET_OBJ_LABEL 0x161 +-#define DPRC_CMDID_GET_OBJ_DESC 0x162 +- +-#define DPRC_CMDID_CONNECT 0x167 +-#define DPRC_CMDID_DISCONNECT 0x168 +-#define DPRC_CMDID_GET_POOL 0x169 +-#define DPRC_CMDID_GET_POOL_COUNT 0x16A +- +-#define DPRC_CMDID_GET_CONNECTION 0x16C ++#define DPRC_CMDID_CLOSE DPRC_CMD(0x800) ++#define DPRC_CMDID_OPEN DPRC_CMD(0x805) ++#define DPRC_CMDID_GET_API_VERSION DPRC_CMD(0xa05) ++ ++#define DPRC_CMDID_GET_ATTR DPRC_CMD(0x004) ++#define DPRC_CMDID_RESET_CONT DPRC_CMD(0x005) ++ ++#define DPRC_CMDID_SET_IRQ DPRC_CMD(0x010) ++#define DPRC_CMDID_GET_IRQ DPRC_CMD(0x011) ++#define DPRC_CMDID_SET_IRQ_ENABLE DPRC_CMD(0x012) ++#define DPRC_CMDID_GET_IRQ_ENABLE DPRC_CMD(0x013) ++#define DPRC_CMDID_SET_IRQ_MASK DPRC_CMD(0x014) ++#define DPRC_CMDID_GET_IRQ_MASK DPRC_CMD(0x015) ++#define DPRC_CMDID_GET_IRQ_STATUS DPRC_CMD(0x016) ++#define DPRC_CMDID_CLEAR_IRQ_STATUS DPRC_CMD(0x017) ++ ++#define DPRC_CMDID_GET_CONT_ID DPRC_CMD(0x830) ++#define DPRC_CMDID_GET_OBJ_COUNT DPRC_CMD(0x159) ++#define DPRC_CMDID_GET_OBJ DPRC_CMD(0x15A) ++#define DPRC_CMDID_GET_RES_COUNT DPRC_CMD(0x15B) ++#define DPRC_CMDID_GET_OBJ_REG DPRC_CMD(0x15E) ++#define DPRC_CMDID_SET_OBJ_IRQ DPRC_CMD(0x15F) ++#define DPRC_CMDID_GET_OBJ_IRQ DPRC_CMD(0x160) + + struct dprc_cmd_open { + __le32 container_id; +@@ -199,9 +189,6 @@ struct dprc_rsp_get_attributes { + /* response word 1 */ + __le32 options; + __le32 portal_id; +- /* response word 2 */ +- __le16 version_major; +- __le16 version_minor; + }; + + struct dprc_cmd_set_res_quota { +@@ -367,11 +354,16 @@ struct dprc_cmd_get_obj_region { + + struct dprc_rsp_get_obj_region { + /* response word 0 */ +- __le64 pad; ++ __le64 pad0; + /* response word 1 */ +- __le64 base_addr; ++ __le32 base_addr; ++ __le32 pad1; + /* response word 2 */ + __le32 size; ++ u8 type; ++ u8 pad2[3]; ++ /* response word 3 */ ++ __le32 flags; + }; + + struct dprc_cmd_set_obj_label { +diff --git a/drivers/staging/fsl-mc/bus/dprc-driver.c b/drivers/staging/fsl-mc/bus/dprc-driver.c +index c5ee4639..f6e6211b 100644 +--- a/drivers/staging/fsl-mc/bus/dprc-driver.c ++++ b/drivers/staging/fsl-mc/bus/dprc-driver.c +@@ -1,7 +1,7 @@ + /* + * Freescale data path resource container (DPRC) driver + * +- * Copyright (C) 2014 Freescale Semiconductor, Inc. ++ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. + * Author: German Rivera + * + * This file is licensed under the terms of the GNU General Public +@@ -160,6 +160,8 @@ static void check_plugged_state_change(struct fsl_mc_device *mc_dev, + * dprc_add_new_devices - Adds devices to the logical bus for a DPRC + * + * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object ++ * @driver_override: driver override to apply to new objects found in the ++ * DPRC, or NULL, if none. + * @obj_desc_array: array of device descriptors for child devices currently + * present in the physical DPRC. + * @num_child_objects_in_mc: number of entries in obj_desc_array +@@ -169,6 +171,7 @@ static void check_plugged_state_change(struct fsl_mc_device *mc_dev, + * in the physical DPRC. + */ + static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev, ++ const char *driver_override, + struct dprc_obj_desc *obj_desc_array, + int num_child_objects_in_mc) + { +@@ -188,11 +191,12 @@ static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev, + child_dev = fsl_mc_device_lookup(obj_desc, mc_bus_dev); + if (child_dev) { + check_plugged_state_change(child_dev, obj_desc); ++ put_device(&child_dev->dev); + continue; + } + + error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev, +- &child_dev); ++ driver_override, &child_dev); + if (error < 0) + continue; + } +@@ -202,6 +206,8 @@ static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev, + * dprc_scan_objects - Discover objects in a DPRC + * + * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object ++ * @driver_override: driver override to apply to new objects found in the ++ * DPRC, or NULL, if none. + * @total_irq_count: total number of IRQs needed by objects in the DPRC. + * + * Detects objects added and removed from a DPRC and synchronizes the +@@ -217,6 +223,7 @@ static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev, + * of the device drivers for the non-allocatable devices. + */ + int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev, ++ const char *driver_override, + unsigned int *total_irq_count) + { + int num_child_objects; +@@ -297,7 +304,7 @@ int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev, + dprc_remove_devices(mc_bus_dev, child_obj_desc_array, + num_child_objects); + +- dprc_add_new_devices(mc_bus_dev, child_obj_desc_array, ++ dprc_add_new_devices(mc_bus_dev, driver_override, child_obj_desc_array, + num_child_objects); + + if (child_obj_desc_array) +@@ -328,7 +335,7 @@ int dprc_scan_container(struct fsl_mc_device *mc_bus_dev) + * Discover objects in the DPRC: + */ + mutex_lock(&mc_bus->scan_mutex); +- error = dprc_scan_objects(mc_bus_dev, &irq_count); ++ error = dprc_scan_objects(mc_bus_dev, NULL, &irq_count); + mutex_unlock(&mc_bus->scan_mutex); + if (error < 0) + goto error; +@@ -415,7 +422,7 @@ static irqreturn_t dprc_irq0_handler_thread(int irq_num, void *arg) + DPRC_IRQ_EVENT_OBJ_CREATED)) { + unsigned int irq_count; + +- error = dprc_scan_objects(mc_dev, &irq_count); ++ error = dprc_scan_objects(mc_dev, NULL, &irq_count); + if (error < 0) { + /* + * If the error is -ENXIO, we ignore it, as it indicates +@@ -505,7 +512,7 @@ static int register_dprc_irq_handler(struct fsl_mc_device *mc_dev) + dprc_irq0_handler, + dprc_irq0_handler_thread, + IRQF_NO_SUSPEND | IRQF_ONESHOT, +- "FSL MC DPRC irq0", ++ dev_name(&mc_dev->dev), + &mc_dev->dev); + if (error < 0) { + dev_err(&mc_dev->dev, +@@ -597,6 +604,7 @@ static int dprc_probe(struct fsl_mc_device *mc_dev) + struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); + bool mc_io_created = false; + bool msi_domain_set = false; ++ u16 major_ver, minor_ver; + + if (WARN_ON(strcmp(mc_dev->obj_desc.type, "dprc") != 0)) + return -EINVAL; +@@ -669,13 +677,21 @@ static int dprc_probe(struct fsl_mc_device *mc_dev) + goto error_cleanup_open; + } + +- if (mc_bus->dprc_attr.version.major < DPRC_MIN_VER_MAJOR || +- (mc_bus->dprc_attr.version.major == DPRC_MIN_VER_MAJOR && +- mc_bus->dprc_attr.version.minor < DPRC_MIN_VER_MINOR)) { ++ error = dprc_get_api_version(mc_dev->mc_io, 0, ++ &major_ver, ++ &minor_ver); ++ if (error < 0) { ++ dev_err(&mc_dev->dev, "dprc_get_api_version() failed: %d\n", ++ error); ++ goto error_cleanup_open; ++ } ++ ++ if (major_ver < DPRC_MIN_VER_MAJOR || ++ (major_ver == DPRC_MIN_VER_MAJOR && ++ minor_ver < DPRC_MIN_VER_MINOR)) { + dev_err(&mc_dev->dev, + "ERROR: DPRC version %d.%d not supported\n", +- mc_bus->dprc_attr.version.major, +- mc_bus->dprc_attr.version.minor); ++ major_ver, minor_ver); + error = -ENOTSUPP; + goto error_cleanup_open; + } +diff --git a/drivers/staging/fsl-mc/bus/dprc.c b/drivers/staging/fsl-mc/bus/dprc.c +index 9fea3def..764cd3fb 100644 +--- a/drivers/staging/fsl-mc/bus/dprc.c ++++ b/drivers/staging/fsl-mc/bus/dprc.c +@@ -1,4 +1,5 @@ +-/* Copyright 2013-2016 Freescale Semiconductor Inc. ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -11,7 +12,6 @@ + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * +- * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any +@@ -99,93 +99,6 @@ int dprc_close(struct fsl_mc_io *mc_io, + } + EXPORT_SYMBOL(dprc_close); + +-/** +- * dprc_create_container() - Create child container +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @cfg: Child container configuration +- * @child_container_id: Returned child container ID +- * @child_portal_offset: Returned child portal offset from MC portal base +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_create_container(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- struct dprc_cfg *cfg, +- int *child_container_id, +- u64 *child_portal_offset) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_create_container *cmd_params; +- struct dprc_rsp_create_container *rsp_params; +- int err; +- +- /* prepare command */ +- cmd_params = (struct dprc_cmd_create_container *)cmd.params; +- cmd_params->options = cpu_to_le32(cfg->options); +- cmd_params->icid = cpu_to_le16(cfg->icid); +- cmd_params->portal_id = cpu_to_le32(cfg->portal_id); +- strncpy(cmd_params->label, cfg->label, 16); +- cmd_params->label[15] = '\0'; +- +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_CREATE_CONT, +- cmd_flags, token); +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dprc_rsp_create_container *)cmd.params; +- *child_container_id = le32_to_cpu(rsp_params->child_container_id); +- *child_portal_offset = le64_to_cpu(rsp_params->child_portal_addr); +- +- return 0; +-} +- +-/** +- * dprc_destroy_container() - Destroy child container. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @child_container_id: ID of the container to destroy +- * +- * This function terminates the child container, so following this call the +- * child container ID becomes invalid. +- * +- * Notes: +- * - All resources and objects of the destroyed container are returned to the +- * parent container or destroyed if were created be the destroyed container. +- * - This function destroy all the child containers of the specified +- * container prior to destroying the container itself. +- * +- * warning: Only the parent container is allowed to destroy a child policy +- * Container 0 can't be destroyed +- * +- * Return: '0' on Success; Error code otherwise. +- * +- */ +-int dprc_destroy_container(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int child_container_id) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_destroy_container *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_DESTROY_CONT, +- cmd_flags, token); +- cmd_params = (struct dprc_cmd_destroy_container *)cmd.params; +- cmd_params->child_container_id = cpu_to_le32(child_container_id); +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- + /** + * dprc_reset_container - Reset child container. + * @mc_io: Pointer to MC portal's I/O object +@@ -565,279 +478,6 @@ int dprc_get_attributes(struct fsl_mc_io *mc_io, + attr->icid = le16_to_cpu(rsp_params->icid); + attr->options = le32_to_cpu(rsp_params->options); + attr->portal_id = le32_to_cpu(rsp_params->portal_id); +- attr->version.major = le16_to_cpu(rsp_params->version_major); +- attr->version.minor = le16_to_cpu(rsp_params->version_minor); +- +- return 0; +-} +- +-/** +- * dprc_set_res_quota() - Set allocation policy for a specific resource/object +- * type in a child container +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @child_container_id: ID of the child container +- * @type: Resource/object type +- * @quota: Sets the maximum number of resources of the selected type +- * that the child container is allowed to allocate from its parent; +- * when quota is set to -1, the policy is the same as container's +- * general policy. +- * +- * Allocation policy determines whether or not a container may allocate +- * resources from its parent. Each container has a 'global' allocation policy +- * that is set when the container is created. +- * +- * This function sets allocation policy for a specific resource type. +- * The default policy for all resource types matches the container's 'global' +- * allocation policy. +- * +- * Return: '0' on Success; Error code otherwise. +- * +- * @warning Only the parent container is allowed to change a child policy. +- */ +-int dprc_set_res_quota(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int child_container_id, +- char *type, +- u16 quota) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_set_res_quota *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_RES_QUOTA, +- cmd_flags, token); +- cmd_params = (struct dprc_cmd_set_res_quota *)cmd.params; +- cmd_params->child_container_id = cpu_to_le32(child_container_id); +- cmd_params->quota = cpu_to_le16(quota); +- strncpy(cmd_params->type, type, 16); +- cmd_params->type[15] = '\0'; +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** +- * dprc_get_res_quota() - Gets the allocation policy of a specific +- * resource/object type in a child container +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @child_container_id; ID of the child container +- * @type: resource/object type +- * @quota: Returnes the maximum number of resources of the selected type +- * that the child container is allowed to allocate from the parent; +- * when quota is set to -1, the policy is the same as container's +- * general policy. +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_get_res_quota(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int child_container_id, +- char *type, +- u16 *quota) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_get_res_quota *cmd_params; +- struct dprc_rsp_get_res_quota *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_RES_QUOTA, +- cmd_flags, token); +- cmd_params = (struct dprc_cmd_get_res_quota *)cmd.params; +- cmd_params->child_container_id = cpu_to_le32(child_container_id); +- strncpy(cmd_params->type, type, 16); +- cmd_params->type[15] = '\0'; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dprc_rsp_get_res_quota *)cmd.params; +- *quota = le16_to_cpu(rsp_params->quota); +- +- return 0; +-} +- +-/** +- * dprc_assign() - Assigns objects or resource to a child container. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @container_id: ID of the child container +- * @res_req: Describes the type and amount of resources to +- * assign to the given container +- * +- * Assignment is usually done by a parent (this DPRC) to one of its child +- * containers. +- * +- * According to the DPRC allocation policy, the assigned resources may be taken +- * (allocated) from the container's ancestors, if not enough resources are +- * available in the container itself. +- * +- * The type of assignment depends on the dprc_res_req options, as follows: +- * - DPRC_RES_REQ_OPT_EXPLICIT: indicates that assigned resources should have +- * the explicit base ID specified at the id_base_align field of res_req. +- * - DPRC_RES_REQ_OPT_ALIGNED: indicates that the assigned resources should be +- * aligned to the value given at id_base_align field of res_req. +- * - DPRC_RES_REQ_OPT_PLUGGED: Relevant only for object assignment, +- * and indicates that the object must be set to the plugged state. +- * +- * A container may use this function with its own ID in order to change a +- * object state to plugged or unplugged. +- * +- * If IRQ information has been set in the child DPRC, it will signal an +- * interrupt following every change in its object assignment. +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_assign(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int container_id, +- struct dprc_res_req *res_req) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_assign *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_ASSIGN, +- cmd_flags, token); +- cmd_params = (struct dprc_cmd_assign *)cmd.params; +- cmd_params->container_id = cpu_to_le32(container_id); +- cmd_params->options = cpu_to_le32(res_req->options); +- cmd_params->num = cpu_to_le32(res_req->num); +- cmd_params->id_base_align = cpu_to_le32(res_req->id_base_align); +- strncpy(cmd_params->type, res_req->type, 16); +- cmd_params->type[15] = '\0'; +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** +- * dprc_unassign() - Un-assigns objects or resources from a child container +- * and moves them into this (parent) DPRC. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @child_container_id: ID of the child container +- * @res_req: Describes the type and amount of resources to un-assign from +- * the child container +- * +- * Un-assignment of objects can succeed only if the object is not in the +- * plugged or opened state. +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_unassign(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int child_container_id, +- struct dprc_res_req *res_req) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_unassign *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_UNASSIGN, +- cmd_flags, +- token); +- cmd_params = (struct dprc_cmd_unassign *)cmd.params; +- cmd_params->child_container_id = cpu_to_le32(child_container_id); +- cmd_params->options = cpu_to_le32(res_req->options); +- cmd_params->num = cpu_to_le32(res_req->num); +- cmd_params->id_base_align = cpu_to_le32(res_req->id_base_align); +- strncpy(cmd_params->type, res_req->type, 16); +- cmd_params->type[15] = '\0'; +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** +- * dprc_get_pool_count() - Get the number of dprc's pools +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @mc_io: Pointer to MC portal's I/O object +- * @token: Token of DPRC object +- * @pool_count: Returned number of resource pools in the dprc +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_get_pool_count(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int *pool_count) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_rsp_get_pool_count *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_POOL_COUNT, +- cmd_flags, token); +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dprc_rsp_get_pool_count *)cmd.params; +- *pool_count = le32_to_cpu(rsp_params->pool_count); +- +- return 0; +-} +- +-/** +- * dprc_get_pool() - Get the type (string) of a certain dprc's pool +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @pool_index; Index of the pool to be queried (< pool_count) +- * @type: The type of the pool +- * +- * The pool types retrieved one by one by incrementing +- * pool_index up to (not including) the value of pool_count returned +- * from dprc_get_pool_count(). dprc_get_pool_count() must +- * be called prior to dprc_get_pool(). +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_get_pool(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int pool_index, +- char *type) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_get_pool *cmd_params; +- struct dprc_rsp_get_pool *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_POOL, +- cmd_flags, +- token); +- cmd_params = (struct dprc_cmd_get_pool *)cmd.params; +- cmd_params->pool_index = cpu_to_le32(pool_index); +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dprc_rsp_get_pool *)cmd.params; +- strncpy(type, rsp_params->type, 16); +- type[15] = '\0'; + + return 0; + } +@@ -933,64 +573,6 @@ int dprc_get_obj(struct fsl_mc_io *mc_io, + } + EXPORT_SYMBOL(dprc_get_obj); + +-/** +- * dprc_get_obj_desc() - Get object descriptor. +- * +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @obj_type: The type of the object to get its descriptor. +- * @obj_id: The id of the object to get its descriptor +- * @obj_desc: The returned descriptor to fill and return to the user +- * +- * Return: '0' on Success; Error code otherwise. +- * +- */ +-int dprc_get_obj_desc(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- char *obj_type, +- int obj_id, +- struct dprc_obj_desc *obj_desc) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_get_obj_desc *cmd_params; +- struct dprc_rsp_get_obj_desc *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_DESC, +- cmd_flags, +- token); +- cmd_params = (struct dprc_cmd_get_obj_desc *)cmd.params; +- cmd_params->obj_id = cpu_to_le32(obj_id); +- strncpy(cmd_params->type, obj_type, 16); +- cmd_params->type[15] = '\0'; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dprc_rsp_get_obj_desc *)cmd.params; +- obj_desc->id = le32_to_cpu(rsp_params->id); +- obj_desc->vendor = le16_to_cpu(rsp_params->vendor); +- obj_desc->irq_count = rsp_params->irq_count; +- obj_desc->region_count = rsp_params->region_count; +- obj_desc->state = le32_to_cpu(rsp_params->state); +- obj_desc->ver_major = le16_to_cpu(rsp_params->version_major); +- obj_desc->ver_minor = le16_to_cpu(rsp_params->version_minor); +- obj_desc->flags = le16_to_cpu(rsp_params->flags); +- strncpy(obj_desc->type, rsp_params->type, 16); +- obj_desc->type[15] = '\0'; +- strncpy(obj_desc->label, rsp_params->label, 16); +- obj_desc->label[15] = '\0'; +- +- return 0; +-} +-EXPORT_SYMBOL(dprc_get_obj_desc); +- + /** + * dprc_set_obj_irq() - Set IRQ information for object to trigger an interrupt. + * @mc_io: Pointer to MC portal's I/O object +@@ -1129,52 +711,6 @@ int dprc_get_res_count(struct fsl_mc_io *mc_io, + } + EXPORT_SYMBOL(dprc_get_res_count); + +-/** +- * dprc_get_res_ids() - Obtains IDs of free resources in the container +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @type: pool type +- * @range_desc: range descriptor +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_get_res_ids(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- char *type, +- struct dprc_res_ids_range_desc *range_desc) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_get_res_ids *cmd_params; +- struct dprc_rsp_get_res_ids *rsp_params; +- int err; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_RES_IDS, +- cmd_flags, token); +- cmd_params = (struct dprc_cmd_get_res_ids *)cmd.params; +- cmd_params->iter_status = range_desc->iter_status; +- cmd_params->base_id = cpu_to_le32(range_desc->base_id); +- cmd_params->last_id = cpu_to_le32(range_desc->last_id); +- strncpy(cmd_params->type, type, 16); +- cmd_params->type[15] = '\0'; +- +- /* send command to mc*/ +- err = mc_send_command(mc_io, &cmd); +- if (err) +- return err; +- +- /* retrieve response parameters */ +- rsp_params = (struct dprc_rsp_get_res_ids *)cmd.params; +- range_desc->iter_status = rsp_params->iter_status; +- range_desc->base_id = le32_to_cpu(rsp_params->base_id); +- range_desc->last_id = le32_to_cpu(rsp_params->last_id); +- +- return 0; +-} +-EXPORT_SYMBOL(dprc_get_res_ids); +- + /** + * dprc_get_obj_region() - Get region information for a specified object. + * @mc_io: Pointer to MC portal's I/O object +@@ -1216,160 +752,66 @@ int dprc_get_obj_region(struct fsl_mc_io *mc_io, + + /* retrieve response parameters */ + rsp_params = (struct dprc_rsp_get_obj_region *)cmd.params; +- region_desc->base_offset = le64_to_cpu(rsp_params->base_addr); ++ region_desc->base_offset = le32_to_cpu(rsp_params->base_addr); + region_desc->size = le32_to_cpu(rsp_params->size); ++ region_desc->type = rsp_params->type; ++ region_desc->flags = le32_to_cpu(rsp_params->flags); + + return 0; + } + EXPORT_SYMBOL(dprc_get_obj_region); + + /** +- * dprc_set_obj_label() - Set object label. +- * @mc_io: Pointer to MC portal's I/O object ++ * dprc_get_api_version - Get Data Path Resource Container API version ++ * @mc_io: Pointer to Mc portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @obj_type: Object's type +- * @obj_id: Object's ID +- * @label: The required label. The maximum length is 16 chars. ++ * @major_ver: Major version of Data Path Resource Container API ++ * @minor_ver: Minor version of Data Path Resource Container API + * + * Return: '0' on Success; Error code otherwise. + */ +-int dprc_set_obj_label(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- char *obj_type, +- int obj_id, +- char *label) ++int dprc_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver) + { + struct mc_command cmd = { 0 }; +- struct dprc_cmd_set_obj_label *cmd_params; ++ int err; + + /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_OBJ_LABEL, +- cmd_flags, +- token); +- cmd_params = (struct dprc_cmd_set_obj_label *)cmd.params; +- cmd_params->obj_id = cpu_to_le32(obj_id); +- strncpy(cmd_params->label, label, 16); +- cmd_params->label[15] = '\0'; +- strncpy(cmd_params->obj_type, obj_type, 16); +- cmd_params->obj_type[15] = '\0'; ++ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_API_VERSION, ++ cmd_flags, 0); + +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +-EXPORT_SYMBOL(dprc_set_obj_label); +- +-/** +- * dprc_connect() - Connect two endpoints to create a network link between them +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @endpoint1: Endpoint 1 configuration parameters +- * @endpoint2: Endpoint 2 configuration parameters +- * @cfg: Connection configuration. The connection configuration is ignored for +- * connections made to DPMAC objects, where rate is retrieved from the +- * MAC configuration. +- * +- * Return: '0' on Success; Error code otherwise. +- */ +-int dprc_connect(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- const struct dprc_endpoint *endpoint1, +- const struct dprc_endpoint *endpoint2, +- const struct dprc_connection_cfg *cfg) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_connect *cmd_params; ++ /* send command to mc */ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; + +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_CONNECT, +- cmd_flags, +- token); +- cmd_params = (struct dprc_cmd_connect *)cmd.params; +- cmd_params->ep1_id = cpu_to_le32(endpoint1->id); +- cmd_params->ep1_interface_id = cpu_to_le32(endpoint1->if_id); +- cmd_params->ep2_id = cpu_to_le32(endpoint2->id); +- cmd_params->ep2_interface_id = cpu_to_le32(endpoint2->if_id); +- strncpy(cmd_params->ep1_type, endpoint1->type, 16); +- cmd_params->ep1_type[15] = '\0'; +- cmd_params->max_rate = cpu_to_le32(cfg->max_rate); +- cmd_params->committed_rate = cpu_to_le32(cfg->committed_rate); +- strncpy(cmd_params->ep2_type, endpoint2->type, 16); +- cmd_params->ep2_type[15] = '\0'; ++ /* retrieve response parameters */ ++ mc_cmd_read_api_version(&cmd, major_ver, minor_ver); + +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); ++ return 0; + } + + /** +- * dprc_disconnect() - Disconnect one endpoint to remove its network connection +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @endpoint: Endpoint configuration parameters ++ * dprc_get_container_id - Get container ID associated with a given portal. ++ * @mc_io: Pointer to Mc portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @container_id: Requested container id + * + * Return: '0' on Success; Error code otherwise. + */ +-int dprc_disconnect(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- const struct dprc_endpoint *endpoint) +-{ +- struct mc_command cmd = { 0 }; +- struct dprc_cmd_disconnect *cmd_params; +- +- /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_DISCONNECT, +- cmd_flags, +- token); +- cmd_params = (struct dprc_cmd_disconnect *)cmd.params; +- cmd_params->id = cpu_to_le32(endpoint->id); +- cmd_params->interface_id = cpu_to_le32(endpoint->if_id); +- strncpy(cmd_params->type, endpoint->type, 16); +- cmd_params->type[15] = '\0'; +- +- /* send command to mc*/ +- return mc_send_command(mc_io, &cmd); +-} +- +-/** +- * dprc_get_connection() - Get connected endpoint and link status if connection +- * exists. +- * @mc_io: Pointer to MC portal's I/O object +- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' +- * @token: Token of DPRC object +- * @endpoint1: Endpoint 1 configuration parameters +- * @endpoint2: Returned endpoint 2 configuration parameters +- * @state: Returned link state: +- * 1 - link is up; +- * 0 - link is down; +- * -1 - no connection (endpoint2 information is irrelevant) +- * +- * Return: '0' on Success; -ENAVAIL if connection does not exist. +- */ +-int dprc_get_connection(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- const struct dprc_endpoint *endpoint1, +- struct dprc_endpoint *endpoint2, +- int *state) ++int dprc_get_container_id(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int *container_id) + { + struct mc_command cmd = { 0 }; +- struct dprc_cmd_get_connection *cmd_params; +- struct dprc_rsp_get_connection *rsp_params; + int err; + + /* prepare command */ +- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_CONNECTION, ++ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_CONT_ID, + cmd_flags, +- token); +- cmd_params = (struct dprc_cmd_get_connection *)cmd.params; +- cmd_params->ep1_id = cpu_to_le32(endpoint1->id); +- cmd_params->ep1_interface_id = cpu_to_le32(endpoint1->if_id); +- strncpy(cmd_params->ep1_type, endpoint1->type, 16); +- cmd_params->ep1_type[15] = '\0'; ++ 0); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); +@@ -1377,12 +819,7 @@ int dprc_get_connection(struct fsl_mc_io *mc_io, + return err; + + /* retrieve response parameters */ +- rsp_params = (struct dprc_rsp_get_connection *)cmd.params; +- endpoint2->id = le32_to_cpu(rsp_params->ep2_id); +- endpoint2->if_id = le32_to_cpu(rsp_params->ep2_interface_id); +- strncpy(endpoint2->type, rsp_params->ep2_type, 16); +- endpoint2->type[15] = '\0'; +- *state = le32_to_cpu(rsp_params->state); ++ *container_id = (int)mc_cmd_read_object_id(&cmd); + + return 0; + } +diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-allocator.c b/drivers/staging/fsl-mc/bus/fsl-mc-allocator.c +index e93ab53b..ce07096c 100644 +--- a/drivers/staging/fsl-mc/bus/fsl-mc-allocator.c ++++ b/drivers/staging/fsl-mc/bus/fsl-mc-allocator.c +@@ -1,7 +1,7 @@ + /* +- * Freescale MC object device allocator driver ++ * fsl-mc object allocator driver + * +- * Copyright (C) 2013 Freescale Semiconductor, Inc. ++ * Copyright (C) 2013-2016 Freescale Semiconductor, Inc. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any +@@ -12,9 +12,9 @@ + #include + #include "../include/mc-bus.h" + #include "../include/mc-sys.h" +-#include "../include/dpbp-cmd.h" +-#include "../include/dpcon-cmd.h" + ++#include "dpbp-cmd.h" ++#include "dpcon-cmd.h" + #include "fsl-mc-private.h" + + #define FSL_MC_IS_ALLOCATABLE(_obj_type) \ +@@ -23,15 +23,12 @@ + strcmp(_obj_type, "dpcon") == 0) + + /** +- * fsl_mc_resource_pool_add_device - add allocatable device to a resource +- * pool of a given MC bus ++ * fsl_mc_resource_pool_add_device - add allocatable object to a resource ++ * pool of a given fsl-mc bus + * +- * @mc_bus: pointer to the MC bus +- * @pool_type: MC bus pool type +- * @mc_dev: Pointer to allocatable MC object device +- * +- * It adds an allocatable MC object device to a container's resource pool of +- * the given resource type ++ * @mc_bus: pointer to the fsl-mc bus ++ * @pool_type: pool type ++ * @mc_dev: pointer to allocatable fsl-mc device + */ + static int __must_check fsl_mc_resource_pool_add_device(struct fsl_mc_bus + *mc_bus, +@@ -95,10 +92,10 @@ static int __must_check fsl_mc_resource_pool_add_device(struct fsl_mc_bus + * fsl_mc_resource_pool_remove_device - remove an allocatable device from a + * resource pool + * +- * @mc_dev: Pointer to allocatable MC object device ++ * @mc_dev: pointer to allocatable fsl-mc device + * +- * It permanently removes an allocatable MC object device from the resource +- * pool, the device is currently in, as long as it is in the pool's free list. ++ * It permanently removes an allocatable fsl-mc device from the resource ++ * pool. It's an error if the device is in use. + */ + static int __must_check fsl_mc_resource_pool_remove_device(struct fsl_mc_device + *mc_dev) +@@ -255,17 +252,18 @@ void fsl_mc_resource_free(struct fsl_mc_resource *resource) + EXPORT_SYMBOL_GPL(fsl_mc_resource_free); + + /** +- * fsl_mc_object_allocate - Allocates a MC object device of the given +- * pool type from a given MC bus ++ * fsl_mc_object_allocate - Allocates an fsl-mc object of the given ++ * pool type from a given fsl-mc bus instance + * +- * @mc_dev: MC device for which the MC object device is to be allocated +- * @pool_type: MC bus resource pool type +- * @new_mc_dev: Pointer to area where the pointer to the allocated +- * MC object device is to be returned ++ * @mc_dev: fsl-mc device which is used in conjunction with the ++ * allocated object ++ * @pool_type: pool type ++ * @new_mc_dev: pointer to area where the pointer to the allocated device ++ * is to be returned + * +- * This function allocates a MC object device from the device's parent DPRC, +- * from the corresponding MC bus' pool of allocatable MC object devices of +- * the given resource type. mc_dev cannot be a DPRC itself. ++ * Allocatable objects are always used in conjunction with some functional ++ * device. This function allocates an object of the specified type from ++ * the DPRC containing the functional device. + * + * NOTE: pool_type must be different from FSL_MC_POOL_MCP, since MC + * portals are allocated using fsl_mc_portal_allocate(), instead of +@@ -312,10 +310,9 @@ int __must_check fsl_mc_object_allocate(struct fsl_mc_device *mc_dev, + EXPORT_SYMBOL_GPL(fsl_mc_object_allocate); + + /** +- * fsl_mc_object_free - Returns an allocatable MC object device to the +- * corresponding resource pool of a given MC bus. +- * +- * @mc_adev: Pointer to the MC object device ++ * fsl_mc_object_free - Returns an fsl-mc object to the resource ++ * pool where it came from. ++ * @mc_adev: Pointer to the fsl-mc device + */ + void fsl_mc_object_free(struct fsl_mc_device *mc_adev) + { +@@ -332,8 +329,14 @@ void fsl_mc_object_free(struct fsl_mc_device *mc_adev) + EXPORT_SYMBOL_GPL(fsl_mc_object_free); + + /* +- * Initialize the interrupt pool associated with a MC bus. +- * It allocates a block of IRQs from the GIC-ITS ++ * A DPRC and the devices in the DPRC all share the same GIC-ITS device ++ * ID. A block of IRQs is pre-allocated and maintained in a pool ++ * from which devices can allocate them when needed. ++ */ ++ ++/* ++ * Initialize the interrupt pool associated with an fsl-mc bus. ++ * It allocates a block of IRQs from the GIC-ITS. + */ + int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus, + unsigned int irq_count) +@@ -395,7 +398,7 @@ int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus, + EXPORT_SYMBOL_GPL(fsl_mc_populate_irq_pool); + + /** +- * Teardown the interrupt pool associated with an MC bus. ++ * Teardown the interrupt pool associated with an fsl-mc bus. + * It frees the IRQs that were allocated to the pool, back to the GIC-ITS. + */ + void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus) +@@ -422,11 +425,7 @@ void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus) + EXPORT_SYMBOL_GPL(fsl_mc_cleanup_irq_pool); + + /** +- * It allocates the IRQs required by a given MC object device. The +- * IRQs are allocated from the interrupt pool associated with the +- * MC bus that contains the device, if the device is not a DPRC device. +- * Otherwise, the IRQs are allocated from the interrupt pool associated +- * with the MC bus that represents the DPRC device itself. ++ * Allocate the IRQs required by a given fsl-mc device. + */ + int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev) + { +@@ -495,8 +494,7 @@ int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev) + EXPORT_SYMBOL_GPL(fsl_mc_allocate_irqs); + + /* +- * It frees the IRQs that were allocated for a MC object device, by +- * returning them to the corresponding interrupt pool. ++ * Frees the IRQs that were allocated for an fsl-mc device. + */ + void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev) + { +@@ -605,7 +603,7 @@ static int fsl_mc_allocator_probe(struct fsl_mc_device *mc_dev) + return error; + + dev_dbg(&mc_dev->dev, +- "Allocatable MC object device bound to fsl_mc_allocator driver"); ++ "Allocatable fsl-mc device bound to fsl_mc_allocator driver"); + return 0; + } + +@@ -627,7 +625,7 @@ static int fsl_mc_allocator_remove(struct fsl_mc_device *mc_dev) + } + + dev_dbg(&mc_dev->dev, +- "Allocatable MC object device unbound from fsl_mc_allocator driver"); ++ "Allocatable fsl-mc device unbound from fsl_mc_allocator driver"); + return 0; + } + +diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-bus.c b/drivers/staging/fsl-mc/bus/fsl-mc-bus.c +index 44f64b6f..30a48df3 100644 +--- a/drivers/staging/fsl-mc/bus/fsl-mc-bus.c ++++ b/drivers/staging/fsl-mc/bus/fsl-mc-bus.c +@@ -1,7 +1,7 @@ + /* + * Freescale Management Complex (MC) bus driver + * +- * Copyright (C) 2014 Freescale Semiconductor, Inc. ++ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. + * Author: German Rivera + * + * This file is licensed under the terms of the GNU General Public +@@ -9,6 +9,8 @@ + * warranty of any kind, whether express or implied. + */ + ++#define pr_fmt(fmt) "fsl-mc: " fmt ++ + #include + #include + #include +@@ -25,8 +27,6 @@ + #include "fsl-mc-private.h" + #include "dprc-cmd.h" + +-static struct kmem_cache *mc_dev_cache; +- + /** + * Default DMA mask for devices on a fsl-mc bus + */ +@@ -34,7 +34,7 @@ static struct kmem_cache *mc_dev_cache; + + /** + * struct fsl_mc - Private data of a "fsl,qoriq-mc" platform device +- * @root_mc_bus_dev: MC object device representing the root DPRC ++ * @root_mc_bus_dev: fsl-mc device representing the root DPRC + * @num_translation_ranges: number of entries in addr_translation_ranges + * @translation_ranges: array of bus to system address translation ranges + */ +@@ -62,8 +62,8 @@ struct fsl_mc_addr_translation_range { + + /** + * fsl_mc_bus_match - device to driver matching callback +- * @dev: the MC object device structure to match against +- * @drv: the device driver to search for matching MC object device id ++ * @dev: the fsl-mc device to match against ++ * @drv: the device driver to search for matching fsl-mc object type + * structures + * + * Returns 1 on success, 0 otherwise. +@@ -75,8 +75,11 @@ static int fsl_mc_bus_match(struct device *dev, struct device_driver *drv) + struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(drv); + bool found = false; + +- if (WARN_ON(!fsl_mc_bus_exists())) ++ /* When driver_override is set, only bind to the matching driver */ ++ if (mc_dev->driver_override) { ++ found = !strcmp(mc_dev->driver_override, mc_drv->driver.name); + goto out; ++ } + + if (!mc_drv->match_id_table) + goto out; +@@ -91,7 +94,7 @@ static int fsl_mc_bus_match(struct device *dev, struct device_driver *drv) + + /* + * Traverse the match_id table of the given driver, trying to find +- * a matching for the given MC object device. ++ * a matching for the given device. + */ + for (id = mc_drv->match_id_table; id->vendor != 0x0; id++) { + if (id->vendor == mc_dev->obj_desc.vendor && +@@ -132,23 +135,141 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + } + static DEVICE_ATTR_RO(modalias); + ++static ssize_t rescan_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ unsigned long val; ++ unsigned int irq_count; ++ struct fsl_mc_device *root_mc_dev; ++ struct fsl_mc_bus *root_mc_bus; ++ ++ if (!fsl_mc_is_root_dprc(dev)) ++ return -EINVAL; ++ ++ root_mc_dev = to_fsl_mc_device(dev); ++ root_mc_bus = to_fsl_mc_bus(root_mc_dev); ++ ++ if (kstrtoul(buf, 0, &val) < 0) ++ return -EINVAL; ++ ++ if (val) { ++ mutex_lock(&root_mc_bus->scan_mutex); ++ dprc_scan_objects(root_mc_dev, NULL, &irq_count); ++ mutex_unlock(&root_mc_bus->scan_mutex); ++ } ++ ++ return count; ++} ++static DEVICE_ATTR_WO(rescan); ++ ++static ssize_t driver_override_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); ++ const char *driver_override, *old = mc_dev->driver_override; ++ char *cp; ++ ++ if (WARN_ON(dev->bus != &fsl_mc_bus_type)) ++ return -EINVAL; ++ ++ if (count >= (PAGE_SIZE - 1)) ++ return -EINVAL; ++ ++ driver_override = kstrndup(buf, count, GFP_KERNEL); ++ if (!driver_override) ++ return -ENOMEM; ++ ++ cp = strchr(driver_override, '\n'); ++ if (cp) ++ *cp = '\0'; ++ ++ if (strlen(driver_override)) { ++ mc_dev->driver_override = driver_override; ++ } else { ++ kfree(driver_override); ++ mc_dev->driver_override = NULL; ++ } ++ ++ kfree(old); ++ ++ return count; ++} ++ ++static ssize_t driver_override_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); ++ ++ return snprintf(buf, PAGE_SIZE, "%s\n", mc_dev->driver_override); ++} ++static DEVICE_ATTR_RW(driver_override); ++ + static struct attribute *fsl_mc_dev_attrs[] = { + &dev_attr_modalias.attr, ++ &dev_attr_rescan.attr, ++ &dev_attr_driver_override.attr, + NULL, + }; + + ATTRIBUTE_GROUPS(fsl_mc_dev); + ++static int scan_fsl_mc_bus(struct device *dev, void *data) ++{ ++ unsigned int irq_count; ++ struct fsl_mc_device *root_mc_dev; ++ struct fsl_mc_bus *root_mc_bus; ++ ++ if (fsl_mc_is_root_dprc(dev)) { ++ root_mc_dev = to_fsl_mc_device(dev); ++ root_mc_bus = to_fsl_mc_bus(root_mc_dev); ++ mutex_lock(&root_mc_bus->scan_mutex); ++ dprc_scan_objects(root_mc_dev, NULL, &irq_count); ++ mutex_unlock(&root_mc_bus->scan_mutex); ++ } ++ ++ return 0; ++} ++ ++static ssize_t bus_rescan_store(struct bus_type *bus, ++ const char *buf, size_t count) ++{ ++ unsigned long val; ++ ++ if (kstrtoul(buf, 0, &val) < 0) ++ return -EINVAL; ++ ++ if (val) ++ bus_for_each_dev(bus, NULL, NULL, scan_fsl_mc_bus); ++ ++ return count; ++} ++static BUS_ATTR(rescan, (S_IWUSR | S_IWGRP), NULL, bus_rescan_store); ++ ++static struct attribute *fsl_mc_bus_attrs[] = { ++ &bus_attr_rescan.attr, ++ NULL, ++}; ++ ++static const struct attribute_group fsl_mc_bus_group = { ++ .attrs = fsl_mc_bus_attrs, ++}; ++ ++static const struct attribute_group *fsl_mc_bus_groups[] = { ++ &fsl_mc_bus_group, ++ NULL, ++}; ++ + struct bus_type fsl_mc_bus_type = { + .name = "fsl-mc", + .match = fsl_mc_bus_match, + .uevent = fsl_mc_bus_uevent, + .dev_groups = fsl_mc_dev_groups, ++ .bus_groups = fsl_mc_bus_groups, + }; + EXPORT_SYMBOL_GPL(fsl_mc_bus_type); + +-static atomic_t root_dprc_count = ATOMIC_INIT(0); +- + static int fsl_mc_driver_probe(struct device *dev) + { + struct fsl_mc_driver *mc_drv; +@@ -164,8 +285,7 @@ static int fsl_mc_driver_probe(struct device *dev) + + error = mc_drv->probe(mc_dev); + if (error < 0) { +- dev_err(dev, "MC object device probe callback failed: %d\n", +- error); ++ dev_err(dev, "%s failed: %d\n", __func__, error); + return error; + } + +@@ -183,9 +303,7 @@ static int fsl_mc_driver_remove(struct device *dev) + + error = mc_drv->remove(mc_dev); + if (error < 0) { +- dev_err(dev, +- "MC object device remove callback failed: %d\n", +- error); ++ dev_err(dev, "%s failed: %d\n", __func__, error); + return error; + } + +@@ -232,8 +350,6 @@ int __fsl_mc_driver_register(struct fsl_mc_driver *mc_driver, + return error; + } + +- pr_info("MC object device driver %s registered\n", +- mc_driver->driver.name); + return 0; + } + EXPORT_SYMBOL_GPL(__fsl_mc_driver_register); +@@ -248,15 +364,6 @@ void fsl_mc_driver_unregister(struct fsl_mc_driver *mc_driver) + } + EXPORT_SYMBOL_GPL(fsl_mc_driver_unregister); + +-/** +- * fsl_mc_bus_exists - check if a root dprc exists +- */ +-bool fsl_mc_bus_exists(void) +-{ +- return atomic_read(&root_dprc_count) > 0; +-} +-EXPORT_SYMBOL_GPL(fsl_mc_bus_exists); +- + /** + * fsl_mc_get_root_dprc - function to traverse to the root dprc + */ +@@ -315,21 +422,6 @@ static int get_dprc_icid(struct fsl_mc_io *mc_io, + return error; + } + +-static int get_dprc_version(struct fsl_mc_io *mc_io, +- int container_id, u16 *major, u16 *minor) +-{ +- struct dprc_attributes attr; +- int error; +- +- error = get_dprc_attr(mc_io, container_id, &attr); +- if (error == 0) { +- *major = attr.version.major; +- *minor = attr.version.minor; +- } +- +- return error; +-} +- + static int translate_mc_addr(struct fsl_mc_device *mc_dev, + enum dprc_region_type mc_region_type, + u64 mc_offset, phys_addr_t *phys_addr) +@@ -451,18 +543,37 @@ bool fsl_mc_is_root_dprc(struct device *dev) + return dev == root_dprc_dev; + } + ++static void fsl_mc_device_release(struct device *dev) ++{ ++ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); ++ struct fsl_mc_bus *mc_bus = NULL; ++ ++ kfree(mc_dev->regions); ++ ++ if (strcmp(mc_dev->obj_desc.type, "dprc") == 0) ++ mc_bus = to_fsl_mc_bus(mc_dev); ++ ++ if (mc_bus) ++ kfree(mc_bus); ++ else ++ kfree(mc_dev); ++} ++ + /** +- * Add a newly discovered MC object device to be visible in Linux ++ * Add a newly discovered fsl-mc device to be visible in Linux + */ + int fsl_mc_device_add(struct dprc_obj_desc *obj_desc, + struct fsl_mc_io *mc_io, + struct device *parent_dev, ++ const char *driver_override, + struct fsl_mc_device **new_mc_dev) + { + int error; + struct fsl_mc_device *mc_dev = NULL; + struct fsl_mc_bus *mc_bus = NULL; + struct fsl_mc_device *parent_mc_dev; ++ struct device *fsl_mc_platform_dev; ++ struct device_node *fsl_mc_platform_node; + + if (dev_is_fsl_mc(parent_dev)) + parent_mc_dev = to_fsl_mc_device(parent_dev); +@@ -473,7 +584,7 @@ int fsl_mc_device_add(struct dprc_obj_desc *obj_desc, + /* + * Allocate an MC bus device object: + */ +- mc_bus = devm_kzalloc(parent_dev, sizeof(*mc_bus), GFP_KERNEL); ++ mc_bus = kzalloc(sizeof(*mc_bus), GFP_KERNEL); + if (!mc_bus) + return -ENOMEM; + +@@ -482,16 +593,30 @@ int fsl_mc_device_add(struct dprc_obj_desc *obj_desc, + /* + * Allocate a regular fsl_mc_device object: + */ +- mc_dev = kmem_cache_zalloc(mc_dev_cache, GFP_KERNEL); ++ mc_dev = kzalloc(sizeof(*mc_dev), GFP_KERNEL); + if (!mc_dev) + return -ENOMEM; + } + + mc_dev->obj_desc = *obj_desc; + mc_dev->mc_io = mc_io; ++ ++ if (driver_override) { ++ /* ++ * We trust driver_override, so we don't need to use ++ * kstrndup() here ++ */ ++ mc_dev->driver_override = kstrdup(driver_override, GFP_KERNEL); ++ if (!mc_dev->driver_override) { ++ error = -ENOMEM; ++ goto error_cleanup_dev; ++ } ++ } ++ + device_initialize(&mc_dev->dev); + mc_dev->dev.parent = parent_dev; + mc_dev->dev.bus = &fsl_mc_bus_type; ++ mc_dev->dev.release = fsl_mc_device_release; + dev_set_name(&mc_dev->dev, "%s.%d", obj_desc->type, obj_desc->id); + + if (strcmp(obj_desc->type, "dprc") == 0) { +@@ -524,8 +649,6 @@ int fsl_mc_device_add(struct dprc_obj_desc *obj_desc, + } + + mc_io2 = mc_io; +- +- atomic_inc(&root_dprc_count); + } + + error = get_dprc_icid(mc_io2, obj_desc->id, &mc_dev->icid); +@@ -533,8 +656,8 @@ int fsl_mc_device_add(struct dprc_obj_desc *obj_desc, + goto error_cleanup_dev; + } else { + /* +- * A non-DPRC MC object device has to be a child of another +- * MC object (specifically a DPRC object) ++ * A non-DPRC object has to be a child of a DPRC, use the ++ * parent's ICID and interrupt domain. + */ + mc_dev->icid = parent_mc_dev->icid; + mc_dev->dma_mask = FSL_MC_DEFAULT_DMA_MASK; +@@ -556,9 +679,14 @@ int fsl_mc_device_add(struct dprc_obj_desc *obj_desc, + goto error_cleanup_dev; + } + +- /* Objects are coherent, unless 'no shareability' flag set. */ +- if (!(obj_desc->flags & DPRC_OBJ_FLAG_NO_MEM_SHAREABILITY)) +- arch_setup_dma_ops(&mc_dev->dev, 0, 0, NULL, true); ++ fsl_mc_platform_dev = &mc_dev->dev; ++ while (dev_is_fsl_mc(fsl_mc_platform_dev)) ++ fsl_mc_platform_dev = fsl_mc_platform_dev->parent; ++ fsl_mc_platform_node = fsl_mc_platform_dev->of_node; ++ ++ /* Set up the iommu configuration for the devices. */ ++ fsl_mc_dma_configure(mc_dev, fsl_mc_platform_node, ++ !(obj_desc->flags & DPRC_OBJ_FLAG_NO_MEM_SHAREABILITY)); + + /* + * The device-specific probe callback will get invoked by device_add() +@@ -571,9 +699,7 @@ int fsl_mc_device_add(struct dprc_obj_desc *obj_desc, + goto error_cleanup_dev; + } + +- (void)get_device(&mc_dev->dev); +- dev_dbg(parent_dev, "Added MC object device %s\n", +- dev_name(&mc_dev->dev)); ++ dev_dbg(parent_dev, "added %s\n", dev_name(&mc_dev->dev)); + + *new_mc_dev = mc_dev; + return 0; +@@ -581,47 +707,34 @@ int fsl_mc_device_add(struct dprc_obj_desc *obj_desc, + error_cleanup_dev: + kfree(mc_dev->regions); + if (mc_bus) +- devm_kfree(parent_dev, mc_bus); ++ kfree(mc_bus); + else +- kmem_cache_free(mc_dev_cache, mc_dev); ++ kfree(mc_dev); + + return error; + } + EXPORT_SYMBOL_GPL(fsl_mc_device_add); + + /** +- * fsl_mc_device_remove - Remove a MC object device from being visible to ++ * fsl_mc_device_remove - Remove an fsl-mc device from being visible to + * Linux + * +- * @mc_dev: Pointer to a MC object device object ++ * @mc_dev: Pointer to an fsl-mc device + */ + void fsl_mc_device_remove(struct fsl_mc_device *mc_dev) + { +- struct fsl_mc_bus *mc_bus = NULL; +- +- kfree(mc_dev->regions); ++ kfree(mc_dev->driver_override); ++ mc_dev->driver_override = NULL; + + /* + * The device-specific remove callback will get invoked by device_del() + */ + device_del(&mc_dev->dev); +- put_device(&mc_dev->dev); + +- if (strcmp(mc_dev->obj_desc.type, "dprc") == 0) { +- mc_bus = to_fsl_mc_bus(mc_dev); ++ if (strcmp(mc_dev->obj_desc.type, "dprc") != 0) ++ mc_dev->dev.iommu_fwspec = NULL; + +- if (fsl_mc_is_root_dprc(&mc_dev->dev)) { +- if (atomic_read(&root_dprc_count) > 0) +- atomic_dec(&root_dprc_count); +- else +- WARN_ON(1); +- } +- } +- +- if (mc_bus) +- devm_kfree(mc_dev->dev.parent, mc_bus); +- else +- kmem_cache_free(mc_dev_cache, mc_dev); ++ put_device(&mc_dev->dev); + } + EXPORT_SYMBOL_GPL(fsl_mc_device_remove); + +@@ -629,8 +742,7 @@ static int parse_mc_ranges(struct device *dev, + int *paddr_cells, + int *mc_addr_cells, + int *mc_size_cells, +- const __be32 **ranges_start, +- u8 *num_ranges) ++ const __be32 **ranges_start) + { + const __be32 *prop; + int range_tuple_cell_count; +@@ -643,8 +755,6 @@ static int parse_mc_ranges(struct device *dev, + dev_warn(dev, + "missing or empty ranges property for device tree node '%s'\n", + mc_node->name); +- +- *num_ranges = 0; + return 0; + } + +@@ -671,8 +781,7 @@ static int parse_mc_ranges(struct device *dev, + return -EINVAL; + } + +- *num_ranges = ranges_len / tuple_len; +- return 0; ++ return ranges_len / tuple_len; + } + + static int get_mc_addr_translation_ranges(struct device *dev, +@@ -680,7 +789,7 @@ static int get_mc_addr_translation_ranges(struct device *dev, + **ranges, + u8 *num_ranges) + { +- int error; ++ int ret; + int paddr_cells; + int mc_addr_cells; + int mc_size_cells; +@@ -688,16 +797,16 @@ static int get_mc_addr_translation_ranges(struct device *dev, + const __be32 *ranges_start; + const __be32 *cell; + +- error = parse_mc_ranges(dev, ++ ret = parse_mc_ranges(dev, + &paddr_cells, + &mc_addr_cells, + &mc_size_cells, +- &ranges_start, +- num_ranges); +- if (error < 0) +- return error; ++ &ranges_start); ++ if (ret < 0) ++ return ret; + +- if (!(*num_ranges)) { ++ *num_ranges = ret; ++ if (!ret) { + /* + * Missing or empty ranges property ("ranges;") for the + * 'fsl,qoriq-mc' node. In this case, identity mapping +@@ -749,8 +858,6 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) + struct mc_version mc_version; + struct resource res; + +- dev_info(&pdev->dev, "Root MC bus device probed"); +- + mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL); + if (!mc) + return -ENOMEM; +@@ -783,8 +890,7 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) + goto error_cleanup_mc_io; + } + +- dev_info(&pdev->dev, +- "Freescale Management Complex Firmware version: %u.%u.%u\n", ++ dev_info(&pdev->dev, "MC firmware version: %u.%u.%u\n", + mc_version.major, mc_version.minor, mc_version.revision); + + error = get_mc_addr_translation_ranges(&pdev->dev, +@@ -793,16 +899,17 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) + if (error < 0) + goto error_cleanup_mc_io; + +- error = dpmng_get_container_id(mc_io, 0, &container_id); ++ error = dprc_get_container_id(mc_io, 0, &container_id); + if (error < 0) { + dev_err(&pdev->dev, +- "dpmng_get_container_id() failed: %d\n", error); ++ "dprc_get_container_id() failed: %d\n", error); + goto error_cleanup_mc_io; + } + + memset(&obj_desc, 0, sizeof(struct dprc_obj_desc)); +- error = get_dprc_version(mc_io, container_id, +- &obj_desc.ver_major, &obj_desc.ver_minor); ++ error = dprc_get_api_version(mc_io, 0, ++ &obj_desc.ver_major, ++ &obj_desc.ver_minor); + if (error < 0) + goto error_cleanup_mc_io; + +@@ -812,7 +919,8 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) + obj_desc.irq_count = 1; + obj_desc.region_count = 0; + +- error = fsl_mc_device_add(&obj_desc, mc_io, &pdev->dev, &mc_bus_dev); ++ error = fsl_mc_device_add(&obj_desc, mc_io, &pdev->dev, NULL, ++ &mc_bus_dev); + if (error < 0) + goto error_cleanup_mc_io; + +@@ -840,7 +948,6 @@ static int fsl_mc_bus_remove(struct platform_device *pdev) + fsl_destroy_mc_io(mc->root_mc_bus_dev->mc_io); + mc->root_mc_bus_dev->mc_io = NULL; + +- dev_info(&pdev->dev, "Root MC bus device removed"); + return 0; + } + +@@ -865,22 +972,12 @@ static int __init fsl_mc_bus_driver_init(void) + { + int error; + +- mc_dev_cache = kmem_cache_create("fsl_mc_device", +- sizeof(struct fsl_mc_device), 0, 0, +- NULL); +- if (!mc_dev_cache) { +- pr_err("Could not create fsl_mc_device cache\n"); +- return -ENOMEM; +- } +- + error = bus_register(&fsl_mc_bus_type); + if (error < 0) { +- pr_err("fsl-mc bus type registration failed: %d\n", error); ++ pr_err("bus type registration failed: %d\n", error); + goto error_cleanup_cache; + } + +- pr_info("fsl-mc bus type registered\n"); +- + error = platform_driver_register(&fsl_mc_bus_driver); + if (error < 0) { + pr_err("platform_driver_register() failed: %d\n", error); +@@ -914,7 +1011,6 @@ static int __init fsl_mc_bus_driver_init(void) + bus_unregister(&fsl_mc_bus_type); + + error_cleanup_cache: +- kmem_cache_destroy(mc_dev_cache); + return error; + } + postcore_initcall(fsl_mc_bus_driver_init); +diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-iommu.c b/drivers/staging/fsl-mc/bus/fsl-mc-iommu.c +new file mode 100644 +index 00000000..86b2cd84 +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/fsl-mc-iommu.c +@@ -0,0 +1,104 @@ ++/* ++ * Copyright 2016-17 NXP ++ * Author: Nipun Gupta ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include "../include/mc.h" ++ ++/* Setup the IOMMU for the DPRC container */ ++static const struct iommu_ops ++*fsl_mc_iommu_configure(struct fsl_mc_device *mc_dev, ++ struct device_node *fsl_mc_platform_node) ++{ ++ struct of_phandle_args iommu_spec; ++ const struct iommu_ops *ops; ++ u32 iommu_phandle; ++ struct device_node *iommu_node; ++ const __be32 *map = NULL; ++ int iommu_cells, map_len, ret; ++ ++ map = of_get_property(fsl_mc_platform_node, "iommu-map", &map_len); ++ if (!map) ++ return NULL; ++ ++ ops = mc_dev->dev.bus->iommu_ops; ++ if (!ops || !ops->of_xlate) ++ return NULL; ++ ++ iommu_phandle = be32_to_cpup(map + 1); ++ iommu_node = of_find_node_by_phandle(iommu_phandle); ++ ++ if (of_property_read_u32(iommu_node, "#iommu-cells", &iommu_cells)) { ++ pr_err("%s: missing #iommu-cells property\n", iommu_node->name); ++ return NULL; ++ } ++ ++ /* Initialize the fwspec */ ++ ret = iommu_fwspec_init(&mc_dev->dev, &iommu_node->fwnode, ops); ++ if (ret) ++ return NULL; ++ ++ /* ++ * Fill in the required stream-id before calling the iommu's ++ * ops->xlate callback. ++ */ ++ iommu_spec.np = iommu_node; ++ iommu_spec.args[0] = mc_dev->icid; ++ iommu_spec.args_count = 1; ++ ++ ret = ops->of_xlate(&mc_dev->dev, &iommu_spec); ++ if (ret) ++ return NULL; ++ ++ of_node_put(iommu_spec.np); ++ ++ return ops; ++} ++ ++/* Set up DMA configuration for fsl-mc devices */ ++void fsl_mc_dma_configure(struct fsl_mc_device *mc_dev, ++ struct device_node *fsl_mc_platform_node, int coherent) ++{ ++ const struct iommu_ops *ops; ++ ++ ops = fsl_mc_iommu_configure(mc_dev, fsl_mc_platform_node); ++ ++ mc_dev->dev.coherent_dma_mask = DMA_BIT_MASK(48); ++ mc_dev->dev.dma_mask = &mc_dev->dev.coherent_dma_mask; ++ arch_setup_dma_ops(&mc_dev->dev, 0, ++ mc_dev->dev.coherent_dma_mask + 1, ops, coherent); ++} ++ ++/* Macro to get the container device of a MC device */ ++#define fsl_mc_cont_dev(_dev) ((to_fsl_mc_device(_dev)->flags & \ ++ FSL_MC_IS_DPRC) ? (_dev) : ((_dev)->parent)) ++ ++/* Macro to check if a device is a container device */ ++#define is_cont_dev(_dev) (to_fsl_mc_device(_dev)->flags & FSL_MC_IS_DPRC) ++ ++/* Get the IOMMU group for device on fsl-mc bus */ ++struct iommu_group *fsl_mc_device_group(struct device *dev) ++{ ++ struct device *cont_dev = fsl_mc_cont_dev(dev); ++ struct iommu_group *group; ++ ++ /* Container device is responsible for creating the iommu group */ ++ if (is_cont_dev(dev)) { ++ group = iommu_group_alloc(); ++ if (IS_ERR(group)) ++ return NULL; ++ } else { ++ get_device(cont_dev); ++ group = iommu_group_get(cont_dev); ++ put_device(cont_dev); ++ } ++ ++ return group; ++} +diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-msi.c b/drivers/staging/fsl-mc/bus/fsl-mc-msi.c +index 3d46b1b1..b8b2c86e 100644 +--- a/drivers/staging/fsl-mc/bus/fsl-mc-msi.c ++++ b/drivers/staging/fsl-mc/bus/fsl-mc-msi.c +@@ -1,7 +1,7 @@ + /* + * Freescale Management Complex (MC) bus driver MSI support + * +- * Copyright (C) 2015 Freescale Semiconductor, Inc. ++ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. + * Author: German Rivera + * + * This file is licensed under the terms of the GNU General Public +@@ -17,6 +17,7 @@ + #include + #include + #include "../include/mc-bus.h" ++#include "fsl-mc-private.h" + + /* + * Generate a unique ID identifying the interrupt (only used within the MSI +diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-private.h b/drivers/staging/fsl-mc/bus/fsl-mc-private.h +index d459c267..e08b8843 100644 +--- a/drivers/staging/fsl-mc/bus/fsl-mc-private.h ++++ b/drivers/staging/fsl-mc/bus/fsl-mc-private.h +@@ -10,13 +10,15 @@ + #ifndef _FSL_MC_PRIVATE_H_ + #define _FSL_MC_PRIVATE_H_ + ++#include "../include/mc.h" ++#include "../include/mc-bus.h" ++ + int __must_check fsl_mc_device_add(struct dprc_obj_desc *obj_desc, + struct fsl_mc_io *mc_io, + struct device *parent_dev, ++ const char *driver_override, + struct fsl_mc_device **new_mc_dev); + +-void fsl_mc_device_remove(struct fsl_mc_device *mc_dev); +- + int __init dprc_driver_init(void); + + void dprc_driver_exit(void); +diff --git a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c b/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c +index 7a6ac640..49127acb 100644 +--- a/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c ++++ b/drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c +@@ -1,7 +1,7 @@ + /* + * Freescale Management Complex (MC) bus driver MSI support + * +- * Copyright (C) 2015 Freescale Semiconductor, Inc. ++ * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. + * Author: German Rivera + * + * This file is licensed under the terms of the GNU General Public +@@ -17,9 +17,10 @@ + #include + #include + #include "../include/mc-bus.h" ++#include "fsl-mc-private.h" + + static struct irq_chip its_msi_irq_chip = { +- .name = "fsl-mc-bus-msi", ++ .name = "ITS-fMSI", + .irq_mask = irq_chip_mask_parent, + .irq_unmask = irq_chip_unmask_parent, + .irq_eoi = irq_chip_eoi_parent, +@@ -51,7 +52,7 @@ static int its_fsl_mc_msi_prepare(struct irq_domain *msi_domain, + return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info); + } + +-static struct msi_domain_ops its_fsl_mc_msi_ops = { ++static struct msi_domain_ops its_fsl_mc_msi_ops __ro_after_init = { + .msi_prepare = its_fsl_mc_msi_prepare, + }; + +@@ -94,8 +95,8 @@ int __init its_fsl_mc_msi_init(void) + continue; + } + +- WARN_ON(mc_msi_domain-> +- host_data != &its_fsl_mc_msi_domain_info); ++ WARN_ON(mc_msi_domain->host_data != ++ &its_fsl_mc_msi_domain_info); + + pr_info("fsl-mc MSI: %s domain created\n", np->full_name); + } +diff --git a/drivers/staging/fsl-mc/bus/mc-io.c b/drivers/staging/fsl-mc/bus/mc-io.c +index 798c965f..d66b87f0 100644 +--- a/drivers/staging/fsl-mc/bus/mc-io.c ++++ b/drivers/staging/fsl-mc/bus/mc-io.c +@@ -1,4 +1,5 @@ +-/* Copyright 2013-2016 Freescale Semiconductor Inc. ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -11,7 +12,6 @@ + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * +- * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any +diff --git a/drivers/staging/fsl-mc/bus/mc-ioctl.h b/drivers/staging/fsl-mc/bus/mc-ioctl.h +new file mode 100644 +index 00000000..8ac502a1 +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/mc-ioctl.h +@@ -0,0 +1,22 @@ ++/* ++ * Freescale Management Complex (MC) ioclt interface ++ * ++ * Copyright (C) 2014 Freescale Semiconductor, Inc. ++ * Author: Lijun Pan ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++#ifndef _FSL_MC_IOCTL_H_ ++#define _FSL_MC_IOCTL_H_ ++ ++#include ++#include "../include/mc-sys.h" ++ ++#define RESTOOL_IOCTL_TYPE 'R' ++ ++#define RESTOOL_SEND_MC_COMMAND \ ++ _IOWR(RESTOOL_IOCTL_TYPE, 0xE0, struct mc_command) ++ ++#endif /* _FSL_MC_IOCTL_H_ */ +diff --git a/drivers/staging/fsl-mc/bus/mc-restool.c b/drivers/staging/fsl-mc/bus/mc-restool.c +new file mode 100644 +index 00000000..d5330b68 +--- /dev/null ++++ b/drivers/staging/fsl-mc/bus/mc-restool.c +@@ -0,0 +1,405 @@ ++/* ++ * Freescale Management Complex (MC) restool driver ++ * ++ * Copyright (C) 2014 Freescale Semiconductor, Inc. ++ * Author: Lijun Pan ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include "../include/mc.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "mc-ioctl.h" ++#include "../include/mc-sys.h" ++#include "../include/mc-bus.h" ++#include "../include/mc-cmd.h" ++#include "../include/dpmng.h" ++ ++/** ++ * Maximum number of DPRCs that can be opened at the same time ++ */ ++#define MAX_DPRC_HANDLES 64 ++ ++/** ++ * restool_misc - information associated with the newly added miscdevice ++ * @misc: newly created miscdevice associated with root dprc ++ * @miscdevt: device id of this miscdevice ++ * @list: a linked list node representing this miscdevcie ++ * @static_mc_io: pointer to the static MC I/O object used by the restool ++ * @dynamic_instance_count: number of dynamically created instances ++ * @static_instance_in_use: static instance is in use or not ++ * @mutex: mutex lock to serialze the open/release operations ++ * @dev: root dprc associated with this miscdevice ++ */ ++struct restool_misc { ++ struct miscdevice misc; ++ dev_t miscdevt; ++ struct list_head list; ++ struct fsl_mc_io *static_mc_io; ++ u32 dynamic_instance_count; ++ bool static_instance_in_use; ++ struct mutex mutex; /* serialze the open/release operations */ ++ struct device *dev; ++}; ++ ++/** ++ * struct fsl_mc - Private data of a "fsl,qoriq-mc" platform device ++ * @root_mc_bus_dev: fsl-mc device representing the root DPRC ++ * @num_translation_ranges: number of entries in addr_translation_ranges ++ * @translation_ranges: array of bus to system address translation ranges ++ */ ++struct fsl_mc { ++ struct fsl_mc_device *root_mc_bus_dev; ++ u8 num_translation_ranges; ++ struct fsl_mc_addr_translation_range *translation_ranges; ++}; ++ ++/* ++ * initialize a global list to link all ++ * the miscdevice nodes (struct restool_misc) ++ */ ++static LIST_HEAD(misc_list); ++static DEFINE_MUTEX(misc_list_mutex); ++ ++static int fsl_mc_restool_dev_open(struct inode *inode, struct file *filep) ++{ ++ struct fsl_mc_device *root_mc_dev; ++ int error; ++ struct fsl_mc_io *dynamic_mc_io = NULL; ++ struct restool_misc *restool_misc = NULL; ++ struct restool_misc *restool_misc_cursor; ++ ++ mutex_lock(&misc_list_mutex); ++ ++ list_for_each_entry(restool_misc_cursor, &misc_list, list) { ++ if (restool_misc_cursor->miscdevt == inode->i_rdev) { ++ restool_misc = restool_misc_cursor; ++ break; ++ } ++ } ++ ++ mutex_unlock(&misc_list_mutex); ++ ++ if (!restool_misc) ++ return -EINVAL; ++ ++ if (WARN_ON(!restool_misc->dev)) ++ return -EINVAL; ++ ++ mutex_lock(&restool_misc->mutex); ++ ++ if (!restool_misc->static_instance_in_use) { ++ restool_misc->static_instance_in_use = true; ++ filep->private_data = restool_misc->static_mc_io; ++ } else { ++ dynamic_mc_io = kzalloc(sizeof(*dynamic_mc_io), GFP_KERNEL); ++ if (!dynamic_mc_io) { ++ error = -ENOMEM; ++ goto err_unlock; ++ } ++ ++ root_mc_dev = to_fsl_mc_device(restool_misc->dev); ++ error = fsl_mc_portal_allocate(root_mc_dev, 0, &dynamic_mc_io); ++ if (error < 0) { ++ pr_err("Not able to allocate MC portal\n"); ++ goto free_dynamic_mc_io; ++ } ++ ++restool_misc->dynamic_instance_count; ++ filep->private_data = dynamic_mc_io; ++ } ++ ++ mutex_unlock(&restool_misc->mutex); ++ ++ return 0; ++ ++free_dynamic_mc_io: ++ kfree(dynamic_mc_io); ++err_unlock: ++ mutex_unlock(&restool_misc->mutex); ++ ++ return error; ++} ++ ++static int fsl_mc_restool_dev_release(struct inode *inode, struct file *filep) ++{ ++ struct fsl_mc_io *local_mc_io = filep->private_data; ++ struct restool_misc *restool_misc = NULL; ++ struct restool_misc *restool_misc_cursor; ++ ++ if (WARN_ON(!filep->private_data)) ++ return -EINVAL; ++ ++ mutex_lock(&misc_list_mutex); ++ ++ list_for_each_entry(restool_misc_cursor, &misc_list, list) { ++ if (restool_misc_cursor->miscdevt == inode->i_rdev) { ++ restool_misc = restool_misc_cursor; ++ break; ++ } ++ } ++ ++ mutex_unlock(&misc_list_mutex); ++ ++ if (!restool_misc) ++ return -EINVAL; ++ ++ mutex_lock(&restool_misc->mutex); ++ ++ if (WARN_ON(restool_misc->dynamic_instance_count == 0 && ++ !restool_misc->static_instance_in_use)) { ++ mutex_unlock(&restool_misc->mutex); ++ return -EINVAL; ++ } ++ ++ /* Globally clean up opened/untracked handles */ ++ fsl_mc_portal_reset(local_mc_io); ++ ++ /* ++ * must check ++ * whether local_mc_io is dynamic or static instance ++ * Otherwise it will free up the reserved portal by accident ++ * or even not free up the dynamic allocated portal ++ * if 2 or more instances running concurrently ++ */ ++ if (local_mc_io == restool_misc->static_mc_io) { ++ restool_misc->static_instance_in_use = false; ++ } else { ++ fsl_mc_portal_free(local_mc_io); ++ kfree(filep->private_data); ++ --restool_misc->dynamic_instance_count; ++ } ++ ++ filep->private_data = NULL; ++ mutex_unlock(&restool_misc->mutex); ++ ++ return 0; ++} ++ ++static int restool_send_mc_command(unsigned long arg, ++ struct fsl_mc_io *local_mc_io) ++{ ++ int error; ++ struct mc_command mc_cmd; ++ ++ if (copy_from_user(&mc_cmd, (void __user *)arg, sizeof(mc_cmd))) ++ return -EFAULT; ++ ++ /* ++ * Send MC command to the MC: ++ */ ++ error = mc_send_command(local_mc_io, &mc_cmd); ++ if (error < 0) ++ return error; ++ ++ if (copy_to_user((void __user *)arg, &mc_cmd, sizeof(mc_cmd))) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++static long ++fsl_mc_restool_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ int error; ++ ++ switch (cmd) { ++ case RESTOOL_SEND_MC_COMMAND: ++ error = restool_send_mc_command(arg, file->private_data); ++ break; ++ default: ++ pr_err("%s: unexpected ioctl call number\n", __func__); ++ error = -EINVAL; ++ } ++ ++ return error; ++} ++ ++static const struct file_operations fsl_mc_restool_dev_fops = { ++ .owner = THIS_MODULE, ++ .open = fsl_mc_restool_dev_open, ++ .release = fsl_mc_restool_dev_release, ++ .unlocked_ioctl = fsl_mc_restool_dev_ioctl, ++}; ++ ++static int restool_add_device_file(struct device *dev) ++{ ++ u32 name1 = 0; ++ char name2[20] = {0}; ++ int error; ++ struct fsl_mc_device *root_mc_dev; ++ struct restool_misc *restool_misc; ++ ++ if (dev->bus == &platform_bus_type && dev->driver_data) { ++ if (sscanf(dev_name(dev), "%x.%s", &name1, name2) != 2) ++ return -EINVAL; ++ ++ if (strcmp(name2, "fsl-mc") == 0) ++ pr_debug("platform's root dprc name is: %s\n", ++ dev_name(&(((struct fsl_mc *) ++ (dev->driver_data))->root_mc_bus_dev->dev))); ++ } ++ ++ if (!fsl_mc_is_root_dprc(dev)) ++ return 0; ++ ++ restool_misc = kzalloc(sizeof(*restool_misc), GFP_KERNEL); ++ if (!restool_misc) ++ return -ENOMEM; ++ ++ restool_misc->dev = dev; ++ root_mc_dev = to_fsl_mc_device(dev); ++ error = fsl_mc_portal_allocate(root_mc_dev, 0, ++ &restool_misc->static_mc_io); ++ if (error < 0) { ++ pr_err("Not able to allocate MC portal\n"); ++ goto free_restool_misc; ++ } ++ ++ restool_misc->misc.minor = MISC_DYNAMIC_MINOR; ++ restool_misc->misc.name = dev_name(dev); ++ restool_misc->misc.fops = &fsl_mc_restool_dev_fops; ++ ++ error = misc_register(&restool_misc->misc); ++ if (error < 0) { ++ pr_err("misc_register() failed: %d\n", error); ++ goto free_portal; ++ } ++ ++ restool_misc->miscdevt = restool_misc->misc.this_device->devt; ++ mutex_init(&restool_misc->mutex); ++ mutex_lock(&misc_list_mutex); ++ list_add(&restool_misc->list, &misc_list); ++ mutex_unlock(&misc_list_mutex); ++ ++ pr_info("/dev/%s driver registered\n", dev_name(dev)); ++ ++ return 0; ++ ++free_portal: ++ fsl_mc_portal_free(restool_misc->static_mc_io); ++free_restool_misc: ++ kfree(restool_misc); ++ ++ return error; ++} ++ ++static int restool_bus_notifier(struct notifier_block *nb, ++ unsigned long action, void *data) ++{ ++ int error; ++ struct device *dev = data; ++ ++ switch (action) { ++ case BUS_NOTIFY_ADD_DEVICE: ++ error = restool_add_device_file(dev); ++ if (error) ++ return error; ++ break; ++ case BUS_NOTIFY_DEL_DEVICE: ++ case BUS_NOTIFY_REMOVED_DEVICE: ++ case BUS_NOTIFY_BIND_DRIVER: ++ case BUS_NOTIFY_BOUND_DRIVER: ++ case BUS_NOTIFY_UNBIND_DRIVER: ++ case BUS_NOTIFY_UNBOUND_DRIVER: ++ break; ++ default: ++ pr_err("%s: unrecognized device action from %s\n", __func__, ++ dev_name(dev)); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int add_to_restool(struct device *dev, void *data) ++{ ++ return restool_add_device_file(dev); ++} ++ ++static int __init fsl_mc_restool_driver_init(void) ++{ ++ int error; ++ struct notifier_block *nb; ++ ++ nb = kzalloc(sizeof(*nb), GFP_KERNEL); ++ if (!nb) ++ return -ENOMEM; ++ ++ nb->notifier_call = restool_bus_notifier; ++ error = bus_register_notifier(&fsl_mc_bus_type, nb); ++ if (error) ++ goto free_nb; ++ ++ /* ++ * This driver runs after fsl-mc bus driver runs. ++ * Hence, many of the root dprcs are already attached to fsl-mc bus ++ * In order to make sure we find all the root dprcs, ++ * we need to scan the fsl_mc_bus_type. ++ */ ++ error = bus_for_each_dev(&fsl_mc_bus_type, NULL, NULL, add_to_restool); ++ if (error) { ++ bus_unregister_notifier(&fsl_mc_bus_type, nb); ++ kfree(nb); ++ pr_err("restool driver registration failure\n"); ++ return error; ++ } ++ ++ return 0; ++ ++free_nb: ++ kfree(nb); ++ return error; ++} ++ ++module_init(fsl_mc_restool_driver_init); ++ ++static void __exit fsl_mc_restool_driver_exit(void) ++{ ++ struct restool_misc *restool_misc; ++ struct restool_misc *restool_misc_tmp; ++ char name1[20] = {0}; ++ u32 name2 = 0; ++ ++ list_for_each_entry_safe(restool_misc, restool_misc_tmp, ++ &misc_list, list) { ++ if (sscanf(restool_misc->misc.name, "%4s.%u", name1, &name2) ++ != 2) ++ continue; ++ ++ pr_debug("name1=%s,name2=%u\n", name1, name2); ++ pr_debug("misc-device: %s\n", restool_misc->misc.name); ++ if (strcmp(name1, "dprc") != 0) ++ continue; ++ ++ if (WARN_ON(!restool_misc->static_mc_io)) ++ return; ++ ++ if (WARN_ON(restool_misc->dynamic_instance_count != 0)) ++ return; ++ ++ if (WARN_ON(restool_misc->static_instance_in_use)) ++ return; ++ ++ misc_deregister(&restool_misc->misc); ++ pr_info("/dev/%s driver unregistered\n", ++ restool_misc->misc.name); ++ fsl_mc_portal_free(restool_misc->static_mc_io); ++ list_del(&restool_misc->list); ++ kfree(restool_misc); ++ } ++} ++ ++module_exit(fsl_mc_restool_driver_exit); ++ ++MODULE_AUTHOR("Freescale Semiconductor Inc."); ++MODULE_DESCRIPTION("Freescale's MC restool driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/staging/fsl-mc/bus/mc-sys.c b/drivers/staging/fsl-mc/bus/mc-sys.c +index 285917c7..cf63c7b6 100644 +--- a/drivers/staging/fsl-mc/bus/mc-sys.c ++++ b/drivers/staging/fsl-mc/bus/mc-sys.c +@@ -1,4 +1,5 @@ +-/* Copyright 2013-2014 Freescale Semiconductor Inc. ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. + * + * I/O services to send MC commands to the MC hardware + * +@@ -13,7 +14,6 @@ + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * +- * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any +@@ -46,7 +46,7 @@ + /** + * Timeout in milliseconds to wait for the completion of an MC command + */ +-#define MC_CMD_COMPLETION_TIMEOUT_MS 500 ++#define MC_CMD_COMPLETION_TIMEOUT_MS 15000 + + /* + * usleep_range() min and max values used to throttle down polling +@@ -67,7 +67,7 @@ static u16 mc_cmd_hdr_read_cmdid(struct mc_command *cmd) + struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header; + u16 cmd_id = le16_to_cpu(hdr->cmd_id); + +- return (cmd_id & MC_CMD_HDR_CMDID_MASK) >> MC_CMD_HDR_CMDID_SHIFT; ++ return cmd_id; + } + + static int mc_status_to_error(enum mc_cmd_status status) +@@ -200,7 +200,7 @@ static int mc_polling_wait_preemptible(struct fsl_mc_io *mc_io, + + if (time_after_eq(jiffies, jiffies_until_timeout)) { + dev_dbg(mc_io->dev, +- "MC command timed out (portal: %#llx, obj handle: %#x, command: %#x)\n", ++ "MC command timed out (portal: %#llx, dprc handle: %#x, command: %#x)\n", + mc_io->portal_phys_addr, + (unsigned int)mc_cmd_hdr_read_token(cmd), + (unsigned int)mc_cmd_hdr_read_cmdid(cmd)); +@@ -240,7 +240,7 @@ static int mc_polling_wait_atomic(struct fsl_mc_io *mc_io, + timeout_usecs -= MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS; + if (timeout_usecs == 0) { + dev_dbg(mc_io->dev, +- "MC command timed out (portal: %#llx, obj handle: %#x, command: %#x)\n", ++ "MC command timed out (portal: %#llx, dprc handle: %#x, command: %#x)\n", + mc_io->portal_phys_addr, + (unsigned int)mc_cmd_hdr_read_token(cmd), + (unsigned int)mc_cmd_hdr_read_cmdid(cmd)); +@@ -294,7 +294,7 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct mc_command *cmd) + + if (status != MC_CMD_STATUS_OK) { + dev_dbg(mc_io->dev, +- "MC command failed: portal: %#llx, obj handle: %#x, command: %#x, status: %s (%#x)\n", ++ "MC command failed: portal: %#llx, dprc handle: %#x, command: %#x, status: %s (%#x)\n", + mc_io->portal_phys_addr, + (unsigned int)mc_cmd_hdr_read_token(cmd), + (unsigned int)mc_cmd_hdr_read_cmdid(cmd), +diff --git a/drivers/staging/fsl-mc/include/dpaa2-fd.h b/drivers/staging/fsl-mc/include/dpaa2-fd.h +new file mode 100644 +index 00000000..72328415 +--- /dev/null ++++ b/drivers/staging/fsl-mc/include/dpaa2-fd.h +@@ -0,0 +1,706 @@ ++/* ++ * Copyright 2014-2016 Freescale Semiconductor Inc. ++ * Copyright 2016 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef __FSL_DPAA2_FD_H ++#define __FSL_DPAA2_FD_H ++ ++#include ++ ++/** ++ * DOC: DPAA2 FD - Frame Descriptor APIs for DPAA2 ++ * ++ * Frame Descriptors (FDs) are used to describe frame data in the DPAA2. ++ * Frames can be enqueued and dequeued to Frame Queues (FQs) which are consumed ++ * by the various DPAA accelerators (WRIOP, SEC, PME, DCE) ++ * ++ * There are three types of frames: single, scatter gather, and frame lists. ++ * ++ * The set of APIs in this file must be used to create, manipulate and ++ * query Frame Descriptors. ++ */ ++ ++/** ++ * struct dpaa2_fd - Struct describing FDs ++ * @words: for easier/faster copying the whole FD structure ++ * @addr: address in the FD ++ * @len: length in the FD ++ * @bpid: buffer pool ID ++ * @format_offset: format, offset, and short-length fields ++ * @frc: frame context ++ * @ctrl: control bits...including dd, sc, va, err, etc ++ * @flc: flow context address ++ * ++ * This structure represents the basic Frame Descriptor used in the system. ++ */ ++struct dpaa2_fd { ++ union { ++ u32 words[8]; ++ struct dpaa2_fd_simple { ++ __le64 addr; ++ __le32 len; ++ __le16 bpid; ++ __le16 format_offset; ++ __le32 frc; ++ __le32 ctrl; ++ __le64 flc; ++ } simple; ++ }; ++}; ++ ++#define FD_SHORT_LEN_FLAG_MASK 0x1 ++#define FD_SHORT_LEN_FLAG_SHIFT 14 ++#define FD_SHORT_LEN_MASK 0x3FFFF ++#define FD_OFFSET_MASK 0x0FFF ++#define FD_FORMAT_MASK 0x3 ++#define FD_FORMAT_SHIFT 12 ++#define FD_BPID_MASK 0x3FFF ++#define SG_SHORT_LEN_FLAG_MASK 0x1 ++#define SG_SHORT_LEN_FLAG_SHIFT 14 ++#define SG_SHORT_LEN_MASK 0x1FFFF ++#define SG_OFFSET_MASK 0x0FFF ++#define SG_FORMAT_MASK 0x3 ++#define SG_FORMAT_SHIFT 12 ++#define SG_BPID_MASK 0x3FFF ++#define SG_FINAL_FLAG_MASK 0x1 ++#define SG_FINAL_FLAG_SHIFT 15 ++#define FL_SHORT_LEN_FLAG_MASK 0x1 ++#define FL_SHORT_LEN_FLAG_SHIFT 14 ++#define FL_SHORT_LEN_MASK 0x3FFFF ++#define FL_OFFSET_MASK 0x0FFF ++#define FL_FORMAT_MASK 0x3 ++#define FL_FORMAT_SHIFT 12 ++#define FL_BPID_MASK 0x3FFF ++#define FL_FINAL_FLAG_MASK 0x1 ++#define FL_FINAL_FLAG_SHIFT 15 ++ ++/* Error bits in FD CTRL */ ++#define FD_CTRL_ERR_MASK 0x000000FF ++#define FD_CTRL_UFD 0x00000004 ++#define FD_CTRL_SBE 0x00000008 ++#define FD_CTRL_FLC 0x00000010 ++#define FD_CTRL_FSE 0x00000020 ++#define FD_CTRL_FAERR 0x00000040 ++ ++/* Annotation bits in FD CTRL */ ++#define FD_CTRL_PTA 0x00800000 ++#define FD_CTRL_PTV1 0x00400000 ++ ++enum dpaa2_fd_format { ++ dpaa2_fd_single = 0, ++ dpaa2_fd_list, ++ dpaa2_fd_sg ++}; ++ ++/** ++ * dpaa2_fd_get_addr() - get the addr field of frame descriptor ++ * @fd: the given frame descriptor ++ * ++ * Return the address in the frame descriptor. ++ */ ++static inline dma_addr_t dpaa2_fd_get_addr(const struct dpaa2_fd *fd) ++{ ++ return (dma_addr_t)le64_to_cpu(fd->simple.addr); ++} ++ ++/** ++ * dpaa2_fd_set_addr() - Set the addr field of frame descriptor ++ * @fd: the given frame descriptor ++ * @addr: the address needs to be set in frame descriptor ++ */ ++static inline void dpaa2_fd_set_addr(struct dpaa2_fd *fd, dma_addr_t addr) ++{ ++ fd->simple.addr = cpu_to_le64(addr); ++} ++ ++/** ++ * dpaa2_fd_get_frc() - Get the frame context in the frame descriptor ++ * @fd: the given frame descriptor ++ * ++ * Return the frame context field in the frame descriptor. ++ */ ++static inline u32 dpaa2_fd_get_frc(const struct dpaa2_fd *fd) ++{ ++ return le32_to_cpu(fd->simple.frc); ++} ++ ++/** ++ * dpaa2_fd_set_frc() - Set the frame context in the frame descriptor ++ * @fd: the given frame descriptor ++ * @frc: the frame context needs to be set in frame descriptor ++ */ ++static inline void dpaa2_fd_set_frc(struct dpaa2_fd *fd, u32 frc) ++{ ++ fd->simple.frc = cpu_to_le32(frc); ++} ++ ++/** ++ * dpaa2_fd_get_ctrl() - Get the control bits in the frame descriptor ++ * @fd: the given frame descriptor ++ * ++ * Return the control bits field in the frame descriptor. ++ */ ++static inline u32 dpaa2_fd_get_ctrl(const struct dpaa2_fd *fd) ++{ ++ return le32_to_cpu(fd->simple.ctrl); ++} ++ ++/** ++ * dpaa2_fd_set_ctrl() - Set the control bits in the frame descriptor ++ * @fd: the given frame descriptor ++ * @ctrl: the control bits to be set in the frame descriptor ++ */ ++static inline void dpaa2_fd_set_ctrl(struct dpaa2_fd *fd, u32 ctrl) ++{ ++ fd->simple.ctrl = cpu_to_le32(ctrl); ++} ++ ++/** ++ * dpaa2_fd_get_flc() - Get the flow context in the frame descriptor ++ * @fd: the given frame descriptor ++ * ++ * Return the flow context in the frame descriptor. ++ */ ++static inline dma_addr_t dpaa2_fd_get_flc(const struct dpaa2_fd *fd) ++{ ++ return (dma_addr_t)le64_to_cpu(fd->simple.flc); ++} ++ ++/** ++ * dpaa2_fd_set_flc() - Set the flow context field of frame descriptor ++ * @fd: the given frame descriptor ++ * @flc_addr: the flow context needs to be set in frame descriptor ++ */ ++static inline void dpaa2_fd_set_flc(struct dpaa2_fd *fd, dma_addr_t flc_addr) ++{ ++ fd->simple.flc = cpu_to_le64(flc_addr); ++} ++ ++static inline bool dpaa2_fd_short_len(const struct dpaa2_fd *fd) ++{ ++ return !!((le16_to_cpu(fd->simple.format_offset) >> ++ FD_SHORT_LEN_FLAG_SHIFT) & FD_SHORT_LEN_FLAG_MASK); ++} ++ ++/** ++ * dpaa2_fd_get_len() - Get the length in the frame descriptor ++ * @fd: the given frame descriptor ++ * ++ * Return the length field in the frame descriptor. ++ */ ++static inline u32 dpaa2_fd_get_len(const struct dpaa2_fd *fd) ++{ ++ if (dpaa2_fd_short_len(fd)) ++ return le32_to_cpu(fd->simple.len) & FD_SHORT_LEN_MASK; ++ ++ return le32_to_cpu(fd->simple.len); ++} ++ ++/** ++ * dpaa2_fd_set_len() - Set the length field of frame descriptor ++ * @fd: the given frame descriptor ++ * @len: the length needs to be set in frame descriptor ++ */ ++static inline void dpaa2_fd_set_len(struct dpaa2_fd *fd, u32 len) ++{ ++ fd->simple.len = cpu_to_le32(len); ++} ++ ++/** ++ * dpaa2_fd_get_offset() - Get the offset field in the frame descriptor ++ * @fd: the given frame descriptor ++ * ++ * Return the offset. ++ */ ++static inline uint16_t dpaa2_fd_get_offset(const struct dpaa2_fd *fd) ++{ ++ return le16_to_cpu(fd->simple.format_offset) & FD_OFFSET_MASK; ++} ++ ++/** ++ * dpaa2_fd_set_offset() - Set the offset field of frame descriptor ++ * @fd: the given frame descriptor ++ * @offset: the offset needs to be set in frame descriptor ++ */ ++static inline void dpaa2_fd_set_offset(struct dpaa2_fd *fd, uint16_t offset) ++{ ++ fd->simple.format_offset &= cpu_to_le16(~FD_OFFSET_MASK); ++ fd->simple.format_offset |= cpu_to_le16(offset); ++} ++ ++/** ++ * dpaa2_fd_get_format() - Get the format field in the frame descriptor ++ * @fd: the given frame descriptor ++ * ++ * Return the format. ++ */ ++static inline enum dpaa2_fd_format dpaa2_fd_get_format( ++ const struct dpaa2_fd *fd) ++{ ++ return (enum dpaa2_fd_format)((le16_to_cpu(fd->simple.format_offset) ++ >> FD_FORMAT_SHIFT) & FD_FORMAT_MASK); ++} ++ ++/** ++ * dpaa2_fd_set_format() - Set the format field of frame descriptor ++ * @fd: the given frame descriptor ++ * @format: the format needs to be set in frame descriptor ++ */ ++static inline void dpaa2_fd_set_format(struct dpaa2_fd *fd, ++ enum dpaa2_fd_format format) ++{ ++ fd->simple.format_offset &= ++ cpu_to_le16(~(FD_FORMAT_MASK << FD_FORMAT_SHIFT)); ++ fd->simple.format_offset |= cpu_to_le16(format << FD_FORMAT_SHIFT); ++} ++ ++/** ++ * dpaa2_fd_get_bpid() - Get the bpid field in the frame descriptor ++ * @fd: the given frame descriptor ++ * ++ * Return the buffer pool id. ++ */ ++static inline uint16_t dpaa2_fd_get_bpid(const struct dpaa2_fd *fd) ++{ ++ return le16_to_cpu(fd->simple.bpid) & FD_BPID_MASK; ++} ++ ++/** ++ * dpaa2_fd_set_bpid() - Set the bpid field of frame descriptor ++ * @fd: the given frame descriptor ++ * @bpid: buffer pool id to be set ++ */ ++static inline void dpaa2_fd_set_bpid(struct dpaa2_fd *fd, uint16_t bpid) ++{ ++ fd->simple.bpid &= cpu_to_le16(~(FD_BPID_MASK)); ++ fd->simple.bpid |= cpu_to_le16(bpid); ++} ++ ++/** ++ * struct dpaa2_sg_entry - the scatter-gathering structure ++ * @addr: address of the sg entry ++ * @len: length in this sg entry ++ * @bpid: buffer pool id ++ * @format_offset: format and offset fields ++ */ ++struct dpaa2_sg_entry { ++ __le64 addr; ++ __le32 len; ++ __le16 bpid; ++ __le16 format_offset; ++}; ++ ++enum dpaa2_sg_format { ++ dpaa2_sg_single = 0, ++ dpaa2_sg_frame_data, ++ dpaa2_sg_sgt_ext ++}; ++ ++/* Accessors for SG entry fields */ ++ ++/** ++ * dpaa2_sg_get_addr() - Get the address from SG entry ++ * @sg: the given scatter-gathering object ++ * ++ * Return the address. ++ */ ++static inline dma_addr_t dpaa2_sg_get_addr(const struct dpaa2_sg_entry *sg) ++{ ++ return le64_to_cpu((dma_addr_t)sg->addr); ++} ++ ++/** ++ * dpaa2_sg_set_addr() - Set the address in SG entry ++ * @sg: the given scatter-gathering object ++ * @addr: the address to be set ++ */ ++static inline void dpaa2_sg_set_addr(struct dpaa2_sg_entry *sg, dma_addr_t addr) ++{ ++ sg->addr = cpu_to_le64(addr); ++} ++ ++static inline bool dpaa2_sg_short_len(const struct dpaa2_sg_entry *sg) ++{ ++ return !!((le16_to_cpu(sg->format_offset) >> SG_SHORT_LEN_FLAG_SHIFT) ++ & SG_SHORT_LEN_FLAG_MASK); ++} ++ ++/** ++ * dpaa2_sg_get_len() - Get the length in SG entry ++ * @sg: the given scatter-gathering object ++ * ++ * Return the length. ++ */ ++static inline u32 dpaa2_sg_get_len(const struct dpaa2_sg_entry *sg) ++{ ++ if (dpaa2_sg_short_len(sg)) ++ return le32_to_cpu(sg->len) & SG_SHORT_LEN_MASK; ++ ++ return le32_to_cpu(sg->len); ++} ++ ++/** ++ * dpaa2_sg_set_len() - Set the length in SG entry ++ * @sg: the given scatter-gathering object ++ * @len: the length to be set ++ */ ++static inline void dpaa2_sg_set_len(struct dpaa2_sg_entry *sg, u32 len) ++{ ++ sg->len = cpu_to_le32(len); ++} ++ ++/** ++ * dpaa2_sg_get_offset() - Get the offset in SG entry ++ * @sg: the given scatter-gathering object ++ * ++ * Return the offset. ++ */ ++static inline u16 dpaa2_sg_get_offset(const struct dpaa2_sg_entry *sg) ++{ ++ return le16_to_cpu(sg->format_offset) & SG_OFFSET_MASK; ++} ++ ++/** ++ * dpaa2_sg_set_offset() - Set the offset in SG entry ++ * @sg: the given scatter-gathering object ++ * @offset: the offset to be set ++ */ ++static inline void dpaa2_sg_set_offset(struct dpaa2_sg_entry *sg, ++ u16 offset) ++{ ++ sg->format_offset &= cpu_to_le16(~SG_OFFSET_MASK); ++ sg->format_offset |= cpu_to_le16(offset); ++} ++ ++/** ++ * dpaa2_sg_get_format() - Get the SG format in SG entry ++ * @sg: the given scatter-gathering object ++ * ++ * Return the format. ++ */ ++static inline enum dpaa2_sg_format ++ dpaa2_sg_get_format(const struct dpaa2_sg_entry *sg) ++{ ++ return (enum dpaa2_sg_format)((le16_to_cpu(sg->format_offset) ++ >> SG_FORMAT_SHIFT) & SG_FORMAT_MASK); ++} ++ ++/** ++ * dpaa2_sg_set_format() - Set the SG format in SG entry ++ * @sg: the given scatter-gathering object ++ * @format: the format to be set ++ */ ++static inline void dpaa2_sg_set_format(struct dpaa2_sg_entry *sg, ++ enum dpaa2_sg_format format) ++{ ++ sg->format_offset &= cpu_to_le16(~(SG_FORMAT_MASK << SG_FORMAT_SHIFT)); ++ sg->format_offset |= cpu_to_le16(format << SG_FORMAT_SHIFT); ++} ++ ++/** ++ * dpaa2_sg_get_bpid() - Get the buffer pool id in SG entry ++ * @sg: the given scatter-gathering object ++ * ++ * Return the bpid. ++ */ ++static inline u16 dpaa2_sg_get_bpid(const struct dpaa2_sg_entry *sg) ++{ ++ return le16_to_cpu(sg->bpid) & SG_BPID_MASK; ++} ++ ++/** ++ * dpaa2_sg_set_bpid() - Set the buffer pool id in SG entry ++ * @sg: the given scatter-gathering object ++ * @bpid: the bpid to be set ++ */ ++static inline void dpaa2_sg_set_bpid(struct dpaa2_sg_entry *sg, u16 bpid) ++{ ++ sg->bpid &= cpu_to_le16(~(SG_BPID_MASK)); ++ sg->bpid |= cpu_to_le16(bpid); ++} ++ ++/** ++ * dpaa2_sg_is_final() - Check final bit in SG entry ++ * @sg: the given scatter-gathering object ++ * ++ * Return bool. ++ */ ++static inline bool dpaa2_sg_is_final(const struct dpaa2_sg_entry *sg) ++{ ++ return !!(le16_to_cpu(sg->format_offset) >> SG_FINAL_FLAG_SHIFT); ++} ++ ++/** ++ * dpaa2_sg_set_final() - Set the final bit in SG entry ++ * @sg: the given scatter-gathering object ++ * @final: the final boolean to be set ++ */ ++static inline void dpaa2_sg_set_final(struct dpaa2_sg_entry *sg, bool final) ++{ ++ sg->format_offset &= cpu_to_le16(~(SG_FINAL_FLAG_MASK ++ << SG_FINAL_FLAG_SHIFT)); ++ sg->format_offset |= cpu_to_le16(final << SG_FINAL_FLAG_SHIFT); ++} ++ ++/** ++ * struct dpaa2_fl_entry - structure for frame list entry. ++ * @addr: address in the FLE ++ * @len: length in the FLE ++ * @bpid: buffer pool ID ++ * @format_offset: format, offset, and short-length fields ++ * @frc: frame context ++ * @ctrl: control bits...including pta, pvt1, pvt2, err, etc ++ * @flc: flow context address ++ */ ++struct dpaa2_fl_entry { ++ __le64 addr; ++ __le32 len; ++ __le16 bpid; ++ __le16 format_offset; ++ __le32 frc; ++ __le32 ctrl; ++ __le64 flc; ++}; ++ ++enum dpaa2_fl_format { ++ dpaa2_fl_single = 0, ++ dpaa2_fl_res, ++ dpaa2_fl_sg ++}; ++ ++/** ++ * dpaa2_fl_get_addr() - get the addr field of FLE ++ * @fle: the given frame list entry ++ * ++ * Return the address in the frame list entry. ++ */ ++static inline dma_addr_t dpaa2_fl_get_addr(const struct dpaa2_fl_entry *fle) ++{ ++ return (dma_addr_t)le64_to_cpu(fle->addr); ++} ++ ++/** ++ * dpaa2_fl_set_addr() - Set the addr field of FLE ++ * @fle: the given frame list entry ++ * @addr: the address needs to be set in frame list entry ++ */ ++static inline void dpaa2_fl_set_addr(struct dpaa2_fl_entry *fle, ++ dma_addr_t addr) ++{ ++ fle->addr = cpu_to_le64(addr); ++} ++ ++/** ++ * dpaa2_fl_get_frc() - Get the frame context in the FLE ++ * @fle: the given frame list entry ++ * ++ * Return the frame context field in the frame lsit entry. ++ */ ++static inline u32 dpaa2_fl_get_frc(const struct dpaa2_fl_entry *fle) ++{ ++ return le32_to_cpu(fle->frc); ++} ++ ++/** ++ * dpaa2_fl_set_frc() - Set the frame context in the FLE ++ * @fle: the given frame list entry ++ * @frc: the frame context needs to be set in frame list entry ++ */ ++static inline void dpaa2_fl_set_frc(struct dpaa2_fl_entry *fle, u32 frc) ++{ ++ fle->frc = cpu_to_le32(frc); ++} ++ ++/** ++ * dpaa2_fl_get_ctrl() - Get the control bits in the FLE ++ * @fle: the given frame list entry ++ * ++ * Return the control bits field in the frame list entry. ++ */ ++static inline u32 dpaa2_fl_get_ctrl(const struct dpaa2_fl_entry *fle) ++{ ++ return le32_to_cpu(fle->ctrl); ++} ++ ++/** ++ * dpaa2_fl_set_ctrl() - Set the control bits in the FLE ++ * @fle: the given frame list entry ++ * @ctrl: the control bits to be set in the frame list entry ++ */ ++static inline void dpaa2_fl_set_ctrl(struct dpaa2_fl_entry *fle, u32 ctrl) ++{ ++ fle->ctrl = cpu_to_le32(ctrl); ++} ++ ++/** ++ * dpaa2_fl_get_flc() - Get the flow context in the FLE ++ * @fle: the given frame list entry ++ * ++ * Return the flow context in the frame list entry. ++ */ ++static inline dma_addr_t dpaa2_fl_get_flc(const struct dpaa2_fl_entry *fle) ++{ ++ return (dma_addr_t)le64_to_cpu(fle->flc); ++} ++ ++/** ++ * dpaa2_fl_set_flc() - Set the flow context field of FLE ++ * @fle: the given frame list entry ++ * @flc_addr: the flow context needs to be set in frame list entry ++ */ ++static inline void dpaa2_fl_set_flc(struct dpaa2_fl_entry *fle, ++ dma_addr_t flc_addr) ++{ ++ fle->flc = cpu_to_le64(flc_addr); ++} ++ ++static inline bool dpaa2_fl_short_len(const struct dpaa2_fl_entry *fle) ++{ ++ return !!((le16_to_cpu(fle->format_offset) >> ++ FL_SHORT_LEN_FLAG_SHIFT) & FL_SHORT_LEN_FLAG_MASK); ++} ++ ++/** ++ * dpaa2_fl_get_len() - Get the length in the FLE ++ * @fle: the given frame list entry ++ * ++ * Return the length field in the frame list entry. ++ */ ++static inline u32 dpaa2_fl_get_len(const struct dpaa2_fl_entry *fle) ++{ ++ if (dpaa2_fl_short_len(fle)) ++ return le32_to_cpu(fle->len) & FL_SHORT_LEN_MASK; ++ ++ return le32_to_cpu(fle->len); ++} ++ ++/** ++ * dpaa2_fl_set_len() - Set the length field of FLE ++ * @fle: the given frame list entry ++ * @len: the length needs to be set in frame list entry ++ */ ++static inline void dpaa2_fl_set_len(struct dpaa2_fl_entry *fle, u32 len) ++{ ++ fle->len = cpu_to_le32(len); ++} ++ ++/** ++ * dpaa2_fl_get_offset() - Get the offset field in the frame list entry ++ * @fle: the given frame list entry ++ * ++ * Return the offset. ++ */ ++static inline u16 dpaa2_fl_get_offset(const struct dpaa2_fl_entry *fle) ++{ ++ return le16_to_cpu(fle->format_offset) & FL_OFFSET_MASK; ++} ++ ++/** ++ * dpaa2_fl_set_offset() - Set the offset field of FLE ++ * @fle: the given frame list entry ++ * @offset: the offset needs to be set in frame list entry ++ */ ++static inline void dpaa2_fl_set_offset(struct dpaa2_fl_entry *fle, u16 offset) ++{ ++ fle->format_offset &= cpu_to_le16(~FL_OFFSET_MASK); ++ fle->format_offset |= cpu_to_le16(offset); ++} ++ ++/** ++ * dpaa2_fl_get_format() - Get the format field in the FLE ++ * @fle: the given frame list entry ++ * ++ * Return the format. ++ */ ++static inline enum dpaa2_fl_format dpaa2_fl_get_format( ++ const struct dpaa2_fl_entry *fle) ++{ ++ return (enum dpaa2_fl_format)((le16_to_cpu(fle->format_offset) >> ++ FL_FORMAT_SHIFT) & FL_FORMAT_MASK); ++} ++ ++/** ++ * dpaa2_fl_set_format() - Set the format field of FLE ++ * @fle: the given frame list entry ++ * @format: the format needs to be set in frame list entry ++ */ ++static inline void dpaa2_fl_set_format(struct dpaa2_fl_entry *fle, ++ enum dpaa2_fl_format format) ++{ ++ fle->format_offset &= cpu_to_le16(~(FL_FORMAT_MASK << FL_FORMAT_SHIFT)); ++ fle->format_offset |= cpu_to_le16(format << FL_FORMAT_SHIFT); ++} ++ ++/** ++ * dpaa2_fl_get_bpid() - Get the bpid field in the FLE ++ * @fle: the given frame list entry ++ * ++ * Return the buffer pool id. ++ */ ++static inline u16 dpaa2_fl_get_bpid(const struct dpaa2_fl_entry *fle) ++{ ++ return le16_to_cpu(fle->bpid) & FL_BPID_MASK; ++} ++ ++/** ++ * dpaa2_fl_set_bpid() - Set the bpid field of FLE ++ * @fle: the given frame list entry ++ * @bpid: buffer pool id to be set ++ */ ++static inline void dpaa2_fl_set_bpid(struct dpaa2_fl_entry *fle, u16 bpid) ++{ ++ fle->bpid &= cpu_to_le16(~(FL_BPID_MASK)); ++ fle->bpid |= cpu_to_le16(bpid); ++} ++ ++/** ++ * dpaa2_fl_is_final() - Check final bit in FLE ++ * @fle: the given frame list entry ++ * ++ * Return bool. ++ */ ++static inline bool dpaa2_fl_is_final(const struct dpaa2_fl_entry *fle) ++{ ++ return !!(le16_to_cpu(fle->format_offset) >> FL_FINAL_FLAG_SHIFT); ++} ++ ++/** ++ * dpaa2_fl_set_final() - Set the final bit in FLE ++ * @fle: the given frame list entry ++ * @final: the final boolean to be set ++ */ ++static inline void dpaa2_fl_set_final(struct dpaa2_fl_entry *fle, bool final) ++{ ++ fle->format_offset &= cpu_to_le16(~(FL_FINAL_FLAG_MASK << ++ FL_FINAL_FLAG_SHIFT)); ++ fle->format_offset |= cpu_to_le16(final << FL_FINAL_FLAG_SHIFT); ++} ++ ++#endif /* __FSL_DPAA2_FD_H */ +diff --git a/drivers/staging/fsl-mc/include/dpaa2-global.h b/drivers/staging/fsl-mc/include/dpaa2-global.h +new file mode 100644 +index 00000000..0326447f +--- /dev/null ++++ b/drivers/staging/fsl-mc/include/dpaa2-global.h +@@ -0,0 +1,202 @@ ++/* ++ * Copyright 2014-2016 Freescale Semiconductor Inc. ++ * Copyright 2016 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef __FSL_DPAA2_GLOBAL_H ++#define __FSL_DPAA2_GLOBAL_H ++ ++#include ++#include ++#include "dpaa2-fd.h" ++ ++struct dpaa2_dq { ++ union { ++ struct common { ++ u8 verb; ++ u8 reserved[63]; ++ } common; ++ struct dq { ++ u8 verb; ++ u8 stat; ++ __le16 seqnum; ++ __le16 oprid; ++ u8 reserved; ++ u8 tok; ++ __le32 fqid; ++ u32 reserved2; ++ __le32 fq_byte_cnt; ++ __le32 fq_frm_cnt; ++ __le64 fqd_ctx; ++ u8 fd[32]; ++ } dq; ++ struct scn { ++ u8 verb; ++ u8 stat; ++ u8 state; ++ u8 reserved; ++ __le32 rid_tok; ++ __le64 ctx; ++ } scn; ++ }; ++}; ++ ++/* Parsing frame dequeue results */ ++/* FQ empty */ ++#define DPAA2_DQ_STAT_FQEMPTY 0x80 ++/* FQ held active */ ++#define DPAA2_DQ_STAT_HELDACTIVE 0x40 ++/* FQ force eligible */ ++#define DPAA2_DQ_STAT_FORCEELIGIBLE 0x20 ++/* valid frame */ ++#define DPAA2_DQ_STAT_VALIDFRAME 0x10 ++/* FQ ODP enable */ ++#define DPAA2_DQ_STAT_ODPVALID 0x04 ++/* volatile dequeue */ ++#define DPAA2_DQ_STAT_VOLATILE 0x02 ++/* volatile dequeue command is expired */ ++#define DPAA2_DQ_STAT_EXPIRED 0x01 ++ ++#define DQ_FQID_MASK 0x00FFFFFF ++#define DQ_FRAME_COUNT_MASK 0x00FFFFFF ++ ++/** ++ * dpaa2_dq_flags() - Get the stat field of dequeue response ++ * @dq: the dequeue result. ++ */ ++static inline u32 dpaa2_dq_flags(const struct dpaa2_dq *dq) ++{ ++ return dq->dq.stat; ++} ++ ++/** ++ * dpaa2_dq_is_pull() - Check whether the dq response is from a pull ++ * command. ++ * @dq: the dequeue result ++ * ++ * Return 1 for volatile(pull) dequeue, 0 for static dequeue. ++ */ ++static inline int dpaa2_dq_is_pull(const struct dpaa2_dq *dq) ++{ ++ return (int)(dpaa2_dq_flags(dq) & DPAA2_DQ_STAT_VOLATILE); ++} ++ ++/** ++ * dpaa2_dq_is_pull_complete() - Check whether the pull command is completed. ++ * @dq: the dequeue result ++ * ++ * Return boolean. ++ */ ++static inline bool dpaa2_dq_is_pull_complete(const struct dpaa2_dq *dq) ++{ ++ return !!(dpaa2_dq_flags(dq) & DPAA2_DQ_STAT_EXPIRED); ++} ++ ++/** ++ * dpaa2_dq_seqnum() - Get the seqnum field in dequeue response ++ * @dq: the dequeue result ++ * ++ * seqnum is valid only if VALIDFRAME flag is TRUE ++ * ++ * Return seqnum. ++ */ ++static inline u16 dpaa2_dq_seqnum(const struct dpaa2_dq *dq) ++{ ++ return le16_to_cpu(dq->dq.seqnum); ++} ++ ++/** ++ * dpaa2_dq_odpid() - Get the odpid field in dequeue response ++ * @dq: the dequeue result ++ * ++ * odpid is valid only if ODPVALID flag is TRUE. ++ * ++ * Return odpid. ++ */ ++static inline u16 dpaa2_dq_odpid(const struct dpaa2_dq *dq) ++{ ++ return le16_to_cpu(dq->dq.oprid); ++} ++ ++/** ++ * dpaa2_dq_fqid() - Get the fqid in dequeue response ++ * @dq: the dequeue result ++ * ++ * Return fqid. ++ */ ++static inline u32 dpaa2_dq_fqid(const struct dpaa2_dq *dq) ++{ ++ return le32_to_cpu(dq->dq.fqid) & DQ_FQID_MASK; ++} ++ ++/** ++ * dpaa2_dq_byte_count() - Get the byte count in dequeue response ++ * @dq: the dequeue result ++ * ++ * Return the byte count remaining in the FQ. ++ */ ++static inline u32 dpaa2_dq_byte_count(const struct dpaa2_dq *dq) ++{ ++ return le32_to_cpu(dq->dq.fq_byte_cnt); ++} ++ ++/** ++ * dpaa2_dq_frame_count() - Get the frame count in dequeue response ++ * @dq: the dequeue result ++ * ++ * Return the frame count remaining in the FQ. ++ */ ++static inline u32 dpaa2_dq_frame_count(const struct dpaa2_dq *dq) ++{ ++ return le32_to_cpu(dq->dq.fq_frm_cnt) & DQ_FRAME_COUNT_MASK; ++} ++ ++/** ++ * dpaa2_dq_fd_ctx() - Get the frame queue context in dequeue response ++ * @dq: the dequeue result ++ * ++ * Return the frame queue context. ++ */ ++static inline u64 dpaa2_dq_fqd_ctx(const struct dpaa2_dq *dq) ++{ ++ return le64_to_cpu(dq->dq.fqd_ctx); ++} ++ ++/** ++ * dpaa2_dq_fd() - Get the frame descriptor in dequeue response ++ * @dq: the dequeue result ++ * ++ * Return the frame descriptor. ++ */ ++static inline const struct dpaa2_fd *dpaa2_dq_fd(const struct dpaa2_dq *dq) ++{ ++ return (const struct dpaa2_fd *)&dq->dq.fd[0]; ++} ++ ++#endif /* __FSL_DPAA2_GLOBAL_H */ +diff --git a/drivers/staging/fsl-mc/include/dpaa2-io.h b/drivers/staging/fsl-mc/include/dpaa2-io.h +new file mode 100644 +index 00000000..c7d1d997 +--- /dev/null ++++ b/drivers/staging/fsl-mc/include/dpaa2-io.h +@@ -0,0 +1,190 @@ ++/* ++ * Copyright 2014-2016 Freescale Semiconductor Inc. ++ * Copyright 2017 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef __FSL_DPAA2_IO_H ++#define __FSL_DPAA2_IO_H ++ ++#include ++#include ++ ++#include "dpaa2-fd.h" ++#include "dpaa2-global.h" ++ ++struct dpaa2_io; ++struct dpaa2_io_store; ++struct device; ++ ++/** ++ * DOC: DPIO Service ++ * ++ * The DPIO service provides APIs for users to interact with the datapath ++ * by enqueueing and dequeing frame descriptors. ++ * ++ * The following set of APIs can be used to enqueue and dequeue frames ++ * as well as producing notification callbacks when data is available ++ * for dequeue. ++ */ ++ ++/** ++ * struct dpaa2_io_desc - The DPIO descriptor ++ * @receives_notifications: Use notificaton mode. Non-zero if the DPIO ++ * has a channel. ++ * @has_8prio: Set to non-zero for channel with 8 priority WQs. Ignored ++ * unless receives_notification is TRUE. ++ * @cpu: The cpu index that at least interrupt handlers will ++ * execute on. ++ * @stash_affinity: The stash affinity for this portal favour 'cpu' ++ * @regs_cena: The cache enabled regs. ++ * @regs_cinh: The cache inhibited regs ++ * @dpio_id: The dpio index ++ * @qman_version: The qman version ++ * ++ * Describes the attributes and features of the DPIO object. ++ */ ++struct dpaa2_io_desc { ++ int receives_notifications; ++ int has_8prio; ++ int cpu; ++ void *regs_cena; ++ void *regs_cinh; ++ int dpio_id; ++ u32 qman_version; ++}; ++ ++struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc); ++ ++void dpaa2_io_down(struct dpaa2_io *d); ++ ++irqreturn_t dpaa2_io_irq(struct dpaa2_io *obj); ++ ++/** ++ * struct dpaa2_io_notification_ctx - The DPIO notification context structure ++ * @cb: The callback to be invoked when the notification arrives ++ * @is_cdan: Zero for FQDAN, non-zero for CDAN ++ * @id: FQID or channel ID, needed for rearm ++ * @desired_cpu: The cpu on which the notifications will show up. -1 means ++ * any CPU. ++ * @dpio_id: The dpio index ++ * @qman64: The 64-bit context value shows up in the FQDAN/CDAN. ++ * @node: The list node ++ * @dpio_private: The dpio object internal to dpio_service ++ * ++ * Used when a FQDAN/CDAN registration is made by drivers. ++ */ ++struct dpaa2_io_notification_ctx { ++ void (*cb)(struct dpaa2_io_notification_ctx *); ++ int is_cdan; ++ u32 id; ++ int desired_cpu; ++ int dpio_id; ++ u64 qman64; ++ struct list_head node; ++ void *dpio_private; ++}; ++ ++int dpaa2_io_service_register(struct dpaa2_io *service, ++ struct dpaa2_io_notification_ctx *ctx); ++void dpaa2_io_service_deregister(struct dpaa2_io *service, ++ struct dpaa2_io_notification_ctx *ctx); ++int dpaa2_io_service_rearm(struct dpaa2_io *service, ++ struct dpaa2_io_notification_ctx *ctx); ++ ++int dpaa2_io_service_pull_fq(struct dpaa2_io *d, u32 fqid, ++ struct dpaa2_io_store *s); ++int dpaa2_io_service_pull_channel(struct dpaa2_io *d, u32 channelid, ++ struct dpaa2_io_store *s); ++ ++int dpaa2_io_service_enqueue_fq(struct dpaa2_io *d, u32 fqid, ++ const struct dpaa2_fd *fd); ++int dpaa2_io_service_enqueue_qd(struct dpaa2_io *d, u32 qdid, u8 prio, ++ u16 qdbin, const struct dpaa2_fd *fd); ++int dpaa2_io_service_release(struct dpaa2_io *d, u32 bpid, ++ const u64 *buffers, unsigned int num_buffers); ++int dpaa2_io_service_acquire(struct dpaa2_io *d, u32 bpid, ++ u64 *buffers, unsigned int num_buffers); ++ ++struct dpaa2_io_store *dpaa2_io_store_create(unsigned int max_frames, ++ struct device *dev); ++void dpaa2_io_store_destroy(struct dpaa2_io_store *s); ++struct dpaa2_dq *dpaa2_io_store_next(struct dpaa2_io_store *s, int *is_last); ++ ++#ifdef CONFIG_FSL_QBMAN_DEBUG ++int dpaa2_io_query_fq_count(struct dpaa2_io *d, uint32_t fqid, ++ uint32_t *fcnt, uint32_t *bcnt); ++int dpaa2_io_query_bp_count(struct dpaa2_io *d, uint32_t bpid, ++ uint32_t *num); ++#endif ++ ++ ++/***************/ ++/* CSCN */ ++/***************/ ++ ++/** ++ * struct dpaa2_cscn - The CSCN message format ++ * @verb: identifies the type of message (should be 0x27). ++ * @stat: status bits related to dequeuing response (not used) ++ * @state: bit 0 = 0/1 if CG is no/is congested ++ * @reserved: reserved byte ++ * @cgid: congest grp ID - the first 16 bits ++ * @ctx: context data ++ * ++ * Congestion management can be implemented in software through ++ * the use of Congestion State Change Notifications (CSCN). These ++ * are messages written by DPAA2 hardware to memory whenever the ++ * instantaneous count (I_CNT field in the CG) exceeds the ++ * Congestion State (CS) entrance threshold, signifying congestion ++ * entrance, or when the instantaneous count returns below exit ++ * threshold, signifying congestion exit. The format of the message ++ * is given by the dpaa2_cscn structure. Bit 0 of the state field ++ * represents congestion state written by the hardware. ++ */ ++struct dpaa2_cscn { ++ u8 verb; ++ u8 stat; ++ u8 state; ++ u8 reserved; ++ __le32 cgid; ++ __le64 ctx; ++}; ++ ++#define DPAA2_CSCN_SIZE 64 ++#define DPAA2_CSCN_ALIGN 16 ++ ++#define DPAA2_CSCN_STATE_MASK 0x1 ++#define DPAA2_CSCN_CONGESTED 1 ++ ++static inline bool dpaa2_cscn_state_congested(struct dpaa2_cscn *cscn) ++{ ++ return ((cscn->state & DPAA2_CSCN_STATE_MASK) == DPAA2_CSCN_CONGESTED); ++} ++ ++#endif /* __FSL_DPAA2_IO_H */ +diff --git a/drivers/staging/fsl-mc/include/dpbp-cmd.h b/drivers/staging/fsl-mc/include/dpbp-cmd.h +deleted file mode 100644 +index 2860411d..00000000 +--- a/drivers/staging/fsl-mc/include/dpbp-cmd.h ++++ /dev/null +@@ -1,185 +0,0 @@ +-/* Copyright 2013-2016 Freescale Semiconductor Inc. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions are met: +- * * Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * * Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * * Neither the name of the above-listed copyright holders nor the +- * names of any contributors may be used to endorse or promote products +- * derived from this software without specific prior written permission. +- * +- * +- * ALTERNATIVELY, this software may be distributed under the terms of the +- * GNU General Public License ("GPL") as published by the Free Software +- * Foundation, either version 2 of that License or (at your option) any +- * later version. +- * +- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +- * POSSIBILITY OF SUCH DAMAGE. +- */ +-#ifndef _FSL_DPBP_CMD_H +-#define _FSL_DPBP_CMD_H +- +-/* DPBP Version */ +-#define DPBP_VER_MAJOR 2 +-#define DPBP_VER_MINOR 2 +- +-/* Command IDs */ +-#define DPBP_CMDID_CLOSE 0x800 +-#define DPBP_CMDID_OPEN 0x804 +-#define DPBP_CMDID_CREATE 0x904 +-#define DPBP_CMDID_DESTROY 0x900 +- +-#define DPBP_CMDID_ENABLE 0x002 +-#define DPBP_CMDID_DISABLE 0x003 +-#define DPBP_CMDID_GET_ATTR 0x004 +-#define DPBP_CMDID_RESET 0x005 +-#define DPBP_CMDID_IS_ENABLED 0x006 +- +-#define DPBP_CMDID_SET_IRQ 0x010 +-#define DPBP_CMDID_GET_IRQ 0x011 +-#define DPBP_CMDID_SET_IRQ_ENABLE 0x012 +-#define DPBP_CMDID_GET_IRQ_ENABLE 0x013 +-#define DPBP_CMDID_SET_IRQ_MASK 0x014 +-#define DPBP_CMDID_GET_IRQ_MASK 0x015 +-#define DPBP_CMDID_GET_IRQ_STATUS 0x016 +-#define DPBP_CMDID_CLEAR_IRQ_STATUS 0x017 +- +-#define DPBP_CMDID_SET_NOTIFICATIONS 0x01b0 +-#define DPBP_CMDID_GET_NOTIFICATIONS 0x01b1 +- +-struct dpbp_cmd_open { +- __le32 dpbp_id; +-}; +- +-#define DPBP_ENABLE 0x1 +- +-struct dpbp_rsp_is_enabled { +- u8 enabled; +-}; +- +-struct dpbp_cmd_set_irq { +- /* cmd word 0 */ +- u8 irq_index; +- u8 pad[3]; +- __le32 irq_val; +- /* cmd word 1 */ +- __le64 irq_addr; +- /* cmd word 2 */ +- __le32 irq_num; +-}; +- +-struct dpbp_cmd_get_irq { +- __le32 pad; +- u8 irq_index; +-}; +- +-struct dpbp_rsp_get_irq { +- /* response word 0 */ +- __le32 irq_val; +- __le32 pad; +- /* response word 1 */ +- __le64 irq_addr; +- /* response word 2 */ +- __le32 irq_num; +- __le32 type; +-}; +- +-struct dpbp_cmd_set_irq_enable { +- u8 enable; +- u8 pad[3]; +- u8 irq_index; +-}; +- +-struct dpbp_cmd_get_irq_enable { +- __le32 pad; +- u8 irq_index; +-}; +- +-struct dpbp_rsp_get_irq_enable { +- u8 enabled; +-}; +- +-struct dpbp_cmd_set_irq_mask { +- __le32 mask; +- u8 irq_index; +-}; +- +-struct dpbp_cmd_get_irq_mask { +- __le32 pad; +- u8 irq_index; +-}; +- +-struct dpbp_rsp_get_irq_mask { +- __le32 mask; +-}; +- +-struct dpbp_cmd_get_irq_status { +- __le32 status; +- u8 irq_index; +-}; +- +-struct dpbp_rsp_get_irq_status { +- __le32 status; +-}; +- +-struct dpbp_cmd_clear_irq_status { +- __le32 status; +- u8 irq_index; +-}; +- +-struct dpbp_rsp_get_attributes { +- /* response word 0 */ +- __le16 pad; +- __le16 bpid; +- __le32 id; +- /* response word 1 */ +- __le16 version_major; +- __le16 version_minor; +-}; +- +-struct dpbp_cmd_set_notifications { +- /* cmd word 0 */ +- __le32 depletion_entry; +- __le32 depletion_exit; +- /* cmd word 1 */ +- __le32 surplus_entry; +- __le32 surplus_exit; +- /* cmd word 2 */ +- __le16 options; +- __le16 pad[3]; +- /* cmd word 3 */ +- __le64 message_ctx; +- /* cmd word 4 */ +- __le64 message_iova; +-}; +- +-struct dpbp_rsp_get_notifications { +- /* response word 0 */ +- __le32 depletion_entry; +- __le32 depletion_exit; +- /* response word 1 */ +- __le32 surplus_entry; +- __le32 surplus_exit; +- /* response word 2 */ +- __le16 options; +- __le16 pad[3]; +- /* response word 3 */ +- __le64 message_ctx; +- /* response word 4 */ +- __le64 message_iova; +-}; +- +-#endif /* _FSL_DPBP_CMD_H */ +diff --git a/drivers/staging/fsl-mc/include/dpbp.h b/drivers/staging/fsl-mc/include/dpbp.h +index e14e85a5..e9e04cce 100644 +--- a/drivers/staging/fsl-mc/include/dpbp.h ++++ b/drivers/staging/fsl-mc/include/dpbp.h +@@ -1,4 +1,5 @@ +-/* Copyright 2013-2015 Freescale Semiconductor Inc. ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -32,7 +33,8 @@ + #ifndef __FSL_DPBP_H + #define __FSL_DPBP_H + +-/* Data Path Buffer Pool API ++/* ++ * Data Path Buffer Pool API + * Contains initialization APIs and runtime control APIs for DPBP + */ + +@@ -44,25 +46,8 @@ int dpbp_open(struct fsl_mc_io *mc_io, + u16 *token); + + int dpbp_close(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token); +- +-/** +- * struct dpbp_cfg - Structure representing DPBP configuration +- * @options: place holder +- */ +-struct dpbp_cfg { +- u32 options; +-}; +- +-int dpbp_create(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- const struct dpbp_cfg *cfg, +- u16 *token); +- +-int dpbp_destroy(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token); ++ u32 cmd_flags, ++ u16 token); + + int dpbp_enable(struct fsl_mc_io *mc_io, + u32 cmd_flags, +@@ -81,140 +66,25 @@ int dpbp_reset(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +-/** +- * struct dpbp_irq_cfg - IRQ configuration +- * @addr: Address that must be written to signal a message-based interrupt +- * @val: Value to write into irq_addr address +- * @irq_num: A user defined number associated with this IRQ +- */ +-struct dpbp_irq_cfg { +- u64 addr; +- u32 val; +- int irq_num; +-}; +- +-int dpbp_set_irq(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- struct dpbp_irq_cfg *irq_cfg); +- +-int dpbp_get_irq(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- int *type, +- struct dpbp_irq_cfg *irq_cfg); +- +-int dpbp_set_irq_enable(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u8 en); +- +-int dpbp_get_irq_enable(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u8 *en); +- +-int dpbp_set_irq_mask(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 mask); +- +-int dpbp_get_irq_mask(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 *mask); +- +-int dpbp_get_irq_status(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 *status); +- +-int dpbp_clear_irq_status(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 status); +- + /** + * struct dpbp_attr - Structure representing DPBP attributes + * @id: DPBP object ID +- * @version: DPBP version + * @bpid: Hardware buffer pool ID; should be used as an argument in + * acquire/release operations on buffers + */ + struct dpbp_attr { + int id; +- /** +- * struct version - Structure representing DPBP version +- * @major: DPBP major version +- * @minor: DPBP minor version +- */ +- struct { +- u16 major; +- u16 minor; +- } version; + u16 bpid; + }; + +-int dpbp_get_attributes(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- struct dpbp_attr *attr); +- +-/** +- * DPBP notifications options +- */ +- +-/** +- * BPSCN write will attempt to allocate into a cache (coherent write) +- */ +-#define DPBP_NOTIF_OPT_COHERENT_WRITE 0x00000001 +- +-/** +- * struct dpbp_notification_cfg - Structure representing DPBP notifications +- * towards software +- * @depletion_entry: below this threshold the pool is "depleted"; +- * set it to '0' to disable it +- * @depletion_exit: greater than or equal to this threshold the pool exit its +- * "depleted" state +- * @surplus_entry: above this threshold the pool is in "surplus" state; +- * set it to '0' to disable it +- * @surplus_exit: less than or equal to this threshold the pool exit its +- * "surplus" state +- * @message_iova: MUST be given if either 'depletion_entry' or 'surplus_entry' +- * is not '0' (enable); I/O virtual address (must be in DMA-able memory), +- * must be 16B aligned. +- * @message_ctx: The context that will be part of the BPSCN message and will +- * be written to 'message_iova' +- * @options: Mask of available options; use 'DPBP_NOTIF_OPT_' values +- */ +-struct dpbp_notification_cfg { +- u32 depletion_entry; +- u32 depletion_exit; +- u32 surplus_entry; +- u32 surplus_exit; +- u64 message_iova; +- u64 message_ctx; +- u16 options; +-}; +- +-int dpbp_set_notifications(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- struct dpbp_notification_cfg *cfg); +- +-int dpbp_get_notifications(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- struct dpbp_notification_cfg *cfg); ++int dpbp_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpbp_attr *attr); + +-/** @} */ ++int dpbp_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver); + + #endif /* __FSL_DPBP_H */ +diff --git a/drivers/staging/fsl-mc/include/dpcon.h b/drivers/staging/fsl-mc/include/dpcon.h +new file mode 100644 +index 00000000..efa23906 +--- /dev/null ++++ b/drivers/staging/fsl-mc/include/dpcon.h +@@ -0,0 +1,115 @@ ++/* Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef __FSL_DPCON_H ++#define __FSL_DPCON_H ++ ++/* Data Path Concentrator API ++ * Contains initialization APIs and runtime control APIs for DPCON ++ */ ++ ++struct fsl_mc_io; ++ ++/** General DPCON macros */ ++ ++/** ++ * Use it to disable notifications; see dpcon_set_notification() ++ */ ++#define DPCON_INVALID_DPIO_ID (int)(-1) ++ ++int dpcon_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpcon_id, ++ u16 *token); ++ ++int dpcon_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpcon_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpcon_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpcon_is_enabled(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int *en); ++ ++int dpcon_reset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++/** ++ * struct dpcon_attr - Structure representing DPCON attributes ++ * @id: DPCON object ID ++ * @qbman_ch_id: Channel ID to be used by dequeue operation ++ * @num_priorities: Number of priorities for the DPCON channel (1-8) ++ */ ++struct dpcon_attr { ++ int id; ++ u16 qbman_ch_id; ++ u8 num_priorities; ++}; ++ ++int dpcon_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpcon_attr *attr); ++ ++/** ++ * struct dpcon_notification_cfg - Structure representing notification params ++ * @dpio_id: DPIO object ID; must be configured with a notification channel; ++ * to disable notifications set it to 'DPCON_INVALID_DPIO_ID'; ++ * @priority: Priority selection within the DPIO channel; valid values ++ * are 0-7, depending on the number of priorities in that channel ++ * @user_ctx: User context value provided with each CDAN message ++ */ ++struct dpcon_notification_cfg { ++ int dpio_id; ++ u8 priority; ++ u64 user_ctx; ++}; ++ ++int dpcon_set_notification(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpcon_notification_cfg *cfg); ++ ++int dpcon_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver); ++ ++#endif /* __FSL_DPCON_H */ +diff --git a/drivers/staging/fsl-mc/include/dpmng.h b/drivers/staging/fsl-mc/include/dpmng.h +index e5cfd017..170c07dd 100644 +--- a/drivers/staging/fsl-mc/include/dpmng.h ++++ b/drivers/staging/fsl-mc/include/dpmng.h +@@ -1,4 +1,5 @@ +-/* Copyright 2013-2015 Freescale Semiconductor Inc. ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -32,7 +33,8 @@ + #ifndef __FSL_DPMNG_H + #define __FSL_DPMNG_H + +-/* Management Complex General API ++/* ++ * Management Complex General API + * Contains general API for the Management Complex firmware + */ + +@@ -58,12 +60,8 @@ struct mc_version { + u32 revision; + }; + +-int mc_get_version(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- struct mc_version *mc_ver_info); +- +-int dpmng_get_container_id(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- int *container_id); ++int mc_get_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ struct mc_version *mc_ver_info); + + #endif /* __FSL_DPMNG_H */ +diff --git a/drivers/staging/fsl-mc/include/dpopr.h b/drivers/staging/fsl-mc/include/dpopr.h +new file mode 100644 +index 00000000..e1110af2 +--- /dev/null ++++ b/drivers/staging/fsl-mc/include/dpopr.h +@@ -0,0 +1,110 @@ ++/* ++ * Copyright 2017 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef __FSL_DPOPR_H_ ++#define __FSL_DPOPR_H_ ++ ++/* Data Path Order Restoration API ++ * Contains initialization APIs and runtime APIs for the Order Restoration ++ */ ++ ++/** Order Restoration properties */ ++ ++/** ++ * Create a new Order Point Record option ++ */ ++#define OPR_OPT_CREATE 0x1 ++/** ++ * Retire an existing Order Point Record option ++ */ ++#define OPR_OPT_RETIRE 0x2 ++ ++/** ++ * struct opr_cfg - Structure representing OPR configuration ++ * @oprrws: Order point record (OPR) restoration window size (0 to 5) ++ * 0 - Window size is 32 frames. ++ * 1 - Window size is 64 frames. ++ * 2 - Window size is 128 frames. ++ * 3 - Window size is 256 frames. ++ * 4 - Window size is 512 frames. ++ * 5 - Window size is 1024 frames. ++ * @oa: OPR auto advance NESN window size (0 disabled, 1 enabled) ++ * @olws: OPR acceptable late arrival window size (0 to 3) ++ * 0 - Disabled. Late arrivals are always rejected. ++ * 1 - Window size is 32 frames. ++ * 2 - Window size is the same as the OPR restoration ++ * window size configured in the OPRRWS field. ++ * 3 - Window size is 8192 frames. Late arrivals are ++ * always accepted. ++ * @oeane: Order restoration list (ORL) resource exhaustion ++ * advance NESN enable (0 disabled, 1 enabled) ++ * @oloe: OPR loose ordering enable (0 disabled, 1 enabled) ++ */ ++struct opr_cfg { ++ u8 oprrws; ++ u8 oa; ++ u8 olws; ++ u8 oeane; ++ u8 oloe; ++}; ++ ++/** ++ * struct opr_qry - Structure representing OPR configuration ++ * @enable: Enabled state ++ * @rip: Retirement In Progress ++ * @ndsn: Next dispensed sequence number ++ * @nesn: Next expected sequence number ++ * @ea_hseq: Early arrival head sequence number ++ * @hseq_nlis: HSEQ not last in sequence ++ * @ea_tseq: Early arrival tail sequence number ++ * @tseq_nlis: TSEQ not last in sequence ++ * @ea_tptr: Early arrival tail pointer ++ * @ea_hptr: Early arrival head pointer ++ * @opr_id: Order Point Record ID ++ * @opr_vid: Order Point Record Virtual ID ++ */ ++struct opr_qry { ++ char enable; ++ char rip; ++ u16 ndsn; ++ u16 nesn; ++ u16 ea_hseq; ++ char hseq_nlis; ++ u16 ea_tseq; ++ char tseq_nlis; ++ u16 ea_tptr; ++ u16 ea_hptr; ++ u16 opr_id; ++ u16 opr_vid; ++}; ++ ++#endif /* __FSL_DPOPR_H_ */ +diff --git a/drivers/staging/fsl-mc/include/dprc.h b/drivers/staging/fsl-mc/include/dprc.h +index 593b2bbe..8dc411ec 100644 +--- a/drivers/staging/fsl-mc/include/dprc.h ++++ b/drivers/staging/fsl-mc/include/dprc.h +@@ -1,4 +1,5 @@ +-/* Copyright 2013-2015 Freescale Semiconductor Inc. ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -34,26 +35,13 @@ + + #include "mc-cmd.h" + +-/* Data Path Resource Container API ++/* ++ * Data Path Resource Container API + * Contains DPRC API for managing and querying DPAA resources + */ + + struct fsl_mc_io; + +-/** +- * Set this value as the icid value in dprc_cfg structure when creating a +- * container, in case the ICID is not selected by the user and should be +- * allocated by the DPRC from the pool of ICIDs. +- */ +-#define DPRC_GET_ICID_FROM_POOL (u16)(~(0)) +- +-/** +- * Set this value as the portal_id value in dprc_cfg structure when creating a +- * container, in case the portal ID is not specifically selected by the +- * user and should be allocated by the DPRC from the pool of portal ids. +- */ +-#define DPRC_GET_PORTAL_ID_FROM_POOL (int)(~(0)) +- + int dprc_open(struct fsl_mc_io *mc_io, + u32 cmd_flags, + int container_id, +@@ -63,75 +51,6 @@ int dprc_close(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +-/** +- * Container general options +- * +- * These options may be selected at container creation by the container creator +- * and can be retrieved using dprc_get_attributes() +- */ +- +-/* Spawn Policy Option allowed - Indicates that the new container is allowed +- * to spawn and have its own child containers. +- */ +-#define DPRC_CFG_OPT_SPAWN_ALLOWED 0x00000001 +- +-/* General Container allocation policy - Indicates that the new container is +- * allowed to allocate requested resources from its parent container; if not +- * set, the container is only allowed to use resources in its own pools; Note +- * that this is a container's global policy, but the parent container may +- * override it and set specific quota per resource type. +- */ +-#define DPRC_CFG_OPT_ALLOC_ALLOWED 0x00000002 +- +-/* Object initialization allowed - software context associated with this +- * container is allowed to invoke object initialization operations. +- */ +-#define DPRC_CFG_OPT_OBJ_CREATE_ALLOWED 0x00000004 +- +-/* Topology change allowed - software context associated with this +- * container is allowed to invoke topology operations, such as attach/detach +- * of network objects. +- */ +-#define DPRC_CFG_OPT_TOPOLOGY_CHANGES_ALLOWED 0x00000008 +- +-/* AIOP - Indicates that container belongs to AIOP. */ +-#define DPRC_CFG_OPT_AIOP 0x00000020 +- +-/* IRQ Config - Indicates that the container allowed to configure its IRQs. */ +-#define DPRC_CFG_OPT_IRQ_CFG_ALLOWED 0x00000040 +- +-/** +- * struct dprc_cfg - Container configuration options +- * @icid: Container's ICID; if set to 'DPRC_GET_ICID_FROM_POOL', a free +- * ICID value is allocated by the DPRC +- * @portal_id: Portal ID; if set to 'DPRC_GET_PORTAL_ID_FROM_POOL', a free +- * portal ID is allocated by the DPRC +- * @options: Combination of 'DPRC_CFG_OPT_' options +- * @label: Object's label +- */ +-struct dprc_cfg { +- u16 icid; +- int portal_id; +- u64 options; +- char label[16]; +-}; +- +-int dprc_create_container(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- struct dprc_cfg *cfg, +- int *child_container_id, +- u64 *child_portal_offset); +- +-int dprc_destroy_container(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int child_container_id); +- +-int dprc_reset_container(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int child_container_id); + + /* IRQ */ + +@@ -139,7 +58,7 @@ int dprc_reset_container(struct fsl_mc_io *mc_io, + #define DPRC_IRQ_INDEX 0 + + /* Number of dprc's IRQs */ +-#define DPRC_NUM_OF_IRQS 1 ++#define DPRC_NUM_OF_IRQS 1 + + /* DPRC IRQ events */ + +@@ -151,12 +70,14 @@ int dprc_reset_container(struct fsl_mc_io *mc_io, + #define DPRC_IRQ_EVENT_RES_ADDED 0x00000004 + /* IRQ event - Indicates that resources removed from the container */ + #define DPRC_IRQ_EVENT_RES_REMOVED 0x00000008 +-/* IRQ event - Indicates that one of the descendant containers that opened by ++/* ++ * IRQ event - Indicates that one of the descendant containers that opened by + * this container is destroyed + */ + #define DPRC_IRQ_EVENT_CONTAINER_DESTROYED 0x00000010 + +-/* IRQ event - Indicates that on one of the container's opened object is ++/* ++ * IRQ event - Indicates that on one of the container's opened object is + * destroyed + */ + #define DPRC_IRQ_EVENT_OBJ_DESTROYED 0x00000020 +@@ -171,59 +92,59 @@ int dprc_reset_container(struct fsl_mc_io *mc_io, + * @irq_num: A user defined number associated with this IRQ + */ + struct dprc_irq_cfg { +- phys_addr_t paddr; +- u32 val; +- int irq_num; ++ phys_addr_t paddr; ++ u32 val; ++ int irq_num; + }; + +-int dprc_set_irq(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- struct dprc_irq_cfg *irq_cfg); +- +-int dprc_get_irq(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- int *type, +- struct dprc_irq_cfg *irq_cfg); +- +-int dprc_set_irq_enable(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u8 en); +- +-int dprc_get_irq_enable(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u8 *en); +- +-int dprc_set_irq_mask(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 mask); +- +-int dprc_get_irq_mask(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 *mask); +- +-int dprc_get_irq_status(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 *status); +- +-int dprc_clear_irq_status(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- u8 irq_index, +- u32 status); ++int dprc_set_irq(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ struct dprc_irq_cfg *irq_cfg); ++ ++int dprc_get_irq(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ int *type, ++ struct dprc_irq_cfg *irq_cfg); ++ ++int dprc_set_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 en); ++ ++int dprc_get_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 *en); ++ ++int dprc_set_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 mask); ++ ++int dprc_get_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *mask); ++ ++int dprc_get_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *status); ++ ++int dprc_clear_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 status); + + /** + * struct dprc_attributes - Container attributes +@@ -231,114 +152,23 @@ int dprc_clear_irq_status(struct fsl_mc_io *mc_io, + * @icid: Container's ICID + * @portal_id: Container's portal ID + * @options: Container's options as set at container's creation +- * @version: DPRC version + */ + struct dprc_attributes { + int container_id; + u16 icid; + int portal_id; + u64 options; +- /** +- * struct version - DPRC version +- * @major: DPRC major version +- * @minor: DPRC minor version +- */ +- struct { +- u16 major; +- u16 minor; +- } version; +-}; +- +-int dprc_get_attributes(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- struct dprc_attributes *attributes); +- +-int dprc_set_res_quota(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int child_container_id, +- char *type, +- u16 quota); +- +-int dprc_get_res_quota(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int child_container_id, +- char *type, +- u16 *quota); +- +-/* Resource request options */ +- +-/* Explicit resource ID request - The requested objects/resources +- * are explicit and sequential (in case of resources). +- * The base ID is given at res_req at base_align field +- */ +-#define DPRC_RES_REQ_OPT_EXPLICIT 0x00000001 +- +-/* Aligned resources request - Relevant only for resources +- * request (and not objects). Indicates that resources base ID should be +- * sequential and aligned to the value given at dprc_res_req base_align field +- */ +-#define DPRC_RES_REQ_OPT_ALIGNED 0x00000002 +- +-/* Plugged Flag - Relevant only for object assignment request. +- * Indicates that after all objects assigned. An interrupt will be invoked at +- * the relevant GPP. The assigned object will be marked as plugged. +- * plugged objects can't be assigned from their container +- */ +-#define DPRC_RES_REQ_OPT_PLUGGED 0x00000004 +- +-/** +- * struct dprc_res_req - Resource request descriptor, to be used in assignment +- * or un-assignment of resources and objects. +- * @type: Resource/object type: Represent as a NULL terminated string. +- * This string may received by using dprc_get_pool() to get resource +- * type and dprc_get_obj() to get object type; +- * Note: it is not possible to assign/un-assign DPRC objects +- * @num: Number of resources +- * @options: Request options: combination of DPRC_RES_REQ_OPT_ options +- * @id_base_align: In case of explicit assignment (DPRC_RES_REQ_OPT_EXPLICIT +- * is set at option), this field represents the required base ID +- * for resource allocation; In case of aligned assignment +- * (DPRC_RES_REQ_OPT_ALIGNED is set at option), this field +- * indicates the required alignment for the resource ID(s) - +- * use 0 if there is no alignment or explicit ID requirements +- */ +-struct dprc_res_req { +- char type[16]; +- u32 num; +- u32 options; +- int id_base_align; + }; + +-int dprc_assign(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int container_id, +- struct dprc_res_req *res_req); +- +-int dprc_unassign(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int child_container_id, +- struct dprc_res_req *res_req); +- +-int dprc_get_pool_count(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int *pool_count); +- +-int dprc_get_pool(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int pool_index, +- char *type); ++int dprc_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dprc_attributes *attributes); + + int dprc_get_obj_count(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int *obj_count); ++ u32 cmd_flags, ++ u16 token, ++ int *obj_count); + + /* Objects Attributes Flags */ + +@@ -353,7 +183,7 @@ int dprc_get_obj_count(struct fsl_mc_io *mc_io, + * masters; + * user is responsible for proper memory handling through IOMMU configuration. + */ +-#define DPRC_OBJ_FLAG_NO_MEM_SHAREABILITY 0x0001 ++#define DPRC_OBJ_FLAG_NO_MEM_SHAREABILITY 0x0001 + + /** + * struct dprc_obj_desc - Object descriptor, returned from dprc_get_obj() +@@ -381,41 +211,41 @@ struct dprc_obj_desc { + u16 flags; + }; + +-int dprc_get_obj(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- int obj_index, +- struct dprc_obj_desc *obj_desc); +- +-int dprc_get_obj_desc(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- char *obj_type, +- int obj_id, +- struct dprc_obj_desc *obj_desc); +- +-int dprc_set_obj_irq(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- char *obj_type, +- int obj_id, +- u8 irq_index, +- struct dprc_irq_cfg *irq_cfg); +- +-int dprc_get_obj_irq(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- char *obj_type, +- int obj_id, +- u8 irq_index, +- int *type, +- struct dprc_irq_cfg *irq_cfg); +- +-int dprc_get_res_count(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- char *type, +- int *res_count); ++int dprc_get_obj(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int obj_index, ++ struct dprc_obj_desc *obj_desc); ++ ++int dprc_get_obj_desc(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ char *obj_type, ++ int obj_id, ++ struct dprc_obj_desc *obj_desc); ++ ++int dprc_set_obj_irq(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ char *obj_type, ++ int obj_id, ++ u8 irq_index, ++ struct dprc_irq_cfg *irq_cfg); ++ ++int dprc_get_obj_irq(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ char *obj_type, ++ int obj_id, ++ u8 irq_index, ++ int *type, ++ struct dprc_irq_cfg *irq_cfg); ++ ++int dprc_get_res_count(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ char *type, ++ int *res_count); + + /** + * enum dprc_iter_status - Iteration status +@@ -429,27 +259,6 @@ enum dprc_iter_status { + DPRC_ITER_STATUS_LAST = 2 + }; + +-/** +- * struct dprc_res_ids_range_desc - Resource ID range descriptor +- * @base_id: Base resource ID of this range +- * @last_id: Last resource ID of this range +- * @iter_status: Iteration status - should be set to DPRC_ITER_STATUS_FIRST at +- * first iteration; while the returned marker is DPRC_ITER_STATUS_MORE, +- * additional iterations are needed, until the returned marker is +- * DPRC_ITER_STATUS_LAST +- */ +-struct dprc_res_ids_range_desc { +- int base_id; +- int last_id; +- enum dprc_iter_status iter_status; +-}; +- +-int dprc_get_res_ids(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- char *type, +- struct dprc_res_ids_range_desc *range_desc); +- + /* Region flags */ + /* Cacheable - Indicates that region should be mapped as cacheable */ + #define DPRC_REGION_CACHEABLE 0x00000001 +@@ -481,64 +290,27 @@ struct dprc_region_desc { + enum dprc_region_type type; + }; + +-int dprc_get_obj_region(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- char *obj_type, +- int obj_id, +- u8 region_index, +- struct dprc_region_desc *region_desc); +- +-int dprc_set_obj_label(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- char *obj_type, +- int obj_id, +- char *label); ++int dprc_get_obj_region(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ char *obj_type, ++ int obj_id, ++ u8 region_index, ++ struct dprc_region_desc *region_desc); + +-/** +- * struct dprc_endpoint - Endpoint description for link connect/disconnect +- * operations +- * @type: Endpoint object type: NULL terminated string +- * @id: Endpoint object ID +- * @if_id: Interface ID; should be set for endpoints with multiple +- * interfaces ("dpsw", "dpdmux"); for others, always set to 0 +- */ +-struct dprc_endpoint { +- char type[16]; +- int id; +- int if_id; +-}; ++int dprc_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver); + +-/** +- * struct dprc_connection_cfg - Connection configuration. +- * Used for virtual connections only +- * @committed_rate: Committed rate (Mbits/s) +- * @max_rate: Maximum rate (Mbits/s) +- */ +-struct dprc_connection_cfg { +- u32 committed_rate; +- u32 max_rate; +-}; ++int dprc_get_container_id(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int *container_id); + +-int dprc_connect(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- const struct dprc_endpoint *endpoint1, +- const struct dprc_endpoint *endpoint2, +- const struct dprc_connection_cfg *cfg); +- +-int dprc_disconnect(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- const struct dprc_endpoint *endpoint); +- +-int dprc_get_connection(struct fsl_mc_io *mc_io, +- u32 cmd_flags, +- u16 token, +- const struct dprc_endpoint *endpoint1, +- struct dprc_endpoint *endpoint2, +- int *state); ++int dprc_reset_container(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int child_container_id); + + #endif /* _FSL_DPRC_H */ + +diff --git a/drivers/staging/fsl-mc/include/mc-bus.h b/drivers/staging/fsl-mc/include/mc-bus.h +index 170684a5..4d1f2d3e 100644 +--- a/drivers/staging/fsl-mc/include/mc-bus.h ++++ b/drivers/staging/fsl-mc/include/mc-bus.h +@@ -1,7 +1,7 @@ + /* + * Freescale Management Complex (MC) bus declarations + * +- * Copyright (C) 2014 Freescale Semiconductor, Inc. ++ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. + * Author: German Rivera + * + * This file is licensed under the terms of the GNU General Public +@@ -42,8 +42,8 @@ struct msi_domain_info; + */ + struct fsl_mc_resource_pool { + enum fsl_mc_pool_type type; +- int16_t max_count; +- int16_t free_count; ++ int max_count; ++ int free_count; + struct mutex mutex; /* serializes access to free_list */ + struct list_head free_list; + struct fsl_mc_bus *mc_bus; +@@ -73,6 +73,7 @@ struct fsl_mc_bus { + int dprc_scan_container(struct fsl_mc_device *mc_bus_dev); + + int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev, ++ const char *driver_override, + unsigned int *total_irq_count); + + int __init dprc_driver_init(void); +diff --git a/drivers/staging/fsl-mc/include/mc-cmd.h b/drivers/staging/fsl-mc/include/mc-cmd.h +index 5decb989..2e08aa31 100644 +--- a/drivers/staging/fsl-mc/include/mc-cmd.h ++++ b/drivers/staging/fsl-mc/include/mc-cmd.h +@@ -1,4 +1,5 @@ +-/* Copyright 2013-2015 Freescale Semiconductor Inc. ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -48,6 +49,15 @@ struct mc_command { + u64 params[MC_CMD_NUM_OF_PARAMS]; + }; + ++struct mc_rsp_create { ++ __le32 object_id; ++}; ++ ++struct mc_rsp_api_ver { ++ __le16 major_ver; ++ __le16 minor_ver; ++}; ++ + enum mc_cmd_status { + MC_CMD_STATUS_OK = 0x0, /* Completed successfully */ + MC_CMD_STATUS_READY = 0x1, /* Ready to be processed */ +@@ -72,11 +82,6 @@ enum mc_cmd_status { + /* Command completion flag */ + #define MC_CMD_FLAG_INTR_DIS 0x01 + +-#define MC_CMD_HDR_CMDID_MASK 0xFFF0 +-#define MC_CMD_HDR_CMDID_SHIFT 4 +-#define MC_CMD_HDR_TOKEN_MASK 0xFFC0 +-#define MC_CMD_HDR_TOKEN_SHIFT 6 +- + static inline u64 mc_encode_cmd_header(u16 cmd_id, + u32 cmd_flags, + u16 token) +@@ -84,10 +89,8 @@ static inline u64 mc_encode_cmd_header(u16 cmd_id, + u64 header = 0; + struct mc_cmd_header *hdr = (struct mc_cmd_header *)&header; + +- hdr->cmd_id = cpu_to_le16((cmd_id << MC_CMD_HDR_CMDID_SHIFT) & +- MC_CMD_HDR_CMDID_MASK); +- hdr->token = cpu_to_le16((token << MC_CMD_HDR_TOKEN_SHIFT) & +- MC_CMD_HDR_TOKEN_MASK); ++ hdr->cmd_id = cpu_to_le16(cmd_id); ++ hdr->token = cpu_to_le16(token); + hdr->status = MC_CMD_STATUS_READY; + if (cmd_flags & MC_CMD_FLAG_PRI) + hdr->flags_hw = MC_CMD_FLAG_PRI; +@@ -102,7 +105,26 @@ static inline u16 mc_cmd_hdr_read_token(struct mc_command *cmd) + struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header; + u16 token = le16_to_cpu(hdr->token); + +- return (token & MC_CMD_HDR_TOKEN_MASK) >> MC_CMD_HDR_TOKEN_SHIFT; ++ return token; ++} ++ ++static inline u32 mc_cmd_read_object_id(struct mc_command *cmd) ++{ ++ struct mc_rsp_create *rsp_params; ++ ++ rsp_params = (struct mc_rsp_create *)cmd->params; ++ return le32_to_cpu(rsp_params->object_id); ++} ++ ++static inline void mc_cmd_read_api_version(struct mc_command *cmd, ++ u16 *major_ver, ++ u16 *minor_ver) ++{ ++ struct mc_rsp_api_ver *rsp_params; ++ ++ rsp_params = (struct mc_rsp_api_ver *)cmd->params; ++ *major_ver = le16_to_cpu(rsp_params->major_ver); ++ *minor_ver = le16_to_cpu(rsp_params->minor_ver); + } + + #endif /* __FSL_MC_CMD_H */ +diff --git a/drivers/staging/fsl-mc/include/mc-sys.h b/drivers/staging/fsl-mc/include/mc-sys.h +index 89ad0cf5..dca7f908 100644 +--- a/drivers/staging/fsl-mc/include/mc-sys.h ++++ b/drivers/staging/fsl-mc/include/mc-sys.h +@@ -1,4 +1,5 @@ +-/* Copyright 2013-2014 Freescale Semiconductor Inc. ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. + * + * Interface of the I/O services to send MC commands to the MC hardware + * +diff --git a/drivers/staging/fsl-mc/include/mc.h b/drivers/staging/fsl-mc/include/mc.h +index f6e720e8..c23b78a4 100644 +--- a/drivers/staging/fsl-mc/include/mc.h ++++ b/drivers/staging/fsl-mc/include/mc.h +@@ -1,7 +1,7 @@ + /* + * Freescale Management Complex (MC) bus public interface + * +- * Copyright (C) 2014 Freescale Semiconductor, Inc. ++ * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. + * Author: German Rivera + * + * This file is licensed under the terms of the GNU General Public +@@ -81,7 +81,7 @@ enum fsl_mc_pool_type { + */ + struct fsl_mc_resource { + enum fsl_mc_pool_type type; +- int32_t id; ++ s32 id; + void *data; + struct fsl_mc_resource_pool *parent_pool; + struct list_head node; +@@ -122,6 +122,7 @@ struct fsl_mc_device_irq { + * @regions: pointer to array of MMIO region entries + * @irqs: pointer to array of pointers to interrupts allocated to this device + * @resource: generic resource associated with this MC object device, if any. ++ * @driver_override: Driver name to force a match + * + * Generic device object for MC object devices that are "attached" to a + * MC bus. +@@ -154,6 +155,7 @@ struct fsl_mc_device { + struct resource *regions; + struct fsl_mc_device_irq **irqs; + struct fsl_mc_resource *resource; ++ const char *driver_override; + }; + + #define to_fsl_mc_device(_dev) \ +@@ -175,6 +177,8 @@ struct fsl_mc_device { + #define fsl_mc_driver_register(drv) \ + __fsl_mc_driver_register(drv, THIS_MODULE) + ++void fsl_mc_device_remove(struct fsl_mc_device *mc_dev); ++ + int __must_check __fsl_mc_driver_register(struct fsl_mc_driver *fsl_mc_driver, + struct module *owner); + +@@ -198,4 +202,13 @@ int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev); + + void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev); + ++void fsl_mc_dma_configure(struct fsl_mc_device *mc_dev, ++ struct device_node *fsl_mc_platform_node, int coherent); ++ ++#ifdef CONFIG_FSL_MC_BUS ++struct iommu_group *fsl_mc_device_group(struct device *dev); ++#else ++#define fsl_mc_device_group(__dev) NULL ++#endif ++ + #endif /* _FSL_MC_H_ */ +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/705-dpaa2-support-layerscape.patch b/target/linux/layerscape/patches-4.9/705-dpaa2-support-layerscape.patch new file mode 100644 index 0000000000..d513efb2fb --- /dev/null +++ b/target/linux/layerscape/patches-4.9/705-dpaa2-support-layerscape.patch @@ -0,0 +1,23027 @@ +From 3a302437605308079db398b67000a77a4fe92da8 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 12:07:58 +0800 +Subject: [PATCH] dpaa2: support layerscape + +This is a integrated patch for layerscape dpaa2 support. + +Signed-off-by: Bogdan Purcareata +Signed-off-by: Ioana Radulescu +Signed-off-by: Razvan Stefanescu +Signed-off-by: costi +Signed-off-by: Catalin Horghidan +Signed-off-by: Yangbo Lu +--- + drivers/soc/fsl/ls2-console/Kconfig | 4 + + drivers/soc/fsl/ls2-console/Makefile | 1 + + drivers/soc/fsl/ls2-console/ls2-console.c | 284 ++ + drivers/staging/fsl-dpaa2/ethernet/Makefile | 11 + + drivers/staging/fsl-dpaa2/ethernet/README | 186 ++ + .../staging/fsl-dpaa2/ethernet/dpaa2-eth-debugfs.c | 350 +++ + .../staging/fsl-dpaa2/ethernet/dpaa2-eth-debugfs.h | 60 + + .../staging/fsl-dpaa2/ethernet/dpaa2-eth-trace.h | 184 ++ + drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c | 3155 ++++++++++++++++++++ + drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h | 460 +++ + drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c | 856 ++++++ + drivers/staging/fsl-dpaa2/ethernet/dpkg.h | 176 ++ + drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h | 600 ++++ + drivers/staging/fsl-dpaa2/ethernet/dpni.c | 1770 +++++++++++ + drivers/staging/fsl-dpaa2/ethernet/dpni.h | 989 ++++++ + drivers/staging/fsl-dpaa2/ethernet/net.h | 480 +++ + drivers/staging/fsl-dpaa2/ethsw/Kconfig | 6 + + drivers/staging/fsl-dpaa2/ethsw/Makefile | 10 + + drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h | 851 ++++++ + drivers/staging/fsl-dpaa2/ethsw/dpsw.c | 2762 +++++++++++++++++ + drivers/staging/fsl-dpaa2/ethsw/dpsw.h | 1269 ++++++++ + drivers/staging/fsl-dpaa2/ethsw/switch.c | 1857 ++++++++++++ + drivers/staging/fsl-dpaa2/evb/Kconfig | 7 + + drivers/staging/fsl-dpaa2/evb/Makefile | 10 + + drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h | 279 ++ + drivers/staging/fsl-dpaa2/evb/dpdmux.c | 1112 +++++++ + drivers/staging/fsl-dpaa2/evb/dpdmux.h | 453 +++ + drivers/staging/fsl-dpaa2/evb/evb.c | 1350 +++++++++ + drivers/staging/fsl-dpaa2/mac/Kconfig | 23 + + drivers/staging/fsl-dpaa2/mac/Makefile | 10 + + drivers/staging/fsl-dpaa2/mac/dpmac-cmd.h | 172 ++ + drivers/staging/fsl-dpaa2/mac/dpmac.c | 620 ++++ + drivers/staging/fsl-dpaa2/mac/dpmac.h | 342 +++ + drivers/staging/fsl-dpaa2/mac/mac.c | 666 +++++ + drivers/staging/fsl-dpaa2/rtc/Makefile | 10 + + drivers/staging/fsl-dpaa2/rtc/dprtc-cmd.h | 160 + + drivers/staging/fsl-dpaa2/rtc/dprtc.c | 746 +++++ + drivers/staging/fsl-dpaa2/rtc/dprtc.h | 172 ++ + drivers/staging/fsl-dpaa2/rtc/rtc.c | 243 ++ + 39 files changed, 22696 insertions(+) + create mode 100644 drivers/soc/fsl/ls2-console/Kconfig + create mode 100644 drivers/soc/fsl/ls2-console/Makefile + create mode 100644 drivers/soc/fsl/ls2-console/ls2-console.c + create mode 100644 drivers/staging/fsl-dpaa2/ethernet/Makefile + create mode 100644 drivers/staging/fsl-dpaa2/ethernet/README + create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-debugfs.c + create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-debugfs.h + create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-trace.h + create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c + create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h + create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c + create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpkg.h + create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h + create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpni.c + create mode 100644 drivers/staging/fsl-dpaa2/ethernet/dpni.h + create mode 100644 drivers/staging/fsl-dpaa2/ethernet/net.h + create mode 100644 drivers/staging/fsl-dpaa2/ethsw/Kconfig + create mode 100644 drivers/staging/fsl-dpaa2/ethsw/Makefile + create mode 100644 drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h + create mode 100644 drivers/staging/fsl-dpaa2/ethsw/dpsw.c + create mode 100644 drivers/staging/fsl-dpaa2/ethsw/dpsw.h + create mode 100644 drivers/staging/fsl-dpaa2/ethsw/switch.c + create mode 100644 drivers/staging/fsl-dpaa2/evb/Kconfig + create mode 100644 drivers/staging/fsl-dpaa2/evb/Makefile + create mode 100644 drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h + create mode 100644 drivers/staging/fsl-dpaa2/evb/dpdmux.c + create mode 100644 drivers/staging/fsl-dpaa2/evb/dpdmux.h + create mode 100644 drivers/staging/fsl-dpaa2/evb/evb.c + create mode 100644 drivers/staging/fsl-dpaa2/mac/Kconfig + create mode 100644 drivers/staging/fsl-dpaa2/mac/Makefile + create mode 100644 drivers/staging/fsl-dpaa2/mac/dpmac-cmd.h + create mode 100644 drivers/staging/fsl-dpaa2/mac/dpmac.c + create mode 100644 drivers/staging/fsl-dpaa2/mac/dpmac.h + create mode 100644 drivers/staging/fsl-dpaa2/mac/mac.c + create mode 100644 drivers/staging/fsl-dpaa2/rtc/Makefile + create mode 100644 drivers/staging/fsl-dpaa2/rtc/dprtc-cmd.h + create mode 100644 drivers/staging/fsl-dpaa2/rtc/dprtc.c + create mode 100644 drivers/staging/fsl-dpaa2/rtc/dprtc.h + create mode 100644 drivers/staging/fsl-dpaa2/rtc/rtc.c + +diff --git a/drivers/soc/fsl/ls2-console/Kconfig b/drivers/soc/fsl/ls2-console/Kconfig +new file mode 100644 +index 00000000..47d0dc11 +--- /dev/null ++++ b/drivers/soc/fsl/ls2-console/Kconfig +@@ -0,0 +1,4 @@ ++config FSL_LS2_CONSOLE ++ tristate "Layerscape MC and AIOP console support" ++ depends on ARCH_LAYERSCAPE ++ default y +diff --git a/drivers/soc/fsl/ls2-console/Makefile b/drivers/soc/fsl/ls2-console/Makefile +new file mode 100644 +index 00000000..62b96346 +--- /dev/null ++++ b/drivers/soc/fsl/ls2-console/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_FSL_LS2_CONSOLE) += ls2-console.o +diff --git a/drivers/soc/fsl/ls2-console/ls2-console.c b/drivers/soc/fsl/ls2-console/ls2-console.c +new file mode 100644 +index 00000000..68415ad0 +--- /dev/null ++++ b/drivers/soc/fsl/ls2-console/ls2-console.c +@@ -0,0 +1,284 @@ ++/* Copyright 2015-2016 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* SoC address for the MC firmware base low/high registers */ ++#define SOC_CCSR_MC_FW_BASE_ADDR_REGS 0x8340020 ++#define SOC_CCSR_MC_FW_BASE_ADDR_REGS_SIZE 2 ++/* MC firmware base low/high registers indexes */ ++#define MCFBALR_OFFSET 0 ++#define MCFBAHR_OFFSET 1 ++ ++/* Bit mask used to obtain the most significant part of the MC base address */ ++#define MC_FW_HIGH_ADDR_MASK 0x1FFFF ++/* Bit mask used to obtain the least significant part of the MC base address */ ++#define MC_FW_LOW_ADDR_MASK 0xE0000000 ++ ++#define MC_BUFFER_OFFSET 0x01000000 ++#define MC_BUFFER_SIZE (1024*1024*16) ++#define MC_OFFSET_DELTA (MC_BUFFER_OFFSET) ++ ++#define AIOP_BUFFER_OFFSET 0x06000000 ++#define AIOP_BUFFER_SIZE (1024*1024*16) ++#define AIOP_OFFSET_DELTA (0) ++ ++struct log_header { ++ char magic_word[8]; /* magic word */ ++ uint32_t buf_start; /* holds the 32-bit little-endian ++ * offset of the start of the buffer ++ */ ++ uint32_t buf_length; /* holds the 32-bit little-endian ++ * length of the buffer ++ */ ++ uint32_t last_byte; /* holds the 32-bit little-endian offset ++ * of the byte after the last byte that ++ * was written ++ */ ++ char reserved[44]; ++}; ++ ++#define LOG_HEADER_FLAG_BUFFER_WRAPAROUND 0x80000000 ++#define LOG_VERSION_MAJOR 1 ++#define LOG_VERSION_MINOR 0 ++ ++ ++#define invalidate(p) { asm volatile("dc ivac, %0" : : "r" (p) : "memory"); } ++ ++struct console_data { ++ char *map_addr; ++ struct log_header *hdr; ++ char *start_addr; /* Start of buffer */ ++ char *end_addr; /* End of buffer */ ++ char *end_of_data; /* Current end of data */ ++ char *cur_ptr; /* Last data sent to console */ ++}; ++ ++#define LAST_BYTE(a) ((a) & ~(LOG_HEADER_FLAG_BUFFER_WRAPAROUND)) ++ ++static inline void __adjust_end(struct console_data *cd) ++{ ++ cd->end_of_data = cd->start_addr ++ + LAST_BYTE(le32_to_cpu(cd->hdr->last_byte)); ++} ++ ++static inline void adjust_end(struct console_data *cd) ++{ ++ invalidate(cd->hdr); ++ __adjust_end(cd); ++} ++ ++static inline uint64_t get_mc_fw_base_address(void) ++{ ++ u32 *mcfbaregs = (u32 *) ioremap(SOC_CCSR_MC_FW_BASE_ADDR_REGS, ++ SOC_CCSR_MC_FW_BASE_ADDR_REGS_SIZE); ++ u64 mcfwbase = 0ULL; ++ ++ mcfwbase = readl(mcfbaregs + MCFBAHR_OFFSET) & MC_FW_HIGH_ADDR_MASK; ++ mcfwbase <<= 32; ++ mcfwbase |= readl(mcfbaregs + MCFBALR_OFFSET) & MC_FW_LOW_ADDR_MASK; ++ iounmap(mcfbaregs); ++ pr_info("fsl-ls2-console: MC base address at 0x%016llx\n", mcfwbase); ++ return mcfwbase; ++} ++ ++static int fsl_ls2_generic_console_open(struct inode *node, struct file *fp, ++ u64 offset, u64 size, ++ uint8_t *emagic, uint8_t magic_len, ++ u32 offset_delta) ++{ ++ struct console_data *cd; ++ uint8_t *magic; ++ uint32_t wrapped; ++ ++ cd = kmalloc(sizeof(*cd), GFP_KERNEL); ++ if (cd == NULL) ++ return -ENOMEM; ++ fp->private_data = cd; ++ cd->map_addr = ioremap(get_mc_fw_base_address() + offset, size); ++ ++ cd->hdr = (struct log_header *) cd->map_addr; ++ invalidate(cd->hdr); ++ ++ magic = cd->hdr->magic_word; ++ if (memcmp(magic, emagic, magic_len)) { ++ pr_info("magic didn't match!\n"); ++ pr_info("expected: %02x %02x %02x %02x %02x %02x %02x %02x\n", ++ emagic[0], emagic[1], emagic[2], emagic[3], ++ emagic[4], emagic[5], emagic[6], emagic[7]); ++ pr_info(" seen: %02x %02x %02x %02x %02x %02x %02x %02x\n", ++ magic[0], magic[1], magic[2], magic[3], ++ magic[4], magic[5], magic[6], magic[7]); ++ kfree(cd); ++ iounmap(cd->map_addr); ++ return -EIO; ++ } ++ ++ cd->start_addr = cd->map_addr ++ + le32_to_cpu(cd->hdr->buf_start) - offset_delta; ++ cd->end_addr = cd->start_addr + le32_to_cpu(cd->hdr->buf_length); ++ ++ wrapped = le32_to_cpu(cd->hdr->last_byte) ++ & LOG_HEADER_FLAG_BUFFER_WRAPAROUND; ++ ++ __adjust_end(cd); ++ if (wrapped && (cd->end_of_data != cd->end_addr)) ++ cd->cur_ptr = cd->end_of_data+1; ++ else ++ cd->cur_ptr = cd->start_addr; ++ ++ return 0; ++} ++ ++static int fsl_ls2_mc_console_open(struct inode *node, struct file *fp) ++{ ++ uint8_t magic_word[] = { 0, 1, 'C', 'M' }; ++ ++ return fsl_ls2_generic_console_open(node, fp, ++ MC_BUFFER_OFFSET, MC_BUFFER_SIZE, ++ magic_word, sizeof(magic_word), ++ MC_OFFSET_DELTA); ++} ++ ++static int fsl_ls2_aiop_console_open(struct inode *node, struct file *fp) ++{ ++ uint8_t magic_word[] = { 'P', 'O', 'I', 'A' }; ++ ++ return fsl_ls2_generic_console_open(node, fp, ++ AIOP_BUFFER_OFFSET, AIOP_BUFFER_SIZE, ++ magic_word, sizeof(magic_word), ++ AIOP_OFFSET_DELTA); ++} ++ ++static int fsl_ls2_console_close(struct inode *node, struct file *fp) ++{ ++ struct console_data *cd = fp->private_data; ++ ++ iounmap(cd->map_addr); ++ kfree(cd); ++ return 0; ++} ++ ++ssize_t fsl_ls2_console_read(struct file *fp, char __user *buf, size_t count, ++ loff_t *f_pos) ++{ ++ struct console_data *cd = fp->private_data; ++ size_t bytes = 0; ++ char data; ++ ++ /* Check if we need to adjust the end of data addr */ ++ adjust_end(cd); ++ ++ while ((count != bytes) && (cd->end_of_data != cd->cur_ptr)) { ++ if (((u64)cd->cur_ptr) % 64 == 0) ++ invalidate(cd->cur_ptr); ++ ++ data = *(cd->cur_ptr); ++ if (copy_to_user(&buf[bytes], &data, 1)) ++ return -EFAULT; ++ cd->cur_ptr++; ++ if (cd->cur_ptr >= cd->end_addr) ++ cd->cur_ptr = cd->start_addr; ++ ++bytes; ++ } ++ return bytes; ++} ++ ++static const struct file_operations fsl_ls2_mc_console_fops = { ++ .owner = THIS_MODULE, ++ .open = fsl_ls2_mc_console_open, ++ .release = fsl_ls2_console_close, ++ .read = fsl_ls2_console_read, ++}; ++ ++static struct miscdevice fsl_ls2_mc_console_dev = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "fsl_mc_console", ++ .fops = &fsl_ls2_mc_console_fops ++}; ++ ++static const struct file_operations fsl_ls2_aiop_console_fops = { ++ .owner = THIS_MODULE, ++ .open = fsl_ls2_aiop_console_open, ++ .release = fsl_ls2_console_close, ++ .read = fsl_ls2_console_read, ++}; ++ ++static struct miscdevice fsl_ls2_aiop_console_dev = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = "fsl_aiop_console", ++ .fops = &fsl_ls2_aiop_console_fops ++}; ++ ++static int __init fsl_ls2_console_init(void) ++{ ++ int err = 0; ++ ++ pr_info("Freescale LS2 console driver\n"); ++ err = misc_register(&fsl_ls2_mc_console_dev); ++ if (err) { ++ pr_err("fsl_mc_console: cannot register device\n"); ++ return err; ++ } ++ pr_info("fsl-ls2-console: device %s registered\n", ++ fsl_ls2_mc_console_dev.name); ++ ++ err = misc_register(&fsl_ls2_aiop_console_dev); ++ if (err) { ++ pr_err("fsl_aiop_console: cannot register device\n"); ++ return err; ++ } ++ pr_info("fsl-ls2-console: device %s registered\n", ++ fsl_ls2_aiop_console_dev.name); ++ ++ return 0; ++} ++ ++static void __exit fsl_ls2_console_exit(void) ++{ ++ misc_deregister(&fsl_ls2_mc_console_dev); ++ ++ misc_deregister(&fsl_ls2_aiop_console_dev); ++} ++ ++module_init(fsl_ls2_console_init); ++module_exit(fsl_ls2_console_exit); ++ ++MODULE_AUTHOR("Roy Pledge "); ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_DESCRIPTION("Freescale LS2 console driver"); +diff --git a/drivers/staging/fsl-dpaa2/ethernet/Makefile b/drivers/staging/fsl-dpaa2/ethernet/Makefile +new file mode 100644 +index 00000000..e26911d5 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethernet/Makefile +@@ -0,0 +1,11 @@ ++# ++# Makefile for the Freescale DPAA2 Ethernet controller ++# ++ ++obj-$(CONFIG_FSL_DPAA2_ETH) += fsl-dpaa2-eth.o ++ ++fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o ++fsl-dpaa2-eth-${CONFIG_FSL_DPAA2_ETH_DEBUGFS} += dpaa2-eth-debugfs.o ++ ++# Needed by the tracing framework ++CFLAGS_dpaa2-eth.o := -I$(src) +diff --git a/drivers/staging/fsl-dpaa2/ethernet/README b/drivers/staging/fsl-dpaa2/ethernet/README +new file mode 100644 +index 00000000..410952ec +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethernet/README +@@ -0,0 +1,186 @@ ++Freescale DPAA2 Ethernet driver ++=============================== ++ ++This file provides documentation for the Freescale DPAA2 Ethernet driver. ++ ++ ++Contents ++======== ++ Supported Platforms ++ Architecture Overview ++ Creating a Network Interface ++ Features & Offloads ++ ++ ++Supported Platforms ++=================== ++This driver provides networking support for Freescale DPAA2 SoCs, e.g. ++LS2080A, LS2088A, LS1088A. ++ ++ ++Architecture Overview ++===================== ++Unlike regular NICs, in the DPAA2 architecture there is no single hardware block ++representing network interfaces; instead, several separate hardware resources ++concur to provide the networking functionality: ++ - network interfaces ++ - queues, channels ++ - buffer pools ++ - MAC/PHY ++ ++All hardware resources are allocated and configured through the Management ++Complex (MC) portals. MC abstracts most of these resources as DPAA2 objects ++and exposes ABIs through which they can be configured and controlled. A few ++hardware resources, like queues, do not have a corresponding MC object and ++are treated as internal resources of other objects. ++ ++For a more detailed description of the DPAA2 architecture and its object ++abstractions see: ++ drivers/staging/fsl-mc/README.txt ++ ++Each Linux net device is built on top of a Datapath Network Interface (DPNI) ++object and uses Buffer Pools (DPBPs), I/O Portals (DPIOs) and Concentrators ++(DPCONs). ++ ++Configuration interface: ++ ++ ----------------------- ++ | DPAA2 Ethernet Driver | ++ ----------------------- ++ . . . ++ . . . ++ . . . . . . . . . . . . ++ . . . ++ . . . ++ ---------- ---------- ----------- ++ | DPBP API | | DPNI API | | DPCON API | ++ ---------- ---------- ----------- ++ . . . software ++=========== . ========== . ============ . =================== ++ . . . hardware ++ ------------------------------------------ ++ | MC hardware portals | ++ ------------------------------------------ ++ . . . ++ . . . ++ ------ ------ ------- ++ | DPBP | | DPNI | | DPCON | ++ ------ ------ ------- ++ ++The DPNIs are network interfaces without a direct one-on-one mapping to PHYs. ++DPBPs represent hardware buffer pools. Packet I/O is performed in the context ++of DPCON objects, using DPIO portals for managing and communicating with the ++hardware resources. ++ ++Datapath (I/O) interface: ++ ++ ----------------------------------------------- ++ | DPAA2 Ethernet Driver | ++ ----------------------------------------------- ++ | ^ ^ | | ++ | | | | | ++ enqueue| dequeue| data | dequeue| seed | ++ (Tx) | (Rx, TxC)| avail.| request| buffers| ++ | | notify| | | ++ | | | | | ++ V | | V V ++ ----------------------------------------------- ++ | DPIO Driver | ++ ----------------------------------------------- ++ | | | | | software ++ | | | | | ================ ++ | | | | | hardware ++ ----------------------------------------------- ++ | I/O hardware portals | ++ ----------------------------------------------- ++ | ^ ^ | | ++ | | | | | ++ | | | V | ++ V | ================ V ++ ---------------------- | ------------- ++ queues ---------------------- | | Buffer pool | ++ ---------------------- | ------------- ++ ======================= ++ Channel ++ ++Datapath I/O (DPIO) portals provide enqueue and dequeue services, data ++availability notifications and buffer pool management. DPIOs are shared between ++all DPAA2 objects (and implicitly all DPAA2 kernel drivers) that work with data ++frames, but must be affine to the CPUs for the purpose of traffic distribution. ++ ++Frames are transmitted and received through hardware frame queues, which can be ++grouped in channels for the purpose of hardware scheduling. The Ethernet driver ++enqueues TX frames on egress queues and after transmission is complete a TX ++confirmation frame is sent back to the CPU. ++ ++When frames are available on ingress queues, a data availability notification ++is sent to the CPU; notifications are raised per channel, so even if multiple ++queues in the same channel have available frames, only one notification is sent. ++After a channel fires a notification, is must be explicitly rearmed. ++ ++Each network interface can have multiple Rx, Tx and confirmation queues affined ++to CPUs, and one channel (DPCON) for each CPU that services at least one queue. ++DPCONs are used to distribute ingress traffic to different CPUs via the cores' ++affine DPIOs. ++ ++The role of hardware buffer pools is storage of ingress frame data. Each network ++interface has a privately owned buffer pool which it seeds with kernel allocated ++buffers. ++ ++ ++DPNIs are decoupled from PHYs; a DPNI can be connected to a PHY through a DPMAC ++object or to another DPNI through an internal link, but the connection is ++managed by MC and completely transparent to the Ethernet driver. ++ ++ --------- --------- --------- ++ | eth if1 | | eth if2 | | eth ifn | ++ --------- --------- --------- ++ . . . ++ . . . ++ . . . ++ --------------------------- ++ | DPAA2 Ethernet Driver | ++ --------------------------- ++ . . . ++ . . . ++ . . . ++ ------ ------ ------ ------- ++ | DPNI | | DPNI | | DPNI | | DPMAC |----+ ++ ------ ------ ------ ------- | ++ | | | | | ++ | | | | ----- ++ =========== ================== | PHY | ++ ----- ++ ++Creating a Network Interface ++============================ ++A net device is created for each DPNI object probed on the MC bus. Each DPNI has ++a number of properties which determine the network interface configuration ++options and associated hardware resources. ++ ++DPNI objects (and the other DPAA2 objects needed for a network interface) can be ++added to a container on the MC bus in one of two ways: statically, through a ++Datapath Layout Binary file (DPL) that is parsed by MC at boot time; or created ++dynamically at runtime, via the DPAA2 objects APIs. ++ ++ ++Features & Offloads ++=================== ++Hardware checksum offloading is supported for TCP and UDP over IPv4/6 frames. ++The checksum offloads can be independently configured on RX and TX through ++ethtool. ++ ++Hardware offload of unicast and multicast MAC filtering is supported on the ++ingress path and permanently enabled. ++ ++Scatter-gather frames are supported on both RX and TX paths. On TX, SG support ++is configurable via ethtool; on RX it is always enabled. ++ ++The DPAA2 hardware can process jumbo Ethernet frames of up to 10K bytes. ++ ++The Ethernet driver defines a static flow hashing scheme that distributes ++traffic based on a 5-tuple key: src IP, dst IP, IP proto, L4 src port, ++L4 dst port. No user configuration is supported for now. ++ ++Hardware specific statistics for the network interface as well as some ++non-standard driver stats can be consulted through ethtool -S option. +diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-debugfs.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-debugfs.c +new file mode 100644 +index 00000000..445c5d17 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-debugfs.c +@@ -0,0 +1,350 @@ ++ ++/* Copyright 2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++#include "dpaa2-eth.h" ++#include "dpaa2-eth-debugfs.h" ++ ++#define DPAA2_ETH_DBG_ROOT "dpaa2-eth" ++ ++static struct dentry *dpaa2_dbg_root; ++ ++static int dpaa2_dbg_cpu_show(struct seq_file *file, void *offset) ++{ ++ struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)file->private; ++ struct rtnl_link_stats64 *stats; ++ struct dpaa2_eth_drv_stats *extras; ++ int i; ++ ++ seq_printf(file, "Per-CPU stats for %s\n", priv->net_dev->name); ++ seq_printf(file, "%s%16s%16s%16s%16s%16s%16s%16s%16s\n", ++ "CPU", "Rx", "Rx Err", "Rx SG", "Tx", "Tx Err", "Tx conf", ++ "Tx SG", "Enq busy"); ++ ++ for_each_online_cpu(i) { ++ stats = per_cpu_ptr(priv->percpu_stats, i); ++ extras = per_cpu_ptr(priv->percpu_extras, i); ++ seq_printf(file, "%3d%16llu%16llu%16llu%16llu%16llu%16llu%16llu%16llu\n", ++ i, ++ stats->rx_packets, ++ stats->rx_errors, ++ extras->rx_sg_frames, ++ stats->tx_packets, ++ stats->tx_errors, ++ extras->tx_conf_frames, ++ extras->tx_sg_frames, ++ extras->tx_portal_busy); ++ } ++ ++ return 0; ++} ++ ++static int dpaa2_dbg_cpu_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)inode->i_private; ++ ++ err = single_open(file, dpaa2_dbg_cpu_show, priv); ++ if (err < 0) ++ netdev_err(priv->net_dev, "single_open() failed\n"); ++ ++ return err; ++} ++ ++static const struct file_operations dpaa2_dbg_cpu_ops = { ++ .open = dpaa2_dbg_cpu_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static char *fq_type_to_str(struct dpaa2_eth_fq *fq) ++{ ++ switch (fq->type) { ++ case DPAA2_RX_FQ: ++ return "Rx"; ++ case DPAA2_TX_CONF_FQ: ++ return "Tx conf"; ++ case DPAA2_RX_ERR_FQ: ++ return "Rx err"; ++ default: ++ return "N/A"; ++ } ++} ++ ++static int dpaa2_dbg_fqs_show(struct seq_file *file, void *offset) ++{ ++ struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)file->private; ++ struct dpaa2_eth_fq *fq; ++ u32 fcnt, bcnt; ++ int i, err; ++ ++ seq_printf(file, "FQ stats for %s:\n", priv->net_dev->name); ++ seq_printf(file, "%s%16s%16s%16s%16s%16s\n", ++ "VFQID", "CPU", "Type", "Frames", "Pending frames", ++ "Congestion"); ++ ++ for (i = 0; i < priv->num_fqs; i++) { ++ fq = &priv->fq[i]; ++ err = dpaa2_io_query_fq_count(NULL, fq->fqid, &fcnt, &bcnt); ++ if (err) ++ fcnt = 0; ++ ++ seq_printf(file, "%5d%16d%16s%16llu%16u%16llu\n", ++ fq->fqid, ++ fq->target_cpu, ++ fq_type_to_str(fq), ++ fq->stats.frames, ++ fcnt, ++ fq->stats.congestion_entry); ++ } ++ ++ return 0; ++} ++ ++static int dpaa2_dbg_fqs_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)inode->i_private; ++ ++ err = single_open(file, dpaa2_dbg_fqs_show, priv); ++ if (err < 0) ++ netdev_err(priv->net_dev, "single_open() failed\n"); ++ ++ return err; ++} ++ ++static const struct file_operations dpaa2_dbg_fq_ops = { ++ .open = dpaa2_dbg_fqs_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static int dpaa2_dbg_ch_show(struct seq_file *file, void *offset) ++{ ++ struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)file->private; ++ struct dpaa2_eth_channel *ch; ++ int i; ++ ++ seq_printf(file, "Channel stats for %s:\n", priv->net_dev->name); ++ seq_printf(file, "%s%16s%16s%16s%16s%16s\n", ++ "CHID", "CPU", "Deq busy", "Frames", "CDANs", ++ "Avg frm/CDAN"); ++ ++ for (i = 0; i < priv->num_channels; i++) { ++ ch = priv->channel[i]; ++ seq_printf(file, "%4d%16d%16llu%16llu%16llu%16llu\n", ++ ch->ch_id, ++ ch->nctx.desired_cpu, ++ ch->stats.dequeue_portal_busy, ++ ch->stats.frames, ++ ch->stats.cdan, ++ ch->stats.frames / ch->stats.cdan); ++ } ++ ++ return 0; ++} ++ ++static int dpaa2_dbg_ch_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)inode->i_private; ++ ++ err = single_open(file, dpaa2_dbg_ch_show, priv); ++ if (err < 0) ++ netdev_err(priv->net_dev, "single_open() failed\n"); ++ ++ return err; ++} ++ ++static const struct file_operations dpaa2_dbg_ch_ops = { ++ .open = dpaa2_dbg_ch_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static ssize_t dpaa2_dbg_reset_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *offset) ++{ ++ struct dpaa2_eth_priv *priv = file->private_data; ++ struct rtnl_link_stats64 *percpu_stats; ++ struct dpaa2_eth_drv_stats *percpu_extras; ++ struct dpaa2_eth_fq *fq; ++ struct dpaa2_eth_channel *ch; ++ int i; ++ ++ for_each_online_cpu(i) { ++ percpu_stats = per_cpu_ptr(priv->percpu_stats, i); ++ memset(percpu_stats, 0, sizeof(*percpu_stats)); ++ ++ percpu_extras = per_cpu_ptr(priv->percpu_extras, i); ++ memset(percpu_extras, 0, sizeof(*percpu_extras)); ++ } ++ ++ for (i = 0; i < priv->num_fqs; i++) { ++ fq = &priv->fq[i]; ++ memset(&fq->stats, 0, sizeof(fq->stats)); ++ } ++ ++ for (i = 0; i < priv->num_channels; i++) { ++ ch = priv->channel[i]; ++ memset(&ch->stats, 0, sizeof(ch->stats)); ++ } ++ ++ return count; ++} ++ ++static const struct file_operations dpaa2_dbg_reset_ops = { ++ .open = simple_open, ++ .write = dpaa2_dbg_reset_write, ++}; ++ ++static ssize_t dpaa2_dbg_reset_mc_write(struct file *file, ++ const char __user *buf, ++ size_t count, loff_t *offset) ++{ ++ struct dpaa2_eth_priv *priv = file->private_data; ++ int err; ++ ++ err = dpni_reset_statistics(priv->mc_io, 0, priv->mc_token); ++ if (err) ++ netdev_err(priv->net_dev, ++ "dpni_reset_statistics() failed %d\n", err); ++ ++ return count; ++} ++ ++static const struct file_operations dpaa2_dbg_reset_mc_ops = { ++ .open = simple_open, ++ .write = dpaa2_dbg_reset_mc_write, ++}; ++ ++void dpaa2_dbg_add(struct dpaa2_eth_priv *priv) ++{ ++ if (!dpaa2_dbg_root) ++ return; ++ ++ /* Create a directory for the interface */ ++ priv->dbg.dir = debugfs_create_dir(priv->net_dev->name, ++ dpaa2_dbg_root); ++ if (!priv->dbg.dir) { ++ netdev_err(priv->net_dev, "debugfs_create_dir() failed\n"); ++ return; ++ } ++ ++ /* per-cpu stats file */ ++ priv->dbg.cpu_stats = debugfs_create_file("cpu_stats", 0444, ++ priv->dbg.dir, priv, ++ &dpaa2_dbg_cpu_ops); ++ if (!priv->dbg.cpu_stats) { ++ netdev_err(priv->net_dev, "debugfs_create_file() failed\n"); ++ goto err_cpu_stats; ++ } ++ ++ /* per-fq stats file */ ++ priv->dbg.fq_stats = debugfs_create_file("fq_stats", 0444, ++ priv->dbg.dir, priv, ++ &dpaa2_dbg_fq_ops); ++ if (!priv->dbg.fq_stats) { ++ netdev_err(priv->net_dev, "debugfs_create_file() failed\n"); ++ goto err_fq_stats; ++ } ++ ++ /* per-fq stats file */ ++ priv->dbg.ch_stats = debugfs_create_file("ch_stats", 0444, ++ priv->dbg.dir, priv, ++ &dpaa2_dbg_ch_ops); ++ if (!priv->dbg.fq_stats) { ++ netdev_err(priv->net_dev, "debugfs_create_file() failed\n"); ++ goto err_ch_stats; ++ } ++ ++ /* reset stats */ ++ priv->dbg.reset_stats = debugfs_create_file("reset_stats", 0200, ++ priv->dbg.dir, priv, ++ &dpaa2_dbg_reset_ops); ++ if (!priv->dbg.reset_stats) { ++ netdev_err(priv->net_dev, "debugfs_create_file() failed\n"); ++ goto err_reset_stats; ++ } ++ ++ /* reset MC stats */ ++ priv->dbg.reset_mc_stats = debugfs_create_file("reset_mc_stats", ++ 0222, priv->dbg.dir, priv, ++ &dpaa2_dbg_reset_mc_ops); ++ if (!priv->dbg.reset_mc_stats) { ++ netdev_err(priv->net_dev, "debugfs_create_file() failed\n"); ++ goto err_reset_mc_stats; ++ } ++ ++ return; ++ ++err_reset_mc_stats: ++ debugfs_remove(priv->dbg.reset_stats); ++err_reset_stats: ++ debugfs_remove(priv->dbg.ch_stats); ++err_ch_stats: ++ debugfs_remove(priv->dbg.fq_stats); ++err_fq_stats: ++ debugfs_remove(priv->dbg.cpu_stats); ++err_cpu_stats: ++ debugfs_remove(priv->dbg.dir); ++} ++ ++void dpaa2_dbg_remove(struct dpaa2_eth_priv *priv) ++{ ++ debugfs_remove(priv->dbg.reset_mc_stats); ++ debugfs_remove(priv->dbg.reset_stats); ++ debugfs_remove(priv->dbg.fq_stats); ++ debugfs_remove(priv->dbg.ch_stats); ++ debugfs_remove(priv->dbg.cpu_stats); ++ debugfs_remove(priv->dbg.dir); ++} ++ ++void dpaa2_eth_dbg_init(void) ++{ ++ dpaa2_dbg_root = debugfs_create_dir(DPAA2_ETH_DBG_ROOT, NULL); ++ if (!dpaa2_dbg_root) { ++ pr_err("DPAA2-ETH: debugfs create failed\n"); ++ return; ++ } ++ ++ pr_info("DPAA2-ETH: debugfs created\n"); ++} ++ ++void __exit dpaa2_eth_dbg_exit(void) ++{ ++ debugfs_remove(dpaa2_dbg_root); ++} +diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-debugfs.h b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-debugfs.h +new file mode 100644 +index 00000000..551e6c4c +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-debugfs.h +@@ -0,0 +1,60 @@ ++/* Copyright 2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef DPAA2_ETH_DEBUGFS_H ++#define DPAA2_ETH_DEBUGFS_H ++ ++#include ++ ++struct dpaa2_eth_priv; ++ ++struct dpaa2_debugfs { ++ struct dentry *dir; ++ struct dentry *fq_stats; ++ struct dentry *ch_stats; ++ struct dentry *cpu_stats; ++ struct dentry *reset_stats; ++ struct dentry *reset_mc_stats; ++}; ++ ++#ifdef CONFIG_FSL_DPAA2_ETH_DEBUGFS ++void dpaa2_eth_dbg_init(void); ++void dpaa2_eth_dbg_exit(void); ++void dpaa2_dbg_add(struct dpaa2_eth_priv *priv); ++void dpaa2_dbg_remove(struct dpaa2_eth_priv *priv); ++#else ++static inline void dpaa2_eth_dbg_init(void) {} ++static inline void dpaa2_eth_dbg_exit(void) {} ++static inline void dpaa2_dbg_add(struct dpaa2_eth_priv *priv) {} ++static inline void dpaa2_dbg_remove(struct dpaa2_eth_priv *priv) {} ++#endif /* CONFIG_FSL_DPAA2_ETH_DEBUGFS */ ++ ++#endif /* DPAA2_ETH_DEBUGFS_H */ +diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-trace.h b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-trace.h +new file mode 100644 +index 00000000..e8e6522a +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth-trace.h +@@ -0,0 +1,184 @@ ++/* Copyright 2014-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#undef TRACE_SYSTEM ++#define TRACE_SYSTEM dpaa2_eth ++ ++#if !defined(_DPAA2_ETH_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) ++#define _DPAA2_ETH_TRACE_H ++ ++#include ++#include ++#include ++ ++#define TR_FMT "[%s] fd: addr=0x%llx, len=%u, off=%u" ++/* trace_printk format for raw buffer event class */ ++#define TR_BUF_FMT "[%s] vaddr=%p size=%zu dma_addr=%pad map_size=%zu bpid=%d" ++ ++/* This is used to declare a class of events. ++ * individual events of this type will be defined below. ++ */ ++ ++/* Store details about a frame descriptor */ ++DECLARE_EVENT_CLASS(dpaa2_eth_fd, ++ /* Trace function prototype */ ++ TP_PROTO(struct net_device *netdev, ++ const struct dpaa2_fd *fd), ++ ++ /* Repeat argument list here */ ++ TP_ARGS(netdev, fd), ++ ++ /* A structure containing the relevant information we want ++ * to record. Declare name and type for each normal element, ++ * name, type and size for arrays. Use __string for variable ++ * length strings. ++ */ ++ TP_STRUCT__entry( ++ __field(u64, fd_addr) ++ __field(u32, fd_len) ++ __field(u16, fd_offset) ++ __string(name, netdev->name) ++ ), ++ ++ /* The function that assigns values to the above declared ++ * fields ++ */ ++ TP_fast_assign( ++ __entry->fd_addr = dpaa2_fd_get_addr(fd); ++ __entry->fd_len = dpaa2_fd_get_len(fd); ++ __entry->fd_offset = dpaa2_fd_get_offset(fd); ++ __assign_str(name, netdev->name); ++ ), ++ ++ /* This is what gets printed when the trace event is ++ * triggered. ++ */ ++ TP_printk(TR_FMT, ++ __get_str(name), ++ __entry->fd_addr, ++ __entry->fd_len, ++ __entry->fd_offset) ++); ++ ++/* Now declare events of the above type. Format is: ++ * DEFINE_EVENT(class, name, proto, args), with proto and args same as for class ++ */ ++ ++/* Tx (egress) fd */ ++DEFINE_EVENT(dpaa2_eth_fd, dpaa2_tx_fd, ++ TP_PROTO(struct net_device *netdev, ++ const struct dpaa2_fd *fd), ++ ++ TP_ARGS(netdev, fd) ++); ++ ++/* Rx fd */ ++DEFINE_EVENT(dpaa2_eth_fd, dpaa2_rx_fd, ++ TP_PROTO(struct net_device *netdev, ++ const struct dpaa2_fd *fd), ++ ++ TP_ARGS(netdev, fd) ++); ++ ++/* Tx confirmation fd */ ++DEFINE_EVENT(dpaa2_eth_fd, dpaa2_tx_conf_fd, ++ TP_PROTO(struct net_device *netdev, ++ const struct dpaa2_fd *fd), ++ ++ TP_ARGS(netdev, fd) ++); ++ ++/* Log data about raw buffers. Useful for tracing DPBP content. */ ++TRACE_EVENT(dpaa2_eth_buf_seed, ++ /* Trace function prototype */ ++ TP_PROTO(struct net_device *netdev, ++ /* virtual address and size */ ++ void *vaddr, ++ size_t size, ++ /* dma map address and size */ ++ dma_addr_t dma_addr, ++ size_t map_size, ++ /* buffer pool id, if relevant */ ++ u16 bpid), ++ ++ /* Repeat argument list here */ ++ TP_ARGS(netdev, vaddr, size, dma_addr, map_size, bpid), ++ ++ /* A structure containing the relevant information we want ++ * to record. Declare name and type for each normal element, ++ * name, type and size for arrays. Use __string for variable ++ * length strings. ++ */ ++ TP_STRUCT__entry( ++ __field(void *, vaddr) ++ __field(size_t, size) ++ __field(dma_addr_t, dma_addr) ++ __field(size_t, map_size) ++ __field(u16, bpid) ++ __string(name, netdev->name) ++ ), ++ ++ /* The function that assigns values to the above declared ++ * fields ++ */ ++ TP_fast_assign( ++ __entry->vaddr = vaddr; ++ __entry->size = size; ++ __entry->dma_addr = dma_addr; ++ __entry->map_size = map_size; ++ __entry->bpid = bpid; ++ __assign_str(name, netdev->name); ++ ), ++ ++ /* This is what gets printed when the trace event is ++ * triggered. ++ */ ++ TP_printk(TR_BUF_FMT, ++ __get_str(name), ++ __entry->vaddr, ++ __entry->size, ++ &__entry->dma_addr, ++ __entry->map_size, ++ __entry->bpid) ++); ++ ++/* If only one event of a certain type needs to be declared, use TRACE_EVENT(). ++ * The syntax is the same as for DECLARE_EVENT_CLASS(). ++ */ ++ ++#endif /* _DPAA2_ETH_TRACE_H */ ++ ++/* This must be outside ifdef _DPAA2_ETH_TRACE_H */ ++#undef TRACE_INCLUDE_PATH ++#define TRACE_INCLUDE_PATH . ++#undef TRACE_INCLUDE_FILE ++#define TRACE_INCLUDE_FILE dpaa2-eth-trace ++#include +diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c +new file mode 100644 +index 00000000..452eca52 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c +@@ -0,0 +1,3155 @@ ++/* Copyright 2014-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../../fsl-mc/include/dpbp.h" ++#include "../../fsl-mc/include/dpcon.h" ++#include "../../fsl-mc/include/mc.h" ++#include "../../fsl-mc/include/mc-sys.h" ++#include "dpaa2-eth.h" ++#include "dpkg.h" ++ ++/* CREATE_TRACE_POINTS only needs to be defined once. Other dpa files ++ * using trace events only need to #include ++ */ ++#define CREATE_TRACE_POINTS ++#include "dpaa2-eth-trace.h" ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("Freescale Semiconductor, Inc"); ++MODULE_DESCRIPTION("Freescale DPAA2 Ethernet Driver"); ++ ++const char dpaa2_eth_drv_version[] = "0.1"; ++ ++void *dpaa2_eth_iova_to_virt(struct iommu_domain *domain, dma_addr_t iova_addr) ++{ ++ phys_addr_t phys_addr; ++ ++ phys_addr = domain ? iommu_iova_to_phys(domain, iova_addr) : iova_addr; ++ ++ return phys_to_virt(phys_addr); ++} ++ ++static void validate_rx_csum(struct dpaa2_eth_priv *priv, ++ u32 fd_status, ++ struct sk_buff *skb) ++{ ++ skb_checksum_none_assert(skb); ++ ++ /* HW checksum validation is disabled, nothing to do here */ ++ if (!(priv->net_dev->features & NETIF_F_RXCSUM)) ++ return; ++ ++ /* Read checksum validation bits */ ++ if (!((fd_status & DPAA2_FAS_L3CV) && ++ (fd_status & DPAA2_FAS_L4CV))) ++ return; ++ ++ /* Inform the stack there's no need to compute L3/L4 csum anymore */ ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++} ++ ++/* Free a received FD. ++ * Not to be used for Tx conf FDs or on any other paths. ++ */ ++static void free_rx_fd(struct dpaa2_eth_priv *priv, ++ const struct dpaa2_fd *fd, ++ void *vaddr) ++{ ++ struct device *dev = priv->net_dev->dev.parent; ++ dma_addr_t addr = dpaa2_fd_get_addr(fd); ++ u8 fd_format = dpaa2_fd_get_format(fd); ++ struct dpaa2_sg_entry *sgt; ++ void *sg_vaddr; ++ int i; ++ ++ /* If single buffer frame, just free the data buffer */ ++ if (fd_format == dpaa2_fd_single) ++ goto free_buf; ++ else if (fd_format != dpaa2_fd_sg) ++ /* we don't support any other format */ ++ return; ++ ++ /* For S/G frames, we first need to free all SG entries */ ++ sgt = vaddr + dpaa2_fd_get_offset(fd); ++ for (i = 0; i < DPAA2_ETH_MAX_SG_ENTRIES; i++) { ++ addr = dpaa2_sg_get_addr(&sgt[i]); ++ sg_vaddr = dpaa2_eth_iova_to_virt(priv->iommu_domain, addr); ++ ++ dma_unmap_single(dev, addr, DPAA2_ETH_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); ++ ++ put_page(virt_to_head_page(sg_vaddr)); ++ ++ if (dpaa2_sg_is_final(&sgt[i])) ++ break; ++ } ++ ++free_buf: ++ put_page(virt_to_head_page(vaddr)); ++} ++ ++/* Build a linear skb based on a single-buffer frame descriptor */ ++static struct sk_buff *build_linear_skb(struct dpaa2_eth_priv *priv, ++ struct dpaa2_eth_channel *ch, ++ const struct dpaa2_fd *fd, ++ void *fd_vaddr) ++{ ++ struct sk_buff *skb = NULL; ++ u16 fd_offset = dpaa2_fd_get_offset(fd); ++ u32 fd_length = dpaa2_fd_get_len(fd); ++ ++ skb = build_skb(fd_vaddr, DPAA2_ETH_SKB_SIZE); ++ if (unlikely(!skb)) ++ return NULL; ++ ++ skb_reserve(skb, fd_offset); ++ skb_put(skb, fd_length); ++ ++ ch->buf_count--; ++ ++ return skb; ++} ++ ++/* Build a non linear (fragmented) skb based on a S/G table */ ++static struct sk_buff *build_frag_skb(struct dpaa2_eth_priv *priv, ++ struct dpaa2_eth_channel *ch, ++ struct dpaa2_sg_entry *sgt) ++{ ++ struct sk_buff *skb = NULL; ++ struct device *dev = priv->net_dev->dev.parent; ++ void *sg_vaddr; ++ dma_addr_t sg_addr; ++ u16 sg_offset; ++ u32 sg_length; ++ struct page *page, *head_page; ++ int page_offset; ++ int i; ++ ++ for (i = 0; i < DPAA2_ETH_MAX_SG_ENTRIES; i++) { ++ struct dpaa2_sg_entry *sge = &sgt[i]; ++ ++ /* NOTE: We only support SG entries in dpaa2_sg_single format, ++ * but this is the only format we may receive from HW anyway ++ */ ++ ++ /* Get the address and length from the S/G entry */ ++ sg_addr = dpaa2_sg_get_addr(sge); ++ sg_vaddr = dpaa2_eth_iova_to_virt(priv->iommu_domain, sg_addr); ++ dma_unmap_single(dev, sg_addr, DPAA2_ETH_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); ++ ++ sg_length = dpaa2_sg_get_len(sge); ++ ++ if (i == 0) { ++ /* We build the skb around the first data buffer */ ++ skb = build_skb(sg_vaddr, DPAA2_ETH_SKB_SIZE); ++ if (unlikely(!skb)) ++ return NULL; ++ ++ sg_offset = dpaa2_sg_get_offset(sge); ++ skb_reserve(skb, sg_offset); ++ skb_put(skb, sg_length); ++ } else { ++ /* Rest of the data buffers are stored as skb frags */ ++ page = virt_to_page(sg_vaddr); ++ head_page = virt_to_head_page(sg_vaddr); ++ ++ /* Offset in page (which may be compound). ++ * Data in subsequent SG entries is stored from the ++ * beginning of the buffer, so we don't need to add the ++ * sg_offset. ++ */ ++ page_offset = ((unsigned long)sg_vaddr & ++ (PAGE_SIZE - 1)) + ++ (page_address(page) - page_address(head_page)); ++ ++ skb_add_rx_frag(skb, i - 1, head_page, page_offset, ++ sg_length, DPAA2_ETH_RX_BUF_SIZE); ++ } ++ ++ if (dpaa2_sg_is_final(sge)) ++ break; ++ } ++ ++ /* Count all data buffers + SG table buffer */ ++ ch->buf_count -= i + 2; ++ ++ return skb; ++} ++ ++/* Main Rx frame processing routine */ ++static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv, ++ struct dpaa2_eth_channel *ch, ++ const struct dpaa2_fd *fd, ++ struct napi_struct *napi, ++ u16 queue_id) ++{ ++ dma_addr_t addr = dpaa2_fd_get_addr(fd); ++ u8 fd_format = dpaa2_fd_get_format(fd); ++ void *vaddr; ++ struct sk_buff *skb; ++ struct rtnl_link_stats64 *percpu_stats; ++ struct dpaa2_eth_drv_stats *percpu_extras; ++ struct device *dev = priv->net_dev->dev.parent; ++ struct dpaa2_fas *fas; ++ void *buf_data; ++ u32 status = 0; ++ ++ /* Tracing point */ ++ trace_dpaa2_rx_fd(priv->net_dev, fd); ++ ++ vaddr = dpaa2_eth_iova_to_virt(priv->iommu_domain, addr); ++ dma_unmap_single(dev, addr, DPAA2_ETH_RX_BUF_SIZE, DMA_FROM_DEVICE); ++ ++ /* HWA - FAS, timestamp */ ++ fas = dpaa2_eth_get_fas(vaddr); ++ prefetch(fas); ++ /* data / SG table */ ++ buf_data = vaddr + dpaa2_fd_get_offset(fd); ++ prefetch(buf_data); ++ ++ percpu_stats = this_cpu_ptr(priv->percpu_stats); ++ percpu_extras = this_cpu_ptr(priv->percpu_extras); ++ ++ switch (fd_format) { ++ case dpaa2_fd_single: ++ skb = build_linear_skb(priv, ch, fd, vaddr); ++ break; ++ case dpaa2_fd_sg: ++ skb = build_frag_skb(priv, ch, buf_data); ++ put_page(virt_to_head_page(vaddr)); ++ percpu_extras->rx_sg_frames++; ++ percpu_extras->rx_sg_bytes += dpaa2_fd_get_len(fd); ++ break; ++ default: ++ /* We don't support any other format */ ++ goto err_frame_format; ++ } ++ ++ if (unlikely(!skb)) ++ goto err_build_skb; ++ ++ prefetch(skb->data); ++ ++ /* Get the timestamp value */ ++ if (priv->ts_rx_en) { ++ struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); ++ u64 *ns = (u64 *)dpaa2_eth_get_ts(vaddr); ++ ++ *ns = DPAA2_PTP_NOMINAL_FREQ_PERIOD_NS * le64_to_cpup(ns); ++ memset(shhwtstamps, 0, sizeof(*shhwtstamps)); ++ shhwtstamps->hwtstamp = ns_to_ktime(*ns); ++ } ++ ++ /* Check if we need to validate the L4 csum */ ++ if (likely(dpaa2_fd_get_frc(fd) & DPAA2_FD_FRC_FASV)) { ++ status = le32_to_cpu(fas->status); ++ validate_rx_csum(priv, status, skb); ++ } ++ ++ skb->protocol = eth_type_trans(skb, priv->net_dev); ++ ++ /* Record Rx queue - this will be used when picking a Tx queue to ++ * forward the frames. We're keeping flow affinity through the ++ * network stack. ++ */ ++ skb_record_rx_queue(skb, queue_id); ++ ++ percpu_stats->rx_packets++; ++ percpu_stats->rx_bytes += dpaa2_fd_get_len(fd); ++ ++ napi_gro_receive(napi, skb); ++ ++ return; ++ ++err_build_skb: ++ free_rx_fd(priv, fd, vaddr); ++err_frame_format: ++ percpu_stats->rx_dropped++; ++} ++ ++#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE ++/* Processing of Rx frames received on the error FQ ++ * We check and print the error bits and then free the frame ++ */ ++static void dpaa2_eth_rx_err(struct dpaa2_eth_priv *priv, ++ struct dpaa2_eth_channel *ch, ++ const struct dpaa2_fd *fd, ++ struct napi_struct *napi __always_unused, ++ u16 queue_id __always_unused) ++{ ++ struct device *dev = priv->net_dev->dev.parent; ++ dma_addr_t addr = dpaa2_fd_get_addr(fd); ++ void *vaddr; ++ struct rtnl_link_stats64 *percpu_stats; ++ struct dpaa2_fas *fas; ++ u32 status = 0; ++ bool check_fas_errors = false; ++ ++ vaddr = dpaa2_eth_iova_to_virt(priv->iommu_domain, addr); ++ dma_unmap_single(dev, addr, DPAA2_ETH_RX_BUF_SIZE, DMA_FROM_DEVICE); ++ ++ /* check frame errors in the FD field */ ++ if (fd->simple.ctrl & DPAA2_FD_RX_ERR_MASK) { ++ check_fas_errors = !!(fd->simple.ctrl & FD_CTRL_FAERR) && ++ !!(dpaa2_fd_get_frc(fd) & DPAA2_FD_FRC_FASV); ++ if (net_ratelimit()) ++ netdev_dbg(priv->net_dev, "Rx frame FD err: %x08\n", ++ fd->simple.ctrl & DPAA2_FD_RX_ERR_MASK); ++ } ++ ++ /* check frame errors in the FAS field */ ++ if (check_fas_errors) { ++ fas = dpaa2_eth_get_fas(vaddr); ++ status = le32_to_cpu(fas->status); ++ if (net_ratelimit()) ++ netdev_dbg(priv->net_dev, "Rx frame FAS err: 0x%08x\n", ++ status & DPAA2_FAS_RX_ERR_MASK); ++ } ++ free_rx_fd(priv, fd, vaddr); ++ ++ percpu_stats = this_cpu_ptr(priv->percpu_stats); ++ percpu_stats->rx_errors++; ++} ++#endif ++ ++/* Consume all frames pull-dequeued into the store. This is the simplest way to ++ * make sure we don't accidentally issue another volatile dequeue which would ++ * overwrite (leak) frames already in the store. ++ * ++ * The number of frames is returned using the last 2 output arguments, ++ * separately for Rx and Tx confirmations. ++ * ++ * Observance of NAPI budget is not our concern, leaving that to the caller. ++ */ ++static bool consume_frames(struct dpaa2_eth_channel *ch, int *rx_cleaned, ++ int *tx_conf_cleaned) ++{ ++ struct dpaa2_eth_priv *priv = ch->priv; ++ struct dpaa2_eth_fq *fq = NULL; ++ struct dpaa2_dq *dq; ++ const struct dpaa2_fd *fd; ++ int cleaned = 0; ++ int is_last; ++ ++ do { ++ dq = dpaa2_io_store_next(ch->store, &is_last); ++ if (unlikely(!dq)) { ++ /* If we're here, we *must* have placed a ++ * volatile dequeue comnmand, so keep reading through ++ * the store until we get some sort of valid response ++ * token (either a valid frame or an "empty dequeue") ++ */ ++ continue; ++ } ++ ++ fd = dpaa2_dq_fd(dq); ++ ++ /* prefetch the frame descriptor */ ++ prefetch(fd); ++ ++ fq = (struct dpaa2_eth_fq *)dpaa2_dq_fqd_ctx(dq); ++ fq->consume(priv, ch, fd, &ch->napi, fq->flowid); ++ cleaned++; ++ } while (!is_last); ++ ++ if (!cleaned) ++ return false; ++ ++ /* All frames brought in store by a volatile dequeue ++ * come from the same queue ++ */ ++ if (fq->type == DPAA2_TX_CONF_FQ) ++ *tx_conf_cleaned += cleaned; ++ else ++ *rx_cleaned += cleaned; ++ ++ fq->stats.frames += cleaned; ++ ch->stats.frames += cleaned; ++ ++ return true; ++} ++ ++/* Configure the egress frame annotation for timestamp update */ ++static void enable_tx_tstamp(struct dpaa2_fd *fd, void *buf_start) ++{ ++ struct dpaa2_faead *faead; ++ u32 ctrl; ++ u32 frc; ++ ++ /* Mark the egress frame annotation area as valid */ ++ frc = dpaa2_fd_get_frc(fd); ++ dpaa2_fd_set_frc(fd, frc | DPAA2_FD_FRC_FAEADV); ++ ++ /* enable UPD (update prepanded data) bit in FAEAD field of ++ * hardware frame annotation area ++ */ ++ ctrl = DPAA2_FAEAD_A2V | DPAA2_FAEAD_UPDV | DPAA2_FAEAD_UPD; ++ faead = dpaa2_eth_get_faead(buf_start); ++ faead->ctrl = cpu_to_le32(ctrl); ++} ++ ++/* Create a frame descriptor based on a fragmented skb */ ++static int build_sg_fd(struct dpaa2_eth_priv *priv, ++ struct sk_buff *skb, ++ struct dpaa2_fd *fd) ++{ ++ struct device *dev = priv->net_dev->dev.parent; ++ void *sgt_buf = NULL; ++ dma_addr_t addr; ++ int nr_frags = skb_shinfo(skb)->nr_frags; ++ struct dpaa2_sg_entry *sgt; ++ int i, err; ++ int sgt_buf_size; ++ struct scatterlist *scl, *crt_scl; ++ int num_sg; ++ int num_dma_bufs; ++ struct dpaa2_fas *fas; ++ struct dpaa2_eth_swa *swa; ++ ++ /* Create and map scatterlist. ++ * We don't advertise NETIF_F_FRAGLIST, so skb_to_sgvec() will not have ++ * to go beyond nr_frags+1. ++ * Note: We don't support chained scatterlists ++ */ ++ if (unlikely(PAGE_SIZE / sizeof(struct scatterlist) < nr_frags + 1)) ++ return -EINVAL; ++ ++ scl = kcalloc(nr_frags + 1, sizeof(struct scatterlist), GFP_ATOMIC); ++ if (unlikely(!scl)) ++ return -ENOMEM; ++ ++ sg_init_table(scl, nr_frags + 1); ++ num_sg = skb_to_sgvec(skb, scl, 0, skb->len); ++ num_dma_bufs = dma_map_sg(dev, scl, num_sg, DMA_TO_DEVICE); ++ if (unlikely(!num_dma_bufs)) { ++ err = -ENOMEM; ++ goto dma_map_sg_failed; ++ } ++ ++ /* Prepare the HW SGT structure */ ++ sgt_buf_size = priv->tx_data_offset + ++ sizeof(struct dpaa2_sg_entry) * (1 + num_dma_bufs); ++ sgt_buf = kzalloc(sgt_buf_size + DPAA2_ETH_TX_BUF_ALIGN, GFP_ATOMIC); ++ if (unlikely(!sgt_buf)) { ++ err = -ENOMEM; ++ goto sgt_buf_alloc_failed; ++ } ++ sgt_buf = PTR_ALIGN(sgt_buf, DPAA2_ETH_TX_BUF_ALIGN); ++ ++ /* PTA from egress side is passed as is to the confirmation side so ++ * we need to clear some fields here in order to find consistent values ++ * on TX confirmation. We are clearing FAS (Frame Annotation Status) ++ * field from the hardware annotation area ++ */ ++ fas = dpaa2_eth_get_fas(sgt_buf); ++ memset(fas, 0, DPAA2_FAS_SIZE); ++ ++ sgt = (struct dpaa2_sg_entry *)(sgt_buf + priv->tx_data_offset); ++ ++ /* Fill in the HW SGT structure. ++ * ++ * sgt_buf is zeroed out, so the following fields are implicit ++ * in all sgt entries: ++ * - offset is 0 ++ * - format is 'dpaa2_sg_single' ++ */ ++ for_each_sg(scl, crt_scl, num_dma_bufs, i) { ++ dpaa2_sg_set_addr(&sgt[i], sg_dma_address(crt_scl)); ++ dpaa2_sg_set_len(&sgt[i], sg_dma_len(crt_scl)); ++ } ++ dpaa2_sg_set_final(&sgt[i - 1], true); ++ ++ /* Store the skb backpointer in the SGT buffer. ++ * Fit the scatterlist and the number of buffers alongside the ++ * skb backpointer in the software annotation area. We'll need ++ * all of them on Tx Conf. ++ */ ++ swa = (struct dpaa2_eth_swa *)sgt_buf; ++ swa->skb = skb; ++ swa->scl = scl; ++ swa->num_sg = num_sg; ++ swa->num_dma_bufs = num_dma_bufs; ++ ++ /* Separately map the SGT buffer */ ++ addr = dma_map_single(dev, sgt_buf, sgt_buf_size, DMA_BIDIRECTIONAL); ++ if (unlikely(dma_mapping_error(dev, addr))) { ++ err = -ENOMEM; ++ goto dma_map_single_failed; ++ } ++ dpaa2_fd_set_offset(fd, priv->tx_data_offset); ++ dpaa2_fd_set_format(fd, dpaa2_fd_sg); ++ dpaa2_fd_set_addr(fd, addr); ++ dpaa2_fd_set_len(fd, skb->len); ++ ++ fd->simple.ctrl = DPAA2_FD_CTRL_ASAL | FD_CTRL_PTA | FD_CTRL_PTV1; ++ ++ if (priv->ts_tx_en && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) ++ enable_tx_tstamp(fd, sgt_buf); ++ ++ return 0; ++ ++dma_map_single_failed: ++ kfree(sgt_buf); ++sgt_buf_alloc_failed: ++ dma_unmap_sg(dev, scl, num_sg, DMA_TO_DEVICE); ++dma_map_sg_failed: ++ kfree(scl); ++ return err; ++} ++ ++/* Create a frame descriptor based on a linear skb */ ++static int build_single_fd(struct dpaa2_eth_priv *priv, ++ struct sk_buff *skb, ++ struct dpaa2_fd *fd) ++{ ++ struct device *dev = priv->net_dev->dev.parent; ++ u8 *buffer_start; ++ struct sk_buff **skbh; ++ dma_addr_t addr; ++ struct dpaa2_fas *fas; ++ ++ buffer_start = PTR_ALIGN(skb->data - priv->tx_data_offset - ++ DPAA2_ETH_TX_BUF_ALIGN, ++ DPAA2_ETH_TX_BUF_ALIGN); ++ ++ /* PTA from egress side is passed as is to the confirmation side so ++ * we need to clear some fields here in order to find consistent values ++ * on TX confirmation. We are clearing FAS (Frame Annotation Status) ++ * field from the hardware annotation area ++ */ ++ fas = dpaa2_eth_get_fas(buffer_start); ++ memset(fas, 0, DPAA2_FAS_SIZE); ++ ++ /* Store a backpointer to the skb at the beginning of the buffer ++ * (in the private data area) such that we can release it ++ * on Tx confirm ++ */ ++ skbh = (struct sk_buff **)buffer_start; ++ *skbh = skb; ++ ++ addr = dma_map_single(dev, buffer_start, ++ skb_tail_pointer(skb) - buffer_start, ++ DMA_BIDIRECTIONAL); ++ if (unlikely(dma_mapping_error(dev, addr))) ++ return -ENOMEM; ++ ++ dpaa2_fd_set_addr(fd, addr); ++ dpaa2_fd_set_offset(fd, (u16)(skb->data - buffer_start)); ++ dpaa2_fd_set_len(fd, skb->len); ++ dpaa2_fd_set_format(fd, dpaa2_fd_single); ++ ++ fd->simple.ctrl = DPAA2_FD_CTRL_ASAL | FD_CTRL_PTA | FD_CTRL_PTV1; ++ ++ if (priv->ts_tx_en && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) ++ enable_tx_tstamp(fd, buffer_start); ++ ++ return 0; ++} ++ ++/* FD freeing routine on the Tx path ++ * ++ * DMA-unmap and free FD and possibly SGT buffer allocated on Tx. The skb ++ * back-pointed to is also freed. ++ * This can be called either from dpaa2_eth_tx_conf() or on the error path of ++ * dpaa2_eth_tx(). ++ * Optionally, return the frame annotation status word (FAS), which needs ++ * to be checked if we're on the confirmation path. ++ */ ++static void free_tx_fd(const struct dpaa2_eth_priv *priv, ++ const struct dpaa2_fd *fd, ++ u32 *status) ++{ ++ struct device *dev = priv->net_dev->dev.parent; ++ dma_addr_t fd_addr; ++ struct sk_buff **skbh, *skb; ++ unsigned char *buffer_start; ++ int unmap_size; ++ struct scatterlist *scl; ++ int num_sg, num_dma_bufs; ++ struct dpaa2_eth_swa *swa; ++ u8 fd_format = dpaa2_fd_get_format(fd); ++ struct dpaa2_fas *fas; ++ ++ fd_addr = dpaa2_fd_get_addr(fd); ++ skbh = dpaa2_eth_iova_to_virt(priv->iommu_domain, fd_addr); ++ ++ /* HWA - FAS, timestamp (for Tx confirmation frames) */ ++ fas = dpaa2_eth_get_fas(skbh); ++ prefetch(fas); ++ ++ switch (fd_format) { ++ case dpaa2_fd_single: ++ skb = *skbh; ++ buffer_start = (unsigned char *)skbh; ++ /* Accessing the skb buffer is safe before dma unmap, because ++ * we didn't map the actual skb shell. ++ */ ++ dma_unmap_single(dev, fd_addr, ++ skb_tail_pointer(skb) - buffer_start, ++ DMA_BIDIRECTIONAL); ++ break; ++ case dpaa2_fd_sg: ++ swa = (struct dpaa2_eth_swa *)skbh; ++ skb = swa->skb; ++ scl = swa->scl; ++ num_sg = swa->num_sg; ++ num_dma_bufs = swa->num_dma_bufs; ++ ++ /* Unmap the scatterlist */ ++ dma_unmap_sg(dev, scl, num_sg, DMA_TO_DEVICE); ++ kfree(scl); ++ ++ /* Unmap the SGT buffer */ ++ unmap_size = priv->tx_data_offset + ++ sizeof(struct dpaa2_sg_entry) * (1 + num_dma_bufs); ++ dma_unmap_single(dev, fd_addr, unmap_size, DMA_BIDIRECTIONAL); ++ break; ++ default: ++ /* Unsupported format, mark it as errored and give up */ ++ if (status) ++ *status = ~0; ++ return; ++ } ++ ++ /* Get the timestamp value */ ++ if (priv->ts_tx_en && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { ++ struct skb_shared_hwtstamps shhwtstamps; ++ u64 *ns; ++ ++ memset(&shhwtstamps, 0, sizeof(shhwtstamps)); ++ ++ ns = (u64 *)dpaa2_eth_get_ts(skbh); ++ *ns = DPAA2_PTP_NOMINAL_FREQ_PERIOD_NS * le64_to_cpup(ns); ++ shhwtstamps.hwtstamp = ns_to_ktime(*ns); ++ skb_tstamp_tx(skb, &shhwtstamps); ++ } ++ ++ /* Read the status from the Frame Annotation after we unmap the first ++ * buffer but before we free it. The caller function is responsible ++ * for checking the status value. ++ */ ++ if (status) ++ *status = le32_to_cpu(fas->status); ++ ++ /* Free SGT buffer kmalloc'ed on tx */ ++ if (fd_format != dpaa2_fd_single) ++ kfree(skbh); ++ ++ /* Move on with skb release */ ++ dev_kfree_skb(skb); ++} ++ ++static int dpaa2_eth_tx(struct sk_buff *skb, struct net_device *net_dev) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ struct device *dev = net_dev->dev.parent; ++ struct dpaa2_fd fd; ++ struct rtnl_link_stats64 *percpu_stats; ++ struct dpaa2_eth_drv_stats *percpu_extras; ++ struct dpaa2_eth_fq *fq; ++ u16 queue_mapping = skb_get_queue_mapping(skb); ++ int err, i; ++ ++ /* If we're congested, stop this tx queue; transmission of the ++ * current skb happens regardless of congestion state ++ */ ++ fq = &priv->fq[queue_mapping]; ++ ++ dma_sync_single_for_cpu(dev, priv->cscn_dma, ++ DPAA2_CSCN_SIZE, DMA_FROM_DEVICE); ++ if (unlikely(dpaa2_cscn_state_congested(priv->cscn_mem))) { ++ netif_stop_subqueue(net_dev, queue_mapping); ++ fq->stats.congestion_entry++; ++ } ++ ++ percpu_stats = this_cpu_ptr(priv->percpu_stats); ++ percpu_extras = this_cpu_ptr(priv->percpu_extras); ++ ++ if (unlikely(skb_headroom(skb) < DPAA2_ETH_NEEDED_HEADROOM(priv))) { ++ struct sk_buff *ns; ++ ++ ns = skb_realloc_headroom(skb, DPAA2_ETH_NEEDED_HEADROOM(priv)); ++ if (unlikely(!ns)) { ++ percpu_stats->tx_dropped++; ++ goto err_alloc_headroom; ++ } ++ dev_kfree_skb(skb); ++ skb = ns; ++ } ++ ++ /* We'll be holding a back-reference to the skb until Tx Confirmation; ++ * we don't want that overwritten by a concurrent Tx with a cloned skb. ++ */ ++ skb = skb_unshare(skb, GFP_ATOMIC); ++ if (unlikely(!skb)) { ++ /* skb_unshare() has already freed the skb */ ++ percpu_stats->tx_dropped++; ++ return NETDEV_TX_OK; ++ } ++ ++ /* Setup the FD fields */ ++ memset(&fd, 0, sizeof(fd)); ++ ++ if (skb_is_nonlinear(skb)) { ++ err = build_sg_fd(priv, skb, &fd); ++ percpu_extras->tx_sg_frames++; ++ percpu_extras->tx_sg_bytes += skb->len; ++ } else { ++ err = build_single_fd(priv, skb, &fd); ++ } ++ ++ if (unlikely(err)) { ++ percpu_stats->tx_dropped++; ++ goto err_build_fd; ++ } ++ ++ /* Tracing point */ ++ trace_dpaa2_tx_fd(net_dev, &fd); ++ ++ for (i = 0; i < DPAA2_ETH_ENQUEUE_RETRIES; i++) { ++ err = dpaa2_io_service_enqueue_qd(NULL, priv->tx_qdid, 0, ++ fq->tx_qdbin, &fd); ++ /* TODO: This doesn't work. Check on simulator. ++ * err = dpaa2_io_service_enqueue_fq(NULL, ++ * priv->fq[0].fqid_tx, &fd); ++ */ ++ if (err != -EBUSY) ++ break; ++ } ++ percpu_extras->tx_portal_busy += i; ++ if (unlikely(err < 0)) { ++ percpu_stats->tx_errors++; ++ /* Clean up everything, including freeing the skb */ ++ free_tx_fd(priv, &fd, NULL); ++ } else { ++ percpu_stats->tx_packets++; ++ percpu_stats->tx_bytes += dpaa2_fd_get_len(&fd); ++ } ++ ++ return NETDEV_TX_OK; ++ ++err_build_fd: ++err_alloc_headroom: ++ dev_kfree_skb(skb); ++ ++ return NETDEV_TX_OK; ++} ++ ++/* Tx confirmation frame processing routine */ ++static void dpaa2_eth_tx_conf(struct dpaa2_eth_priv *priv, ++ struct dpaa2_eth_channel *ch, ++ const struct dpaa2_fd *fd, ++ struct napi_struct *napi __always_unused, ++ u16 queue_id) ++{ ++ struct device *dev = priv->net_dev->dev.parent; ++ struct rtnl_link_stats64 *percpu_stats; ++ struct dpaa2_eth_drv_stats *percpu_extras; ++ u32 status = 0; ++ bool errors = !!(fd->simple.ctrl & DPAA2_FD_TX_ERR_MASK); ++ bool check_fas_errors = false; ++ ++ /* Tracing point */ ++ trace_dpaa2_tx_conf_fd(priv->net_dev, fd); ++ ++ percpu_extras = this_cpu_ptr(priv->percpu_extras); ++ percpu_extras->tx_conf_frames++; ++ percpu_extras->tx_conf_bytes += dpaa2_fd_get_len(fd); ++ ++ /* Check congestion state and wake all queues if necessary */ ++ if (unlikely(__netif_subqueue_stopped(priv->net_dev, queue_id))) { ++ dma_sync_single_for_cpu(dev, priv->cscn_dma, ++ DPAA2_CSCN_SIZE, DMA_FROM_DEVICE); ++ if (!dpaa2_cscn_state_congested(priv->cscn_mem)) ++ netif_tx_wake_all_queues(priv->net_dev); ++ } ++ ++ /* check frame errors in the FD field */ ++ if (unlikely(errors)) { ++ check_fas_errors = !!(fd->simple.ctrl & FD_CTRL_FAERR) && ++ !!(dpaa2_fd_get_frc(fd) & DPAA2_FD_FRC_FASV); ++ if (net_ratelimit()) ++ netdev_dbg(priv->net_dev, "Tx frame FD err: %x08\n", ++ fd->simple.ctrl & DPAA2_FD_TX_ERR_MASK); ++ } ++ ++ free_tx_fd(priv, fd, check_fas_errors ? &status : NULL); ++ ++ /* if there are no errors, we're done */ ++ if (likely(!errors)) ++ return; ++ ++ percpu_stats = this_cpu_ptr(priv->percpu_stats); ++ /* Tx-conf logically pertains to the egress path. */ ++ percpu_stats->tx_errors++; ++ ++ if (net_ratelimit()) ++ netdev_dbg(priv->net_dev, "Tx frame FAS err: %x08\n", ++ status & DPAA2_FAS_TX_ERR_MASK); ++} ++ ++static int set_rx_csum(struct dpaa2_eth_priv *priv, bool enable) ++{ ++ int err; ++ ++ err = dpni_set_offload(priv->mc_io, 0, priv->mc_token, ++ DPNI_OFF_RX_L3_CSUM, enable); ++ if (err) { ++ netdev_err(priv->net_dev, ++ "dpni_set_offload() DPNI_OFF_RX_L3_CSUM failed\n"); ++ return err; ++ } ++ ++ err = dpni_set_offload(priv->mc_io, 0, priv->mc_token, ++ DPNI_OFF_RX_L4_CSUM, enable); ++ if (err) { ++ netdev_err(priv->net_dev, ++ "dpni_set_offload() DPNI_OFF_RX_L4_CSUM failed\n"); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int set_tx_csum(struct dpaa2_eth_priv *priv, bool enable) ++{ ++ int err; ++ ++ err = dpni_set_offload(priv->mc_io, 0, priv->mc_token, ++ DPNI_OFF_TX_L3_CSUM, enable); ++ if (err) { ++ netdev_err(priv->net_dev, ++ "dpni_set_offload() DPNI_OFF_RX_L3_CSUM failed\n"); ++ return err; ++ } ++ ++ err = dpni_set_offload(priv->mc_io, 0, priv->mc_token, ++ DPNI_OFF_TX_L4_CSUM, enable); ++ if (err) { ++ netdev_err(priv->net_dev, ++ "dpni_set_offload() DPNI_OFF_RX_L4_CSUM failed\n"); ++ return err; ++ } ++ ++ return 0; ++} ++ ++/* Perform a single release command to add buffers ++ * to the specified buffer pool ++ */ ++static int add_bufs(struct dpaa2_eth_priv *priv, u16 bpid) ++{ ++ struct device *dev = priv->net_dev->dev.parent; ++ u64 buf_array[DPAA2_ETH_BUFS_PER_CMD]; ++ void *buf; ++ dma_addr_t addr; ++ int i; ++ ++ for (i = 0; i < DPAA2_ETH_BUFS_PER_CMD; i++) { ++ /* Allocate buffer visible to WRIOP + skb shared info + ++ * alignment padding. ++ */ ++ buf = napi_alloc_frag(DPAA2_ETH_BUF_RAW_SIZE(priv)); ++ if (unlikely(!buf)) ++ goto err_alloc; ++ ++ buf = PTR_ALIGN(buf, priv->rx_buf_align); ++ ++ addr = dma_map_single(dev, buf, DPAA2_ETH_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); ++ if (unlikely(dma_mapping_error(dev, addr))) ++ goto err_map; ++ ++ buf_array[i] = addr; ++ ++ /* tracing point */ ++ trace_dpaa2_eth_buf_seed(priv->net_dev, ++ buf, DPAA2_ETH_BUF_RAW_SIZE(priv), ++ addr, DPAA2_ETH_RX_BUF_SIZE, ++ bpid); ++ } ++ ++release_bufs: ++ /* In case the portal is busy, retry until successful. ++ * The buffer release function would only fail if the QBMan portal ++ * was busy, which implies portal contention (i.e. more CPUs than ++ * portals, i.e. GPPs w/o affine DPIOs). For all practical purposes, ++ * there is little we can realistically do, short of giving up - ++ * in which case we'd risk depleting the buffer pool and never again ++ * receiving the Rx interrupt which would kick-start the refill logic. ++ * So just keep retrying, at the risk of being moved to ksoftirqd. ++ */ ++ while (dpaa2_io_service_release(NULL, bpid, buf_array, i)) ++ cpu_relax(); ++ return i; ++ ++err_map: ++ put_page(virt_to_head_page(buf)); ++err_alloc: ++ if (i) ++ goto release_bufs; ++ ++ return 0; ++} ++ ++static int seed_pool(struct dpaa2_eth_priv *priv, u16 bpid) ++{ ++ int i, j; ++ int new_count; ++ ++ /* This is the lazy seeding of Rx buffer pools. ++ * dpaa2_add_bufs() is also used on the Rx hotpath and calls ++ * napi_alloc_frag(). The trouble with that is that it in turn ends up ++ * calling this_cpu_ptr(), which mandates execution in atomic context. ++ * Rather than splitting up the code, do a one-off preempt disable. ++ */ ++ preempt_disable(); ++ for (j = 0; j < priv->num_channels; j++) { ++ priv->channel[j]->buf_count = 0; ++ for (i = 0; i < priv->num_bufs; ++ i += DPAA2_ETH_BUFS_PER_CMD) { ++ new_count = add_bufs(priv, bpid); ++ priv->channel[j]->buf_count += new_count; ++ ++ if (new_count < DPAA2_ETH_BUFS_PER_CMD) { ++ preempt_enable(); ++ return -ENOMEM; ++ } ++ } ++ } ++ preempt_enable(); ++ ++ return 0; ++} ++ ++/** ++ * Drain the specified number of buffers from the DPNI's private buffer pool. ++ * @count must not exceeed DPAA2_ETH_BUFS_PER_CMD ++ */ ++static void drain_bufs(struct dpaa2_eth_priv *priv, int count) ++{ ++ struct device *dev = priv->net_dev->dev.parent; ++ u64 buf_array[DPAA2_ETH_BUFS_PER_CMD]; ++ void *vaddr; ++ int ret, i; ++ ++ do { ++ ret = dpaa2_io_service_acquire(NULL, priv->bpid, ++ buf_array, count); ++ if (ret < 0) { ++ netdev_err(priv->net_dev, "dpaa2_io_service_acquire() failed\n"); ++ return; ++ } ++ for (i = 0; i < ret; i++) { ++ /* Same logic as on regular Rx path */ ++ vaddr = dpaa2_eth_iova_to_virt(priv->iommu_domain, ++ buf_array[i]); ++ dma_unmap_single(dev, buf_array[i], ++ DPAA2_ETH_RX_BUF_SIZE, ++ DMA_FROM_DEVICE); ++ put_page(virt_to_head_page(vaddr)); ++ } ++ } while (ret); ++} ++ ++static void drain_pool(struct dpaa2_eth_priv *priv) ++{ ++ preempt_disable(); ++ drain_bufs(priv, DPAA2_ETH_BUFS_PER_CMD); ++ drain_bufs(priv, 1); ++ preempt_enable(); ++} ++ ++/* Function is called from softirq context only, so we don't need to guard ++ * the access to percpu count ++ */ ++static int refill_pool(struct dpaa2_eth_priv *priv, ++ struct dpaa2_eth_channel *ch, ++ u16 bpid) ++{ ++ int new_count; ++ ++ if (likely(ch->buf_count >= priv->refill_thresh)) ++ return 0; ++ ++ do { ++ new_count = add_bufs(priv, bpid); ++ if (unlikely(!new_count)) { ++ /* Out of memory; abort for now, we'll try later on */ ++ break; ++ } ++ ch->buf_count += new_count; ++ } while (ch->buf_count < priv->num_bufs); ++ ++ if (unlikely(ch->buf_count < priv->num_bufs)) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++static int pull_channel(struct dpaa2_eth_channel *ch) ++{ ++ int err; ++ int dequeues = -1; ++ ++ /* Retry while portal is busy */ ++ do { ++ err = dpaa2_io_service_pull_channel(NULL, ch->ch_id, ch->store); ++ dequeues++; ++ cpu_relax(); ++ } while (err == -EBUSY); ++ ++ ch->stats.dequeue_portal_busy += dequeues; ++ if (unlikely(err)) ++ ch->stats.pull_err++; ++ ++ return err; ++} ++ ++/* NAPI poll routine ++ * ++ * Frames are dequeued from the QMan channel associated with this NAPI context. ++ * Rx and (if configured) Rx error frames count towards the NAPI budget. Tx ++ * confirmation frames are limited by a threshold per NAPI poll cycle. ++ */ ++static int dpaa2_eth_poll(struct napi_struct *napi, int budget) ++{ ++ struct dpaa2_eth_channel *ch; ++ int rx_cleaned = 0, tx_conf_cleaned = 0; ++ bool store_cleaned; ++ struct dpaa2_eth_priv *priv; ++ int err; ++ ++ ch = container_of(napi, struct dpaa2_eth_channel, napi); ++ priv = ch->priv; ++ ++ do { ++ err = pull_channel(ch); ++ if (unlikely(err)) ++ break; ++ ++ /* Refill pool if appropriate */ ++ refill_pool(priv, ch, priv->bpid); ++ ++ store_cleaned = consume_frames(ch, &rx_cleaned, ++ &tx_conf_cleaned); ++ ++ /* If we've either consumed the budget with Rx frames, ++ * or reached the Tx conf threshold, we're done. ++ */ ++ if (rx_cleaned >= budget || ++ tx_conf_cleaned >= TX_CONF_PER_NAPI_POLL) ++ return budget; ++ } while (store_cleaned); ++ ++ /* We didn't consume the entire budget, finish napi and ++ * re-enable data availability notifications. ++ */ ++ napi_complete(napi); ++ do { ++ err = dpaa2_io_service_rearm(NULL, &ch->nctx); ++ cpu_relax(); ++ } while (err == -EBUSY); ++ ++ return max(rx_cleaned, 1); ++} ++ ++static void enable_ch_napi(struct dpaa2_eth_priv *priv) ++{ ++ struct dpaa2_eth_channel *ch; ++ int i; ++ ++ for (i = 0; i < priv->num_channels; i++) { ++ ch = priv->channel[i]; ++ napi_enable(&ch->napi); ++ } ++} ++ ++static void disable_ch_napi(struct dpaa2_eth_priv *priv) ++{ ++ struct dpaa2_eth_channel *ch; ++ int i; ++ ++ for (i = 0; i < priv->num_channels; i++) { ++ ch = priv->channel[i]; ++ napi_disable(&ch->napi); ++ } ++} ++ ++static int link_state_update(struct dpaa2_eth_priv *priv) ++{ ++ struct dpni_link_state state; ++ int err; ++ ++ err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token, &state); ++ if (unlikely(err)) { ++ netdev_err(priv->net_dev, ++ "dpni_get_link_state() failed\n"); ++ return err; ++ } ++ ++ /* Chech link state; speed / duplex changes are not treated yet */ ++ if (priv->link_state.up == state.up) ++ return 0; ++ ++ priv->link_state = state; ++ if (state.up) { ++ netif_carrier_on(priv->net_dev); ++ netif_tx_start_all_queues(priv->net_dev); ++ } else { ++ netif_tx_stop_all_queues(priv->net_dev); ++ netif_carrier_off(priv->net_dev); ++ } ++ ++ netdev_info(priv->net_dev, "Link Event: state %s", ++ state.up ? "up" : "down"); ++ ++ return 0; ++} ++ ++static int dpaa2_eth_open(struct net_device *net_dev) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ int err; ++ ++ /* We'll only start the txqs when the link is actually ready; make sure ++ * we don't race against the link up notification, which may come ++ * immediately after dpni_enable(); ++ */ ++ netif_tx_stop_all_queues(net_dev); ++ ++ /* Also, explicitly set carrier off, otherwise netif_carrier_ok() will ++ * return true and cause 'ip link show' to report the LOWER_UP flag, ++ * even though the link notification wasn't even received. ++ */ ++ netif_carrier_off(net_dev); ++ ++ err = seed_pool(priv, priv->bpid); ++ if (err) { ++ /* Not much to do; the buffer pool, though not filled up, ++ * may still contain some buffers which would enable us ++ * to limp on. ++ */ ++ netdev_err(net_dev, "Buffer seeding failed for DPBP %d (bpid=%d)\n", ++ priv->dpbp_dev->obj_desc.id, priv->bpid); ++ } ++ ++ if (priv->tx_pause_frames) ++ priv->refill_thresh = priv->num_bufs - DPAA2_ETH_BUFS_PER_CMD; ++ else ++ priv->refill_thresh = DPAA2_ETH_REFILL_THRESH_TD; ++ ++ err = dpni_enable(priv->mc_io, 0, priv->mc_token); ++ if (err < 0) { ++ netdev_err(net_dev, "dpni_enable() failed\n"); ++ goto enable_err; ++ } ++ ++ /* If the DPMAC object has already processed the link up interrupt, ++ * we have to learn the link state ourselves. ++ */ ++ err = link_state_update(priv); ++ if (err < 0) { ++ netdev_err(net_dev, "Can't update link state\n"); ++ goto link_state_err; ++ } ++ ++ return 0; ++ ++link_state_err: ++enable_err: ++ priv->refill_thresh = 0; ++ drain_pool(priv); ++ return err; ++} ++ ++static int dpaa2_eth_stop(struct net_device *net_dev) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ int dpni_enabled; ++ int retries = 10, i; ++ ++ netif_tx_stop_all_queues(net_dev); ++ netif_carrier_off(net_dev); ++ ++ /* Loop while dpni_disable() attempts to drain the egress FQs ++ * and confirm them back to us. ++ */ ++ do { ++ dpni_disable(priv->mc_io, 0, priv->mc_token); ++ dpni_is_enabled(priv->mc_io, 0, priv->mc_token, &dpni_enabled); ++ if (dpni_enabled) ++ /* Allow the MC some slack */ ++ msleep(100); ++ } while (dpni_enabled && --retries); ++ if (!retries) { ++ netdev_warn(net_dev, "Retry count exceeded disabling DPNI\n"); ++ /* Must go on and disable NAPI nonetheless, so we don't crash at ++ * the next "ifconfig up" ++ */ ++ } ++ ++ priv->refill_thresh = 0; ++ ++ /* Wait for all running napi poll routines to finish, so that no ++ * new refill operations are started. ++ */ ++ for (i = 0; i < priv->num_channels; i++) ++ napi_synchronize(&priv->channel[i]->napi); ++ ++ /* Empty the buffer pool */ ++ drain_pool(priv); ++ ++ return 0; ++} ++ ++static int dpaa2_eth_init(struct net_device *net_dev) ++{ ++ u64 supported = 0; ++ u64 not_supported = 0; ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ u32 options = priv->dpni_attrs.options; ++ ++ /* Capabilities listing */ ++ supported |= IFF_LIVE_ADDR_CHANGE; ++ ++ if (options & DPNI_OPT_NO_MAC_FILTER) ++ not_supported |= IFF_UNICAST_FLT; ++ else ++ supported |= IFF_UNICAST_FLT; ++ ++ net_dev->priv_flags |= supported; ++ net_dev->priv_flags &= ~not_supported; ++ ++ /* Features */ ++ net_dev->features = NETIF_F_RXCSUM | ++ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | ++ NETIF_F_SG | NETIF_F_HIGHDMA | ++ NETIF_F_LLTX; ++ net_dev->hw_features = net_dev->features; ++ ++ return 0; ++} ++ ++static int dpaa2_eth_set_addr(struct net_device *net_dev, void *addr) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ struct device *dev = net_dev->dev.parent; ++ int err; ++ ++ err = eth_mac_addr(net_dev, addr); ++ if (err < 0) { ++ dev_err(dev, "eth_mac_addr() failed (%d)\n", err); ++ return err; ++ } ++ ++ err = dpni_set_primary_mac_addr(priv->mc_io, 0, priv->mc_token, ++ net_dev->dev_addr); ++ if (err) { ++ dev_err(dev, "dpni_set_primary_mac_addr() failed (%d)\n", err); ++ return err; ++ } ++ ++ return 0; ++} ++ ++/** Fill in counters maintained by the GPP driver. These may be different from ++ * the hardware counters obtained by ethtool. ++ */ ++static void dpaa2_eth_get_stats(struct net_device *net_dev, ++ struct rtnl_link_stats64 *stats) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ struct rtnl_link_stats64 *percpu_stats; ++ u64 *cpustats; ++ u64 *netstats = (u64 *)stats; ++ int i, j; ++ int num = sizeof(struct rtnl_link_stats64) / sizeof(u64); ++ ++ for_each_possible_cpu(i) { ++ percpu_stats = per_cpu_ptr(priv->percpu_stats, i); ++ cpustats = (u64 *)percpu_stats; ++ for (j = 0; j < num; j++) ++ netstats[j] += cpustats[j]; ++ } ++} ++ ++static int dpaa2_eth_change_mtu(struct net_device *net_dev, int mtu) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ int err; ++ ++ /* Set the maximum Rx frame length to match the transmit side; ++ * account for L2 headers when computing the MFL ++ */ ++ err = dpni_set_max_frame_length(priv->mc_io, 0, priv->mc_token, ++ (u16)DPAA2_ETH_L2_MAX_FRM(mtu)); ++ if (err) { ++ netdev_err(net_dev, "dpni_set_max_frame_length() failed\n"); ++ return err; ++ } ++ ++ net_dev->mtu = mtu; ++ return 0; ++} ++ ++/* Copy mac unicast addresses from @net_dev to @priv. ++ * Its sole purpose is to make dpaa2_eth_set_rx_mode() more readable. ++ */ ++static void add_uc_hw_addr(const struct net_device *net_dev, ++ struct dpaa2_eth_priv *priv) ++{ ++ struct netdev_hw_addr *ha; ++ int err; ++ ++ netdev_for_each_uc_addr(ha, net_dev) { ++ err = dpni_add_mac_addr(priv->mc_io, 0, priv->mc_token, ++ ha->addr); ++ if (err) ++ netdev_warn(priv->net_dev, ++ "Could not add ucast MAC %pM to the filtering table (err %d)\n", ++ ha->addr, err); ++ } ++} ++ ++/* Copy mac multicast addresses from @net_dev to @priv ++ * Its sole purpose is to make dpaa2_eth_set_rx_mode() more readable. ++ */ ++static void add_mc_hw_addr(const struct net_device *net_dev, ++ struct dpaa2_eth_priv *priv) ++{ ++ struct netdev_hw_addr *ha; ++ int err; ++ ++ netdev_for_each_mc_addr(ha, net_dev) { ++ err = dpni_add_mac_addr(priv->mc_io, 0, priv->mc_token, ++ ha->addr); ++ if (err) ++ netdev_warn(priv->net_dev, ++ "Could not add mcast MAC %pM to the filtering table (err %d)\n", ++ ha->addr, err); ++ } ++} ++ ++static void dpaa2_eth_set_rx_mode(struct net_device *net_dev) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ int uc_count = netdev_uc_count(net_dev); ++ int mc_count = netdev_mc_count(net_dev); ++ u8 max_mac = priv->dpni_attrs.mac_filter_entries; ++ u32 options = priv->dpni_attrs.options; ++ u16 mc_token = priv->mc_token; ++ struct fsl_mc_io *mc_io = priv->mc_io; ++ int err; ++ ++ /* Basic sanity checks; these probably indicate a misconfiguration */ ++ if (options & DPNI_OPT_NO_MAC_FILTER && max_mac != 0) ++ netdev_info(net_dev, ++ "mac_filter_entries=%d, DPNI_OPT_NO_MAC_FILTER option must be disabled\n", ++ max_mac); ++ ++ /* Force promiscuous if the uc or mc counts exceed our capabilities. */ ++ if (uc_count > max_mac) { ++ netdev_info(net_dev, ++ "Unicast addr count reached %d, max allowed is %d; forcing promisc\n", ++ uc_count, max_mac); ++ goto force_promisc; ++ } ++ if (mc_count + uc_count > max_mac) { ++ netdev_info(net_dev, ++ "Unicast + Multicast addr count reached %d, max allowed is %d; forcing promisc\n", ++ uc_count + mc_count, max_mac); ++ goto force_mc_promisc; ++ } ++ ++ /* Adjust promisc settings due to flag combinations */ ++ if (net_dev->flags & IFF_PROMISC) ++ goto force_promisc; ++ if (net_dev->flags & IFF_ALLMULTI) { ++ /* First, rebuild unicast filtering table. This should be done ++ * in promisc mode, in order to avoid frame loss while we ++ * progressively add entries to the table. ++ * We don't know whether we had been in promisc already, and ++ * making an MC call to find out is expensive; so set uc promisc ++ * nonetheless. ++ */ ++ err = dpni_set_unicast_promisc(mc_io, 0, mc_token, 1); ++ if (err) ++ netdev_warn(net_dev, "Can't set uc promisc\n"); ++ ++ /* Actual uc table reconstruction. */ ++ err = dpni_clear_mac_filters(mc_io, 0, mc_token, 1, 0); ++ if (err) ++ netdev_warn(net_dev, "Can't clear uc filters\n"); ++ add_uc_hw_addr(net_dev, priv); ++ ++ /* Finally, clear uc promisc and set mc promisc as requested. */ ++ err = dpni_set_unicast_promisc(mc_io, 0, mc_token, 0); ++ if (err) ++ netdev_warn(net_dev, "Can't clear uc promisc\n"); ++ goto force_mc_promisc; ++ } ++ ++ /* Neither unicast, nor multicast promisc will be on... eventually. ++ * For now, rebuild mac filtering tables while forcing both of them on. ++ */ ++ err = dpni_set_unicast_promisc(mc_io, 0, mc_token, 1); ++ if (err) ++ netdev_warn(net_dev, "Can't set uc promisc (%d)\n", err); ++ err = dpni_set_multicast_promisc(mc_io, 0, mc_token, 1); ++ if (err) ++ netdev_warn(net_dev, "Can't set mc promisc (%d)\n", err); ++ ++ /* Actual mac filtering tables reconstruction */ ++ err = dpni_clear_mac_filters(mc_io, 0, mc_token, 1, 1); ++ if (err) ++ netdev_warn(net_dev, "Can't clear mac filters\n"); ++ add_mc_hw_addr(net_dev, priv); ++ add_uc_hw_addr(net_dev, priv); ++ ++ /* Now we can clear both ucast and mcast promisc, without risking ++ * to drop legitimate frames anymore. ++ */ ++ err = dpni_set_unicast_promisc(mc_io, 0, mc_token, 0); ++ if (err) ++ netdev_warn(net_dev, "Can't clear ucast promisc\n"); ++ err = dpni_set_multicast_promisc(mc_io, 0, mc_token, 0); ++ if (err) ++ netdev_warn(net_dev, "Can't clear mcast promisc\n"); ++ ++ return; ++ ++force_promisc: ++ err = dpni_set_unicast_promisc(mc_io, 0, mc_token, 1); ++ if (err) ++ netdev_warn(net_dev, "Can't set ucast promisc\n"); ++force_mc_promisc: ++ err = dpni_set_multicast_promisc(mc_io, 0, mc_token, 1); ++ if (err) ++ netdev_warn(net_dev, "Can't set mcast promisc\n"); ++} ++ ++static int dpaa2_eth_set_features(struct net_device *net_dev, ++ netdev_features_t features) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ netdev_features_t changed = features ^ net_dev->features; ++ bool enable; ++ int err; ++ ++ if (changed & NETIF_F_RXCSUM) { ++ enable = !!(features & NETIF_F_RXCSUM); ++ err = set_rx_csum(priv, enable); ++ if (err) ++ return err; ++ } ++ ++ if (changed & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) { ++ enable = !!(features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)); ++ err = set_tx_csum(priv, enable); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int dpaa2_eth_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(dev); ++ struct hwtstamp_config config; ++ ++ if (copy_from_user(&config, rq->ifr_data, sizeof(config))) ++ return -EFAULT; ++ ++ switch (config.tx_type) { ++ case HWTSTAMP_TX_OFF: ++ priv->ts_tx_en = false; ++ break; ++ case HWTSTAMP_TX_ON: ++ priv->ts_tx_en = true; ++ break; ++ default: ++ return -ERANGE; ++ } ++ ++ if (config.rx_filter == HWTSTAMP_FILTER_NONE) { ++ priv->ts_rx_en = false; ++ } else { ++ priv->ts_rx_en = true; ++ /* TS is set for all frame types, not only those requested */ ++ config.rx_filter = HWTSTAMP_FILTER_ALL; ++ } ++ ++ return copy_to_user(rq->ifr_data, &config, sizeof(config)) ? ++ -EFAULT : 0; ++} ++ ++static int dpaa2_eth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ++{ ++ if (cmd == SIOCSHWTSTAMP) ++ return dpaa2_eth_ts_ioctl(dev, rq, cmd); ++ ++ return -EINVAL; ++} ++ ++static const struct net_device_ops dpaa2_eth_ops = { ++ .ndo_open = dpaa2_eth_open, ++ .ndo_start_xmit = dpaa2_eth_tx, ++ .ndo_stop = dpaa2_eth_stop, ++ .ndo_init = dpaa2_eth_init, ++ .ndo_set_mac_address = dpaa2_eth_set_addr, ++ .ndo_get_stats64 = dpaa2_eth_get_stats, ++ .ndo_change_mtu = dpaa2_eth_change_mtu, ++ .ndo_set_rx_mode = dpaa2_eth_set_rx_mode, ++ .ndo_set_features = dpaa2_eth_set_features, ++ .ndo_do_ioctl = dpaa2_eth_ioctl, ++}; ++ ++static void cdan_cb(struct dpaa2_io_notification_ctx *ctx) ++{ ++ struct dpaa2_eth_channel *ch; ++ ++ ch = container_of(ctx, struct dpaa2_eth_channel, nctx); ++ ++ /* Update NAPI statistics */ ++ ch->stats.cdan++; ++ ++ napi_schedule_irqoff(&ch->napi); ++} ++ ++/* Allocate and configure a DPCON object */ ++static struct fsl_mc_device *setup_dpcon(struct dpaa2_eth_priv *priv) ++{ ++ struct fsl_mc_device *dpcon; ++ struct device *dev = priv->net_dev->dev.parent; ++ struct dpcon_attr attrs; ++ int err; ++ ++ err = fsl_mc_object_allocate(to_fsl_mc_device(dev), ++ FSL_MC_POOL_DPCON, &dpcon); ++ if (err) { ++ dev_info(dev, "Not enough DPCONs, will go on as-is\n"); ++ return NULL; ++ } ++ ++ err = dpcon_open(priv->mc_io, 0, dpcon->obj_desc.id, &dpcon->mc_handle); ++ if (err) { ++ dev_err(dev, "dpcon_open() failed\n"); ++ goto err_open; ++ } ++ ++ err = dpcon_reset(priv->mc_io, 0, dpcon->mc_handle); ++ if (err) { ++ dev_err(dev, "dpcon_reset() failed\n"); ++ goto err_reset; ++ } ++ ++ err = dpcon_get_attributes(priv->mc_io, 0, dpcon->mc_handle, &attrs); ++ if (err) { ++ dev_err(dev, "dpcon_get_attributes() failed\n"); ++ goto err_get_attr; ++ } ++ ++ err = dpcon_enable(priv->mc_io, 0, dpcon->mc_handle); ++ if (err) { ++ dev_err(dev, "dpcon_enable() failed\n"); ++ goto err_enable; ++ } ++ ++ return dpcon; ++ ++err_enable: ++err_get_attr: ++err_reset: ++ dpcon_close(priv->mc_io, 0, dpcon->mc_handle); ++err_open: ++ fsl_mc_object_free(dpcon); ++ ++ return NULL; ++} ++ ++static void free_dpcon(struct dpaa2_eth_priv *priv, ++ struct fsl_mc_device *dpcon) ++{ ++ dpcon_disable(priv->mc_io, 0, dpcon->mc_handle); ++ dpcon_close(priv->mc_io, 0, dpcon->mc_handle); ++ fsl_mc_object_free(dpcon); ++} ++ ++static struct dpaa2_eth_channel * ++alloc_channel(struct dpaa2_eth_priv *priv) ++{ ++ struct dpaa2_eth_channel *channel; ++ struct dpcon_attr attr; ++ struct device *dev = priv->net_dev->dev.parent; ++ int err; ++ ++ channel = kzalloc(sizeof(*channel), GFP_KERNEL); ++ if (!channel) ++ return NULL; ++ ++ channel->dpcon = setup_dpcon(priv); ++ if (!channel->dpcon) ++ goto err_setup; ++ ++ err = dpcon_get_attributes(priv->mc_io, 0, channel->dpcon->mc_handle, ++ &attr); ++ if (err) { ++ dev_err(dev, "dpcon_get_attributes() failed\n"); ++ goto err_get_attr; ++ } ++ ++ channel->dpcon_id = attr.id; ++ channel->ch_id = attr.qbman_ch_id; ++ channel->priv = priv; ++ ++ return channel; ++ ++err_get_attr: ++ free_dpcon(priv, channel->dpcon); ++err_setup: ++ kfree(channel); ++ return NULL; ++} ++ ++static void free_channel(struct dpaa2_eth_priv *priv, ++ struct dpaa2_eth_channel *channel) ++{ ++ free_dpcon(priv, channel->dpcon); ++ kfree(channel); ++} ++ ++/* DPIO setup: allocate and configure QBMan channels, setup core affinity ++ * and register data availability notifications ++ */ ++static int setup_dpio(struct dpaa2_eth_priv *priv) ++{ ++ struct dpaa2_io_notification_ctx *nctx; ++ struct dpaa2_eth_channel *channel; ++ struct dpcon_notification_cfg dpcon_notif_cfg; ++ struct device *dev = priv->net_dev->dev.parent; ++ int i, err; ++ ++ /* We want the ability to spread ingress traffic (RX, TX conf) to as ++ * many cores as possible, so we need one channel for each core ++ * (unless there's fewer queues than cores, in which case the extra ++ * channels would be wasted). ++ * Allocate one channel per core and register it to the core's ++ * affine DPIO. If not enough channels are available for all cores ++ * or if some cores don't have an affine DPIO, there will be no ++ * ingress frame processing on those cores. ++ */ ++ cpumask_clear(&priv->dpio_cpumask); ++ for_each_online_cpu(i) { ++ /* Try to allocate a channel */ ++ channel = alloc_channel(priv); ++ if (!channel) { ++ dev_info(dev, ++ "No affine channel for cpu %d and above\n", i); ++ goto err_alloc_ch; ++ } ++ ++ priv->channel[priv->num_channels] = channel; ++ ++ nctx = &channel->nctx; ++ nctx->is_cdan = 1; ++ nctx->cb = cdan_cb; ++ nctx->id = channel->ch_id; ++ nctx->desired_cpu = i; ++ ++ /* Register the new context */ ++ err = dpaa2_io_service_register(NULL, nctx); ++ if (err) { ++ dev_dbg(dev, "No affine DPIO for cpu %d\n", i); ++ /* If no affine DPIO for this core, there's probably ++ * none available for next cores either. ++ */ ++ goto err_service_reg; ++ } ++ ++ /* Register DPCON notification with MC */ ++ dpcon_notif_cfg.dpio_id = nctx->dpio_id; ++ dpcon_notif_cfg.priority = 0; ++ dpcon_notif_cfg.user_ctx = nctx->qman64; ++ err = dpcon_set_notification(priv->mc_io, 0, ++ channel->dpcon->mc_handle, ++ &dpcon_notif_cfg); ++ if (err) { ++ dev_err(dev, "dpcon_set_notification failed()\n"); ++ goto err_set_cdan; ++ } ++ ++ /* If we managed to allocate a channel and also found an affine ++ * DPIO for this core, add it to the final mask ++ */ ++ cpumask_set_cpu(i, &priv->dpio_cpumask); ++ priv->num_channels++; ++ ++ /* Stop if we already have enough channels to accommodate all ++ * RX and TX conf queues ++ */ ++ if (priv->num_channels == dpaa2_eth_queue_count(priv)) ++ break; ++ } ++ ++ /* Tx confirmation queues can only be serviced by cpus ++ * with an affine DPIO/channel ++ */ ++ cpumask_copy(&priv->txconf_cpumask, &priv->dpio_cpumask); ++ ++ return 0; ++ ++err_set_cdan: ++ dpaa2_io_service_deregister(NULL, nctx); ++err_service_reg: ++ free_channel(priv, channel); ++err_alloc_ch: ++ if (cpumask_empty(&priv->dpio_cpumask)) { ++ dev_dbg(dev, "No cpu with an affine DPIO/DPCON\n"); ++ return -ENODEV; ++ } ++ cpumask_copy(&priv->txconf_cpumask, &priv->dpio_cpumask); ++ ++ dev_info(dev, "Cores %*pbl available for processing ingress traffic\n", ++ cpumask_pr_args(&priv->dpio_cpumask)); ++ ++ return 0; ++} ++ ++static void free_dpio(struct dpaa2_eth_priv *priv) ++{ ++ int i; ++ struct dpaa2_eth_channel *ch; ++ ++ /* deregister CDAN notifications and free channels */ ++ for (i = 0; i < priv->num_channels; i++) { ++ ch = priv->channel[i]; ++ dpaa2_io_service_deregister(NULL, &ch->nctx); ++ free_channel(priv, ch); ++ } ++} ++ ++static struct dpaa2_eth_channel *get_affine_channel(struct dpaa2_eth_priv *priv, ++ int cpu) ++{ ++ struct device *dev = priv->net_dev->dev.parent; ++ int i; ++ ++ for (i = 0; i < priv->num_channels; i++) ++ if (priv->channel[i]->nctx.desired_cpu == cpu) ++ return priv->channel[i]; ++ ++ /* We should never get here. Issue a warning and return ++ * the first channel, because it's still better than nothing ++ */ ++ dev_warn(dev, "No affine channel found for cpu %d\n", cpu); ++ ++ return priv->channel[0]; ++} ++ ++static void set_fq_affinity(struct dpaa2_eth_priv *priv) ++{ ++ struct device *dev = priv->net_dev->dev.parent; ++ struct cpumask xps_mask = CPU_MASK_NONE; ++ struct dpaa2_eth_fq *fq; ++ int rx_cpu, txc_cpu; ++ int i, err; ++ ++ /* For each FQ, pick one channel/CPU to deliver frames to. ++ * This may well change at runtime, either through irqbalance or ++ * through direct user intervention. ++ */ ++ rx_cpu = cpumask_first(&priv->dpio_cpumask); ++ txc_cpu = cpumask_first(&priv->txconf_cpumask); ++ ++ for (i = 0; i < priv->num_fqs; i++) { ++ fq = &priv->fq[i]; ++ switch (fq->type) { ++ case DPAA2_RX_FQ: ++ case DPAA2_RX_ERR_FQ: ++ fq->target_cpu = rx_cpu; ++ rx_cpu = cpumask_next(rx_cpu, &priv->dpio_cpumask); ++ if (rx_cpu >= nr_cpu_ids) ++ rx_cpu = cpumask_first(&priv->dpio_cpumask); ++ break; ++ case DPAA2_TX_CONF_FQ: ++ fq->target_cpu = txc_cpu; ++ ++ /* register txc_cpu to XPS */ ++ cpumask_set_cpu(txc_cpu, &xps_mask); ++ err = netif_set_xps_queue(priv->net_dev, &xps_mask, ++ fq->flowid); ++ if (err) ++ dev_info_once(dev, ++ "Tx: error setting XPS queue\n"); ++ cpumask_clear_cpu(txc_cpu, &xps_mask); ++ ++ txc_cpu = cpumask_next(txc_cpu, &priv->txconf_cpumask); ++ if (txc_cpu >= nr_cpu_ids) ++ txc_cpu = cpumask_first(&priv->txconf_cpumask); ++ break; ++ default: ++ dev_err(dev, "Unknown FQ type: %d\n", fq->type); ++ } ++ fq->channel = get_affine_channel(priv, fq->target_cpu); ++ } ++} ++ ++static void setup_fqs(struct dpaa2_eth_priv *priv) ++{ ++ int i; ++ ++ /* We have one TxConf FQ per Tx flow. Tx queues MUST be at the ++ * beginning of the queue array. ++ * Number of Rx and Tx queues are the same. ++ * We only support one traffic class for now. ++ */ ++ for (i = 0; i < dpaa2_eth_queue_count(priv); i++) { ++ priv->fq[priv->num_fqs].type = DPAA2_TX_CONF_FQ; ++ priv->fq[priv->num_fqs].consume = dpaa2_eth_tx_conf; ++ priv->fq[priv->num_fqs++].flowid = (u16)i; ++ } ++ ++ for (i = 0; i < dpaa2_eth_queue_count(priv); i++) { ++ priv->fq[priv->num_fqs].type = DPAA2_RX_FQ; ++ priv->fq[priv->num_fqs].consume = dpaa2_eth_rx; ++ priv->fq[priv->num_fqs++].flowid = (u16)i; ++ } ++ ++#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE ++ /* We have exactly one Rx error queue per DPNI */ ++ priv->fq[priv->num_fqs].type = DPAA2_RX_ERR_FQ; ++ priv->fq[priv->num_fqs++].consume = dpaa2_eth_rx_err; ++#endif ++ ++ /* For each FQ, decide on which core to process incoming frames */ ++ set_fq_affinity(priv); ++} ++ ++/* Allocate and configure one buffer pool for each interface */ ++static int setup_dpbp(struct dpaa2_eth_priv *priv) ++{ ++ int err; ++ struct fsl_mc_device *dpbp_dev; ++ struct dpbp_attr dpbp_attrs; ++ struct device *dev = priv->net_dev->dev.parent; ++ ++ err = fsl_mc_object_allocate(to_fsl_mc_device(dev), FSL_MC_POOL_DPBP, ++ &dpbp_dev); ++ if (err) { ++ dev_err(dev, "DPBP device allocation failed\n"); ++ return err; ++ } ++ ++ priv->dpbp_dev = dpbp_dev; ++ ++ err = dpbp_open(priv->mc_io, 0, priv->dpbp_dev->obj_desc.id, ++ &dpbp_dev->mc_handle); ++ if (err) { ++ dev_err(dev, "dpbp_open() failed\n"); ++ goto err_open; ++ } ++ ++ err = dpbp_reset(priv->mc_io, 0, dpbp_dev->mc_handle); ++ if (err) { ++ dev_err(dev, "dpbp_reset() failed\n"); ++ goto err_reset; ++ } ++ ++ err = dpbp_enable(priv->mc_io, 0, dpbp_dev->mc_handle); ++ if (err) { ++ dev_err(dev, "dpbp_enable() failed\n"); ++ goto err_enable; ++ } ++ ++ err = dpbp_get_attributes(priv->mc_io, 0, dpbp_dev->mc_handle, ++ &dpbp_attrs); ++ if (err) { ++ dev_err(dev, "dpbp_get_attributes() failed\n"); ++ goto err_get_attr; ++ } ++ ++ priv->bpid = dpbp_attrs.bpid; ++ priv->num_bufs = DPAA2_ETH_NUM_BUFS_FC / priv->num_channels; ++ ++ return 0; ++ ++err_get_attr: ++ dpbp_disable(priv->mc_io, 0, dpbp_dev->mc_handle); ++err_enable: ++err_reset: ++ dpbp_close(priv->mc_io, 0, dpbp_dev->mc_handle); ++err_open: ++ fsl_mc_object_free(dpbp_dev); ++ ++ return err; ++} ++ ++static void free_dpbp(struct dpaa2_eth_priv *priv) ++{ ++ drain_pool(priv); ++ dpbp_disable(priv->mc_io, 0, priv->dpbp_dev->mc_handle); ++ dpbp_close(priv->mc_io, 0, priv->dpbp_dev->mc_handle); ++ fsl_mc_object_free(priv->dpbp_dev); ++} ++ ++static int setup_tx_congestion(struct dpaa2_eth_priv *priv) ++{ ++ struct dpni_congestion_notification_cfg cong_notif_cfg = { 0 }; ++ struct device *dev = priv->net_dev->dev.parent; ++ int err; ++ ++ priv->cscn_unaligned = kzalloc(DPAA2_CSCN_SIZE + DPAA2_CSCN_ALIGN, ++ GFP_KERNEL); ++ if (!priv->cscn_unaligned) ++ return -ENOMEM; ++ ++ priv->cscn_mem = PTR_ALIGN(priv->cscn_unaligned, DPAA2_CSCN_ALIGN); ++ priv->cscn_dma = dma_map_single(dev, priv->cscn_mem, DPAA2_CSCN_SIZE, ++ DMA_FROM_DEVICE); ++ if (dma_mapping_error(dev, priv->cscn_dma)) { ++ dev_err(dev, "Error mapping CSCN memory area\n"); ++ err = -ENOMEM; ++ goto err_dma_map; ++ } ++ ++ cong_notif_cfg.units = DPNI_CONGESTION_UNIT_BYTES; ++ cong_notif_cfg.threshold_entry = DPAA2_ETH_TX_CONG_ENTRY_THRESH; ++ cong_notif_cfg.threshold_exit = DPAA2_ETH_TX_CONG_EXIT_THRESH; ++ cong_notif_cfg.message_ctx = (u64)priv; ++ cong_notif_cfg.message_iova = priv->cscn_dma; ++ cong_notif_cfg.notification_mode = DPNI_CONG_OPT_WRITE_MEM_ON_ENTER | ++ DPNI_CONG_OPT_WRITE_MEM_ON_EXIT | ++ DPNI_CONG_OPT_COHERENT_WRITE; ++ err = dpni_set_congestion_notification(priv->mc_io, 0, priv->mc_token, ++ DPNI_QUEUE_TX, 0, ++ &cong_notif_cfg); ++ if (err) { ++ dev_err(dev, "dpni_set_congestion_notification failed\n"); ++ goto err_set_cong; ++ } ++ ++ return 0; ++ ++err_set_cong: ++ dma_unmap_single(dev, priv->cscn_dma, DPAA2_CSCN_SIZE, DMA_FROM_DEVICE); ++err_dma_map: ++ kfree(priv->cscn_unaligned); ++ ++ return err; ++} ++ ++/* Configure the DPNI object this interface is associated with */ ++static int setup_dpni(struct fsl_mc_device *ls_dev) ++{ ++ struct device *dev = &ls_dev->dev; ++ struct dpaa2_eth_priv *priv; ++ struct net_device *net_dev; ++ struct dpni_buffer_layout buf_layout; ++ struct dpni_link_cfg cfg = {0}; ++ int err; ++ ++ net_dev = dev_get_drvdata(dev); ++ priv = netdev_priv(net_dev); ++ ++ priv->dpni_id = ls_dev->obj_desc.id; ++ ++ /* get a handle for the DPNI object */ ++ err = dpni_open(priv->mc_io, 0, priv->dpni_id, &priv->mc_token); ++ if (err) { ++ dev_err(dev, "dpni_open() failed\n"); ++ goto err_open; ++ } ++ ++ ls_dev->mc_io = priv->mc_io; ++ ls_dev->mc_handle = priv->mc_token; ++ ++ err = dpni_reset(priv->mc_io, 0, priv->mc_token); ++ if (err) { ++ dev_err(dev, "dpni_reset() failed\n"); ++ goto err_reset; ++ } ++ ++ err = dpni_get_attributes(priv->mc_io, 0, priv->mc_token, ++ &priv->dpni_attrs); ++ ++ if (err) { ++ dev_err(dev, "dpni_get_attributes() failed (err=%d)\n", err); ++ goto err_get_attr; ++ } ++ ++ /* due to a limitation in WRIOP 1.0.0 (ERR009354), the Rx buf ++ * align value must be a multiple of 256. ++ */ ++ priv->rx_buf_align = ++ priv->dpni_attrs.wriop_version & 0x3ff ? ++ DPAA2_ETH_RX_BUF_ALIGN : DPAA2_ETH_RX_BUF_ALIGN_V1; ++ ++ /* Update number of logical FQs in netdev */ ++ err = netif_set_real_num_tx_queues(net_dev, ++ dpaa2_eth_queue_count(priv)); ++ if (err) { ++ dev_err(dev, "netif_set_real_num_tx_queues failed (%d)\n", err); ++ goto err_set_tx_queues; ++ } ++ ++ err = netif_set_real_num_rx_queues(net_dev, ++ dpaa2_eth_queue_count(priv)); ++ if (err) { ++ dev_err(dev, "netif_set_real_num_rx_queues failed (%d)\n", err); ++ goto err_set_rx_queues; ++ } ++ ++ /* Configure buffer layouts */ ++ /* rx buffer */ ++ buf_layout.pass_parser_result = true; ++ buf_layout.pass_frame_status = true; ++ buf_layout.private_data_size = DPAA2_ETH_SWA_SIZE; ++ buf_layout.data_align = priv->rx_buf_align; ++ buf_layout.data_head_room = DPAA2_ETH_RX_HEAD_ROOM; ++ buf_layout.options = DPNI_BUF_LAYOUT_OPT_PARSER_RESULT | ++ DPNI_BUF_LAYOUT_OPT_FRAME_STATUS | ++ DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE | ++ DPNI_BUF_LAYOUT_OPT_DATA_ALIGN | ++ DPNI_BUF_LAYOUT_OPT_DATA_HEAD_ROOM; ++ err = dpni_set_buffer_layout(priv->mc_io, 0, priv->mc_token, ++ DPNI_QUEUE_RX, &buf_layout); ++ if (err) { ++ dev_err(dev, ++ "dpni_set_buffer_layout(RX) failed\n"); ++ goto err_buf_layout; ++ } ++ ++ /* tx buffer */ ++ buf_layout.options = DPNI_BUF_LAYOUT_OPT_FRAME_STATUS | ++ DPNI_BUF_LAYOUT_OPT_TIMESTAMP | ++ DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE; ++ buf_layout.pass_timestamp = true; ++ err = dpni_set_buffer_layout(priv->mc_io, 0, priv->mc_token, ++ DPNI_QUEUE_TX, &buf_layout); ++ if (err) { ++ dev_err(dev, ++ "dpni_set_buffer_layout(TX) failed\n"); ++ goto err_buf_layout; ++ } ++ ++ /* tx-confirm buffer */ ++ buf_layout.options = DPNI_BUF_LAYOUT_OPT_FRAME_STATUS | ++ DPNI_BUF_LAYOUT_OPT_TIMESTAMP; ++ err = dpni_set_buffer_layout(priv->mc_io, 0, priv->mc_token, ++ DPNI_QUEUE_TX_CONFIRM, &buf_layout); ++ if (err) { ++ dev_err(dev, "dpni_set_buffer_layout(TX_CONF) failed\n"); ++ goto err_buf_layout; ++ } ++ ++ /* Now that we've set our tx buffer layout, retrieve the minimum ++ * required tx data offset. ++ */ ++ err = dpni_get_tx_data_offset(priv->mc_io, 0, priv->mc_token, ++ &priv->tx_data_offset); ++ if (err) { ++ dev_err(dev, "dpni_get_tx_data_offset() failed (%d)\n", err); ++ goto err_data_offset; ++ } ++ ++ if ((priv->tx_data_offset % 64) != 0) ++ dev_warn(dev, "Tx data offset (%d) not a multiple of 64B", ++ priv->tx_data_offset); ++ ++ /* Accommodate software annotation space (SWA) */ ++ priv->tx_data_offset += DPAA2_ETH_SWA_SIZE; ++ ++ /* Enable congestion notifications for Tx queues */ ++ err = setup_tx_congestion(priv); ++ if (err) ++ goto err_tx_cong; ++ ++ /* allocate classification rule space */ ++ priv->cls_rule = kzalloc(sizeof(*priv->cls_rule) * ++ dpaa2_eth_fs_count(priv), GFP_KERNEL); ++ if (!priv->cls_rule) ++ goto err_cls_rule; ++ ++ /* Enable flow control */ ++ cfg.options = DPNI_LINK_OPT_AUTONEG | DPNI_LINK_OPT_PAUSE; ++ priv->tx_pause_frames = 1; ++ ++ err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &cfg); ++ if (err) { ++ netdev_err(net_dev, "ERROR %d setting link cfg", err); ++ goto err_set_link_cfg; ++ } ++ ++ return 0; ++ ++err_set_link_cfg: ++err_cls_rule: ++err_tx_cong: ++err_data_offset: ++err_buf_layout: ++err_set_rx_queues: ++err_set_tx_queues: ++err_get_attr: ++err_reset: ++ dpni_close(priv->mc_io, 0, priv->mc_token); ++err_open: ++ return err; ++} ++ ++static void free_dpni(struct dpaa2_eth_priv *priv) ++{ ++ struct device *dev = priv->net_dev->dev.parent; ++ int err; ++ ++ err = dpni_reset(priv->mc_io, 0, priv->mc_token); ++ if (err) ++ netdev_warn(priv->net_dev, "dpni_reset() failed (err %d)\n", ++ err); ++ ++ dpni_close(priv->mc_io, 0, priv->mc_token); ++ ++ kfree(priv->cls_rule); ++ ++ dma_unmap_single(dev, priv->cscn_dma, DPAA2_CSCN_SIZE, DMA_FROM_DEVICE); ++ kfree(priv->cscn_unaligned); ++} ++ ++int setup_fqs_taildrop(struct dpaa2_eth_priv *priv, ++ bool enable) ++{ ++ struct device *dev = priv->net_dev->dev.parent; ++ struct dpni_taildrop td; ++ int err = 0, i; ++ ++ td.enable = enable; ++ td.threshold = DPAA2_ETH_TAILDROP_THRESH; ++ ++ if (enable) { ++ priv->num_bufs = DPAA2_ETH_NUM_BUFS_TD; ++ priv->refill_thresh = DPAA2_ETH_REFILL_THRESH_TD; ++ } else { ++ priv->num_bufs = DPAA2_ETH_NUM_BUFS_FC / ++ priv->num_channels; ++ priv->refill_thresh = priv->num_bufs - DPAA2_ETH_BUFS_PER_CMD; ++ } ++ ++ for (i = 0; i < priv->num_fqs; i++) { ++ if (priv->fq[i].type != DPAA2_RX_FQ) ++ continue; ++ ++ err = dpni_set_taildrop(priv->mc_io, 0, priv->mc_token, ++ DPNI_CP_QUEUE, DPNI_QUEUE_RX, 0, ++ priv->fq[i].flowid, &td); ++ if (err) { ++ dev_err(dev, "dpni_set_taildrop() failed (%d)\n", err); ++ break; ++ } ++ } ++ ++ return err; ++} ++ ++static int setup_rx_flow(struct dpaa2_eth_priv *priv, ++ struct dpaa2_eth_fq *fq) ++{ ++ struct device *dev = priv->net_dev->dev.parent; ++ struct dpni_queue q = { { 0 } }; ++ struct dpni_queue_id qid; ++ u8 q_opt = DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST; ++ int err; ++ ++ err = dpni_get_queue(priv->mc_io, 0, priv->mc_token, ++ DPNI_QUEUE_RX, 0, fq->flowid, &q, &qid); ++ if (err) { ++ dev_err(dev, "dpni_get_queue() failed (%d)\n", err); ++ return err; ++ } ++ ++ fq->fqid = qid.fqid; ++ ++ q.destination.id = fq->channel->dpcon_id; ++ q.destination.type = DPNI_DEST_DPCON; ++ q.destination.priority = 1; ++ q.user_context = (u64)fq; ++ err = dpni_set_queue(priv->mc_io, 0, priv->mc_token, ++ DPNI_QUEUE_RX, 0, fq->flowid, q_opt, &q); ++ if (err) { ++ dev_err(dev, "dpni_set_queue() failed (%d)\n", err); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int setup_tx_flow(struct dpaa2_eth_priv *priv, ++ struct dpaa2_eth_fq *fq) ++{ ++ struct device *dev = priv->net_dev->dev.parent; ++ struct dpni_queue q = { { 0 } }; ++ struct dpni_queue_id qid; ++ u8 q_opt = DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST; ++ int err; ++ ++ err = dpni_get_queue(priv->mc_io, 0, priv->mc_token, ++ DPNI_QUEUE_TX, 0, fq->flowid, &q, &qid); ++ if (err) { ++ dev_err(dev, "dpni_get_queue() failed (%d)\n", err); ++ return err; ++ } ++ ++ fq->tx_qdbin = qid.qdbin; ++ ++ err = dpni_get_queue(priv->mc_io, 0, priv->mc_token, ++ DPNI_QUEUE_TX_CONFIRM, 0, fq->flowid, &q, &qid); ++ if (err) { ++ dev_err(dev, "dpni_get_queue() failed (%d)\n", err); ++ return err; ++ } ++ ++ fq->fqid = qid.fqid; ++ ++ q.destination.id = fq->channel->dpcon_id; ++ q.destination.type = DPNI_DEST_DPCON; ++ q.destination.priority = 0; ++ q.user_context = (u64)fq; ++ err = dpni_set_queue(priv->mc_io, 0, priv->mc_token, ++ DPNI_QUEUE_TX_CONFIRM, 0, fq->flowid, q_opt, &q); ++ if (err) { ++ dev_err(dev, "dpni_get_queue() failed (%d)\n", err); ++ return err; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE ++static int setup_rx_err_flow(struct dpaa2_eth_priv *priv, ++ struct dpaa2_eth_fq *fq) ++{ ++ struct device *dev = priv->net_dev->dev.parent; ++ struct dpni_queue q = { { 0 } }; ++ struct dpni_queue_id qid; ++ u8 q_opt = DPNI_QUEUE_OPT_USER_CTX | DPNI_QUEUE_OPT_DEST; ++ int err; ++ ++ err = dpni_get_queue(priv->mc_io, 0, priv->mc_token, ++ DPNI_QUEUE_RX_ERR, 0, 0, &q, &qid); ++ if (err) { ++ dev_err(dev, "dpni_get_queue() failed (%d)\n", err); ++ return err; ++ } ++ ++ fq->fqid = qid.fqid; ++ ++ q.destination.id = fq->channel->dpcon_id; ++ q.destination.type = DPNI_DEST_DPCON; ++ q.destination.priority = 1; ++ q.user_context = (u64)fq; ++ err = dpni_set_queue(priv->mc_io, 0, priv->mc_token, ++ DPNI_QUEUE_RX_ERR, 0, 0, q_opt, &q); ++ if (err) { ++ dev_err(dev, "dpni_set_queue() failed (%d)\n", err); ++ return err; ++ } ++ ++ return 0; ++} ++#endif ++ ++/* default hash key fields */ ++static struct dpaa2_eth_hash_fields default_hash_fields[] = { ++ { ++ /* L2 header */ ++ .rxnfc_field = RXH_L2DA, ++ .cls_prot = NET_PROT_ETH, ++ .cls_field = NH_FLD_ETH_DA, ++ .size = 6, ++ }, { ++ .cls_prot = NET_PROT_ETH, ++ .cls_field = NH_FLD_ETH_SA, ++ .size = 6, ++ }, { ++ /* This is the last ethertype field parsed: ++ * depending on frame format, it can be the MAC ethertype ++ * or the VLAN etype. ++ */ ++ .cls_prot = NET_PROT_ETH, ++ .cls_field = NH_FLD_ETH_TYPE, ++ .size = 2, ++ }, { ++ /* VLAN header */ ++ .rxnfc_field = RXH_VLAN, ++ .cls_prot = NET_PROT_VLAN, ++ .cls_field = NH_FLD_VLAN_TCI, ++ .size = 2, ++ }, { ++ /* IP header */ ++ .rxnfc_field = RXH_IP_SRC, ++ .cls_prot = NET_PROT_IP, ++ .cls_field = NH_FLD_IP_SRC, ++ .size = 4, ++ }, { ++ .rxnfc_field = RXH_IP_DST, ++ .cls_prot = NET_PROT_IP, ++ .cls_field = NH_FLD_IP_DST, ++ .size = 4, ++ }, { ++ .rxnfc_field = RXH_L3_PROTO, ++ .cls_prot = NET_PROT_IP, ++ .cls_field = NH_FLD_IP_PROTO, ++ .size = 1, ++ }, { ++ /* Using UDP ports, this is functionally equivalent to raw ++ * byte pairs from L4 header. ++ */ ++ .rxnfc_field = RXH_L4_B_0_1, ++ .cls_prot = NET_PROT_UDP, ++ .cls_field = NH_FLD_UDP_PORT_SRC, ++ .size = 2, ++ }, { ++ .rxnfc_field = RXH_L4_B_2_3, ++ .cls_prot = NET_PROT_UDP, ++ .cls_field = NH_FLD_UDP_PORT_DST, ++ .size = 2, ++ }, ++}; ++ ++/* Set RX hash options */ ++static int set_hash(struct dpaa2_eth_priv *priv) ++{ ++ struct device *dev = priv->net_dev->dev.parent; ++ struct dpkg_profile_cfg cls_cfg; ++ struct dpni_rx_tc_dist_cfg dist_cfg; ++ u8 *dma_mem; ++ int i; ++ int err = 0; ++ ++ memset(&cls_cfg, 0, sizeof(cls_cfg)); ++ ++ for (i = 0; i < priv->num_hash_fields; i++) { ++ struct dpkg_extract *key = ++ &cls_cfg.extracts[cls_cfg.num_extracts]; ++ ++ key->type = DPKG_EXTRACT_FROM_HDR; ++ key->extract.from_hdr.prot = priv->hash_fields[i].cls_prot; ++ key->extract.from_hdr.type = DPKG_FULL_FIELD; ++ key->extract.from_hdr.field = priv->hash_fields[i].cls_field; ++ cls_cfg.num_extracts++; ++ ++ priv->rx_flow_hash |= priv->hash_fields[i].rxnfc_field; ++ } ++ ++ dma_mem = kzalloc(DPAA2_CLASSIFIER_DMA_SIZE, GFP_DMA | GFP_KERNEL); ++ if (!dma_mem) ++ return -ENOMEM; ++ ++ err = dpni_prepare_key_cfg(&cls_cfg, dma_mem); ++ if (err) { ++ dev_err(dev, "dpni_prepare_key_cfg() failed (%d)", err); ++ goto err_prep_key; ++ } ++ ++ memset(&dist_cfg, 0, sizeof(dist_cfg)); ++ ++ /* Prepare for setting the rx dist */ ++ dist_cfg.key_cfg_iova = dma_map_single(dev, dma_mem, ++ DPAA2_CLASSIFIER_DMA_SIZE, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, dist_cfg.key_cfg_iova)) { ++ dev_err(dev, "DMA mapping failed\n"); ++ err = -ENOMEM; ++ goto err_dma_map; ++ } ++ ++ dist_cfg.dist_size = dpaa2_eth_queue_count(priv); ++ if (dpaa2_eth_fs_enabled(priv)) { ++ dist_cfg.dist_mode = DPNI_DIST_MODE_FS; ++ dist_cfg.fs_cfg.miss_action = DPNI_FS_MISS_HASH; ++ } else { ++ dist_cfg.dist_mode = DPNI_DIST_MODE_HASH; ++ } ++ ++ err = dpni_set_rx_tc_dist(priv->mc_io, 0, priv->mc_token, 0, &dist_cfg); ++ dma_unmap_single(dev, dist_cfg.key_cfg_iova, ++ DPAA2_CLASSIFIER_DMA_SIZE, DMA_TO_DEVICE); ++ if (err) ++ dev_err(dev, "dpni_set_rx_tc_dist() failed (%d)\n", err); ++ ++err_dma_map: ++err_prep_key: ++ kfree(dma_mem); ++ return err; ++} ++ ++/* Bind the DPNI to its needed objects and resources: buffer pool, DPIOs, ++ * frame queues and channels ++ */ ++static int bind_dpni(struct dpaa2_eth_priv *priv) ++{ ++ struct net_device *net_dev = priv->net_dev; ++ struct device *dev = net_dev->dev.parent; ++ struct dpni_pools_cfg pools_params; ++ struct dpni_error_cfg err_cfg; ++ int err = 0; ++ int i; ++ ++ pools_params.num_dpbp = 1; ++ pools_params.pools[0].dpbp_id = priv->dpbp_dev->obj_desc.id; ++ pools_params.pools[0].backup_pool = 0; ++ pools_params.pools[0].buffer_size = DPAA2_ETH_RX_BUF_SIZE; ++ err = dpni_set_pools(priv->mc_io, 0, priv->mc_token, &pools_params); ++ if (err) { ++ dev_err(dev, "dpni_set_pools() failed\n"); ++ return err; ++ } ++ ++ /* Verify classification options and disable hashing and/or ++ * flow steering support in case of invalid configuration values ++ */ ++ priv->hash_fields = default_hash_fields; ++ priv->num_hash_fields = ARRAY_SIZE(default_hash_fields); ++ check_cls_support(priv); ++ ++ /* have the interface implicitly distribute traffic based on ++ * a static hash key ++ */ ++ if (dpaa2_eth_hash_enabled(priv)) { ++ err = set_hash(priv); ++ if (err) { ++ dev_err(dev, "Hashing configuration failed\n"); ++ return err; ++ } ++ } ++ ++ /* Configure handling of error frames */ ++ err_cfg.errors = DPAA2_FAS_RX_ERR_MASK; ++ err_cfg.set_frame_annotation = 1; ++#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE ++ err_cfg.error_action = DPNI_ERROR_ACTION_SEND_TO_ERROR_QUEUE; ++#else ++ err_cfg.error_action = DPNI_ERROR_ACTION_DISCARD; ++#endif ++ err = dpni_set_errors_behavior(priv->mc_io, 0, priv->mc_token, ++ &err_cfg); ++ if (err) { ++ dev_err(dev, "dpni_set_errors_behavior() failed (%d)\n", err); ++ return err; ++ } ++ ++ /* Configure Rx and Tx conf queues to generate CDANs */ ++ for (i = 0; i < priv->num_fqs; i++) { ++ switch (priv->fq[i].type) { ++ case DPAA2_RX_FQ: ++ err = setup_rx_flow(priv, &priv->fq[i]); ++ break; ++ case DPAA2_TX_CONF_FQ: ++ err = setup_tx_flow(priv, &priv->fq[i]); ++ break; ++#ifdef CONFIG_FSL_DPAA2_ETH_USE_ERR_QUEUE ++ case DPAA2_RX_ERR_FQ: ++ err = setup_rx_err_flow(priv, &priv->fq[i]); ++ break; ++#endif ++ default: ++ dev_err(dev, "Invalid FQ type %d\n", priv->fq[i].type); ++ return -EINVAL; ++ } ++ if (err) ++ return err; ++ } ++ ++ err = dpni_get_qdid(priv->mc_io, 0, priv->mc_token, DPNI_QUEUE_TX, ++ &priv->tx_qdid); ++ if (err) { ++ dev_err(dev, "dpni_get_qdid() failed\n"); ++ return err; ++ } ++ ++ return 0; ++} ++ ++/* Allocate rings for storing incoming frame descriptors */ ++static int alloc_rings(struct dpaa2_eth_priv *priv) ++{ ++ struct net_device *net_dev = priv->net_dev; ++ struct device *dev = net_dev->dev.parent; ++ int i; ++ ++ for (i = 0; i < priv->num_channels; i++) { ++ priv->channel[i]->store = ++ dpaa2_io_store_create(DPAA2_ETH_STORE_SIZE, dev); ++ if (!priv->channel[i]->store) { ++ netdev_err(net_dev, "dpaa2_io_store_create() failed\n"); ++ goto err_ring; ++ } ++ } ++ ++ return 0; ++ ++err_ring: ++ for (i = 0; i < priv->num_channels; i++) { ++ if (!priv->channel[i]->store) ++ break; ++ dpaa2_io_store_destroy(priv->channel[i]->store); ++ } ++ ++ return -ENOMEM; ++} ++ ++static void free_rings(struct dpaa2_eth_priv *priv) ++{ ++ int i; ++ ++ for (i = 0; i < priv->num_channels; i++) ++ dpaa2_io_store_destroy(priv->channel[i]->store); ++} ++ ++static int netdev_init(struct net_device *net_dev) ++{ ++ int err; ++ struct device *dev = net_dev->dev.parent; ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ u8 mac_addr[ETH_ALEN], dpni_mac_addr[ETH_ALEN]; ++ u8 bcast_addr[ETH_ALEN]; ++ u16 rx_headroom, rx_req_headroom; ++ ++ net_dev->netdev_ops = &dpaa2_eth_ops; ++ ++ /* Get firmware address, if any */ ++ err = dpni_get_port_mac_addr(priv->mc_io, 0, priv->mc_token, mac_addr); ++ if (err) { ++ dev_err(dev, "dpni_get_port_mac_addr() failed (%d)\n", err); ++ return err; ++ } ++ ++ /* Get DPNI atttributes address, if any */ ++ err = dpni_get_primary_mac_addr(priv->mc_io, 0, priv->mc_token, ++ dpni_mac_addr); ++ if (err) { ++ dev_err(dev, "dpni_get_primary_mac_addr() failed (%d)\n", err); ++ return err; ++ } ++ ++ /* First check if firmware has any address configured by bootloader */ ++ if (!is_zero_ether_addr(mac_addr)) { ++ /* If the DPMAC addr != the DPNI addr, update it */ ++ if (!ether_addr_equal(mac_addr, dpni_mac_addr)) { ++ err = dpni_set_primary_mac_addr(priv->mc_io, 0, ++ priv->mc_token, ++ mac_addr); ++ if (err) { ++ dev_err(dev, ++ "dpni_set_primary_mac_addr() failed (%d)\n", ++ err); ++ return err; ++ } ++ } ++ memcpy(net_dev->dev_addr, mac_addr, net_dev->addr_len); ++ } else if (is_zero_ether_addr(dpni_mac_addr)) { ++ /* Fills in net_dev->dev_addr, as required by ++ * register_netdevice() ++ */ ++ eth_hw_addr_random(net_dev); ++ /* Make the user aware, without cluttering the boot log */ ++ dev_dbg_once(dev, " device(s) have all-zero hwaddr, replaced with random\n"); ++ err = dpni_set_primary_mac_addr(priv->mc_io, 0, ++ priv->mc_token, net_dev->dev_addr); ++ if (err) { ++ dev_err(dev, ++ "dpni_set_primary_mac_addr() failed (%d)\n", err); ++ return err; ++ } ++ /* Override NET_ADDR_RANDOM set by eth_hw_addr_random(); for all ++ * practical purposes, this will be our "permanent" mac address, ++ * at least until the next reboot. This move will also permit ++ * register_netdevice() to properly fill up net_dev->perm_addr. ++ */ ++ net_dev->addr_assign_type = NET_ADDR_PERM; ++ /* If DPMAC address is non-zero, use that one */ ++ } else { ++ /* NET_ADDR_PERM is default, all we have to do is ++ * fill in the device addr. ++ */ ++ memcpy(net_dev->dev_addr, dpni_mac_addr, net_dev->addr_len); ++ } ++ ++ /* Explicitly add the broadcast address to the MAC filtering table; ++ * the MC won't do that for us. ++ */ ++ eth_broadcast_addr(bcast_addr); ++ err = dpni_add_mac_addr(priv->mc_io, 0, priv->mc_token, bcast_addr); ++ if (err) { ++ dev_warn(dev, "dpni_add_mac_addr() failed (%d)\n", err); ++ /* Won't return an error; at least, we'd have egress traffic */ ++ } ++ ++ /* Reserve enough space to align buffer as per hardware requirement; ++ * NOTE: priv->tx_data_offset MUST be initialized at this point. ++ */ ++ net_dev->needed_headroom = DPAA2_ETH_NEEDED_HEADROOM(priv); ++ ++ /* Set MTU limits */ ++ net_dev->min_mtu = 68; ++ net_dev->max_mtu = DPAA2_ETH_MAX_MTU; ++ ++ /* Required headroom for Rx skbs, to avoid reallocation on ++ * forwarding path. ++ */ ++ rx_req_headroom = LL_RESERVED_SPACE(net_dev) - ETH_HLEN; ++ rx_headroom = ALIGN(DPAA2_ETH_RX_HWA_SIZE + DPAA2_ETH_SWA_SIZE + ++ DPAA2_ETH_RX_HEAD_ROOM, priv->rx_buf_align); ++ if (rx_req_headroom > rx_headroom) ++ dev_info_once(dev, ++ "Required headroom (%d) greater than available (%d).\n" ++ "This will impact performance due to reallocations.\n", ++ rx_req_headroom, rx_headroom); ++ ++ /* Our .ndo_init will be called herein */ ++ err = register_netdev(net_dev); ++ if (err < 0) { ++ dev_err(dev, "register_netdev() failed (%d)\n", err); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int poll_link_state(void *arg) ++{ ++ struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)arg; ++ int err; ++ ++ while (!kthread_should_stop()) { ++ err = link_state_update(priv); ++ if (unlikely(err)) ++ return err; ++ ++ msleep(DPAA2_ETH_LINK_STATE_REFRESH); ++ } ++ ++ return 0; ++} ++ ++static irqreturn_t dpni_irq0_handler(int irq_num, void *arg) ++{ ++ return IRQ_WAKE_THREAD; ++} ++ ++static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg) ++{ ++ u32 status = 0, clear = 0; ++ struct device *dev = (struct device *)arg; ++ struct fsl_mc_device *dpni_dev = to_fsl_mc_device(dev); ++ struct net_device *net_dev = dev_get_drvdata(dev); ++ int err; ++ ++ err = dpni_get_irq_status(dpni_dev->mc_io, 0, dpni_dev->mc_handle, ++ DPNI_IRQ_INDEX, &status); ++ if (unlikely(err)) { ++ netdev_err(net_dev, "Can't get irq status (err %d)", err); ++ clear = 0xffffffff; ++ goto out; ++ } ++ ++ if (status & DPNI_IRQ_EVENT_LINK_CHANGED) { ++ clear |= DPNI_IRQ_EVENT_LINK_CHANGED; ++ link_state_update(netdev_priv(net_dev)); ++ } ++ ++out: ++ dpni_clear_irq_status(dpni_dev->mc_io, 0, dpni_dev->mc_handle, ++ DPNI_IRQ_INDEX, clear); ++ return IRQ_HANDLED; ++} ++ ++static int setup_irqs(struct fsl_mc_device *ls_dev) ++{ ++ int err = 0; ++ struct fsl_mc_device_irq *irq; ++ ++ err = fsl_mc_allocate_irqs(ls_dev); ++ if (err) { ++ dev_err(&ls_dev->dev, "MC irqs allocation failed\n"); ++ return err; ++ } ++ ++ irq = ls_dev->irqs[0]; ++ err = devm_request_threaded_irq(&ls_dev->dev, irq->msi_desc->irq, ++ dpni_irq0_handler, ++ dpni_irq0_handler_thread, ++ IRQF_NO_SUSPEND | IRQF_ONESHOT, ++ dev_name(&ls_dev->dev), &ls_dev->dev); ++ if (err < 0) { ++ dev_err(&ls_dev->dev, "devm_request_threaded_irq(): %d", err); ++ goto free_mc_irq; ++ } ++ ++ err = dpni_set_irq_mask(ls_dev->mc_io, 0, ls_dev->mc_handle, ++ DPNI_IRQ_INDEX, DPNI_IRQ_EVENT_LINK_CHANGED); ++ if (err < 0) { ++ dev_err(&ls_dev->dev, "dpni_set_irq_mask(): %d", err); ++ goto free_irq; ++ } ++ ++ err = dpni_set_irq_enable(ls_dev->mc_io, 0, ls_dev->mc_handle, ++ DPNI_IRQ_INDEX, 1); ++ if (err < 0) { ++ dev_err(&ls_dev->dev, "dpni_set_irq_enable(): %d", err); ++ goto free_irq; ++ } ++ ++ return 0; ++ ++free_irq: ++ devm_free_irq(&ls_dev->dev, irq->msi_desc->irq, &ls_dev->dev); ++free_mc_irq: ++ fsl_mc_free_irqs(ls_dev); ++ ++ return err; ++} ++ ++static void add_ch_napi(struct dpaa2_eth_priv *priv) ++{ ++ int i; ++ struct dpaa2_eth_channel *ch; ++ ++ for (i = 0; i < priv->num_channels; i++) { ++ ch = priv->channel[i]; ++ /* NAPI weight *MUST* be a multiple of DPAA2_ETH_STORE_SIZE */ ++ netif_napi_add(priv->net_dev, &ch->napi, dpaa2_eth_poll, ++ NAPI_POLL_WEIGHT); ++ } ++} ++ ++static void del_ch_napi(struct dpaa2_eth_priv *priv) ++{ ++ int i; ++ struct dpaa2_eth_channel *ch; ++ ++ for (i = 0; i < priv->num_channels; i++) { ++ ch = priv->channel[i]; ++ netif_napi_del(&ch->napi); ++ } ++} ++ ++/* SysFS support */ ++static ssize_t dpaa2_eth_show_tx_shaping(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(to_net_dev(dev)); ++ /* No MC API for getting the shaping config. We're stateful. */ ++ struct dpni_tx_shaping_cfg *scfg = &priv->shaping_cfg; ++ ++ return sprintf(buf, "%u %hu\n", scfg->rate_limit, scfg->max_burst_size); ++} ++ ++static ssize_t dpaa2_eth_write_tx_shaping(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, ++ size_t count) ++{ ++ int err, items; ++ struct dpaa2_eth_priv *priv = netdev_priv(to_net_dev(dev)); ++ struct dpni_tx_shaping_cfg scfg; ++ ++ items = sscanf(buf, "%u %hu", &scfg.rate_limit, &scfg.max_burst_size); ++ if (items != 2) { ++ pr_err("Expected format: \"rate_limit(Mbps) max_burst_size(bytes)\"\n"); ++ return -EINVAL; ++ } ++ /* Size restriction as per MC API documentation */ ++ if (scfg.max_burst_size > DPAA2_ETH_MAX_BURST_SIZE) { ++ pr_err("max_burst_size must be <= %d\n", ++ DPAA2_ETH_MAX_BURST_SIZE); ++ return -EINVAL; ++ } ++ ++ err = dpni_set_tx_shaping(priv->mc_io, 0, priv->mc_token, &scfg); ++ if (err) { ++ dev_err(dev, "dpni_set_tx_shaping() failed\n"); ++ return -EPERM; ++ } ++ /* If successful, save the current configuration for future inquiries */ ++ priv->shaping_cfg = scfg; ++ ++ return count; ++} ++ ++static ssize_t dpaa2_eth_show_txconf_cpumask(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(to_net_dev(dev)); ++ ++ return cpumap_print_to_pagebuf(1, buf, &priv->txconf_cpumask); ++} ++ ++static ssize_t dpaa2_eth_write_txconf_cpumask(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, ++ size_t count) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(to_net_dev(dev)); ++ struct dpaa2_eth_fq *fq; ++ bool running = netif_running(priv->net_dev); ++ int i, err; ++ ++ err = cpulist_parse(buf, &priv->txconf_cpumask); ++ if (err) ++ return err; ++ ++ /* Only accept CPUs that have an affine DPIO */ ++ if (!cpumask_subset(&priv->txconf_cpumask, &priv->dpio_cpumask)) { ++ netdev_info(priv->net_dev, ++ "cpumask must be a subset of 0x%lx\n", ++ *cpumask_bits(&priv->dpio_cpumask)); ++ cpumask_and(&priv->txconf_cpumask, &priv->dpio_cpumask, ++ &priv->txconf_cpumask); ++ } ++ ++ /* Rewiring the TxConf FQs requires interface shutdown. ++ */ ++ if (running) { ++ err = dpaa2_eth_stop(priv->net_dev); ++ if (err) ++ return -ENODEV; ++ } ++ ++ /* Set the new TxConf FQ affinities */ ++ set_fq_affinity(priv); ++ ++ /* dpaa2_eth_open() below will *stop* the Tx queues until an explicit ++ * link up notification is received. Give the polling thread enough time ++ * to detect the link state change, or else we'll end up with the ++ * transmission side forever shut down. ++ */ ++ if (priv->do_link_poll) ++ msleep(2 * DPAA2_ETH_LINK_STATE_REFRESH); ++ ++ for (i = 0; i < priv->num_fqs; i++) { ++ fq = &priv->fq[i]; ++ if (fq->type != DPAA2_TX_CONF_FQ) ++ continue; ++ setup_tx_flow(priv, fq); ++ } ++ ++ if (running) { ++ err = dpaa2_eth_open(priv->net_dev); ++ if (err) ++ return -ENODEV; ++ } ++ ++ return count; ++} ++ ++static struct device_attribute dpaa2_eth_attrs[] = { ++ __ATTR(txconf_cpumask, ++ 0600, ++ dpaa2_eth_show_txconf_cpumask, ++ dpaa2_eth_write_txconf_cpumask), ++ ++ __ATTR(tx_shaping, ++ 0600, ++ dpaa2_eth_show_tx_shaping, ++ dpaa2_eth_write_tx_shaping), ++}; ++ ++static void dpaa2_eth_sysfs_init(struct device *dev) ++{ ++ int i, err; ++ ++ for (i = 0; i < ARRAY_SIZE(dpaa2_eth_attrs); i++) { ++ err = device_create_file(dev, &dpaa2_eth_attrs[i]); ++ if (err) { ++ dev_err(dev, "ERROR creating sysfs file\n"); ++ goto undo; ++ } ++ } ++ return; ++ ++undo: ++ while (i > 0) ++ device_remove_file(dev, &dpaa2_eth_attrs[--i]); ++} ++ ++static void dpaa2_eth_sysfs_remove(struct device *dev) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(dpaa2_eth_attrs); i++) ++ device_remove_file(dev, &dpaa2_eth_attrs[i]); ++} ++ ++static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev) ++{ ++ struct device *dev; ++ struct net_device *net_dev = NULL; ++ struct dpaa2_eth_priv *priv = NULL; ++ int err = 0; ++ ++ dev = &dpni_dev->dev; ++ ++ /* Net device */ ++ net_dev = alloc_etherdev_mq(sizeof(*priv), DPAA2_ETH_MAX_TX_QUEUES); ++ if (!net_dev) { ++ dev_err(dev, "alloc_etherdev_mq() failed\n"); ++ return -ENOMEM; ++ } ++ ++ SET_NETDEV_DEV(net_dev, dev); ++ dev_set_drvdata(dev, net_dev); ++ ++ priv = netdev_priv(net_dev); ++ priv->net_dev = net_dev; ++ ++ priv->iommu_domain = iommu_get_domain_for_dev(dev); ++ ++ /* Obtain a MC portal */ ++ err = fsl_mc_portal_allocate(dpni_dev, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, ++ &priv->mc_io); ++ if (err) { ++ dev_err(dev, "MC portal allocation failed\n"); ++ goto err_portal_alloc; ++ } ++ ++ /* MC objects initialization and configuration */ ++ err = setup_dpni(dpni_dev); ++ if (err) ++ goto err_dpni_setup; ++ ++ err = setup_dpio(priv); ++ if (err) { ++ dev_info(dev, "Defer probing as no DPIO available\n"); ++ err = -EPROBE_DEFER; ++ goto err_dpio_setup; ++ } ++ ++ setup_fqs(priv); ++ ++ err = setup_dpbp(priv); ++ if (err) ++ goto err_dpbp_setup; ++ ++ err = bind_dpni(priv); ++ if (err) ++ goto err_bind; ++ ++ /* Add a NAPI context for each channel */ ++ add_ch_napi(priv); ++ enable_ch_napi(priv); ++ ++ /* Percpu statistics */ ++ priv->percpu_stats = alloc_percpu(*priv->percpu_stats); ++ if (!priv->percpu_stats) { ++ dev_err(dev, "alloc_percpu(percpu_stats) failed\n"); ++ err = -ENOMEM; ++ goto err_alloc_percpu_stats; ++ } ++ priv->percpu_extras = alloc_percpu(*priv->percpu_extras); ++ if (!priv->percpu_extras) { ++ dev_err(dev, "alloc_percpu(percpu_extras) failed\n"); ++ err = -ENOMEM; ++ goto err_alloc_percpu_extras; ++ } ++ ++ snprintf(net_dev->name, IFNAMSIZ, "ni%d", dpni_dev->obj_desc.id); ++ if (!dev_valid_name(net_dev->name)) { ++ dev_warn(&net_dev->dev, ++ "netdevice name \"%s\" cannot be used, reverting to default..\n", ++ net_dev->name); ++ dev_alloc_name(net_dev, "eth%d"); ++ dev_warn(&net_dev->dev, "using name \"%s\"\n", net_dev->name); ++ } ++ ++ err = netdev_init(net_dev); ++ if (err) ++ goto err_netdev_init; ++ ++ /* Configure checksum offload based on current interface flags */ ++ err = set_rx_csum(priv, !!(net_dev->features & NETIF_F_RXCSUM)); ++ if (err) ++ goto err_csum; ++ ++ err = set_tx_csum(priv, !!(net_dev->features & ++ (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))); ++ if (err) ++ goto err_csum; ++ ++ err = alloc_rings(priv); ++ if (err) ++ goto err_alloc_rings; ++ ++ net_dev->ethtool_ops = &dpaa2_ethtool_ops; ++ ++ err = setup_irqs(dpni_dev); ++ if (err) { ++ netdev_warn(net_dev, "Failed to set link interrupt, fall back to polling\n"); ++ priv->poll_thread = kthread_run(poll_link_state, priv, ++ "%s_poll_link", net_dev->name); ++ if (IS_ERR(priv->poll_thread)) { ++ netdev_err(net_dev, "Error starting polling thread\n"); ++ goto err_poll_thread; ++ } ++ priv->do_link_poll = true; ++ } ++ ++ dpaa2_eth_sysfs_init(&net_dev->dev); ++#ifdef CONFIG_FSL_DPAA2_ETH_DEBUGFS ++ dpaa2_dbg_add(priv); ++#endif ++ ++ dev_info(dev, "Probed interface %s\n", net_dev->name); ++ return 0; ++ ++err_poll_thread: ++ free_rings(priv); ++err_alloc_rings: ++err_csum: ++ unregister_netdev(net_dev); ++err_netdev_init: ++ free_percpu(priv->percpu_extras); ++err_alloc_percpu_extras: ++ free_percpu(priv->percpu_stats); ++err_alloc_percpu_stats: ++ disable_ch_napi(priv); ++ del_ch_napi(priv); ++err_bind: ++ free_dpbp(priv); ++err_dpbp_setup: ++ free_dpio(priv); ++err_dpio_setup: ++ free_dpni(priv); ++err_dpni_setup: ++ fsl_mc_portal_free(priv->mc_io); ++err_portal_alloc: ++ dev_set_drvdata(dev, NULL); ++ free_netdev(net_dev); ++ ++ return err; ++} ++ ++static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev) ++{ ++ struct device *dev; ++ struct net_device *net_dev; ++ struct dpaa2_eth_priv *priv; ++ ++ dev = &ls_dev->dev; ++ net_dev = dev_get_drvdata(dev); ++ priv = netdev_priv(net_dev); ++ ++#ifdef CONFIG_FSL_DPAA2_ETH_DEBUGFS ++ dpaa2_dbg_remove(priv); ++#endif ++ dpaa2_eth_sysfs_remove(&net_dev->dev); ++ ++ unregister_netdev(net_dev); ++ dev_info(net_dev->dev.parent, "Removed interface %s\n", net_dev->name); ++ ++ if (priv->do_link_poll) ++ kthread_stop(priv->poll_thread); ++ else ++ fsl_mc_free_irqs(ls_dev); ++ ++ free_rings(priv); ++ free_percpu(priv->percpu_stats); ++ free_percpu(priv->percpu_extras); ++ ++ disable_ch_napi(priv); ++ del_ch_napi(priv); ++ free_dpbp(priv); ++ free_dpio(priv); ++ free_dpni(priv); ++ ++ fsl_mc_portal_free(priv->mc_io); ++ ++ dev_set_drvdata(dev, NULL); ++ free_netdev(net_dev); ++ ++ return 0; ++} ++ ++static const struct fsl_mc_device_id dpaa2_eth_match_id_table[] = { ++ { ++ .vendor = FSL_MC_VENDOR_FREESCALE, ++ .obj_type = "dpni", ++ }, ++ { .vendor = 0x0 } ++}; ++MODULE_DEVICE_TABLE(fslmc, dpaa2_eth_match_id_table); ++ ++static struct fsl_mc_driver dpaa2_eth_driver = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = dpaa2_eth_probe, ++ .remove = dpaa2_eth_remove, ++ .match_id_table = dpaa2_eth_match_id_table ++}; ++ ++static int __init dpaa2_eth_driver_init(void) ++{ ++ int err; ++ ++ dpaa2_eth_dbg_init(); ++ err = fsl_mc_driver_register(&dpaa2_eth_driver); ++ if (err) { ++ dpaa2_eth_dbg_exit(); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static void __exit dpaa2_eth_driver_exit(void) ++{ ++ dpaa2_eth_dbg_exit(); ++ fsl_mc_driver_unregister(&dpaa2_eth_driver); ++} ++ ++module_init(dpaa2_eth_driver_init); ++module_exit(dpaa2_eth_driver_exit); +diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h +new file mode 100644 +index 00000000..86cb12e9 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h +@@ -0,0 +1,460 @@ ++/* Copyright 2014-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __DPAA2_ETH_H ++#define __DPAA2_ETH_H ++ ++#include ++#include ++#include ++#include "../../fsl-mc/include/dpaa2-io.h" ++#include "dpni.h" ++#include "net.h" ++ ++#include "dpaa2-eth-debugfs.h" ++ ++#define DPAA2_ETH_STORE_SIZE 16 ++ ++/* We set a max threshold for how many Tx confirmations we should process ++ * on a NAPI poll call, they take less processing time. ++ */ ++#define TX_CONF_PER_NAPI_POLL 256 ++ ++/* Maximum number of scatter-gather entries in an ingress frame, ++ * considering the maximum receive frame size is 64K ++ */ ++#define DPAA2_ETH_MAX_SG_ENTRIES ((64 * 1024) / DPAA2_ETH_RX_BUF_SIZE) ++ ++/* Maximum acceptable MTU value. It is in direct relation with the hardware ++ * enforced Max Frame Length (currently 10k). ++ */ ++#define DPAA2_ETH_MFL (10 * 1024) ++#define DPAA2_ETH_MAX_MTU (DPAA2_ETH_MFL - VLAN_ETH_HLEN) ++/* Convert L3 MTU to L2 MFL */ ++#define DPAA2_ETH_L2_MAX_FRM(mtu) ((mtu) + VLAN_ETH_HLEN) ++ ++/* Maximum burst size value for Tx shaping */ ++#define DPAA2_ETH_MAX_BURST_SIZE 0xF7FF ++ ++/* Maximum number of buffers that can be acquired/released through a single ++ * QBMan command ++ */ ++#define DPAA2_ETH_BUFS_PER_CMD 7 ++ ++/* Set the taildrop threshold (in bytes) to allow the enqueue of several jumbo ++ * frames in the Rx queues (length of the current frame is not ++ * taken into account when making the taildrop decision) ++ */ ++#define DPAA2_ETH_TAILDROP_THRESH (64 * 1024) ++ ++/* Buffer quota per queue. Must be large enough such that for minimum sized ++ * frames taildrop kicks in before the bpool gets depleted, so we compute ++ * how many 64B frames fit inside the taildrop threshold and add a margin ++ * to accommodate the buffer refill delay. ++ */ ++#define DPAA2_ETH_MAX_FRAMES_PER_QUEUE (DPAA2_ETH_TAILDROP_THRESH / 64) ++#define DPAA2_ETH_NUM_BUFS_TD (DPAA2_ETH_MAX_FRAMES_PER_QUEUE + 256) ++#define DPAA2_ETH_REFILL_THRESH_TD \ ++ (DPAA2_ETH_NUM_BUFS_TD - DPAA2_ETH_BUFS_PER_CMD) ++ ++/* Buffer quota per queue to use when flow control is active. */ ++#define DPAA2_ETH_NUM_BUFS_FC 256 ++ ++/* Hardware requires alignment for ingress/egress buffer addresses ++ * and ingress buffer lengths. ++ */ ++#define DPAA2_ETH_RX_BUF_SIZE 2048 ++#define DPAA2_ETH_TX_BUF_ALIGN 64 ++#define DPAA2_ETH_RX_BUF_ALIGN 64 ++#define DPAA2_ETH_RX_BUF_ALIGN_V1 256 ++#define DPAA2_ETH_NEEDED_HEADROOM(p_priv) \ ++ ((p_priv)->tx_data_offset + DPAA2_ETH_TX_BUF_ALIGN) ++ ++/* rx_extra_head prevents reallocations in L3 processing. */ ++#define DPAA2_ETH_SKB_SIZE \ ++ (DPAA2_ETH_RX_BUF_SIZE + \ ++ SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) ++ ++/* Hardware only sees DPAA2_ETH_RX_BUF_SIZE, but we need to allocate ingress ++ * buffers large enough to allow building an skb around them and also account ++ * for alignment restrictions. ++ */ ++#define DPAA2_ETH_BUF_RAW_SIZE(p_priv) \ ++ (DPAA2_ETH_SKB_SIZE + \ ++ (p_priv)->rx_buf_align) ++ ++/* PTP nominal frequency 1GHz */ ++#define DPAA2_PTP_NOMINAL_FREQ_PERIOD_NS 1 ++ ++/* Leave enough extra space in the headroom to make sure the skb is ++ * not realloc'd in forwarding scenarios. ++ */ ++#define DPAA2_ETH_RX_HEAD_ROOM 192 ++ ++/* We are accommodating a skb backpointer and some S/G info ++ * in the frame's software annotation. The hardware ++ * options are either 0 or 64, so we choose the latter. ++ */ ++#define DPAA2_ETH_SWA_SIZE 64 ++ ++/* Must keep this struct smaller than DPAA2_ETH_SWA_SIZE */ ++struct dpaa2_eth_swa { ++ struct sk_buff *skb; ++ struct scatterlist *scl; ++ int num_sg; ++ int num_dma_bufs; ++}; ++ ++/* Annotation valid bits in FD FRC */ ++#define DPAA2_FD_FRC_FASV 0x8000 ++#define DPAA2_FD_FRC_FAEADV 0x4000 ++#define DPAA2_FD_FRC_FAPRV 0x2000 ++#define DPAA2_FD_FRC_FAIADV 0x1000 ++#define DPAA2_FD_FRC_FASWOV 0x0800 ++#define DPAA2_FD_FRC_FAICFDV 0x0400 ++ ++#define DPAA2_FD_RX_ERR_MASK (FD_CTRL_SBE | FD_CTRL_FAERR) ++#define DPAA2_FD_TX_ERR_MASK (FD_CTRL_UFD | \ ++ FD_CTRL_SBE | \ ++ FD_CTRL_FSE | \ ++ FD_CTRL_FAERR) ++ ++/* Annotation bits in FD CTRL */ ++#define DPAA2_FD_CTRL_ASAL 0x00020000 /* ASAL = 128 */ ++ ++/* Size of hardware annotation area based on the current buffer layout ++ * configuration ++ */ ++#define DPAA2_ETH_RX_HWA_SIZE 64 ++#define DPAA2_ETH_TX_HWA_SIZE 128 ++ ++/* Frame annotation status */ ++struct dpaa2_fas { ++ u8 reserved; ++ u8 ppid; ++ __le16 ifpid; ++ __le32 status; ++} __packed; ++ ++/* Frame annotation status word is located in the first 8 bytes ++ * of the buffer's hardware annotation area ++ */ ++#define DPAA2_FAS_OFFSET 0 ++#define DPAA2_FAS_SIZE (sizeof(struct dpaa2_fas)) ++ ++/* Timestamp is located in the next 8 bytes of the buffer's ++ * hardware annotation area ++ */ ++#define DPAA2_TS_OFFSET 0x8 ++ ++/* Frame annotation egress action descriptor */ ++#define DPAA2_FAEAD_OFFSET 0x58 ++ ++struct dpaa2_faead { ++ __le32 conf_fqid; ++ __le32 ctrl; ++}; ++ ++#define DPAA2_FAEAD_A2V 0x20000000 ++#define DPAA2_FAEAD_UPDV 0x00001000 ++#define DPAA2_FAEAD_UPD 0x00000010 ++ ++/* accessors for the hardware annotation fields that we use */ ++#define dpaa2_eth_get_hwa(buf_addr) \ ++ ((void *)(buf_addr) + DPAA2_ETH_SWA_SIZE) ++ ++#define dpaa2_eth_get_fas(buf_addr) \ ++ (struct dpaa2_fas *)(dpaa2_eth_get_hwa(buf_addr) + DPAA2_FAS_OFFSET) ++ ++#define dpaa2_eth_get_ts(buf_addr) \ ++ (u64 *)(dpaa2_eth_get_hwa(buf_addr) + DPAA2_TS_OFFSET) ++ ++#define dpaa2_eth_get_faead(buf_addr) \ ++ (struct dpaa2_faead *)(dpaa2_eth_get_hwa(buf_addr) + DPAA2_FAEAD_OFFSET) ++ ++/* Error and status bits in the frame annotation status word */ ++/* Debug frame, otherwise supposed to be discarded */ ++#define DPAA2_FAS_DISC 0x80000000 ++/* MACSEC frame */ ++#define DPAA2_FAS_MS 0x40000000 ++#define DPAA2_FAS_PTP 0x08000000 ++/* Ethernet multicast frame */ ++#define DPAA2_FAS_MC 0x04000000 ++/* Ethernet broadcast frame */ ++#define DPAA2_FAS_BC 0x02000000 ++#define DPAA2_FAS_KSE 0x00040000 ++#define DPAA2_FAS_EOFHE 0x00020000 ++#define DPAA2_FAS_MNLE 0x00010000 ++#define DPAA2_FAS_TIDE 0x00008000 ++#define DPAA2_FAS_PIEE 0x00004000 ++/* Frame length error */ ++#define DPAA2_FAS_FLE 0x00002000 ++/* Frame physical error */ ++#define DPAA2_FAS_FPE 0x00001000 ++#define DPAA2_FAS_PTE 0x00000080 ++#define DPAA2_FAS_ISP 0x00000040 ++#define DPAA2_FAS_PHE 0x00000020 ++#define DPAA2_FAS_BLE 0x00000010 ++/* L3 csum validation performed */ ++#define DPAA2_FAS_L3CV 0x00000008 ++/* L3 csum error */ ++#define DPAA2_FAS_L3CE 0x00000004 ++/* L4 csum validation performed */ ++#define DPAA2_FAS_L4CV 0x00000002 ++/* L4 csum error */ ++#define DPAA2_FAS_L4CE 0x00000001 ++/* Possible errors on the ingress path */ ++#define DPAA2_FAS_RX_ERR_MASK ((DPAA2_FAS_KSE) | \ ++ (DPAA2_FAS_EOFHE) | \ ++ (DPAA2_FAS_MNLE) | \ ++ (DPAA2_FAS_TIDE) | \ ++ (DPAA2_FAS_PIEE) | \ ++ (DPAA2_FAS_FLE) | \ ++ (DPAA2_FAS_FPE) | \ ++ (DPAA2_FAS_PTE) | \ ++ (DPAA2_FAS_ISP) | \ ++ (DPAA2_FAS_PHE) | \ ++ (DPAA2_FAS_BLE) | \ ++ (DPAA2_FAS_L3CE) | \ ++ (DPAA2_FAS_L4CE)) ++/* Tx errors */ ++#define DPAA2_FAS_TX_ERR_MASK ((DPAA2_FAS_KSE) | \ ++ (DPAA2_FAS_EOFHE) | \ ++ (DPAA2_FAS_MNLE) | \ ++ (DPAA2_FAS_TIDE)) ++ ++/* Time in milliseconds between link state updates */ ++#define DPAA2_ETH_LINK_STATE_REFRESH 1000 ++ ++/* Number of times to retry a frame enqueue before giving up. ++ * Value determined empirically, in order to minimize the number ++ * of frames dropped on Tx ++ */ ++#define DPAA2_ETH_ENQUEUE_RETRIES 10 ++ ++/* Tx congestion entry & exit thresholds, in number of bytes. ++ * We allow a maximum of 512KB worth of frames pending processing on the Tx ++ * queues of an interface ++ */ ++#define DPAA2_ETH_TX_CONG_ENTRY_THRESH (512 * 1024) ++#define DPAA2_ETH_TX_CONG_EXIT_THRESH (DPAA2_ETH_TX_CONG_ENTRY_THRESH * 9/10) ++ ++/* Driver statistics, other than those in struct rtnl_link_stats64. ++ * These are usually collected per-CPU and aggregated by ethtool. ++ */ ++struct dpaa2_eth_drv_stats { ++ __u64 tx_conf_frames; ++ __u64 tx_conf_bytes; ++ __u64 tx_sg_frames; ++ __u64 tx_sg_bytes; ++ __u64 rx_sg_frames; ++ __u64 rx_sg_bytes; ++ /* Enqueues retried due to portal busy */ ++ __u64 tx_portal_busy; ++}; ++ ++/* Per-FQ statistics */ ++struct dpaa2_eth_fq_stats { ++ /* Number of frames received on this queue */ ++ __u64 frames; ++ /* Number of times this queue entered congestion */ ++ __u64 congestion_entry; ++}; ++ ++/* Per-channel statistics */ ++struct dpaa2_eth_ch_stats { ++ /* Volatile dequeues retried due to portal busy */ ++ __u64 dequeue_portal_busy; ++ /* Number of CDANs; useful to estimate avg NAPI len */ ++ __u64 cdan; ++ /* Number of frames received on queues from this channel */ ++ __u64 frames; ++ /* Pull errors */ ++ __u64 pull_err; ++}; ++ ++/* Maximum number of queues associated with a DPNI */ ++#define DPAA2_ETH_MAX_RX_QUEUES 16 ++#define DPAA2_ETH_MAX_TX_QUEUES NR_CPUS ++#define DPAA2_ETH_MAX_RX_ERR_QUEUES 1 ++#define DPAA2_ETH_MAX_QUEUES (DPAA2_ETH_MAX_RX_QUEUES + \ ++ DPAA2_ETH_MAX_TX_QUEUES + \ ++ DPAA2_ETH_MAX_RX_ERR_QUEUES) ++ ++#define DPAA2_ETH_MAX_DPCONS NR_CPUS ++ ++enum dpaa2_eth_fq_type { ++ DPAA2_RX_FQ = 0, ++ DPAA2_TX_CONF_FQ, ++ DPAA2_RX_ERR_FQ ++}; ++ ++struct dpaa2_eth_priv; ++ ++struct dpaa2_eth_fq { ++ u32 fqid; ++ u32 tx_qdbin; ++ u16 flowid; ++ int target_cpu; ++ struct dpaa2_eth_channel *channel; ++ enum dpaa2_eth_fq_type type; ++ ++ void (*consume)(struct dpaa2_eth_priv *, ++ struct dpaa2_eth_channel *, ++ const struct dpaa2_fd *, ++ struct napi_struct *, ++ u16 queue_id); ++ struct dpaa2_eth_fq_stats stats; ++}; ++ ++struct dpaa2_eth_channel { ++ struct dpaa2_io_notification_ctx nctx; ++ struct fsl_mc_device *dpcon; ++ int dpcon_id; ++ int ch_id; ++ int dpio_id; ++ struct napi_struct napi; ++ struct dpaa2_io_store *store; ++ struct dpaa2_eth_priv *priv; ++ int buf_count; ++ struct dpaa2_eth_ch_stats stats; ++}; ++ ++struct dpaa2_eth_cls_rule { ++ struct ethtool_rx_flow_spec fs; ++ bool in_use; ++}; ++ ++struct dpaa2_eth_hash_fields { ++ u64 rxnfc_field; ++ enum net_prot cls_prot; ++ int cls_field; ++ int offset; ++ int size; ++}; ++ ++/* Driver private data */ ++struct dpaa2_eth_priv { ++ struct net_device *net_dev; ++ ++ /* Standard statistics */ ++ struct rtnl_link_stats64 __percpu *percpu_stats; ++ /* Extra stats, in addition to the ones known by the kernel */ ++ struct dpaa2_eth_drv_stats __percpu *percpu_extras; ++ struct iommu_domain *iommu_domain; ++ ++ bool ts_tx_en; /* Tx timestamping enabled */ ++ bool ts_rx_en; /* Rx timestamping enabled */ ++ ++ u16 tx_data_offset; ++ u16 rx_buf_align; ++ ++ u16 bpid; ++ u16 tx_qdid; ++ ++ int tx_pause_frames; ++ int num_bufs; ++ int refill_thresh; ++ ++ /* Tx congestion notifications are written here */ ++ void *cscn_mem; ++ void *cscn_unaligned; ++ dma_addr_t cscn_dma; ++ ++ u8 num_fqs; ++ /* Tx queues are at the beginning of the array */ ++ struct dpaa2_eth_fq fq[DPAA2_ETH_MAX_QUEUES]; ++ ++ u8 num_channels; ++ struct dpaa2_eth_channel *channel[DPAA2_ETH_MAX_DPCONS]; ++ ++ int dpni_id; ++ struct dpni_attr dpni_attrs; ++ struct fsl_mc_device *dpbp_dev; ++ ++ struct fsl_mc_io *mc_io; ++ /* SysFS-controlled affinity mask for TxConf FQs */ ++ struct cpumask txconf_cpumask; ++ /* Cores which have an affine DPIO/DPCON. ++ * This is the cpu set on which Rx frames are processed; ++ * Tx confirmation frames are processed on a subset of this, ++ * depending on user settings. ++ */ ++ struct cpumask dpio_cpumask; ++ ++ u16 mc_token; ++ ++ struct dpni_link_state link_state; ++ bool do_link_poll; ++ struct task_struct *poll_thread; ++ ++ struct dpaa2_eth_hash_fields *hash_fields; ++ u8 num_hash_fields; ++ /* enabled ethtool hashing bits */ ++ u64 rx_flow_hash; ++ ++#ifdef CONFIG_FSL_DPAA2_ETH_DEBUGFS ++ struct dpaa2_debugfs dbg; ++#endif ++ ++ /* array of classification rules */ ++ struct dpaa2_eth_cls_rule *cls_rule; ++ ++ struct dpni_tx_shaping_cfg shaping_cfg; ++}; ++ ++#define dpaa2_eth_hash_enabled(priv) \ ++ ((priv)->dpni_attrs.num_queues > 1) ++ ++#define dpaa2_eth_fs_enabled(priv) \ ++ (!((priv)->dpni_attrs.options & DPNI_OPT_NO_FS)) ++ ++#define dpaa2_eth_fs_mask_enabled(priv) \ ++ ((priv)->dpni_attrs.options & DPNI_OPT_HAS_KEY_MASKING) ++ ++#define dpaa2_eth_fs_count(priv) \ ++ ((priv)->dpni_attrs.fs_entries) ++ ++/* size of DMA memory used to pass configuration to classifier, in bytes */ ++#define DPAA2_CLASSIFIER_DMA_SIZE 256 ++ ++extern const struct ethtool_ops dpaa2_ethtool_ops; ++extern const char dpaa2_eth_drv_version[]; ++ ++static inline int dpaa2_eth_queue_count(struct dpaa2_eth_priv *priv) ++{ ++ return priv->dpni_attrs.num_queues; ++} ++ ++void check_cls_support(struct dpaa2_eth_priv *priv); ++ ++int setup_fqs_taildrop(struct dpaa2_eth_priv *priv, bool enable); ++#endif /* __DPAA2_H */ +diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c +new file mode 100644 +index 00000000..9859814e +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c +@@ -0,0 +1,856 @@ ++/* Copyright 2014-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "dpni.h" /* DPNI_LINK_OPT_* */ ++#include "dpaa2-eth.h" ++ ++/* To be kept in sync with dpni_statistics */ ++static char dpaa2_ethtool_stats[][ETH_GSTRING_LEN] = { ++ "rx frames", ++ "rx bytes", ++ "rx mcast frames", ++ "rx mcast bytes", ++ "rx bcast frames", ++ "rx bcast bytes", ++ "tx frames", ++ "tx bytes", ++ "tx mcast frames", ++ "tx mcast bytes", ++ "tx bcast frames", ++ "tx bcast bytes", ++ "rx filtered frames", ++ "rx discarded frames", ++ "rx nobuffer discards", ++ "tx discarded frames", ++ "tx confirmed frames", ++}; ++ ++#define DPAA2_ETH_NUM_STATS ARRAY_SIZE(dpaa2_ethtool_stats) ++ ++/* To be kept in sync with 'struct dpaa2_eth_drv_stats' */ ++static char dpaa2_ethtool_extras[][ETH_GSTRING_LEN] = { ++ /* per-cpu stats */ ++ ++ "tx conf frames", ++ "tx conf bytes", ++ "tx sg frames", ++ "tx sg bytes", ++ "rx sg frames", ++ "rx sg bytes", ++ /* how many times we had to retry the enqueue command */ ++ "enqueue portal busy", ++ ++ /* Channel stats */ ++ /* How many times we had to retry the volatile dequeue command */ ++ "dequeue portal busy", ++ "channel pull errors", ++ /* Number of notifications received */ ++ "cdan", ++ "tx congestion state", ++#ifdef CONFIG_FSL_QBMAN_DEBUG ++ /* FQ stats */ ++ "rx pending frames", ++ "rx pending bytes", ++ "tx conf pending frames", ++ "tx conf pending bytes", ++ "buffer count" ++#endif ++}; ++ ++#define DPAA2_ETH_NUM_EXTRA_STATS ARRAY_SIZE(dpaa2_ethtool_extras) ++ ++static void dpaa2_eth_get_drvinfo(struct net_device *net_dev, ++ struct ethtool_drvinfo *drvinfo) ++{ ++ strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver)); ++ strlcpy(drvinfo->version, dpaa2_eth_drv_version, ++ sizeof(drvinfo->version)); ++ strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version)); ++ strlcpy(drvinfo->bus_info, dev_name(net_dev->dev.parent->parent), ++ sizeof(drvinfo->bus_info)); ++} ++ ++static int dpaa2_eth_get_settings(struct net_device *net_dev, ++ struct ethtool_cmd *cmd) ++{ ++ struct dpni_link_state state = {0}; ++ int err = 0; ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ ++ err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token, &state); ++ if (err) { ++ netdev_err(net_dev, "ERROR %d getting link state", err); ++ goto out; ++ } ++ ++ /* At the moment, we have no way of interrogating the DPMAC ++ * from the DPNI side - and for that matter there may exist ++ * no DPMAC at all. So for now we just don't report anything ++ * beyond the DPNI attributes. ++ */ ++ if (state.options & DPNI_LINK_OPT_AUTONEG) ++ cmd->autoneg = AUTONEG_ENABLE; ++ if (!(state.options & DPNI_LINK_OPT_HALF_DUPLEX)) ++ cmd->duplex = DUPLEX_FULL; ++ ethtool_cmd_speed_set(cmd, state.rate); ++ ++out: ++ return err; ++} ++ ++static int dpaa2_eth_set_settings(struct net_device *net_dev, ++ struct ethtool_cmd *cmd) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ struct dpni_link_state state = {0}; ++ struct dpni_link_cfg cfg = {0}; ++ int err = 0; ++ ++ netdev_dbg(net_dev, "Setting link parameters..."); ++ ++ /* Need to interrogate on link state to get flow control params */ ++ err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token, &state); ++ if (err) { ++ netdev_err(net_dev, "ERROR %d getting link state", err); ++ goto out; ++ } ++ ++ cfg.options = state.options; ++ cfg.rate = ethtool_cmd_speed(cmd); ++ if (cmd->autoneg == AUTONEG_ENABLE) ++ cfg.options |= DPNI_LINK_OPT_AUTONEG; ++ else ++ cfg.options &= ~DPNI_LINK_OPT_AUTONEG; ++ if (cmd->duplex == DUPLEX_HALF) ++ cfg.options |= DPNI_LINK_OPT_HALF_DUPLEX; ++ else ++ cfg.options &= ~DPNI_LINK_OPT_HALF_DUPLEX; ++ ++ err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &cfg); ++ if (err) ++ /* ethtool will be loud enough if we return an error; no point ++ * in putting our own error message on the console by default ++ */ ++ netdev_dbg(net_dev, "ERROR %d setting link cfg", err); ++ ++out: ++ return err; ++} ++ ++static void dpaa2_eth_get_pauseparam(struct net_device *net_dev, ++ struct ethtool_pauseparam *pause) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ struct dpni_link_state state = {0}; ++ int err; ++ ++ err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token, &state); ++ if (err) ++ netdev_dbg(net_dev, "ERROR %d getting link state", err); ++ ++ /* for now, pause frames autonegotiation is not separate */ ++ pause->autoneg = !!(state.options & DPNI_LINK_OPT_AUTONEG); ++ pause->rx_pause = !!(state.options & DPNI_LINK_OPT_PAUSE); ++ pause->tx_pause = pause->rx_pause ^ ++ !!(state.options & DPNI_LINK_OPT_ASYM_PAUSE); ++} ++ ++static int dpaa2_eth_set_pauseparam(struct net_device *net_dev, ++ struct ethtool_pauseparam *pause) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ struct dpni_link_state state = {0}; ++ struct dpni_link_cfg cfg = {0}; ++ u32 current_tx_pause; ++ int err = 0; ++ ++ err = dpni_get_link_state(priv->mc_io, 0, priv->mc_token, &state); ++ if (err) { ++ netdev_dbg(net_dev, "ERROR %d getting link state", err); ++ goto out; ++ } ++ ++ cfg.rate = state.rate; ++ cfg.options = state.options; ++ current_tx_pause = !!(cfg.options & DPNI_LINK_OPT_PAUSE) ^ ++ !!(cfg.options & DPNI_LINK_OPT_ASYM_PAUSE); ++ ++ if (pause->autoneg != !!(state.options & DPNI_LINK_OPT_AUTONEG)) ++ netdev_warn(net_dev, ++ "WARN: Can't change pause frames autoneg separately\n"); ++ ++ if (pause->rx_pause) ++ cfg.options |= DPNI_LINK_OPT_PAUSE; ++ else ++ cfg.options &= ~DPNI_LINK_OPT_PAUSE; ++ ++ if (pause->rx_pause ^ pause->tx_pause) ++ cfg.options |= DPNI_LINK_OPT_ASYM_PAUSE; ++ else ++ cfg.options &= ~DPNI_LINK_OPT_ASYM_PAUSE; ++ ++ err = dpni_set_link_cfg(priv->mc_io, 0, priv->mc_token, &cfg); ++ if (err) { ++ /* ethtool will be loud enough if we return an error; no point ++ * in putting our own error message on the console by default ++ */ ++ netdev_dbg(net_dev, "ERROR %d setting link cfg", err); ++ goto out; ++ } ++ ++ /* Enable / disable taildrops if Tx pause frames have changed */ ++ if (current_tx_pause == pause->tx_pause) ++ goto out; ++ ++ err = setup_fqs_taildrop(priv, !pause->tx_pause); ++ if (err) ++ netdev_dbg(net_dev, "ERROR %d configuring taildrop", err); ++ ++ priv->tx_pause_frames = pause->tx_pause; ++out: ++ return err; ++} ++ ++static void dpaa2_eth_get_strings(struct net_device *netdev, u32 stringset, ++ u8 *data) ++{ ++ u8 *p = data; ++ int i; ++ ++ switch (stringset) { ++ case ETH_SS_STATS: ++ for (i = 0; i < DPAA2_ETH_NUM_STATS; i++) { ++ strlcpy(p, dpaa2_ethtool_stats[i], ETH_GSTRING_LEN); ++ p += ETH_GSTRING_LEN; ++ } ++ for (i = 0; i < DPAA2_ETH_NUM_EXTRA_STATS; i++) { ++ strlcpy(p, dpaa2_ethtool_extras[i], ETH_GSTRING_LEN); ++ p += ETH_GSTRING_LEN; ++ } ++ break; ++ } ++} ++ ++static int dpaa2_eth_get_sset_count(struct net_device *net_dev, int sset) ++{ ++ switch (sset) { ++ case ETH_SS_STATS: /* ethtool_get_stats(), ethtool_get_drvinfo() */ ++ return DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS; ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++/** Fill in hardware counters, as returned by MC. ++ */ ++static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev, ++ struct ethtool_stats *stats, ++ u64 *data) ++{ ++ int i = 0; /* Current index in the data array */ ++ int j = 0, k, err; ++ union dpni_statistics dpni_stats; ++ ++#ifdef CONFIG_FSL_QBMAN_DEBUG ++ u32 fcnt, bcnt; ++ u32 fcnt_rx_total = 0, fcnt_tx_total = 0; ++ u32 bcnt_rx_total = 0, bcnt_tx_total = 0; ++ u32 buf_cnt; ++#endif ++ u64 cdan = 0; ++ u64 portal_busy = 0, pull_err = 0; ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ struct dpaa2_eth_drv_stats *extras; ++ struct dpaa2_eth_ch_stats *ch_stats; ++ ++ memset(data, 0, ++ sizeof(u64) * (DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS)); ++ ++ /* Print standard counters, from DPNI statistics */ ++ for (j = 0; j <= 2; j++) { ++ err = dpni_get_statistics(priv->mc_io, 0, priv->mc_token, ++ j, &dpni_stats); ++ if (err != 0) ++ netdev_warn(net_dev, "Err %d getting DPNI stats page %d", ++ err, j); ++ ++ switch (j) { ++ case 0: ++ *(data + i++) = dpni_stats.page_0.ingress_all_frames; ++ *(data + i++) = dpni_stats.page_0.ingress_all_bytes; ++ *(data + i++) = dpni_stats.page_0.ingress_multicast_frames; ++ *(data + i++) = dpni_stats.page_0.ingress_multicast_bytes; ++ *(data + i++) = dpni_stats.page_0.ingress_broadcast_frames; ++ *(data + i++) = dpni_stats.page_0.ingress_broadcast_bytes; ++ break; ++ case 1: ++ *(data + i++) = dpni_stats.page_1.egress_all_frames; ++ *(data + i++) = dpni_stats.page_1.egress_all_bytes; ++ *(data + i++) = dpni_stats.page_1.egress_multicast_frames; ++ *(data + i++) = dpni_stats.page_1.egress_multicast_bytes; ++ *(data + i++) = dpni_stats.page_1.egress_broadcast_frames; ++ *(data + i++) = dpni_stats.page_1.egress_broadcast_bytes; ++ break; ++ case 2: ++ *(data + i++) = dpni_stats.page_2.ingress_filtered_frames; ++ *(data + i++) = dpni_stats.page_2.ingress_discarded_frames; ++ *(data + i++) = dpni_stats.page_2.ingress_nobuffer_discards; ++ *(data + i++) = dpni_stats.page_2.egress_discarded_frames; ++ *(data + i++) = dpni_stats.page_2.egress_confirmed_frames; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ /* Print per-cpu extra stats */ ++ for_each_online_cpu(k) { ++ extras = per_cpu_ptr(priv->percpu_extras, k); ++ for (j = 0; j < sizeof(*extras) / sizeof(__u64); j++) ++ *((__u64 *)data + i + j) += *((__u64 *)extras + j); ++ } ++ ++ i += j; ++ ++ /* We may be using fewer DPIOs than actual CPUs */ ++ for (j = 0; j < priv->num_channels; j++) { ++ ch_stats = &priv->channel[j]->stats; ++ cdan += ch_stats->cdan; ++ portal_busy += ch_stats->dequeue_portal_busy; ++ pull_err += ch_stats->pull_err; ++ } ++ ++ *(data + i++) = portal_busy; ++ *(data + i++) = pull_err; ++ *(data + i++) = cdan; ++ ++ *(data + i++) = dpaa2_cscn_state_congested(priv->cscn_mem); ++ ++#ifdef CONFIG_FSL_QBMAN_DEBUG ++ for (j = 0; j < priv->num_fqs; j++) { ++ /* Print FQ instantaneous counts */ ++ err = dpaa2_io_query_fq_count(NULL, priv->fq[j].fqid, ++ &fcnt, &bcnt); ++ if (err) { ++ netdev_warn(net_dev, "FQ query error %d", err); ++ return; ++ } ++ ++ if (priv->fq[j].type == DPAA2_TX_CONF_FQ) { ++ fcnt_tx_total += fcnt; ++ bcnt_tx_total += bcnt; ++ } else { ++ fcnt_rx_total += fcnt; ++ bcnt_rx_total += bcnt; ++ } ++ } ++ ++ *(data + i++) = fcnt_rx_total; ++ *(data + i++) = bcnt_rx_total; ++ *(data + i++) = fcnt_tx_total; ++ *(data + i++) = bcnt_tx_total; ++ ++ err = dpaa2_io_query_bp_count(NULL, priv->bpid, &buf_cnt); ++ if (err) { ++ netdev_warn(net_dev, "Buffer count query error %d\n", err); ++ return; ++ } ++ *(data + i++) = buf_cnt; ++#endif ++} ++ ++static int cls_key_off(struct dpaa2_eth_priv *priv, int prot, int field) ++{ ++ int i, off = 0; ++ ++ for (i = 0; i < priv->num_hash_fields; i++) { ++ if (priv->hash_fields[i].cls_prot == prot && ++ priv->hash_fields[i].cls_field == field) ++ return off; ++ off += priv->hash_fields[i].size; ++ } ++ ++ return -1; ++} ++ ++static u8 cls_key_size(struct dpaa2_eth_priv *priv) ++{ ++ u8 i, size = 0; ++ ++ for (i = 0; i < priv->num_hash_fields; i++) ++ size += priv->hash_fields[i].size; ++ ++ return size; ++} ++ ++void check_cls_support(struct dpaa2_eth_priv *priv) ++{ ++ u8 key_size = cls_key_size(priv); ++ struct device *dev = priv->net_dev->dev.parent; ++ ++ if (dpaa2_eth_hash_enabled(priv)) { ++ if (priv->dpni_attrs.fs_key_size < key_size) { ++ dev_info(dev, "max_dist_key_size = %d, expected %d. Hashing and steering are disabled\n", ++ priv->dpni_attrs.fs_key_size, ++ key_size); ++ goto disable_fs; ++ } ++ if (priv->num_hash_fields > DPKG_MAX_NUM_OF_EXTRACTS) { ++ dev_info(dev, "Too many key fields (max = %d). Hashing and steering are disabled\n", ++ DPKG_MAX_NUM_OF_EXTRACTS); ++ goto disable_fs; ++ } ++ } ++ ++ if (dpaa2_eth_fs_enabled(priv)) { ++ if (!dpaa2_eth_hash_enabled(priv)) { ++ dev_info(dev, "Insufficient queues. Steering is disabled\n"); ++ goto disable_fs; ++ } ++ ++ if (!dpaa2_eth_fs_mask_enabled(priv)) { ++ dev_info(dev, "Key masks not supported. Steering is disabled\n"); ++ goto disable_fs; ++ } ++ } ++ ++ return; ++ ++disable_fs: ++ priv->dpni_attrs.options |= DPNI_OPT_NO_FS; ++ priv->dpni_attrs.options &= ~DPNI_OPT_HAS_KEY_MASKING; ++} ++ ++static int prep_l4_rule(struct dpaa2_eth_priv *priv, ++ struct ethtool_tcpip4_spec *l4_value, ++ struct ethtool_tcpip4_spec *l4_mask, ++ void *key, void *mask, u8 l4_proto) ++{ ++ int offset; ++ ++ if (l4_mask->tos) { ++ netdev_err(priv->net_dev, "ToS is not supported for IPv4 L4\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ if (l4_mask->ip4src) { ++ offset = cls_key_off(priv, NET_PROT_IP, NH_FLD_IP_SRC); ++ *(u32 *)(key + offset) = l4_value->ip4src; ++ *(u32 *)(mask + offset) = l4_mask->ip4src; ++ } ++ ++ if (l4_mask->ip4dst) { ++ offset = cls_key_off(priv, NET_PROT_IP, NH_FLD_IP_DST); ++ *(u32 *)(key + offset) = l4_value->ip4dst; ++ *(u32 *)(mask + offset) = l4_mask->ip4dst; ++ } ++ ++ if (l4_mask->psrc) { ++ offset = cls_key_off(priv, NET_PROT_UDP, NH_FLD_UDP_PORT_SRC); ++ *(u32 *)(key + offset) = l4_value->psrc; ++ *(u32 *)(mask + offset) = l4_mask->psrc; ++ } ++ ++ if (l4_mask->pdst) { ++ offset = cls_key_off(priv, NET_PROT_UDP, NH_FLD_UDP_PORT_DST); ++ *(u32 *)(key + offset) = l4_value->pdst; ++ *(u32 *)(mask + offset) = l4_mask->pdst; ++ } ++ ++ /* Only apply the rule for the user-specified L4 protocol ++ * and if ethertype matches IPv4 ++ */ ++ offset = cls_key_off(priv, NET_PROT_ETH, NH_FLD_ETH_TYPE); ++ *(u16 *)(key + offset) = htons(ETH_P_IP); ++ *(u16 *)(mask + offset) = 0xFFFF; ++ ++ offset = cls_key_off(priv, NET_PROT_IP, NH_FLD_IP_PROTO); ++ *(u8 *)(key + offset) = l4_proto; ++ *(u8 *)(mask + offset) = 0xFF; ++ ++ /* TODO: check IP version */ ++ ++ return 0; ++} ++ ++static int prep_eth_rule(struct dpaa2_eth_priv *priv, ++ struct ethhdr *eth_value, struct ethhdr *eth_mask, ++ void *key, void *mask) ++{ ++ int offset; ++ ++ if (eth_mask->h_proto) { ++ netdev_err(priv->net_dev, "Ethertype is not supported!\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ if (!is_zero_ether_addr(eth_mask->h_source)) { ++ offset = cls_key_off(priv, NET_PROT_ETH, NH_FLD_ETH_SA); ++ ether_addr_copy(key + offset, eth_value->h_source); ++ ether_addr_copy(mask + offset, eth_mask->h_source); ++ } ++ ++ if (!is_zero_ether_addr(eth_mask->h_dest)) { ++ offset = cls_key_off(priv, NET_PROT_ETH, NH_FLD_ETH_DA); ++ ether_addr_copy(key + offset, eth_value->h_dest); ++ ether_addr_copy(mask + offset, eth_mask->h_dest); ++ } ++ ++ return 0; ++} ++ ++static int prep_user_ip_rule(struct dpaa2_eth_priv *priv, ++ struct ethtool_usrip4_spec *uip_value, ++ struct ethtool_usrip4_spec *uip_mask, ++ void *key, void *mask) ++{ ++ int offset; ++ ++ if (uip_mask->tos) ++ return -EOPNOTSUPP; ++ ++ if (uip_mask->ip4src) { ++ offset = cls_key_off(priv, NET_PROT_IP, NH_FLD_IP_SRC); ++ *(u32 *)(key + offset) = uip_value->ip4src; ++ *(u32 *)(mask + offset) = uip_mask->ip4src; ++ } ++ ++ if (uip_mask->ip4dst) { ++ offset = cls_key_off(priv, NET_PROT_IP, NH_FLD_IP_DST); ++ *(u32 *)(key + offset) = uip_value->ip4dst; ++ *(u32 *)(mask + offset) = uip_mask->ip4dst; ++ } ++ ++ if (uip_mask->proto) { ++ offset = cls_key_off(priv, NET_PROT_IP, NH_FLD_IP_PROTO); ++ *(u32 *)(key + offset) = uip_value->proto; ++ *(u32 *)(mask + offset) = uip_mask->proto; ++ } ++ if (uip_mask->l4_4_bytes) { ++ offset = cls_key_off(priv, NET_PROT_UDP, NH_FLD_UDP_PORT_SRC); ++ *(u16 *)(key + offset) = uip_value->l4_4_bytes << 16; ++ *(u16 *)(mask + offset) = uip_mask->l4_4_bytes << 16; ++ ++ offset = cls_key_off(priv, NET_PROT_UDP, NH_FLD_UDP_PORT_DST); ++ *(u16 *)(key + offset) = uip_value->l4_4_bytes & 0xFFFF; ++ *(u16 *)(mask + offset) = uip_mask->l4_4_bytes & 0xFFFF; ++ } ++ ++ /* Ethertype must be IP */ ++ offset = cls_key_off(priv, NET_PROT_ETH, NH_FLD_ETH_TYPE); ++ *(u16 *)(key + offset) = htons(ETH_P_IP); ++ *(u16 *)(mask + offset) = 0xFFFF; ++ ++ return 0; ++} ++ ++static int prep_ext_rule(struct dpaa2_eth_priv *priv, ++ struct ethtool_flow_ext *ext_value, ++ struct ethtool_flow_ext *ext_mask, ++ void *key, void *mask) ++{ ++ int offset; ++ ++ if (ext_mask->vlan_etype) ++ return -EOPNOTSUPP; ++ ++ if (ext_mask->vlan_tci) { ++ offset = cls_key_off(priv, NET_PROT_VLAN, NH_FLD_VLAN_TCI); ++ *(u16 *)(key + offset) = ext_value->vlan_tci; ++ *(u16 *)(mask + offset) = ext_mask->vlan_tci; ++ } ++ ++ return 0; ++} ++ ++static int prep_mac_ext_rule(struct dpaa2_eth_priv *priv, ++ struct ethtool_flow_ext *ext_value, ++ struct ethtool_flow_ext *ext_mask, ++ void *key, void *mask) ++{ ++ int offset; ++ ++ if (!is_zero_ether_addr(ext_mask->h_dest)) { ++ offset = cls_key_off(priv, NET_PROT_ETH, NH_FLD_ETH_DA); ++ ether_addr_copy(key + offset, ext_value->h_dest); ++ ether_addr_copy(mask + offset, ext_mask->h_dest); ++ } ++ ++ return 0; ++} ++ ++static int prep_cls_rule(struct net_device *net_dev, ++ struct ethtool_rx_flow_spec *fs, ++ void *key) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ const u8 key_size = cls_key_size(priv); ++ void *msk = key + key_size; ++ int err; ++ ++ memset(key, 0, key_size * 2); ++ ++ switch (fs->flow_type & 0xff) { ++ case TCP_V4_FLOW: ++ err = prep_l4_rule(priv, &fs->h_u.tcp_ip4_spec, ++ &fs->m_u.tcp_ip4_spec, key, msk, ++ IPPROTO_TCP); ++ break; ++ case UDP_V4_FLOW: ++ err = prep_l4_rule(priv, &fs->h_u.udp_ip4_spec, ++ &fs->m_u.udp_ip4_spec, key, msk, ++ IPPROTO_UDP); ++ break; ++ case SCTP_V4_FLOW: ++ err = prep_l4_rule(priv, &fs->h_u.sctp_ip4_spec, ++ &fs->m_u.sctp_ip4_spec, key, msk, ++ IPPROTO_SCTP); ++ break; ++ case ETHER_FLOW: ++ err = prep_eth_rule(priv, &fs->h_u.ether_spec, ++ &fs->m_u.ether_spec, key, msk); ++ break; ++ case IP_USER_FLOW: ++ err = prep_user_ip_rule(priv, &fs->h_u.usr_ip4_spec, ++ &fs->m_u.usr_ip4_spec, key, msk); ++ break; ++ default: ++ /* TODO: AH, ESP */ ++ return -EOPNOTSUPP; ++ } ++ if (err) ++ return err; ++ ++ if (fs->flow_type & FLOW_EXT) { ++ err = prep_ext_rule(priv, &fs->h_ext, &fs->m_ext, key, msk); ++ if (err) ++ return err; ++ } ++ ++ if (fs->flow_type & FLOW_MAC_EXT) { ++ err = prep_mac_ext_rule(priv, &fs->h_ext, &fs->m_ext, key, msk); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int del_cls(struct net_device *net_dev, int location); ++ ++static int do_cls(struct net_device *net_dev, ++ struct ethtool_rx_flow_spec *fs, ++ bool add) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ struct device *dev = net_dev->dev.parent; ++ const int rule_cnt = dpaa2_eth_fs_count(priv); ++ struct dpni_rule_cfg rule_cfg; ++ struct dpni_fs_action_cfg fs_act = { 0 }; ++ void *dma_mem; ++ int err = 0; ++ ++ if (!dpaa2_eth_fs_enabled(priv)) { ++ netdev_err(net_dev, "dev does not support steering!\n"); ++ /* dev doesn't support steering */ ++ return -EOPNOTSUPP; ++ } ++ ++ if ((fs->ring_cookie != RX_CLS_FLOW_DISC && ++ fs->ring_cookie >= dpaa2_eth_queue_count(priv)) || ++ fs->location >= rule_cnt) ++ return -EINVAL; ++ ++ /* When adding a new rule, check if location if available, ++ * and if not free the existing table entry before inserting ++ * the new one ++ */ ++ if (add && (priv->cls_rule[fs->location].in_use == true)) ++ del_cls(net_dev, fs->location); ++ ++ memset(&rule_cfg, 0, sizeof(rule_cfg)); ++ rule_cfg.key_size = cls_key_size(priv); ++ ++ /* allocate twice the key size, for the actual key and for mask */ ++ dma_mem = kzalloc(rule_cfg.key_size * 2, GFP_DMA | GFP_KERNEL); ++ if (!dma_mem) ++ return -ENOMEM; ++ ++ err = prep_cls_rule(net_dev, fs, dma_mem); ++ if (err) ++ goto err_free_mem; ++ ++ rule_cfg.key_iova = dma_map_single(dev, dma_mem, ++ rule_cfg.key_size * 2, ++ DMA_TO_DEVICE); ++ ++ rule_cfg.mask_iova = rule_cfg.key_iova + rule_cfg.key_size; ++ ++ if (fs->ring_cookie == RX_CLS_FLOW_DISC) ++ fs_act.options |= DPNI_FS_OPT_DISCARD; ++ else ++ fs_act.flow_id = fs->ring_cookie; ++ ++ if (add) ++ err = dpni_add_fs_entry(priv->mc_io, 0, priv->mc_token, ++ 0, fs->location, &rule_cfg, &fs_act); ++ else ++ err = dpni_remove_fs_entry(priv->mc_io, 0, priv->mc_token, ++ 0, &rule_cfg); ++ ++ dma_unmap_single(dev, rule_cfg.key_iova, ++ rule_cfg.key_size * 2, DMA_TO_DEVICE); ++ ++ if (err) ++ netdev_err(net_dev, "dpaa2_add/remove_cls() error %d\n", err); ++ ++err_free_mem: ++ kfree(dma_mem); ++ ++ return err; ++} ++ ++static int add_cls(struct net_device *net_dev, ++ struct ethtool_rx_flow_spec *fs) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ int err; ++ ++ err = do_cls(net_dev, fs, true); ++ if (err) ++ return err; ++ ++ priv->cls_rule[fs->location].in_use = true; ++ priv->cls_rule[fs->location].fs = *fs; ++ ++ return 0; ++} ++ ++static int del_cls(struct net_device *net_dev, int location) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ int err; ++ ++ err = do_cls(net_dev, &priv->cls_rule[location].fs, false); ++ if (err) ++ return err; ++ ++ priv->cls_rule[location].in_use = false; ++ ++ return 0; ++} ++ ++static int dpaa2_eth_set_rxnfc(struct net_device *net_dev, ++ struct ethtool_rxnfc *rxnfc) ++{ ++ int err = 0; ++ ++ switch (rxnfc->cmd) { ++ case ETHTOOL_SRXCLSRLINS: ++ err = add_cls(net_dev, &rxnfc->fs); ++ break; ++ ++ case ETHTOOL_SRXCLSRLDEL: ++ err = del_cls(net_dev, rxnfc->fs.location); ++ break; ++ ++ default: ++ err = -EOPNOTSUPP; ++ } ++ ++ return err; ++} ++ ++static int dpaa2_eth_get_rxnfc(struct net_device *net_dev, ++ struct ethtool_rxnfc *rxnfc, u32 *rule_locs) ++{ ++ struct dpaa2_eth_priv *priv = netdev_priv(net_dev); ++ const int rule_cnt = dpaa2_eth_fs_count(priv); ++ int i, j; ++ ++ switch (rxnfc->cmd) { ++ case ETHTOOL_GRXFH: ++ /* we purposely ignore cmd->flow_type, because the hashing key ++ * is the same (and fixed) for all protocols ++ */ ++ rxnfc->data = priv->rx_flow_hash; ++ break; ++ ++ case ETHTOOL_GRXRINGS: ++ rxnfc->data = dpaa2_eth_queue_count(priv); ++ break; ++ ++ case ETHTOOL_GRXCLSRLCNT: ++ for (i = 0, rxnfc->rule_cnt = 0; i < rule_cnt; i++) ++ if (priv->cls_rule[i].in_use) ++ rxnfc->rule_cnt++; ++ rxnfc->data = rule_cnt; ++ break; ++ ++ case ETHTOOL_GRXCLSRULE: ++ if (!priv->cls_rule[rxnfc->fs.location].in_use) ++ return -EINVAL; ++ ++ rxnfc->fs = priv->cls_rule[rxnfc->fs.location].fs; ++ break; ++ ++ case ETHTOOL_GRXCLSRLALL: ++ for (i = 0, j = 0; i < rule_cnt; i++) { ++ if (!priv->cls_rule[i].in_use) ++ continue; ++ if (j == rxnfc->rule_cnt) ++ return -EMSGSIZE; ++ rule_locs[j++] = i; ++ } ++ rxnfc->rule_cnt = j; ++ rxnfc->data = rule_cnt; ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++const struct ethtool_ops dpaa2_ethtool_ops = { ++ .get_drvinfo = dpaa2_eth_get_drvinfo, ++ .get_link = ethtool_op_get_link, ++ .get_settings = dpaa2_eth_get_settings, ++ .set_settings = dpaa2_eth_set_settings, ++ .get_pauseparam = dpaa2_eth_get_pauseparam, ++ .set_pauseparam = dpaa2_eth_set_pauseparam, ++ .get_sset_count = dpaa2_eth_get_sset_count, ++ .get_ethtool_stats = dpaa2_eth_get_ethtool_stats, ++ .get_strings = dpaa2_eth_get_strings, ++ .get_rxnfc = dpaa2_eth_get_rxnfc, ++ .set_rxnfc = dpaa2_eth_set_rxnfc, ++}; +diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpkg.h b/drivers/staging/fsl-dpaa2/ethernet/dpkg.h +new file mode 100644 +index 00000000..02290a08 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethernet/dpkg.h +@@ -0,0 +1,176 @@ ++/* Copyright 2013-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef __FSL_DPKG_H_ ++#define __FSL_DPKG_H_ ++ ++#include ++#include "net.h" ++ ++/* Data Path Key Generator API ++ * Contains initialization APIs and runtime APIs for the Key Generator ++ */ ++ ++/** Key Generator properties */ ++ ++/** ++ * Number of masks per key extraction ++ */ ++#define DPKG_NUM_OF_MASKS 4 ++/** ++ * Number of extractions per key profile ++ */ ++#define DPKG_MAX_NUM_OF_EXTRACTS 10 ++ ++/** ++ * enum dpkg_extract_from_hdr_type - Selecting extraction by header types ++ * @DPKG_FROM_HDR: Extract selected bytes from header, by offset ++ * @DPKG_FROM_FIELD: Extract selected bytes from header, by offset from field ++ * @DPKG_FULL_FIELD: Extract a full field ++ */ ++enum dpkg_extract_from_hdr_type { ++ DPKG_FROM_HDR = 0, ++ DPKG_FROM_FIELD = 1, ++ DPKG_FULL_FIELD = 2 ++}; ++ ++/** ++ * enum dpkg_extract_type - Enumeration for selecting extraction type ++ * @DPKG_EXTRACT_FROM_HDR: Extract from the header ++ * @DPKG_EXTRACT_FROM_DATA: Extract from data not in specific header ++ * @DPKG_EXTRACT_FROM_PARSE: Extract from parser-result; ++ * e.g. can be used to extract header existence; ++ * please refer to 'Parse Result definition' section in the parser BG ++ */ ++enum dpkg_extract_type { ++ DPKG_EXTRACT_FROM_HDR = 0, ++ DPKG_EXTRACT_FROM_DATA = 1, ++ DPKG_EXTRACT_FROM_PARSE = 3 ++}; ++ ++/** ++ * struct dpkg_mask - A structure for defining a single extraction mask ++ * @mask: Byte mask for the extracted content ++ * @offset: Offset within the extracted content ++ */ ++struct dpkg_mask { ++ u8 mask; ++ u8 offset; ++}; ++ ++/** ++ * struct dpkg_extract - A structure for defining a single extraction ++ * @type: Determines how the union below is interpreted: ++ * DPKG_EXTRACT_FROM_HDR: selects 'from_hdr'; ++ * DPKG_EXTRACT_FROM_DATA: selects 'from_data'; ++ * DPKG_EXTRACT_FROM_PARSE: selects 'from_parse' ++ * @extract: Selects extraction method ++ * @num_of_byte_masks: Defines the number of valid entries in the array below; ++ * This is also the number of bytes to be used as masks ++ * @masks: Masks parameters ++ */ ++struct dpkg_extract { ++ enum dpkg_extract_type type; ++ /** ++ * union extract - Selects extraction method ++ * @from_hdr - Used when 'type = DPKG_EXTRACT_FROM_HDR' ++ * @from_data - Used when 'type = DPKG_EXTRACT_FROM_DATA' ++ * @from_parse - Used when 'type = DPKG_EXTRACT_FROM_PARSE' ++ */ ++ union { ++ /** ++ * struct from_hdr - Used when 'type = DPKG_EXTRACT_FROM_HDR' ++ * @prot: Any of the supported headers ++ * @type: Defines the type of header extraction: ++ * DPKG_FROM_HDR: use size & offset below; ++ * DPKG_FROM_FIELD: use field, size and offset below; ++ * DPKG_FULL_FIELD: use field below ++ * @field: One of the supported fields (NH_FLD_) ++ * ++ * @size: Size in bytes ++ * @offset: Byte offset ++ * @hdr_index: Clear for cases not listed below; ++ * Used for protocols that may have more than a single ++ * header, 0 indicates an outer header; ++ * Supported protocols (possible values): ++ * NET_PROT_VLAN (0, HDR_INDEX_LAST); ++ * NET_PROT_MPLS (0, 1, HDR_INDEX_LAST); ++ * NET_PROT_IP(0, HDR_INDEX_LAST); ++ * NET_PROT_IPv4(0, HDR_INDEX_LAST); ++ * NET_PROT_IPv6(0, HDR_INDEX_LAST); ++ */ ++ ++ struct { ++ enum net_prot prot; ++ enum dpkg_extract_from_hdr_type type; ++ u32 field; ++ u8 size; ++ u8 offset; ++ u8 hdr_index; ++ } from_hdr; ++ /** ++ * struct from_data - Used when 'type = DPKG_EXTRACT_FROM_DATA' ++ * @size: Size in bytes ++ * @offset: Byte offset ++ */ ++ struct { ++ u8 size; ++ u8 offset; ++ } from_data; ++ ++ /** ++ * struct from_parse - Used when ++ * 'type = DPKG_EXTRACT_FROM_PARSE' ++ * @size: Size in bytes ++ * @offset: Byte offset ++ */ ++ struct { ++ u8 size; ++ u8 offset; ++ } from_parse; ++ } extract; ++ ++ u8 num_of_byte_masks; ++ struct dpkg_mask masks[DPKG_NUM_OF_MASKS]; ++}; ++ ++/** ++ * struct dpkg_profile_cfg - A structure for defining a full Key Generation ++ * profile (rule) ++ * @num_extracts: Defines the number of valid entries in the array below ++ * @extracts: Array of required extractions ++ */ ++struct dpkg_profile_cfg { ++ u8 num_extracts; ++ struct dpkg_extract extracts[DPKG_MAX_NUM_OF_EXTRACTS]; ++}; ++ ++#endif /* __FSL_DPKG_H_ */ +diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h b/drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h +new file mode 100644 +index 00000000..fa353d75 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethernet/dpni-cmd.h +@@ -0,0 +1,600 @@ ++/* Copyright 2013-2016 Freescale Semiconductor Inc. ++ * Copyright 2016 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef _FSL_DPNI_CMD_H ++#define _FSL_DPNI_CMD_H ++ ++/* DPNI Version */ ++#define DPNI_VER_MAJOR 7 ++#define DPNI_VER_MINOR 0 ++#define DPNI_CMD_BASE_VERSION 1 ++#define DPNI_CMD_ID_OFFSET 4 ++ ++#define DPNI_CMD(id) (((id) << DPNI_CMD_ID_OFFSET) | DPNI_CMD_BASE_VERSION) ++ ++#define DPNI_CMDID_OPEN DPNI_CMD(0x801) ++#define DPNI_CMDID_CLOSE DPNI_CMD(0x800) ++#define DPNI_CMDID_CREATE DPNI_CMD(0x901) ++#define DPNI_CMDID_DESTROY DPNI_CMD(0x900) ++#define DPNI_CMDID_GET_API_VERSION DPNI_CMD(0xa01) ++ ++#define DPNI_CMDID_ENABLE DPNI_CMD(0x002) ++#define DPNI_CMDID_DISABLE DPNI_CMD(0x003) ++#define DPNI_CMDID_GET_ATTR DPNI_CMD(0x004) ++#define DPNI_CMDID_RESET DPNI_CMD(0x005) ++#define DPNI_CMDID_IS_ENABLED DPNI_CMD(0x006) ++ ++#define DPNI_CMDID_SET_IRQ DPNI_CMD(0x010) ++#define DPNI_CMDID_GET_IRQ DPNI_CMD(0x011) ++#define DPNI_CMDID_SET_IRQ_ENABLE DPNI_CMD(0x012) ++#define DPNI_CMDID_GET_IRQ_ENABLE DPNI_CMD(0x013) ++#define DPNI_CMDID_SET_IRQ_MASK DPNI_CMD(0x014) ++#define DPNI_CMDID_GET_IRQ_MASK DPNI_CMD(0x015) ++#define DPNI_CMDID_GET_IRQ_STATUS DPNI_CMD(0x016) ++#define DPNI_CMDID_CLEAR_IRQ_STATUS DPNI_CMD(0x017) ++ ++#define DPNI_CMDID_SET_POOLS DPNI_CMD(0x200) ++#define DPNI_CMDID_SET_ERRORS_BEHAVIOR DPNI_CMD(0x20B) ++ ++#define DPNI_CMDID_GET_QDID DPNI_CMD(0x210) ++#define DPNI_CMDID_GET_TX_DATA_OFFSET DPNI_CMD(0x212) ++#define DPNI_CMDID_GET_LINK_STATE DPNI_CMD(0x215) ++#define DPNI_CMDID_SET_MAX_FRAME_LENGTH DPNI_CMD(0x216) ++#define DPNI_CMDID_GET_MAX_FRAME_LENGTH DPNI_CMD(0x217) ++#define DPNI_CMDID_SET_LINK_CFG DPNI_CMD(0x21A) ++#define DPNI_CMDID_SET_TX_SHAPING DPNI_CMD(0x21B) ++ ++#define DPNI_CMDID_SET_MCAST_PROMISC DPNI_CMD(0x220) ++#define DPNI_CMDID_GET_MCAST_PROMISC DPNI_CMD(0x221) ++#define DPNI_CMDID_SET_UNICAST_PROMISC DPNI_CMD(0x222) ++#define DPNI_CMDID_GET_UNICAST_PROMISC DPNI_CMD(0x223) ++#define DPNI_CMDID_SET_PRIM_MAC DPNI_CMD(0x224) ++#define DPNI_CMDID_GET_PRIM_MAC DPNI_CMD(0x225) ++#define DPNI_CMDID_ADD_MAC_ADDR DPNI_CMD(0x226) ++#define DPNI_CMDID_REMOVE_MAC_ADDR DPNI_CMD(0x227) ++#define DPNI_CMDID_CLR_MAC_FILTERS DPNI_CMD(0x228) ++ ++#define DPNI_CMDID_SET_RX_TC_DIST DPNI_CMD(0x235) ++ ++#define DPNI_CMDID_ADD_FS_ENT DPNI_CMD(0x244) ++#define DPNI_CMDID_REMOVE_FS_ENT DPNI_CMD(0x245) ++#define DPNI_CMDID_CLR_FS_ENT DPNI_CMD(0x246) ++ ++#define DPNI_CMDID_GET_STATISTICS DPNI_CMD(0x25D) ++#define DPNI_CMDID_RESET_STATISTICS DPNI_CMD(0x25E) ++#define DPNI_CMDID_GET_QUEUE DPNI_CMD(0x25F) ++#define DPNI_CMDID_SET_QUEUE DPNI_CMD(0x260) ++#define DPNI_CMDID_GET_TAILDROP DPNI_CMD(0x261) ++#define DPNI_CMDID_SET_TAILDROP DPNI_CMD(0x262) ++ ++#define DPNI_CMDID_GET_PORT_MAC_ADDR DPNI_CMD(0x263) ++ ++#define DPNI_CMDID_GET_BUFFER_LAYOUT DPNI_CMD(0x264) ++#define DPNI_CMDID_SET_BUFFER_LAYOUT DPNI_CMD(0x265) ++ ++#define DPNI_CMDID_SET_TX_CONFIRMATION_MODE DPNI_CMD(0x266) ++#define DPNI_CMDID_SET_CONGESTION_NOTIFICATION DPNI_CMD(0x267) ++#define DPNI_CMDID_GET_CONGESTION_NOTIFICATION DPNI_CMD(0x268) ++#define DPNI_CMDID_SET_EARLY_DROP DPNI_CMD(0x269) ++#define DPNI_CMDID_GET_EARLY_DROP DPNI_CMD(0x26A) ++#define DPNI_CMDID_GET_OFFLOAD DPNI_CMD(0x26B) ++#define DPNI_CMDID_SET_OFFLOAD DPNI_CMD(0x26C) ++ ++/* Macros for accessing command fields smaller than 1byte */ ++#define DPNI_MASK(field) \ ++ GENMASK(DPNI_##field##_SHIFT + DPNI_##field##_SIZE - 1, \ ++ DPNI_##field##_SHIFT) ++ ++#define dpni_set_field(var, field, val) \ ++ ((var) |= (((val) << DPNI_##field##_SHIFT) & DPNI_MASK(field))) ++#define dpni_get_field(var, field) \ ++ (((var) & DPNI_MASK(field)) >> DPNI_##field##_SHIFT) ++ ++struct dpni_cmd_open { ++ __le32 dpni_id; ++}; ++ ++#define DPNI_BACKUP_POOL(val, order) (((val) & 0x1) << (order)) ++struct dpni_cmd_set_pools { ++ /* cmd word 0 */ ++ u8 num_dpbp; ++ u8 backup_pool_mask; ++ __le16 pad; ++ /* cmd word 0..4 */ ++ __le32 dpbp_id[DPNI_MAX_DPBP]; ++ /* cmd word 4..6 */ ++ __le16 buffer_size[DPNI_MAX_DPBP]; ++}; ++ ++/* The enable indication is always the least significant bit */ ++#define DPNI_ENABLE_SHIFT 0 ++#define DPNI_ENABLE_SIZE 1 ++ ++struct dpni_rsp_is_enabled { ++ u8 enabled; ++}; ++ ++struct dpni_rsp_get_irq { ++ /* response word 0 */ ++ __le32 irq_val; ++ __le32 pad; ++ /* response word 1 */ ++ __le64 irq_addr; ++ /* response word 2 */ ++ __le32 irq_num; ++ __le32 type; ++}; ++ ++struct dpni_cmd_set_irq_enable { ++ u8 enable; ++ u8 pad[3]; ++ u8 irq_index; ++}; ++ ++struct dpni_cmd_get_irq_enable { ++ __le32 pad; ++ u8 irq_index; ++}; ++ ++struct dpni_rsp_get_irq_enable { ++ u8 enabled; ++}; ++ ++struct dpni_cmd_set_irq_mask { ++ __le32 mask; ++ u8 irq_index; ++}; ++ ++struct dpni_cmd_get_irq_mask { ++ __le32 pad; ++ u8 irq_index; ++}; ++ ++struct dpni_rsp_get_irq_mask { ++ __le32 mask; ++}; ++ ++struct dpni_cmd_get_irq_status { ++ __le32 status; ++ u8 irq_index; ++}; ++ ++struct dpni_rsp_get_irq_status { ++ __le32 status; ++}; ++ ++struct dpni_cmd_clear_irq_status { ++ __le32 status; ++ u8 irq_index; ++}; ++ ++struct dpni_rsp_get_attr { ++ /* response word 0 */ ++ __le32 options; ++ u8 num_queues; ++ u8 num_tcs; ++ u8 mac_filter_entries; ++ u8 pad0; ++ /* response word 1 */ ++ u8 vlan_filter_entries; ++ u8 pad1; ++ u8 qos_entries; ++ u8 pad2; ++ __le16 fs_entries; ++ __le16 pad3; ++ /* response word 2 */ ++ u8 qos_key_size; ++ u8 fs_key_size; ++ __le16 wriop_version; ++}; ++ ++#define DPNI_ERROR_ACTION_SHIFT 0 ++#define DPNI_ERROR_ACTION_SIZE 4 ++#define DPNI_FRAME_ANN_SHIFT 4 ++#define DPNI_FRAME_ANN_SIZE 1 ++ ++struct dpni_cmd_set_errors_behavior { ++ __le32 errors; ++ /* from least significant bit: error_action:4, set_frame_annotation:1 */ ++ u8 flags; ++}; ++ ++/* There are 3 separate commands for configuring Rx, Tx and Tx confirmation ++ * buffer layouts, but they all share the same parameters. ++ * If one of the functions changes, below structure needs to be split. ++ */ ++ ++#define DPNI_PASS_TS_SHIFT 0 ++#define DPNI_PASS_TS_SIZE 1 ++#define DPNI_PASS_PR_SHIFT 1 ++#define DPNI_PASS_PR_SIZE 1 ++#define DPNI_PASS_FS_SHIFT 2 ++#define DPNI_PASS_FS_SIZE 1 ++ ++struct dpni_cmd_get_buffer_layout { ++ u8 qtype; ++}; ++ ++struct dpni_rsp_get_buffer_layout { ++ /* response word 0 */ ++ u8 pad0[6]; ++ /* from LSB: pass_timestamp:1, parser_result:1, frame_status:1 */ ++ u8 flags; ++ u8 pad1; ++ /* response word 1 */ ++ __le16 private_data_size; ++ __le16 data_align; ++ __le16 head_room; ++ __le16 tail_room; ++}; ++ ++struct dpni_cmd_set_buffer_layout { ++ /* cmd word 0 */ ++ u8 qtype; ++ u8 pad0[3]; ++ __le16 options; ++ /* from LSB: pass_timestamp:1, parser_result:1, frame_status:1 */ ++ u8 flags; ++ u8 pad1; ++ /* cmd word 1 */ ++ __le16 private_data_size; ++ __le16 data_align; ++ __le16 head_room; ++ __le16 tail_room; ++}; ++ ++struct dpni_cmd_set_offload { ++ u8 pad[3]; ++ u8 dpni_offload; ++ __le32 config; ++}; ++ ++struct dpni_cmd_get_offload { ++ u8 pad[3]; ++ u8 dpni_offload; ++}; ++ ++struct dpni_rsp_get_offload { ++ __le32 pad; ++ __le32 config; ++}; ++ ++struct dpni_cmd_get_qdid { ++ u8 qtype; ++}; ++ ++struct dpni_rsp_get_qdid { ++ __le16 qdid; ++}; ++ ++struct dpni_rsp_get_tx_data_offset { ++ __le16 data_offset; ++}; ++ ++struct dpni_cmd_get_statistics { ++ u8 page_number; ++}; ++ ++struct dpni_rsp_get_statistics { ++ __le64 counter[DPNI_STATISTICS_CNT]; ++}; ++ ++struct dpni_cmd_set_link_cfg { ++ /* cmd word 0 */ ++ __le64 pad0; ++ /* cmd word 1 */ ++ __le32 rate; ++ __le32 pad1; ++ /* cmd word 2 */ ++ __le64 options; ++}; ++ ++#define DPNI_LINK_STATE_SHIFT 0 ++#define DPNI_LINK_STATE_SIZE 1 ++ ++struct dpni_rsp_get_link_state { ++ /* response word 0 */ ++ __le32 pad0; ++ /* from LSB: up:1 */ ++ u8 flags; ++ u8 pad1[3]; ++ /* response word 1 */ ++ __le32 rate; ++ __le32 pad2; ++ /* response word 2 */ ++ __le64 options; ++}; ++ ++struct dpni_cmd_set_tx_shaping { ++ /* cmd word 0 */ ++ __le16 max_burst_size; ++ __le16 pad0[3]; ++ /* cmd word 1 */ ++ __le32 rate_limit; ++}; ++ ++struct dpni_cmd_set_max_frame_length { ++ __le16 max_frame_length; ++}; ++ ++struct dpni_rsp_get_max_frame_length { ++ __le16 max_frame_length; ++}; ++ ++struct dpni_cmd_set_multicast_promisc { ++ u8 enable; ++}; ++ ++struct dpni_rsp_get_multicast_promisc { ++ u8 enabled; ++}; ++ ++struct dpni_cmd_set_unicast_promisc { ++ u8 enable; ++}; ++ ++struct dpni_rsp_get_unicast_promisc { ++ u8 enabled; ++}; ++ ++struct dpni_cmd_set_primary_mac_addr { ++ __le16 pad; ++ u8 mac_addr[6]; ++}; ++ ++struct dpni_rsp_get_primary_mac_addr { ++ __le16 pad; ++ u8 mac_addr[6]; ++}; ++ ++struct dpni_rsp_get_port_mac_addr { ++ __le16 pad; ++ u8 mac_addr[6]; ++}; ++ ++struct dpni_cmd_add_mac_addr { ++ __le16 pad; ++ u8 mac_addr[6]; ++}; ++ ++struct dpni_cmd_remove_mac_addr { ++ __le16 pad; ++ u8 mac_addr[6]; ++}; ++ ++#define DPNI_UNICAST_FILTERS_SHIFT 0 ++#define DPNI_UNICAST_FILTERS_SIZE 1 ++#define DPNI_MULTICAST_FILTERS_SHIFT 1 ++#define DPNI_MULTICAST_FILTERS_SIZE 1 ++ ++struct dpni_cmd_clear_mac_filters { ++ /* from LSB: unicast:1, multicast:1 */ ++ u8 flags; ++}; ++ ++#define DPNI_DIST_MODE_SHIFT 0 ++#define DPNI_DIST_MODE_SIZE 4 ++#define DPNI_MISS_ACTION_SHIFT 4 ++#define DPNI_MISS_ACTION_SIZE 4 ++ ++struct dpni_cmd_set_rx_tc_dist { ++ /* cmd word 0 */ ++ __le16 dist_size; ++ u8 tc_id; ++ /* from LSB: dist_mode:4, miss_action:4 */ ++ u8 flags; ++ __le16 pad0; ++ __le16 default_flow_id; ++ /* cmd word 1..5 */ ++ __le64 pad1[5]; ++ /* cmd word 6 */ ++ __le64 key_cfg_iova; ++}; ++ ++/* dpni_set_rx_tc_dist extension (structure of the DMA-able memory at ++ * key_cfg_iova) ++ */ ++struct dpni_mask_cfg { ++ u8 mask; ++ u8 offset; ++}; ++ ++#define DPNI_EFH_TYPE_SHIFT 0 ++#define DPNI_EFH_TYPE_SIZE 4 ++#define DPNI_EXTRACT_TYPE_SHIFT 0 ++#define DPNI_EXTRACT_TYPE_SIZE 4 ++ ++struct dpni_dist_extract { ++ /* word 0 */ ++ u8 prot; ++ /* EFH type stored in the 4 least significant bits */ ++ u8 efh_type; ++ u8 size; ++ u8 offset; ++ __le32 field; ++ /* word 1 */ ++ u8 hdr_index; ++ u8 constant; ++ u8 num_of_repeats; ++ u8 num_of_byte_masks; ++ /* Extraction type is stored in the 4 LSBs */ ++ u8 extract_type; ++ u8 pad[3]; ++ /* word 2 */ ++ struct dpni_mask_cfg masks[4]; ++}; ++ ++struct dpni_ext_set_rx_tc_dist { ++ /* extension word 0 */ ++ u8 num_extracts; ++ u8 pad[7]; ++ /* words 1..25 */ ++ struct dpni_dist_extract extracts[DPKG_MAX_NUM_OF_EXTRACTS]; ++}; ++ ++struct dpni_cmd_get_queue { ++ u8 qtype; ++ u8 tc; ++ u8 index; ++}; ++ ++#define DPNI_DEST_TYPE_SHIFT 0 ++#define DPNI_DEST_TYPE_SIZE 4 ++#define DPNI_STASH_CTRL_SHIFT 6 ++#define DPNI_STASH_CTRL_SIZE 1 ++#define DPNI_HOLD_ACTIVE_SHIFT 7 ++#define DPNI_HOLD_ACTIVE_SIZE 1 ++ ++struct dpni_rsp_get_queue { ++ /* response word 0 */ ++ __le64 pad0; ++ /* response word 1 */ ++ __le32 dest_id; ++ __le16 pad1; ++ u8 dest_prio; ++ /* From LSB: dest_type:4, pad:2, flc_stash_ctrl:1, hold_active:1 */ ++ u8 flags; ++ /* response word 2 */ ++ __le64 flc; ++ /* response word 3 */ ++ __le64 user_context; ++ /* response word 4 */ ++ __le32 fqid; ++ __le16 qdbin; ++}; ++ ++struct dpni_cmd_set_queue { ++ /* cmd word 0 */ ++ u8 qtype; ++ u8 tc; ++ u8 index; ++ u8 options; ++ __le32 pad0; ++ /* cmd word 1 */ ++ __le32 dest_id; ++ __le16 pad1; ++ u8 dest_prio; ++ u8 flags; ++ /* cmd word 2 */ ++ __le64 flc; ++ /* cmd word 3 */ ++ __le64 user_context; ++}; ++ ++struct dpni_cmd_add_fs_entry { ++ /* cmd word 0 */ ++ u16 options; ++ u8 tc_id; ++ u8 key_size; ++ u16 index; ++ u16 flow_id; ++ /* cmd word 1 */ ++ u64 key_iova; ++ /* cmd word 2 */ ++ u64 mask_iova; ++ /* cmd word 3 */ ++ u64 flc; ++}; ++ ++struct dpni_cmd_remove_fs_entry { ++ /* cmd word 0 */ ++ __le16 pad0; ++ u8 tc_id; ++ u8 key_size; ++ __le32 pad1; ++ /* cmd word 1 */ ++ u64 key_iova; ++ /* cmd word 2 */ ++ u64 mask_iova; ++}; ++ ++struct dpni_cmd_set_taildrop { ++ /* cmd word 0 */ ++ u8 congestion_point; ++ u8 qtype; ++ u8 tc; ++ u8 index; ++ __le32 pad0; ++ /* cmd word 1 */ ++ /* Only least significant bit is relevant */ ++ u8 enable; ++ u8 pad1; ++ u8 units; ++ u8 pad2; ++ __le32 threshold; ++}; ++ ++struct dpni_cmd_get_taildrop { ++ u8 congestion_point; ++ u8 qtype; ++ u8 tc; ++ u8 index; ++}; ++ ++struct dpni_rsp_get_taildrop { ++ /* cmd word 0 */ ++ __le64 pad0; ++ /* cmd word 1 */ ++ /* only least significant bit is relevant */ ++ u8 enable; ++ u8 pad1; ++ u8 units; ++ u8 pad2; ++ __le32 threshold; ++}; ++ ++#define DPNI_DEST_TYPE_SHIFT 0 ++#define DPNI_DEST_TYPE_SIZE 4 ++#define DPNI_CONG_UNITS_SHIFT 4 ++#define DPNI_CONG_UNITS_SIZE 2 ++ ++struct dpni_cmd_set_congestion_notification { ++ /* cmd word 0 */ ++ u8 qtype; ++ u8 tc; ++ u8 pad[6]; ++ /* cmd word 1 */ ++ u32 dest_id; ++ u16 notification_mode; ++ u8 dest_priority; ++ /* from LSB: dest_type: 4 units:2 */ ++ u8 type_units; ++ /* cmd word 2 */ ++ u64 message_iova; ++ /* cmd word 3 */ ++ u64 message_ctx; ++ /* cmd word 4 */ ++ u32 threshold_entry; ++ u32 threshold_exit; ++}; ++ ++#endif /* _FSL_DPNI_CMD_H */ +diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpni.c b/drivers/staging/fsl-dpaa2/ethernet/dpni.c +new file mode 100644 +index 00000000..3c23e4dc +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethernet/dpni.c +@@ -0,0 +1,1770 @@ ++/* Copyright 2013-2016 Freescale Semiconductor Inc. ++ * Copyright 2016 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#include "../../fsl-mc/include/mc-sys.h" ++#include "../../fsl-mc/include/mc-cmd.h" ++#include "dpni.h" ++#include "dpni-cmd.h" ++ ++/** ++ * dpni_prepare_key_cfg() - function prepare extract parameters ++ * @cfg: defining a full Key Generation profile (rule) ++ * @key_cfg_buf: Zeroed 256 bytes of memory before mapping it to DMA ++ * ++ * This function has to be called before the following functions: ++ * - dpni_set_rx_tc_dist() ++ * - dpni_set_qos_table() ++ */ ++int dpni_prepare_key_cfg(const struct dpkg_profile_cfg *cfg, u8 *key_cfg_buf) ++{ ++ int i, j; ++ struct dpni_ext_set_rx_tc_dist *dpni_ext; ++ struct dpni_dist_extract *extr; ++ ++ if (cfg->num_extracts > DPKG_MAX_NUM_OF_EXTRACTS) ++ return -EINVAL; ++ ++ dpni_ext = (struct dpni_ext_set_rx_tc_dist *)key_cfg_buf; ++ dpni_ext->num_extracts = cfg->num_extracts; ++ ++ for (i = 0; i < cfg->num_extracts; i++) { ++ extr = &dpni_ext->extracts[i]; ++ ++ switch (cfg->extracts[i].type) { ++ case DPKG_EXTRACT_FROM_HDR: ++ extr->prot = cfg->extracts[i].extract.from_hdr.prot; ++ dpni_set_field(extr->efh_type, EFH_TYPE, ++ cfg->extracts[i].extract.from_hdr.type); ++ extr->size = cfg->extracts[i].extract.from_hdr.size; ++ extr->offset = cfg->extracts[i].extract.from_hdr.offset; ++ extr->field = cpu_to_le32( ++ cfg->extracts[i].extract.from_hdr.field); ++ extr->hdr_index = ++ cfg->extracts[i].extract.from_hdr.hdr_index; ++ break; ++ case DPKG_EXTRACT_FROM_DATA: ++ extr->size = cfg->extracts[i].extract.from_data.size; ++ extr->offset = ++ cfg->extracts[i].extract.from_data.offset; ++ break; ++ case DPKG_EXTRACT_FROM_PARSE: ++ extr->size = cfg->extracts[i].extract.from_parse.size; ++ extr->offset = ++ cfg->extracts[i].extract.from_parse.offset; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ extr->num_of_byte_masks = cfg->extracts[i].num_of_byte_masks; ++ dpni_set_field(extr->extract_type, EXTRACT_TYPE, ++ cfg->extracts[i].type); ++ ++ for (j = 0; j < DPKG_NUM_OF_MASKS; j++) { ++ extr->masks[j].mask = cfg->extracts[i].masks[j].mask; ++ extr->masks[j].offset = ++ cfg->extracts[i].masks[j].offset; ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ * dpni_open() - Open a control session for the specified object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @dpni_id: DPNI unique ID ++ * @token: Returned token; use in subsequent API calls ++ * ++ * This function can be used to open a control session for an ++ * already created object; an object may have been declared in ++ * the DPL or by calling the dpni_create() function. ++ * This function returns a unique authentication token, ++ * associated with the specific object ID and the specific MC ++ * portal; this token must be used in all subsequent commands for ++ * this specific object. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpni_id, ++ u16 *token) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_open *cmd_params; ++ ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_OPEN, ++ cmd_flags, ++ 0); ++ cmd_params = (struct dpni_cmd_open *)cmd.params; ++ cmd_params->dpni_id = cpu_to_le32(dpni_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *token = mc_cmd_hdr_read_token(&cmd); ++ ++ return 0; ++} ++ ++/** ++ * dpni_close() - Close the control session of the object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * ++ * After this function is called, no further operations are ++ * allowed on the object without opening a new control session. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLOSE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_set_pools() - Set buffer pools configuration ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @cfg: Buffer pools configuration ++ * ++ * mandatory for DPNI operation ++ * warning:Allowed only when DPNI is disabled ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_set_pools(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const struct dpni_pools_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_set_pools *cmd_params; ++ int i; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_POOLS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_set_pools *)cmd.params; ++ cmd_params->num_dpbp = cfg->num_dpbp; ++ for (i = 0; i < DPNI_MAX_DPBP; i++) { ++ cmd_params->dpbp_id[i] = cpu_to_le32(cfg->pools[i].dpbp_id); ++ cmd_params->buffer_size[i] = ++ cpu_to_le16(cfg->pools[i].buffer_size); ++ cmd_params->backup_pool_mask |= ++ DPNI_BACKUP_POOL(cfg->pools[i].backup_pool, i); ++ } ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_enable() - Enable the DPNI, allow sending and receiving frames. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_ENABLE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_disable() - Disable the DPNI, stop sending and receiving frames. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_DISABLE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_is_enabled() - Check if the DPNI is enabled. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @en: Returns '1' if object is enabled; '0' otherwise ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_is_enabled(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int *en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_rsp_is_enabled *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_IS_ENABLED, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_is_enabled *)cmd.params; ++ *en = dpni_get_field(rsp_params->enabled, ENABLE); ++ ++ return 0; ++} ++ ++/** ++ * dpni_reset() - Reset the DPNI, returns the object to initial state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_reset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_RESET, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_set_irq_enable() - Set overall interrupt state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @irq_index: The interrupt index to configure ++ * @en: Interrupt state: - enable = 1, disable = 0 ++ * ++ * Allows GPP software to control when interrupts are generated. ++ * Each interrupt can have up to 32 causes. The enable/disable control's the ++ * overall interrupt state. if the interrupt is disabled no causes will cause ++ * an interrupt. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_set_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_set_irq_enable *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_IRQ_ENABLE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_set_irq_enable *)cmd.params; ++ dpni_set_field(cmd_params->enable, ENABLE, en); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_get_irq_enable() - Get overall interrupt state ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @irq_index: The interrupt index to configure ++ * @en: Returned interrupt state - enable = 1, disable = 0 ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_get_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 *en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_get_irq_enable *cmd_params; ++ struct dpni_rsp_get_irq_enable *rsp_params; ++ ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_IRQ_ENABLE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_get_irq_enable *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_get_irq_enable *)cmd.params; ++ *en = dpni_get_field(rsp_params->enabled, ENABLE); ++ ++ return 0; ++} ++ ++/** ++ * dpni_set_irq_mask() - Set interrupt mask. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @irq_index: The interrupt index to configure ++ * @mask: event mask to trigger interrupt; ++ * each bit: ++ * 0 = ignore event ++ * 1 = consider event for asserting IRQ ++ * ++ * Every interrupt can have up to 32 causes and the interrupt model supports ++ * masking/unmasking each cause independently ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_set_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 mask) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_set_irq_mask *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_IRQ_MASK, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_set_irq_mask *)cmd.params; ++ cmd_params->mask = cpu_to_le32(mask); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_get_irq_mask() - Get interrupt mask. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @irq_index: The interrupt index to configure ++ * @mask: Returned event mask to trigger interrupt ++ * ++ * Every interrupt can have up to 32 causes and the interrupt model supports ++ * masking/unmasking each cause independently ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_get_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *mask) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_get_irq_mask *cmd_params; ++ struct dpni_rsp_get_irq_mask *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_IRQ_MASK, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_get_irq_mask *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_get_irq_mask *)cmd.params; ++ *mask = le32_to_cpu(rsp_params->mask); ++ ++ return 0; ++} ++ ++/** ++ * dpni_get_irq_status() - Get the current status of any pending interrupts. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @irq_index: The interrupt index to configure ++ * @status: Returned interrupts status - one bit per cause: ++ * 0 = no interrupt pending ++ * 1 = interrupt pending ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_get_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *status) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_get_irq_status *cmd_params; ++ struct dpni_rsp_get_irq_status *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_IRQ_STATUS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_get_irq_status *)cmd.params; ++ cmd_params->status = cpu_to_le32(*status); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_get_irq_status *)cmd.params; ++ *status = le32_to_cpu(rsp_params->status); ++ ++ return 0; ++} ++ ++/** ++ * dpni_clear_irq_status() - Clear a pending interrupt's status ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @irq_index: The interrupt index to configure ++ * @status: bits to clear (W1C) - one bit per cause: ++ * 0 = don't change ++ * 1 = clear status bit ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_clear_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 status) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_clear_irq_status *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLEAR_IRQ_STATUS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_clear_irq_status *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ cmd_params->status = cpu_to_le32(status); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_get_attributes() - Retrieve DPNI attributes. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @attr: Object's attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpni_attr *attr) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_rsp_get_attr *rsp_params; ++ ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_ATTR, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_get_attr *)cmd.params; ++ attr->options = le32_to_cpu(rsp_params->options); ++ attr->num_queues = rsp_params->num_queues; ++ attr->num_tcs = rsp_params->num_tcs; ++ attr->mac_filter_entries = rsp_params->mac_filter_entries; ++ attr->vlan_filter_entries = rsp_params->vlan_filter_entries; ++ attr->qos_entries = rsp_params->qos_entries; ++ attr->fs_entries = le16_to_cpu(rsp_params->fs_entries); ++ attr->qos_key_size = rsp_params->qos_key_size; ++ attr->fs_key_size = rsp_params->fs_key_size; ++ attr->wriop_version = le16_to_cpu(rsp_params->wriop_version); ++ ++ return 0; ++} ++ ++/** ++ * dpni_set_errors_behavior() - Set errors behavior ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @cfg: Errors configuration ++ * ++ * this function may be called numerous times with different ++ * error masks ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_set_errors_behavior(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpni_error_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_set_errors_behavior *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_ERRORS_BEHAVIOR, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_set_errors_behavior *)cmd.params; ++ cmd_params->errors = cpu_to_le32(cfg->errors); ++ dpni_set_field(cmd_params->flags, ERROR_ACTION, cfg->error_action); ++ dpni_set_field(cmd_params->flags, FRAME_ANN, cfg->set_frame_annotation); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_get_buffer_layout() - Retrieve buffer layout attributes. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @qtype: Type of queue to retrieve configuration for ++ * @layout: Returns buffer layout attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_get_buffer_layout(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_queue_type qtype, ++ struct dpni_buffer_layout *layout) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_get_buffer_layout *cmd_params; ++ struct dpni_rsp_get_buffer_layout *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_BUFFER_LAYOUT, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_get_buffer_layout *)cmd.params; ++ cmd_params->qtype = qtype; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_get_buffer_layout *)cmd.params; ++ layout->pass_timestamp = dpni_get_field(rsp_params->flags, PASS_TS); ++ layout->pass_parser_result = dpni_get_field(rsp_params->flags, PASS_PR); ++ layout->pass_frame_status = dpni_get_field(rsp_params->flags, PASS_FS); ++ layout->private_data_size = le16_to_cpu(rsp_params->private_data_size); ++ layout->data_align = le16_to_cpu(rsp_params->data_align); ++ layout->data_head_room = le16_to_cpu(rsp_params->head_room); ++ layout->data_tail_room = le16_to_cpu(rsp_params->tail_room); ++ ++ return 0; ++} ++ ++/** ++ * dpni_set_buffer_layout() - Set buffer layout configuration. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @qtype: Type of queue this configuration applies to ++ * @layout: Buffer layout configuration ++ * ++ * Return: '0' on Success; Error code otherwise. ++ * ++ * @warning Allowed only when DPNI is disabled ++ */ ++int dpni_set_buffer_layout(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_queue_type qtype, ++ const struct dpni_buffer_layout *layout) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_set_buffer_layout *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_BUFFER_LAYOUT, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_set_buffer_layout *)cmd.params; ++ cmd_params->qtype = qtype; ++ cmd_params->options = cpu_to_le16(layout->options); ++ dpni_set_field(cmd_params->flags, PASS_TS, layout->pass_timestamp); ++ dpni_set_field(cmd_params->flags, PASS_PR, layout->pass_parser_result); ++ dpni_set_field(cmd_params->flags, PASS_FS, layout->pass_frame_status); ++ cmd_params->private_data_size = cpu_to_le16(layout->private_data_size); ++ cmd_params->data_align = cpu_to_le16(layout->data_align); ++ cmd_params->head_room = cpu_to_le16(layout->data_head_room); ++ cmd_params->tail_room = cpu_to_le16(layout->data_tail_room); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_set_offload() - Set DPNI offload configuration. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @type: Type of DPNI offload ++ * @config: Offload configuration. ++ * For checksum offloads, non-zero value enables the offload ++ * ++ * Return: '0' on Success; Error code otherwise. ++ * ++ * @warning Allowed only when DPNI is disabled ++ */ ++ ++int dpni_set_offload(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_offload type, ++ u32 config) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_set_offload *cmd_params; ++ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_OFFLOAD, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_set_offload *)cmd.params; ++ cmd_params->dpni_offload = type; ++ cmd_params->config = cpu_to_le32(config); ++ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++int dpni_get_offload(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_offload type, ++ u32 *config) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_get_offload *cmd_params; ++ struct dpni_rsp_get_offload *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_OFFLOAD, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_get_offload *)cmd.params; ++ cmd_params->dpni_offload = type; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_get_offload *)cmd.params; ++ *config = le32_to_cpu(rsp_params->config); ++ ++ return 0; ++} ++ ++/** ++ * dpni_get_qdid() - Get the Queuing Destination ID (QDID) that should be used ++ * for enqueue operations ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @qtype: Type of queue to receive QDID for ++ * @qdid: Returned virtual QDID value that should be used as an argument ++ * in all enqueue operations ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_get_qdid(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_queue_type qtype, ++ u16 *qdid) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_get_qdid *cmd_params; ++ struct dpni_rsp_get_qdid *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_QDID, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_get_qdid *)cmd.params; ++ cmd_params->qtype = qtype; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_get_qdid *)cmd.params; ++ *qdid = le16_to_cpu(rsp_params->qdid); ++ ++ return 0; ++} ++ ++/** ++ * dpni_get_tx_data_offset() - Get the Tx data offset (from start of buffer) ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @data_offset: Tx data offset (from start of buffer) ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_get_tx_data_offset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 *data_offset) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_rsp_get_tx_data_offset *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_DATA_OFFSET, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_get_tx_data_offset *)cmd.params; ++ *data_offset = le16_to_cpu(rsp_params->data_offset); ++ ++ return 0; ++} ++ ++/** ++ * dpni_set_link_cfg() - set the link configuration. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @cfg: Link configuration ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_set_link_cfg(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const struct dpni_link_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_set_link_cfg *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_LINK_CFG, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_set_link_cfg *)cmd.params; ++ cmd_params->rate = cpu_to_le32(cfg->rate); ++ cmd_params->options = cpu_to_le64(cfg->options); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_get_link_state() - Return the link state (either up or down) ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @state: Returned link state; ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_get_link_state(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpni_link_state *state) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_rsp_get_link_state *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_LINK_STATE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_get_link_state *)cmd.params; ++ state->up = dpni_get_field(rsp_params->flags, LINK_STATE); ++ state->rate = le32_to_cpu(rsp_params->rate); ++ state->options = le64_to_cpu(rsp_params->options); ++ ++ return 0; ++} ++ ++/** ++ * dpni_set_tx_shaping() - Set the transmit shaping ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @tx_shaper: tx shaping configuration ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_set_tx_shaping(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const struct dpni_tx_shaping_cfg *tx_shaper) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_set_tx_shaping *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_SHAPING, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_set_tx_shaping *)cmd.params; ++ cmd_params->max_burst_size = cpu_to_le16(tx_shaper->max_burst_size); ++ cmd_params->rate_limit = cpu_to_le32(tx_shaper->rate_limit); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_set_max_frame_length() - Set the maximum received frame length. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @max_frame_length: Maximum received frame length (in ++ * bytes); frame is discarded if its ++ * length exceeds this value ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_set_max_frame_length(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 max_frame_length) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_set_max_frame_length *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_MAX_FRAME_LENGTH, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_set_max_frame_length *)cmd.params; ++ cmd_params->max_frame_length = cpu_to_le16(max_frame_length); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_get_max_frame_length() - Get the maximum received frame length. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @max_frame_length: Maximum received frame length (in ++ * bytes); frame is discarded if its ++ * length exceeds this value ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_get_max_frame_length(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 *max_frame_length) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_rsp_get_max_frame_length *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_MAX_FRAME_LENGTH, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_get_max_frame_length *)cmd.params; ++ *max_frame_length = le16_to_cpu(rsp_params->max_frame_length); ++ ++ return 0; ++} ++ ++/** ++ * dpni_set_multicast_promisc() - Enable/disable multicast promiscuous mode ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @en: Set to '1' to enable; '0' to disable ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_set_multicast_promisc(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_set_multicast_promisc *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_MCAST_PROMISC, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_set_multicast_promisc *)cmd.params; ++ dpni_set_field(cmd_params->enable, ENABLE, en); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_get_multicast_promisc() - Get multicast promiscuous mode ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @en: Returns '1' if enabled; '0' otherwise ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_get_multicast_promisc(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int *en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_rsp_get_multicast_promisc *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_MCAST_PROMISC, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_get_multicast_promisc *)cmd.params; ++ *en = dpni_get_field(rsp_params->enabled, ENABLE); ++ ++ return 0; ++} ++ ++/** ++ * dpni_set_unicast_promisc() - Enable/disable unicast promiscuous mode ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @en: Set to '1' to enable; '0' to disable ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_set_unicast_promisc(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_set_unicast_promisc *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_UNICAST_PROMISC, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_set_unicast_promisc *)cmd.params; ++ dpni_set_field(cmd_params->enable, ENABLE, en); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_get_unicast_promisc() - Get unicast promiscuous mode ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @en: Returns '1' if enabled; '0' otherwise ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_get_unicast_promisc(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int *en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_rsp_get_unicast_promisc *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_UNICAST_PROMISC, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_get_unicast_promisc *)cmd.params; ++ *en = dpni_get_field(rsp_params->enabled, ENABLE); ++ ++ return 0; ++} ++ ++/** ++ * dpni_set_primary_mac_addr() - Set the primary MAC address ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @mac_addr: MAC address to set as primary address ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_set_primary_mac_addr(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const u8 mac_addr[6]) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_set_primary_mac_addr *cmd_params; ++ int i; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_PRIM_MAC, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_set_primary_mac_addr *)cmd.params; ++ for (i = 0; i < 6; i++) ++ cmd_params->mac_addr[i] = mac_addr[5 - i]; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_get_primary_mac_addr() - Get the primary MAC address ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @mac_addr: Returned MAC address ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_get_primary_mac_addr(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 mac_addr[6]) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_rsp_get_primary_mac_addr *rsp_params; ++ int i, err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_PRIM_MAC, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_get_primary_mac_addr *)cmd.params; ++ for (i = 0; i < 6; i++) ++ mac_addr[5 - i] = rsp_params->mac_addr[i]; ++ ++ return 0; ++} ++ ++/** ++ * dpni_get_port_mac_addr() - Retrieve MAC address associated to the physical ++ * port the DPNI is attached to ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @mac_addr: MAC address of the physical port, if any, otherwise 0 ++ * ++ * The primary MAC address is not cleared by this operation. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_get_port_mac_addr(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 mac_addr[6]) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_rsp_get_port_mac_addr *rsp_params; ++ int i, err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_PORT_MAC_ADDR, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_get_port_mac_addr *)cmd.params; ++ for (i = 0; i < 6; i++) ++ mac_addr[5 - i] = rsp_params->mac_addr[i]; ++ ++ return 0; ++} ++ ++/** ++ * dpni_add_mac_addr() - Add MAC address filter ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @mac_addr: MAC address to add ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_add_mac_addr(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const u8 mac_addr[6]) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_add_mac_addr *cmd_params; ++ int i; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_ADD_MAC_ADDR, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_add_mac_addr *)cmd.params; ++ for (i = 0; i < 6; i++) ++ cmd_params->mac_addr[i] = mac_addr[5 - i]; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_remove_mac_addr() - Remove MAC address filter ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @mac_addr: MAC address to remove ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_remove_mac_addr(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const u8 mac_addr[6]) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_remove_mac_addr *cmd_params; ++ int i; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_REMOVE_MAC_ADDR, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_remove_mac_addr *)cmd.params; ++ for (i = 0; i < 6; i++) ++ cmd_params->mac_addr[i] = mac_addr[5 - i]; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_clear_mac_filters() - Clear all unicast and/or multicast MAC filters ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @unicast: Set to '1' to clear unicast addresses ++ * @multicast: Set to '1' to clear multicast addresses ++ * ++ * The primary MAC address is not cleared by this operation. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_clear_mac_filters(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int unicast, ++ int multicast) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_clear_mac_filters *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLR_MAC_FILTERS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_clear_mac_filters *)cmd.params; ++ dpni_set_field(cmd_params->flags, UNICAST_FILTERS, unicast); ++ dpni_set_field(cmd_params->flags, MULTICAST_FILTERS, multicast); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_set_rx_tc_dist() - Set Rx traffic class distribution configuration ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @tc_id: Traffic class selection (0-7) ++ * @cfg: Traffic class distribution configuration ++ * ++ * warning: if 'dist_mode != DPNI_DIST_MODE_NONE', call dpni_prepare_key_cfg() ++ * first to prepare the key_cfg_iova parameter ++ * ++ * Return: '0' on Success; error code otherwise. ++ */ ++int dpni_set_rx_tc_dist(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 tc_id, ++ const struct dpni_rx_tc_dist_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_set_rx_tc_dist *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_RX_TC_DIST, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_set_rx_tc_dist *)cmd.params; ++ cmd_params->dist_size = cpu_to_le16(cfg->dist_size); ++ cmd_params->tc_id = tc_id; ++ dpni_set_field(cmd_params->flags, DIST_MODE, cfg->dist_mode); ++ dpni_set_field(cmd_params->flags, MISS_ACTION, cfg->fs_cfg.miss_action); ++ cmd_params->default_flow_id = cpu_to_le16(cfg->fs_cfg.default_flow_id); ++ cmd_params->key_cfg_iova = cpu_to_le64(cfg->key_cfg_iova); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_add_fs_entry() - Add Flow Steering entry for a specific traffic class ++ * (to select a flow ID) ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @tc_id: Traffic class selection (0-7) ++ * @index: Location in the QoS table where to insert the entry. ++ * Only relevant if MASKING is enabled for QoS ++ * classification on this DPNI, it is ignored for exact match. ++ * @cfg: Flow steering rule to add ++ * @action: Action to be taken as result of a classification hit ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_add_fs_entry(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 tc_id, ++ u16 index, ++ const struct dpni_rule_cfg *cfg, ++ const struct dpni_fs_action_cfg *action) ++{ ++ struct dpni_cmd_add_fs_entry *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_ADD_FS_ENT, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_add_fs_entry *)cmd.params; ++ cmd_params->tc_id = tc_id; ++ cmd_params->key_size = cfg->key_size; ++ cmd_params->index = cpu_to_le16(index); ++ cmd_params->key_iova = cpu_to_le64(cfg->key_iova); ++ cmd_params->mask_iova = cpu_to_le64(cfg->mask_iova); ++ cmd_params->options = cpu_to_le16(action->options); ++ cmd_params->flow_id = cpu_to_le16(action->flow_id); ++ cmd_params->flc = cpu_to_le64(action->flc); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_remove_fs_entry() - Remove Flow Steering entry from a specific ++ * traffic class ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @tc_id: Traffic class selection (0-7) ++ * @cfg: Flow steering rule to remove ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_remove_fs_entry(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 tc_id, ++ const struct dpni_rule_cfg *cfg) ++{ ++ struct dpni_cmd_remove_fs_entry *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_REMOVE_FS_ENT, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_remove_fs_entry *)cmd.params; ++ cmd_params->tc_id = tc_id; ++ cmd_params->key_size = cfg->key_size; ++ cmd_params->key_iova = cpu_to_le64(cfg->key_iova); ++ cmd_params->mask_iova = cpu_to_le64(cfg->mask_iova); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_set_congestion_notification() - Set traffic class congestion ++ * notification configuration ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @qtype: Type of queue - Rx, Tx and Tx confirm types are supported ++ * @tc_id: Traffic class selection (0-7) ++ * @cfg: congestion notification configuration ++ * ++ * Return: '0' on Success; error code otherwise. ++ */ ++int dpni_set_congestion_notification(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_queue_type qtype, ++ u8 tc_id, ++ const struct dpni_congestion_notification_cfg *cfg) ++{ ++ struct dpni_cmd_set_congestion_notification *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header( ++ DPNI_CMDID_SET_CONGESTION_NOTIFICATION, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_set_congestion_notification *)cmd.params; ++ cmd_params->qtype = qtype; ++ cmd_params->tc = tc_id; ++ cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id); ++ cmd_params->notification_mode = cpu_to_le16(cfg->notification_mode); ++ cmd_params->dest_priority = cfg->dest_cfg.priority; ++ dpni_set_field(cmd_params->type_units, DEST_TYPE, ++ cfg->dest_cfg.dest_type); ++ dpni_set_field(cmd_params->type_units, CONG_UNITS, cfg->units); ++ cmd_params->message_iova = cpu_to_le64(cfg->message_iova); ++ cmd_params->message_ctx = cpu_to_le64(cfg->message_ctx); ++ cmd_params->threshold_entry = cpu_to_le32(cfg->threshold_entry); ++ cmd_params->threshold_exit = cpu_to_le32(cfg->threshold_exit); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_set_queue() - Set queue parameters ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @qtype: Type of queue - all queue types are supported, although ++ * the command is ignored for Tx ++ * @tc: Traffic class, in range 0 to NUM_TCS - 1 ++ * @index: Selects the specific queue out of the set allocated for the ++ * same TC. Value must be in range 0 to NUM_QUEUES - 1 ++ * @options: A combination of DPNI_QUEUE_OPT_ values that control what ++ * configuration options are set on the queue ++ * @queue: Queue structure ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_set_queue(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_queue_type qtype, ++ u8 tc, ++ u8 index, ++ u8 options, ++ const struct dpni_queue *queue) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_set_queue *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_QUEUE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_set_queue *)cmd.params; ++ cmd_params->qtype = qtype; ++ cmd_params->tc = tc; ++ cmd_params->index = index; ++ cmd_params->options = options; ++ cmd_params->dest_id = cpu_to_le32(queue->destination.id); ++ cmd_params->dest_prio = queue->destination.priority; ++ dpni_set_field(cmd_params->flags, DEST_TYPE, queue->destination.type); ++ dpni_set_field(cmd_params->flags, STASH_CTRL, queue->flc.stash_control); ++ dpni_set_field(cmd_params->flags, HOLD_ACTIVE, ++ queue->destination.hold_active); ++ cmd_params->flc = cpu_to_le64(queue->flc.value); ++ cmd_params->user_context = cpu_to_le64(queue->user_context); ++ ++ /* send command to mc */ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_get_queue() - Get queue parameters ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @qtype: Type of queue - all queue types are supported ++ * @tc: Traffic class, in range 0 to NUM_TCS - 1 ++ * @index: Selects the specific queue out of the set allocated for the ++ * same TC. Value must be in range 0 to NUM_QUEUES - 1 ++ * @queue: Queue configuration structure ++ * @qid: Queue identification ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_get_queue(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_queue_type qtype, ++ u8 tc, ++ u8 index, ++ struct dpni_queue *queue, ++ struct dpni_queue_id *qid) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_get_queue *cmd_params; ++ struct dpni_rsp_get_queue *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_QUEUE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_get_queue *)cmd.params; ++ cmd_params->qtype = qtype; ++ cmd_params->tc = tc; ++ cmd_params->index = index; ++ ++ /* send command to mc */ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_get_queue *)cmd.params; ++ queue->destination.id = le32_to_cpu(rsp_params->dest_id); ++ queue->destination.priority = rsp_params->dest_prio; ++ queue->destination.type = dpni_get_field(rsp_params->flags, ++ DEST_TYPE); ++ queue->flc.stash_control = dpni_get_field(rsp_params->flags, ++ STASH_CTRL); ++ queue->destination.hold_active = dpni_get_field(rsp_params->flags, ++ HOLD_ACTIVE); ++ queue->flc.value = le64_to_cpu(rsp_params->flc); ++ queue->user_context = le64_to_cpu(rsp_params->user_context); ++ qid->fqid = le32_to_cpu(rsp_params->fqid); ++ qid->qdbin = le16_to_cpu(rsp_params->qdbin); ++ ++ return 0; ++} ++ ++/** ++ * dpni_get_statistics() - Get DPNI statistics ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @page: Selects the statistics page to retrieve, see ++ * DPNI_GET_STATISTICS output. Pages are numbered 0 to 2. ++ * @stat: Structure containing the statistics ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_get_statistics(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 page, ++ union dpni_statistics *stat) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_get_statistics *cmd_params; ++ struct dpni_rsp_get_statistics *rsp_params; ++ int i, err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_STATISTICS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_get_statistics *)cmd.params; ++ cmd_params->page_number = page; ++ ++ /* send command to mc */ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_get_statistics *)cmd.params; ++ for (i = 0; i < DPNI_STATISTICS_CNT; i++) ++ stat->raw.counter[i] = le64_to_cpu(rsp_params->counter[i]); ++ ++ return 0; ++} ++ ++/** ++ * dpni_reset_statistics() - Clears DPNI statistics ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_reset_statistics(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_RESET_STATISTICS, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_set_taildrop() - Set taildrop per queue or TC ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @cg_point: Congestion point ++ * @q_type: Queue type on which the taildrop is configured. ++ * Only Rx queues are supported for now ++ * @tc: Traffic class to apply this taildrop to ++ * @q_index: Index of the queue if the DPNI supports multiple queues for ++ * traffic distribution. Ignored if CONGESTION_POINT is not 0. ++ * @taildrop: Taildrop structure ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_set_taildrop(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_congestion_point cg_point, ++ enum dpni_queue_type qtype, ++ u8 tc, ++ u8 index, ++ struct dpni_taildrop *taildrop) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_set_taildrop *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TAILDROP, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_set_taildrop *)cmd.params; ++ cmd_params->congestion_point = cg_point; ++ cmd_params->qtype = qtype; ++ cmd_params->tc = tc; ++ cmd_params->index = index; ++ dpni_set_field(cmd_params->enable, ENABLE, taildrop->enable); ++ cmd_params->units = taildrop->units; ++ cmd_params->threshold = cpu_to_le32(taildrop->threshold); ++ ++ /* send command to mc */ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpni_get_taildrop() - Get taildrop information ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPNI object ++ * @cg_point: Congestion point ++ * @q_type: Queue type on which the taildrop is configured. ++ * Only Rx queues are supported for now ++ * @tc: Traffic class to apply this taildrop to ++ * @q_index: Index of the queue if the DPNI supports multiple queues for ++ * traffic distribution. Ignored if CONGESTION_POINT is not 0. ++ * @taildrop: Taildrop structure ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpni_get_taildrop(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_congestion_point cg_point, ++ enum dpni_queue_type qtype, ++ u8 tc, ++ u8 index, ++ struct dpni_taildrop *taildrop) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpni_cmd_get_taildrop *cmd_params; ++ struct dpni_rsp_get_taildrop *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TAILDROP, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpni_cmd_get_taildrop *)cmd.params; ++ cmd_params->congestion_point = cg_point; ++ cmd_params->qtype = qtype; ++ cmd_params->tc = tc; ++ cmd_params->index = index; ++ ++ /* send command to mc */ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpni_rsp_get_taildrop *)cmd.params; ++ taildrop->enable = dpni_get_field(rsp_params->enable, ENABLE); ++ taildrop->units = rsp_params->units; ++ taildrop->threshold = le32_to_cpu(rsp_params->threshold); ++ ++ return 0; ++} +diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpni.h b/drivers/staging/fsl-dpaa2/ethernet/dpni.h +new file mode 100644 +index 00000000..600c3574 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethernet/dpni.h +@@ -0,0 +1,989 @@ ++/* Copyright 2013-2016 Freescale Semiconductor Inc. ++ * Copyright 2016 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef __FSL_DPNI_H ++#define __FSL_DPNI_H ++ ++#include "dpkg.h" ++ ++struct fsl_mc_io; ++ ++/** ++ * Data Path Network Interface API ++ * Contains initialization APIs and runtime control APIs for DPNI ++ */ ++ ++/** General DPNI macros */ ++ ++/** ++ * Maximum number of traffic classes ++ */ ++#define DPNI_MAX_TC 8 ++/** ++ * Maximum number of buffer pools per DPNI ++ */ ++#define DPNI_MAX_DPBP 8 ++ ++/** ++ * All traffic classes considered; see dpni_set_queue() ++ */ ++#define DPNI_ALL_TCS (u8)(-1) ++/** ++ * All flows within traffic class considered; see dpni_set_queue() ++ */ ++#define DPNI_ALL_TC_FLOWS (u16)(-1) ++/** ++ * Generate new flow ID; see dpni_set_queue() ++ */ ++#define DPNI_NEW_FLOW_ID (u16)(-1) ++ ++/** ++ * Tx traffic is always released to a buffer pool on transmit, there are no ++ * resources allocated to have the frames confirmed back to the source after ++ * transmission. ++ */ ++#define DPNI_OPT_TX_FRM_RELEASE 0x000001 ++/** ++ * Disables support for MAC address filtering for addresses other than primary ++ * MAC address. This affects both unicast and multicast. Promiscuous mode can ++ * still be enabled/disabled for both unicast and multicast. If promiscuous mode ++ * is disabled, only traffic matching the primary MAC address will be accepted. ++ */ ++#define DPNI_OPT_NO_MAC_FILTER 0x000002 ++/** ++ * Allocate policers for this DPNI. They can be used to rate-limit traffic per ++ * traffic class (TC) basis. ++ */ ++#define DPNI_OPT_HAS_POLICING 0x000004 ++/** ++ * Congestion can be managed in several ways, allowing the buffer pool to ++ * deplete on ingress, taildrop on each queue or use congestion groups for sets ++ * of queues. If set, it configures a single congestion groups across all TCs. ++ * If reset, a congestion group is allocated for each TC. Only relevant if the ++ * DPNI has multiple traffic classes. ++ */ ++#define DPNI_OPT_SHARED_CONGESTION 0x000008 ++/** ++ * Enables TCAM for Flow Steering and QoS look-ups. If not specified, all ++ * look-ups are exact match. Note that TCAM is not available on LS1088 and its ++ * variants. Setting this bit on these SoCs will trigger an error. ++ */ ++#define DPNI_OPT_HAS_KEY_MASKING 0x000010 ++/** ++ * Disables the flow steering table. ++ */ ++#define DPNI_OPT_NO_FS 0x000020 ++ ++int dpni_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpni_id, ++ u16 *token); ++ ++int dpni_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++/** ++ * struct dpni_pools_cfg - Structure representing buffer pools configuration ++ * @num_dpbp: Number of DPBPs ++ * @pools: Array of buffer pools parameters; The number of valid entries ++ * must match 'num_dpbp' value ++ */ ++struct dpni_pools_cfg { ++ u8 num_dpbp; ++ /** ++ * struct pools - Buffer pools parameters ++ * @dpbp_id: DPBP object ID ++ * @buffer_size: Buffer size ++ * @backup_pool: Backup pool ++ */ ++ struct { ++ int dpbp_id; ++ u16 buffer_size; ++ int backup_pool; ++ } pools[DPNI_MAX_DPBP]; ++}; ++ ++int dpni_set_pools(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const struct dpni_pools_cfg *cfg); ++ ++int dpni_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpni_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpni_is_enabled(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int *en); ++ ++int dpni_reset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++/** ++ * DPNI IRQ Index and Events ++ */ ++ ++/** ++ * IRQ index ++ */ ++#define DPNI_IRQ_INDEX 0 ++/** ++ * IRQ event - indicates a change in link state ++ */ ++#define DPNI_IRQ_EVENT_LINK_CHANGED 0x00000001 ++ ++int dpni_set_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 en); ++ ++int dpni_get_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 *en); ++ ++int dpni_set_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 mask); ++ ++int dpni_get_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *mask); ++ ++int dpni_get_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *status); ++ ++int dpni_clear_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 status); ++ ++/** ++ * struct dpni_attr - Structure representing DPNI attributes ++ * @options: Any combination of the following options: ++ * DPNI_OPT_TX_FRM_RELEASE ++ * DPNI_OPT_NO_MAC_FILTER ++ * DPNI_OPT_HAS_POLICING ++ * DPNI_OPT_SHARED_CONGESTION ++ * DPNI_OPT_HAS_KEY_MASKING ++ * DPNI_OPT_NO_FS ++ * @num_queues: Number of Tx and Rx queues used for traffic distribution. ++ * @num_tcs: Number of traffic classes (TCs), reserved for the DPNI. ++ * @mac_filter_entries: Number of entries in the MAC address filtering table. ++ * @vlan_filter_entries: Number of entries in the VLAN address filtering table. ++ * @qos_entries: Number of entries in the QoS classification table. ++ * @fs_entries: Number of entries in the flow steering table. ++ * @qos_key_size: Size, in bytes, of the QoS look-up key. Defining a key larger ++ * than this when adding QoS entries will result in an error. ++ * @fs_key_size: Size, in bytes, of the flow steering look-up key. Defining a ++ * key larger than this when composing the hash + FS key will ++ * result in an error. ++ * @wriop_version: Version of WRIOP HW block. The 3 version values are stored ++ * on 6, 5, 5 bits respectively. ++ */ ++struct dpni_attr { ++ u32 options; ++ u8 num_queues; ++ u8 num_tcs; ++ u8 mac_filter_entries; ++ u8 vlan_filter_entries; ++ u8 qos_entries; ++ u16 fs_entries; ++ u8 qos_key_size; ++ u8 fs_key_size; ++ u16 wriop_version; ++}; ++ ++int dpni_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpni_attr *attr); ++ ++/** ++ * DPNI errors ++ */ ++ ++/** ++ * Extract out of frame header error ++ */ ++#define DPNI_ERROR_EOFHE 0x00020000 ++/** ++ * Frame length error ++ */ ++#define DPNI_ERROR_FLE 0x00002000 ++/** ++ * Frame physical error ++ */ ++#define DPNI_ERROR_FPE 0x00001000 ++/** ++ * Parsing header error ++ */ ++#define DPNI_ERROR_PHE 0x00000020 ++/** ++ * Parser L3 checksum error ++ */ ++#define DPNI_ERROR_L3CE 0x00000004 ++/** ++ * Parser L3 checksum error ++ */ ++#define DPNI_ERROR_L4CE 0x00000001 ++ ++/** ++ * enum dpni_error_action - Defines DPNI behavior for errors ++ * @DPNI_ERROR_ACTION_DISCARD: Discard the frame ++ * @DPNI_ERROR_ACTION_CONTINUE: Continue with the normal flow ++ * @DPNI_ERROR_ACTION_SEND_TO_ERROR_QUEUE: Send the frame to the error queue ++ */ ++enum dpni_error_action { ++ DPNI_ERROR_ACTION_DISCARD = 0, ++ DPNI_ERROR_ACTION_CONTINUE = 1, ++ DPNI_ERROR_ACTION_SEND_TO_ERROR_QUEUE = 2 ++}; ++ ++/** ++ * struct dpni_error_cfg - Structure representing DPNI errors treatment ++ * @errors: Errors mask; use 'DPNI_ERROR__ ++ * @error_action: The desired action for the errors mask ++ * @set_frame_annotation: Set to '1' to mark the errors in frame annotation ++ * status (FAS); relevant only for the non-discard action ++ */ ++struct dpni_error_cfg { ++ u32 errors; ++ enum dpni_error_action error_action; ++ int set_frame_annotation; ++}; ++ ++int dpni_set_errors_behavior(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpni_error_cfg *cfg); ++ ++/** ++ * DPNI buffer layout modification options ++ */ ++ ++/** ++ * Select to modify the time-stamp setting ++ */ ++#define DPNI_BUF_LAYOUT_OPT_TIMESTAMP 0x00000001 ++/** ++ * Select to modify the parser-result setting; not applicable for Tx ++ */ ++#define DPNI_BUF_LAYOUT_OPT_PARSER_RESULT 0x00000002 ++/** ++ * Select to modify the frame-status setting ++ */ ++#define DPNI_BUF_LAYOUT_OPT_FRAME_STATUS 0x00000004 ++/** ++ * Select to modify the private-data-size setting ++ */ ++#define DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE 0x00000008 ++/** ++ * Select to modify the data-alignment setting ++ */ ++#define DPNI_BUF_LAYOUT_OPT_DATA_ALIGN 0x00000010 ++/** ++ * Select to modify the data-head-room setting ++ */ ++#define DPNI_BUF_LAYOUT_OPT_DATA_HEAD_ROOM 0x00000020 ++/** ++ * Select to modify the data-tail-room setting ++ */ ++#define DPNI_BUF_LAYOUT_OPT_DATA_TAIL_ROOM 0x00000040 ++ ++/** ++ * struct dpni_buffer_layout - Structure representing DPNI buffer layout ++ * @options: Flags representing the suggested modifications to the buffer ++ * layout; Use any combination of 'DPNI_BUF_LAYOUT_OPT_' flags ++ * @pass_timestamp: Pass timestamp value ++ * @pass_parser_result: Pass parser results ++ * @pass_frame_status: Pass frame status ++ * @private_data_size: Size kept for private data (in bytes) ++ * @data_align: Data alignment ++ * @data_head_room: Data head room ++ * @data_tail_room: Data tail room ++ */ ++struct dpni_buffer_layout { ++ u32 options; ++ int pass_timestamp; ++ int pass_parser_result; ++ int pass_frame_status; ++ u16 private_data_size; ++ u16 data_align; ++ u16 data_head_room; ++ u16 data_tail_room; ++}; ++ ++/** ++ * enum dpni_queue_type - Identifies a type of queue targeted by the command ++ * @DPNI_QUEUE_RX: Rx queue ++ * @DPNI_QUEUE_TX: Tx queue ++ * @DPNI_QUEUE_TX_CONFIRM: Tx confirmation queue ++ * @DPNI_QUEUE_RX_ERR: Rx error queue ++ */enum dpni_queue_type { ++ DPNI_QUEUE_RX, ++ DPNI_QUEUE_TX, ++ DPNI_QUEUE_TX_CONFIRM, ++ DPNI_QUEUE_RX_ERR, ++}; ++ ++int dpni_get_buffer_layout(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_queue_type qtype, ++ struct dpni_buffer_layout *layout); ++ ++int dpni_set_buffer_layout(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_queue_type qtype, ++ const struct dpni_buffer_layout *layout); ++ ++/** ++ * enum dpni_offload - Identifies a type of offload targeted by the command ++ * @DPNI_OFF_RX_L3_CSUM: Rx L3 checksum validation ++ * @DPNI_OFF_RX_L4_CSUM: Rx L4 checksum validation ++ * @DPNI_OFF_TX_L3_CSUM: Tx L3 checksum generation ++ * @DPNI_OFF_TX_L4_CSUM: Tx L4 checksum generation ++ */ ++enum dpni_offload { ++ DPNI_OFF_RX_L3_CSUM, ++ DPNI_OFF_RX_L4_CSUM, ++ DPNI_OFF_TX_L3_CSUM, ++ DPNI_OFF_TX_L4_CSUM, ++}; ++ ++int dpni_set_offload(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_offload type, ++ u32 config); ++ ++int dpni_get_offload(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_offload type, ++ u32 *config); ++ ++int dpni_get_qdid(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_queue_type qtype, ++ u16 *qdid); ++ ++int dpni_get_tx_data_offset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 *data_offset); ++ ++#define DPNI_STATISTICS_CNT 7 ++ ++union dpni_statistics { ++ /** ++ * struct page_0 - Page_0 statistics structure ++ * @ingress_all_frames: Ingress frame count ++ * @ingress_all_bytes: Ingress byte count ++ * @ingress_multicast_frames: Ingress multicast frame count ++ * @ingress_multicast_bytes: Ingress multicast byte count ++ * @ingress_broadcast_frames: Ingress broadcast frame count ++ * @ingress_broadcast_bytes: Ingress broadcast byte count ++ */ ++ struct { ++ u64 ingress_all_frames; ++ u64 ingress_all_bytes; ++ u64 ingress_multicast_frames; ++ u64 ingress_multicast_bytes; ++ u64 ingress_broadcast_frames; ++ u64 ingress_broadcast_bytes; ++ } page_0; ++ /** ++ * struct page_1 - Page_1 statistics structure ++ * @egress_all_frames: Egress frame count ++ * @egress_all_bytes: Egress byte count ++ * @egress_multicast_frames: Egress multicast frame count ++ * @egress_multicast_bytes: Egress multicast byte count ++ * @egress_broadcast_frames: Egress broadcast frame count ++ * @egress_broadcast_bytes: Egress broadcast byte count ++ */ ++ struct { ++ u64 egress_all_frames; ++ u64 egress_all_bytes; ++ u64 egress_multicast_frames; ++ u64 egress_multicast_bytes; ++ u64 egress_broadcast_frames; ++ u64 egress_broadcast_bytes; ++ } page_1; ++ /** ++ * struct page_2 - Page_2 statistics structure ++ * @ingress_filtered_frames: Ingress filtered frame count ++ * @ingress_discarded_frames: Ingress discarded frame count ++ * @ingress_nobuffer_discards: Ingress discarded frame count ++ * due to lack of buffers ++ * @egress_discarded_frames: Egress discarded frame count ++ * @egress_confirmed_frames: Egress confirmed frame count ++ */ ++ struct { ++ u64 ingress_filtered_frames; ++ u64 ingress_discarded_frames; ++ u64 ingress_nobuffer_discards; ++ u64 egress_discarded_frames; ++ u64 egress_confirmed_frames; ++ } page_2; ++ /** ++ * struct raw - raw statistics structure ++ */ ++ struct { ++ u64 counter[DPNI_STATISTICS_CNT]; ++ } raw; ++}; ++ ++int dpni_get_statistics(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 page, ++ union dpni_statistics *stat); ++ ++int dpni_reset_statistics(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++/** ++ * Enable auto-negotiation ++ */ ++#define DPNI_LINK_OPT_AUTONEG 0x0000000000000001ULL ++/** ++ * Enable half-duplex mode ++ */ ++#define DPNI_LINK_OPT_HALF_DUPLEX 0x0000000000000002ULL ++/** ++ * Enable pause frames ++ */ ++#define DPNI_LINK_OPT_PAUSE 0x0000000000000004ULL ++/** ++ * Enable a-symmetric pause frames ++ */ ++#define DPNI_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL ++ ++/** ++ * struct - Structure representing DPNI link configuration ++ * @rate: Rate ++ * @options: Mask of available options; use 'DPNI_LINK_OPT_' values ++ */ ++struct dpni_link_cfg { ++ u32 rate; ++ u64 options; ++}; ++ ++int dpni_set_link_cfg(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const struct dpni_link_cfg *cfg); ++ ++/** ++ * struct dpni_link_state - Structure representing DPNI link state ++ * @rate: Rate ++ * @options: Mask of available options; use 'DPNI_LINK_OPT_' values ++ * @up: Link state; '0' for down, '1' for up ++ */ ++struct dpni_link_state { ++ u32 rate; ++ u64 options; ++ int up; ++}; ++ ++int dpni_get_link_state(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpni_link_state *state); ++ ++/** ++ * struct dpni_tx_shaping - Structure representing DPNI tx shaping configuration ++ * @rate_limit: rate in Mbps ++ * @max_burst_size: burst size in bytes (up to 64KB) ++ */ ++struct dpni_tx_shaping_cfg { ++ u32 rate_limit; ++ u16 max_burst_size; ++}; ++ ++int dpni_set_tx_shaping(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const struct dpni_tx_shaping_cfg *tx_shaper); ++ ++int dpni_set_max_frame_length(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 max_frame_length); ++ ++int dpni_get_max_frame_length(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 *max_frame_length); ++ ++int dpni_set_multicast_promisc(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int en); ++ ++int dpni_get_multicast_promisc(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int *en); ++ ++int dpni_set_unicast_promisc(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int en); ++ ++int dpni_get_unicast_promisc(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int *en); ++ ++int dpni_set_primary_mac_addr(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const u8 mac_addr[6]); ++ ++int dpni_get_primary_mac_addr(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 mac_addr[6]); ++ ++int dpni_get_port_mac_addr(struct fsl_mc_io *mc_io, ++ u32 cm_flags, ++ u16 token, ++ u8 mac_addr[6]); ++ ++int dpni_add_mac_addr(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const u8 mac_addr[6]); ++ ++int dpni_remove_mac_addr(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const u8 mac_addr[6]); ++ ++int dpni_clear_mac_filters(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int unicast, ++ int multicast); ++ ++/** ++ * enum dpni_dist_mode - DPNI distribution mode ++ * @DPNI_DIST_MODE_NONE: No distribution ++ * @DPNI_DIST_MODE_HASH: Use hash distribution; only relevant if ++ * the 'DPNI_OPT_DIST_HASH' option was set at DPNI creation ++ * @DPNI_DIST_MODE_FS: Use explicit flow steering; only relevant if ++ * the 'DPNI_OPT_DIST_FS' option was set at DPNI creation ++ */ ++enum dpni_dist_mode { ++ DPNI_DIST_MODE_NONE = 0, ++ DPNI_DIST_MODE_HASH = 1, ++ DPNI_DIST_MODE_FS = 2 ++}; ++ ++/** ++ * enum dpni_fs_miss_action - DPNI Flow Steering miss action ++ * @DPNI_FS_MISS_DROP: In case of no-match, drop the frame ++ * @DPNI_FS_MISS_EXPLICIT_FLOWID: In case of no-match, use explicit flow-id ++ * @DPNI_FS_MISS_HASH: In case of no-match, distribute using hash ++ */ ++enum dpni_fs_miss_action { ++ DPNI_FS_MISS_DROP = 0, ++ DPNI_FS_MISS_EXPLICIT_FLOWID = 1, ++ DPNI_FS_MISS_HASH = 2 ++}; ++ ++/** ++ * struct dpni_fs_tbl_cfg - Flow Steering table configuration ++ * @miss_action: Miss action selection ++ * @default_flow_id: Used when 'miss_action = DPNI_FS_MISS_EXPLICIT_FLOWID' ++ */ ++struct dpni_fs_tbl_cfg { ++ enum dpni_fs_miss_action miss_action; ++ u16 default_flow_id; ++}; ++ ++int dpni_prepare_key_cfg(const struct dpkg_profile_cfg *cfg, ++ u8 *key_cfg_buf); ++ ++/** ++ * struct dpni_rx_tc_dist_cfg - Rx traffic class distribution configuration ++ * @dist_size: Set the distribution size; ++ * supported values: 1,2,3,4,6,7,8,12,14,16,24,28,32,48,56,64,96, ++ * 112,128,192,224,256,384,448,512,768,896,1024 ++ * @dist_mode: Distribution mode ++ * @key_cfg_iova: I/O virtual address of 256 bytes DMA-able memory filled with ++ * the extractions to be used for the distribution key by calling ++ * dpni_prepare_key_cfg() relevant only when ++ * 'dist_mode != DPNI_DIST_MODE_NONE', otherwise it can be '0' ++ * @fs_cfg: Flow Steering table configuration; only relevant if ++ * 'dist_mode = DPNI_DIST_MODE_FS' ++ */ ++struct dpni_rx_tc_dist_cfg { ++ u16 dist_size; ++ enum dpni_dist_mode dist_mode; ++ u64 key_cfg_iova; ++ struct dpni_fs_tbl_cfg fs_cfg; ++}; ++ ++int dpni_set_rx_tc_dist(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 tc_id, ++ const struct dpni_rx_tc_dist_cfg *cfg); ++ ++/** ++ * enum dpni_dest - DPNI destination types ++ * @DPNI_DEST_NONE: Unassigned destination; The queue is set in parked mode and ++ * does not generate FQDAN notifications; user is expected to ++ * dequeue from the queue based on polling or other user-defined ++ * method ++ * @DPNI_DEST_DPIO: The queue is set in schedule mode and generates FQDAN ++ * notifications to the specified DPIO; user is expected to dequeue ++ * from the queue only after notification is received ++ * @DPNI_DEST_DPCON: The queue is set in schedule mode and does not generate ++ * FQDAN notifications, but is connected to the specified DPCON ++ * object; user is expected to dequeue from the DPCON channel ++ */ ++enum dpni_dest { ++ DPNI_DEST_NONE = 0, ++ DPNI_DEST_DPIO = 1, ++ DPNI_DEST_DPCON = 2 ++}; ++ ++/** ++ * struct dpni_queue - Queue structure ++ * @user_context: User data, presented to the user along with any frames from ++ * this queue. Not relevant for Tx queues. ++ */ ++struct dpni_queue { ++/** ++ * struct destination - Destination structure ++ * @id: ID of the destination, only relevant if DEST_TYPE is > 0. ++ * Identifies either a DPIO or a DPCON object. Not relevant for ++ * Tx queues. ++ * @type: May be one of the following: ++ * 0 - No destination, queue can be manually queried, but will not ++ * push traffic or notifications to a DPIO; ++ * 1 - The destination is a DPIO. When traffic becomes available in ++ * the queue a FQDAN (FQ data available notification) will be ++ * generated to selected DPIO; ++ * 2 - The destination is a DPCON. The queue is associated with a ++ * DPCON object for the purpose of scheduling between multiple ++ * queues. The DPCON may be independently configured to ++ * generate notifications. Not relevant for Tx queues. ++ * @hold_active: Hold active, maintains a queue scheduled for longer ++ * in a DPIO during dequeue to reduce spread of traffic. ++ * Only relevant if queues are not affined to a single DPIO. ++ */ ++ struct { ++ u16 id; ++ enum dpni_dest type; ++ char hold_active; ++ u8 priority; ++ } destination; ++ u64 user_context; ++ struct { ++ u64 value; ++ char stash_control; ++ } flc; ++}; ++ ++/** ++ * struct dpni_queue_id - Queue identification, used for enqueue commands ++ * or queue control ++ * @fqid: FQID used for enqueueing to and/or configuration of this specific FQ ++ * @qdbin: Queueing bin, used to enqueue using QDID, DQBIN, QPRI. Only relevant ++ * for Tx queues. ++ */ ++struct dpni_queue_id { ++ u32 fqid; ++ u16 qdbin; ++}; ++ ++/** ++ * Set User Context ++ */ ++#define DPNI_QUEUE_OPT_USER_CTX 0x00000001 ++#define DPNI_QUEUE_OPT_DEST 0x00000002 ++#define DPNI_QUEUE_OPT_FLC 0x00000004 ++#define DPNI_QUEUE_OPT_HOLD_ACTIVE 0x00000008 ++ ++int dpni_set_queue(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_queue_type qtype, ++ u8 tc, ++ u8 index, ++ u8 options, ++ const struct dpni_queue *queue); ++ ++int dpni_get_queue(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_queue_type qtype, ++ u8 tc, ++ u8 index, ++ struct dpni_queue *queue, ++ struct dpni_queue_id *qid); ++ ++/** ++ * enum dpni_congestion_unit - DPNI congestion units ++ * @DPNI_CONGESTION_UNIT_BYTES: bytes units ++ * @DPNI_CONGESTION_UNIT_FRAMES: frames units ++ */ ++enum dpni_congestion_unit { ++ DPNI_CONGESTION_UNIT_BYTES = 0, ++ DPNI_CONGESTION_UNIT_FRAMES ++}; ++ ++/** ++ * enum dpni_congestion_point - Structure representing congestion point ++ * @DPNI_CP_QUEUE: Set taildrop per queue, identified by QUEUE_TYPE, TC and ++ * QUEUE_INDEX ++ * @DPNI_CP_GROUP: Set taildrop per queue group. Depending on options used to ++ * define the DPNI this can be either per TC (default) or per ++ * interface (DPNI_OPT_SHARED_CONGESTION set at DPNI create). ++ * QUEUE_INDEX is ignored if this type is used. ++ */ ++enum dpni_congestion_point { ++ DPNI_CP_QUEUE, ++ DPNI_CP_GROUP, ++}; ++ ++/** ++ * struct dpni_dest_cfg - Structure representing DPNI destination parameters ++ * @dest_type: Destination type ++ * @dest_id: Either DPIO ID or DPCON ID, depending on the destination type ++ * @priority: Priority selection within the DPIO or DPCON channel; valid values ++ * are 0-1 or 0-7, depending on the number of priorities in that ++ * channel; not relevant for 'DPNI_DEST_NONE' option ++ */ ++struct dpni_dest_cfg { ++ enum dpni_dest dest_type; ++ int dest_id; ++ u8 priority; ++}; ++ ++/* DPNI congestion options */ ++ ++/** ++ * CSCN message is written to message_iova once entering a ++ * congestion state (see 'threshold_entry') ++ */ ++#define DPNI_CONG_OPT_WRITE_MEM_ON_ENTER 0x00000001 ++/** ++ * CSCN message is written to message_iova once exiting a ++ * congestion state (see 'threshold_exit') ++ */ ++#define DPNI_CONG_OPT_WRITE_MEM_ON_EXIT 0x00000002 ++/** ++ * CSCN write will attempt to allocate into a cache (coherent write); ++ * valid only if 'DPNI_CONG_OPT_WRITE_MEM_' is selected ++ */ ++#define DPNI_CONG_OPT_COHERENT_WRITE 0x00000004 ++/** ++ * if 'dest_cfg.dest_type != DPNI_DEST_NONE' CSCN message is sent to ++ * DPIO/DPCON's WQ channel once entering a congestion state ++ * (see 'threshold_entry') ++ */ ++#define DPNI_CONG_OPT_NOTIFY_DEST_ON_ENTER 0x00000008 ++/** ++ * if 'dest_cfg.dest_type != DPNI_DEST_NONE' CSCN message is sent to ++ * DPIO/DPCON's WQ channel once exiting a congestion state ++ * (see 'threshold_exit') ++ */ ++#define DPNI_CONG_OPT_NOTIFY_DEST_ON_EXIT 0x00000010 ++/** ++ * if 'dest_cfg.dest_type != DPNI_DEST_NONE' when the CSCN is written to the ++ * sw-portal's DQRR, the DQRI interrupt is asserted immediately (if enabled) ++ */ ++#define DPNI_CONG_OPT_INTR_COALESCING_DISABLED 0x00000020 ++ ++/** ++ * struct dpni_congestion_notification_cfg - congestion notification ++ * configuration ++ * @units: units type ++ * @threshold_entry: above this threshold we enter a congestion state. ++ * set it to '0' to disable it ++ * @threshold_exit: below this threshold we exit the congestion state. ++ * @message_ctx: The context that will be part of the CSCN message ++ * @message_iova: I/O virtual address (must be in DMA-able memory), ++ * must be 16B aligned; valid only if 'DPNI_CONG_OPT_WRITE_MEM_' is ++ * contained in 'options' ++ * @dest_cfg: CSCN can be send to either DPIO or DPCON WQ channel ++ * @notification_mode: Mask of available options; use 'DPNI_CONG_OPT_' values ++ */ ++ ++struct dpni_congestion_notification_cfg { ++ enum dpni_congestion_unit units; ++ u32 threshold_entry; ++ u32 threshold_exit; ++ u64 message_ctx; ++ u64 message_iova; ++ struct dpni_dest_cfg dest_cfg; ++ u16 notification_mode; ++}; ++ ++int dpni_set_congestion_notification(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_queue_type qtype, ++ u8 tc_id, ++ const struct dpni_congestion_notification_cfg *cfg); ++ ++/** ++ * struct dpni_taildrop - Structure representing the taildrop ++ * @enable: Indicates whether the taildrop is active or not. ++ * @units: Indicates the unit of THRESHOLD. Queue taildrop only supports ++ * byte units, this field is ignored and assumed = 0 if ++ * CONGESTION_POINT is 0. ++ * @threshold: Threshold value, in units identified by UNITS field. Value 0 ++ * cannot be used as a valid taildrop threshold, THRESHOLD must ++ * be > 0 if the taildrop is enabled. ++ */ ++struct dpni_taildrop { ++ char enable; ++ enum dpni_congestion_unit units; ++ u32 threshold; ++}; ++ ++int dpni_set_taildrop(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_congestion_point cg_point, ++ enum dpni_queue_type q_type, ++ u8 tc, ++ u8 q_index, ++ struct dpni_taildrop *taildrop); ++ ++int dpni_get_taildrop(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpni_congestion_point cg_point, ++ enum dpni_queue_type q_type, ++ u8 tc, ++ u8 q_index, ++ struct dpni_taildrop *taildrop); ++ ++/** ++ * struct dpni_rule_cfg - Rule configuration for table lookup ++ * @key_iova: I/O virtual address of the key (must be in DMA-able memory) ++ * @mask_iova: I/O virtual address of the mask (must be in DMA-able memory) ++ * @key_size: key and mask size (in bytes) ++ */ ++struct dpni_rule_cfg { ++ u64 key_iova; ++ u64 mask_iova; ++ u8 key_size; ++}; ++ ++/** ++ * Discard matching traffic. If set, this takes precedence over any other ++ * configuration and matching traffic is always discarded. ++ */ ++ #define DPNI_FS_OPT_DISCARD 0x1 ++ ++/** ++ * Set FLC value. If set, flc member of truct dpni_fs_action_cfg is used to ++ * override the FLC value set per queue. ++ * For more details check the Frame Descriptor section in the hardware ++ * documentation. ++ */ ++#define DPNI_FS_OPT_SET_FLC 0x2 ++ ++/* ++ * Indicates whether the 6 lowest significant bits of FLC are used for stash ++ * control. If set, the 6 least significant bits in value are interpreted as ++ * follows: ++ * - bits 0-1: indicates the number of 64 byte units of context that are ++ * stashed. FLC value is interpreted as a memory address in this case, ++ * excluding the 6 LS bits. ++ * - bits 2-3: indicates the number of 64 byte units of frame annotation ++ * to be stashed. Annotation is placed at FD[ADDR]. ++ * - bits 4-5: indicates the number of 64 byte units of frame data to be ++ * stashed. Frame data is placed at FD[ADDR] + FD[OFFSET]. ++ * This flag is ignored if DPNI_FS_OPT_SET_FLC is not specified. ++ */ ++#define DPNI_FS_OPT_SET_STASH_CONTROL 0x4 ++ ++/** ++ * struct dpni_fs_action_cfg - Action configuration for table look-up ++ * @flc: FLC value for traffic matching this rule. Please check the Frame ++ * Descriptor section in the hardware documentation for more information. ++ * @flow_id: Identifies the Rx queue used for matching traffic. Supported ++ * values are in range 0 to num_queue-1. ++ * @options: Any combination of DPNI_FS_OPT_ values. ++ */ ++struct dpni_fs_action_cfg { ++ u64 flc; ++ u16 flow_id; ++ u16 options; ++}; ++ ++int dpni_add_fs_entry(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 tc_id, ++ u16 index, ++ const struct dpni_rule_cfg *cfg, ++ const struct dpni_fs_action_cfg *action); ++ ++int dpni_remove_fs_entry(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 tc_id, ++ const struct dpni_rule_cfg *cfg); ++ ++#endif /* __FSL_DPNI_H */ +diff --git a/drivers/staging/fsl-dpaa2/ethernet/net.h b/drivers/staging/fsl-dpaa2/ethernet/net.h +new file mode 100644 +index 00000000..5020dee1 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethernet/net.h +@@ -0,0 +1,480 @@ ++/* Copyright 2013-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef __FSL_NET_H ++#define __FSL_NET_H ++ ++#define LAST_HDR_INDEX 0xFFFFFFFF ++ ++/*****************************************************************************/ ++/* Protocol fields */ ++/*****************************************************************************/ ++ ++/************************* Ethernet fields *********************************/ ++#define NH_FLD_ETH_DA (1) ++#define NH_FLD_ETH_SA (NH_FLD_ETH_DA << 1) ++#define NH_FLD_ETH_LENGTH (NH_FLD_ETH_DA << 2) ++#define NH_FLD_ETH_TYPE (NH_FLD_ETH_DA << 3) ++#define NH_FLD_ETH_FINAL_CKSUM (NH_FLD_ETH_DA << 4) ++#define NH_FLD_ETH_PADDING (NH_FLD_ETH_DA << 5) ++#define NH_FLD_ETH_ALL_FIELDS ((NH_FLD_ETH_DA << 6) - 1) ++ ++#define NH_FLD_ETH_ADDR_SIZE 6 ++ ++/*************************** VLAN fields ***********************************/ ++#define NH_FLD_VLAN_VPRI (1) ++#define NH_FLD_VLAN_CFI (NH_FLD_VLAN_VPRI << 1) ++#define NH_FLD_VLAN_VID (NH_FLD_VLAN_VPRI << 2) ++#define NH_FLD_VLAN_LENGTH (NH_FLD_VLAN_VPRI << 3) ++#define NH_FLD_VLAN_TYPE (NH_FLD_VLAN_VPRI << 4) ++#define NH_FLD_VLAN_ALL_FIELDS ((NH_FLD_VLAN_VPRI << 5) - 1) ++ ++#define NH_FLD_VLAN_TCI (NH_FLD_VLAN_VPRI | \ ++ NH_FLD_VLAN_CFI | \ ++ NH_FLD_VLAN_VID) ++ ++/************************ IP (generic) fields ******************************/ ++#define NH_FLD_IP_VER (1) ++#define NH_FLD_IP_DSCP (NH_FLD_IP_VER << 2) ++#define NH_FLD_IP_ECN (NH_FLD_IP_VER << 3) ++#define NH_FLD_IP_PROTO (NH_FLD_IP_VER << 4) ++#define NH_FLD_IP_SRC (NH_FLD_IP_VER << 5) ++#define NH_FLD_IP_DST (NH_FLD_IP_VER << 6) ++#define NH_FLD_IP_TOS_TC (NH_FLD_IP_VER << 7) ++#define NH_FLD_IP_ID (NH_FLD_IP_VER << 8) ++#define NH_FLD_IP_ALL_FIELDS ((NH_FLD_IP_VER << 9) - 1) ++ ++#define NH_FLD_IP_PROTO_SIZE 1 ++ ++/***************************** IPV4 fields *********************************/ ++#define NH_FLD_IPV4_VER (1) ++#define NH_FLD_IPV4_HDR_LEN (NH_FLD_IPV4_VER << 1) ++#define NH_FLD_IPV4_TOS (NH_FLD_IPV4_VER << 2) ++#define NH_FLD_IPV4_TOTAL_LEN (NH_FLD_IPV4_VER << 3) ++#define NH_FLD_IPV4_ID (NH_FLD_IPV4_VER << 4) ++#define NH_FLD_IPV4_FLAG_D (NH_FLD_IPV4_VER << 5) ++#define NH_FLD_IPV4_FLAG_M (NH_FLD_IPV4_VER << 6) ++#define NH_FLD_IPV4_OFFSET (NH_FLD_IPV4_VER << 7) ++#define NH_FLD_IPV4_TTL (NH_FLD_IPV4_VER << 8) ++#define NH_FLD_IPV4_PROTO (NH_FLD_IPV4_VER << 9) ++#define NH_FLD_IPV4_CKSUM (NH_FLD_IPV4_VER << 10) ++#define NH_FLD_IPV4_SRC_IP (NH_FLD_IPV4_VER << 11) ++#define NH_FLD_IPV4_DST_IP (NH_FLD_IPV4_VER << 12) ++#define NH_FLD_IPV4_OPTS (NH_FLD_IPV4_VER << 13) ++#define NH_FLD_IPV4_OPTS_COUNT (NH_FLD_IPV4_VER << 14) ++#define NH_FLD_IPV4_ALL_FIELDS ((NH_FLD_IPV4_VER << 15) - 1) ++ ++#define NH_FLD_IPV4_ADDR_SIZE 4 ++#define NH_FLD_IPV4_PROTO_SIZE 1 ++ ++/***************************** IPV6 fields *********************************/ ++#define NH_FLD_IPV6_VER (1) ++#define NH_FLD_IPV6_TC (NH_FLD_IPV6_VER << 1) ++#define NH_FLD_IPV6_SRC_IP (NH_FLD_IPV6_VER << 2) ++#define NH_FLD_IPV6_DST_IP (NH_FLD_IPV6_VER << 3) ++#define NH_FLD_IPV6_NEXT_HDR (NH_FLD_IPV6_VER << 4) ++#define NH_FLD_IPV6_FL (NH_FLD_IPV6_VER << 5) ++#define NH_FLD_IPV6_HOP_LIMIT (NH_FLD_IPV6_VER << 6) ++#define NH_FLD_IPV6_ID (NH_FLD_IPV6_VER << 7) ++#define NH_FLD_IPV6_ALL_FIELDS ((NH_FLD_IPV6_VER << 8) - 1) ++ ++#define NH_FLD_IPV6_ADDR_SIZE 16 ++#define NH_FLD_IPV6_NEXT_HDR_SIZE 1 ++ ++/***************************** ICMP fields *********************************/ ++#define NH_FLD_ICMP_TYPE (1) ++#define NH_FLD_ICMP_CODE (NH_FLD_ICMP_TYPE << 1) ++#define NH_FLD_ICMP_CKSUM (NH_FLD_ICMP_TYPE << 2) ++#define NH_FLD_ICMP_ID (NH_FLD_ICMP_TYPE << 3) ++#define NH_FLD_ICMP_SQ_NUM (NH_FLD_ICMP_TYPE << 4) ++#define NH_FLD_ICMP_ALL_FIELDS ((NH_FLD_ICMP_TYPE << 5) - 1) ++ ++#define NH_FLD_ICMP_CODE_SIZE 1 ++#define NH_FLD_ICMP_TYPE_SIZE 1 ++ ++/***************************** IGMP fields *********************************/ ++#define NH_FLD_IGMP_VERSION (1) ++#define NH_FLD_IGMP_TYPE (NH_FLD_IGMP_VERSION << 1) ++#define NH_FLD_IGMP_CKSUM (NH_FLD_IGMP_VERSION << 2) ++#define NH_FLD_IGMP_DATA (NH_FLD_IGMP_VERSION << 3) ++#define NH_FLD_IGMP_ALL_FIELDS ((NH_FLD_IGMP_VERSION << 4) - 1) ++ ++/***************************** TCP fields **********************************/ ++#define NH_FLD_TCP_PORT_SRC (1) ++#define NH_FLD_TCP_PORT_DST (NH_FLD_TCP_PORT_SRC << 1) ++#define NH_FLD_TCP_SEQ (NH_FLD_TCP_PORT_SRC << 2) ++#define NH_FLD_TCP_ACK (NH_FLD_TCP_PORT_SRC << 3) ++#define NH_FLD_TCP_OFFSET (NH_FLD_TCP_PORT_SRC << 4) ++#define NH_FLD_TCP_FLAGS (NH_FLD_TCP_PORT_SRC << 5) ++#define NH_FLD_TCP_WINDOW (NH_FLD_TCP_PORT_SRC << 6) ++#define NH_FLD_TCP_CKSUM (NH_FLD_TCP_PORT_SRC << 7) ++#define NH_FLD_TCP_URGPTR (NH_FLD_TCP_PORT_SRC << 8) ++#define NH_FLD_TCP_OPTS (NH_FLD_TCP_PORT_SRC << 9) ++#define NH_FLD_TCP_OPTS_COUNT (NH_FLD_TCP_PORT_SRC << 10) ++#define NH_FLD_TCP_ALL_FIELDS ((NH_FLD_TCP_PORT_SRC << 11) - 1) ++ ++#define NH_FLD_TCP_PORT_SIZE 2 ++ ++/***************************** UDP fields **********************************/ ++#define NH_FLD_UDP_PORT_SRC (1) ++#define NH_FLD_UDP_PORT_DST (NH_FLD_UDP_PORT_SRC << 1) ++#define NH_FLD_UDP_LEN (NH_FLD_UDP_PORT_SRC << 2) ++#define NH_FLD_UDP_CKSUM (NH_FLD_UDP_PORT_SRC << 3) ++#define NH_FLD_UDP_ALL_FIELDS ((NH_FLD_UDP_PORT_SRC << 4) - 1) ++ ++#define NH_FLD_UDP_PORT_SIZE 2 ++ ++/*************************** UDP-lite fields *******************************/ ++#define NH_FLD_UDP_LITE_PORT_SRC (1) ++#define NH_FLD_UDP_LITE_PORT_DST (NH_FLD_UDP_LITE_PORT_SRC << 1) ++#define NH_FLD_UDP_LITE_ALL_FIELDS \ ++ ((NH_FLD_UDP_LITE_PORT_SRC << 2) - 1) ++ ++#define NH_FLD_UDP_LITE_PORT_SIZE 2 ++ ++/*************************** UDP-encap-ESP fields **************************/ ++#define NH_FLD_UDP_ENC_ESP_PORT_SRC (1) ++#define NH_FLD_UDP_ENC_ESP_PORT_DST (NH_FLD_UDP_ENC_ESP_PORT_SRC << 1) ++#define NH_FLD_UDP_ENC_ESP_LEN (NH_FLD_UDP_ENC_ESP_PORT_SRC << 2) ++#define NH_FLD_UDP_ENC_ESP_CKSUM (NH_FLD_UDP_ENC_ESP_PORT_SRC << 3) ++#define NH_FLD_UDP_ENC_ESP_SPI (NH_FLD_UDP_ENC_ESP_PORT_SRC << 4) ++#define NH_FLD_UDP_ENC_ESP_SEQUENCE_NUM (NH_FLD_UDP_ENC_ESP_PORT_SRC << 5) ++#define NH_FLD_UDP_ENC_ESP_ALL_FIELDS \ ++ ((NH_FLD_UDP_ENC_ESP_PORT_SRC << 6) - 1) ++ ++#define NH_FLD_UDP_ENC_ESP_PORT_SIZE 2 ++#define NH_FLD_UDP_ENC_ESP_SPI_SIZE 4 ++ ++/***************************** SCTP fields *********************************/ ++#define NH_FLD_SCTP_PORT_SRC (1) ++#define NH_FLD_SCTP_PORT_DST (NH_FLD_SCTP_PORT_SRC << 1) ++#define NH_FLD_SCTP_VER_TAG (NH_FLD_SCTP_PORT_SRC << 2) ++#define NH_FLD_SCTP_CKSUM (NH_FLD_SCTP_PORT_SRC << 3) ++#define NH_FLD_SCTP_ALL_FIELDS ((NH_FLD_SCTP_PORT_SRC << 4) - 1) ++ ++#define NH_FLD_SCTP_PORT_SIZE 2 ++ ++/***************************** DCCP fields *********************************/ ++#define NH_FLD_DCCP_PORT_SRC (1) ++#define NH_FLD_DCCP_PORT_DST (NH_FLD_DCCP_PORT_SRC << 1) ++#define NH_FLD_DCCP_ALL_FIELDS ((NH_FLD_DCCP_PORT_SRC << 2) - 1) ++ ++#define NH_FLD_DCCP_PORT_SIZE 2 ++ ++/***************************** IPHC fields *********************************/ ++#define NH_FLD_IPHC_CID (1) ++#define NH_FLD_IPHC_CID_TYPE (NH_FLD_IPHC_CID << 1) ++#define NH_FLD_IPHC_HCINDEX (NH_FLD_IPHC_CID << 2) ++#define NH_FLD_IPHC_GEN (NH_FLD_IPHC_CID << 3) ++#define NH_FLD_IPHC_D_BIT (NH_FLD_IPHC_CID << 4) ++#define NH_FLD_IPHC_ALL_FIELDS ((NH_FLD_IPHC_CID << 5) - 1) ++ ++/***************************** SCTP fields *********************************/ ++#define NH_FLD_SCTP_CHUNK_DATA_TYPE (1) ++#define NH_FLD_SCTP_CHUNK_DATA_FLAGS (NH_FLD_SCTP_CHUNK_DATA_TYPE << 1) ++#define NH_FLD_SCTP_CHUNK_DATA_LENGTH (NH_FLD_SCTP_CHUNK_DATA_TYPE << 2) ++#define NH_FLD_SCTP_CHUNK_DATA_TSN (NH_FLD_SCTP_CHUNK_DATA_TYPE << 3) ++#define NH_FLD_SCTP_CHUNK_DATA_STREAM_ID (NH_FLD_SCTP_CHUNK_DATA_TYPE << 4) ++#define NH_FLD_SCTP_CHUNK_DATA_STREAM_SQN (NH_FLD_SCTP_CHUNK_DATA_TYPE << 5) ++#define NH_FLD_SCTP_CHUNK_DATA_PAYLOAD_PID (NH_FLD_SCTP_CHUNK_DATA_TYPE << 6) ++#define NH_FLD_SCTP_CHUNK_DATA_UNORDERED (NH_FLD_SCTP_CHUNK_DATA_TYPE << 7) ++#define NH_FLD_SCTP_CHUNK_DATA_BEGGINING (NH_FLD_SCTP_CHUNK_DATA_TYPE << 8) ++#define NH_FLD_SCTP_CHUNK_DATA_END (NH_FLD_SCTP_CHUNK_DATA_TYPE << 9) ++#define NH_FLD_SCTP_CHUNK_DATA_ALL_FIELDS \ ++ ((NH_FLD_SCTP_CHUNK_DATA_TYPE << 10) - 1) ++ ++/*************************** L2TPV2 fields *********************************/ ++#define NH_FLD_L2TPV2_TYPE_BIT (1) ++#define NH_FLD_L2TPV2_LENGTH_BIT (NH_FLD_L2TPV2_TYPE_BIT << 1) ++#define NH_FLD_L2TPV2_SEQUENCE_BIT (NH_FLD_L2TPV2_TYPE_BIT << 2) ++#define NH_FLD_L2TPV2_OFFSET_BIT (NH_FLD_L2TPV2_TYPE_BIT << 3) ++#define NH_FLD_L2TPV2_PRIORITY_BIT (NH_FLD_L2TPV2_TYPE_BIT << 4) ++#define NH_FLD_L2TPV2_VERSION (NH_FLD_L2TPV2_TYPE_BIT << 5) ++#define NH_FLD_L2TPV2_LEN (NH_FLD_L2TPV2_TYPE_BIT << 6) ++#define NH_FLD_L2TPV2_TUNNEL_ID (NH_FLD_L2TPV2_TYPE_BIT << 7) ++#define NH_FLD_L2TPV2_SESSION_ID (NH_FLD_L2TPV2_TYPE_BIT << 8) ++#define NH_FLD_L2TPV2_NS (NH_FLD_L2TPV2_TYPE_BIT << 9) ++#define NH_FLD_L2TPV2_NR (NH_FLD_L2TPV2_TYPE_BIT << 10) ++#define NH_FLD_L2TPV2_OFFSET_SIZE (NH_FLD_L2TPV2_TYPE_BIT << 11) ++#define NH_FLD_L2TPV2_FIRST_BYTE (NH_FLD_L2TPV2_TYPE_BIT << 12) ++#define NH_FLD_L2TPV2_ALL_FIELDS \ ++ ((NH_FLD_L2TPV2_TYPE_BIT << 13) - 1) ++ ++/*************************** L2TPV3 fields *********************************/ ++#define NH_FLD_L2TPV3_CTRL_TYPE_BIT (1) ++#define NH_FLD_L2TPV3_CTRL_LENGTH_BIT (NH_FLD_L2TPV3_CTRL_TYPE_BIT << 1) ++#define NH_FLD_L2TPV3_CTRL_SEQUENCE_BIT (NH_FLD_L2TPV3_CTRL_TYPE_BIT << 2) ++#define NH_FLD_L2TPV3_CTRL_VERSION (NH_FLD_L2TPV3_CTRL_TYPE_BIT << 3) ++#define NH_FLD_L2TPV3_CTRL_LENGTH (NH_FLD_L2TPV3_CTRL_TYPE_BIT << 4) ++#define NH_FLD_L2TPV3_CTRL_CONTROL (NH_FLD_L2TPV3_CTRL_TYPE_BIT << 5) ++#define NH_FLD_L2TPV3_CTRL_SENT (NH_FLD_L2TPV3_CTRL_TYPE_BIT << 6) ++#define NH_FLD_L2TPV3_CTRL_RECV (NH_FLD_L2TPV3_CTRL_TYPE_BIT << 7) ++#define NH_FLD_L2TPV3_CTRL_FIRST_BYTE (NH_FLD_L2TPV3_CTRL_TYPE_BIT << 8) ++#define NH_FLD_L2TPV3_CTRL_ALL_FIELDS \ ++ ((NH_FLD_L2TPV3_CTRL_TYPE_BIT << 9) - 1) ++ ++#define NH_FLD_L2TPV3_SESS_TYPE_BIT (1) ++#define NH_FLD_L2TPV3_SESS_VERSION (NH_FLD_L2TPV3_SESS_TYPE_BIT << 1) ++#define NH_FLD_L2TPV3_SESS_ID (NH_FLD_L2TPV3_SESS_TYPE_BIT << 2) ++#define NH_FLD_L2TPV3_SESS_COOKIE (NH_FLD_L2TPV3_SESS_TYPE_BIT << 3) ++#define NH_FLD_L2TPV3_SESS_ALL_FIELDS \ ++ ((NH_FLD_L2TPV3_SESS_TYPE_BIT << 4) - 1) ++ ++/**************************** PPP fields ***********************************/ ++#define NH_FLD_PPP_PID (1) ++#define NH_FLD_PPP_COMPRESSED (NH_FLD_PPP_PID << 1) ++#define NH_FLD_PPP_ALL_FIELDS ((NH_FLD_PPP_PID << 2) - 1) ++ ++/************************** PPPoE fields ***********************************/ ++#define NH_FLD_PPPOE_VER (1) ++#define NH_FLD_PPPOE_TYPE (NH_FLD_PPPOE_VER << 1) ++#define NH_FLD_PPPOE_CODE (NH_FLD_PPPOE_VER << 2) ++#define NH_FLD_PPPOE_SID (NH_FLD_PPPOE_VER << 3) ++#define NH_FLD_PPPOE_LEN (NH_FLD_PPPOE_VER << 4) ++#define NH_FLD_PPPOE_SESSION (NH_FLD_PPPOE_VER << 5) ++#define NH_FLD_PPPOE_PID (NH_FLD_PPPOE_VER << 6) ++#define NH_FLD_PPPOE_ALL_FIELDS ((NH_FLD_PPPOE_VER << 7) - 1) ++ ++/************************* PPP-Mux fields **********************************/ ++#define NH_FLD_PPPMUX_PID (1) ++#define NH_FLD_PPPMUX_CKSUM (NH_FLD_PPPMUX_PID << 1) ++#define NH_FLD_PPPMUX_COMPRESSED (NH_FLD_PPPMUX_PID << 2) ++#define NH_FLD_PPPMUX_ALL_FIELDS ((NH_FLD_PPPMUX_PID << 3) - 1) ++ ++/*********************** PPP-Mux sub-frame fields **************************/ ++#define NH_FLD_PPPMUX_SUBFRM_PFF (1) ++#define NH_FLD_PPPMUX_SUBFRM_LXT (NH_FLD_PPPMUX_SUBFRM_PFF << 1) ++#define NH_FLD_PPPMUX_SUBFRM_LEN (NH_FLD_PPPMUX_SUBFRM_PFF << 2) ++#define NH_FLD_PPPMUX_SUBFRM_PID (NH_FLD_PPPMUX_SUBFRM_PFF << 3) ++#define NH_FLD_PPPMUX_SUBFRM_USE_PID (NH_FLD_PPPMUX_SUBFRM_PFF << 4) ++#define NH_FLD_PPPMUX_SUBFRM_ALL_FIELDS \ ++ ((NH_FLD_PPPMUX_SUBFRM_PFF << 5) - 1) ++ ++/*************************** LLC fields ************************************/ ++#define NH_FLD_LLC_DSAP (1) ++#define NH_FLD_LLC_SSAP (NH_FLD_LLC_DSAP << 1) ++#define NH_FLD_LLC_CTRL (NH_FLD_LLC_DSAP << 2) ++#define NH_FLD_LLC_ALL_FIELDS ((NH_FLD_LLC_DSAP << 3) - 1) ++ ++/*************************** NLPID fields **********************************/ ++#define NH_FLD_NLPID_NLPID (1) ++#define NH_FLD_NLPID_ALL_FIELDS ((NH_FLD_NLPID_NLPID << 1) - 1) ++ ++/*************************** SNAP fields ***********************************/ ++#define NH_FLD_SNAP_OUI (1) ++#define NH_FLD_SNAP_PID (NH_FLD_SNAP_OUI << 1) ++#define NH_FLD_SNAP_ALL_FIELDS ((NH_FLD_SNAP_OUI << 2) - 1) ++ ++/*************************** LLC SNAP fields *******************************/ ++#define NH_FLD_LLC_SNAP_TYPE (1) ++#define NH_FLD_LLC_SNAP_ALL_FIELDS ((NH_FLD_LLC_SNAP_TYPE << 1) - 1) ++ ++#define NH_FLD_ARP_HTYPE (1) ++#define NH_FLD_ARP_PTYPE (NH_FLD_ARP_HTYPE << 1) ++#define NH_FLD_ARP_HLEN (NH_FLD_ARP_HTYPE << 2) ++#define NH_FLD_ARP_PLEN (NH_FLD_ARP_HTYPE << 3) ++#define NH_FLD_ARP_OPER (NH_FLD_ARP_HTYPE << 4) ++#define NH_FLD_ARP_SHA (NH_FLD_ARP_HTYPE << 5) ++#define NH_FLD_ARP_SPA (NH_FLD_ARP_HTYPE << 6) ++#define NH_FLD_ARP_THA (NH_FLD_ARP_HTYPE << 7) ++#define NH_FLD_ARP_TPA (NH_FLD_ARP_HTYPE << 8) ++#define NH_FLD_ARP_ALL_FIELDS ((NH_FLD_ARP_HTYPE << 9) - 1) ++ ++/*************************** RFC2684 fields ********************************/ ++#define NH_FLD_RFC2684_LLC (1) ++#define NH_FLD_RFC2684_NLPID (NH_FLD_RFC2684_LLC << 1) ++#define NH_FLD_RFC2684_OUI (NH_FLD_RFC2684_LLC << 2) ++#define NH_FLD_RFC2684_PID (NH_FLD_RFC2684_LLC << 3) ++#define NH_FLD_RFC2684_VPN_OUI (NH_FLD_RFC2684_LLC << 4) ++#define NH_FLD_RFC2684_VPN_IDX (NH_FLD_RFC2684_LLC << 5) ++#define NH_FLD_RFC2684_ALL_FIELDS ((NH_FLD_RFC2684_LLC << 6) - 1) ++ ++/*************************** User defined fields ***************************/ ++#define NH_FLD_USER_DEFINED_SRCPORT (1) ++#define NH_FLD_USER_DEFINED_PCDID (NH_FLD_USER_DEFINED_SRCPORT << 1) ++#define NH_FLD_USER_DEFINED_ALL_FIELDS \ ++ ((NH_FLD_USER_DEFINED_SRCPORT << 2) - 1) ++ ++/*************************** Payload fields ********************************/ ++#define NH_FLD_PAYLOAD_BUFFER (1) ++#define NH_FLD_PAYLOAD_SIZE (NH_FLD_PAYLOAD_BUFFER << 1) ++#define NH_FLD_MAX_FRM_SIZE (NH_FLD_PAYLOAD_BUFFER << 2) ++#define NH_FLD_MIN_FRM_SIZE (NH_FLD_PAYLOAD_BUFFER << 3) ++#define NH_FLD_PAYLOAD_TYPE (NH_FLD_PAYLOAD_BUFFER << 4) ++#define NH_FLD_FRAME_SIZE (NH_FLD_PAYLOAD_BUFFER << 5) ++#define NH_FLD_PAYLOAD_ALL_FIELDS ((NH_FLD_PAYLOAD_BUFFER << 6) - 1) ++ ++/*************************** GRE fields ************************************/ ++#define NH_FLD_GRE_TYPE (1) ++#define NH_FLD_GRE_ALL_FIELDS ((NH_FLD_GRE_TYPE << 1) - 1) ++ ++/*************************** MINENCAP fields *******************************/ ++#define NH_FLD_MINENCAP_SRC_IP (1) ++#define NH_FLD_MINENCAP_DST_IP (NH_FLD_MINENCAP_SRC_IP << 1) ++#define NH_FLD_MINENCAP_TYPE (NH_FLD_MINENCAP_SRC_IP << 2) ++#define NH_FLD_MINENCAP_ALL_FIELDS \ ++ ((NH_FLD_MINENCAP_SRC_IP << 3) - 1) ++ ++/*************************** IPSEC AH fields *******************************/ ++#define NH_FLD_IPSEC_AH_SPI (1) ++#define NH_FLD_IPSEC_AH_NH (NH_FLD_IPSEC_AH_SPI << 1) ++#define NH_FLD_IPSEC_AH_ALL_FIELDS ((NH_FLD_IPSEC_AH_SPI << 2) - 1) ++ ++/*************************** IPSEC ESP fields ******************************/ ++#define NH_FLD_IPSEC_ESP_SPI (1) ++#define NH_FLD_IPSEC_ESP_SEQUENCE_NUM (NH_FLD_IPSEC_ESP_SPI << 1) ++#define NH_FLD_IPSEC_ESP_ALL_FIELDS ((NH_FLD_IPSEC_ESP_SPI << 2) - 1) ++ ++#define NH_FLD_IPSEC_ESP_SPI_SIZE 4 ++ ++/*************************** MPLS fields ***********************************/ ++#define NH_FLD_MPLS_LABEL_STACK (1) ++#define NH_FLD_MPLS_LABEL_STACK_ALL_FIELDS \ ++ ((NH_FLD_MPLS_LABEL_STACK << 1) - 1) ++ ++/*************************** MACSEC fields *********************************/ ++#define NH_FLD_MACSEC_SECTAG (1) ++#define NH_FLD_MACSEC_ALL_FIELDS ((NH_FLD_MACSEC_SECTAG << 1) - 1) ++ ++/*************************** GTP fields ************************************/ ++#define NH_FLD_GTP_TEID (1) ++ ++/* Protocol options */ ++ ++/* Ethernet options */ ++#define NH_OPT_ETH_BROADCAST 1 ++#define NH_OPT_ETH_MULTICAST 2 ++#define NH_OPT_ETH_UNICAST 3 ++#define NH_OPT_ETH_BPDU 4 ++ ++#define NH_ETH_IS_MULTICAST_ADDR(addr) (addr[0] & 0x01) ++/* also applicable for broadcast */ ++ ++/* VLAN options */ ++#define NH_OPT_VLAN_CFI 1 ++ ++/* IPV4 options */ ++#define NH_OPT_IPV4_UNICAST 1 ++#define NH_OPT_IPV4_MULTICAST 2 ++#define NH_OPT_IPV4_BROADCAST 3 ++#define NH_OPT_IPV4_OPTION 4 ++#define NH_OPT_IPV4_FRAG 5 ++#define NH_OPT_IPV4_INITIAL_FRAG 6 ++ ++/* IPV6 options */ ++#define NH_OPT_IPV6_UNICAST 1 ++#define NH_OPT_IPV6_MULTICAST 2 ++#define NH_OPT_IPV6_OPTION 3 ++#define NH_OPT_IPV6_FRAG 4 ++#define NH_OPT_IPV6_INITIAL_FRAG 5 ++ ++/* General IP options (may be used for any version) */ ++#define NH_OPT_IP_FRAG 1 ++#define NH_OPT_IP_INITIAL_FRAG 2 ++#define NH_OPT_IP_OPTION 3 ++ ++/* Minenc. options */ ++#define NH_OPT_MINENCAP_SRC_ADDR_PRESENT 1 ++ ++/* GRE. options */ ++#define NH_OPT_GRE_ROUTING_PRESENT 1 ++ ++/* TCP options */ ++#define NH_OPT_TCP_OPTIONS 1 ++#define NH_OPT_TCP_CONTROL_HIGH_BITS 2 ++#define NH_OPT_TCP_CONTROL_LOW_BITS 3 ++ ++/* CAPWAP options */ ++#define NH_OPT_CAPWAP_DTLS 1 ++ ++enum net_prot { ++ NET_PROT_NONE = 0, ++ NET_PROT_PAYLOAD, ++ NET_PROT_ETH, ++ NET_PROT_VLAN, ++ NET_PROT_IPV4, ++ NET_PROT_IPV6, ++ NET_PROT_IP, ++ NET_PROT_TCP, ++ NET_PROT_UDP, ++ NET_PROT_UDP_LITE, ++ NET_PROT_IPHC, ++ NET_PROT_SCTP, ++ NET_PROT_SCTP_CHUNK_DATA, ++ NET_PROT_PPPOE, ++ NET_PROT_PPP, ++ NET_PROT_PPPMUX, ++ NET_PROT_PPPMUX_SUBFRM, ++ NET_PROT_L2TPV2, ++ NET_PROT_L2TPV3_CTRL, ++ NET_PROT_L2TPV3_SESS, ++ NET_PROT_LLC, ++ NET_PROT_LLC_SNAP, ++ NET_PROT_NLPID, ++ NET_PROT_SNAP, ++ NET_PROT_MPLS, ++ NET_PROT_IPSEC_AH, ++ NET_PROT_IPSEC_ESP, ++ NET_PROT_UDP_ENC_ESP, /* RFC 3948 */ ++ NET_PROT_MACSEC, ++ NET_PROT_GRE, ++ NET_PROT_MINENCAP, ++ NET_PROT_DCCP, ++ NET_PROT_ICMP, ++ NET_PROT_IGMP, ++ NET_PROT_ARP, ++ NET_PROT_CAPWAP_DATA, ++ NET_PROT_CAPWAP_CTRL, ++ NET_PROT_RFC2684, ++ NET_PROT_ICMPV6, ++ NET_PROT_FCOE, ++ NET_PROT_FIP, ++ NET_PROT_ISCSI, ++ NET_PROT_GTP, ++ NET_PROT_USER_DEFINED_L2, ++ NET_PROT_USER_DEFINED_L3, ++ NET_PROT_USER_DEFINED_L4, ++ NET_PROT_USER_DEFINED_L5, ++ NET_PROT_USER_DEFINED_SHIM1, ++ NET_PROT_USER_DEFINED_SHIM2, ++ ++ NET_PROT_DUMMY_LAST ++}; ++ ++/*! IEEE8021.Q */ ++#define NH_IEEE8021Q_ETYPE 0x8100 ++#define NH_IEEE8021Q_HDR(etype, pcp, dei, vlan_id) \ ++ ((((u32)((etype) & 0xFFFF)) << 16) | \ ++ (((u32)((pcp) & 0x07)) << 13) | \ ++ (((u32)((dei) & 0x01)) << 12) | \ ++ (((u32)((vlan_id) & 0xFFF)))) ++ ++#endif /* __FSL_NET_H */ +diff --git a/drivers/staging/fsl-dpaa2/ethsw/Kconfig b/drivers/staging/fsl-dpaa2/ethsw/Kconfig +new file mode 100644 +index 00000000..06c70408 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethsw/Kconfig +@@ -0,0 +1,6 @@ ++config FSL_DPAA2_ETHSW ++ tristate "DPAA2 Ethernet Switch" ++ depends on FSL_MC_BUS && FSL_DPAA2 ++ default y ++ ---help--- ++ Prototype driver for DPAA2 Ethernet Switch. +diff --git a/drivers/staging/fsl-dpaa2/ethsw/Makefile b/drivers/staging/fsl-dpaa2/ethsw/Makefile +new file mode 100644 +index 00000000..20eb3ac4 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethsw/Makefile +@@ -0,0 +1,10 @@ ++ ++obj-$(CONFIG_FSL_DPAA2_ETHSW) += dpaa2-ethsw.o ++ ++dpaa2-ethsw-objs := switch.o dpsw.o ++ ++all: ++ make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules ++ ++clean: ++ make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean +diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h +new file mode 100644 +index 00000000..f7374d1c +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h +@@ -0,0 +1,851 @@ ++/* Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef __FSL_DPSW_CMD_H ++#define __FSL_DPSW_CMD_H ++ ++/* DPSW Version */ ++#define DPSW_VER_MAJOR 8 ++#define DPSW_VER_MINOR 0 ++ ++#define DPSW_CMD_BASE_VERSION 1 ++#define DPSW_CMD_ID_OFFSET 4 ++ ++#define DPSW_CMD_ID(id) (((id) << DPSW_CMD_ID_OFFSET) | DPSW_CMD_BASE_VERSION) ++ ++/* Command IDs */ ++#define DPSW_CMDID_CLOSE DPSW_CMD_ID(0x800) ++#define DPSW_CMDID_OPEN DPSW_CMD_ID(0x802) ++ ++#define DPSW_CMDID_GET_API_VERSION DPSW_CMD_ID(0xa02) ++ ++#define DPSW_CMDID_ENABLE DPSW_CMD_ID(0x002) ++#define DPSW_CMDID_DISABLE DPSW_CMD_ID(0x003) ++#define DPSW_CMDID_GET_ATTR DPSW_CMD_ID(0x004) ++#define DPSW_CMDID_RESET DPSW_CMD_ID(0x005) ++#define DPSW_CMDID_IS_ENABLED DPSW_CMD_ID(0x006) ++ ++#define DPSW_CMDID_SET_IRQ DPSW_CMD_ID(0x010) ++#define DPSW_CMDID_GET_IRQ DPSW_CMD_ID(0x011) ++#define DPSW_CMDID_SET_IRQ_ENABLE DPSW_CMD_ID(0x012) ++#define DPSW_CMDID_GET_IRQ_ENABLE DPSW_CMD_ID(0x013) ++#define DPSW_CMDID_SET_IRQ_MASK DPSW_CMD_ID(0x014) ++#define DPSW_CMDID_GET_IRQ_MASK DPSW_CMD_ID(0x015) ++#define DPSW_CMDID_GET_IRQ_STATUS DPSW_CMD_ID(0x016) ++#define DPSW_CMDID_CLEAR_IRQ_STATUS DPSW_CMD_ID(0x017) ++ ++#define DPSW_CMDID_SET_REFLECTION_IF DPSW_CMD_ID(0x022) ++ ++#define DPSW_CMDID_ADD_CUSTOM_TPID DPSW_CMD_ID(0x024) ++ ++#define DPSW_CMDID_REMOVE_CUSTOM_TPID DPSW_CMD_ID(0x026) ++ ++#define DPSW_CMDID_IF_SET_TCI DPSW_CMD_ID(0x030) ++#define DPSW_CMDID_IF_SET_STP DPSW_CMD_ID(0x031) ++#define DPSW_CMDID_IF_SET_ACCEPTED_FRAMES DPSW_CMD_ID(0x032) ++#define DPSW_CMDID_SET_IF_ACCEPT_ALL_VLAN DPSW_CMD_ID(0x033) ++#define DPSW_CMDID_IF_GET_COUNTER DPSW_CMD_ID(0x034) ++#define DPSW_CMDID_IF_SET_COUNTER DPSW_CMD_ID(0x035) ++#define DPSW_CMDID_IF_SET_TX_SELECTION DPSW_CMD_ID(0x036) ++#define DPSW_CMDID_IF_ADD_REFLECTION DPSW_CMD_ID(0x037) ++#define DPSW_CMDID_IF_REMOVE_REFLECTION DPSW_CMD_ID(0x038) ++#define DPSW_CMDID_IF_SET_FLOODING_METERING DPSW_CMD_ID(0x039) ++#define DPSW_CMDID_IF_SET_METERING DPSW_CMD_ID(0x03A) ++#define DPSW_CMDID_IF_SET_EARLY_DROP DPSW_CMD_ID(0x03B) ++ ++#define DPSW_CMDID_IF_ENABLE DPSW_CMD_ID(0x03D) ++#define DPSW_CMDID_IF_DISABLE DPSW_CMD_ID(0x03E) ++ ++#define DPSW_CMDID_IF_GET_ATTR DPSW_CMD_ID(0x042) ++ ++#define DPSW_CMDID_IF_SET_MAX_FRAME_LENGTH DPSW_CMD_ID(0x044) ++#define DPSW_CMDID_IF_GET_MAX_FRAME_LENGTH DPSW_CMD_ID(0x045) ++#define DPSW_CMDID_IF_GET_LINK_STATE DPSW_CMD_ID(0x046) ++#define DPSW_CMDID_IF_SET_FLOODING DPSW_CMD_ID(0x047) ++#define DPSW_CMDID_IF_SET_BROADCAST DPSW_CMD_ID(0x048) ++#define DPSW_CMDID_IF_SET_MULTICAST DPSW_CMD_ID(0x049) ++#define DPSW_CMDID_IF_GET_TCI DPSW_CMD_ID(0x04A) ++ ++#define DPSW_CMDID_IF_SET_LINK_CFG DPSW_CMD_ID(0x04C) ++ ++#define DPSW_CMDID_VLAN_ADD DPSW_CMD_ID(0x060) ++#define DPSW_CMDID_VLAN_ADD_IF DPSW_CMD_ID(0x061) ++#define DPSW_CMDID_VLAN_ADD_IF_UNTAGGED DPSW_CMD_ID(0x062) ++#define DPSW_CMDID_VLAN_ADD_IF_FLOODING DPSW_CMD_ID(0x063) ++#define DPSW_CMDID_VLAN_REMOVE_IF DPSW_CMD_ID(0x064) ++#define DPSW_CMDID_VLAN_REMOVE_IF_UNTAGGED DPSW_CMD_ID(0x065) ++#define DPSW_CMDID_VLAN_REMOVE_IF_FLOODING DPSW_CMD_ID(0x066) ++#define DPSW_CMDID_VLAN_REMOVE DPSW_CMD_ID(0x067) ++#define DPSW_CMDID_VLAN_GET_IF DPSW_CMD_ID(0x068) ++#define DPSW_CMDID_VLAN_GET_IF_FLOODING DPSW_CMD_ID(0x069) ++#define DPSW_CMDID_VLAN_GET_IF_UNTAGGED DPSW_CMD_ID(0x06A) ++#define DPSW_CMDID_VLAN_GET_ATTRIBUTES DPSW_CMD_ID(0x06B) ++ ++#define DPSW_CMDID_FDB_GET_MULTICAST DPSW_CMD_ID(0x080) ++#define DPSW_CMDID_FDB_GET_UNICAST DPSW_CMD_ID(0x081) ++#define DPSW_CMDID_FDB_ADD DPSW_CMD_ID(0x082) ++#define DPSW_CMDID_FDB_REMOVE DPSW_CMD_ID(0x083) ++#define DPSW_CMDID_FDB_ADD_UNICAST DPSW_CMD_ID(0x084) ++#define DPSW_CMDID_FDB_REMOVE_UNICAST DPSW_CMD_ID(0x085) ++#define DPSW_CMDID_FDB_ADD_MULTICAST DPSW_CMD_ID(0x086) ++#define DPSW_CMDID_FDB_REMOVE_MULTICAST DPSW_CMD_ID(0x087) ++#define DPSW_CMDID_FDB_SET_LEARNING_MODE DPSW_CMD_ID(0x088) ++#define DPSW_CMDID_FDB_GET_ATTR DPSW_CMD_ID(0x089) ++ ++#define DPSW_CMDID_ACL_ADD DPSW_CMD_ID(0x090) ++#define DPSW_CMDID_ACL_REMOVE DPSW_CMD_ID(0x091) ++#define DPSW_CMDID_ACL_ADD_ENTRY DPSW_CMD_ID(0x092) ++#define DPSW_CMDID_ACL_REMOVE_ENTRY DPSW_CMD_ID(0x093) ++#define DPSW_CMDID_ACL_ADD_IF DPSW_CMD_ID(0x094) ++#define DPSW_CMDID_ACL_REMOVE_IF DPSW_CMD_ID(0x095) ++#define DPSW_CMDID_ACL_GET_ATTR DPSW_CMD_ID(0x096) ++ ++#define DPSW_CMDID_CTRL_IF_GET_ATTR DPSW_CMD_ID(0x0A0) ++#define DPSW_CMDID_CTRL_IF_SET_POOLS DPSW_CMD_ID(0x0A1) ++#define DPSW_CMDID_CTRL_IF_ENABLE DPSW_CMD_ID(0x0A2) ++#define DPSW_CMDID_CTRL_IF_DISABLE DPSW_CMD_ID(0x0A3) ++ ++/* Macros for accessing command fields smaller than 1byte */ ++#define DPSW_MASK(field) \ ++ GENMASK(DPSW_##field##_SHIFT + DPSW_##field##_SIZE - 1, \ ++ DPSW_##field##_SHIFT) ++#define dpsw_set_field(var, field, val) \ ++ ((var) |= (((val) << DPSW_##field##_SHIFT) & DPSW_MASK(field))) ++#define dpsw_get_field(var, field) \ ++ (((var) & DPSW_MASK(field)) >> DPSW_##field##_SHIFT) ++#define dpsw_get_bit(var, bit) \ ++ (((var) >> (bit)) & GENMASK(0, 0)) ++ ++static inline u64 dpsw_set_bit(u64 var, unsigned int bit, u8 val) ++{ ++ var |= (u64)val << bit & GENMASK(bit, bit); ++ return var; ++} ++ ++struct dpsw_cmd_open { ++ __le32 dpsw_id; ++}; ++ ++#define DPSW_COMPONENT_TYPE_SHIFT 0 ++#define DPSW_COMPONENT_TYPE_SIZE 4 ++ ++struct dpsw_cmd_create { ++ /* cmd word 0 */ ++ __le16 num_ifs; ++ u8 max_fdbs; ++ u8 max_meters_per_if; ++ /* from LSB: only the first 4 bits */ ++ u8 component_type; ++ u8 pad[3]; ++ /* cmd word 1 */ ++ __le16 max_vlans; ++ __le16 max_fdb_entries; ++ __le16 fdb_aging_time; ++ __le16 max_fdb_mc_groups; ++ /* cmd word 2 */ ++ __le64 options; ++}; ++ ++struct dpsw_cmd_destroy { ++ __le32 dpsw_id; ++}; ++ ++#define DPSW_ENABLE_SHIFT 0 ++#define DPSW_ENABLE_SIZE 1 ++ ++struct dpsw_rsp_is_enabled { ++ /* from LSB: enable:1 */ ++ u8 enabled; ++}; ++ ++struct dpsw_cmd_set_irq { ++ /* cmd word 0 */ ++ u8 irq_index; ++ u8 pad[3]; ++ __le32 irq_val; ++ /* cmd word 1 */ ++ __le64 irq_addr; ++ /* cmd word 2 */ ++ __le32 irq_num; ++}; ++ ++struct dpsw_cmd_get_irq { ++ __le32 pad; ++ u8 irq_index; ++}; ++ ++struct dpsw_rsp_get_irq { ++ /* cmd word 0 */ ++ __le32 irq_val; ++ __le32 pad; ++ /* cmd word 1 */ ++ __le64 irq_addr; ++ /* cmd word 2 */ ++ __le32 irq_num; ++ __le32 irq_type; ++}; ++ ++struct dpsw_cmd_set_irq_enable { ++ u8 enable_state; ++ u8 pad[3]; ++ u8 irq_index; ++}; ++ ++struct dpsw_cmd_get_irq_enable { ++ __le32 pad; ++ u8 irq_index; ++}; ++ ++struct dpsw_rsp_get_irq_enable { ++ u8 enable_state; ++}; ++ ++struct dpsw_cmd_set_irq_mask { ++ __le32 mask; ++ u8 irq_index; ++}; ++ ++struct dpsw_cmd_get_irq_mask { ++ __le32 pad; ++ u8 irq_index; ++}; ++ ++struct dpsw_rsp_get_irq_mask { ++ __le32 mask; ++}; ++ ++struct dpsw_cmd_get_irq_status { ++ __le32 status; ++ u8 irq_index; ++}; ++ ++struct dpsw_rsp_get_irq_status { ++ __le32 status; ++}; ++ ++struct dpsw_cmd_clear_irq_status { ++ __le32 status; ++ u8 irq_index; ++}; ++ ++#define DPSW_COMPONENT_TYPE_SHIFT 0 ++#define DPSW_COMPONENT_TYPE_SIZE 4 ++ ++struct dpsw_rsp_get_attr { ++ /* cmd word 0 */ ++ __le16 num_ifs; ++ u8 max_fdbs; ++ u8 num_fdbs; ++ __le16 max_vlans; ++ __le16 num_vlans; ++ /* cmd word 1 */ ++ __le16 max_fdb_entries; ++ __le16 fdb_aging_time; ++ __le32 dpsw_id; ++ /* cmd word 2 */ ++ __le16 mem_size; ++ __le16 max_fdb_mc_groups; ++ u8 max_meters_per_if; ++ /* from LSB only the ffirst 4 bits */ ++ u8 component_type; ++ __le16 pad; ++ /* cmd word 3 */ ++ __le64 options; ++}; ++ ++struct dpsw_cmd_set_reflection_if { ++ __le16 if_id; ++}; ++ ++struct dpsw_cmd_if_set_flooding { ++ __le16 if_id; ++ /* from LSB: enable:1 */ ++ u8 enable; ++}; ++ ++struct dpsw_cmd_if_set_broadcast { ++ __le16 if_id; ++ /* from LSB: enable:1 */ ++ u8 enable; ++}; ++ ++struct dpsw_cmd_if_set_multicast { ++ __le16 if_id; ++ /* from LSB: enable:1 */ ++ u8 enable; ++}; ++ ++#define DPSW_VLAN_ID_SHIFT 0 ++#define DPSW_VLAN_ID_SIZE 12 ++#define DPSW_DEI_SHIFT 12 ++#define DPSW_DEI_SIZE 1 ++#define DPSW_PCP_SHIFT 13 ++#define DPSW_PCP_SIZE 3 ++ ++struct dpsw_cmd_if_set_tci { ++ __le16 if_id; ++ /* from LSB: VLAN_ID:12 DEI:1 PCP:3 */ ++ __le16 conf; ++}; ++ ++struct dpsw_cmd_if_get_tci { ++ __le16 if_id; ++}; ++ ++struct dpsw_rsp_if_get_tci { ++ __le16 pad; ++ __le16 vlan_id; ++ u8 dei; ++ u8 pcp; ++}; ++ ++#define DPSW_STATE_SHIFT 0 ++#define DPSW_STATE_SIZE 4 ++ ++struct dpsw_cmd_if_set_stp { ++ __le16 if_id; ++ __le16 vlan_id; ++ /* only the first LSB 4 bits */ ++ u8 state; ++}; ++ ++#define DPSW_FRAME_TYPE_SHIFT 0 ++#define DPSW_FRAME_TYPE_SIZE 4 ++#define DPSW_UNACCEPTED_ACT_SHIFT 4 ++#define DPSW_UNACCEPTED_ACT_SIZE 4 ++ ++struct dpsw_cmd_if_set_accepted_frames { ++ __le16 if_id; ++ /* from LSB: type:4 unaccepted_act:4 */ ++ u8 unaccepted; ++}; ++ ++#define DPSW_ACCEPT_ALL_SHIFT 0 ++#define DPSW_ACCEPT_ALL_SIZE 1 ++ ++struct dpsw_cmd_if_set_accept_all_vlan { ++ __le16 if_id; ++ /* only the least significant bit */ ++ u8 accept_all; ++}; ++ ++#define DPSW_COUNTER_TYPE_SHIFT 0 ++#define DPSW_COUNTER_TYPE_SIZE 5 ++ ++struct dpsw_cmd_if_get_counter { ++ __le16 if_id; ++ /* from LSB: type:5 */ ++ u8 type; ++}; ++ ++struct dpsw_rsp_if_get_counter { ++ __le64 pad; ++ __le64 counter; ++}; ++ ++struct dpsw_cmd_if_set_counter { ++ /* cmd word 0 */ ++ __le16 if_id; ++ /* from LSB: type:5 */ ++ u8 type; ++ /* cmd word 1 */ ++ __le64 counter; ++}; ++ ++#define DPSW_PRIORITY_SELECTOR_SHIFT 0 ++#define DPSW_PRIORITY_SELECTOR_SIZE 3 ++#define DPSW_SCHED_MODE_SHIFT 0 ++#define DPSW_SCHED_MODE_SIZE 4 ++ ++struct dpsw_cmd_if_set_tx_selection { ++ __le16 if_id; ++ /* from LSB: priority_selector:3 */ ++ u8 priority_selector; ++ u8 pad[5]; ++ u8 tc_id[8]; ++ ++ struct dpsw_tc_sched { ++ __le16 delta_bandwidth; ++ u8 mode; ++ u8 pad; ++ } tc_sched[8]; ++}; ++ ++#define DPSW_FILTER_SHIFT 0 ++#define DPSW_FILTER_SIZE 2 ++ ++struct dpsw_cmd_if_reflection { ++ __le16 if_id; ++ __le16 vlan_id; ++ /* only 2 bits from the LSB */ ++ u8 filter; ++}; ++ ++#define DPSW_MODE_SHIFT 0 ++#define DPSW_MODE_SIZE 4 ++#define DPSW_UNITS_SHIFT 4 ++#define DPSW_UNITS_SIZE 4 ++ ++struct dpsw_cmd_if_set_flooding_metering { ++ /* cmd word 0 */ ++ __le16 if_id; ++ u8 pad; ++ /* from LSB: mode:4 units:4 */ ++ u8 mode_units; ++ __le32 cir; ++ /* cmd word 1 */ ++ __le32 eir; ++ __le32 cbs; ++ /* cmd word 2 */ ++ __le32 ebs; ++}; ++ ++struct dpsw_cmd_if_set_metering { ++ /* cmd word 0 */ ++ __le16 if_id; ++ u8 tc_id; ++ /* from LSB: mode:4 units:4 */ ++ u8 mode_units; ++ __le32 cir; ++ /* cmd word 1 */ ++ __le32 eir; ++ __le32 cbs; ++ /* cmd word 2 */ ++ __le32 ebs; ++}; ++ ++#define DPSW_EARLY_DROP_MODE_SHIFT 0 ++#define DPSW_EARLY_DROP_MODE_SIZE 2 ++#define DPSW_EARLY_DROP_UNIT_SHIFT 2 ++#define DPSW_EARLY_DROP_UNIT_SIZE 2 ++ ++struct dpsw_prep_early_drop { ++ /* from LSB: mode:2 units:2 */ ++ u8 conf; ++ u8 pad0[3]; ++ __le32 tail_drop_threshold; ++ u8 green_drop_probability; ++ u8 pad1[7]; ++ __le64 green_max_threshold; ++ __le64 green_min_threshold; ++ __le64 pad2; ++ u8 yellow_drop_probability; ++ u8 pad3[7]; ++ __le64 yellow_max_threshold; ++ __le64 yellow_min_threshold; ++}; ++ ++struct dpsw_cmd_if_set_early_drop { ++ /* cmd word 0 */ ++ u8 pad0; ++ u8 tc_id; ++ __le16 if_id; ++ __le32 pad1; ++ /* cmd word 1 */ ++ __le64 early_drop_iova; ++}; ++ ++struct dpsw_cmd_custom_tpid { ++ __le16 pad; ++ __le16 tpid; ++}; ++ ++struct dpsw_cmd_if { ++ __le16 if_id; ++}; ++ ++#define DPSW_ADMIT_UNTAGGED_SHIFT 0 ++#define DPSW_ADMIT_UNTAGGED_SIZE 4 ++#define DPSW_ENABLED_SHIFT 5 ++#define DPSW_ENABLED_SIZE 1 ++#define DPSW_ACCEPT_ALL_VLAN_SHIFT 6 ++#define DPSW_ACCEPT_ALL_VLAN_SIZE 1 ++ ++struct dpsw_rsp_if_get_attr { ++ /* cmd word 0 */ ++ /* from LSB: admit_untagged:4 enabled:1 accept_all_vlan:1 */ ++ u8 conf; ++ u8 pad1; ++ u8 num_tcs; ++ u8 pad2; ++ __le16 qdid; ++ /* cmd word 1 */ ++ __le32 options; ++ __le32 pad3; ++ /* cmd word 2 */ ++ __le32 rate; ++}; ++ ++struct dpsw_cmd_if_set_max_frame_length { ++ __le16 if_id; ++ __le16 frame_length; ++}; ++ ++struct dpsw_cmd_if_get_max_frame_length { ++ __le16 if_id; ++}; ++ ++struct dpsw_rsp_if_get_max_frame_length { ++ __le16 pad; ++ __le16 frame_length; ++}; ++ ++struct dpsw_cmd_if_set_link_cfg { ++ /* cmd word 0 */ ++ __le16 if_id; ++ u8 pad[6]; ++ /* cmd word 1 */ ++ __le32 rate; ++ __le32 pad1; ++ /* cmd word 2 */ ++ __le64 options; ++}; ++ ++struct dpsw_cmd_if_get_link_state { ++ __le16 if_id; ++}; ++ ++#define DPSW_UP_SHIFT 0 ++#define DPSW_UP_SIZE 1 ++ ++struct dpsw_rsp_if_get_link_state { ++ /* cmd word 0 */ ++ __le32 pad0; ++ u8 up; ++ u8 pad1[3]; ++ /* cmd word 1 */ ++ __le32 rate; ++ __le32 pad2; ++ /* cmd word 2 */ ++ __le64 options; ++}; ++ ++struct dpsw_vlan_add { ++ __le16 fdb_id; ++ __le16 vlan_id; ++}; ++ ++struct dpsw_cmd_vlan_manage_if { ++ /* cmd word 0 */ ++ __le16 pad0; ++ __le16 vlan_id; ++ __le32 pad1; ++ /* cmd word 1 */ ++ __le64 if_id[4]; ++}; ++ ++struct dpsw_cmd_vlan_remove { ++ __le16 pad; ++ __le16 vlan_id; ++}; ++ ++struct dpsw_cmd_vlan_get_attr { ++ __le16 vlan_id; ++}; ++ ++struct dpsw_rsp_vlan_get_attr { ++ /* cmd word 0 */ ++ __le64 pad; ++ /* cmd word 1 */ ++ __le16 fdb_id; ++ __le16 num_ifs; ++ __le16 num_untagged_ifs; ++ __le16 num_flooding_ifs; ++}; ++ ++struct dpsw_cmd_vlan_get_if { ++ __le16 vlan_id; ++}; ++ ++struct dpsw_rsp_vlan_get_if { ++ /* cmd word 0 */ ++ __le16 pad0; ++ __le16 num_ifs; ++ u8 pad1[4]; ++ /* cmd word 1 */ ++ __le64 if_id[4]; ++}; ++ ++struct dpsw_cmd_vlan_get_if_untagged { ++ __le16 vlan_id; ++}; ++ ++struct dpsw_rsp_vlan_get_if_untagged { ++ /* cmd word 0 */ ++ __le16 pad0; ++ __le16 num_ifs; ++ u8 pad1[4]; ++ /* cmd word 1 */ ++ __le64 if_id[4]; ++}; ++ ++struct dpsw_cmd_vlan_get_if_flooding { ++ __le16 vlan_id; ++}; ++ ++struct dpsw_rsp_vlan_get_if_flooding { ++ /* cmd word 0 */ ++ __le16 pad0; ++ __le16 num_ifs; ++ u8 pad1[4]; ++ /* cmd word 1 */ ++ __le64 if_id[4]; ++}; ++ ++struct dpsw_cmd_fdb_add { ++ __le32 pad; ++ __le16 fdb_aging_time; ++ __le16 num_fdb_entries; ++}; ++ ++struct dpsw_rsp_fdb_add { ++ __le16 fdb_id; ++}; ++ ++struct dpsw_cmd_fdb_remove { ++ __le16 fdb_id; ++}; ++ ++#define DPSW_ENTRY_TYPE_SHIFT 0 ++#define DPSW_ENTRY_TYPE_SIZE 4 ++ ++struct dpsw_cmd_fdb_add_unicast { ++ /* cmd word 0 */ ++ __le16 fdb_id; ++ u8 mac_addr[6]; ++ /* cmd word 1 */ ++ u8 if_egress; ++ u8 pad; ++ /* only the first 4 bits from LSB */ ++ u8 type; ++}; ++ ++struct dpsw_cmd_fdb_get_unicast { ++ __le16 fdb_id; ++ u8 mac_addr[6]; ++}; ++ ++struct dpsw_rsp_fdb_get_unicast { ++ __le64 pad; ++ __le16 if_egress; ++ /* only first 4 bits from LSB */ ++ u8 type; ++}; ++ ++struct dpsw_cmd_fdb_remove_unicast { ++ /* cmd word 0 */ ++ __le16 fdb_id; ++ u8 mac_addr[6]; ++ /* cmd word 1 */ ++ __le16 if_egress; ++ /* only the first 4 bits from LSB */ ++ u8 type; ++}; ++ ++struct dpsw_cmd_fdb_add_multicast { ++ /* cmd word 0 */ ++ __le16 fdb_id; ++ __le16 num_ifs; ++ /* only the first 4 bits from LSB */ ++ u8 type; ++ u8 pad[3]; ++ /* cmd word 1 */ ++ u8 mac_addr[6]; ++ __le16 pad2; ++ /* cmd word 2 */ ++ __le64 if_id[4]; ++}; ++ ++struct dpsw_cmd_fdb_get_multicast { ++ __le16 fdb_id; ++ u8 mac_addr[6]; ++}; ++ ++struct dpsw_rsp_fdb_get_multicast { ++ /* cmd word 0 */ ++ __le64 pad0; ++ /* cmd word 1 */ ++ __le16 num_ifs; ++ /* only the first 4 bits from LSB */ ++ u8 type; ++ u8 pad1[5]; ++ /* cmd word 2 */ ++ __le64 if_id[4]; ++}; ++ ++struct dpsw_cmd_fdb_remove_multicast { ++ /* cmd word 0 */ ++ __le16 fdb_id; ++ __le16 num_ifs; ++ /* only the first 4 bits from LSB */ ++ u8 type; ++ u8 pad[3]; ++ /* cmd word 1 */ ++ u8 mac_addr[6]; ++ __le16 pad2; ++ /* cmd word 2 */ ++ __le64 if_id[4]; ++}; ++ ++#define DPSW_LEARNING_MODE_SHIFT 0 ++#define DPSW_LEARNING_MODE_SIZE 4 ++ ++struct dpsw_cmd_fdb_set_learning_mode { ++ __le16 fdb_id; ++ /* only the first 4 bits from LSB */ ++ u8 mode; ++}; ++ ++struct dpsw_cmd_fdb_get_attr { ++ __le16 fdb_id; ++}; ++ ++struct dpsw_rsp_fdb_get_attr { ++ /* cmd word 0 */ ++ __le16 pad; ++ __le16 max_fdb_entries; ++ __le16 fdb_aging_time; ++ __le16 num_fdb_mc_groups; ++ /* cmd word 1 */ ++ __le16 max_fdb_mc_groups; ++ /* only the first 4 bits from LSB */ ++ u8 learning_mode; ++}; ++ ++struct dpsw_cmd_acl_add { ++ __le16 pad; ++ __le16 max_entries; ++}; ++ ++struct dpsw_rsp_acl_add { ++ __le16 acl_id; ++}; ++ ++struct dpsw_cmd_acl_remove { ++ __le16 acl_id; ++}; ++ ++struct dpsw_prep_acl_entry { ++ u8 match_l2_dest_mac[6]; ++ __le16 match_l2_tpid; ++ ++ u8 match_l2_source_mac[6]; ++ __le16 match_l2_vlan_id; ++ ++ __le32 match_l3_dest_ip; ++ __le32 match_l3_source_ip; ++ ++ __le16 match_l4_dest_port; ++ __le16 match_l4_source_port; ++ __le16 match_l2_ether_type; ++ u8 match_l2_pcp_dei; ++ u8 match_l3_dscp; ++ ++ u8 mask_l2_dest_mac[6]; ++ __le16 mask_l2_tpid; ++ ++ u8 mask_l2_source_mac[6]; ++ __le16 mask_l2_vlan_id; ++ ++ __le32 mask_l3_dest_ip; ++ __le32 mask_l3_source_ip; ++ ++ __le16 mask_l4_dest_port; ++ __le16 mask_l4_source_port; ++ __le16 mask_l2_ether_type; ++ u8 mask_l2_pcp_dei; ++ u8 mask_l3_dscp; ++ ++ u8 match_l3_protocol; ++ u8 mask_l3_protocol; ++}; ++ ++#define DPSW_RESULT_ACTION_SHIFT 0 ++#define DPSW_RESULT_ACTION_SIZE 4 ++ ++struct dpsw_cmd_acl_entry { ++ __le16 acl_id; ++ __le16 result_if_id; ++ __le32 precedence; ++ /* from LSB only the first 4 bits */ ++ u8 result_action; ++ u8 pad[7]; ++ __le64 pad2[4]; ++ __le64 key_iova; ++}; ++ ++struct dpsw_cmd_acl_if { ++ /* cmd word 0 */ ++ __le16 acl_id; ++ __le16 num_ifs; ++ __le32 pad; ++ /* cmd word 1 */ ++ __le64 if_id[4]; ++}; ++ ++struct dpsw_cmd_acl_get_attr { ++ __le16 acl_id; ++}; ++ ++struct dpsw_rsp_acl_get_attr { ++ /* cmd word 0 */ ++ __le64 pad; ++ /* cmd word 1 */ ++ __le16 max_entries; ++ __le16 num_entries; ++ __le16 num_ifs; ++}; ++ ++struct dpsw_rsp_ctrl_if_get_attr { ++ /* cmd word 0 */ ++ __le64 pad; ++ /* cmd word 1 */ ++ __le32 rx_fqid; ++ __le32 rx_err_fqid; ++ /* cmd word 2 */ ++ __le32 tx_err_conf_fqid; ++}; ++ ++struct dpsw_cmd_ctrl_if_set_pools { ++ u8 num_dpbp; ++ /* from LSB: POOL0_BACKUP_POOL:1 ... POOL7_BACKUP_POOL */ ++ u8 backup_pool; ++ __le16 pad; ++ __le32 dpbp_id[8]; ++ __le16 buffer_size[8]; ++}; ++ ++struct dpsw_rsp_get_api_version { ++ __le16 version_major; ++ __le16 version_minor; ++}; ++ ++#endif /* __FSL_DPSW_CMD_H */ +diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c +new file mode 100644 +index 00000000..179e98c8 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c +@@ -0,0 +1,2762 @@ ++/* Copyright 2013-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#include "../../fsl-mc/include/mc-sys.h" ++#include "../../fsl-mc/include/mc-cmd.h" ++#include "dpsw.h" ++#include "dpsw-cmd.h" ++ ++static void build_if_id_bitmap(__le64 *bmap, ++ const u16 *id, ++ const u16 num_ifs) { ++ int i; ++ ++ for (i = 0; (i < num_ifs) && (i < DPSW_MAX_IF); i++) ++ bmap[id[i] / 64] = dpsw_set_bit(bmap[id[i] / 64], ++ (id[i] % 64), ++ 1); ++} ++ ++static void read_if_id_bitmap(u16 *if_id, ++ u16 *num_ifs, ++ __le64 *bmap) { ++ int bitmap[DPSW_MAX_IF] = { 0 }; ++ int i, j = 0; ++ int count = 0; ++ ++ for (i = 0; i < DPSW_MAX_IF; i++) { ++ bitmap[i] = dpsw_get_bit(le64_to_cpu(bmap[i / 64]), ++ i % 64); ++ count += bitmap[i]; ++ } ++ ++ *num_ifs = (u16)count; ++ ++ for (i = 0; (i < DPSW_MAX_IF) && (j < count); i++) { ++ if (bitmap[i]) { ++ if_id[j] = (u16)i; ++ j++; ++ } ++ } ++} ++ ++/** ++ * dpsw_open() - Open a control session for the specified object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @dpsw_id: DPSW unique ID ++ * @token: Returned token; use in subsequent API calls ++ * ++ * This function can be used to open a control session for an ++ * already created object; an object may have been declared in ++ * the DPL or by calling the dpsw_create() function. ++ * This function returns a unique authentication token, ++ * associated with the specific object ID and the specific MC ++ * portal; this token must be used in all subsequent commands for ++ * this specific object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpsw_id, ++ u16 *token) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_open *cmd_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_OPEN, ++ cmd_flags, ++ 0); ++ cmd_params = (struct dpsw_cmd_open *)cmd.params; ++ cmd_params->dpsw_id = cpu_to_le32(dpsw_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *token = mc_cmd_hdr_read_token(&cmd); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_close() - Close the control session of the object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * ++ * After this function is called, no further operations are ++ * allowed on the object without opening a new control session. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_CLOSE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_enable() - Enable DPSW functionality ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_ENABLE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_disable() - Disable DPSW functionality ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_DISABLE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_is_enabled() - Check if the DPSW is enabled ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @en: Returns '1' if object is enabled; '0' otherwise ++ * ++ * Return: '0' on Success; Error code otherwise ++ */ ++int dpsw_is_enabled(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int *en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_rsp_is_enabled *cmd_rsp; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IS_ENABLED, cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ cmd_rsp = (struct dpsw_rsp_is_enabled *)cmd.params; ++ *en = dpsw_get_field(cmd_rsp->enabled, ENABLE); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_reset() - Reset the DPSW, returns the object to initial state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_reset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_RESET, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_set_irq() - Set IRQ information for the DPSW to trigger an interrupt. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @irq_index: Identifies the interrupt index to configure ++ * @irq_cfg: IRQ configuration ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_set_irq(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ struct dpsw_irq_cfg *irq_cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_set_irq *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_SET_IRQ, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_set_irq *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ cmd_params->irq_val = cpu_to_le32(irq_cfg->val); ++ cmd_params->irq_addr = cpu_to_le64(irq_cfg->addr); ++ cmd_params->irq_num = cpu_to_le32(irq_cfg->irq_num); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_get_irq() - Get IRQ information from the DPSW ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @irq_index: The interrupt index to configure ++ * @type: Interrupt type: 0 represents message interrupt ++ * type (both irq_addr and irq_val are valid) ++ * @irq_cfg: IRQ attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_get_irq(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ int *type, ++ struct dpsw_irq_cfg *irq_cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_get_irq *cmd_params; ++ struct dpsw_rsp_get_irq *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_GET_IRQ, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_get_irq *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_get_irq *)cmd.params; ++ irq_cfg->addr = le64_to_cpu(rsp_params->irq_addr); ++ irq_cfg->val = le32_to_cpu(rsp_params->irq_val); ++ irq_cfg->irq_num = le32_to_cpu(rsp_params->irq_num); ++ *type = le32_to_cpu(rsp_params->irq_type); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_set_irq_enable() - Set overall interrupt state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPCI object ++ * @irq_index: The interrupt index to configure ++ * @en: Interrupt state - enable = 1, disable = 0 ++ * ++ * Allows GPP software to control when interrupts are generated. ++ * Each interrupt can have up to 32 causes. The enable/disable control's the ++ * overall interrupt state. if the interrupt is disabled no causes will cause ++ * an interrupt ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_set_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_set_irq_enable *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_SET_IRQ_ENABLE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_set_irq_enable *)cmd.params; ++ dpsw_set_field(cmd_params->enable_state, ENABLE, en); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_set_irq_mask() - Set interrupt mask. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPCI object ++ * @irq_index: The interrupt index to configure ++ * @mask: Event mask to trigger interrupt; ++ * each bit: ++ * 0 = ignore event ++ * 1 = consider event for asserting IRQ ++ * ++ * Every interrupt can have up to 32 causes and the interrupt model supports ++ * masking/unmasking each cause independently ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_set_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 mask) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_set_irq_mask *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_SET_IRQ_MASK, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_set_irq_mask *)cmd.params; ++ cmd_params->mask = cpu_to_le32(mask); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_get_irq_status() - Get the current status of any pending interrupts ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @irq_index: The interrupt index to configure ++ * @status: Returned interrupts status - one bit per cause: ++ * 0 = no interrupt pending ++ * 1 = interrupt pending ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_get_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *status) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_get_irq_status *cmd_params; ++ struct dpsw_rsp_get_irq_status *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_GET_IRQ_STATUS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_get_irq_status *)cmd.params; ++ cmd_params->status = cpu_to_le32(*status); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_get_irq_status *)cmd.params; ++ *status = le32_to_cpu(rsp_params->status); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_clear_irq_status() - Clear a pending interrupt's status ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPCI object ++ * @irq_index: The interrupt index to configure ++ * @status: bits to clear (W1C) - one bit per cause: ++ * 0 = don't change ++ * 1 = clear status bit ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_clear_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 status) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_clear_irq_status *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_CLEAR_IRQ_STATUS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_clear_irq_status *)cmd.params; ++ cmd_params->status = cpu_to_le32(status); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_get_attributes() - Retrieve DPSW attributes ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @attr: Returned DPSW attributes ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpsw_attr *attr) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_rsp_get_attr *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_GET_ATTR, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_get_attr *)cmd.params; ++ attr->num_ifs = le16_to_cpu(rsp_params->num_ifs); ++ attr->max_fdbs = rsp_params->max_fdbs; ++ attr->num_fdbs = rsp_params->num_fdbs; ++ attr->max_vlans = le16_to_cpu(rsp_params->max_vlans); ++ attr->num_vlans = le16_to_cpu(rsp_params->num_vlans); ++ attr->max_fdb_entries = le16_to_cpu(rsp_params->max_fdb_entries); ++ attr->fdb_aging_time = le16_to_cpu(rsp_params->fdb_aging_time); ++ attr->id = le32_to_cpu(rsp_params->dpsw_id); ++ attr->mem_size = le16_to_cpu(rsp_params->mem_size); ++ attr->max_fdb_mc_groups = le16_to_cpu(rsp_params->max_fdb_mc_groups); ++ attr->max_meters_per_if = rsp_params->max_meters_per_if; ++ attr->options = le64_to_cpu(rsp_params->options); ++ attr->component_type = dpsw_get_field(rsp_params->component_type, ++ COMPONENT_TYPE); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_set_reflection_if() - Set target interface for reflected interfaces. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Id ++ * ++ * Only one reflection receive interface is allowed per switch ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_set_reflection_if(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_set_reflection_if *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_SET_REFLECTION_IF, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_set_reflection_if *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_set_link_cfg() - Set the link configuration. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface id ++ * @cfg: Link configuration ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_set_link_cfg(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ struct dpsw_link_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_set_link_cfg *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_LINK_CFG, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_set_link_cfg *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ cmd_params->rate = cpu_to_le32(cfg->rate); ++ cmd_params->options = cpu_to_le64(cfg->options); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_get_link_state - Return the link state ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface id ++ * @state: Link state 1 - linkup, 0 - link down or disconnected ++ * ++ * @Return '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_get_link_state(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ struct dpsw_link_state *state) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_get_link_state *cmd_params; ++ struct dpsw_rsp_if_get_link_state *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_LINK_STATE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_get_link_state *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_if_get_link_state *)cmd.params; ++ state->rate = le32_to_cpu(rsp_params->rate); ++ state->options = le64_to_cpu(rsp_params->options); ++ state->up = dpsw_get_field(rsp_params->up, UP); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_if_set_flooding() - Enable Disable flooding for particular interface ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @en: 1 - enable, 0 - disable ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_set_flooding(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ int en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_set_flooding *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_FLOODING, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_set_flooding *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ dpsw_set_field(cmd_params->enable, ENABLE, en); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_set_broadcast() - Enable/disable broadcast for particular interface ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @en: 1 - enable, 0 - disable ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_set_broadcast(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ int en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_set_broadcast *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_BROADCAST, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_set_broadcast *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ dpsw_set_field(cmd_params->enable, ENABLE, en); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_set_multicast() - Enable/disable multicast for particular interface ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @en: 1 - enable, 0 - disable ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_set_multicast(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ int en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_set_multicast *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_MULTICAST, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_set_multicast *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ dpsw_set_field(cmd_params->enable, ENABLE, en); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_set_tci() - Set default VLAN Tag Control Information (TCI) ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @cfg: Tag Control Information Configuration ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_set_tci(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpsw_tci_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_set_tci *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_TCI, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_set_tci *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ dpsw_set_field(cmd_params->conf, VLAN_ID, cfg->vlan_id); ++ dpsw_set_field(cmd_params->conf, DEI, cfg->dei); ++ dpsw_set_field(cmd_params->conf, PCP, cfg->pcp); ++ cmd_params->conf = cpu_to_le16(cmd_params->conf); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_get_tci() - Get default VLAN Tag Control Information (TCI) ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @cfg: Tag Control Information Configuration ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_get_tci(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ struct dpsw_tci_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_get_tci *cmd_params; ++ struct dpsw_rsp_if_get_tci *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_TCI, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_get_tci *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_if_get_tci *)cmd.params; ++ cfg->pcp = rsp_params->pcp; ++ cfg->dei = rsp_params->dei; ++ cfg->vlan_id = le16_to_cpu(rsp_params->vlan_id); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_if_set_stp() - Function sets Spanning Tree Protocol (STP) state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @cfg: STP State configuration parameters ++ * ++ * The following STP states are supported - ++ * blocking, listening, learning, forwarding and disabled. ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_set_stp(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpsw_stp_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_set_stp *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_STP, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_set_stp *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ cmd_params->vlan_id = cpu_to_le16(cfg->vlan_id); ++ dpsw_set_field(cmd_params->state, STATE, cfg->state); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_set_accepted_frames() ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @cfg: Frame types configuration ++ * ++ * When is admit_only_vlan_tagged- the device will discard untagged ++ * frames or Priority-Tagged frames received on this interface. ++ * When admit_only_untagged- untagged frames or Priority-Tagged ++ * frames received on this interface will be accepted and assigned ++ * to a VID based on the PVID and VID Set for this interface. ++ * When admit_all - the device will accept VLAN tagged, untagged ++ * and priority tagged frames. ++ * The default is admit_all ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_set_accepted_frames(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpsw_accepted_frames_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_set_accepted_frames *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_ACCEPTED_FRAMES, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_set_accepted_frames *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ dpsw_set_field(cmd_params->unaccepted, FRAME_TYPE, cfg->type); ++ dpsw_set_field(cmd_params->unaccepted, UNACCEPTED_ACT, ++ cfg->unaccept_act); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_set_accept_all_vlan() ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @accept_all: Accept or drop frames having different VLAN ++ * ++ * When this is accept (FALSE), the device will discard incoming ++ * frames for VLANs that do not include this interface in its ++ * Member set. When accept (TRUE), the interface will accept all incoming frames ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_set_accept_all_vlan(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ int accept_all) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_set_accept_all_vlan *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_SET_IF_ACCEPT_ALL_VLAN, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_set_accept_all_vlan *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ dpsw_set_field(cmd_params->accept_all, ACCEPT_ALL, accept_all); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_get_counter() - Get specific counter of particular interface ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @type: Counter type ++ * @counter: return value ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_get_counter(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ enum dpsw_counter type, ++ u64 *counter) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_get_counter *cmd_params; ++ struct dpsw_rsp_if_get_counter *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_COUNTER, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_get_counter *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ dpsw_set_field(cmd_params->type, COUNTER_TYPE, type); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_if_get_counter *)cmd.params; ++ *counter = le64_to_cpu(rsp_params->counter); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_if_set_counter() - Set specific counter of particular interface ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @type: Counter type ++ * @counter: New counter value ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_set_counter(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ enum dpsw_counter type, ++ u64 counter) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_set_counter *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_COUNTER, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_set_counter *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ cmd_params->counter = cpu_to_le64(counter); ++ dpsw_set_field(cmd_params->type, COUNTER_TYPE, type); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_set_tx_selection() - Function is used for mapping variety ++ * of frame fields ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @cfg: Traffic class mapping configuration ++ * ++ * Function is used for mapping variety of frame fields (DSCP, PCP) ++ * to Traffic Class. Traffic class is a number ++ * in the range from 0 to 7 ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_set_tx_selection(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpsw_tx_selection_cfg *cfg) ++{ ++ struct dpsw_cmd_if_set_tx_selection *cmd_params; ++ struct mc_command cmd = { 0 }; ++ int i; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_TX_SELECTION, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_set_tx_selection *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ dpsw_set_field(cmd_params->priority_selector, PRIORITY_SELECTOR, ++ cfg->priority_selector); ++ ++ for (i = 0; i < 8; i++) { ++ cmd_params->tc_sched[i].delta_bandwidth = ++ cpu_to_le16(cfg->tc_sched[i].delta_bandwidth); ++ dpsw_set_field(cmd_params->tc_sched[i].mode, SCHED_MODE, ++ cfg->tc_sched[i].mode); ++ cmd_params->tc_id[i] = cfg->tc_id[i]; ++ } ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_add_reflection() - Identify interface to be reflected or mirrored ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @cfg: Reflection configuration ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_add_reflection(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpsw_reflection_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_reflection *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_ADD_REFLECTION, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_reflection *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ cmd_params->vlan_id = cpu_to_le16(cfg->vlan_id); ++ dpsw_set_field(cmd_params->filter, FILTER, cfg->filter); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_remove_reflection() - Remove interface to be reflected or mirrored ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @cfg: Reflection configuration ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_remove_reflection(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpsw_reflection_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_reflection *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_REMOVE_REFLECTION, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_reflection *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ cmd_params->vlan_id = cpu_to_le16(cfg->vlan_id); ++ dpsw_set_field(cmd_params->filter, FILTER, cfg->filter); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_set_flooding_metering() - Set flooding metering ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @cfg: Metering parameters ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_set_flooding_metering(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpsw_metering_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_set_flooding_metering *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_FLOODING_METERING, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_set_flooding_metering *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ dpsw_set_field(cmd_params->mode_units, MODE, cfg->mode); ++ dpsw_set_field(cmd_params->mode_units, UNITS, cfg->units); ++ cmd_params->cir = cpu_to_le32(cfg->cir); ++ cmd_params->eir = cpu_to_le32(cfg->eir); ++ cmd_params->cbs = cpu_to_le32(cfg->cbs); ++ cmd_params->ebs = cpu_to_le32(cfg->ebs); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_set_metering() - Set interface metering for flooding ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @tc_id: Traffic class ID ++ * @cfg: Metering parameters ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_set_metering(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ u8 tc_id, ++ const struct dpsw_metering_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_set_metering *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_METERING, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_set_metering *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ cmd_params->tc_id = tc_id; ++ dpsw_set_field(cmd_params->mode_units, MODE, cfg->mode); ++ dpsw_set_field(cmd_params->mode_units, UNITS, cfg->units); ++ cmd_params->cir = cpu_to_le32(cfg->cir); ++ cmd_params->eir = cpu_to_le32(cfg->eir); ++ cmd_params->cbs = cpu_to_le32(cfg->cbs); ++ cmd_params->ebs = cpu_to_le32(cfg->ebs); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_prepare_early_drop() - Prepare an early drop for setting in to interface ++ * @cfg: Early-drop configuration ++ * @early_drop_buf: Zeroed 256 bytes of memory before mapping it to DMA ++ * ++ * This function has to be called before dpsw_if_tc_set_early_drop ++ * ++ */ ++void dpsw_prepare_early_drop(const struct dpsw_early_drop_cfg *cfg, ++ u8 *early_drop_buf) ++{ ++ struct dpsw_prep_early_drop *ext_params; ++ ++ ext_params = (struct dpsw_prep_early_drop *)early_drop_buf; ++ dpsw_set_field(ext_params->conf, EARLY_DROP_MODE, cfg->drop_mode); ++ dpsw_set_field(ext_params->conf, EARLY_DROP_UNIT, cfg->units); ++ ext_params->tail_drop_threshold = cpu_to_le32(cfg->tail_drop_threshold); ++ ext_params->green_drop_probability = cfg->green.drop_probability; ++ ext_params->green_max_threshold = cpu_to_le64(cfg->green.max_threshold); ++ ext_params->green_min_threshold = cpu_to_le64(cfg->green.min_threshold); ++ ext_params->yellow_drop_probability = cfg->yellow.drop_probability; ++ ext_params->yellow_max_threshold = ++ cpu_to_le64(cfg->yellow.max_threshold); ++ ext_params->yellow_min_threshold = ++ cpu_to_le64(cfg->yellow.min_threshold); ++} ++ ++/** ++ * dpsw_if_set_early_drop() - Set interface traffic class early-drop ++ * configuration ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @tc_id: Traffic class selection (0-7) ++ * @early_drop_iova: I/O virtual address of 64 bytes; ++ * Must be cacheline-aligned and DMA-able memory ++ * ++ * warning: Before calling this function, call dpsw_prepare_if_tc_early_drop() ++ * to prepare the early_drop_iova parameter ++ * ++ * Return: '0' on Success; error code otherwise. ++ */ ++int dpsw_if_set_early_drop(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ u8 tc_id, ++ u64 early_drop_iova) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_set_early_drop *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_EARLY_DROP, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_set_early_drop *)cmd.params; ++ cmd_params->tc_id = tc_id; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ cmd_params->early_drop_iova = cpu_to_le64(early_drop_iova); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_add_custom_tpid() - API Configures a distinct Ethernet type value ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @cfg: Tag Protocol identifier ++ * ++ * API Configures a distinct Ethernet type value (or TPID value) ++ * to indicate a VLAN tag in addition to the common ++ * TPID values 0x8100 and 0x88A8. ++ * Two additional TPID's are supported ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_add_custom_tpid(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const struct dpsw_custom_tpid_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_custom_tpid *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_ADD_CUSTOM_TPID, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_custom_tpid *)cmd.params; ++ cmd_params->tpid = cpu_to_le16(cfg->tpid); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_remove_custom_tpid - API removes a distinct Ethernet type value ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @cfg: Tag Protocol identifier ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_remove_custom_tpid(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const struct dpsw_custom_tpid_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_custom_tpid *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_REMOVE_CUSTOM_TPID, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_custom_tpid *)cmd.params; ++ cmd_params->tpid = cpu_to_le16(cfg->tpid); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_enable() - Enable Interface ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_ENABLE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_disable() - Disable Interface ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_DISABLE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_get_attributes() - Function obtains attributes of interface ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @attr: Returned interface attributes ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ struct dpsw_if_attr *attr) ++{ ++ struct dpsw_rsp_if_get_attr *rsp_params; ++ struct dpsw_cmd_if *cmd_params; ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_ATTR, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_if_get_attr *)cmd.params; ++ attr->num_tcs = rsp_params->num_tcs; ++ attr->rate = le32_to_cpu(rsp_params->rate); ++ attr->options = le32_to_cpu(rsp_params->options); ++ attr->enabled = dpsw_get_field(rsp_params->conf, ENABLED); ++ attr->accept_all_vlan = dpsw_get_field(rsp_params->conf, ++ ACCEPT_ALL_VLAN); ++ attr->admit_untagged = dpsw_get_field(rsp_params->conf, ADMIT_UNTAGGED); ++ attr->qdid = le16_to_cpu(rsp_params->qdid); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_if_set_max_frame_length() - Set Maximum Receive frame length. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @frame_length: Maximum Frame Length ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_set_max_frame_length(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ u16 frame_length) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_set_max_frame_length *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_MAX_FRAME_LENGTH, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_set_max_frame_length *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ cmd_params->frame_length = cpu_to_le16(frame_length); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_if_get_max_frame_length() - Get Maximum Receive frame length. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: Interface Identifier ++ * @frame_length: Returned maximum Frame Length ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_if_get_max_frame_length(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ u16 *frame_length) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_if_get_max_frame_length *cmd_params; ++ struct dpsw_rsp_if_get_max_frame_length *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_MAX_FRAME_LENGTH, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_if_get_max_frame_length *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ rsp_params = (struct dpsw_rsp_if_get_max_frame_length *)cmd.params; ++ *frame_length = le16_to_cpu(rsp_params->frame_length); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_vlan_add() - Adding new VLAN to DPSW. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @vlan_id: VLAN Identifier ++ * @cfg: VLAN configuration ++ * ++ * Only VLAN ID and FDB ID are required parameters here. ++ * 12 bit VLAN ID is defined in IEEE802.1Q. ++ * Adding a duplicate VLAN ID is not allowed. ++ * FDB ID can be shared across multiple VLANs. Shared learning ++ * is obtained by calling dpsw_vlan_add for multiple VLAN IDs ++ * with same fdb_id ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_vlan_add(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ const struct dpsw_vlan_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_vlan_add *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_ADD, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_vlan_add *)cmd.params; ++ cmd_params->fdb_id = cpu_to_le16(cfg->fdb_id); ++ cmd_params->vlan_id = cpu_to_le16(vlan_id); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_vlan_add_if() - Adding a set of interfaces to an existing VLAN. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @vlan_id: VLAN Identifier ++ * @cfg: Set of interfaces to add ++ * ++ * It adds only interfaces not belonging to this VLAN yet, ++ * otherwise an error is generated and an entire command is ++ * ignored. This function can be called numerous times always ++ * providing required interfaces delta. ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_vlan_add_if(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ const struct dpsw_vlan_if_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_vlan_manage_if *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_ADD_IF, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; ++ cmd_params->vlan_id = cpu_to_le16(vlan_id); ++ build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_vlan_add_if_untagged() - Defining a set of interfaces that should be ++ * transmitted as untagged. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @vlan_id: VLAN Identifier ++ * @cfg: Set of interfaces that should be transmitted as untagged ++ * ++ * These interfaces should already belong to this VLAN. ++ * By default all interfaces are transmitted as tagged. ++ * Providing un-existing interface or untagged interface that is ++ * configured untagged already generates an error and the entire ++ * command is ignored. ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_vlan_add_if_untagged(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ const struct dpsw_vlan_if_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_vlan_manage_if *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_ADD_IF_UNTAGGED, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; ++ cmd_params->vlan_id = cpu_to_le16(vlan_id); ++ build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_vlan_add_if_flooding() - Define a set of interfaces that should be ++ * included in flooding when frame with unknown destination ++ * unicast MAC arrived. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @vlan_id: VLAN Identifier ++ * @cfg: Set of interfaces that should be used for flooding ++ * ++ * These interfaces should belong to this VLAN. By default all ++ * interfaces are included into flooding list. Providing ++ * un-existing interface or an interface that already in the ++ * flooding list generates an error and the entire command is ++ * ignored. ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_vlan_add_if_flooding(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ const struct dpsw_vlan_if_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_vlan_manage_if *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_ADD_IF_FLOODING, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; ++ cmd_params->vlan_id = cpu_to_le16(vlan_id); ++ build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_vlan_remove_if() - Remove interfaces from an existing VLAN. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @vlan_id: VLAN Identifier ++ * @cfg: Set of interfaces that should be removed ++ * ++ * Interfaces must belong to this VLAN, otherwise an error ++ * is returned and an the command is ignored ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_vlan_remove_if(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ const struct dpsw_vlan_if_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_vlan_manage_if *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_REMOVE_IF, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; ++ cmd_params->vlan_id = cpu_to_le16(vlan_id); ++ build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_vlan_remove_if_untagged() - Define a set of interfaces that should be ++ * converted from transmitted as untagged to transmit as tagged. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @vlan_id: VLAN Identifier ++ * @cfg: Set of interfaces that should be removed ++ * ++ * Interfaces provided by API have to belong to this VLAN and ++ * configured untagged, otherwise an error is returned and the ++ * command is ignored ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_vlan_remove_if_untagged(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ const struct dpsw_vlan_if_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_vlan_manage_if *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_REMOVE_IF_UNTAGGED, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; ++ cmd_params->vlan_id = cpu_to_le16(vlan_id); ++ build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_vlan_remove_if_flooding() - Define a set of interfaces that should be ++ * removed from the flooding list. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @vlan_id: VLAN Identifier ++ * @cfg: Set of interfaces used for flooding ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_vlan_remove_if_flooding(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ const struct dpsw_vlan_if_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_vlan_manage_if *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_REMOVE_IF_FLOODING, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_vlan_manage_if *)cmd.params; ++ cmd_params->vlan_id = cpu_to_le16(vlan_id); ++ build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_vlan_remove() - Remove an entire VLAN ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @vlan_id: VLAN Identifier ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_vlan_remove(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_vlan_remove *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_REMOVE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_vlan_remove *)cmd.params; ++ cmd_params->vlan_id = cpu_to_le16(vlan_id); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_vlan_get_attributes() - Get VLAN attributes ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @vlan_id: VLAN Identifier ++ * @attr: Returned DPSW attributes ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_vlan_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ struct dpsw_vlan_attr *attr) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_vlan_get_attr *cmd_params; ++ struct dpsw_rsp_vlan_get_attr *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_GET_ATTRIBUTES, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_vlan_get_attr *)cmd.params; ++ cmd_params->vlan_id = cpu_to_le16(vlan_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_vlan_get_attr *)cmd.params; ++ attr->fdb_id = le16_to_cpu(rsp_params->fdb_id); ++ attr->num_ifs = le16_to_cpu(rsp_params->num_ifs); ++ attr->num_untagged_ifs = le16_to_cpu(rsp_params->num_untagged_ifs); ++ attr->num_flooding_ifs = le16_to_cpu(rsp_params->num_flooding_ifs); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_vlan_get_if() - Get interfaces belong to this VLAN ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @vlan_id: VLAN Identifier ++ * @cfg: Returned set of interfaces belong to this VLAN ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_vlan_get_if(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ struct dpsw_vlan_if_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_vlan_get_if *cmd_params; ++ struct dpsw_rsp_vlan_get_if *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_GET_IF, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_vlan_get_if *)cmd.params; ++ cmd_params->vlan_id = cpu_to_le16(vlan_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_vlan_get_if *)cmd.params; ++ cfg->num_ifs = le16_to_cpu(rsp_params->num_ifs); ++ read_if_id_bitmap(cfg->if_id, &cfg->num_ifs, rsp_params->if_id); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_vlan_get_if_flooding() - Get interfaces used in flooding for this VLAN ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @vlan_id: VLAN Identifier ++ * @cfg: Returned set of flooding interfaces ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++ ++int dpsw_vlan_get_if_flooding(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ struct dpsw_vlan_if_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_vlan_get_if_flooding *cmd_params; ++ struct dpsw_rsp_vlan_get_if_flooding *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_GET_IF_FLOODING, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_vlan_get_if_flooding *)cmd.params; ++ cmd_params->vlan_id = cpu_to_le16(vlan_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_vlan_get_if_flooding *)cmd.params; ++ cfg->num_ifs = le16_to_cpu(rsp_params->num_ifs); ++ read_if_id_bitmap(cfg->if_id, &cfg->num_ifs, rsp_params->if_id); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_vlan_get_if_untagged() - Get interfaces that should be transmitted as ++ * untagged ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @vlan_id: VLAN Identifier ++ * @cfg: Returned set of untagged interfaces ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_vlan_get_if_untagged(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ struct dpsw_vlan_if_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_vlan_get_if_untagged *cmd_params; ++ struct dpsw_rsp_vlan_get_if_untagged *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_VLAN_GET_IF_UNTAGGED, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_vlan_get_if_untagged *)cmd.params; ++ cmd_params->vlan_id = cpu_to_le16(vlan_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_vlan_get_if_untagged *)cmd.params; ++ cfg->num_ifs = le16_to_cpu(rsp_params->num_ifs); ++ read_if_id_bitmap(cfg->if_id, &cfg->num_ifs, rsp_params->if_id); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_fdb_add() - Add FDB to switch and Returns handle to FDB table for ++ * the reference ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @fdb_id: Returned Forwarding Database Identifier ++ * @cfg: FDB Configuration ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_fdb_add(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 *fdb_id, ++ const struct dpsw_fdb_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_fdb_add *cmd_params; ++ struct dpsw_rsp_fdb_add *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_ADD, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_fdb_add *)cmd.params; ++ cmd_params->fdb_aging_time = cpu_to_le16(cfg->fdb_aging_time); ++ cmd_params->num_fdb_entries = cpu_to_le16(cfg->num_fdb_entries); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_fdb_add *)cmd.params; ++ *fdb_id = le16_to_cpu(rsp_params->fdb_id); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_fdb_remove() - Remove FDB from switch ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @fdb_id: Forwarding Database Identifier ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_fdb_remove(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_fdb_remove *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_REMOVE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_fdb_remove *)cmd.params; ++ cmd_params->fdb_id = cpu_to_le16(fdb_id); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_fdb_add_unicast() - Function adds an unicast entry into MAC lookup table ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @fdb_id: Forwarding Database Identifier ++ * @cfg: Unicast entry configuration ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_fdb_add_unicast(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id, ++ const struct dpsw_fdb_unicast_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_fdb_add_unicast *cmd_params; ++ int i; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_ADD_UNICAST, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_fdb_add_unicast *)cmd.params; ++ cmd_params->fdb_id = cpu_to_le16(fdb_id); ++ cmd_params->if_egress = cpu_to_le16(cfg->if_egress); ++ for (i = 0; i < 6; i++) ++ cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; ++ dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_fdb_get_unicast() - Get unicast entry from MAC lookup table by ++ * unicast Ethernet address ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @fdb_id: Forwarding Database Identifier ++ * @cfg: Returned unicast entry configuration ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_fdb_get_unicast(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id, ++ struct dpsw_fdb_unicast_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_fdb_get_unicast *cmd_params; ++ struct dpsw_rsp_fdb_get_unicast *rsp_params; ++ int err, i; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_GET_UNICAST, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_fdb_get_unicast *)cmd.params; ++ cmd_params->fdb_id = cpu_to_le16(fdb_id); ++ for (i = 0; i < 6; i++) ++ cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_fdb_get_unicast *)cmd.params; ++ cfg->if_egress = le16_to_cpu(rsp_params->if_egress); ++ cfg->type = dpsw_get_field(rsp_params->type, ENTRY_TYPE); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_fdb_remove_unicast() - removes an entry from MAC lookup table ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @fdb_id: Forwarding Database Identifier ++ * @cfg: Unicast entry configuration ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_fdb_remove_unicast(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id, ++ const struct dpsw_fdb_unicast_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_fdb_remove_unicast *cmd_params; ++ int i; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_REMOVE_UNICAST, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_fdb_remove_unicast *)cmd.params; ++ cmd_params->fdb_id = cpu_to_le16(fdb_id); ++ for (i = 0; i < 6; i++) ++ cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; ++ cmd_params->if_egress = cpu_to_le16(cfg->if_egress); ++ dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_fdb_add_multicast() - Add a set of egress interfaces to multi-cast group ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @fdb_id: Forwarding Database Identifier ++ * @cfg: Multicast entry configuration ++ * ++ * If group doesn't exist, it will be created. ++ * It adds only interfaces not belonging to this multicast group ++ * yet, otherwise error will be generated and the command is ++ * ignored. ++ * This function may be called numerous times always providing ++ * required interfaces delta. ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_fdb_add_multicast(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id, ++ const struct dpsw_fdb_multicast_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_fdb_add_multicast *cmd_params; ++ int i; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_ADD_MULTICAST, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_fdb_add_multicast *)cmd.params; ++ cmd_params->fdb_id = cpu_to_le16(fdb_id); ++ cmd_params->num_ifs = cpu_to_le16(cfg->num_ifs); ++ dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type); ++ build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); ++ for (i = 0; i < 6; i++) ++ cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_fdb_get_multicast() - Reading multi-cast group by multi-cast Ethernet ++ * address. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @fdb_id: Forwarding Database Identifier ++ * @cfg: Returned multicast entry configuration ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_fdb_get_multicast(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id, ++ struct dpsw_fdb_multicast_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_fdb_get_multicast *cmd_params; ++ struct dpsw_rsp_fdb_get_multicast *rsp_params; ++ int err, i; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_GET_MULTICAST, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_fdb_get_multicast *)cmd.params; ++ cmd_params->fdb_id = cpu_to_le16(fdb_id); ++ for (i = 0; i < 6; i++) ++ cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_fdb_get_multicast *)cmd.params; ++ cfg->num_ifs = le16_to_cpu(rsp_params->num_ifs); ++ cfg->type = dpsw_get_field(rsp_params->type, ENTRY_TYPE); ++ read_if_id_bitmap(cfg->if_id, &cfg->num_ifs, rsp_params->if_id); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_fdb_remove_multicast() - Removing interfaces from an existing multicast ++ * group. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @fdb_id: Forwarding Database Identifier ++ * @cfg: Multicast entry configuration ++ * ++ * Interfaces provided by this API have to exist in the group, ++ * otherwise an error will be returned and an entire command ++ * ignored. If there is no interface left in the group, ++ * an entire group is deleted ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_fdb_remove_multicast(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id, ++ const struct dpsw_fdb_multicast_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_fdb_remove_multicast *cmd_params; ++ int i; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_REMOVE_MULTICAST, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_fdb_remove_multicast *)cmd.params; ++ cmd_params->fdb_id = cpu_to_le16(fdb_id); ++ cmd_params->num_ifs = cpu_to_le16(cfg->num_ifs); ++ dpsw_set_field(cmd_params->type, ENTRY_TYPE, cfg->type); ++ build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); ++ for (i = 0; i < 6; i++) ++ cmd_params->mac_addr[i] = cfg->mac_addr[5 - i]; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_fdb_set_learning_mode() - Define FDB learning mode ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @fdb_id: Forwarding Database Identifier ++ * @mode: Learning mode ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_fdb_set_learning_mode(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id, ++ enum dpsw_fdb_learning_mode mode) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_fdb_set_learning_mode *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_SET_LEARNING_MODE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_fdb_set_learning_mode *)cmd.params; ++ cmd_params->fdb_id = cpu_to_le16(fdb_id); ++ dpsw_set_field(cmd_params->mode, LEARNING_MODE, mode); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_fdb_get_attributes() - Get FDB attributes ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @fdb_id: Forwarding Database Identifier ++ * @attr: Returned FDB attributes ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpsw_fdb_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id, ++ struct dpsw_fdb_attr *attr) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_fdb_get_attr *cmd_params; ++ struct dpsw_rsp_fdb_get_attr *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_GET_ATTR, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_fdb_get_attr *)cmd.params; ++ cmd_params->fdb_id = cpu_to_le16(fdb_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_fdb_get_attr *)cmd.params; ++ attr->max_fdb_entries = le16_to_cpu(rsp_params->max_fdb_entries); ++ attr->fdb_aging_time = le16_to_cpu(rsp_params->fdb_aging_time); ++ attr->learning_mode = dpsw_get_field(rsp_params->learning_mode, ++ LEARNING_MODE); ++ attr->num_fdb_mc_groups = le16_to_cpu(rsp_params->num_fdb_mc_groups); ++ attr->max_fdb_mc_groups = le16_to_cpu(rsp_params->max_fdb_mc_groups); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_acl_add() - Adds ACL to L2 switch. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @acl_id: Returned ACL ID, for the future reference ++ * @cfg: ACL configuration ++ * ++ * Create Access Control List. Multiple ACLs can be created and ++ * co-exist in L2 switch ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_acl_add(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 *acl_id, ++ const struct dpsw_acl_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_acl_add *cmd_params; ++ struct dpsw_rsp_acl_add *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_ACL_ADD, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_acl_add *)cmd.params; ++ cmd_params->max_entries = cpu_to_le16(cfg->max_entries); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_acl_add *)cmd.params; ++ *acl_id = le16_to_cpu(rsp_params->acl_id); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_acl_remove() - Removes ACL from L2 switch. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @acl_id: ACL ID ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_acl_remove(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 acl_id) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_acl_remove *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_ACL_REMOVE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_acl_remove *)cmd.params; ++ cmd_params->acl_id = cpu_to_le16(acl_id); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_acl_prepare_entry_cfg() - Set an entry to ACL. ++ * @key: Key ++ * @entry_cfg_buf: Zeroed 256 bytes of memory before mapping it to DMA ++ * ++ * This function has to be called before adding or removing acl_entry ++ * ++ */ ++void dpsw_acl_prepare_entry_cfg(const struct dpsw_acl_key *key, ++ u8 *entry_cfg_buf) ++{ ++ struct dpsw_prep_acl_entry *ext_params; ++ int i; ++ ++ ext_params = (struct dpsw_prep_acl_entry *)entry_cfg_buf; ++ ++ for (i = 0; i < 6; i++) { ++ ext_params->match_l2_dest_mac[i] = ++ key->match.l2_dest_mac[5 - i]; ++ ext_params->match_l2_source_mac[i] = ++ key->match.l2_source_mac[5 - i]; ++ ext_params->mask_l2_dest_mac[i] = ++ key->mask.l2_dest_mac[5 - i]; ++ ext_params->mask_l2_source_mac[i] = ++ key->mask.l2_source_mac[5 - i]; ++ } ++ ++ ext_params->match_l2_tpid = cpu_to_le16(key->match.l2_tpid); ++ ext_params->match_l2_vlan_id = cpu_to_le16(key->match.l2_vlan_id); ++ ext_params->match_l3_dest_ip = cpu_to_le32(key->match.l3_dest_ip); ++ ext_params->match_l3_source_ip = cpu_to_le32(key->match.l3_source_ip); ++ ext_params->match_l4_dest_port = cpu_to_le16(key->match.l4_dest_port); ++ ext_params->match_l2_ether_type = cpu_to_le16(key->match.l2_ether_type); ++ ext_params->match_l2_pcp_dei = key->match.l2_pcp_dei; ++ ext_params->match_l3_dscp = key->match.l3_dscp; ++ ext_params->match_l4_source_port = ++ cpu_to_le16(key->match.l4_source_port); ++ ++ ext_params->mask_l2_tpid = cpu_to_le16(key->mask.l2_tpid); ++ ext_params->mask_l2_vlan_id = cpu_to_le16(key->mask.l2_vlan_id); ++ ext_params->mask_l3_dest_ip = cpu_to_le32(key->mask.l3_dest_ip); ++ ext_params->mask_l3_source_ip = cpu_to_le32(key->mask.l3_source_ip); ++ ext_params->mask_l4_dest_port = cpu_to_le16(key->mask.l4_dest_port); ++ ext_params->mask_l4_source_port = cpu_to_le16(key->mask.l4_source_port); ++ ext_params->mask_l2_ether_type = cpu_to_le16(key->mask.l2_ether_type); ++ ext_params->mask_l2_pcp_dei = key->mask.l2_pcp_dei; ++ ext_params->mask_l3_dscp = key->mask.l3_dscp; ++ ext_params->match_l3_protocol = key->match.l3_protocol; ++ ext_params->mask_l3_protocol = key->mask.l3_protocol; ++} ++ ++/** ++ * dpsw_acl_add_entry() - Adds an entry to ACL. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @acl_id: ACL ID ++ * @cfg: Entry configuration ++ * ++ * warning: This function has to be called after dpsw_acl_set_entry_cfg() ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_acl_add_entry(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 acl_id, ++ const struct dpsw_acl_entry_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_acl_entry *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_ACL_ADD_ENTRY, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_acl_entry *)cmd.params; ++ cmd_params->acl_id = cpu_to_le16(acl_id); ++ cmd_params->result_if_id = cpu_to_le16(cfg->result.if_id); ++ cmd_params->precedence = cpu_to_le32(cfg->precedence); ++ dpsw_set_field(cmd_params->result_action, RESULT_ACTION, ++ cfg->result.action); ++ cmd_params->key_iova = cpu_to_le64(cfg->key_iova); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_acl_remove_entry() - Removes an entry from ACL. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @acl_id: ACL ID ++ * @cfg: Entry configuration ++ * ++ * warning: This function has to be called after dpsw_acl_set_entry_cfg() ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_acl_remove_entry(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 acl_id, ++ const struct dpsw_acl_entry_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_acl_entry *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_ACL_REMOVE_ENTRY, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_acl_entry *)cmd.params; ++ cmd_params->acl_id = cpu_to_le16(acl_id); ++ cmd_params->result_if_id = cpu_to_le16(cfg->result.if_id); ++ cmd_params->precedence = cpu_to_le32(cfg->precedence); ++ dpsw_set_field(cmd_params->result_action, RESULT_ACTION, ++ cfg->result.action); ++ cmd_params->key_iova = cpu_to_le64(cfg->key_iova); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_acl_add_if() - Associate interface/interfaces with ACL. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @acl_id: ACL ID ++ * @cfg: Interfaces list ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_acl_add_if(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 acl_id, ++ const struct dpsw_acl_if_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_acl_if *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_ACL_ADD_IF, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_acl_if *)cmd.params; ++ cmd_params->acl_id = cpu_to_le16(acl_id); ++ cmd_params->num_ifs = cpu_to_le16(cfg->num_ifs); ++ build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_acl_remove_if() - De-associate interface/interfaces from ACL. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @acl_id: ACL ID ++ * @cfg: Interfaces list ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_acl_remove_if(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 acl_id, ++ const struct dpsw_acl_if_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_acl_if *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_ACL_REMOVE_IF, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_acl_if *)cmd.params; ++ cmd_params->acl_id = cpu_to_le16(acl_id); ++ cmd_params->num_ifs = cpu_to_le16(cfg->num_ifs); ++ build_if_id_bitmap(cmd_params->if_id, cfg->if_id, cfg->num_ifs); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_acl_get_attributes() - Get specific counter of particular interface ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @acl_id: ACL Identifier ++ * @attr: Returned ACL attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_acl_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 acl_id, ++ struct dpsw_acl_attr *attr) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_acl_get_attr *cmd_params; ++ struct dpsw_rsp_acl_get_attr *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_ACL_GET_ATTR, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_acl_get_attr *)cmd.params; ++ cmd_params->acl_id = cpu_to_le16(acl_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_acl_get_attr *)cmd.params; ++ attr->max_entries = le16_to_cpu(rsp_params->max_entries); ++ attr->num_entries = le16_to_cpu(rsp_params->num_entries); ++ attr->num_ifs = le16_to_cpu(rsp_params->num_ifs); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_ctrl_if_get_attributes() - Obtain control interface attributes ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @attr: Returned control interface attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_ctrl_if_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpsw_ctrl_if_attr *attr) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_rsp_ctrl_if_get_attr *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_CTRL_IF_GET_ATTR, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpsw_rsp_ctrl_if_get_attr *)cmd.params; ++ attr->rx_fqid = le32_to_cpu(rsp_params->rx_fqid); ++ attr->rx_err_fqid = le32_to_cpu(rsp_params->rx_err_fqid); ++ attr->tx_err_conf_fqid = le32_to_cpu(rsp_params->tx_err_conf_fqid); ++ ++ return 0; ++} ++ ++/** ++ * dpsw_ctrl_if_set_pools() - Set control interface buffer pools ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @cfg: Buffer pools configuration ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_ctrl_if_set_pools(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const struct dpsw_ctrl_if_pools_cfg *pools) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_cmd_ctrl_if_set_pools *cmd_params; ++ int i; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_CTRL_IF_SET_POOLS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpsw_cmd_ctrl_if_set_pools *)cmd.params; ++ cmd_params->num_dpbp = pools->num_dpbp; ++ for (i = 0; i < 8; i++) { ++ cmd_params->backup_pool = dpsw_set_bit(cmd_params->backup_pool, ++ i, ++ pools->pools[i].backup_pool); ++ cmd_params->buffer_size[i] = ++ cpu_to_le16(pools->pools[i].buffer_size); ++ cmd_params->dpbp_id[i] = ++ cpu_to_le32(pools->pools[i].dpbp_id); ++ } ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_ctrl_if_enable() - Enable control interface ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_ctrl_if_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_CTRL_IF_ENABLE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_ctrl_if_disable() - Function disables control interface ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_ctrl_if_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_CTRL_IF_DISABLE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpsw_get_api_version() - Get Data Path Switch API version ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @major_ver: Major version of data path switch API ++ * @minor_ver: Minor version of data path switch API ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpsw_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpsw_rsp_get_api_version *rsp_params; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header(DPSW_CMDID_GET_API_VERSION, ++ cmd_flags, ++ 0); ++ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ rsp_params = (struct dpsw_rsp_get_api_version *)cmd.params; ++ *major_ver = le16_to_cpu(rsp_params->version_major); ++ *minor_ver = le16_to_cpu(rsp_params->version_minor); ++ ++ return 0; ++} +diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h +new file mode 100644 +index 00000000..c91abeb4 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h +@@ -0,0 +1,1269 @@ ++/* Copyright 2013-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef __FSL_DPSW_H ++#define __FSL_DPSW_H ++ ++/* Data Path L2-Switch API ++ * Contains API for handling DPSW topology and functionality ++ */ ++ ++struct fsl_mc_io; ++ ++/** ++ * DPSW general definitions ++ */ ++ ++/** ++ * Maximum number of traffic class priorities ++ */ ++#define DPSW_MAX_PRIORITIES 8 ++/** ++ * Maximum number of interfaces ++ */ ++#define DPSW_MAX_IF 64 ++ ++int dpsw_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpsw_id, ++ u16 *token); ++ ++int dpsw_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++/** ++ * DPSW options ++ */ ++ ++/** ++ * Disable flooding ++ */ ++#define DPSW_OPT_FLOODING_DIS 0x0000000000000001ULL ++/** ++ * Disable Multicast ++ */ ++#define DPSW_OPT_MULTICAST_DIS 0x0000000000000004ULL ++/** ++ * Support control interface ++ */ ++#define DPSW_OPT_CTRL_IF_DIS 0x0000000000000010ULL ++/** ++ * Disable flooding metering ++ */ ++#define DPSW_OPT_FLOODING_METERING_DIS 0x0000000000000020ULL ++/** ++ * Enable metering ++ */ ++#define DPSW_OPT_METERING_EN 0x0000000000000040ULL ++ ++/** ++ * enum dpsw_component_type - component type of a bridge ++ * @DPSW_COMPONENT_TYPE_C_VLAN: A C-VLAN component of an ++ * enterprise VLAN bridge or of a Provider Bridge used ++ * to process C-tagged frames ++ * @DPSW_COMPONENT_TYPE_S_VLAN: An S-VLAN component of a ++ * Provider Bridge ++ * ++ */ ++enum dpsw_component_type { ++ DPSW_COMPONENT_TYPE_C_VLAN = 0, ++ DPSW_COMPONENT_TYPE_S_VLAN ++}; ++ ++/** ++ * struct dpsw_cfg - DPSW configuration ++ * @num_ifs: Number of external and internal interfaces ++ * @adv: Advanced parameters; default is all zeros; ++ * use this structure to change default settings ++ */ ++struct dpsw_cfg { ++ u16 num_ifs; ++ /** ++ * struct adv - Advanced parameters ++ * @options: Enable/Disable DPSW features (bitmap) ++ * @max_vlans: Maximum Number of VLAN's; 0 - indicates default 16 ++ * @max_meters_per_if: Number of meters per interface ++ * @max_fdbs: Maximum Number of FDB's; 0 - indicates default 16 ++ * @max_fdb_entries: Number of FDB entries for default FDB table; ++ * 0 - indicates default 1024 entries. ++ * @fdb_aging_time: Default FDB aging time for default FDB table; ++ * 0 - indicates default 300 seconds ++ * @max_fdb_mc_groups: Number of multicast groups in each FDB table; ++ * 0 - indicates default 32 ++ * @component_type: Indicates the component type of this bridge ++ */ ++ struct { ++ u64 options; ++ u16 max_vlans; ++ u8 max_meters_per_if; ++ u8 max_fdbs; ++ u16 max_fdb_entries; ++ u16 fdb_aging_time; ++ u16 max_fdb_mc_groups; ++ enum dpsw_component_type component_type; ++ } adv; ++}; ++ ++int dpsw_create(struct fsl_mc_io *mc_io, ++ u16 dprc_token, ++ u32 cmd_flags, ++ const struct dpsw_cfg *cfg, ++ u32 *obj_id); ++ ++int dpsw_destroy(struct fsl_mc_io *mc_io, ++ u16 dprc_token, ++ u32 cmd_flags, ++ u32 object_id); ++ ++int dpsw_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpsw_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpsw_is_enabled(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int *en); ++ ++int dpsw_reset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++/** ++ * DPSW IRQ Index and Events ++ */ ++ ++#define DPSW_IRQ_INDEX_IF 0x0000 ++#define DPSW_IRQ_INDEX_L2SW 0x0001 ++ ++/** ++ * IRQ event - Indicates that the link state changed ++ */ ++#define DPSW_IRQ_EVENT_LINK_CHANGED 0x0001 ++ ++/** ++ * struct dpsw_irq_cfg - IRQ configuration ++ * @addr: Address that must be written to signal a message-based interrupt ++ * @val: Value to write into irq_addr address ++ * @irq_num: A user defined number associated with this IRQ ++ */ ++struct dpsw_irq_cfg { ++ u64 addr; ++ u32 val; ++ int irq_num; ++}; ++ ++int dpsw_set_irq(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ struct dpsw_irq_cfg *irq_cfg); ++ ++int dpsw_get_irq(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ int *type, ++ struct dpsw_irq_cfg *irq_cfg); ++ ++int dpsw_set_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 en); ++ ++int dpsw_get_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 *en); ++ ++int dpsw_set_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 mask); ++ ++int dpsw_get_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *mask); ++ ++int dpsw_get_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *status); ++ ++int dpsw_clear_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 status); ++ ++/** ++ * struct dpsw_attr - Structure representing DPSW attributes ++ * @id: DPSW object ID ++ * @options: Enable/Disable DPSW features ++ * @max_vlans: Maximum Number of VLANs ++ * @max_meters_per_if: Number of meters per interface ++ * @max_fdbs: Maximum Number of FDBs ++ * @max_fdb_entries: Number of FDB entries for default FDB table; ++ * 0 - indicates default 1024 entries. ++ * @fdb_aging_time: Default FDB aging time for default FDB table; ++ * 0 - indicates default 300 seconds ++ * @max_fdb_mc_groups: Number of multicast groups in each FDB table; ++ * 0 - indicates default 32 ++ * @mem_size: DPSW frame storage memory size ++ * @num_ifs: Number of interfaces ++ * @num_vlans: Current number of VLANs ++ * @num_fdbs: Current number of FDBs ++ * @component_type: Component type of this bridge ++ */ ++struct dpsw_attr { ++ int id; ++ u64 options; ++ u16 max_vlans; ++ u8 max_meters_per_if; ++ u8 max_fdbs; ++ u16 max_fdb_entries; ++ u16 fdb_aging_time; ++ u16 max_fdb_mc_groups; ++ u16 num_ifs; ++ u16 mem_size; ++ u16 num_vlans; ++ u8 num_fdbs; ++ enum dpsw_component_type component_type; ++}; ++ ++int dpsw_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpsw_attr *attr); ++ ++int dpsw_set_reflection_if(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id); ++ ++/** ++ * enum dpsw_action - Action selection for special/control frames ++ * @DPSW_ACTION_DROP: Drop frame ++ * @DPSW_ACTION_REDIRECT: Redirect frame to control port ++ */ ++enum dpsw_action { ++ DPSW_ACTION_DROP = 0, ++ DPSW_ACTION_REDIRECT = 1 ++}; ++ ++/** ++ * Enable auto-negotiation ++ */ ++#define DPSW_LINK_OPT_AUTONEG 0x0000000000000001ULL ++/** ++ * Enable half-duplex mode ++ */ ++#define DPSW_LINK_OPT_HALF_DUPLEX 0x0000000000000002ULL ++/** ++ * Enable pause frames ++ */ ++#define DPSW_LINK_OPT_PAUSE 0x0000000000000004ULL ++/** ++ * Enable a-symmetric pause frames ++ */ ++#define DPSW_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL ++ ++/** ++ * struct dpsw_link_cfg - Structure representing DPSW link configuration ++ * @rate: Rate ++ * @options: Mask of available options; use 'DPSW_LINK_OPT_' values ++ */ ++struct dpsw_link_cfg { ++ u32 rate; ++ u64 options; ++}; ++ ++int dpsw_if_set_link_cfg(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ struct dpsw_link_cfg *cfg); ++/** ++ * struct dpsw_link_state - Structure representing DPSW link state ++ * @rate: Rate ++ * @options: Mask of available options; use 'DPSW_LINK_OPT_' values ++ * @up: 0 - covers two cases: down and disconnected, 1 - up ++ */ ++struct dpsw_link_state { ++ u32 rate; ++ u64 options; ++ int up; ++}; ++ ++int dpsw_if_get_link_state(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ struct dpsw_link_state *state); ++ ++int dpsw_if_set_flooding(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ int en); ++ ++int dpsw_if_set_broadcast(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ int en); ++ ++int dpsw_if_set_multicast(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ int en); ++ ++/** ++ * struct dpsw_tci_cfg - Tag Contorl Information (TCI) configuration ++ * @pcp: Priority Code Point (PCP): a 3-bit field which refers ++ * to the IEEE 802.1p priority ++ * @dei: Drop Eligible Indicator (DEI): a 1-bit field. May be used ++ * separately or in conjunction with PCP to indicate frames ++ * eligible to be dropped in the presence of congestion ++ * @vlan_id: VLAN Identifier (VID): a 12-bit field specifying the VLAN ++ * to which the frame belongs. The hexadecimal values ++ * of 0x000 and 0xFFF are reserved; ++ * all other values may be used as VLAN identifiers, ++ * allowing up to 4,094 VLANs ++ */ ++struct dpsw_tci_cfg { ++ u8 pcp; ++ u8 dei; ++ u16 vlan_id; ++}; ++ ++int dpsw_if_set_tci(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpsw_tci_cfg *cfg); ++ ++int dpsw_if_get_tci(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ struct dpsw_tci_cfg *cfg); ++ ++/** ++ * enum dpsw_stp_state - Spanning Tree Protocol (STP) states ++ * @DPSW_STP_STATE_BLOCKING: Blocking state ++ * @DPSW_STP_STATE_LISTENING: Listening state ++ * @DPSW_STP_STATE_LEARNING: Learning state ++ * @DPSW_STP_STATE_FORWARDING: Forwarding state ++ * ++ */ ++enum dpsw_stp_state { ++ DPSW_STP_STATE_BLOCKING = 0, ++ DPSW_STP_STATE_LISTENING = 1, ++ DPSW_STP_STATE_LEARNING = 2, ++ DPSW_STP_STATE_FORWARDING = 3 ++}; ++ ++/** ++ * struct dpsw_stp_cfg - Spanning Tree Protocol (STP) Configuration ++ * @vlan_id: VLAN ID STP state ++ * @state: STP state ++ */ ++struct dpsw_stp_cfg { ++ u16 vlan_id; ++ enum dpsw_stp_state state; ++}; ++ ++int dpsw_if_set_stp(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpsw_stp_cfg *cfg); ++ ++/** ++ * enum dpsw_accepted_frames - Types of frames to accept ++ * @DPSW_ADMIT_ALL: The device accepts VLAN tagged, untagged and ++ * priority tagged frames ++ * @DPSW_ADMIT_ONLY_VLAN_TAGGED: The device discards untagged frames or ++ * Priority-Tagged frames received on this interface. ++ * ++ */ ++enum dpsw_accepted_frames { ++ DPSW_ADMIT_ALL = 1, ++ DPSW_ADMIT_ONLY_VLAN_TAGGED = 3 ++}; ++ ++/** ++ * struct dpsw_accepted_frames_cfg - Types of frames to accept configuration ++ * @type: Defines ingress accepted frames ++ * @unaccept_act: When a frame is not accepted, it may be discarded or ++ * redirected to control interface depending on this mode ++ */ ++struct dpsw_accepted_frames_cfg { ++ enum dpsw_accepted_frames type; ++ enum dpsw_action unaccept_act; ++}; ++ ++int dpsw_if_set_accepted_frames(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpsw_accepted_frames_cfg *cfg); ++ ++int dpsw_if_set_accept_all_vlan(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ int accept_all); ++ ++/** ++ * enum dpsw_counter - Counters types ++ * @DPSW_CNT_ING_FRAME: Counts ingress frames ++ * @DPSW_CNT_ING_BYTE: Counts ingress bytes ++ * @DPSW_CNT_ING_FLTR_FRAME: Counts filtered ingress frames ++ * @DPSW_CNT_ING_FRAME_DISCARD: Counts discarded ingress frame ++ * @DPSW_CNT_ING_MCAST_FRAME: Counts ingress multicast frames ++ * @DPSW_CNT_ING_MCAST_BYTE: Counts ingress multicast bytes ++ * @DPSW_CNT_ING_BCAST_FRAME: Counts ingress broadcast frames ++ * @DPSW_CNT_ING_BCAST_BYTES: Counts ingress broadcast bytes ++ * @DPSW_CNT_EGR_FRAME: Counts egress frames ++ * @DPSW_CNT_EGR_BYTE: Counts eEgress bytes ++ * @DPSW_CNT_EGR_FRAME_DISCARD: Counts discarded egress frames ++ * @DPSW_CNT_EGR_STP_FRAME_DISCARD: Counts egress STP discarded frames ++ */ ++enum dpsw_counter { ++ DPSW_CNT_ING_FRAME = 0x0, ++ DPSW_CNT_ING_BYTE = 0x1, ++ DPSW_CNT_ING_FLTR_FRAME = 0x2, ++ DPSW_CNT_ING_FRAME_DISCARD = 0x3, ++ DPSW_CNT_ING_MCAST_FRAME = 0x4, ++ DPSW_CNT_ING_MCAST_BYTE = 0x5, ++ DPSW_CNT_ING_BCAST_FRAME = 0x6, ++ DPSW_CNT_ING_BCAST_BYTES = 0x7, ++ DPSW_CNT_EGR_FRAME = 0x8, ++ DPSW_CNT_EGR_BYTE = 0x9, ++ DPSW_CNT_EGR_FRAME_DISCARD = 0xa, ++ DPSW_CNT_EGR_STP_FRAME_DISCARD = 0xb ++}; ++ ++int dpsw_if_get_counter(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ enum dpsw_counter type, ++ u64 *counter); ++ ++int dpsw_if_set_counter(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ enum dpsw_counter type, ++ u64 counter); ++ ++/** ++ * Maximum number of TC ++ */ ++#define DPSW_MAX_TC 8 ++ ++/** ++ * enum dpsw_priority_selector - User priority ++ * @DPSW_UP_PCP: Priority Code Point (PCP): a 3-bit field which ++ * refers to the IEEE 802.1p priority. ++ * @DPSW_UP_DSCP: Differentiated services Code Point (DSCP): 6 bit ++ * field from IP header ++ * ++ */ ++enum dpsw_priority_selector { ++ DPSW_UP_PCP = 0, ++ DPSW_UP_DSCP = 1 ++}; ++ ++/** ++ * enum dpsw_schedule_mode - Traffic classes scheduling ++ * @DPSW_SCHED_STRICT_PRIORITY: schedule strict priority ++ * @DPSW_SCHED_WEIGHTED: schedule based on token bucket created algorithm ++ */ ++enum dpsw_schedule_mode { ++ DPSW_SCHED_STRICT_PRIORITY, ++ DPSW_SCHED_WEIGHTED ++}; ++ ++/** ++ * struct dpsw_tx_schedule_cfg - traffic class configuration ++ * @mode: Strict or weight-based scheduling ++ * @delta_bandwidth: weighted Bandwidth in range from 100 to 10000 ++ */ ++struct dpsw_tx_schedule_cfg { ++ enum dpsw_schedule_mode mode; ++ u16 delta_bandwidth; ++}; ++ ++/** ++ * struct dpsw_tx_selection_cfg - Mapping user priority into traffic ++ * class configuration ++ * @priority_selector: Source for user priority regeneration ++ * @tc_id: The Regenerated User priority that the incoming ++ * User Priority is mapped to for this interface ++ * @tc_sched: Traffic classes configuration ++ */ ++struct dpsw_tx_selection_cfg { ++ enum dpsw_priority_selector priority_selector; ++ u8 tc_id[DPSW_MAX_PRIORITIES]; ++ struct dpsw_tx_schedule_cfg tc_sched[DPSW_MAX_TC]; ++}; ++ ++int dpsw_if_set_tx_selection(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpsw_tx_selection_cfg *cfg); ++ ++/** ++ * enum dpsw_reflection_filter - Filter type for frames to reflect ++ * @DPSW_REFLECTION_FILTER_INGRESS_ALL: Reflect all frames ++ * @DPSW_REFLECTION_FILTER_INGRESS_VLAN: Reflect only frames belong to ++ * particular VLAN defined by vid parameter ++ * ++ */ ++enum dpsw_reflection_filter { ++ DPSW_REFLECTION_FILTER_INGRESS_ALL = 0, ++ DPSW_REFLECTION_FILTER_INGRESS_VLAN = 1 ++}; ++ ++/** ++ * struct dpsw_reflection_cfg - Structure representing reflection information ++ * @filter: Filter type for frames to reflect ++ * @vlan_id: Vlan Id to reflect; valid only when filter type is ++ * DPSW_INGRESS_VLAN ++ */ ++struct dpsw_reflection_cfg { ++ enum dpsw_reflection_filter filter; ++ u16 vlan_id; ++}; ++ ++int dpsw_if_add_reflection(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpsw_reflection_cfg *cfg); ++ ++int dpsw_if_remove_reflection(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpsw_reflection_cfg *cfg); ++ ++/** ++ * enum dpsw_metering_mode - Metering modes ++ * @DPSW_METERING_MODE_NONE: metering disabled ++ * @DPSW_METERING_MODE_RFC2698: RFC 2698 ++ * @DPSW_METERING_MODE_RFC4115: RFC 4115 ++ */ ++enum dpsw_metering_mode { ++ DPSW_METERING_MODE_NONE = 0, ++ DPSW_METERING_MODE_RFC2698, ++ DPSW_METERING_MODE_RFC4115 ++}; ++ ++/** ++ * enum dpsw_metering_unit - Metering count ++ * @DPSW_METERING_UNIT_BYTES: count bytes ++ * @DPSW_METERING_UNIT_FRAMES: count frames ++ */ ++enum dpsw_metering_unit { ++ DPSW_METERING_UNIT_BYTES = 0, ++ DPSW_METERING_UNIT_FRAMES ++}; ++ ++/** ++ * struct dpsw_metering_cfg - Metering configuration ++ * @mode: metering modes ++ * @units: Bytes or frame units ++ * @cir: Committed information rate (CIR) in Kbits/s ++ * @eir: Peak information rate (PIR) Kbit/s rfc2698 ++ * Excess information rate (EIR) Kbit/s rfc4115 ++ * @cbs: Committed burst size (CBS) in bytes ++ * @ebs: Peak burst size (PBS) in bytes for rfc2698 ++ * Excess bust size (EBS) in bytes rfc4115 ++ * ++ */ ++struct dpsw_metering_cfg { ++ enum dpsw_metering_mode mode; ++ enum dpsw_metering_unit units; ++ u32 cir; ++ u32 eir; ++ u32 cbs; ++ u32 ebs; ++}; ++ ++int dpsw_if_set_flooding_metering(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpsw_metering_cfg *cfg); ++ ++int dpsw_if_set_metering(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ u8 tc_id, ++ const struct dpsw_metering_cfg *cfg); ++ ++/** ++ * enum dpsw_early_drop_unit - DPSW early drop unit ++ * @DPSW_EARLY_DROP_UNIT_BYTE: count bytes ++ * @DPSW_EARLY_DROP_UNIT_FRAMES: count frames ++ */ ++enum dpsw_early_drop_unit { ++ DPSW_EARLY_DROP_UNIT_BYTE = 0, ++ DPSW_EARLY_DROP_UNIT_FRAMES ++}; ++ ++/** ++ * enum dpsw_early_drop_mode - DPSW early drop mode ++ * @DPSW_EARLY_DROP_MODE_NONE: early drop is disabled ++ * @DPSW_EARLY_DROP_MODE_TAIL: early drop in taildrop mode ++ * @DPSW_EARLY_DROP_MODE_WRED: early drop in WRED mode ++ */ ++enum dpsw_early_drop_mode { ++ DPSW_EARLY_DROP_MODE_NONE = 0, ++ DPSW_EARLY_DROP_MODE_TAIL, ++ DPSW_EARLY_DROP_MODE_WRED ++}; ++ ++/** ++ * struct dpsw_wred_cfg - WRED configuration ++ * @max_threshold: maximum threshold that packets may be discarded. Above this ++ * threshold all packets are discarded; must be less than 2^39; ++ * approximated to be expressed as (x+256)*2^(y-1) due to HW ++ * implementation. ++ * @min_threshold: minimum threshold that packets may be discarded at ++ * @drop_probability: probability that a packet will be discarded (1-100, ++ * associated with the maximum threshold) ++ */ ++struct dpsw_wred_cfg { ++ u64 min_threshold; ++ u64 max_threshold; ++ u8 drop_probability; ++}; ++ ++/** ++ * struct dpsw_early_drop_cfg - early-drop configuration ++ * @drop_mode: drop mode ++ * @units: count units ++ * @yellow: WRED - 'yellow' configuration ++ * @green: WRED - 'green' configuration ++ * @tail_drop_threshold: tail drop threshold ++ */ ++struct dpsw_early_drop_cfg { ++ enum dpsw_early_drop_mode drop_mode; ++ enum dpsw_early_drop_unit units; ++ struct dpsw_wred_cfg yellow; ++ struct dpsw_wred_cfg green; ++ u32 tail_drop_threshold; ++}; ++ ++void dpsw_prepare_early_drop(const struct dpsw_early_drop_cfg *cfg, ++ u8 *early_drop_buf); ++ ++int dpsw_if_set_early_drop(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ u8 tc_id, ++ u64 early_drop_iova); ++ ++/** ++ * struct dpsw_custom_tpid_cfg - Structure representing tag Protocol identifier ++ * @tpid: An additional tag protocol identifier ++ */ ++struct dpsw_custom_tpid_cfg { ++ u16 tpid; ++}; ++ ++int dpsw_add_custom_tpid(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const struct dpsw_custom_tpid_cfg *cfg); ++ ++int dpsw_remove_custom_tpid(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const struct dpsw_custom_tpid_cfg *cfg); ++ ++int dpsw_if_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id); ++ ++int dpsw_if_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id); ++ ++/** ++ * struct dpsw_if_attr - Structure representing DPSW interface attributes ++ * @num_tcs: Number of traffic classes ++ * @rate: Transmit rate in bits per second ++ * @options: Interface configuration options (bitmap) ++ * @enabled: Indicates if interface is enabled ++ * @accept_all_vlan: The device discards/accepts incoming frames ++ * for VLANs that do not include this interface ++ * @admit_untagged: When set to 'DPSW_ADMIT_ONLY_VLAN_TAGGED', the device ++ * discards untagged frames or priority-tagged frames received on ++ * this interface; ++ * When set to 'DPSW_ADMIT_ALL', untagged frames or priority- ++ * tagged frames received on this interface are accepted ++ * @qdid: control frames transmit qdid ++ */ ++struct dpsw_if_attr { ++ u8 num_tcs; ++ u32 rate; ++ u32 options; ++ int enabled; ++ int accept_all_vlan; ++ enum dpsw_accepted_frames admit_untagged; ++ u16 qdid; ++}; ++ ++int dpsw_if_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ struct dpsw_if_attr *attr); ++ ++int dpsw_if_set_max_frame_length(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ u16 frame_length); ++ ++int dpsw_if_get_max_frame_length(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ u16 *frame_length); ++ ++/** ++ * struct dpsw_vlan_cfg - VLAN Configuration ++ * @fdb_id: Forwarding Data Base ++ */ ++struct dpsw_vlan_cfg { ++ u16 fdb_id; ++}; ++ ++int dpsw_vlan_add(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ const struct dpsw_vlan_cfg *cfg); ++ ++/** ++ * struct dpsw_vlan_if_cfg - Set of VLAN Interfaces ++ * @num_ifs: The number of interfaces that are assigned to the egress ++ * list for this VLAN ++ * @if_id: The set of interfaces that are ++ * assigned to the egress list for this VLAN ++ */ ++struct dpsw_vlan_if_cfg { ++ u16 num_ifs; ++ u16 if_id[DPSW_MAX_IF]; ++}; ++ ++int dpsw_vlan_add_if(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ const struct dpsw_vlan_if_cfg *cfg); ++ ++int dpsw_vlan_add_if_untagged(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ const struct dpsw_vlan_if_cfg *cfg); ++ ++int dpsw_vlan_add_if_flooding(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ const struct dpsw_vlan_if_cfg *cfg); ++ ++int dpsw_vlan_remove_if(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ const struct dpsw_vlan_if_cfg *cfg); ++ ++int dpsw_vlan_remove_if_untagged(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ const struct dpsw_vlan_if_cfg *cfg); ++ ++int dpsw_vlan_remove_if_flooding(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ const struct dpsw_vlan_if_cfg *cfg); ++ ++int dpsw_vlan_remove(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id); ++ ++/** ++ * struct dpsw_vlan_attr - VLAN attributes ++ * @fdb_id: Associated FDB ID ++ * @num_ifs: Number of interfaces ++ * @num_untagged_ifs: Number of untagged interfaces ++ * @num_flooding_ifs: Number of flooding interfaces ++ */ ++struct dpsw_vlan_attr { ++ u16 fdb_id; ++ u16 num_ifs; ++ u16 num_untagged_ifs; ++ u16 num_flooding_ifs; ++}; ++ ++int dpsw_vlan_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ struct dpsw_vlan_attr *attr); ++ ++int dpsw_vlan_get_if(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ struct dpsw_vlan_if_cfg *cfg); ++ ++int dpsw_vlan_get_if_flooding(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ struct dpsw_vlan_if_cfg *cfg); ++ ++int dpsw_vlan_get_if_untagged(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 vlan_id, ++ struct dpsw_vlan_if_cfg *cfg); ++ ++/** ++ * struct dpsw_fdb_cfg - FDB Configuration ++ * @num_fdb_entries: Number of FDB entries ++ * @fdb_aging_time: Aging time in seconds ++ */ ++struct dpsw_fdb_cfg { ++ u16 num_fdb_entries; ++ u16 fdb_aging_time; ++}; ++ ++int dpsw_fdb_add(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 *fdb_id, ++ const struct dpsw_fdb_cfg *cfg); ++ ++int dpsw_fdb_remove(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id); ++ ++/** ++ * enum dpsw_fdb_entry_type - FDB Entry type - Static/Dynamic ++ * @DPSW_FDB_ENTRY_STATIC: Static entry ++ * @DPSW_FDB_ENTRY_DINAMIC: Dynamic entry ++ */ ++enum dpsw_fdb_entry_type { ++ DPSW_FDB_ENTRY_STATIC = 0, ++ DPSW_FDB_ENTRY_DINAMIC = 1 ++}; ++ ++/** ++ * struct dpsw_fdb_unicast_cfg - Unicast entry configuration ++ * @type: Select static or dynamic entry ++ * @mac_addr: MAC address ++ * @if_egress: Egress interface ID ++ */ ++struct dpsw_fdb_unicast_cfg { ++ enum dpsw_fdb_entry_type type; ++ u8 mac_addr[6]; ++ u16 if_egress; ++}; ++ ++int dpsw_fdb_add_unicast(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id, ++ const struct dpsw_fdb_unicast_cfg *cfg); ++ ++int dpsw_fdb_get_unicast(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id, ++ struct dpsw_fdb_unicast_cfg *cfg); ++ ++int dpsw_fdb_remove_unicast(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id, ++ const struct dpsw_fdb_unicast_cfg *cfg); ++ ++/** ++ * struct dpsw_fdb_multicast_cfg - Multi-cast entry configuration ++ * @type: Select static or dynamic entry ++ * @mac_addr: MAC address ++ * @num_ifs: Number of external and internal interfaces ++ * @if_id: Egress interface IDs ++ */ ++struct dpsw_fdb_multicast_cfg { ++ enum dpsw_fdb_entry_type type; ++ u8 mac_addr[6]; ++ u16 num_ifs; ++ u16 if_id[DPSW_MAX_IF]; ++}; ++ ++int dpsw_fdb_add_multicast(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id, ++ const struct dpsw_fdb_multicast_cfg *cfg); ++ ++int dpsw_fdb_get_multicast(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id, ++ struct dpsw_fdb_multicast_cfg *cfg); ++ ++int dpsw_fdb_remove_multicast(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id, ++ const struct dpsw_fdb_multicast_cfg *cfg); ++ ++/** ++ * enum dpsw_fdb_learning_mode - Auto-learning modes ++ * @DPSW_FDB_LEARNING_MODE_DIS: Disable Auto-learning ++ * @DPSW_FDB_LEARNING_MODE_HW: Enable HW auto-Learning ++ * @DPSW_FDB_LEARNING_MODE_NON_SECURE: Enable None secure learning by CPU ++ * @DPSW_FDB_LEARNING_MODE_SECURE: Enable secure learning by CPU ++ * ++ * NONE - SECURE LEARNING ++ * SMAC found DMAC found CTLU Action ++ * v v Forward frame to ++ * 1. DMAC destination ++ * - v Forward frame to ++ * 1. DMAC destination ++ * 2. Control interface ++ * v - Forward frame to ++ * 1. Flooding list of interfaces ++ * - - Forward frame to ++ * 1. Flooding list of interfaces ++ * 2. Control interface ++ * SECURE LEARING ++ * SMAC found DMAC found CTLU Action ++ * v v Forward frame to ++ * 1. DMAC destination ++ * - v Forward frame to ++ * 1. Control interface ++ * v - Forward frame to ++ * 1. Flooding list of interfaces ++ * - - Forward frame to ++ * 1. Control interface ++ */ ++enum dpsw_fdb_learning_mode { ++ DPSW_FDB_LEARNING_MODE_DIS = 0, ++ DPSW_FDB_LEARNING_MODE_HW = 1, ++ DPSW_FDB_LEARNING_MODE_NON_SECURE = 2, ++ DPSW_FDB_LEARNING_MODE_SECURE = 3 ++}; ++ ++int dpsw_fdb_set_learning_mode(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id, ++ enum dpsw_fdb_learning_mode mode); ++ ++/** ++ * struct dpsw_fdb_attr - FDB Attributes ++ * @max_fdb_entries: Number of FDB entries ++ * @fdb_aging_time: Aging time in seconds ++ * @learning_mode: Learning mode ++ * @num_fdb_mc_groups: Current number of multicast groups ++ * @max_fdb_mc_groups: Maximum number of multicast groups ++ */ ++struct dpsw_fdb_attr { ++ u16 max_fdb_entries; ++ u16 fdb_aging_time; ++ enum dpsw_fdb_learning_mode learning_mode; ++ u16 num_fdb_mc_groups; ++ u16 max_fdb_mc_groups; ++}; ++ ++int dpsw_fdb_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 fdb_id, ++ struct dpsw_fdb_attr *attr); ++ ++/** ++ * struct dpsw_acl_cfg - ACL Configuration ++ * @max_entries: Number of FDB entries ++ */ ++struct dpsw_acl_cfg { ++ u16 max_entries; ++}; ++ ++/** ++ * struct dpsw_acl_fields - ACL fields. ++ * @l2_dest_mac: Destination MAC address: BPDU, Multicast, Broadcast, Unicast, ++ * slow protocols, MVRP, STP ++ * @l2_source_mac: Source MAC address ++ * @l2_tpid: Layer 2 (Ethernet) protocol type, used to identify the following ++ * protocols: MPLS, PTP, PFC, ARP, Jumbo frames, LLDP, IEEE802.1ae, ++ * Q-in-Q, IPv4, IPv6, PPPoE ++ * @l2_pcp_dei: indicate which protocol is encapsulated in the payload ++ * @l2_vlan_id: layer 2 VLAN ID ++ * @l2_ether_type: layer 2 Ethernet type ++ * @l3_dscp: Layer 3 differentiated services code point ++ * @l3_protocol: Tells the Network layer at the destination host, to which ++ * Protocol this packet belongs to. The following protocol are ++ * supported: ICMP, IGMP, IPv4 (encapsulation), TCP, IPv6 ++ * (encapsulation), GRE, PTP ++ * @l3_source_ip: Source IPv4 IP ++ * @l3_dest_ip: Destination IPv4 IP ++ * @l4_source_port: Source TCP/UDP Port ++ * @l4_dest_port: Destination TCP/UDP Port ++ */ ++struct dpsw_acl_fields { ++ u8 l2_dest_mac[6]; ++ u8 l2_source_mac[6]; ++ u16 l2_tpid; ++ u8 l2_pcp_dei; ++ u16 l2_vlan_id; ++ u16 l2_ether_type; ++ u8 l3_dscp; ++ u8 l3_protocol; ++ u32 l3_source_ip; ++ u32 l3_dest_ip; ++ u16 l4_source_port; ++ u16 l4_dest_port; ++}; ++ ++/** ++ * struct dpsw_acl_key - ACL key ++ * @match: Match fields ++ * @mask: Mask: b'1 - valid, b'0 don't care ++ */ ++struct dpsw_acl_key { ++ struct dpsw_acl_fields match; ++ struct dpsw_acl_fields mask; ++}; ++ ++/** ++ * enum dpsw_acl_action ++ * @DPSW_ACL_ACTION_DROP: Drop frame ++ * @DPSW_ACL_ACTION_REDIRECT: Redirect to certain port ++ * @DPSW_ACL_ACTION_ACCEPT: Accept frame ++ * @DPSW_ACL_ACTION_REDIRECT_TO_CTRL_IF: Redirect to control interface ++ */ ++enum dpsw_acl_action { ++ DPSW_ACL_ACTION_DROP, ++ DPSW_ACL_ACTION_REDIRECT, ++ DPSW_ACL_ACTION_ACCEPT, ++ DPSW_ACL_ACTION_REDIRECT_TO_CTRL_IF ++}; ++ ++/** ++ * struct dpsw_acl_result - ACL action ++ * @action: Action should be taken when ACL entry hit ++ * @if_id: Interface IDs to redirect frame. Valid only if redirect selected for ++ * action ++ */ ++struct dpsw_acl_result { ++ enum dpsw_acl_action action; ++ u16 if_id; ++}; ++ ++/** ++ * struct dpsw_acl_entry_cfg - ACL entry ++ * @key_iova: I/O virtual address of DMA-able memory filled with key after call ++ * to dpsw_acl_prepare_entry_cfg() ++ * @result: Required action when entry hit occurs ++ * @precedence: Precedence inside ACL 0 is lowest; This priority can not change ++ * during the lifetime of a Policy. It is user responsibility to ++ * space the priorities according to consequent rule additions. ++ */ ++struct dpsw_acl_entry_cfg { ++ u64 key_iova; ++ struct dpsw_acl_result result; ++ int precedence; ++}; ++ ++int dpsw_acl_add(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 *acl_id, ++ const struct dpsw_acl_cfg *cfg); ++ ++int dpsw_acl_remove(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 acl_id); ++ ++void dpsw_acl_prepare_entry_cfg(const struct dpsw_acl_key *key, ++ uint8_t *entry_cfg_buf); ++ ++int dpsw_acl_add_entry(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 acl_id, ++ const struct dpsw_acl_entry_cfg *cfg); ++ ++int dpsw_acl_remove_entry(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 acl_id, ++ const struct dpsw_acl_entry_cfg *cfg); ++ ++/** ++ * struct dpsw_acl_if_cfg - List of interfaces to Associate with ACL ++ * @num_ifs: Number of interfaces ++ * @if_id: List of interfaces ++ */ ++struct dpsw_acl_if_cfg { ++ u16 num_ifs; ++ u16 if_id[DPSW_MAX_IF]; ++}; ++ ++int dpsw_acl_add_if(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 acl_id, ++ const struct dpsw_acl_if_cfg *cfg); ++ ++int dpsw_acl_remove_if(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 acl_id, ++ const struct dpsw_acl_if_cfg *cfg); ++ ++/** ++ * struct dpsw_acl_attr - ACL Attributes ++ * @max_entries: Max number of ACL entries ++ * @num_entries: Number of used ACL entries ++ * @num_ifs: Number of interfaces associated with ACL ++ */ ++struct dpsw_acl_attr { ++ u16 max_entries; ++ u16 num_entries; ++ u16 num_ifs; ++}; ++ ++int dpsw_acl_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 acl_id, ++ struct dpsw_acl_attr *attr); ++/** ++ * struct dpsw_ctrl_if_attr - Control interface attributes ++ * @rx_fqid: Receive FQID ++ * @rx_err_fqid: Receive error FQID ++ * @tx_err_conf_fqid: Transmit error and confirmation FQID ++ */ ++struct dpsw_ctrl_if_attr { ++ u32 rx_fqid; ++ u32 rx_err_fqid; ++ u32 tx_err_conf_fqid; ++}; ++ ++int dpsw_ctrl_if_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpsw_ctrl_if_attr *attr); ++ ++/** ++ * Maximum number of DPBP ++ */ ++#define DPSW_MAX_DPBP 8 ++ ++/** ++ * struct dpsw_ctrl_if_pools_cfg - Control interface buffer pools configuration ++ * @num_dpbp: Number of DPBPs ++ * @pools: Array of buffer pools parameters; The number of valid entries ++ * must match 'num_dpbp' value ++ */ ++struct dpsw_ctrl_if_pools_cfg { ++ u8 num_dpbp; ++ /** ++ * struct pools - Buffer pools parameters ++ * @dpbp_id: DPBP object ID ++ * @buffer_size: Buffer size ++ * @backup_pool: Backup pool ++ */ ++ struct { ++ int dpbp_id; ++ u16 buffer_size; ++ int backup_pool; ++ } pools[DPSW_MAX_DPBP]; ++}; ++ ++int dpsw_ctrl_if_set_pools(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const struct dpsw_ctrl_if_pools_cfg *cfg); ++ ++int dpsw_ctrl_if_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpsw_ctrl_if_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpsw_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver); ++ ++#endif /* __FSL_DPSW_H */ +diff --git a/drivers/staging/fsl-dpaa2/ethsw/switch.c b/drivers/staging/fsl-dpaa2/ethsw/switch.c +new file mode 100644 +index 00000000..3f2c9648 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/ethsw/switch.c +@@ -0,0 +1,1857 @@ ++/* Copyright 2014-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "../../fsl-mc/include/mc.h" ++#include "dpsw.h" ++#include "dpsw-cmd.h" ++ ++static const char ethsw_drv_version[] = "0.1"; ++ ++/* Minimal supported DPSE version */ ++#define DPSW_MIN_VER_MAJOR 8 ++#define DPSW_MIN_VER_MINOR 0 ++ ++/* IRQ index */ ++#define DPSW_MAX_IRQ_NUM 2 ++ ++#define ETHSW_VLAN_MEMBER 1 ++#define ETHSW_VLAN_UNTAGGED 2 ++#define ETHSW_VLAN_PVID 4 ++#define ETHSW_VLAN_GLOBAL 8 ++ ++/* Maximum Frame Length supported by HW (currently 10k) */ ++#define DPAA2_MFL (10 * 1024) ++#define ETHSW_MAX_FRAME_LENGTH (DPAA2_MFL - VLAN_ETH_HLEN - ETH_FCS_LEN) ++#define ETHSW_L2_MAX_FRM(mtu) ((mtu) + VLAN_ETH_HLEN + ETH_FCS_LEN) ++ ++struct ethsw_port_priv { ++ struct net_device *netdev; ++ struct list_head list; ++ u16 port_index; ++ struct ethsw_dev_priv *ethsw_priv; ++ u8 stp_state; ++ ++ char vlans[VLAN_VID_MASK + 1]; ++ ++}; ++ ++struct ethsw_dev_priv { ++ struct net_device *netdev; ++ struct fsl_mc_io *mc_io; ++ u16 dpsw_handle; ++ struct dpsw_attr sw_attr; ++ int dev_id; ++ /*TODO: redundant, we can use the slave dev list */ ++ struct list_head port_list; ++ ++ bool flood; ++ bool learning; ++ ++ char vlans[VLAN_VID_MASK + 1]; ++}; ++ ++static int ethsw_port_stop(struct net_device *netdev); ++static int ethsw_port_open(struct net_device *netdev); ++ ++static inline void __get_priv(struct net_device *netdev, ++ struct ethsw_dev_priv **priv, ++ struct ethsw_port_priv **port_priv) ++{ ++ struct ethsw_dev_priv *_priv = NULL; ++ struct ethsw_port_priv *_port_priv = NULL; ++ ++ if (netdev->flags & IFF_MASTER) { ++ _priv = netdev_priv(netdev); ++ } else { ++ _port_priv = netdev_priv(netdev); ++ _priv = _port_priv->ethsw_priv; ++ } ++ ++ if (priv) ++ *priv = _priv; ++ if (port_priv) ++ *port_priv = _port_priv; ++} ++ ++/* -------------------------------------------------------------------------- */ ++/* ethsw netdevice ops */ ++ ++static netdev_tx_t ethsw_dropframe(struct sk_buff *skb, struct net_device *dev) ++{ ++ /* we don't support I/O for now, drop the frame */ ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++} ++ ++static int ethsw_open(struct net_device *netdev) ++{ ++ struct ethsw_dev_priv *priv = netdev_priv(netdev); ++ struct list_head *pos; ++ struct ethsw_port_priv *port_priv = NULL; ++ int err; ++ ++ err = dpsw_enable(priv->mc_io, 0, priv->dpsw_handle); ++ if (err) { ++ netdev_err(netdev, "dpsw_enable err %d\n", err); ++ return err; ++ } ++ ++ list_for_each(pos, &priv->port_list) { ++ port_priv = list_entry(pos, struct ethsw_port_priv, list); ++ err = dev_open(port_priv->netdev); ++ if (err) ++ netdev_err(port_priv->netdev, "dev_open err %d\n", err); ++ } ++ ++ return 0; ++} ++ ++static int ethsw_stop(struct net_device *netdev) ++{ ++ struct ethsw_dev_priv *priv = netdev_priv(netdev); ++ struct list_head *pos; ++ struct ethsw_port_priv *port_priv = NULL; ++ int err; ++ ++ err = dpsw_disable(priv->mc_io, 0, priv->dpsw_handle); ++ if (err) { ++ netdev_err(netdev, "dpsw_disable err %d\n", err); ++ return err; ++ } ++ ++ list_for_each(pos, &priv->port_list) { ++ port_priv = list_entry(pos, struct ethsw_port_priv, list); ++ err = dev_close(port_priv->netdev); ++ if (err) ++ netdev_err(port_priv->netdev, ++ "dev_close err %d\n", err); ++ } ++ ++ return 0; ++} ++ ++static int ethsw_add_vlan(struct net_device *netdev, u16 vid) ++{ ++ struct ethsw_dev_priv *priv = netdev_priv(netdev); ++ int err; ++ ++ struct dpsw_vlan_cfg vcfg = { ++ /* TODO: add support for VLAN private FDBs */ ++ .fdb_id = 0, ++ }; ++ if (priv->vlans[vid]) { ++ netdev_err(netdev, "VLAN already configured\n"); ++ return -EEXIST; ++ } ++ ++ err = dpsw_vlan_add(priv->mc_io, 0, priv->dpsw_handle, vid, &vcfg); ++ if (err) { ++ netdev_err(netdev, "dpsw_vlan_add err %d\n", err); ++ return err; ++ } ++ priv->vlans[vid] = ETHSW_VLAN_MEMBER; ++ ++ return 0; ++} ++ ++static int ethsw_port_add_vlan(struct net_device *netdev, u16 vid, u16 flags) ++{ ++ struct ethsw_port_priv *port_priv = netdev_priv(netdev); ++ struct ethsw_dev_priv *priv = port_priv->ethsw_priv; ++ int err; ++ ++ struct dpsw_vlan_if_cfg vcfg = { ++ .num_ifs = 1, ++ .if_id[0] = port_priv->port_index, ++ }; ++ ++ if (port_priv->vlans[vid]) { ++ netdev_err(netdev, "VLAN already configured\n"); ++ return -EEXIST; ++ } ++ ++ if (flags & BRIDGE_VLAN_INFO_PVID && netif_oper_up(netdev)) { ++ netdev_err(netdev, "interface must be down to change PVID!\n"); ++ return -EBUSY; ++ } ++ ++ err = dpsw_vlan_add_if(priv->mc_io, 0, priv->dpsw_handle, vid, &vcfg); ++ if (err) { ++ netdev_err(netdev, "dpsw_vlan_add_if err %d\n", err); ++ return err; ++ } ++ port_priv->vlans[vid] = ETHSW_VLAN_MEMBER; ++ ++ if (flags & BRIDGE_VLAN_INFO_UNTAGGED) { ++ err = dpsw_vlan_add_if_untagged(priv->mc_io, 0, ++ priv->dpsw_handle, vid, &vcfg); ++ if (err) { ++ netdev_err(netdev, "dpsw_vlan_add_if_untagged err %d\n", ++ err); ++ return err; ++ } ++ port_priv->vlans[vid] |= ETHSW_VLAN_UNTAGGED; ++ } ++ ++ if (flags & BRIDGE_VLAN_INFO_PVID) { ++ struct dpsw_tci_cfg tci_cfg = { ++ /* TODO: at least add better defaults if these cannot ++ * be configured ++ */ ++ .pcp = 0, ++ .dei = 0, ++ .vlan_id = vid, ++ }; ++ ++ err = dpsw_if_set_tci(priv->mc_io, 0, priv->dpsw_handle, ++ port_priv->port_index, &tci_cfg); ++ if (err) { ++ netdev_err(netdev, "dpsw_if_set_tci err %d\n", err); ++ return err; ++ } ++ port_priv->vlans[vid] |= ETHSW_VLAN_PVID; ++ } ++ ++ return 0; ++} ++ ++static const struct nla_policy ifla_br_policy[IFLA_MAX + 1] = { ++ [IFLA_BRIDGE_FLAGS] = { .type = NLA_U16 }, ++ [IFLA_BRIDGE_MODE] = { .type = NLA_U16 }, ++ [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY, ++ .len = sizeof(struct bridge_vlan_info), }, ++}; ++ ++static int ethsw_setlink_af_spec(struct net_device *netdev, ++ struct nlattr **tb) ++{ ++ struct bridge_vlan_info *vinfo; ++ struct ethsw_dev_priv *priv = NULL; ++ struct ethsw_port_priv *port_priv = NULL; ++ int err = 0; ++ ++ if (!tb[IFLA_BRIDGE_VLAN_INFO]) { ++ netdev_err(netdev, "no VLAN INFO in nlmsg\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]); ++ ++ if (!vinfo->vid || vinfo->vid > VLAN_VID_MASK) ++ return -EINVAL; ++ ++ __get_priv(netdev, &priv, &port_priv); ++ ++ if (!port_priv || !priv->vlans[vinfo->vid]) { ++ /* command targets switch device or this is a new VLAN */ ++ err = ethsw_add_vlan(priv->netdev, vinfo->vid); ++ if (err) ++ return err; ++ ++ /* command targets switch device; mark it*/ ++ if (!port_priv) ++ priv->vlans[vinfo->vid] |= ETHSW_VLAN_GLOBAL; ++ } ++ ++ if (port_priv) { ++ /* command targets switch port */ ++ err = ethsw_port_add_vlan(netdev, vinfo->vid, vinfo->flags); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ ++static const struct nla_policy ifla_brport_policy[IFLA_BRPORT_MAX + 1] = { ++ [IFLA_BRPORT_STATE] = { .type = NLA_U8 }, ++ [IFLA_BRPORT_COST] = { .type = NLA_U32 }, ++ [IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 }, ++ [IFLA_BRPORT_MODE] = { .type = NLA_U8 }, ++ [IFLA_BRPORT_GUARD] = { .type = NLA_U8 }, ++ [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 }, ++ [IFLA_BRPORT_LEARNING] = { .type = NLA_U8 }, ++ [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 }, ++}; ++ ++static int ethsw_set_learning(struct net_device *netdev, u8 flag) ++{ ++ struct ethsw_dev_priv *priv = netdev_priv(netdev); ++ enum dpsw_fdb_learning_mode learn_mode; ++ int err; ++ ++ if (flag) ++ learn_mode = DPSW_FDB_LEARNING_MODE_HW; ++ else ++ learn_mode = DPSW_FDB_LEARNING_MODE_DIS; ++ ++ err = dpsw_fdb_set_learning_mode(priv->mc_io, 0, priv->dpsw_handle, ++ 0, learn_mode); ++ if (err) { ++ netdev_err(netdev, "dpsw_fdb_set_learning_mode err %d\n", err); ++ return err; ++ } ++ priv->learning = !!flag; ++ ++ return 0; ++} ++ ++static int ethsw_port_set_flood(struct net_device *netdev, u8 flag) ++{ ++ struct ethsw_port_priv *port_priv = netdev_priv(netdev); ++ struct ethsw_dev_priv *priv = port_priv->ethsw_priv; ++ int err; ++ ++ err = dpsw_if_set_flooding(priv->mc_io, 0, priv->dpsw_handle, ++ port_priv->port_index, (int)flag); ++ if (err) { ++ netdev_err(netdev, "dpsw_fdb_set_learning_mode err %d\n", err); ++ return err; ++ } ++ priv->flood = !!flag; ++ ++ return 0; ++} ++ ++static int ethsw_port_set_state(struct net_device *netdev, u8 state) ++{ ++ struct ethsw_port_priv *port_priv = netdev_priv(netdev); ++ struct ethsw_dev_priv *priv = port_priv->ethsw_priv; ++ u8 old_state = port_priv->stp_state; ++ int err; ++ ++ struct dpsw_stp_cfg stp_cfg = { ++ .vlan_id = 1, ++ .state = state, ++ }; ++ /* TODO: check port state, interface may be down */ ++ ++ if (state > BR_STATE_BLOCKING) ++ return -EINVAL; ++ ++ if (state == port_priv->stp_state) ++ return 0; ++ ++ if (state == BR_STATE_DISABLED) { ++ port_priv->stp_state = state; ++ ++ err = ethsw_port_stop(netdev); ++ if (err) ++ goto error; ++ } else { ++ err = dpsw_if_set_stp(priv->mc_io, 0, priv->dpsw_handle, ++ port_priv->port_index, &stp_cfg); ++ if (err) { ++ netdev_err(netdev, "dpsw_if_set_stp err %d\n", err); ++ return err; ++ } ++ ++ port_priv->stp_state = state; ++ ++ if (old_state == BR_STATE_DISABLED) { ++ err = ethsw_port_open(netdev); ++ if (err) ++ goto error; ++ } ++ } ++ ++ return 0; ++error: ++ port_priv->stp_state = old_state; ++ return err; ++} ++ ++static int ethsw_setlink_protinfo(struct net_device *netdev, ++ struct nlattr **tb) ++{ ++ struct ethsw_dev_priv *priv; ++ struct ethsw_port_priv *port_priv = NULL; ++ int err = 0; ++ ++ __get_priv(netdev, &priv, &port_priv); ++ ++ if (tb[IFLA_BRPORT_LEARNING]) { ++ u8 flag = nla_get_u8(tb[IFLA_BRPORT_LEARNING]); ++ ++ if (port_priv) ++ netdev_warn(netdev, ++ "learning set on whole switch dev\n"); ++ ++ err = ethsw_set_learning(priv->netdev, flag); ++ if (err) ++ return err; ++ ++ } else if (tb[IFLA_BRPORT_UNICAST_FLOOD] && port_priv) { ++ u8 flag = nla_get_u8(tb[IFLA_BRPORT_UNICAST_FLOOD]); ++ ++ err = ethsw_port_set_flood(port_priv->netdev, flag); ++ if (err) ++ return err; ++ ++ } else if (tb[IFLA_BRPORT_STATE] && port_priv) { ++ u8 state = nla_get_u8(tb[IFLA_BRPORT_STATE]); ++ ++ err = ethsw_port_set_state(port_priv->netdev, state); ++ if (err) ++ return err; ++ ++ } else { ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++static int ethsw_setlink(struct net_device *netdev, ++ struct nlmsghdr *nlh, ++ u16 flags) ++{ ++ struct nlattr *attr; ++ struct nlattr *tb[(IFLA_BRIDGE_MAX > IFLA_BRPORT_MAX) ? ++ IFLA_BRIDGE_MAX : IFLA_BRPORT_MAX + 1]; ++ int err = 0; ++ ++ attr = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); ++ if (attr) { ++ err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, attr, ++ ifla_br_policy); ++ if (err) { ++ netdev_err(netdev, ++ "nla_parse_nested for br_policy err %d\n", ++ err); ++ return err; ++ } ++ ++ err = ethsw_setlink_af_spec(netdev, tb); ++ return err; ++ } ++ ++ attr = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_PROTINFO); ++ if (attr) { ++ err = nla_parse_nested(tb, IFLA_BRPORT_MAX, attr, ++ ifla_brport_policy); ++ if (err) { ++ netdev_err(netdev, ++ "nla_parse_nested for brport_policy err %d\n", ++ err); ++ return err; ++ } ++ ++ err = ethsw_setlink_protinfo(netdev, tb); ++ return err; ++ } ++ ++ netdev_err(netdev, "nlmsg_find_attr found no AF_SPEC/PROTINFO\n"); ++ return -EOPNOTSUPP; ++} ++ ++static int __nla_put_netdev(struct sk_buff *skb, struct net_device *netdev, ++ struct ethsw_dev_priv *priv) ++{ ++ u8 operstate = netif_running(netdev) ? netdev->operstate : IF_OPER_DOWN; ++ int iflink; ++ int err; ++ ++ err = nla_put_string(skb, IFLA_IFNAME, netdev->name); ++ if (err) ++ goto nla_put_err; ++ err = nla_put_u32(skb, IFLA_MASTER, priv->netdev->ifindex); ++ if (err) ++ goto nla_put_err; ++ err = nla_put_u32(skb, IFLA_MTU, netdev->mtu); ++ if (err) ++ goto nla_put_err; ++ err = nla_put_u8(skb, IFLA_OPERSTATE, operstate); ++ if (err) ++ goto nla_put_err; ++ if (netdev->addr_len) { ++ err = nla_put(skb, IFLA_ADDRESS, netdev->addr_len, ++ netdev->dev_addr); ++ if (err) ++ goto nla_put_err; ++ } ++ ++ iflink = dev_get_iflink(netdev); ++ if (netdev->ifindex != iflink) { ++ err = nla_put_u32(skb, IFLA_LINK, iflink); ++ if (err) ++ goto nla_put_err; ++ } ++ ++ return 0; ++ ++nla_put_err: ++ netdev_err(netdev, "nla_put_ err %d\n", err); ++ return err; ++} ++ ++static int __nla_put_port(struct sk_buff *skb, struct net_device *netdev, ++ struct ethsw_port_priv *port_priv) ++{ ++ struct nlattr *nest; ++ int err; ++ ++ u8 stp_state = port_priv->stp_state; ++ ++ if (port_priv->stp_state == DPSW_STP_STATE_BLOCKING) ++ stp_state = BR_STATE_BLOCKING; ++ ++ nest = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED); ++ if (!nest) { ++ netdev_err(netdev, "nla_nest_start failed\n"); ++ return -ENOMEM; ++ } ++ ++ err = nla_put_u8(skb, IFLA_BRPORT_STATE, stp_state); ++ if (err) ++ goto nla_put_err; ++ err = nla_put_u16(skb, IFLA_BRPORT_PRIORITY, 0); ++ if (err) ++ goto nla_put_err; ++ err = nla_put_u32(skb, IFLA_BRPORT_COST, 0); ++ if (err) ++ goto nla_put_err; ++ err = nla_put_u8(skb, IFLA_BRPORT_MODE, 0); ++ if (err) ++ goto nla_put_err; ++ err = nla_put_u8(skb, IFLA_BRPORT_GUARD, 0); ++ if (err) ++ goto nla_put_err; ++ err = nla_put_u8(skb, IFLA_BRPORT_PROTECT, 0); ++ if (err) ++ goto nla_put_err; ++ err = nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, 0); ++ if (err) ++ goto nla_put_err; ++ err = nla_put_u8(skb, IFLA_BRPORT_LEARNING, ++ port_priv->ethsw_priv->learning); ++ if (err) ++ goto nla_put_err; ++ err = nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, ++ port_priv->ethsw_priv->flood); ++ if (err) ++ goto nla_put_err; ++ nla_nest_end(skb, nest); ++ ++ return 0; ++ ++nla_put_err: ++ netdev_err(netdev, "nla_put_ err %d\n", err); ++ nla_nest_cancel(skb, nest); ++ return err; ++} ++ ++static int __nla_put_vlan(struct sk_buff *skb, struct net_device *netdev, ++ struct ethsw_dev_priv *priv, ++ struct ethsw_port_priv *port_priv) ++{ ++ struct nlattr *nest; ++ struct bridge_vlan_info vinfo; ++ const char *vlans; ++ u16 i; ++ int err; ++ ++ nest = nla_nest_start(skb, IFLA_AF_SPEC); ++ if (!nest) { ++ netdev_err(netdev, "nla_nest_start failed"); ++ return -ENOMEM; ++ } ++ ++ if (port_priv) ++ vlans = port_priv->vlans; ++ else ++ vlans = priv->vlans; ++ ++ for (i = 0; i < VLAN_VID_MASK + 1; i++) { ++ vinfo.flags = 0; ++ vinfo.vid = i; ++ ++ if (vlans[i] & ETHSW_VLAN_UNTAGGED) ++ vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED; ++ ++ if (vlans[i] & ETHSW_VLAN_PVID) ++ vinfo.flags |= BRIDGE_VLAN_INFO_PVID; ++ ++ if (vlans[i] & ETHSW_VLAN_MEMBER) { ++ err = nla_put(skb, IFLA_BRIDGE_VLAN_INFO, ++ sizeof(vinfo), &vinfo); ++ if (err) ++ goto nla_put_err; ++ } ++ } ++ ++ nla_nest_end(skb, nest); ++ ++ return 0; ++nla_put_err: ++ netdev_err(netdev, "nla_put_ err %d\n", err); ++ nla_nest_cancel(skb, nest); ++ return err; ++} ++ ++static int ethsw_getlink(struct sk_buff *skb, u32 pid, u32 seq, ++ struct net_device *netdev, u32 filter_mask, ++ int nlflags) ++{ ++ struct ethsw_dev_priv *priv; ++ struct ethsw_port_priv *port_priv = NULL; ++ struct ifinfomsg *hdr; ++ struct nlmsghdr *nlh; ++ int err; ++ ++ __get_priv(netdev, &priv, &port_priv); ++ ++ nlh = nlmsg_put(skb, pid, seq, RTM_NEWLINK, sizeof(*hdr), NLM_F_MULTI); ++ if (!nlh) ++ return -EMSGSIZE; ++ ++ hdr = nlmsg_data(nlh); ++ memset(hdr, 0, sizeof(*hdr)); ++ hdr->ifi_family = AF_BRIDGE; ++ hdr->ifi_type = netdev->type; ++ hdr->ifi_index = netdev->ifindex; ++ hdr->ifi_flags = dev_get_flags(netdev); ++ ++ err = __nla_put_netdev(skb, netdev, priv); ++ if (err) ++ goto nla_put_err; ++ ++ if (port_priv) { ++ err = __nla_put_port(skb, netdev, port_priv); ++ if (err) ++ goto nla_put_err; ++ } ++ ++ /* Check if the VID information is requested */ ++ if (filter_mask & RTEXT_FILTER_BRVLAN) { ++ err = __nla_put_vlan(skb, netdev, priv, port_priv); ++ if (err) ++ goto nla_put_err; ++ } ++ ++ nlmsg_end(skb, nlh); ++ return skb->len; ++ ++nla_put_err: ++ nlmsg_cancel(skb, nlh); ++ return -EMSGSIZE; ++} ++ ++static int ethsw_dellink_switch(struct ethsw_dev_priv *priv, u16 vid) ++{ ++ struct list_head *pos; ++ struct ethsw_port_priv *ppriv_local = NULL; ++ int err = 0; ++ ++ if (!priv->vlans[vid]) ++ return -ENOENT; ++ ++ err = dpsw_vlan_remove(priv->mc_io, 0, priv->dpsw_handle, vid); ++ if (err) { ++ netdev_err(priv->netdev, "dpsw_vlan_remove err %d\n", err); ++ return err; ++ } ++ priv->vlans[vid] = 0; ++ ++ list_for_each(pos, &priv->port_list) { ++ ppriv_local = list_entry(pos, struct ethsw_port_priv, ++ list); ++ ppriv_local->vlans[vid] = 0; ++ } ++ ++ return 0; ++} ++ ++static int ethsw_dellink_port(struct ethsw_dev_priv *priv, ++ struct ethsw_port_priv *port_priv, ++ u16 vid) ++{ ++ struct list_head *pos; ++ struct ethsw_port_priv *ppriv_local = NULL; ++ struct dpsw_vlan_if_cfg vcfg = { ++ .num_ifs = 1, ++ .if_id[0] = port_priv->port_index, ++ }; ++ unsigned int count = 0; ++ int err = 0; ++ ++ if (!port_priv->vlans[vid]) ++ return -ENOENT; ++ ++ /* VLAN will be deleted from switch if global flag is not set ++ * and is configured on only one port ++ */ ++ if (!(priv->vlans[vid] & ETHSW_VLAN_GLOBAL)) { ++ list_for_each(pos, &priv->port_list) { ++ ppriv_local = list_entry(pos, struct ethsw_port_priv, ++ list); ++ if (ppriv_local->vlans[vid] & ETHSW_VLAN_MEMBER) ++ count++; ++ } ++ ++ if (count == 1) ++ return ethsw_dellink_switch(priv, vid); ++ } ++ ++ err = dpsw_vlan_remove_if(priv->mc_io, 0, priv->dpsw_handle, ++ vid, &vcfg); ++ if (err) { ++ netdev_err(priv->netdev, "dpsw_vlan_remove_if err %d\n", err); ++ return err; ++ } ++ port_priv->vlans[vid] = 0; ++ return 0; ++} ++ ++static int ethsw_dellink(struct net_device *netdev, ++ struct nlmsghdr *nlh, ++ u16 flags) ++{ ++ struct nlattr *tb[IFLA_BRIDGE_MAX + 1]; ++ struct nlattr *spec; ++ struct bridge_vlan_info *vinfo; ++ struct ethsw_dev_priv *priv; ++ struct ethsw_port_priv *port_priv = NULL; ++ int err = 0; ++ ++ spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); ++ if (!spec) ++ return 0; ++ ++ err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, spec, ifla_br_policy); ++ if (err) ++ return err; ++ ++ if (!tb[IFLA_BRIDGE_VLAN_INFO]) ++ return -EOPNOTSUPP; ++ ++ vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]); ++ ++ if (!vinfo->vid || vinfo->vid > VLAN_VID_MASK) ++ return -EINVAL; ++ ++ __get_priv(netdev, &priv, &port_priv); ++ ++ /* decide if command targets switch device or port */ ++ if (!port_priv) ++ err = ethsw_dellink_switch(priv, vinfo->vid); ++ else ++ err = ethsw_dellink_port(priv, port_priv, vinfo->vid); ++ ++ return err; ++} ++ ++static const struct net_device_ops ethsw_ops = { ++ .ndo_open = ðsw_open, ++ .ndo_stop = ðsw_stop, ++ ++ .ndo_bridge_setlink = ðsw_setlink, ++ .ndo_bridge_getlink = ðsw_getlink, ++ .ndo_bridge_dellink = ðsw_dellink, ++ ++ .ndo_start_xmit = ðsw_dropframe, ++}; ++ ++/*--------------------------------------------------------------------------- */ ++/* switch port netdevice ops */ ++ ++static int _ethsw_port_carrier_state_sync(struct net_device *netdev) ++{ ++ struct ethsw_port_priv *port_priv = netdev_priv(netdev); ++ struct dpsw_link_state state; ++ int err; ++ ++ err = dpsw_if_get_link_state(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ port_priv->port_index, &state); ++ if (unlikely(err)) { ++ netdev_err(netdev, "dpsw_if_get_link_state() err %d\n", err); ++ return err; ++ } ++ ++ WARN_ONCE(state.up > 1, "Garbage read into link_state"); ++ ++ if (state.up) ++ netif_carrier_on(port_priv->netdev); ++ else ++ netif_carrier_off(port_priv->netdev); ++ ++ return 0; ++} ++ ++static int ethsw_port_open(struct net_device *netdev) ++{ ++ struct ethsw_port_priv *port_priv = netdev_priv(netdev); ++ int err; ++ ++ err = dpsw_if_enable(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ port_priv->port_index); ++ if (err) { ++ netdev_err(netdev, "dpsw_if_enable err %d\n", err); ++ return err; ++ } ++ ++ /* sync carrier state */ ++ err = _ethsw_port_carrier_state_sync(netdev); ++ if (err) { ++ netdev_err(netdev, "_ethsw_port_carrier_state_sync err %d\n", ++ err); ++ goto err_carrier_sync; ++ } ++ ++ return 0; ++ ++err_carrier_sync: ++ dpsw_if_disable(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ port_priv->port_index); ++ return err; ++} ++ ++static int ethsw_port_stop(struct net_device *netdev) ++{ ++ struct ethsw_port_priv *port_priv = netdev_priv(netdev); ++ int err; ++ ++ err = dpsw_if_disable(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ port_priv->port_index); ++ if (err) { ++ netdev_err(netdev, "dpsw_if_disable err %d\n", err); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int ethsw_port_fdb_add_uc(struct net_device *netdev, ++ const unsigned char *addr) ++{ ++ struct ethsw_port_priv *port_priv = netdev_priv(netdev); ++ struct dpsw_fdb_unicast_cfg entry = {0}; ++ int err; ++ ++ entry.if_egress = port_priv->port_index; ++ entry.type = DPSW_FDB_ENTRY_STATIC; ++ ether_addr_copy(entry.mac_addr, addr); ++ ++ err = dpsw_fdb_add_unicast(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ 0, &entry); ++ if (err) ++ netdev_err(netdev, "dpsw_fdb_add_unicast err %d\n", err); ++ return err; ++} ++ ++static int ethsw_port_fdb_del_uc(struct net_device *netdev, ++ const unsigned char *addr) ++{ ++ struct ethsw_port_priv *port_priv = netdev_priv(netdev); ++ struct dpsw_fdb_unicast_cfg entry = {0}; ++ int err; ++ ++ entry.if_egress = port_priv->port_index; ++ entry.type = DPSW_FDB_ENTRY_STATIC; ++ ether_addr_copy(entry.mac_addr, addr); ++ ++ err = dpsw_fdb_remove_unicast(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ 0, &entry); ++ if (err) ++ netdev_err(netdev, "dpsw_fdb_remove_unicast err %d\n", err); ++ return err; ++} ++ ++static int ethsw_port_fdb_add_mc(struct net_device *netdev, ++ const unsigned char *addr) ++{ ++ struct ethsw_port_priv *port_priv = netdev_priv(netdev); ++ struct dpsw_fdb_multicast_cfg entry = {0}; ++ int err; ++ ++ ether_addr_copy(entry.mac_addr, addr); ++ entry.type = DPSW_FDB_ENTRY_STATIC; ++ entry.num_ifs = 1; ++ entry.if_id[0] = port_priv->port_index; ++ ++ err = dpsw_fdb_add_multicast(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ 0, &entry); ++ if (err) ++ netdev_err(netdev, "dpsw_fdb_add_multicast err %d\n", err); ++ return err; ++} ++ ++static int ethsw_port_fdb_del_mc(struct net_device *netdev, ++ const unsigned char *addr) ++{ ++ struct ethsw_port_priv *port_priv = netdev_priv(netdev); ++ struct dpsw_fdb_multicast_cfg entry = {0}; ++ int err; ++ ++ ether_addr_copy(entry.mac_addr, addr); ++ entry.type = DPSW_FDB_ENTRY_STATIC; ++ entry.num_ifs = 1; ++ entry.if_id[0] = port_priv->port_index; ++ ++ err = dpsw_fdb_remove_multicast(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ 0, &entry); ++ if (err) ++ netdev_err(netdev, "dpsw_fdb_remove_multicast err %d\n", err); ++ return err; ++} ++ ++static int _lookup_address(struct net_device *netdev, int is_uc, ++ const unsigned char *addr) ++{ ++ struct netdev_hw_addr *ha; ++ struct netdev_hw_addr_list *list = (is_uc) ? &netdev->uc : &netdev->mc; ++ ++ netif_addr_lock_bh(netdev); ++ list_for_each_entry(ha, &list->list, list) { ++ if (ether_addr_equal(ha->addr, addr)) { ++ netif_addr_unlock_bh(netdev); ++ return 1; ++ } ++ } ++ netif_addr_unlock_bh(netdev); ++ return 0; ++} ++ ++static int ethsw_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], ++ struct net_device *netdev, ++ const unsigned char *addr, u16 vid, ++ u16 flags) ++{ ++ struct list_head *pos; ++ struct ethsw_port_priv *port_priv = netdev_priv(netdev); ++ struct ethsw_dev_priv *priv = port_priv->ethsw_priv; ++ int err; ++ ++ /* TODO: add replace support when added to iproute bridge */ ++ if (!(flags & NLM_F_REQUEST)) { ++ netdev_err(netdev, ++ "ethsw_port_fdb_add unexpected flags value %08x\n", ++ flags); ++ return -EINVAL; ++ } ++ ++ if (is_unicast_ether_addr(addr)) { ++ /* if entry cannot be replaced, return error if exists */ ++ if (flags & NLM_F_EXCL || flags & NLM_F_APPEND) { ++ list_for_each(pos, &priv->port_list) { ++ port_priv = list_entry(pos, ++ struct ethsw_port_priv, ++ list); ++ if (_lookup_address(port_priv->netdev, ++ 1, addr)) ++ return -EEXIST; ++ } ++ } ++ ++ err = ethsw_port_fdb_add_uc(netdev, addr); ++ if (err) { ++ netdev_err(netdev, "ethsw_port_fdb_add_uc err %d\n", ++ err); ++ return err; ++ } ++ ++ /* we might have replaced an existing entry for a different ++ * switch port, make sure the address doesn't linger in any ++ * port address list ++ */ ++ list_for_each(pos, &priv->port_list) { ++ port_priv = list_entry(pos, struct ethsw_port_priv, ++ list); ++ dev_uc_del(port_priv->netdev, addr); ++ } ++ ++ err = dev_uc_add(netdev, addr); ++ if (err) { ++ netdev_err(netdev, "dev_uc_add err %d\n", err); ++ return err; ++ } ++ } else { ++ struct dpsw_fdb_multicast_cfg entry = { ++ .type = DPSW_FDB_ENTRY_STATIC, ++ .num_ifs = 0, ++ }; ++ ++ /* check if address is already set on this port */ ++ if (_lookup_address(netdev, 0, addr)) ++ return -EEXIST; ++ ++ /* check if the address exists on other port */ ++ ether_addr_copy(entry.mac_addr, addr); ++ err = dpsw_fdb_get_multicast(priv->mc_io, 0, priv->dpsw_handle, ++ 0, &entry); ++ if (!err) { ++ /* entry exists, can we replace it? */ ++ if (flags & NLM_F_EXCL) ++ return -EEXIST; ++ } else if (err != -ENAVAIL) { ++ netdev_err(netdev, "dpsw_fdb_get_unicast err %d\n", ++ err); ++ return err; ++ } ++ ++ err = ethsw_port_fdb_add_mc(netdev, addr); ++ if (err) { ++ netdev_err(netdev, "ethsw_port_fdb_add_mc err %d\n", ++ err); ++ return err; ++ } ++ ++ err = dev_mc_add(netdev, addr); ++ if (err) { ++ netdev_err(netdev, "dev_mc_add err %d\n", err); ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ ++static int ethsw_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], ++ struct net_device *netdev, ++ const unsigned char *addr, u16 vid) ++{ ++ int err; ++ ++ if (is_unicast_ether_addr(addr)) { ++ err = ethsw_port_fdb_del_uc(netdev, addr); ++ if (err) { ++ netdev_err(netdev, "ethsw_port_fdb_del_uc err %d\n", ++ err); ++ return err; ++ } ++ ++ /* also delete if configured on port */ ++ err = dev_uc_del(netdev, addr); ++ if (err && err != -ENOENT) { ++ netdev_err(netdev, "dev_uc_del err %d\n", err); ++ return err; ++ } ++ } else { ++ if (!_lookup_address(netdev, 0, addr)) ++ return -ENOENT; ++ ++ err = dev_mc_del(netdev, addr); ++ if (err) { ++ netdev_err(netdev, "dev_mc_del err %d\n", err); ++ return err; ++ } ++ ++ err = ethsw_port_fdb_del_mc(netdev, addr); ++ if (err) { ++ netdev_err(netdev, "ethsw_port_fdb_del_mc err %d\n", ++ err); ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ ++void ethsw_port_get_stats(struct net_device *netdev, ++ struct rtnl_link_stats64 *storage) ++{ ++ struct ethsw_port_priv *port_priv = netdev_priv(netdev); ++ u64 tmp; ++ int err; ++ ++ err = dpsw_if_get_counter(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ port_priv->port_index, ++ DPSW_CNT_ING_FRAME, &storage->rx_packets); ++ if (err) ++ goto error; ++ ++ err = dpsw_if_get_counter(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ port_priv->port_index, ++ DPSW_CNT_EGR_FRAME, &storage->tx_packets); ++ if (err) ++ goto error; ++ ++ err = dpsw_if_get_counter(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ port_priv->port_index, ++ DPSW_CNT_ING_BYTE, &storage->rx_bytes); ++ if (err) ++ goto error; ++ ++ err = dpsw_if_get_counter(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ port_priv->port_index, ++ DPSW_CNT_EGR_BYTE, &storage->tx_bytes); ++ if (err) ++ goto error; ++ ++ err = dpsw_if_get_counter(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ port_priv->port_index, ++ DPSW_CNT_ING_FRAME_DISCARD, ++ &storage->rx_dropped); ++ if (err) ++ goto error; ++ ++ err = dpsw_if_get_counter(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ port_priv->port_index, ++ DPSW_CNT_ING_FLTR_FRAME, ++ &tmp); ++ if (err) ++ goto error; ++ storage->rx_dropped += tmp; ++ ++ err = dpsw_if_get_counter(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ port_priv->port_index, ++ DPSW_CNT_EGR_FRAME_DISCARD, ++ &storage->tx_dropped); ++ if (err) ++ goto error; ++ ++ return; ++ ++error: ++ netdev_err(netdev, "dpsw_if_get_counter err %d\n", err); ++} ++ ++static int ethsw_port_change_mtu(struct net_device *netdev, int mtu) ++{ ++ struct ethsw_port_priv *port_priv = netdev_priv(netdev); ++ int err; ++ ++ if (mtu < ETH_ZLEN || mtu > ETHSW_MAX_FRAME_LENGTH) { ++ netdev_err(netdev, "Invalid MTU %d. Valid range is: %d..%d\n", ++ mtu, ETH_ZLEN, ETHSW_MAX_FRAME_LENGTH); ++ return -EINVAL; ++ } ++ ++ err = dpsw_if_set_max_frame_length(port_priv->ethsw_priv->mc_io, ++ 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ port_priv->port_index, ++ (u16)ETHSW_L2_MAX_FRM(mtu)); ++ if (err) { ++ netdev_err(netdev, ++ "dpsw_if_set_max_frame_length() err %d\n", err); ++ return err; ++ } ++ ++ netdev->mtu = mtu; ++ return 0; ++} ++ ++static const struct net_device_ops ethsw_port_ops = { ++ .ndo_open = ðsw_port_open, ++ .ndo_stop = ðsw_port_stop, ++ ++ .ndo_fdb_add = ðsw_port_fdb_add, ++ .ndo_fdb_del = ðsw_port_fdb_del, ++ .ndo_fdb_dump = &ndo_dflt_fdb_dump, ++ ++ .ndo_get_stats64 = ðsw_port_get_stats, ++ .ndo_change_mtu = ðsw_port_change_mtu, ++ ++ .ndo_start_xmit = ðsw_dropframe, ++}; ++ ++static void ethsw_get_drvinfo(struct net_device *netdev, ++ struct ethtool_drvinfo *drvinfo) ++{ ++ struct ethsw_port_priv *port_priv = netdev_priv(netdev); ++ u16 version_major, version_minor; ++ int err; ++ ++ strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver)); ++ strlcpy(drvinfo->version, ethsw_drv_version, sizeof(drvinfo->version)); ++ ++ err = dpsw_get_api_version(port_priv->ethsw_priv->mc_io, 0, ++ &version_major, ++ &version_minor); ++ if (err) ++ strlcpy(drvinfo->fw_version, "N/A", ++ sizeof(drvinfo->fw_version)); ++ else ++ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), ++ "%u.%u", version_major, version_minor); ++ ++ strlcpy(drvinfo->bus_info, dev_name(netdev->dev.parent->parent), ++ sizeof(drvinfo->bus_info)); ++} ++ ++static int ethsw_get_settings(struct net_device *netdev, ++ struct ethtool_cmd *cmd) ++{ ++ struct ethsw_port_priv *port_priv = netdev_priv(netdev); ++ struct dpsw_link_state state = {0}; ++ int err = 0; ++ ++ err = dpsw_if_get_link_state(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ port_priv->port_index, ++ &state); ++ if (err) { ++ netdev_err(netdev, "ERROR %d getting link state", err); ++ goto out; ++ } ++ ++ /* At the moment, we have no way of interrogating the DPMAC ++ * from the DPSW side or there may not exist a DPMAC at all. ++ * Report only autoneg state, duplexity and speed. ++ */ ++ if (state.options & DPSW_LINK_OPT_AUTONEG) ++ cmd->autoneg = AUTONEG_ENABLE; ++ if (!(state.options & DPSW_LINK_OPT_HALF_DUPLEX)) ++ cmd->autoneg = DUPLEX_FULL; ++ ethtool_cmd_speed_set(cmd, state.rate); ++ ++out: ++ return err; ++} ++ ++static int ethsw_set_settings(struct net_device *netdev, ++ struct ethtool_cmd *cmd) ++{ ++ struct ethsw_port_priv *port_priv = netdev_priv(netdev); ++ struct dpsw_link_state state = {0}; ++ struct dpsw_link_cfg cfg = {0}; ++ int err = 0; ++ ++ netdev_dbg(netdev, "Setting link parameters..."); ++ ++ err = dpsw_if_get_link_state(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ port_priv->port_index, ++ &state); ++ if (err) { ++ netdev_err(netdev, "ERROR %d getting link state", err); ++ goto out; ++ } ++ ++ /* Due to a temporary MC limitation, the DPSW port must be down ++ * in order to be able to change link settings. Taking steps to let ++ * the user know that. ++ */ ++ if (netif_running(netdev)) { ++ netdev_info(netdev, ++ "Sorry, interface must be brought down first.\n"); ++ return -EACCES; ++ } ++ ++ cfg.options = state.options; ++ cfg.rate = ethtool_cmd_speed(cmd); ++ if (cmd->autoneg == AUTONEG_ENABLE) ++ cfg.options |= DPSW_LINK_OPT_AUTONEG; ++ else ++ cfg.options &= ~DPSW_LINK_OPT_AUTONEG; ++ if (cmd->duplex == DUPLEX_HALF) ++ cfg.options |= DPSW_LINK_OPT_HALF_DUPLEX; ++ else ++ cfg.options &= ~DPSW_LINK_OPT_HALF_DUPLEX; ++ ++ err = dpsw_if_set_link_cfg(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ port_priv->port_index, ++ &cfg); ++ if (err) ++ /* ethtool will be loud enough if we return an error; no point ++ * in putting our own error message on the console by default ++ */ ++ netdev_dbg(netdev, "ERROR %d setting link cfg", err); ++ ++out: ++ return err; ++} ++ ++static struct { ++ enum dpsw_counter id; ++ char name[ETH_GSTRING_LEN]; ++} ethsw_ethtool_counters[] = { ++ {DPSW_CNT_ING_FRAME, "rx frames"}, ++ {DPSW_CNT_ING_BYTE, "rx bytes"}, ++ {DPSW_CNT_ING_FLTR_FRAME, "rx filtered frames"}, ++ {DPSW_CNT_ING_FRAME_DISCARD, "rx discarded frames"}, ++ {DPSW_CNT_ING_BCAST_FRAME, "rx b-cast frames"}, ++ {DPSW_CNT_ING_BCAST_BYTES, "rx b-cast bytes"}, ++ {DPSW_CNT_ING_MCAST_FRAME, "rx m-cast frames"}, ++ {DPSW_CNT_ING_MCAST_BYTE, "rx m-cast bytes"}, ++ {DPSW_CNT_EGR_FRAME, "tx frames"}, ++ {DPSW_CNT_EGR_BYTE, "tx bytes"}, ++ {DPSW_CNT_EGR_FRAME_DISCARD, "tx discarded frames"}, ++ ++}; ++ ++static int ethsw_ethtool_get_sset_count(struct net_device *dev, int sset) ++{ ++ switch (sset) { ++ case ETH_SS_STATS: ++ return ARRAY_SIZE(ethsw_ethtool_counters); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static void ethsw_ethtool_get_strings(struct net_device *netdev, ++ u32 stringset, u8 *data) ++{ ++ u32 i; ++ ++ switch (stringset) { ++ case ETH_SS_STATS: ++ for (i = 0; i < ARRAY_SIZE(ethsw_ethtool_counters); i++) ++ memcpy(data + i * ETH_GSTRING_LEN, ++ ethsw_ethtool_counters[i].name, ETH_GSTRING_LEN); ++ break; ++ } ++} ++ ++static void ethsw_ethtool_get_stats(struct net_device *netdev, ++ struct ethtool_stats *stats, ++ u64 *data) ++{ ++ struct ethsw_port_priv *port_priv = netdev_priv(netdev); ++ u32 i; ++ int err; ++ ++ for (i = 0; i < ARRAY_SIZE(ethsw_ethtool_counters); i++) { ++ err = dpsw_if_get_counter(port_priv->ethsw_priv->mc_io, 0, ++ port_priv->ethsw_priv->dpsw_handle, ++ port_priv->port_index, ++ ethsw_ethtool_counters[i].id, ++ &data[i]); ++ if (err) ++ netdev_err(netdev, "dpsw_if_get_counter[%s] err %d\n", ++ ethsw_ethtool_counters[i].name, err); ++ } ++} ++ ++static const struct ethtool_ops ethsw_port_ethtool_ops = { ++ .get_drvinfo = ðsw_get_drvinfo, ++ .get_link = ðtool_op_get_link, ++ .get_settings = ðsw_get_settings, ++ .set_settings = ðsw_set_settings, ++ .get_strings = ðsw_ethtool_get_strings, ++ .get_ethtool_stats = ðsw_ethtool_get_stats, ++ .get_sset_count = ðsw_ethtool_get_sset_count, ++}; ++ ++/* -------------------------------------------------------------------------- */ ++/* ethsw driver functions */ ++ ++static int ethsw_links_state_update(struct ethsw_dev_priv *priv) ++{ ++ struct list_head *pos; ++ struct ethsw_port_priv *port_priv; ++ int err; ++ ++ list_for_each(pos, &priv->port_list) { ++ port_priv = list_entry(pos, struct ethsw_port_priv, ++ list); ++ ++ err = _ethsw_port_carrier_state_sync(port_priv->netdev); ++ if (err) ++ netdev_err(port_priv->netdev, ++ "_ethsw_port_carrier_state_sync err %d\n", ++ err); ++ } ++ ++ return 0; ++} ++ ++static irqreturn_t ethsw_irq0_handler(int irq_num, void *arg) ++{ ++ return IRQ_WAKE_THREAD; ++} ++ ++static irqreturn_t _ethsw_irq0_handler_thread(int irq_num, void *arg) ++{ ++ struct device *dev = (struct device *)arg; ++ struct net_device *netdev = dev_get_drvdata(dev); ++ struct ethsw_dev_priv *priv = netdev_priv(netdev); ++ ++ struct fsl_mc_io *io = priv->mc_io; ++ u16 token = priv->dpsw_handle; ++ int irq_index = DPSW_IRQ_INDEX_IF; ++ ++ /* Mask the events and the if_id reserved bits to be cleared on read */ ++ u32 status = DPSW_IRQ_EVENT_LINK_CHANGED | 0xFFFF0000; ++ int err; ++ ++ err = dpsw_get_irq_status(io, 0, token, irq_index, &status); ++ if (unlikely(err)) { ++ netdev_err(netdev, "Can't get irq status (err %d)", err); ++ ++ err = dpsw_clear_irq_status(io, 0, token, irq_index, ++ 0xFFFFFFFF); ++ if (unlikely(err)) ++ netdev_err(netdev, "Can't clear irq status (err %d)", ++ err); ++ goto out; ++ } ++ ++ if (status & DPSW_IRQ_EVENT_LINK_CHANGED) { ++ err = ethsw_links_state_update(priv); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++out: ++ return IRQ_HANDLED; ++} ++ ++static int ethsw_setup_irqs(struct fsl_mc_device *sw_dev) ++{ ++ struct device *dev = &sw_dev->dev; ++ struct net_device *netdev = dev_get_drvdata(dev); ++ struct ethsw_dev_priv *priv = netdev_priv(netdev); ++ int err = 0; ++ struct fsl_mc_device_irq *irq; ++ const int irq_index = DPSW_IRQ_INDEX_IF; ++ u32 mask = DPSW_IRQ_EVENT_LINK_CHANGED; ++ ++ err = fsl_mc_allocate_irqs(sw_dev); ++ if (unlikely(err)) { ++ dev_err(dev, "MC irqs allocation failed\n"); ++ return err; ++ } ++ ++ if (WARN_ON(sw_dev->obj_desc.irq_count != DPSW_MAX_IRQ_NUM)) { ++ err = -EINVAL; ++ goto free_irq; ++ } ++ ++ err = dpsw_set_irq_enable(priv->mc_io, 0, priv->dpsw_handle, ++ irq_index, 0); ++ if (unlikely(err)) { ++ dev_err(dev, "dpsw_set_irq_enable err %d\n", err); ++ goto free_irq; ++ } ++ ++ irq = sw_dev->irqs[irq_index]; ++ ++ err = devm_request_threaded_irq(dev, irq->msi_desc->irq, ++ ethsw_irq0_handler, ++ _ethsw_irq0_handler_thread, ++ IRQF_NO_SUSPEND | IRQF_ONESHOT, ++ dev_name(dev), dev); ++ if (unlikely(err)) { ++ dev_err(dev, "devm_request_threaded_irq(): %d", err); ++ goto free_irq; ++ } ++ ++ err = dpsw_set_irq_mask(priv->mc_io, 0, priv->dpsw_handle, ++ irq_index, mask); ++ if (unlikely(err)) { ++ dev_err(dev, "dpsw_set_irq_mask(): %d", err); ++ goto free_devm_irq; ++ } ++ ++ err = dpsw_set_irq_enable(priv->mc_io, 0, priv->dpsw_handle, ++ irq_index, 1); ++ if (unlikely(err)) { ++ dev_err(dev, "dpsw_set_irq_enable(): %d", err); ++ goto free_devm_irq; ++ } ++ ++ return 0; ++ ++free_devm_irq: ++ devm_free_irq(dev, irq->msi_desc->irq, dev); ++free_irq: ++ fsl_mc_free_irqs(sw_dev); ++ return err; ++} ++ ++static void ethsw_teardown_irqs(struct fsl_mc_device *sw_dev) ++{ ++ struct device *dev = &sw_dev->dev; ++ struct net_device *netdev = dev_get_drvdata(dev); ++ struct ethsw_dev_priv *priv = netdev_priv(netdev); ++ ++ dpsw_set_irq_enable(priv->mc_io, 0, priv->dpsw_handle, ++ DPSW_IRQ_INDEX_IF, 0); ++ devm_free_irq(dev, ++ sw_dev->irqs[DPSW_IRQ_INDEX_IF]->msi_desc->irq, ++ dev); ++ fsl_mc_free_irqs(sw_dev); ++} ++ ++static int __cold ++ethsw_init(struct fsl_mc_device *sw_dev) ++{ ++ struct device *dev = &sw_dev->dev; ++ struct ethsw_dev_priv *priv; ++ struct net_device *netdev; ++ int err = 0; ++ u16 i; ++ u16 version_major, version_minor; ++ const struct dpsw_stp_cfg stp_cfg = { ++ .vlan_id = 1, ++ .state = DPSW_STP_STATE_FORWARDING, ++ }; ++ ++ netdev = dev_get_drvdata(dev); ++ priv = netdev_priv(netdev); ++ ++ priv->dev_id = sw_dev->obj_desc.id; ++ ++ err = dpsw_open(priv->mc_io, 0, priv->dev_id, &priv->dpsw_handle); ++ if (err) { ++ dev_err(dev, "dpsw_open err %d\n", err); ++ goto err_exit; ++ } ++ if (!priv->dpsw_handle) { ++ dev_err(dev, "dpsw_open returned null handle but no error\n"); ++ err = -EFAULT; ++ goto err_exit; ++ } ++ ++ err = dpsw_get_attributes(priv->mc_io, 0, priv->dpsw_handle, ++ &priv->sw_attr); ++ if (err) { ++ dev_err(dev, "dpsw_get_attributes err %d\n", err); ++ goto err_close; ++ } ++ ++ err = dpsw_get_api_version(priv->mc_io, 0, ++ &version_major, ++ &version_minor); ++ if (err) { ++ dev_err(dev, "dpsw_get_api_version err %d\n", err); ++ goto err_close; ++ } ++ ++ /* Minimum supported DPSW version check */ ++ if (version_major < DPSW_MIN_VER_MAJOR || ++ (version_major == DPSW_MIN_VER_MAJOR && ++ version_minor < DPSW_MIN_VER_MINOR)) { ++ dev_err(dev, "DPSW version %d:%d not supported. Use %d.%d or greater.\n", ++ version_major, ++ version_minor, ++ DPSW_MIN_VER_MAJOR, DPSW_MIN_VER_MINOR); ++ err = -ENOTSUPP; ++ goto err_close; ++ } ++ ++ err = dpsw_reset(priv->mc_io, 0, priv->dpsw_handle); ++ if (err) { ++ dev_err(dev, "dpsw_reset err %d\n", err); ++ goto err_close; ++ } ++ ++ err = dpsw_fdb_set_learning_mode(priv->mc_io, 0, priv->dpsw_handle, 0, ++ DPSW_FDB_LEARNING_MODE_HW); ++ if (err) { ++ dev_err(dev, "dpsw_fdb_set_learning_mode err %d\n", err); ++ goto err_close; ++ } ++ ++ for (i = 0; i < priv->sw_attr.num_ifs; i++) { ++ err = dpsw_if_set_stp(priv->mc_io, 0, priv->dpsw_handle, i, ++ &stp_cfg); ++ if (err) { ++ dev_err(dev, "dpsw_if_set_stp err %d for port %d\n", ++ err, i); ++ goto err_close; ++ } ++ ++ err = dpsw_if_set_broadcast(priv->mc_io, 0, ++ priv->dpsw_handle, i, 1); ++ if (err) { ++ dev_err(dev, ++ "dpsw_if_set_broadcast err %d for port %d\n", ++ err, i); ++ goto err_close; ++ } ++ } ++ ++ return 0; ++ ++err_close: ++ dpsw_close(priv->mc_io, 0, priv->dpsw_handle); ++err_exit: ++ return err; ++} ++ ++static int __cold ++ethsw_takedown(struct fsl_mc_device *sw_dev) ++{ ++ struct device *dev = &sw_dev->dev; ++ struct net_device *netdev; ++ struct ethsw_dev_priv *priv; ++ int err; ++ ++ netdev = dev_get_drvdata(dev); ++ priv = netdev_priv(netdev); ++ ++ err = dpsw_close(priv->mc_io, 0, priv->dpsw_handle); ++ if (err) ++ dev_warn(dev, "dpsw_close err %d\n", err); ++ ++ return 0; ++} ++ ++static int __cold ++ethsw_remove(struct fsl_mc_device *sw_dev) ++{ ++ struct device *dev; ++ struct net_device *netdev; ++ struct ethsw_dev_priv *priv; ++ struct ethsw_port_priv *port_priv; ++ struct list_head *pos; ++ ++ dev = &sw_dev->dev; ++ netdev = dev_get_drvdata(dev); ++ priv = netdev_priv(netdev); ++ ++ list_for_each(pos, &priv->port_list) { ++ port_priv = list_entry(pos, struct ethsw_port_priv, list); ++ ++ rtnl_lock(); ++ netdev_upper_dev_unlink(port_priv->netdev, netdev); ++ rtnl_unlock(); ++ ++ unregister_netdev(port_priv->netdev); ++ free_netdev(port_priv->netdev); ++ } ++ ++ ethsw_teardown_irqs(sw_dev); ++ ++ unregister_netdev(netdev); ++ ++ ethsw_takedown(sw_dev); ++ fsl_mc_portal_free(priv->mc_io); ++ ++ dev_set_drvdata(dev, NULL); ++ free_netdev(netdev); ++ ++ return 0; ++} ++ ++static int __cold ++ethsw_probe(struct fsl_mc_device *sw_dev) ++{ ++ struct device *dev; ++ struct net_device *netdev = NULL; ++ struct ethsw_dev_priv *priv = NULL; ++ int err = 0; ++ u16 i; ++ const char def_mcast[ETH_ALEN] = { ++ 0x01, 0x00, 0x5e, 0x00, 0x00, 0x01, ++ }; ++ char port_name[IFNAMSIZ]; ++ ++ dev = &sw_dev->dev; ++ ++ /* register switch device, it's for management only - no I/O */ ++ netdev = alloc_etherdev(sizeof(*priv)); ++ if (!netdev) { ++ dev_err(dev, "alloc_etherdev error\n"); ++ return -ENOMEM; ++ } ++ netdev->netdev_ops = ðsw_ops; ++ ++ SET_NETDEV_DEV(netdev, dev); ++ dev_set_drvdata(dev, netdev); ++ ++ priv = netdev_priv(netdev); ++ priv->netdev = netdev; ++ ++ err = fsl_mc_portal_allocate(sw_dev, 0, &priv->mc_io); ++ if (err) { ++ dev_err(dev, "fsl_mc_portal_allocate err %d\n", err); ++ goto err_free_netdev; ++ } ++ if (!priv->mc_io) { ++ dev_err(dev, "fsl_mc_portal_allocate returned null handle but no error\n"); ++ err = -EFAULT; ++ goto err_free_netdev; ++ } ++ ++ err = ethsw_init(sw_dev); ++ if (err) { ++ dev_err(dev, "switch init err %d\n", err); ++ goto err_free_cmdport; ++ } ++ ++ netdev->flags = netdev->flags | IFF_PROMISC | IFF_MASTER; ++ ++ /* TODO: should we hold rtnl_lock here? We can't register_netdev under ++ * lock ++ */ ++ dev_alloc_name(netdev, "sw%d"); ++ err = register_netdev(netdev); ++ if (err < 0) { ++ dev_err(dev, "register_netdev error %d\n", err); ++ goto err_takedown; ++ } ++ if (err) ++ dev_info(dev, "register_netdev res %d\n", err); ++ ++ /* VLAN 1 is implicitly configured on the switch */ ++ priv->vlans[1] = ETHSW_VLAN_MEMBER; ++ /* Flooding, learning are implicitly enabled */ ++ priv->learning = true; ++ priv->flood = true; ++ ++ /* register switch ports */ ++ snprintf(port_name, IFNAMSIZ, "%sp%%d", netdev->name); ++ ++ INIT_LIST_HEAD(&priv->port_list); ++ for (i = 0; i < priv->sw_attr.num_ifs; i++) { ++ struct net_device *port_netdev; ++ struct ethsw_port_priv *port_priv; ++ ++ port_netdev = alloc_etherdev(sizeof(struct ethsw_port_priv)); ++ if (!port_netdev) { ++ dev_err(dev, "alloc_etherdev error\n"); ++ goto err_takedown; ++ } ++ ++ port_priv = netdev_priv(port_netdev); ++ port_priv->netdev = port_netdev; ++ port_priv->ethsw_priv = priv; ++ ++ port_priv->port_index = i; ++ port_priv->stp_state = BR_STATE_FORWARDING; ++ /* VLAN 1 is configured by default on all switch ports */ ++ port_priv->vlans[1] = ETHSW_VLAN_MEMBER | ETHSW_VLAN_UNTAGGED | ++ ETHSW_VLAN_PVID; ++ ++ SET_NETDEV_DEV(port_netdev, dev); ++ port_netdev->netdev_ops = ðsw_port_ops; ++ port_netdev->ethtool_ops = ðsw_port_ethtool_ops; ++ ++ port_netdev->flags = port_netdev->flags | ++ IFF_PROMISC | IFF_SLAVE; ++ ++ dev_alloc_name(port_netdev, port_name); ++ err = register_netdev(port_netdev); ++ if (err < 0) { ++ dev_err(dev, "register_netdev error %d\n", err); ++ free_netdev(port_netdev); ++ goto err_takedown; ++ } ++ ++ rtnl_lock(); ++ ++ err = netdev_master_upper_dev_link(port_netdev, netdev, ++ NULL, NULL); ++ if (err) { ++ dev_err(dev, "netdev_master_upper_dev_link error %d\n", ++ err); ++ unregister_netdev(port_netdev); ++ free_netdev(port_netdev); ++ rtnl_unlock(); ++ goto err_takedown; ++ } ++ ++ rtmsg_ifinfo(RTM_NEWLINK, port_netdev, IFF_SLAVE, GFP_KERNEL); ++ ++ rtnl_unlock(); ++ ++ list_add(&port_priv->list, &priv->port_list); ++ ++ /* TODO: implmenet set_rm_mode instead of this */ ++ err = ethsw_port_fdb_add_mc(port_netdev, def_mcast); ++ if (err) ++ dev_warn(&netdev->dev, ++ "ethsw_port_fdb_add_mc err %d\n", err); ++ } ++ ++ /* the switch starts up enabled */ ++ rtnl_lock(); ++ err = dev_open(netdev); ++ rtnl_unlock(); ++ if (err) ++ dev_warn(dev, "dev_open err %d\n", err); ++ ++ /* setup irqs */ ++ err = ethsw_setup_irqs(sw_dev); ++ if (unlikely(err)) { ++ dev_warn(dev, "ethsw_setup_irqs err %d\n", err); ++ goto err_takedown; ++ } ++ ++ dev_info(&netdev->dev, ++ "probed %d port switch\n", priv->sw_attr.num_ifs); ++ return 0; ++ ++err_takedown: ++ ethsw_remove(sw_dev); ++err_free_cmdport: ++ fsl_mc_portal_free(priv->mc_io); ++err_free_netdev: ++ dev_set_drvdata(dev, NULL); ++ free_netdev(netdev); ++ ++ return err; ++} ++ ++static const struct fsl_mc_device_id ethsw_match_id_table[] = { ++ { ++ .vendor = FSL_MC_VENDOR_FREESCALE, ++ .obj_type = "dpsw", ++ }, ++ {} ++}; ++ ++static struct fsl_mc_driver eth_sw_drv = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = ethsw_probe, ++ .remove = ethsw_remove, ++ .match_id_table = ethsw_match_id_table, ++}; ++ ++module_fsl_mc_driver(eth_sw_drv); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("DPAA2 Ethernet Switch Driver (prototype)"); +diff --git a/drivers/staging/fsl-dpaa2/evb/Kconfig b/drivers/staging/fsl-dpaa2/evb/Kconfig +new file mode 100644 +index 00000000..3534f697 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/evb/Kconfig +@@ -0,0 +1,7 @@ ++config FSL_DPAA2_EVB ++ tristate "DPAA2 Edge Virtual Bridge" ++ depends on FSL_MC_BUS && FSL_DPAA2 ++ select VLAN_8021Q ++ default y ++ ---help--- ++ Prototype driver for DPAA2 Edge Virtual Bridge. +diff --git a/drivers/staging/fsl-dpaa2/evb/Makefile b/drivers/staging/fsl-dpaa2/evb/Makefile +new file mode 100644 +index 00000000..ecc529d7 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/evb/Makefile +@@ -0,0 +1,10 @@ ++ ++obj-$(CONFIG_FSL_DPAA2_EVB) += dpaa2-evb.o ++ ++dpaa2-evb-objs := evb.o dpdmux.o ++ ++all: ++ make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules ++ ++clean: ++ make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean +diff --git a/drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h b/drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h +new file mode 100644 +index 00000000..66306804 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/evb/dpdmux-cmd.h +@@ -0,0 +1,279 @@ ++/* Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef _FSL_DPDMUX_CMD_H ++#define _FSL_DPDMUX_CMD_H ++ ++/* DPDMUX Version */ ++#define DPDMUX_VER_MAJOR 6 ++#define DPDMUX_VER_MINOR 1 ++ ++#define DPDMUX_CMD_BASE_VER 1 ++#define DPDMUX_CMD_ID_OFFSET 4 ++ ++#define DPDMUX_CMD(id) (((id) << DPDMUX_CMD_ID_OFFSET) | DPDMUX_CMD_BASE_VER) ++ ++/* Command IDs */ ++#define DPDMUX_CMDID_CLOSE DPDMUX_CMD(0x800) ++#define DPDMUX_CMDID_OPEN DPDMUX_CMD(0x806) ++#define DPDMUX_CMDID_CREATE DPDMUX_CMD(0x906) ++#define DPDMUX_CMDID_DESTROY DPDMUX_CMD(0x986) ++#define DPDMUX_CMDID_GET_API_VERSION DPDMUX_CMD(0xa06) ++ ++#define DPDMUX_CMDID_ENABLE DPDMUX_CMD(0x002) ++#define DPDMUX_CMDID_DISABLE DPDMUX_CMD(0x003) ++#define DPDMUX_CMDID_GET_ATTR DPDMUX_CMD(0x004) ++#define DPDMUX_CMDID_RESET DPDMUX_CMD(0x005) ++#define DPDMUX_CMDID_IS_ENABLED DPDMUX_CMD(0x006) ++ ++#define DPDMUX_CMDID_SET_IRQ_ENABLE DPDMUX_CMD(0x012) ++#define DPDMUX_CMDID_GET_IRQ_ENABLE DPDMUX_CMD(0x013) ++#define DPDMUX_CMDID_SET_IRQ_MASK DPDMUX_CMD(0x014) ++#define DPDMUX_CMDID_GET_IRQ_MASK DPDMUX_CMD(0x015) ++#define DPDMUX_CMDID_GET_IRQ_STATUS DPDMUX_CMD(0x016) ++#define DPDMUX_CMDID_CLEAR_IRQ_STATUS DPDMUX_CMD(0x017) ++ ++#define DPDMUX_CMDID_SET_MAX_FRAME_LENGTH DPDMUX_CMD(0x0a1) ++ ++#define DPDMUX_CMDID_UL_RESET_COUNTERS DPDMUX_CMD(0x0a3) ++ ++#define DPDMUX_CMDID_IF_SET_ACCEPTED_FRAMES DPDMUX_CMD(0x0a7) ++#define DPDMUX_CMDID_IF_GET_ATTR DPDMUX_CMD(0x0a8) ++#define DPDMUX_CMDID_IF_ENABLE DPDMUX_CMD(0x0a9) ++#define DPDMUX_CMDID_IF_DISABLE DPDMUX_CMD(0x0aa) ++ ++#define DPDMUX_CMDID_IF_ADD_L2_RULE DPDMUX_CMD(0x0b0) ++#define DPDMUX_CMDID_IF_REMOVE_L2_RULE DPDMUX_CMD(0x0b1) ++#define DPDMUX_CMDID_IF_GET_COUNTER DPDMUX_CMD(0x0b2) ++#define DPDMUX_CMDID_IF_SET_LINK_CFG DPDMUX_CMD(0x0b3) ++#define DPDMUX_CMDID_IF_GET_LINK_STATE DPDMUX_CMD(0x0b4) ++ ++#define DPDMUX_CMDID_SET_CUSTOM_KEY DPDMUX_CMD(0x0b5) ++#define DPDMUX_CMDID_ADD_CUSTOM_CLS_ENTRY DPDMUX_CMD(0x0b6) ++#define DPDMUX_CMDID_REMOVE_CUSTOM_CLS_ENTRY DPDMUX_CMD(0x0b7) ++ ++#define DPDMUX_MASK(field) \ ++ GENMASK(DPDMUX_##field##_SHIFT + DPDMUX_##field##_SIZE - 1, \ ++ DPDMUX_##field##_SHIFT) ++#define dpdmux_set_field(var, field, val) \ ++ ((var) |= (((val) << DPDMUX_##field##_SHIFT) & DPDMUX_MASK(field))) ++#define dpdmux_get_field(var, field) \ ++ (((var) & DPDMUX_MASK(field)) >> DPDMUX_##field##_SHIFT) ++ ++struct dpdmux_cmd_open { ++ u32 dpdmux_id; ++}; ++ ++struct dpdmux_cmd_create { ++ u8 method; ++ u8 manip; ++ u16 num_ifs; ++ u32 pad; ++ ++ u16 adv_max_dmat_entries; ++ u16 adv_max_mc_groups; ++ u16 adv_max_vlan_ids; ++ u16 pad1; ++ ++ u64 options; ++}; ++ ++struct dpdmux_cmd_destroy { ++ u32 dpdmux_id; ++}; ++ ++#define DPDMUX_ENABLE_SHIFT 0 ++#define DPDMUX_ENABLE_SIZE 1 ++ ++struct dpdmux_rsp_is_enabled { ++ u8 en; ++}; ++ ++struct dpdmux_cmd_set_irq_enable { ++ u8 enable; ++ u8 pad[3]; ++ u8 irq_index; ++}; ++ ++struct dpdmux_cmd_get_irq_enable { ++ u32 pad; ++ u8 irq_index; ++}; ++ ++struct dpdmux_rsp_get_irq_enable { ++ u8 enable; ++}; ++ ++struct dpdmux_cmd_set_irq_mask { ++ u32 mask; ++ u8 irq_index; ++}; ++ ++struct dpdmux_cmd_get_irq_mask { ++ u32 pad; ++ u8 irq_index; ++}; ++ ++struct dpdmux_rsp_get_irq_mask { ++ u32 mask; ++}; ++ ++struct dpdmux_cmd_get_irq_status { ++ u32 status; ++ u8 irq_index; ++}; ++ ++struct dpdmux_rsp_get_irq_status { ++ u32 status; ++}; ++ ++struct dpdmux_cmd_clear_irq_status { ++ u32 status; ++ u8 irq_index; ++}; ++ ++struct dpdmux_rsp_get_attr { ++ u8 method; ++ u8 manip; ++ u16 num_ifs; ++ u16 mem_size; ++ u16 pad; ++ ++ u64 pad1; ++ ++ u32 id; ++ u32 pad2; ++ ++ u64 options; ++}; ++ ++struct dpdmux_cmd_set_max_frame_length { ++ u16 max_frame_length; ++}; ++ ++#define DPDMUX_ACCEPTED_FRAMES_TYPE_SHIFT 0 ++#define DPDMUX_ACCEPTED_FRAMES_TYPE_SIZE 4 ++#define DPDMUX_UNACCEPTED_FRAMES_ACTION_SHIFT 4 ++#define DPDMUX_UNACCEPTED_FRAMES_ACTION_SIZE 4 ++ ++struct dpdmux_cmd_if_set_accepted_frames { ++ u16 if_id; ++ u8 frames_options; ++}; ++ ++struct dpdmux_cmd_if { ++ u16 if_id; ++}; ++ ++struct dpdmux_rsp_if_get_attr { ++ u8 pad[3]; ++ u8 enabled; ++ u8 pad1[3]; ++ u8 accepted_frames_type; ++ u32 rate; ++}; ++ ++struct dpdmux_cmd_if_l2_rule { ++ u16 if_id; ++ u8 mac_addr5; ++ u8 mac_addr4; ++ u8 mac_addr3; ++ u8 mac_addr2; ++ u8 mac_addr1; ++ u8 mac_addr0; ++ ++ u32 pad; ++ u16 vlan_id; ++}; ++ ++struct dpdmux_cmd_if_get_counter { ++ u16 if_id; ++ u8 counter_type; ++}; ++ ++struct dpdmux_rsp_if_get_counter { ++ u64 pad; ++ u64 counter; ++}; ++ ++struct dpdmux_cmd_if_set_link_cfg { ++ u16 if_id; ++ u16 pad[3]; ++ ++ u32 rate; ++ u32 pad1; ++ ++ u64 options; ++}; ++ ++struct dpdmux_cmd_if_get_link_state { ++ u16 if_id; ++}; ++ ++struct dpdmux_rsp_if_get_link_state { ++ u32 pad; ++ u8 up; ++ u8 pad1[3]; ++ ++ u32 rate; ++ u32 pad2; ++ ++ u64 options; ++}; ++ ++struct dpdmux_rsp_get_api_version { ++ u16 major; ++ u16 minor; ++}; ++ ++struct dpdmux_set_custom_key { ++ u64 pad[6]; ++ u64 key_cfg_iova; ++}; ++ ++struct dpdmux_cmd_add_custom_cls_entry { ++ u8 pad[3]; ++ u8 key_size; ++ u16 pad1; ++ u16 dest_if; ++ u64 key_iova; ++ u64 mask_iova; ++}; ++ ++struct dpdmux_cmd_remove_custom_cls_entry { ++ u8 pad[3]; ++ u8 key_size; ++ u32 pad1; ++ u64 key_iova; ++ u64 mask_iova; ++}; ++ ++#endif /* _FSL_DPDMUX_CMD_H */ +diff --git a/drivers/staging/fsl-dpaa2/evb/dpdmux.c b/drivers/staging/fsl-dpaa2/evb/dpdmux.c +new file mode 100644 +index 00000000..f7a87633 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/evb/dpdmux.c +@@ -0,0 +1,1112 @@ ++/* Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#include "../../fsl-mc/include/mc-sys.h" ++#include "../../fsl-mc/include/mc-cmd.h" ++#include "dpdmux.h" ++#include "dpdmux-cmd.h" ++ ++/** ++ * dpdmux_open() - Open a control session for the specified object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @dpdmux_id: DPDMUX unique ID ++ * @token: Returned token; use in subsequent API calls ++ * ++ * This function can be used to open a control session for an ++ * already created object; an object may have been declared in ++ * the DPL or by calling the dpdmux_create() function. ++ * This function returns a unique authentication token, ++ * associated with the specific object ID and the specific MC ++ * portal; this token must be used in all subsequent commands for ++ * this specific object. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpdmux_id, ++ u16 *token) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_cmd_open *cmd_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_OPEN, ++ cmd_flags, ++ 0); ++ cmd_params = (struct dpdmux_cmd_open *)cmd.params; ++ cmd_params->dpdmux_id = cpu_to_le32(dpdmux_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *token = mc_cmd_hdr_read_token(&cmd); ++ ++ return 0; ++} ++ ++/** ++ * dpdmux_close() - Close the control session of the object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * ++ * After this function is called, no further operations are ++ * allowed on the object without opening a new control session. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CLOSE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_create() - Create the DPDMUX object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @dprc_token: Parent container token; '0' for default container ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @cfg: Configuration structure ++ * @obj_id: returned object id ++ * ++ * Create the DPDMUX object, allocate required resources and ++ * perform required initialization. ++ * ++ * The object can be created either by declaring it in the ++ * DPL file, or by calling this function. ++ * ++ * The function accepts an authentication token of a parent ++ * container that this object should be assigned to. The token ++ * can be '0' so the object will be assigned to the default container. ++ * The newly created object can be opened with the returned ++ * object id and using the container's associated tokens and MC portals. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_create(struct fsl_mc_io *mc_io, ++ u16 dprc_token, ++ u32 cmd_flags, ++ const struct dpdmux_cfg *cfg, ++ u32 *obj_id) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_cmd_create *cmd_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CREATE, ++ cmd_flags, ++ dprc_token); ++ cmd_params = (struct dpdmux_cmd_create *)cmd.params; ++ cmd_params->method = cfg->method; ++ cmd_params->manip = cfg->manip; ++ cmd_params->num_ifs = cpu_to_le16(cfg->num_ifs); ++ cmd_params->adv_max_dmat_entries = ++ cpu_to_le16(cfg->adv.max_dmat_entries); ++ cmd_params->adv_max_mc_groups = cpu_to_le16(cfg->adv.max_mc_groups); ++ cmd_params->adv_max_vlan_ids = cpu_to_le16(cfg->adv.max_vlan_ids); ++ cmd_params->options = cpu_to_le64(cfg->adv.options); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *obj_id = mc_cmd_hdr_read_token(&cmd); ++ ++ return 0; ++} ++ ++/** ++ * dpdmux_destroy() - Destroy the DPDMUX object and release all its resources. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @dprc_token: Parent container token; '0' for default container ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @object_id: The object id; it must be a valid id within the container that ++ * created this object; ++ * ++ * The function accepts the authentication token of the parent container that ++ * created the object (not the one that currently owns the object). The object ++ * is searched within parent using the provided 'object_id'. ++ * All tokens to the object must be closed before calling destroy. ++ * ++ * Return: '0' on Success; error code otherwise. ++ */ ++int dpdmux_destroy(struct fsl_mc_io *mc_io, ++ u16 dprc_token, ++ u32 cmd_flags, ++ u32 object_id) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_cmd_destroy *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_DESTROY, ++ cmd_flags, ++ dprc_token); ++ cmd_params = (struct dpdmux_cmd_destroy *)cmd.params; ++ cmd_params->dpdmux_id = cpu_to_le32(object_id); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_enable() - Enable DPDMUX functionality ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_ENABLE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_disable() - Disable DPDMUX functionality ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_DISABLE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_is_enabled() - Check if the DPDMUX is enabled. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * @en: Returns '1' if object is enabled; '0' otherwise ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_is_enabled(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int *en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_rsp_is_enabled *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IS_ENABLED, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpdmux_rsp_is_enabled *)cmd.params; ++ *en = dpdmux_get_field(rsp_params->en, ENABLE); ++ ++ return 0; ++} ++ ++/** ++ * dpdmux_reset() - Reset the DPDMUX, returns the object to initial state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_reset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_RESET, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_set_irq_enable() - Set overall interrupt state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * @irq_index: The interrupt index to configure ++ * @en: Interrupt state - enable = 1, disable = 0 ++ * ++ * Allows GPP software to control when interrupts are generated. ++ * Each interrupt can have up to 32 causes. The enable/disable control's the ++ * overall interrupt state. if the interrupt is disabled no causes will cause ++ * an interrupt. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_set_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_cmd_set_irq_enable *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_IRQ_ENABLE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_cmd_set_irq_enable *)cmd.params; ++ cmd_params->enable = en; ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_get_irq_enable() - Get overall interrupt state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * @irq_index: The interrupt index to configure ++ * @en: Returned interrupt state - enable = 1, disable = 0 ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_get_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 *en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_cmd_get_irq_enable *cmd_params; ++ struct dpdmux_rsp_get_irq_enable *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_ENABLE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_cmd_get_irq_enable *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpdmux_rsp_get_irq_enable *)cmd.params; ++ *en = rsp_params->enable; ++ ++ return 0; ++} ++ ++/** ++ * dpdmux_set_irq_mask() - Set interrupt mask. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * @irq_index: The interrupt index to configure ++ * @mask: event mask to trigger interrupt; ++ * each bit: ++ * 0 = ignore event ++ * 1 = consider event for asserting IRQ ++ * ++ * Every interrupt can have up to 32 causes and the interrupt model supports ++ * masking/unmasking each cause independently ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_set_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 mask) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_cmd_set_irq_mask *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_IRQ_MASK, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_cmd_set_irq_mask *)cmd.params; ++ cmd_params->mask = cpu_to_le32(mask); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_get_irq_mask() - Get interrupt mask. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * @irq_index: The interrupt index to configure ++ * @mask: Returned event mask to trigger interrupt ++ * ++ * Every interrupt can have up to 32 causes and the interrupt model supports ++ * masking/unmasking each cause independently ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_get_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *mask) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_cmd_get_irq_mask *cmd_params; ++ struct dpdmux_rsp_get_irq_mask *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_MASK, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_cmd_get_irq_mask *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpdmux_rsp_get_irq_mask *)cmd.params; ++ *mask = le32_to_cpu(rsp_params->mask); ++ ++ return 0; ++} ++ ++/** ++ * dpdmux_get_irq_status() - Get the current status of any pending interrupts. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * @irq_index: The interrupt index to configure ++ * @status: Returned interrupts status - one bit per cause: ++ * 0 = no interrupt pending ++ * 1 = interrupt pending ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_get_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *status) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_cmd_get_irq_status *cmd_params; ++ struct dpdmux_rsp_get_irq_status *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_IRQ_STATUS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_cmd_get_irq_status *)cmd.params; ++ cmd_params->status = cpu_to_le32(*status); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpdmux_rsp_get_irq_status *)cmd.params; ++ *status = le32_to_cpu(rsp_params->status); ++ ++ return 0; ++} ++ ++/** ++ * dpdmux_clear_irq_status() - Clear a pending interrupt's status ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * @irq_index: The interrupt index to configure ++ * @status: bits to clear (W1C) - one bit per cause: ++ * 0 = don't change ++ * 1 = clear status bit ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_clear_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 status) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_cmd_clear_irq_status *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_CLEAR_IRQ_STATUS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_cmd_clear_irq_status *)cmd.params; ++ cmd_params->status = cpu_to_le32(status); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_get_attributes() - Retrieve DPDMUX attributes ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * @attr: Returned object's attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpdmux_attr *attr) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_rsp_get_attr *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_ATTR, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpdmux_rsp_get_attr *)cmd.params; ++ attr->id = le32_to_cpu(rsp_params->id); ++ attr->options = le64_to_cpu(rsp_params->options); ++ attr->method = rsp_params->method; ++ attr->manip = rsp_params->manip; ++ attr->num_ifs = le16_to_cpu(rsp_params->num_ifs); ++ attr->mem_size = le16_to_cpu(rsp_params->mem_size); ++ ++ return 0; ++} ++ ++/** ++ * dpdmux_if_enable() - Enable Interface ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * @if_id: Interface Identifier ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpdmux_if_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id) ++{ ++ struct dpdmux_cmd_if *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_ENABLE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_cmd_if *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_if_disable() - Disable Interface ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * @if_id: Interface Identifier ++ * ++ * Return: Completion status. '0' on Success; Error code otherwise. ++ */ ++int dpdmux_if_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id) ++{ ++ struct dpdmux_cmd_if *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_DISABLE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_cmd_if *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_set_max_frame_length() - Set the maximum frame length in DPDMUX ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * @max_frame_length: The required maximum frame length ++ * ++ * Update the maximum frame length on all DMUX interfaces. ++ * In case of VEPA, the maximum frame length on all dmux interfaces ++ * will be updated with the minimum value of the mfls of the connected ++ * dpnis and the actual value of dmux mfl. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_set_max_frame_length(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 max_frame_length) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_cmd_set_max_frame_length *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_MAX_FRAME_LENGTH, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_cmd_set_max_frame_length *)cmd.params; ++ cmd_params->max_frame_length = cpu_to_le16(max_frame_length); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_ul_reset_counters() - Function resets the uplink counter ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_ul_reset_counters(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_UL_RESET_COUNTERS, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_if_set_accepted_frames() - Set the accepted frame types ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * @if_id: Interface ID (0 for uplink, or 1-num_ifs); ++ * @cfg: Frame types configuration ++ * ++ * if 'DPDMUX_ADMIT_ONLY_VLAN_TAGGED' is set - untagged frames or ++ * priority-tagged frames are discarded. ++ * if 'DPDMUX_ADMIT_ONLY_UNTAGGED' is set - untagged frames or ++ * priority-tagged frames are accepted. ++ * if 'DPDMUX_ADMIT_ALL' is set (default mode) - all VLAN tagged, ++ * untagged and priority-tagged frame are accepted; ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_if_set_accepted_frames(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpdmux_accepted_frames *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_cmd_if_set_accepted_frames *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_SET_ACCEPTED_FRAMES, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_cmd_if_set_accepted_frames *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ dpdmux_set_field(cmd_params->frames_options, ACCEPTED_FRAMES_TYPE, ++ cfg->type); ++ dpdmux_set_field(cmd_params->frames_options, UNACCEPTED_FRAMES_ACTION, ++ cfg->unaccept_act); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_if_get_attributes() - Obtain DPDMUX interface attributes ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * @if_id: Interface ID (0 for uplink, or 1-num_ifs); ++ * @attr: Interface attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_if_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ struct dpdmux_if_attr *attr) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_cmd_if *cmd_params; ++ struct dpdmux_rsp_if_get_attr *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_ATTR, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_cmd_if *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpdmux_rsp_if_get_attr *)cmd.params; ++ attr->rate = le32_to_cpu(rsp_params->rate); ++ attr->enabled = dpdmux_get_field(rsp_params->enabled, ENABLE); ++ attr->accept_frame_type = ++ dpdmux_get_field(rsp_params->accepted_frames_type, ++ ACCEPTED_FRAMES_TYPE); ++ ++ return 0; ++} ++ ++/** ++ * dpdmux_if_remove_l2_rule() - Remove L2 rule from DPDMUX table ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * @if_id: Destination interface ID ++ * @rule: L2 rule ++ * ++ * Function removes a L2 rule from DPDMUX table ++ * or adds an interface to an existing multicast address ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_if_remove_l2_rule(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpdmux_l2_rule *rule) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_cmd_if_l2_rule *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_REMOVE_L2_RULE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_cmd_if_l2_rule *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ cmd_params->vlan_id = cpu_to_le16(rule->vlan_id); ++ cmd_params->mac_addr5 = rule->mac_addr[5]; ++ cmd_params->mac_addr4 = rule->mac_addr[4]; ++ cmd_params->mac_addr3 = rule->mac_addr[3]; ++ cmd_params->mac_addr2 = rule->mac_addr[2]; ++ cmd_params->mac_addr1 = rule->mac_addr[1]; ++ cmd_params->mac_addr0 = rule->mac_addr[0]; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_if_add_l2_rule() - Add L2 rule into DPDMUX table ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * @if_id: Destination interface ID ++ * @rule: L2 rule ++ * ++ * Function adds a L2 rule into DPDMUX table ++ * or adds an interface to an existing multicast address ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_if_add_l2_rule(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpdmux_l2_rule *rule) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_cmd_if_l2_rule *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_ADD_L2_RULE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_cmd_if_l2_rule *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ cmd_params->vlan_id = cpu_to_le16(rule->vlan_id); ++ cmd_params->mac_addr5 = rule->mac_addr[5]; ++ cmd_params->mac_addr4 = rule->mac_addr[4]; ++ cmd_params->mac_addr3 = rule->mac_addr[3]; ++ cmd_params->mac_addr2 = rule->mac_addr[2]; ++ cmd_params->mac_addr1 = rule->mac_addr[1]; ++ cmd_params->mac_addr0 = rule->mac_addr[0]; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_if_get_counter() - Functions obtains specific counter of an interface ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMUX object ++ * @if_id: Interface Id ++ * @counter_type: counter type ++ * @counter: Returned specific counter information ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_if_get_counter(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ enum dpdmux_counter_type counter_type, ++ u64 *counter) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_cmd_if_get_counter *cmd_params; ++ struct dpdmux_rsp_if_get_counter *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_COUNTER, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_cmd_if_get_counter *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ cmd_params->counter_type = counter_type; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpdmux_rsp_if_get_counter *)cmd.params; ++ *counter = le64_to_cpu(rsp_params->counter); ++ ++ return 0; ++} ++ ++/** ++ * dpdmux_if_set_link_cfg() - set the link configuration. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: interface id ++ * @cfg: Link configuration ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_if_set_link_cfg(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ struct dpdmux_link_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_cmd_if_set_link_cfg *cmd_params; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_SET_LINK_CFG, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_cmd_if_set_link_cfg *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ cmd_params->rate = cpu_to_le32(cfg->rate); ++ cmd_params->options = cpu_to_le64(cfg->options); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_if_get_link_state - Return the link state ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: interface id ++ * @state: link state ++ * ++ * @returns '0' on Success; Error code otherwise. ++ */ ++int dpdmux_if_get_link_state(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ struct dpdmux_link_state *state) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_cmd_if_get_link_state *cmd_params; ++ struct dpdmux_rsp_if_get_link_state *rsp_params; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_IF_GET_LINK_STATE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_cmd_if_get_link_state *)cmd.params; ++ cmd_params->if_id = cpu_to_le16(if_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpdmux_rsp_if_get_link_state *)cmd.params; ++ state->rate = le32_to_cpu(rsp_params->rate); ++ state->options = le64_to_cpu(rsp_params->options); ++ state->up = dpdmux_get_field(rsp_params->up, ENABLE); ++ ++ return 0; ++} ++ ++/** ++ * dpdmux_set_custom_key - Set a custom classification key. ++ * ++ * This API is only available for DPDMUX instance created with ++ * DPDMUX_METHOD_CUSTOM. This API must be called before populating the ++ * classification table using dpdmux_add_custom_cls_entry. ++ * ++ * Calls to dpdmux_set_custom_key remove all existing classification entries ++ * that may have been added previously using dpdmux_add_custom_cls_entry. ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @if_id: interface id ++ * @key_cfg_iova: DMA address of a configuration structure set up using ++ * dpkg_prepare_key_cfg. Maximum key size is 24 bytes. ++ * ++ * @returns '0' on Success; Error code otherwise. ++ */ ++int dpdmux_set_custom_key(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u64 key_cfg_iova) ++{ ++ struct dpdmux_set_custom_key *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_SET_CUSTOM_KEY, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_set_custom_key *)cmd.params; ++ cmd_params->key_cfg_iova = cpu_to_le64(key_cfg_iova); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_add_custom_cls_entry - Adds a custom classification entry. ++ * ++ * This API is only available for DPDMUX instances created with ++ * DPDMUX_METHOD_CUSTOM. Before calling this function a classification key ++ * composition rule must be set up using dpdmux_set_custom_key. ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @rule: Classification rule to insert. Rules cannot be duplicated, if a ++ * matching rule already exists, the action will be replaced. ++ * @action: Action to perform for matching traffic. ++ * ++ * @returns '0' on Success; Error code otherwise. ++ */ ++int dpdmux_add_custom_cls_entry(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpdmux_rule_cfg *rule, ++ struct dpdmux_cls_action *action) ++{ ++ struct dpdmux_cmd_add_custom_cls_entry *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_ADD_CUSTOM_CLS_ENTRY, ++ cmd_flags, ++ token); ++ ++ cmd_params = (struct dpdmux_cmd_add_custom_cls_entry *)cmd.params; ++ cmd_params->key_size = rule->key_size; ++ cmd_params->dest_if = cpu_to_le16(action->dest_if); ++ cmd_params->key_iova = cpu_to_le64(rule->key_iova); ++ cmd_params->mask_iova = cpu_to_le64(rule->mask_iova); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_remove_custom_cls_entry - Removes a custom classification entry. ++ * ++ * This API is only available for DPDMUX instances created with ++ * DPDMUX_METHOD_CUSTOM. The API can be used to remove classification ++ * entries previously inserted using dpdmux_add_custom_cls_entry. ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSW object ++ * @rule: Classification rule to remove ++ * ++ * @returns '0' on Success; Error code otherwise. ++ */ ++int dpdmux_remove_custom_cls_entry(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpdmux_rule_cfg *rule) ++{ ++ struct dpdmux_cmd_remove_custom_cls_entry *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_REMOVE_CUSTOM_CLS_ENTRY, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpdmux_cmd_remove_custom_cls_entry *)cmd.params; ++ cmd_params->key_size = rule->key_size; ++ cmd_params->key_iova = cpu_to_le64(rule->key_iova); ++ cmd_params->mask_iova = cpu_to_le64(rule->mask_iova); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpdmux_get_api_version() - Get Data Path Demux API version ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @major_ver: Major version of data path demux API ++ * @minor_ver: Minor version of data path demux API ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmux_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpdmux_rsp_get_api_version *rsp_params; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header(DPDMUX_CMDID_GET_API_VERSION, ++ cmd_flags, ++ 0); ++ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ rsp_params = (struct dpdmux_rsp_get_api_version *)cmd.params; ++ *major_ver = le16_to_cpu(rsp_params->major); ++ *minor_ver = le16_to_cpu(rsp_params->minor); ++ ++ return 0; ++} +diff --git a/drivers/staging/fsl-dpaa2/evb/dpdmux.h b/drivers/staging/fsl-dpaa2/evb/dpdmux.h +new file mode 100644 +index 00000000..a6ccc7ef +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/evb/dpdmux.h +@@ -0,0 +1,453 @@ ++/* Copyright 2013-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef __FSL_DPDMUX_H ++#define __FSL_DPDMUX_H ++ ++struct fsl_mc_io; ++ ++/* Data Path Demux API ++ * Contains API for handling DPDMUX topology and functionality ++ */ ++ ++int dpdmux_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpdmux_id, ++ u16 *token); ++ ++int dpdmux_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++/** ++ * DPDMUX general options ++ */ ++ ++/** ++ * Enable bridging between internal interfaces ++ */ ++#define DPDMUX_OPT_BRIDGE_EN 0x0000000000000002ULL ++ ++/** ++ * Mask support for classification ++ */ ++#define DPDMUX_OPT_CLS_MASK_SUPPORT 0x0000000000000020ULL ++ ++#define DPDMUX_IRQ_INDEX_IF 0x0000 ++#define DPDMUX_IRQ_INDEX 0x0001 ++ ++/** ++ * IRQ event - Indicates that the link state changed ++ */ ++#define DPDMUX_IRQ_EVENT_LINK_CHANGED 0x0001 ++ ++/** ++ * enum dpdmux_manip - DPDMUX manipulation operations ++ * @DPDMUX_MANIP_NONE: No manipulation on frames ++ * @DPDMUX_MANIP_ADD_REMOVE_S_VLAN: Add S-VLAN on egress, remove it on ingress ++ */ ++enum dpdmux_manip { ++ DPDMUX_MANIP_NONE = 0x0, ++ DPDMUX_MANIP_ADD_REMOVE_S_VLAN = 0x1 ++}; ++ ++/** ++ * enum dpdmux_method - DPDMUX method options ++ * @DPDMUX_METHOD_NONE: no DPDMUX method ++ * @DPDMUX_METHOD_C_VLAN_MAC: DPDMUX based on C-VLAN and MAC address ++ * @DPDMUX_METHOD_MAC: DPDMUX based on MAC address ++ * @DPDMUX_METHOD_C_VLAN: DPDMUX based on C-VLAN ++ * @DPDMUX_METHOD_S_VLAN: DPDMUX based on S-VLAN ++ */ ++enum dpdmux_method { ++ DPDMUX_METHOD_NONE = 0x0, ++ DPDMUX_METHOD_C_VLAN_MAC = 0x1, ++ DPDMUX_METHOD_MAC = 0x2, ++ DPDMUX_METHOD_C_VLAN = 0x3, ++ DPDMUX_METHOD_S_VLAN = 0x4, ++ DPDMUX_METHOD_CUSTOM = 0x5 ++}; ++ ++/** ++ * struct dpdmux_cfg - DPDMUX configuration parameters ++ * @method: Defines the operation method for the DPDMUX address table ++ * @manip: Required manipulation operation ++ * @num_ifs: Number of interfaces (excluding the uplink interface) ++ * @adv: Advanced parameters; default is all zeros; ++ * use this structure to change default settings ++ */ ++struct dpdmux_cfg { ++ enum dpdmux_method method; ++ enum dpdmux_manip manip; ++ u16 num_ifs; ++ /** ++ * struct adv - Advanced parameters ++ * @options: DPDMUX options - combination of 'DPDMUX_OPT_' flags ++ * @max_dmat_entries: Maximum entries in DPDMUX address table ++ * 0 - indicates default: 64 entries per interface. ++ * @max_mc_groups: Number of multicast groups in DPDMUX table ++ * 0 - indicates default: 32 multicast groups ++ * @max_vlan_ids: max vlan ids allowed in the system - ++ * relevant only case of working in mac+vlan method. ++ * 0 - indicates default 16 vlan ids. ++ */ ++ struct { ++ u64 options; ++ u16 max_dmat_entries; ++ u16 max_mc_groups; ++ u16 max_vlan_ids; ++ } adv; ++}; ++ ++int dpdmux_create(struct fsl_mc_io *mc_io, ++ u16 dprc_token, ++ u32 cmd_flags, ++ const struct dpdmux_cfg *cfg, ++ u32 *obj_id); ++ ++int dpdmux_destroy(struct fsl_mc_io *mc_io, ++ u16 dprc_token, ++ u32 cmd_flags, ++ u32 object_id); ++ ++int dpdmux_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpdmux_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpdmux_is_enabled(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ int *en); ++ ++int dpdmux_reset(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++int dpdmux_set_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 en); ++ ++int dpdmux_get_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 *en); ++ ++int dpdmux_set_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 mask); ++ ++int dpdmux_get_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *mask); ++ ++int dpdmux_get_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *status); ++ ++int dpdmux_clear_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 status); ++ ++/** ++ * struct dpdmux_attr - Structure representing DPDMUX attributes ++ * @id: DPDMUX object ID ++ * @options: Configuration options (bitmap) ++ * @method: DPDMUX address table method ++ * @manip: DPDMUX manipulation type ++ * @num_ifs: Number of interfaces (excluding the uplink interface) ++ * @mem_size: DPDMUX frame storage memory size ++ */ ++struct dpdmux_attr { ++ int id; ++ u64 options; ++ enum dpdmux_method method; ++ enum dpdmux_manip manip; ++ u16 num_ifs; ++ u16 mem_size; ++}; ++ ++int dpdmux_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpdmux_attr *attr); ++ ++int dpdmux_set_max_frame_length(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 max_frame_length); ++ ++/** ++ * enum dpdmux_counter_type - Counter types ++ * @DPDMUX_CNT_ING_FRAME: Counts ingress frames ++ * @DPDMUX_CNT_ING_BYTE: Counts ingress bytes ++ * @DPDMUX_CNT_ING_FLTR_FRAME: Counts filtered ingress frames ++ * @DPDMUX_CNT_ING_FRAME_DISCARD: Counts discarded ingress frames ++ * @DPDMUX_CNT_ING_MCAST_FRAME: Counts ingress multicast frames ++ * @DPDMUX_CNT_ING_MCAST_BYTE: Counts ingress multicast bytes ++ * @DPDMUX_CNT_ING_BCAST_FRAME: Counts ingress broadcast frames ++ * @DPDMUX_CNT_ING_BCAST_BYTES: Counts ingress broadcast bytes ++ * @DPDMUX_CNT_EGR_FRAME: Counts egress frames ++ * @DPDMUX_CNT_EGR_BYTE: Counts egress bytes ++ * @DPDMUX_CNT_EGR_FRAME_DISCARD: Counts discarded egress frames ++ */ ++enum dpdmux_counter_type { ++ DPDMUX_CNT_ING_FRAME = 0x0, ++ DPDMUX_CNT_ING_BYTE = 0x1, ++ DPDMUX_CNT_ING_FLTR_FRAME = 0x2, ++ DPDMUX_CNT_ING_FRAME_DISCARD = 0x3, ++ DPDMUX_CNT_ING_MCAST_FRAME = 0x4, ++ DPDMUX_CNT_ING_MCAST_BYTE = 0x5, ++ DPDMUX_CNT_ING_BCAST_FRAME = 0x6, ++ DPDMUX_CNT_ING_BCAST_BYTES = 0x7, ++ DPDMUX_CNT_EGR_FRAME = 0x8, ++ DPDMUX_CNT_EGR_BYTE = 0x9, ++ DPDMUX_CNT_EGR_FRAME_DISCARD = 0xa ++}; ++ ++/** ++ * enum dpdmux_accepted_frames_type - DPDMUX frame types ++ * @DPDMUX_ADMIT_ALL: The device accepts VLAN tagged, untagged and ++ * priority-tagged frames ++ * @DPDMUX_ADMIT_ONLY_VLAN_TAGGED: The device discards untagged frames or ++ * priority-tagged frames that are received on this ++ * interface ++ * @DPDMUX_ADMIT_ONLY_UNTAGGED: Untagged frames or priority-tagged frames ++ * received on this interface are accepted ++ */ ++enum dpdmux_accepted_frames_type { ++ DPDMUX_ADMIT_ALL = 0, ++ DPDMUX_ADMIT_ONLY_VLAN_TAGGED = 1, ++ DPDMUX_ADMIT_ONLY_UNTAGGED = 2 ++}; ++ ++/** ++ * enum dpdmux_action - DPDMUX action for un-accepted frames ++ * @DPDMUX_ACTION_DROP: Drop un-accepted frames ++ * @DPDMUX_ACTION_REDIRECT_TO_CTRL: Redirect un-accepted frames to the ++ * control interface ++ */ ++enum dpdmux_action { ++ DPDMUX_ACTION_DROP = 0, ++ DPDMUX_ACTION_REDIRECT_TO_CTRL = 1 ++}; ++ ++/** ++ * struct dpdmux_accepted_frames - Frame types configuration ++ * @type: Defines ingress accepted frames ++ * @unaccept_act: Defines action on frames not accepted ++ */ ++struct dpdmux_accepted_frames { ++ enum dpdmux_accepted_frames_type type; ++ enum dpdmux_action unaccept_act; ++}; ++ ++int dpdmux_if_set_accepted_frames(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpdmux_accepted_frames *cfg); ++ ++/** ++ * struct dpdmux_if_attr - Structure representing frame types configuration ++ * @rate: Configured interface rate (in bits per second) ++ * @enabled: Indicates if interface is enabled ++ * @accept_frame_type: Indicates type of accepted frames for the interface ++ */ ++struct dpdmux_if_attr { ++ u32 rate; ++ int enabled; ++ enum dpdmux_accepted_frames_type accept_frame_type; ++}; ++ ++int dpdmux_if_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ struct dpdmux_if_attr *attr); ++ ++int dpdmux_if_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id); ++ ++int dpdmux_if_disable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id); ++ ++/** ++ * struct dpdmux_l2_rule - Structure representing L2 rule ++ * @mac_addr: MAC address ++ * @vlan_id: VLAN ID ++ */ ++struct dpdmux_l2_rule { ++ u8 mac_addr[6]; ++ u16 vlan_id; ++}; ++ ++int dpdmux_if_remove_l2_rule(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpdmux_l2_rule *rule); ++ ++int dpdmux_if_add_l2_rule(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ const struct dpdmux_l2_rule *rule); ++ ++int dpdmux_if_get_counter(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ enum dpdmux_counter_type counter_type, ++ u64 *counter); ++ ++int dpdmux_ul_reset_counters(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++/** ++ * Enable auto-negotiation ++ */ ++#define DPDMUX_LINK_OPT_AUTONEG 0x0000000000000001ULL ++/** ++ * Enable half-duplex mode ++ */ ++#define DPDMUX_LINK_OPT_HALF_DUPLEX 0x0000000000000002ULL ++/** ++ * Enable pause frames ++ */ ++#define DPDMUX_LINK_OPT_PAUSE 0x0000000000000004ULL ++/** ++ * Enable a-symmetric pause frames ++ */ ++#define DPDMUX_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL ++ ++/** ++ * struct dpdmux_link_cfg - Structure representing DPDMUX link configuration ++ * @rate: Rate ++ * @options: Mask of available options; use 'DPDMUX_LINK_OPT_' values ++ */ ++struct dpdmux_link_cfg { ++ u32 rate; ++ u64 options; ++}; ++ ++int dpdmux_if_set_link_cfg(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ struct dpdmux_link_cfg *cfg); ++/** ++ * struct dpdmux_link_state - Structure representing DPDMUX link state ++ * @rate: Rate ++ * @options: Mask of available options; use 'DPDMUX_LINK_OPT_' values ++ * @up: 0 - down, 1 - up ++ */ ++struct dpdmux_link_state { ++ u32 rate; ++ u64 options; ++ int up; ++}; ++ ++int dpdmux_if_get_link_state(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u16 if_id, ++ struct dpdmux_link_state *state); ++ ++int dpdmux_set_custom_key(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u64 key_cfg_iova); ++ ++/** ++ * struct dpdmux_rule_cfg - Custom classification rule. ++ * ++ * @key_iova: DMA address of buffer storing the look-up value ++ * @mask_iova: DMA address of the mask used for TCAM classification ++ * @key_size: size, in bytes, of the look-up value. This must match the size ++ * of the look-up key defined using dpdmux_set_custom_key, otherwise the ++ * entry will never be hit ++ */ ++struct dpdmux_rule_cfg { ++ u64 key_iova; ++ u64 mask_iova; ++ u8 key_size; ++}; ++ ++/** ++ * struct dpdmux_cls_action - Action to execute for frames matching the ++ * classification entry ++ * ++ * @dest_if: Interface to forward the frames to. Port numbering is similar to ++ * the one used to connect interfaces: ++ * - 0 is the uplink port, ++ * - all others are downlink ports. ++ */ ++struct dpdmux_cls_action { ++ u16 dest_if; ++}; ++ ++int dpdmux_add_custom_cls_entry(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpdmux_rule_cfg *rule, ++ struct dpdmux_cls_action *action); ++ ++int dpdmux_remove_custom_cls_entry(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpdmux_rule_cfg *rule); ++ ++int dpdmux_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver); ++ ++#endif /* __FSL_DPDMUX_H */ +diff --git a/drivers/staging/fsl-dpaa2/evb/evb.c b/drivers/staging/fsl-dpaa2/evb/evb.c +new file mode 100644 +index 00000000..9ee09b42 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/evb/evb.c +@@ -0,0 +1,1350 @@ ++/* Copyright 2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "../../fsl-mc/include/mc.h" ++ ++#include "dpdmux.h" ++#include "dpdmux-cmd.h" ++ ++static const char evb_drv_version[] = "0.1"; ++ ++/* Minimal supported DPDMUX version */ ++#define DPDMUX_MIN_VER_MAJOR 6 ++#define DPDMUX_MIN_VER_MINOR 0 ++ ++/* IRQ index */ ++#define DPDMUX_MAX_IRQ_NUM 2 ++ ++/* MAX FRAME LENGTH (currently 10k) */ ++#define EVB_MAX_FRAME_LENGTH (10 * 1024) ++/* MIN FRAME LENGTH (64 bytes + 4 bytes CRC) */ ++#define EVB_MIN_FRAME_LENGTH 68 ++ ++struct evb_port_priv { ++ struct net_device *netdev; ++ struct list_head list; ++ u16 port_index; ++ struct evb_priv *evb_priv; ++ u8 vlans[VLAN_VID_MASK + 1]; ++}; ++ ++struct evb_priv { ++ /* keep first */ ++ struct evb_port_priv uplink; ++ ++ struct fsl_mc_io *mc_io; ++ struct list_head port_list; ++ struct dpdmux_attr attr; ++ u16 mux_handle; ++ int dev_id; ++}; ++ ++static int _evb_port_carrier_state_sync(struct net_device *netdev) ++{ ++ struct evb_port_priv *port_priv = netdev_priv(netdev); ++ struct dpdmux_link_state state; ++ int err; ++ ++ err = dpdmux_if_get_link_state(port_priv->evb_priv->mc_io, 0, ++ port_priv->evb_priv->mux_handle, ++ port_priv->port_index, &state); ++ if (unlikely(err)) { ++ netdev_err(netdev, "dpdmux_if_get_link_state() err %d\n", err); ++ return err; ++ } ++ ++ WARN_ONCE(state.up > 1, "Garbage read into link_state"); ++ ++ if (state.up) ++ netif_carrier_on(port_priv->netdev); ++ else ++ netif_carrier_off(port_priv->netdev); ++ ++ return 0; ++} ++ ++static int evb_port_open(struct net_device *netdev) ++{ ++ int err; ++ ++ /* FIXME: enable port when support added */ ++ ++ err = _evb_port_carrier_state_sync(netdev); ++ if (err) { ++ netdev_err(netdev, "ethsw_port_carrier_state_sync err %d\n", ++ err); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static netdev_tx_t evb_dropframe(struct sk_buff *skb, struct net_device *dev) ++{ ++ /* we don't support I/O for now, drop the frame */ ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++} ++ ++static int evb_links_state_update(struct evb_priv *priv) ++{ ++ struct evb_port_priv *port_priv; ++ struct list_head *pos; ++ int err; ++ ++ list_for_each(pos, &priv->port_list) { ++ port_priv = list_entry(pos, struct evb_port_priv, list); ++ ++ err = _evb_port_carrier_state_sync(port_priv->netdev); ++ if (err) ++ netdev_err(port_priv->netdev, ++ "_evb_port_carrier_state_sync err %d\n", ++ err); ++ } ++ ++ return 0; ++} ++ ++static irqreturn_t evb_irq0_handler(int irq_num, void *arg) ++{ ++ return IRQ_WAKE_THREAD; ++} ++ ++static irqreturn_t _evb_irq0_handler_thread(int irq_num, void *arg) ++{ ++ struct device *dev = (struct device *)arg; ++ struct fsl_mc_device *evb_dev = to_fsl_mc_device(dev); ++ struct net_device *netdev = dev_get_drvdata(dev); ++ struct evb_priv *priv = netdev_priv(netdev); ++ struct fsl_mc_io *io = priv->mc_io; ++ u16 token = priv->mux_handle; ++ int irq_index = DPDMUX_IRQ_INDEX_IF; ++ ++ /* Mask the events and the if_id reserved bits to be cleared on read */ ++ u32 status = DPDMUX_IRQ_EVENT_LINK_CHANGED | 0xFFFF0000; ++ int err; ++ ++ /* Sanity check */ ++ if (WARN_ON(!evb_dev || !evb_dev->irqs || !evb_dev->irqs[irq_index])) ++ goto out; ++ if (WARN_ON(evb_dev->irqs[irq_index]->msi_desc->irq != (u32)irq_num)) ++ goto out; ++ ++ err = dpdmux_get_irq_status(io, 0, token, irq_index, &status); ++ if (unlikely(err)) { ++ netdev_err(netdev, "Can't get irq status (err %d)", err); ++ err = dpdmux_clear_irq_status(io, 0, token, irq_index, ++ 0xFFFFFFFF); ++ if (unlikely(err)) ++ netdev_err(netdev, "Can't clear irq status (err %d)", ++ err); ++ goto out; ++ } ++ ++ if (status & DPDMUX_IRQ_EVENT_LINK_CHANGED) { ++ err = evb_links_state_update(priv); ++ if (unlikely(err)) ++ goto out; ++ } ++ ++out: ++ return IRQ_HANDLED; ++} ++ ++static int evb_setup_irqs(struct fsl_mc_device *evb_dev) ++{ ++ struct device *dev = &evb_dev->dev; ++ struct net_device *netdev = dev_get_drvdata(dev); ++ struct evb_priv *priv = netdev_priv(netdev); ++ int err = 0; ++ struct fsl_mc_device_irq *irq; ++ const int irq_index = DPDMUX_IRQ_INDEX_IF; ++ u32 mask = DPDMUX_IRQ_EVENT_LINK_CHANGED; ++ ++ err = fsl_mc_allocate_irqs(evb_dev); ++ if (unlikely(err)) { ++ dev_err(dev, "MC irqs allocation failed\n"); ++ return err; ++ } ++ ++ if (WARN_ON(evb_dev->obj_desc.irq_count != DPDMUX_MAX_IRQ_NUM)) { ++ err = -EINVAL; ++ goto free_irq; ++ } ++ ++ err = dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle, ++ irq_index, 0); ++ if (unlikely(err)) { ++ dev_err(dev, "dpdmux_set_irq_enable err %d\n", err); ++ goto free_irq; ++ } ++ ++ irq = evb_dev->irqs[irq_index]; ++ ++ err = devm_request_threaded_irq(dev, irq->msi_desc->irq, ++ evb_irq0_handler, ++ _evb_irq0_handler_thread, ++ IRQF_NO_SUSPEND | IRQF_ONESHOT, ++ dev_name(dev), dev); ++ if (unlikely(err)) { ++ dev_err(dev, "devm_request_threaded_irq(): %d", err); ++ goto free_irq; ++ } ++ ++ err = dpdmux_set_irq_mask(priv->mc_io, 0, priv->mux_handle, ++ irq_index, mask); ++ if (unlikely(err)) { ++ dev_err(dev, "dpdmux_set_irq_mask(): %d", err); ++ goto free_devm_irq; ++ } ++ ++ err = dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle, ++ irq_index, 1); ++ if (unlikely(err)) { ++ dev_err(dev, "dpdmux_set_irq_enable(): %d", err); ++ goto free_devm_irq; ++ } ++ ++ return 0; ++ ++free_devm_irq: ++ devm_free_irq(dev, irq->msi_desc->irq, dev); ++free_irq: ++ fsl_mc_free_irqs(evb_dev); ++ return err; ++} ++ ++static void evb_teardown_irqs(struct fsl_mc_device *evb_dev) ++{ ++ struct device *dev = &evb_dev->dev; ++ struct net_device *netdev = dev_get_drvdata(dev); ++ struct evb_priv *priv = netdev_priv(netdev); ++ ++ dpdmux_set_irq_enable(priv->mc_io, 0, priv->mux_handle, ++ DPDMUX_IRQ_INDEX_IF, 0); ++ ++ devm_free_irq(dev, ++ evb_dev->irqs[DPDMUX_IRQ_INDEX_IF]->msi_desc->irq, ++ dev); ++ fsl_mc_free_irqs(evb_dev); ++} ++ ++static int evb_port_add_rule(struct net_device *netdev, ++ const unsigned char *addr, u16 vid) ++{ ++ struct evb_port_priv *port_priv = netdev_priv(netdev); ++ struct dpdmux_l2_rule rule = { .vlan_id = vid }; ++ int err; ++ ++ if (addr) ++ ether_addr_copy(rule.mac_addr, addr); ++ ++ err = dpdmux_if_add_l2_rule(port_priv->evb_priv->mc_io, ++ 0, ++ port_priv->evb_priv->mux_handle, ++ port_priv->port_index, &rule); ++ if (unlikely(err)) ++ netdev_err(netdev, "dpdmux_if_add_l2_rule err %d\n", err); ++ return err; ++} ++ ++static int evb_port_del_rule(struct net_device *netdev, ++ const unsigned char *addr, u16 vid) ++{ ++ struct evb_port_priv *port_priv = netdev_priv(netdev); ++ struct dpdmux_l2_rule rule = { .vlan_id = vid }; ++ int err; ++ ++ if (addr) ++ ether_addr_copy(rule.mac_addr, addr); ++ ++ err = dpdmux_if_remove_l2_rule(port_priv->evb_priv->mc_io, ++ 0, ++ port_priv->evb_priv->mux_handle, ++ port_priv->port_index, &rule); ++ if (unlikely(err)) ++ netdev_err(netdev, "dpdmux_if_remove_l2_rule err %d\n", err); ++ return err; ++} ++ ++static bool _lookup_address(struct net_device *netdev, ++ const unsigned char *addr) ++{ ++ struct netdev_hw_addr *ha; ++ struct netdev_hw_addr_list *list = (is_unicast_ether_addr(addr)) ? ++ &netdev->uc : &netdev->mc; ++ ++ netif_addr_lock_bh(netdev); ++ list_for_each_entry(ha, &list->list, list) { ++ if (ether_addr_equal(ha->addr, addr)) { ++ netif_addr_unlock_bh(netdev); ++ return true; ++ } ++ } ++ netif_addr_unlock_bh(netdev); ++ return false; ++} ++ ++static inline int evb_port_fdb_prep(struct nlattr *tb[], ++ struct net_device *netdev, ++ const unsigned char *addr, u16 *vid, ++ bool del) ++{ ++ struct evb_port_priv *port_priv = netdev_priv(netdev); ++ struct evb_priv *evb_priv = port_priv->evb_priv; ++ ++ *vid = 0; ++ ++ if (evb_priv->attr.method != DPDMUX_METHOD_MAC && ++ evb_priv->attr.method != DPDMUX_METHOD_C_VLAN_MAC) { ++ netdev_err(netdev, ++ "EVB mode does not support MAC classification\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ /* check if the address is configured on this port */ ++ if (_lookup_address(netdev, addr)) { ++ if (!del) ++ return -EEXIST; ++ } else { ++ if (del) ++ return -ENOENT; ++ } ++ ++ if (tb[NDA_VLAN] && evb_priv->attr.method == DPDMUX_METHOD_C_VLAN_MAC) { ++ if (nla_len(tb[NDA_VLAN]) != sizeof(unsigned short)) { ++ netdev_err(netdev, "invalid vlan size %d\n", ++ nla_len(tb[NDA_VLAN])); ++ return -EINVAL; ++ } ++ ++ *vid = nla_get_u16(tb[NDA_VLAN]); ++ ++ if (!*vid || *vid >= VLAN_VID_MASK) { ++ netdev_err(netdev, "invalid vid value 0x%04x\n", *vid); ++ return -EINVAL; ++ } ++ } else if (evb_priv->attr.method == DPDMUX_METHOD_C_VLAN_MAC) { ++ netdev_err(netdev, ++ "EVB mode requires explicit VLAN configuration\n"); ++ return -EINVAL; ++ } else if (tb[NDA_VLAN]) { ++ netdev_warn(netdev, "VLAN not supported, argument ignored\n"); ++ } ++ ++ return 0; ++} ++ ++static int evb_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], ++ struct net_device *netdev, ++ const unsigned char *addr, u16 vid, u16 flags) ++{ ++ u16 _vid; ++ int err; ++ ++ /* TODO: add replace support when added to iproute bridge */ ++ if (!(flags & NLM_F_REQUEST)) { ++ netdev_err(netdev, ++ "evb_port_fdb_add unexpected flags value %08x\n", ++ flags); ++ return -EINVAL; ++ } ++ ++ err = evb_port_fdb_prep(tb, netdev, addr, &_vid, 0); ++ if (unlikely(err)) ++ return err; ++ ++ err = evb_port_add_rule(netdev, addr, _vid); ++ if (unlikely(err)) ++ return err; ++ ++ if (is_unicast_ether_addr(addr)) { ++ err = dev_uc_add(netdev, addr); ++ if (unlikely(err)) { ++ netdev_err(netdev, "dev_uc_add err %d\n", err); ++ return err; ++ } ++ } else { ++ err = dev_mc_add(netdev, addr); ++ if (unlikely(err)) { ++ netdev_err(netdev, "dev_mc_add err %d\n", err); ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ ++static int evb_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], ++ struct net_device *netdev, ++ const unsigned char *addr, u16 vid) ++{ ++ u16 _vid; ++ int err; ++ ++ err = evb_port_fdb_prep(tb, netdev, addr, &_vid, 1); ++ if (unlikely(err)) ++ return err; ++ ++ err = evb_port_del_rule(netdev, addr, _vid); ++ if (unlikely(err)) ++ return err; ++ ++ if (is_unicast_ether_addr(addr)) { ++ err = dev_uc_del(netdev, addr); ++ if (unlikely(err)) { ++ netdev_err(netdev, "dev_uc_del err %d\n", err); ++ return err; ++ } ++ } else { ++ err = dev_mc_del(netdev, addr); ++ if (unlikely(err)) { ++ netdev_err(netdev, "dev_mc_del err %d\n", err); ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ ++static int evb_change_mtu(struct net_device *netdev, ++ int mtu) ++{ ++ struct evb_port_priv *port_priv = netdev_priv(netdev); ++ struct evb_priv *evb_priv = port_priv->evb_priv; ++ struct list_head *pos; ++ int err = 0; ++ ++ /* This operation is not permitted on downlinks */ ++ if (port_priv->port_index > 0) ++ return -EPERM; ++ ++ if (mtu < EVB_MIN_FRAME_LENGTH || mtu > EVB_MAX_FRAME_LENGTH) { ++ netdev_err(netdev, "Invalid MTU %d. Valid range is: %d..%d\n", ++ mtu, EVB_MIN_FRAME_LENGTH, EVB_MAX_FRAME_LENGTH); ++ return -EINVAL; ++ } ++ ++ err = dpdmux_set_max_frame_length(evb_priv->mc_io, ++ 0, ++ evb_priv->mux_handle, ++ (uint16_t)mtu); ++ ++ if (unlikely(err)) { ++ netdev_err(netdev, "dpdmux_ul_set_max_frame_length err %d\n", ++ err); ++ return err; ++ } ++ ++ /* Update the max frame length for downlinks */ ++ list_for_each(pos, &evb_priv->port_list) { ++ port_priv = list_entry(pos, struct evb_port_priv, list); ++ port_priv->netdev->mtu = mtu; ++ } ++ ++ netdev->mtu = mtu; ++ return 0; ++} ++ ++static const struct nla_policy ifla_br_policy[IFLA_MAX + 1] = { ++ [IFLA_BRIDGE_FLAGS] = { .type = NLA_U16 }, ++ [IFLA_BRIDGE_MODE] = { .type = NLA_U16 }, ++ [IFLA_BRIDGE_VLAN_INFO] = { .type = NLA_BINARY, ++ .len = sizeof(struct bridge_vlan_info), }, ++}; ++ ++static int evb_setlink_af_spec(struct net_device *netdev, ++ struct nlattr **tb) ++{ ++ struct bridge_vlan_info *vinfo; ++ struct evb_port_priv *port_priv = netdev_priv(netdev); ++ int err = 0; ++ ++ if (!tb[IFLA_BRIDGE_VLAN_INFO]) { ++ netdev_err(netdev, "no VLAN INFO in nlmsg\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]); ++ ++ if (!vinfo->vid || vinfo->vid > VLAN_VID_MASK) ++ return -EINVAL; ++ ++ err = evb_port_add_rule(netdev, NULL, vinfo->vid); ++ if (unlikely(err)) ++ return err; ++ ++ port_priv->vlans[vinfo->vid] = 1; ++ ++ return 0; ++} ++ ++static int evb_setlink(struct net_device *netdev, ++ struct nlmsghdr *nlh, ++ u16 flags) ++{ ++ struct evb_port_priv *port_priv = netdev_priv(netdev); ++ struct evb_priv *evb_priv = port_priv->evb_priv; ++ struct nlattr *attr; ++ struct nlattr *tb[(IFLA_BRIDGE_MAX > IFLA_BRPORT_MAX) ? ++ IFLA_BRIDGE_MAX : IFLA_BRPORT_MAX + 1]; ++ int err = 0; ++ ++ if (evb_priv->attr.method != DPDMUX_METHOD_C_VLAN && ++ evb_priv->attr.method != DPDMUX_METHOD_S_VLAN) { ++ netdev_err(netdev, ++ "EVB mode does not support VLAN only classification\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ attr = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); ++ if (attr) { ++ err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, attr, ++ ifla_br_policy); ++ if (unlikely(err)) { ++ netdev_err(netdev, ++ "nla_parse_nested for br_policy err %d\n", ++ err); ++ return err; ++ } ++ ++ err = evb_setlink_af_spec(netdev, tb); ++ return err; ++ } ++ ++ netdev_err(netdev, "nlmsg_find_attr found no AF_SPEC\n"); ++ return -EOPNOTSUPP; ++} ++ ++static int __nla_put_netdev(struct sk_buff *skb, struct net_device *netdev) ++{ ++ struct evb_port_priv *port_priv = netdev_priv(netdev); ++ struct evb_priv *evb_priv = port_priv->evb_priv; ++ u8 operstate = netif_running(netdev) ? ++ netdev->operstate : IF_OPER_DOWN; ++ int iflink; ++ int err; ++ ++ err = nla_put_string(skb, IFLA_IFNAME, netdev->name); ++ if (unlikely(err)) ++ goto nla_put_err; ++ err = nla_put_u32(skb, IFLA_MASTER, evb_priv->uplink.netdev->ifindex); ++ if (unlikely(err)) ++ goto nla_put_err; ++ err = nla_put_u32(skb, IFLA_MTU, netdev->mtu); ++ if (unlikely(err)) ++ goto nla_put_err; ++ err = nla_put_u8(skb, IFLA_OPERSTATE, operstate); ++ if (unlikely(err)) ++ goto nla_put_err; ++ if (netdev->addr_len) { ++ err = nla_put(skb, IFLA_ADDRESS, netdev->addr_len, ++ netdev->dev_addr); ++ if (unlikely(err)) ++ goto nla_put_err; ++ } ++ ++ iflink = dev_get_iflink(netdev); ++ if (netdev->ifindex != iflink) { ++ err = nla_put_u32(skb, IFLA_LINK, iflink); ++ if (unlikely(err)) ++ goto nla_put_err; ++ } ++ ++ return 0; ++ ++nla_put_err: ++ netdev_err(netdev, "nla_put_ err %d\n", err); ++ return err; ++} ++ ++static int __nla_put_port(struct sk_buff *skb, struct net_device *netdev) ++{ ++ struct nlattr *nest; ++ int err; ++ ++ nest = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED); ++ if (!nest) { ++ netdev_err(netdev, "nla_nest_start failed\n"); ++ return -ENOMEM; ++ } ++ ++ err = nla_put_u8(skb, IFLA_BRPORT_STATE, BR_STATE_FORWARDING); ++ if (unlikely(err)) ++ goto nla_put_err; ++ err = nla_put_u16(skb, IFLA_BRPORT_PRIORITY, 0); ++ if (unlikely(err)) ++ goto nla_put_err; ++ err = nla_put_u32(skb, IFLA_BRPORT_COST, 0); ++ if (unlikely(err)) ++ goto nla_put_err; ++ err = nla_put_u8(skb, IFLA_BRPORT_MODE, 0); ++ if (unlikely(err)) ++ goto nla_put_err; ++ err = nla_put_u8(skb, IFLA_BRPORT_GUARD, 0); ++ if (unlikely(err)) ++ goto nla_put_err; ++ err = nla_put_u8(skb, IFLA_BRPORT_PROTECT, 0); ++ if (unlikely(err)) ++ goto nla_put_err; ++ err = nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE, 0); ++ if (unlikely(err)) ++ goto nla_put_err; ++ err = nla_put_u8(skb, IFLA_BRPORT_LEARNING, 0); ++ if (unlikely(err)) ++ goto nla_put_err; ++ err = nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD, 1); ++ if (unlikely(err)) ++ goto nla_put_err; ++ nla_nest_end(skb, nest); ++ ++ return 0; ++ ++nla_put_err: ++ netdev_err(netdev, "nla_put_ err %d\n", err); ++ nla_nest_cancel(skb, nest); ++ return err; ++} ++ ++static int __nla_put_vlan(struct sk_buff *skb, struct net_device *netdev) ++{ ++ struct evb_port_priv *port_priv = netdev_priv(netdev); ++ struct nlattr *nest; ++ struct bridge_vlan_info vinfo; ++ const u8 *vlans = port_priv->vlans; ++ u16 i; ++ int err; ++ ++ nest = nla_nest_start(skb, IFLA_AF_SPEC); ++ if (!nest) { ++ netdev_err(netdev, "nla_nest_start failed"); ++ return -ENOMEM; ++ } ++ ++ for (i = 0; i < VLAN_VID_MASK + 1; i++) { ++ if (!vlans[i]) ++ continue; ++ ++ vinfo.flags = 0; ++ vinfo.vid = i; ++ ++ err = nla_put(skb, IFLA_BRIDGE_VLAN_INFO, ++ sizeof(vinfo), &vinfo); ++ if (unlikely(err)) ++ goto nla_put_err; ++ } ++ ++ nla_nest_end(skb, nest); ++ ++ return 0; ++ ++nla_put_err: ++ netdev_err(netdev, "nla_put_ err %d\n", err); ++ nla_nest_cancel(skb, nest); ++ return err; ++} ++ ++static int evb_getlink(struct sk_buff *skb, u32 pid, u32 seq, ++ struct net_device *netdev, u32 filter_mask, int nlflags) ++{ ++ struct evb_port_priv *port_priv = netdev_priv(netdev); ++ struct evb_priv *evb_priv = port_priv->evb_priv; ++ struct ifinfomsg *hdr; ++ struct nlmsghdr *nlh; ++ int err; ++ ++ if (evb_priv->attr.method != DPDMUX_METHOD_C_VLAN && ++ evb_priv->attr.method != DPDMUX_METHOD_S_VLAN) { ++ return 0; ++ } ++ ++ nlh = nlmsg_put(skb, pid, seq, RTM_NEWLINK, sizeof(*hdr), NLM_F_MULTI); ++ if (!nlh) ++ return -EMSGSIZE; ++ ++ hdr = nlmsg_data(nlh); ++ memset(hdr, 0, sizeof(*hdr)); ++ hdr->ifi_family = AF_BRIDGE; ++ hdr->ifi_type = netdev->type; ++ hdr->ifi_index = netdev->ifindex; ++ hdr->ifi_flags = dev_get_flags(netdev); ++ ++ err = __nla_put_netdev(skb, netdev); ++ if (unlikely(err)) ++ goto nla_put_err; ++ ++ err = __nla_put_port(skb, netdev); ++ if (unlikely(err)) ++ goto nla_put_err; ++ ++ /* Check if the VID information is requested */ ++ if (filter_mask & RTEXT_FILTER_BRVLAN) { ++ err = __nla_put_vlan(skb, netdev); ++ if (unlikely(err)) ++ goto nla_put_err; ++ } ++ ++ nlmsg_end(skb, nlh); ++ return skb->len; ++ ++nla_put_err: ++ nlmsg_cancel(skb, nlh); ++ return -EMSGSIZE; ++} ++ ++static int evb_dellink(struct net_device *netdev, ++ struct nlmsghdr *nlh, ++ u16 flags) ++{ ++ struct nlattr *tb[IFLA_BRIDGE_MAX + 1]; ++ struct nlattr *spec; ++ struct bridge_vlan_info *vinfo; ++ struct evb_port_priv *port_priv = netdev_priv(netdev); ++ int err = 0; ++ ++ spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); ++ if (!spec) ++ return 0; ++ ++ err = nla_parse_nested(tb, IFLA_BRIDGE_MAX, spec, ifla_br_policy); ++ if (unlikely(err)) ++ return err; ++ ++ if (!tb[IFLA_BRIDGE_VLAN_INFO]) ++ return -EOPNOTSUPP; ++ ++ vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]); ++ ++ if (!vinfo->vid || vinfo->vid > VLAN_VID_MASK) ++ return -EINVAL; ++ ++ err = evb_port_del_rule(netdev, NULL, vinfo->vid); ++ if (unlikely(err)) { ++ netdev_err(netdev, "evb_port_del_rule err %d\n", err); ++ return err; ++ } ++ port_priv->vlans[vinfo->vid] = 0; ++ ++ return 0; ++} ++ ++void evb_port_get_stats(struct net_device *netdev, ++ struct rtnl_link_stats64 *storage) ++{ ++ struct evb_port_priv *port_priv = netdev_priv(netdev); ++ u64 tmp; ++ int err; ++ ++ err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io, ++ 0, ++ port_priv->evb_priv->mux_handle, ++ port_priv->port_index, ++ DPDMUX_CNT_ING_FRAME, &storage->rx_packets); ++ if (unlikely(err)) ++ goto error; ++ ++ err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io, ++ 0, ++ port_priv->evb_priv->mux_handle, ++ port_priv->port_index, ++ DPDMUX_CNT_ING_BYTE, &storage->rx_bytes); ++ if (unlikely(err)) ++ goto error; ++ ++ err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io, ++ 0, ++ port_priv->evb_priv->mux_handle, ++ port_priv->port_index, ++ DPDMUX_CNT_ING_FLTR_FRAME, &tmp); ++ if (unlikely(err)) ++ goto error; ++ ++ err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io, ++ 0, ++ port_priv->evb_priv->mux_handle, ++ port_priv->port_index, ++ DPDMUX_CNT_ING_FRAME_DISCARD, ++ &storage->rx_dropped); ++ if (unlikely(err)) { ++ storage->rx_dropped = tmp; ++ goto error; ++ } ++ storage->rx_dropped += tmp; ++ ++ err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io, ++ 0, ++ port_priv->evb_priv->mux_handle, ++ port_priv->port_index, ++ DPDMUX_CNT_ING_MCAST_FRAME, ++ &storage->multicast); ++ if (unlikely(err)) ++ goto error; ++ ++ err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io, ++ 0, ++ port_priv->evb_priv->mux_handle, ++ port_priv->port_index, ++ DPDMUX_CNT_EGR_FRAME, &storage->tx_packets); ++ if (unlikely(err)) ++ goto error; ++ ++ err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io, ++ 0, ++ port_priv->evb_priv->mux_handle, ++ port_priv->port_index, ++ DPDMUX_CNT_EGR_BYTE, &storage->tx_bytes); ++ if (unlikely(err)) ++ goto error; ++ ++ err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io, ++ 0, ++ port_priv->evb_priv->mux_handle, ++ port_priv->port_index, ++ DPDMUX_CNT_EGR_FRAME_DISCARD, ++ &storage->tx_dropped); ++ if (unlikely(err)) ++ goto error; ++ ++ return; ++ ++error: ++ netdev_err(netdev, "dpdmux_if_get_counter err %d\n", err); ++} ++ ++static const struct net_device_ops evb_port_ops = { ++ .ndo_open = &evb_port_open, ++ ++ .ndo_start_xmit = &evb_dropframe, ++ ++ .ndo_fdb_add = &evb_port_fdb_add, ++ .ndo_fdb_del = &evb_port_fdb_del, ++ ++ .ndo_get_stats64 = &evb_port_get_stats, ++ .ndo_change_mtu = &evb_change_mtu, ++}; ++ ++static void evb_get_drvinfo(struct net_device *netdev, ++ struct ethtool_drvinfo *drvinfo) ++{ ++ struct evb_port_priv *port_priv = netdev_priv(netdev); ++ u16 version_major, version_minor; ++ int err; ++ ++ strlcpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver)); ++ strlcpy(drvinfo->version, evb_drv_version, sizeof(drvinfo->version)); ++ ++ err = dpdmux_get_api_version(port_priv->evb_priv->mc_io, 0, ++ &version_major, ++ &version_minor); ++ if (err) ++ strlcpy(drvinfo->fw_version, "N/A", ++ sizeof(drvinfo->fw_version)); ++ else ++ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), ++ "%u.%u", version_major, version_minor); ++ ++ strlcpy(drvinfo->bus_info, dev_name(netdev->dev.parent->parent), ++ sizeof(drvinfo->bus_info)); ++} ++ ++static int evb_get_settings(struct net_device *netdev, ++ struct ethtool_cmd *cmd) ++{ ++ struct evb_port_priv *port_priv = netdev_priv(netdev); ++ struct dpdmux_link_state state = {0}; ++ int err = 0; ++ ++ err = dpdmux_if_get_link_state(port_priv->evb_priv->mc_io, 0, ++ port_priv->evb_priv->mux_handle, ++ port_priv->port_index, ++ &state); ++ if (err) { ++ netdev_err(netdev, "ERROR %d getting link state", err); ++ goto out; ++ } ++ ++ /* At the moment, we have no way of interrogating the DPMAC ++ * from the DPDMUX side or there may not exist a DPMAC at all. ++ * Report only autoneg state, duplexity and speed. ++ */ ++ if (state.options & DPDMUX_LINK_OPT_AUTONEG) ++ cmd->autoneg = AUTONEG_ENABLE; ++ if (!(state.options & DPDMUX_LINK_OPT_HALF_DUPLEX)) ++ cmd->duplex = DUPLEX_FULL; ++ ethtool_cmd_speed_set(cmd, state.rate); ++ ++out: ++ return err; ++} ++ ++static int evb_set_settings(struct net_device *netdev, ++ struct ethtool_cmd *cmd) ++{ ++ struct evb_port_priv *port_priv = netdev_priv(netdev); ++ struct dpdmux_link_state state = {0}; ++ struct dpdmux_link_cfg cfg = {0}; ++ int err = 0; ++ ++ netdev_dbg(netdev, "Setting link parameters..."); ++ ++ err = dpdmux_if_get_link_state(port_priv->evb_priv->mc_io, 0, ++ port_priv->evb_priv->mux_handle, ++ port_priv->port_index, ++ &state); ++ if (err) { ++ netdev_err(netdev, "ERROR %d getting link state", err); ++ goto out; ++ } ++ ++ /* Due to a temporary MC limitation, the DPDMUX port must be down ++ * in order to be able to change link settings. Taking steps to let ++ * the user know that. ++ */ ++ if (netif_running(netdev)) { ++ netdev_info(netdev, ++ "Sorry, interface must be brought down first.\n"); ++ return -EACCES; ++ } ++ ++ cfg.options = state.options; ++ cfg.rate = ethtool_cmd_speed(cmd); ++ if (cmd->autoneg == AUTONEG_ENABLE) ++ cfg.options |= DPDMUX_LINK_OPT_AUTONEG; ++ else ++ cfg.options &= ~DPDMUX_LINK_OPT_AUTONEG; ++ if (cmd->duplex == DUPLEX_HALF) ++ cfg.options |= DPDMUX_LINK_OPT_HALF_DUPLEX; ++ else ++ cfg.options &= ~DPDMUX_LINK_OPT_HALF_DUPLEX; ++ ++ err = dpdmux_if_set_link_cfg(port_priv->evb_priv->mc_io, 0, ++ port_priv->evb_priv->mux_handle, ++ port_priv->port_index, ++ &cfg); ++ if (err) ++ /* ethtool will be loud enough if we return an error; no point ++ * in putting our own error message on the console by default ++ */ ++ netdev_dbg(netdev, "ERROR %d setting link cfg", err); ++ ++out: ++ return err; ++} ++ ++static struct { ++ enum dpdmux_counter_type id; ++ char name[ETH_GSTRING_LEN]; ++} evb_ethtool_counters[] = { ++ {DPDMUX_CNT_ING_FRAME, "rx frames"}, ++ {DPDMUX_CNT_ING_BYTE, "rx bytes"}, ++ {DPDMUX_CNT_ING_FLTR_FRAME, "rx filtered frames"}, ++ {DPDMUX_CNT_ING_FRAME_DISCARD, "rx discarded frames"}, ++ {DPDMUX_CNT_ING_BCAST_FRAME, "rx b-cast frames"}, ++ {DPDMUX_CNT_ING_BCAST_BYTES, "rx b-cast bytes"}, ++ {DPDMUX_CNT_ING_MCAST_FRAME, "rx m-cast frames"}, ++ {DPDMUX_CNT_ING_MCAST_BYTE, "rx m-cast bytes"}, ++ {DPDMUX_CNT_EGR_FRAME, "tx frames"}, ++ {DPDMUX_CNT_EGR_BYTE, "tx bytes"}, ++ {DPDMUX_CNT_EGR_FRAME_DISCARD, "tx discarded frames"}, ++}; ++ ++static int evb_ethtool_get_sset_count(struct net_device *dev, int sset) ++{ ++ switch (sset) { ++ case ETH_SS_STATS: ++ return ARRAY_SIZE(evb_ethtool_counters); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static void evb_ethtool_get_strings(struct net_device *netdev, ++ u32 stringset, u8 *data) ++{ ++ u32 i; ++ ++ switch (stringset) { ++ case ETH_SS_STATS: ++ for (i = 0; i < ARRAY_SIZE(evb_ethtool_counters); i++) ++ memcpy(data + i * ETH_GSTRING_LEN, ++ evb_ethtool_counters[i].name, ETH_GSTRING_LEN); ++ break; ++ } ++} ++ ++static void evb_ethtool_get_stats(struct net_device *netdev, ++ struct ethtool_stats *stats, ++ u64 *data) ++{ ++ struct evb_port_priv *port_priv = netdev_priv(netdev); ++ u32 i; ++ int err; ++ ++ for (i = 0; i < ARRAY_SIZE(evb_ethtool_counters); i++) { ++ err = dpdmux_if_get_counter(port_priv->evb_priv->mc_io, ++ 0, ++ port_priv->evb_priv->mux_handle, ++ port_priv->port_index, ++ evb_ethtool_counters[i].id, ++ &data[i]); ++ if (err) ++ netdev_err(netdev, "dpdmux_if_get_counter[%s] err %d\n", ++ evb_ethtool_counters[i].name, err); ++ } ++} ++ ++static const struct ethtool_ops evb_port_ethtool_ops = { ++ .get_drvinfo = &evb_get_drvinfo, ++ .get_link = ðtool_op_get_link, ++ .get_settings = &evb_get_settings, ++ .set_settings = &evb_set_settings, ++ .get_strings = &evb_ethtool_get_strings, ++ .get_ethtool_stats = &evb_ethtool_get_stats, ++ .get_sset_count = &evb_ethtool_get_sset_count, ++}; ++ ++static int evb_open(struct net_device *netdev) ++{ ++ struct evb_priv *priv = netdev_priv(netdev); ++ int err = 0; ++ ++ err = dpdmux_enable(priv->mc_io, 0, priv->mux_handle); ++ if (unlikely(err)) ++ netdev_err(netdev, "dpdmux_enable err %d\n", err); ++ ++ return err; ++} ++ ++static int evb_close(struct net_device *netdev) ++{ ++ struct evb_priv *priv = netdev_priv(netdev); ++ int err = 0; ++ ++ err = dpdmux_disable(priv->mc_io, 0, priv->mux_handle); ++ if (unlikely(err)) ++ netdev_err(netdev, "dpdmux_disable err %d\n", err); ++ ++ return err; ++} ++ ++static const struct net_device_ops evb_ops = { ++ .ndo_start_xmit = &evb_dropframe, ++ .ndo_open = &evb_open, ++ .ndo_stop = &evb_close, ++ ++ .ndo_bridge_setlink = &evb_setlink, ++ .ndo_bridge_getlink = &evb_getlink, ++ .ndo_bridge_dellink = &evb_dellink, ++ ++ .ndo_get_stats64 = &evb_port_get_stats, ++ .ndo_change_mtu = &evb_change_mtu, ++}; ++ ++static int evb_takedown(struct fsl_mc_device *evb_dev) ++{ ++ struct device *dev = &evb_dev->dev; ++ struct net_device *netdev = dev_get_drvdata(dev); ++ struct evb_priv *priv = netdev_priv(netdev); ++ int err; ++ ++ err = dpdmux_close(priv->mc_io, 0, priv->mux_handle); ++ if (unlikely(err)) ++ dev_warn(dev, "dpdmux_close err %d\n", err); ++ ++ return 0; ++} ++ ++static int evb_init(struct fsl_mc_device *evb_dev) ++{ ++ struct device *dev = &evb_dev->dev; ++ struct net_device *netdev = dev_get_drvdata(dev); ++ struct evb_priv *priv = netdev_priv(netdev); ++ u16 version_major; ++ u16 version_minor; ++ int err = 0; ++ ++ priv->dev_id = evb_dev->obj_desc.id; ++ ++ err = dpdmux_open(priv->mc_io, 0, priv->dev_id, &priv->mux_handle); ++ if (unlikely(err)) { ++ dev_err(dev, "dpdmux_open err %d\n", err); ++ goto err_exit; ++ } ++ if (!priv->mux_handle) { ++ dev_err(dev, "dpdmux_open returned null handle but no error\n"); ++ err = -EFAULT; ++ goto err_exit; ++ } ++ ++ err = dpdmux_get_attributes(priv->mc_io, 0, priv->mux_handle, ++ &priv->attr); ++ if (unlikely(err)) { ++ dev_err(dev, "dpdmux_get_attributes err %d\n", err); ++ goto err_close; ++ } ++ ++ err = dpdmux_get_api_version(priv->mc_io, 0, ++ &version_major, ++ &version_minor); ++ if (unlikely(err)) { ++ dev_err(dev, "dpdmux_get_api_version err %d\n", err); ++ goto err_close; ++ } ++ ++ /* Minimum supported DPDMUX version check */ ++ if (version_major < DPDMUX_MIN_VER_MAJOR || ++ (version_major == DPDMUX_MIN_VER_MAJOR && ++ version_minor < DPDMUX_MIN_VER_MINOR)) { ++ dev_err(dev, "DPDMUX version %d.%d not supported. Use %d.%d or greater.\n", ++ version_major, version_minor, ++ DPDMUX_MIN_VER_MAJOR, DPDMUX_MIN_VER_MAJOR); ++ err = -ENOTSUPP; ++ goto err_close; ++ } ++ ++ err = dpdmux_reset(priv->mc_io, 0, priv->mux_handle); ++ if (unlikely(err)) { ++ dev_err(dev, "dpdmux_reset err %d\n", err); ++ goto err_close; ++ } ++ ++ return 0; ++ ++err_close: ++ dpdmux_close(priv->mc_io, 0, priv->mux_handle); ++err_exit: ++ return err; ++} ++ ++static int evb_remove(struct fsl_mc_device *evb_dev) ++{ ++ struct device *dev = &evb_dev->dev; ++ struct net_device *netdev = dev_get_drvdata(dev); ++ struct evb_priv *priv = netdev_priv(netdev); ++ struct evb_port_priv *port_priv; ++ struct list_head *pos; ++ ++ list_for_each(pos, &priv->port_list) { ++ port_priv = list_entry(pos, struct evb_port_priv, list); ++ ++ rtnl_lock(); ++ netdev_upper_dev_unlink(port_priv->netdev, netdev); ++ rtnl_unlock(); ++ ++ unregister_netdev(port_priv->netdev); ++ free_netdev(port_priv->netdev); ++ } ++ ++ evb_teardown_irqs(evb_dev); ++ ++ unregister_netdev(netdev); ++ ++ evb_takedown(evb_dev); ++ fsl_mc_portal_free(priv->mc_io); ++ ++ dev_set_drvdata(dev, NULL); ++ free_netdev(netdev); ++ ++ return 0; ++} ++ ++static int evb_probe(struct fsl_mc_device *evb_dev) ++{ ++ struct device *dev; ++ struct evb_priv *priv = NULL; ++ struct net_device *netdev = NULL; ++ char port_name[IFNAMSIZ]; ++ int i; ++ int err = 0; ++ ++ dev = &evb_dev->dev; ++ ++ /* register switch device, it's for management only - no I/O */ ++ netdev = alloc_etherdev(sizeof(*priv)); ++ if (!netdev) { ++ dev_err(dev, "alloc_etherdev error\n"); ++ return -ENOMEM; ++ } ++ netdev->netdev_ops = &evb_ops; ++ ++ dev_set_drvdata(dev, netdev); ++ ++ priv = netdev_priv(netdev); ++ ++ err = fsl_mc_portal_allocate(evb_dev, 0, &priv->mc_io); ++ if (unlikely(err)) { ++ dev_err(dev, "fsl_mc_portal_allocate err %d\n", err); ++ goto err_free_netdev; ++ } ++ if (!priv->mc_io) { ++ dev_err(dev, "fsl_mc_portal_allocate returned null handle but no error\n"); ++ err = -EFAULT; ++ goto err_free_netdev; ++ } ++ ++ err = evb_init(evb_dev); ++ if (unlikely(err)) { ++ dev_err(dev, "evb init err %d\n", err); ++ goto err_free_cmdport; ++ } ++ ++ INIT_LIST_HEAD(&priv->port_list); ++ netdev->flags |= IFF_PROMISC | IFF_MASTER; ++ ++ dev_alloc_name(netdev, "evb%d"); ++ ++ /* register switch ports */ ++ snprintf(port_name, IFNAMSIZ, "%sp%%d", netdev->name); ++ ++ /* only register downlinks? */ ++ for (i = 0; i < priv->attr.num_ifs + 1; i++) { ++ struct net_device *port_netdev; ++ struct evb_port_priv *port_priv; ++ ++ if (i) { ++ port_netdev = ++ alloc_etherdev(sizeof(struct evb_port_priv)); ++ if (!port_netdev) { ++ dev_err(dev, "alloc_etherdev error\n"); ++ goto err_takedown; ++ } ++ ++ port_priv = netdev_priv(port_netdev); ++ ++ port_netdev->flags |= IFF_PROMISC | IFF_SLAVE; ++ ++ dev_alloc_name(port_netdev, port_name); ++ } else { ++ port_netdev = netdev; ++ port_priv = &priv->uplink; ++ } ++ ++ port_priv->netdev = port_netdev; ++ port_priv->evb_priv = priv; ++ port_priv->port_index = i; ++ ++ SET_NETDEV_DEV(port_netdev, dev); ++ ++ if (i) { ++ port_netdev->netdev_ops = &evb_port_ops; ++ ++ err = register_netdev(port_netdev); ++ if (err < 0) { ++ dev_err(dev, "register_netdev err %d\n", err); ++ free_netdev(port_netdev); ++ goto err_takedown; ++ } ++ ++ rtnl_lock(); ++ err = netdev_master_upper_dev_link(port_netdev, netdev, ++ NULL, NULL); ++ if (unlikely(err)) { ++ dev_err(dev, "netdev_master_upper_dev_link err %d\n", ++ err); ++ unregister_netdev(port_netdev); ++ free_netdev(port_netdev); ++ rtnl_unlock(); ++ goto err_takedown; ++ } ++ rtmsg_ifinfo(RTM_NEWLINK, port_netdev, ++ IFF_SLAVE, GFP_KERNEL); ++ rtnl_unlock(); ++ ++ list_add(&port_priv->list, &priv->port_list); ++ } else { ++ err = register_netdev(netdev); ++ ++ if (err < 0) { ++ dev_err(dev, "register_netdev error %d\n", err); ++ goto err_takedown; ++ } ++ } ++ ++ port_netdev->ethtool_ops = &evb_port_ethtool_ops; ++ ++ /* ports are up from init */ ++ rtnl_lock(); ++ err = dev_open(port_netdev); ++ rtnl_unlock(); ++ if (unlikely(err)) ++ dev_warn(dev, "dev_open err %d\n", err); ++ } ++ ++ /* setup irqs */ ++ err = evb_setup_irqs(evb_dev); ++ if (unlikely(err)) { ++ dev_warn(dev, "evb_setup_irqs err %d\n", err); ++ goto err_takedown; ++ } ++ ++ dev_info(dev, "probed evb device with %d ports\n", ++ priv->attr.num_ifs); ++ return 0; ++ ++err_takedown: ++ evb_remove(evb_dev); ++err_free_cmdport: ++ fsl_mc_portal_free(priv->mc_io); ++err_free_netdev: ++ return err; ++} ++ ++static const struct fsl_mc_device_id evb_match_id_table[] = { ++ { ++ .vendor = FSL_MC_VENDOR_FREESCALE, ++ .obj_type = "dpdmux", ++ }, ++ {} ++}; ++ ++static struct fsl_mc_driver evb_drv = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = evb_probe, ++ .remove = evb_remove, ++ .match_id_table = evb_match_id_table, ++}; ++ ++module_fsl_mc_driver(evb_drv); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Layerscape DPAA Edge Virtual Bridge driver (prototype)"); +diff --git a/drivers/staging/fsl-dpaa2/mac/Kconfig b/drivers/staging/fsl-dpaa2/mac/Kconfig +new file mode 100644 +index 00000000..c94f7c1b +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/mac/Kconfig +@@ -0,0 +1,23 @@ ++config FSL_DPAA2_MAC ++ tristate "DPAA2 MAC / PHY interface" ++ depends on FSL_MC_BUS && FSL_DPAA2 ++ select MDIO_BUS_MUX_MMIOREG ++ select FSL_XGMAC_MDIO ++ select FIXED_PHY ++ ---help--- ++ Prototype driver for DPAA2 MAC / PHY interface object. ++ This driver works as a proxy between phylib including phy drivers and ++ the MC firmware. It receives updates on link state changes from PHY ++ lib and forwards them to MC and receives interrupt from MC whenever ++ a request is made to change the link state. ++ ++ ++config FSL_DPAA2_MAC_NETDEVS ++ bool "Expose net interfaces for PHYs" ++ default n ++ depends on FSL_DPAA2_MAC ++ ---help--- ++ Exposes macX net interfaces which allow direct control over MACs and ++ PHYs. ++ . ++ Leave disabled if unsure. +diff --git a/drivers/staging/fsl-dpaa2/mac/Makefile b/drivers/staging/fsl-dpaa2/mac/Makefile +new file mode 100644 +index 00000000..bda94101 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/mac/Makefile +@@ -0,0 +1,10 @@ ++ ++obj-$(CONFIG_FSL_DPAA2_MAC) += dpaa2-mac.o ++ ++dpaa2-mac-objs := mac.o dpmac.o ++ ++all: ++ make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules ++ ++clean: ++ make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean +diff --git a/drivers/staging/fsl-dpaa2/mac/dpmac-cmd.h b/drivers/staging/fsl-dpaa2/mac/dpmac-cmd.h +new file mode 100644 +index 00000000..abdc3c0d +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/mac/dpmac-cmd.h +@@ -0,0 +1,172 @@ ++/* Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef _FSL_DPMAC_CMD_H ++#define _FSL_DPMAC_CMD_H ++ ++/* DPMAC Version */ ++#define DPMAC_VER_MAJOR 4 ++#define DPMAC_VER_MINOR 2 ++#define DPMAC_CMD_BASE_VERSION 1 ++#define DPMAC_CMD_ID_OFFSET 4 ++ ++#define DPMAC_CMD(id) (((id) << DPMAC_CMD_ID_OFFSET) | DPMAC_CMD_BASE_VERSION) ++ ++/* Command IDs */ ++#define DPMAC_CMDID_CLOSE DPMAC_CMD(0x800) ++#define DPMAC_CMDID_OPEN DPMAC_CMD(0x80c) ++#define DPMAC_CMDID_CREATE DPMAC_CMD(0x90c) ++#define DPMAC_CMDID_DESTROY DPMAC_CMD(0x98c) ++#define DPMAC_CMDID_GET_API_VERSION DPMAC_CMD(0xa0c) ++ ++#define DPMAC_CMDID_GET_ATTR DPMAC_CMD(0x004) ++#define DPMAC_CMDID_RESET DPMAC_CMD(0x005) ++ ++#define DPMAC_CMDID_SET_IRQ_ENABLE DPMAC_CMD(0x012) ++#define DPMAC_CMDID_GET_IRQ_ENABLE DPMAC_CMD(0x013) ++#define DPMAC_CMDID_SET_IRQ_MASK DPMAC_CMD(0x014) ++#define DPMAC_CMDID_GET_IRQ_MASK DPMAC_CMD(0x015) ++#define DPMAC_CMDID_GET_IRQ_STATUS DPMAC_CMD(0x016) ++#define DPMAC_CMDID_CLEAR_IRQ_STATUS DPMAC_CMD(0x017) ++ ++#define DPMAC_CMDID_GET_LINK_CFG DPMAC_CMD(0x0c2) ++#define DPMAC_CMDID_SET_LINK_STATE DPMAC_CMD(0x0c3) ++#define DPMAC_CMDID_GET_COUNTER DPMAC_CMD(0x0c4) ++ ++#define DPMAC_CMDID_SET_PORT_MAC_ADDR DPMAC_CMD(0x0c5) ++ ++/* Macros for accessing command fields smaller than 1byte */ ++#define DPMAC_MASK(field) \ ++ GENMASK(DPMAC_##field##_SHIFT + DPMAC_##field##_SIZE - 1, \ ++ DPMAC_##field##_SHIFT) ++#define dpmac_set_field(var, field, val) \ ++ ((var) |= (((val) << DPMAC_##field##_SHIFT) & DPMAC_MASK(field))) ++#define dpmac_get_field(var, field) \ ++ (((var) & DPMAC_MASK(field)) >> DPMAC_##field##_SHIFT) ++ ++struct dpmac_cmd_open { ++ u32 dpmac_id; ++}; ++ ++struct dpmac_cmd_create { ++ u32 mac_id; ++}; ++ ++struct dpmac_cmd_destroy { ++ u32 dpmac_id; ++}; ++ ++struct dpmac_cmd_set_irq_enable { ++ u8 enable; ++ u8 pad[3]; ++ u8 irq_index; ++}; ++ ++struct dpmac_cmd_get_irq_enable { ++ u32 pad; ++ u8 irq_index; ++}; ++ ++struct dpmac_rsp_get_irq_enable { ++ u8 enabled; ++}; ++ ++struct dpmac_cmd_set_irq_mask { ++ u32 mask; ++ u8 irq_index; ++}; ++ ++struct dpmac_cmd_get_irq_mask { ++ u32 pad; ++ u8 irq_index; ++}; ++ ++struct dpmac_rsp_get_irq_mask { ++ u32 mask; ++}; ++ ++struct dpmac_cmd_get_irq_status { ++ u32 status; ++ u8 irq_index; ++}; ++ ++struct dpmac_rsp_get_irq_status { ++ u32 status; ++}; ++ ++struct dpmac_cmd_clear_irq_status { ++ u32 status; ++ u8 irq_index; ++}; ++ ++struct dpmac_rsp_get_attributes { ++ u8 eth_if; ++ u8 link_type; ++ u16 id; ++ u32 max_rate; ++}; ++ ++struct dpmac_rsp_get_link_cfg { ++ u64 options; ++ u32 rate; ++}; ++ ++#define DPMAC_STATE_SIZE 1 ++#define DPMAC_STATE_SHIFT 0 ++ ++struct dpmac_cmd_set_link_state { ++ u64 options; ++ u32 rate; ++ u32 pad; ++ /* only least significant bit is valid */ ++ u8 up; ++}; ++ ++struct dpmac_cmd_get_counter { ++ u8 type; ++}; ++ ++struct dpmac_rsp_get_counter { ++ u64 pad; ++ u64 counter; ++}; ++ ++struct dpmac_rsp_get_api_version { ++ u16 major; ++ u16 minor; ++}; ++ ++struct dpmac_cmd_set_port_mac_addr { ++ u8 pad[2]; ++ u8 addr[6]; ++}; ++ ++#endif /* _FSL_DPMAC_CMD_H */ +diff --git a/drivers/staging/fsl-dpaa2/mac/dpmac.c b/drivers/staging/fsl-dpaa2/mac/dpmac.c +new file mode 100644 +index 00000000..f7827423 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/mac/dpmac.c +@@ -0,0 +1,620 @@ ++/* Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#include "../../fsl-mc/include/mc-sys.h" ++#include "../../fsl-mc/include/mc-cmd.h" ++#include "dpmac.h" ++#include "dpmac-cmd.h" ++ ++/** ++ * dpmac_open() - Open a control session for the specified object. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @dpmac_id: DPMAC unique ID ++ * @token: Returned token; use in subsequent API calls ++ * ++ * This function can be used to open a control session for an ++ * already created object; an object may have been declared in ++ * the DPL or by calling the dpmac_create function. ++ * This function returns a unique authentication token, ++ * associated with the specific object ID and the specific MC ++ * portal; this token must be used in all subsequent commands for ++ * this specific object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpmac_id, ++ u16 *token) ++{ ++ struct dpmac_cmd_open *cmd_params; ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_OPEN, ++ cmd_flags, ++ 0); ++ cmd_params = (struct dpmac_cmd_open *)cmd.params; ++ cmd_params->dpmac_id = cpu_to_le32(dpmac_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *token = mc_cmd_hdr_read_token(&cmd); ++ ++ return err; ++} ++ ++/** ++ * dpmac_close() - Close the control session of the object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * ++ * After this function is called, no further operations are ++ * allowed on the object without opening a new control session. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CLOSE, cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpmac_create() - Create the DPMAC object. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @dprc_token: Parent container token; '0' for default container ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @cfg: Configuration structure ++ * @obj_id: Returned object id ++ * ++ * Create the DPMAC object, allocate required resources and ++ * perform required initialization. ++ * ++ * The function accepts an authentication token of a parent ++ * container that this object should be assigned to. The token ++ * can be '0' so the object will be assigned to the default container. ++ * The newly created object can be opened with the returned ++ * object id and using the container's associated tokens and MC portals. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_create(struct fsl_mc_io *mc_io, ++ u16 dprc_token, ++ u32 cmd_flags, ++ const struct dpmac_cfg *cfg, ++ u32 *obj_id) ++{ ++ struct dpmac_cmd_create *cmd_params; ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CREATE, ++ cmd_flags, ++ dprc_token); ++ cmd_params = (struct dpmac_cmd_create *)cmd.params; ++ cmd_params->mac_id = cpu_to_le32(cfg->mac_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *obj_id = mc_cmd_read_object_id(&cmd); ++ ++ return 0; ++} ++ ++/** ++ * dpmac_destroy() - Destroy the DPMAC object and release all its resources. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @dprc_token: Parent container token; '0' for default container ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @object_id: The object id; it must be a valid id within the container that ++ * created this object; ++ * ++ * The function accepts the authentication token of the parent container that ++ * created the object (not the one that currently owns the object). The object ++ * is searched within parent using the provided 'object_id'. ++ * All tokens to the object must be closed before calling destroy. ++ * ++ * Return: '0' on Success; error code otherwise. ++ */ ++int dpmac_destroy(struct fsl_mc_io *mc_io, ++ u16 dprc_token, ++ u32 cmd_flags, ++ u32 object_id) ++{ ++ struct dpmac_cmd_destroy *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_DESTROY, ++ cmd_flags, ++ dprc_token); ++ cmd_params = (struct dpmac_cmd_destroy *)cmd.params; ++ cmd_params->dpmac_id = cpu_to_le32(object_id); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpmac_set_irq_enable() - Set overall interrupt state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @irq_index: The interrupt index to configure ++ * @en: Interrupt state - enable = 1, disable = 0 ++ * ++ * Allows GPP software to control when interrupts are generated. ++ * Each interrupt can have up to 32 causes. The enable/disable control's the ++ * overall interrupt state. if the interrupt is disabled no causes will cause ++ * an interrupt. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_set_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 en) ++{ ++ struct dpmac_cmd_set_irq_enable *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_IRQ_ENABLE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpmac_cmd_set_irq_enable *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ cmd_params->enable = en; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpmac_get_irq_enable() - Get overall interrupt state ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @irq_index: The interrupt index to configure ++ * @en: Returned interrupt state - enable = 1, disable = 0 ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_get_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 *en) ++{ ++ struct dpmac_cmd_get_irq_enable *cmd_params; ++ struct dpmac_rsp_get_irq_enable *rsp_params; ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_IRQ_ENABLE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpmac_cmd_get_irq_enable *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpmac_rsp_get_irq_enable *)cmd.params; ++ *en = rsp_params->enabled; ++ ++ return 0; ++} ++ ++/** ++ * dpmac_set_irq_mask() - Set interrupt mask. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @irq_index: The interrupt index to configure ++ * @mask: Event mask to trigger interrupt; ++ * each bit: ++ * 0 = ignore event ++ * 1 = consider event for asserting IRQ ++ * ++ * Every interrupt can have up to 32 causes and the interrupt model supports ++ * masking/unmasking each cause independently ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_set_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 mask) ++{ ++ struct dpmac_cmd_set_irq_mask *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_IRQ_MASK, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpmac_cmd_set_irq_mask *)cmd.params; ++ cmd_params->mask = cpu_to_le32(mask); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpmac_get_irq_mask() - Get interrupt mask. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @irq_index: The interrupt index to configure ++ * @mask: Returned event mask to trigger interrupt ++ * ++ * Every interrupt can have up to 32 causes and the interrupt model supports ++ * masking/unmasking each cause independently ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_get_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *mask) ++{ ++ struct dpmac_cmd_get_irq_mask *cmd_params; ++ struct dpmac_rsp_get_irq_mask *rsp_params; ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_IRQ_MASK, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpmac_cmd_get_irq_mask *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpmac_rsp_get_irq_mask *)cmd.params; ++ *mask = le32_to_cpu(rsp_params->mask); ++ ++ return 0; ++} ++ ++/** ++ * dpmac_get_irq_status() - Get the current status of any pending interrupts. ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @irq_index: The interrupt index to configure ++ * @status: Returned interrupts status - one bit per cause: ++ * 0 = no interrupt pending ++ * 1 = interrupt pending ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_get_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *status) ++{ ++ struct dpmac_cmd_get_irq_status *cmd_params; ++ struct dpmac_rsp_get_irq_status *rsp_params; ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_IRQ_STATUS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpmac_cmd_get_irq_status *)cmd.params; ++ cmd_params->status = cpu_to_le32(*status); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpmac_rsp_get_irq_status *)cmd.params; ++ *status = le32_to_cpu(rsp_params->status); ++ ++ return 0; ++} ++ ++/** ++ * dpmac_clear_irq_status() - Clear a pending interrupt's status ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @irq_index: The interrupt index to configure ++ * @status: Bits to clear (W1C) - one bit per cause: ++ * 0 = don't change ++ * 1 = clear status bit ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_clear_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 status) ++{ ++ struct dpmac_cmd_clear_irq_status *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CLEAR_IRQ_STATUS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpmac_cmd_clear_irq_status *)cmd.params; ++ cmd_params->status = cpu_to_le32(status); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpmac_get_attributes - Retrieve DPMAC attributes. ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @attr: Returned object's attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpmac_attr *attr) ++{ ++ struct dpmac_rsp_get_attributes *rsp_params; ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_ATTR, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dpmac_rsp_get_attributes *)cmd.params; ++ attr->eth_if = rsp_params->eth_if; ++ attr->link_type = rsp_params->link_type; ++ attr->id = le16_to_cpu(rsp_params->id); ++ attr->max_rate = le32_to_cpu(rsp_params->max_rate); ++ ++ return 0; ++} ++ ++/** ++ * dpmac_get_link_cfg() - Get Ethernet link configuration ++ * @mc_io: Pointer to opaque I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @cfg: Returned structure with the link configuration ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_get_link_cfg(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpmac_link_cfg *cfg) ++{ ++ struct dpmac_rsp_get_link_cfg *rsp_params; ++ struct mc_command cmd = { 0 }; ++ int err = 0; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_LINK_CFG, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ rsp_params = (struct dpmac_rsp_get_link_cfg *)cmd.params; ++ cfg->options = le64_to_cpu(rsp_params->options); ++ cfg->rate = le32_to_cpu(rsp_params->rate); ++ ++ return 0; ++} ++ ++/** ++ * dpmac_set_link_state() - Set the Ethernet link status ++ * @mc_io: Pointer to opaque I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @link_state: Link state configuration ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_set_link_state(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpmac_link_state *link_state) ++{ ++ struct dpmac_cmd_set_link_state *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_LINK_STATE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpmac_cmd_set_link_state *)cmd.params; ++ cmd_params->options = cpu_to_le64(link_state->options); ++ cmd_params->rate = cpu_to_le32(link_state->rate); ++ cmd_params->up = dpmac_get_field(link_state->up, STATE); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpmac_get_counter() - Read a specific DPMAC counter ++ * @mc_io: Pointer to opaque I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @type: The requested counter ++ * @counter: Returned counter value ++ * ++ * Return: The requested counter; '0' otherwise. ++ */ ++int dpmac_get_counter(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpmac_counter type, ++ u64 *counter) ++{ ++ struct dpmac_cmd_get_counter *dpmac_cmd; ++ struct dpmac_rsp_get_counter *dpmac_rsp; ++ struct mc_command cmd = { 0 }; ++ int err = 0; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_COUNTER, ++ cmd_flags, ++ token); ++ dpmac_cmd = (struct dpmac_cmd_get_counter *)cmd.params; ++ dpmac_cmd->type = type; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ dpmac_rsp = (struct dpmac_rsp_get_counter *)cmd.params; ++ *counter = le64_to_cpu(dpmac_rsp->counter); ++ ++ return 0; ++} ++ ++/* untested */ ++int dpmac_set_port_mac_addr(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const u8 addr[6]) ++{ ++ struct dpmac_cmd_set_port_mac_addr *dpmac_cmd; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_PORT_MAC_ADDR, ++ cmd_flags, ++ token); ++ dpmac_cmd = (struct dpmac_cmd_set_port_mac_addr *)cmd.params; ++ dpmac_cmd->addr[0] = addr[5]; ++ dpmac_cmd->addr[1] = addr[4]; ++ dpmac_cmd->addr[2] = addr[3]; ++ dpmac_cmd->addr[3] = addr[2]; ++ dpmac_cmd->addr[4] = addr[1]; ++ dpmac_cmd->addr[5] = addr[0]; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpmac_get_api_version() - Get Data Path MAC version ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @major_ver: Major version of data path mac API ++ * @minor_ver: Minor version of data path mac API ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpmac_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver) ++{ ++ struct dpmac_rsp_get_api_version *rsp_params; ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_API_VERSION, ++ cmd_flags, ++ 0); ++ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ rsp_params = (struct dpmac_rsp_get_api_version *)cmd.params; ++ *major_ver = le16_to_cpu(rsp_params->major); ++ *minor_ver = le16_to_cpu(rsp_params->minor); ++ ++ return 0; ++} +diff --git a/drivers/staging/fsl-dpaa2/mac/dpmac.h b/drivers/staging/fsl-dpaa2/mac/dpmac.h +new file mode 100644 +index 00000000..32d4ada2 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/mac/dpmac.h +@@ -0,0 +1,342 @@ ++/* Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef __FSL_DPMAC_H ++#define __FSL_DPMAC_H ++ ++/* Data Path MAC API ++ * Contains initialization APIs and runtime control APIs for DPMAC ++ */ ++ ++struct fsl_mc_io; ++ ++int dpmac_open(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ int dpmac_id, ++ u16 *token); ++ ++int dpmac_close(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token); ++ ++/** ++ * enum dpmac_link_type - DPMAC link type ++ * @DPMAC_LINK_TYPE_NONE: No link ++ * @DPMAC_LINK_TYPE_FIXED: Link is fixed type ++ * @DPMAC_LINK_TYPE_PHY: Link by PHY ID ++ * @DPMAC_LINK_TYPE_BACKPLANE: Backplane link type ++ */ ++enum dpmac_link_type { ++ DPMAC_LINK_TYPE_NONE, ++ DPMAC_LINK_TYPE_FIXED, ++ DPMAC_LINK_TYPE_PHY, ++ DPMAC_LINK_TYPE_BACKPLANE ++}; ++ ++/** ++ * enum dpmac_eth_if - DPMAC Ethrnet interface ++ * @DPMAC_ETH_IF_MII: MII interface ++ * @DPMAC_ETH_IF_RMII: RMII interface ++ * @DPMAC_ETH_IF_SMII: SMII interface ++ * @DPMAC_ETH_IF_GMII: GMII interface ++ * @DPMAC_ETH_IF_RGMII: RGMII interface ++ * @DPMAC_ETH_IF_SGMII: SGMII interface ++ * @DPMAC_ETH_IF_QSGMII: QSGMII interface ++ * @DPMAC_ETH_IF_XAUI: XAUI interface ++ * @DPMAC_ETH_IF_XFI: XFI interface ++ */ ++enum dpmac_eth_if { ++ DPMAC_ETH_IF_MII, ++ DPMAC_ETH_IF_RMII, ++ DPMAC_ETH_IF_SMII, ++ DPMAC_ETH_IF_GMII, ++ DPMAC_ETH_IF_RGMII, ++ DPMAC_ETH_IF_SGMII, ++ DPMAC_ETH_IF_QSGMII, ++ DPMAC_ETH_IF_XAUI, ++ DPMAC_ETH_IF_XFI ++}; ++ ++/** ++ * struct dpmac_cfg - Structure representing DPMAC configuration ++ * @mac_id: Represents the Hardware MAC ID; in case of multiple WRIOP, ++ * the MAC IDs are continuous. ++ * For example: 2 WRIOPs, 16 MACs in each: ++ * MAC IDs for the 1st WRIOP: 1-16, ++ * MAC IDs for the 2nd WRIOP: 17-32. ++ */ ++struct dpmac_cfg { ++ u16 mac_id; ++}; ++ ++int dpmac_create(struct fsl_mc_io *mc_io, ++ u16 dprc_token, ++ u32 cmd_flags, ++ const struct dpmac_cfg *cfg, ++ u32 *obj_id); ++ ++int dpmac_destroy(struct fsl_mc_io *mc_io, ++ u16 dprc_token, ++ u32 cmd_flags, ++ u32 object_id); ++ ++/** ++ * DPMAC IRQ Index and Events ++ */ ++ ++/** ++ * IRQ index ++ */ ++#define DPMAC_IRQ_INDEX 0 ++/** ++ * IRQ event - indicates a change in link state ++ */ ++#define DPMAC_IRQ_EVENT_LINK_CFG_REQ 0x00000001 ++/** ++ * IRQ event - Indicates that the link state changed ++ */ ++#define DPMAC_IRQ_EVENT_LINK_CHANGED 0x00000002 ++ ++int dpmac_set_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 en); ++ ++int dpmac_get_irq_enable(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u8 *en); ++ ++int dpmac_set_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 mask); ++ ++int dpmac_get_irq_mask(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *mask); ++ ++int dpmac_get_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 *status); ++ ++int dpmac_clear_irq_status(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ u8 irq_index, ++ u32 status); ++ ++/** ++ * struct dpmac_attr - Structure representing DPMAC attributes ++ * @id: DPMAC object ID ++ * @max_rate: Maximum supported rate - in Mbps ++ * @eth_if: Ethernet interface ++ * @link_type: link type ++ */ ++struct dpmac_attr { ++ u16 id; ++ u32 max_rate; ++ enum dpmac_eth_if eth_if; ++ enum dpmac_link_type link_type; ++}; ++ ++int dpmac_get_attributes(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpmac_attr *attr); ++ ++/** ++ * DPMAC link configuration/state options ++ */ ++ ++/** ++ * Enable auto-negotiation ++ */ ++#define DPMAC_LINK_OPT_AUTONEG 0x0000000000000001ULL ++/** ++ * Enable half-duplex mode ++ */ ++#define DPMAC_LINK_OPT_HALF_DUPLEX 0x0000000000000002ULL ++/** ++ * Enable pause frames ++ */ ++#define DPMAC_LINK_OPT_PAUSE 0x0000000000000004ULL ++/** ++ * Enable a-symmetric pause frames ++ */ ++#define DPMAC_LINK_OPT_ASYM_PAUSE 0x0000000000000008ULL ++ ++/** ++ * struct dpmac_link_cfg - Structure representing DPMAC link configuration ++ * @rate: Link's rate - in Mbps ++ * @options: Enable/Disable DPMAC link cfg features (bitmap) ++ */ ++struct dpmac_link_cfg { ++ u32 rate; ++ u64 options; ++}; ++ ++int dpmac_get_link_cfg(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpmac_link_cfg *cfg); ++ ++/** ++ * struct dpmac_link_state - DPMAC link configuration request ++ * @rate: Rate in Mbps ++ * @options: Enable/Disable DPMAC link cfg features (bitmap) ++ * @up: Link state ++ */ ++struct dpmac_link_state { ++ u32 rate; ++ u64 options; ++ int up; ++}; ++ ++int dpmac_set_link_state(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ struct dpmac_link_state *link_state); ++ ++/** ++ * enum dpmac_counter - DPMAC counter types ++ * @DPMAC_CNT_ING_FRAME_64: counts 64-bytes frames, good or bad. ++ * @DPMAC_CNT_ING_FRAME_127: counts 65- to 127-bytes frames, good or bad. ++ * @DPMAC_CNT_ING_FRAME_255: counts 128- to 255-bytes frames, good or bad. ++ * @DPMAC_CNT_ING_FRAME_511: counts 256- to 511-bytes frames, good or bad. ++ * @DPMAC_CNT_ING_FRAME_1023: counts 512- to 1023-bytes frames, good or bad. ++ * @DPMAC_CNT_ING_FRAME_1518: counts 1024- to 1518-bytes frames, good or bad. ++ * @DPMAC_CNT_ING_FRAME_1519_MAX: counts 1519-bytes frames and larger ++ * (up to max frame length specified), ++ * good or bad. ++ * @DPMAC_CNT_ING_FRAG: counts frames which are shorter than 64 bytes received ++ * with a wrong CRC ++ * @DPMAC_CNT_ING_JABBER: counts frames longer than the maximum frame length ++ * specified, with a bad frame check sequence. ++ * @DPMAC_CNT_ING_FRAME_DISCARD: counts dropped frames due to internal errors. ++ * Occurs when a receive FIFO overflows. ++ * Includes also frames truncated as a result of ++ * the receive FIFO overflow. ++ * @DPMAC_CNT_ING_ALIGN_ERR: counts frames with an alignment error ++ * (optional used for wrong SFD). ++ * @DPMAC_CNT_EGR_UNDERSIZED: counts frames transmitted that was less than 64 ++ * bytes long with a good CRC. ++ * @DPMAC_CNT_ING_OVERSIZED: counts frames longer than the maximum frame length ++ * specified, with a good frame check sequence. ++ * @DPMAC_CNT_ING_VALID_PAUSE_FRAME: counts valid pause frames (regular and PFC) ++ * @DPMAC_CNT_EGR_VALID_PAUSE_FRAME: counts valid pause frames transmitted ++ * (regular and PFC). ++ * @DPMAC_CNT_ING_BYTE: counts bytes received except preamble for all valid ++ * frames and valid pause frames. ++ * @DPMAC_CNT_ING_MCAST_FRAME: counts received multicast frames. ++ * @DPMAC_CNT_ING_BCAST_FRAME: counts received broadcast frames. ++ * @DPMAC_CNT_ING_ALL_FRAME: counts each good or bad frames received. ++ * @DPMAC_CNT_ING_UCAST_FRAME: counts received unicast frames. ++ * @DPMAC_CNT_ING_ERR_FRAME: counts frames received with an error ++ * (except for undersized/fragment frame). ++ * @DPMAC_CNT_EGR_BYTE: counts bytes transmitted except preamble for all valid ++ * frames and valid pause frames transmitted. ++ * @DPMAC_CNT_EGR_MCAST_FRAME: counts transmitted multicast frames. ++ * @DPMAC_CNT_EGR_BCAST_FRAME: counts transmitted broadcast frames. ++ * @DPMAC_CNT_EGR_UCAST_FRAME: counts transmitted unicast frames. ++ * @DPMAC_CNT_EGR_ERR_FRAME: counts frames transmitted with an error. ++ * @DPMAC_CNT_ING_GOOD_FRAME: counts frames received without error, including ++ * pause frames. ++ * @DPMAC_CNT_ENG_GOOD_FRAME: counts frames transmitted without error, including ++ * pause frames. ++ */ ++enum dpmac_counter { ++ DPMAC_CNT_ING_FRAME_64, ++ DPMAC_CNT_ING_FRAME_127, ++ DPMAC_CNT_ING_FRAME_255, ++ DPMAC_CNT_ING_FRAME_511, ++ DPMAC_CNT_ING_FRAME_1023, ++ DPMAC_CNT_ING_FRAME_1518, ++ DPMAC_CNT_ING_FRAME_1519_MAX, ++ DPMAC_CNT_ING_FRAG, ++ DPMAC_CNT_ING_JABBER, ++ DPMAC_CNT_ING_FRAME_DISCARD, ++ DPMAC_CNT_ING_ALIGN_ERR, ++ DPMAC_CNT_EGR_UNDERSIZED, ++ DPMAC_CNT_ING_OVERSIZED, ++ DPMAC_CNT_ING_VALID_PAUSE_FRAME, ++ DPMAC_CNT_EGR_VALID_PAUSE_FRAME, ++ DPMAC_CNT_ING_BYTE, ++ DPMAC_CNT_ING_MCAST_FRAME, ++ DPMAC_CNT_ING_BCAST_FRAME, ++ DPMAC_CNT_ING_ALL_FRAME, ++ DPMAC_CNT_ING_UCAST_FRAME, ++ DPMAC_CNT_ING_ERR_FRAME, ++ DPMAC_CNT_EGR_BYTE, ++ DPMAC_CNT_EGR_MCAST_FRAME, ++ DPMAC_CNT_EGR_BCAST_FRAME, ++ DPMAC_CNT_EGR_UCAST_FRAME, ++ DPMAC_CNT_EGR_ERR_FRAME, ++ DPMAC_CNT_ING_GOOD_FRAME, ++ DPMAC_CNT_ENG_GOOD_FRAME ++}; ++ ++int dpmac_get_counter(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ enum dpmac_counter type, ++ u64 *counter); ++ ++/** ++ * dpmac_set_port_mac_addr() - Set a MAC address associated with the physical ++ * port. This is not used for filtering, MAC is always in ++ * promiscuous mode, it is passed to DPNIs through DPNI API for ++ * application used. ++ * @mc_io: Pointer to opaque I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPMAC object ++ * @addr: MAC address to set ++ * ++ * Return: The requested counter; '0' otherwise. ++ */ ++int dpmac_set_port_mac_addr(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 token, ++ const u8 addr[6]); ++ ++int dpmac_get_api_version(struct fsl_mc_io *mc_io, ++ u32 cmd_flags, ++ u16 *major_ver, ++ u16 *minor_ver); ++ ++#endif /* __FSL_DPMAC_H */ +diff --git a/drivers/staging/fsl-dpaa2/mac/mac.c b/drivers/staging/fsl-dpaa2/mac/mac.c +new file mode 100644 +index 00000000..30169639 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/mac/mac.c +@@ -0,0 +1,666 @@ ++/* Copyright 2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "../../fsl-mc/include/mc.h" ++#include "../../fsl-mc/include/mc-sys.h" ++ ++#include "dpmac.h" ++#include "dpmac-cmd.h" ++ ++struct dpaa2_mac_priv { ++ struct net_device *netdev; ++ struct fsl_mc_device *mc_dev; ++ struct dpmac_attr attr; ++ struct dpmac_link_state old_state; ++}; ++ ++/* TODO: fix the 10G modes, mapping can't be right: ++ * XGMII is paralel ++ * XAUI is serial, using 8b/10b encoding ++ * XFI is also serial but using 64b/66b encoding ++ * they can't all map to XGMII... ++ * ++ * This must be kept in sync with enum dpmac_eth_if. ++ */ ++static phy_interface_t dpaa2_mac_iface_mode[] = { ++ PHY_INTERFACE_MODE_MII, /* DPMAC_ETH_IF_MII */ ++ PHY_INTERFACE_MODE_RMII, /* DPMAC_ETH_IF_RMII */ ++ PHY_INTERFACE_MODE_SMII, /* DPMAC_ETH_IF_SMII */ ++ PHY_INTERFACE_MODE_GMII, /* DPMAC_ETH_IF_GMII */ ++ PHY_INTERFACE_MODE_RGMII, /* DPMAC_ETH_IF_RGMII */ ++ PHY_INTERFACE_MODE_SGMII, /* DPMAC_ETH_IF_SGMII */ ++ PHY_INTERFACE_MODE_QSGMII, /* DPMAC_ETH_IF_QSGMII */ ++ PHY_INTERFACE_MODE_XGMII, /* DPMAC_ETH_IF_XAUI */ ++ PHY_INTERFACE_MODE_XGMII, /* DPMAC_ETH_IF_XFI */ ++}; ++ ++static void dpaa2_mac_link_changed(struct net_device *netdev) ++{ ++ struct phy_device *phydev; ++ struct dpmac_link_state state = { 0 }; ++ struct dpaa2_mac_priv *priv = netdev_priv(netdev); ++ int err; ++ ++ /* the PHY just notified us of link state change */ ++ phydev = netdev->phydev; ++ ++ state.up = !!phydev->link; ++ if (phydev->link) { ++ state.rate = phydev->speed; ++ ++ if (!phydev->duplex) ++ state.options |= DPMAC_LINK_OPT_HALF_DUPLEX; ++ if (phydev->autoneg) ++ state.options |= DPMAC_LINK_OPT_AUTONEG; ++ ++ netif_carrier_on(netdev); ++ } else { ++ netif_carrier_off(netdev); ++ } ++ ++ if (priv->old_state.up != state.up || ++ priv->old_state.rate != state.rate || ++ priv->old_state.options != state.options) { ++ priv->old_state = state; ++ phy_print_status(phydev); ++ } ++ ++ /* We must interrogate MC at all times, because we don't know ++ * when and whether a potential DPNI may have read the link state. ++ */ ++ err = dpmac_set_link_state(priv->mc_dev->mc_io, 0, ++ priv->mc_dev->mc_handle, &state); ++ if (unlikely(err)) ++ dev_err(&priv->mc_dev->dev, "dpmac_set_link_state: %d\n", err); ++} ++ ++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS ++static netdev_tx_t dpaa2_mac_drop_frame(struct sk_buff *skb, ++ struct net_device *dev) ++{ ++ /* we don't support I/O for now, drop the frame */ ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; ++} ++ ++static int dpaa2_mac_open(struct net_device *netdev) ++{ ++ /* start PHY state machine */ ++ phy_start(netdev->phydev); ++ ++ return 0; ++} ++ ++static int dpaa2_mac_stop(struct net_device *netdev) ++{ ++ if (!netdev->phydev) ++ goto done; ++ ++ /* stop PHY state machine */ ++ phy_stop(netdev->phydev); ++ ++ /* signal link down to firmware */ ++ netdev->phydev->link = 0; ++ dpaa2_mac_link_changed(netdev); ++ ++done: ++ return 0; ++} ++ ++static int dpaa2_mac_get_settings(struct net_device *netdev, ++ struct ethtool_cmd *cmd) ++{ ++ return phy_ethtool_gset(netdev->phydev, cmd); ++} ++ ++static int dpaa2_mac_set_settings(struct net_device *netdev, ++ struct ethtool_cmd *cmd) ++{ ++ return phy_ethtool_sset(netdev->phydev, cmd); ++} ++ ++static void dpaa2_mac_get_stats(struct net_device *netdev, ++ struct rtnl_link_stats64 *storage) ++{ ++ struct dpaa2_mac_priv *priv = netdev_priv(netdev); ++ u64 tmp; ++ int err; ++ ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_EGR_MCAST_FRAME, ++ &storage->tx_packets); ++ if (err) ++ goto error; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_EGR_BCAST_FRAME, &tmp); ++ if (err) ++ goto error; ++ storage->tx_packets += tmp; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_EGR_UCAST_FRAME, &tmp); ++ if (err) ++ goto error; ++ storage->tx_packets += tmp; ++ ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_EGR_UNDERSIZED, &storage->tx_dropped); ++ if (err) ++ goto error; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_EGR_BYTE, &storage->tx_bytes); ++ if (err) ++ goto error; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_EGR_ERR_FRAME, &storage->tx_errors); ++ if (err) ++ goto error; ++ ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_ING_ALL_FRAME, &storage->rx_packets); ++ if (err) ++ goto error; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_ING_MCAST_FRAME, &storage->multicast); ++ if (err) ++ goto error; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_ING_FRAME_DISCARD, ++ &storage->rx_dropped); ++ if (err) ++ goto error; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_ING_ALIGN_ERR, &storage->rx_errors); ++ if (err) ++ goto error; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_ING_OVERSIZED, &tmp); ++ if (err) ++ goto error; ++ storage->rx_errors += tmp; ++ err = dpmac_get_counter(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle, ++ DPMAC_CNT_ING_BYTE, &storage->rx_bytes); ++ if (err) ++ goto error; ++ ++ return; ++error: ++ netdev_err(netdev, "dpmac_get_counter err %d\n", err); ++} ++ ++static struct { ++ enum dpmac_counter id; ++ char name[ETH_GSTRING_LEN]; ++} dpaa2_mac_counters[] = { ++ {DPMAC_CNT_ING_ALL_FRAME, "rx all frames"}, ++ {DPMAC_CNT_ING_GOOD_FRAME, "rx frames ok"}, ++ {DPMAC_CNT_ING_ERR_FRAME, "rx frame errors"}, ++ {DPMAC_CNT_ING_FRAME_DISCARD, "rx frame discards"}, ++ {DPMAC_CNT_ING_UCAST_FRAME, "rx u-cast"}, ++ {DPMAC_CNT_ING_BCAST_FRAME, "rx b-cast"}, ++ {DPMAC_CNT_ING_MCAST_FRAME, "rx m-cast"}, ++ {DPMAC_CNT_ING_FRAME_64, "rx 64 bytes"}, ++ {DPMAC_CNT_ING_FRAME_127, "rx 65-127 bytes"}, ++ {DPMAC_CNT_ING_FRAME_255, "rx 128-255 bytes"}, ++ {DPMAC_CNT_ING_FRAME_511, "rx 256-511 bytes"}, ++ {DPMAC_CNT_ING_FRAME_1023, "rx 512-1023 bytes"}, ++ {DPMAC_CNT_ING_FRAME_1518, "rx 1024-1518 bytes"}, ++ {DPMAC_CNT_ING_FRAME_1519_MAX, "rx 1519-max bytes"}, ++ {DPMAC_CNT_ING_FRAG, "rx frags"}, ++ {DPMAC_CNT_ING_JABBER, "rx jabber"}, ++ {DPMAC_CNT_ING_ALIGN_ERR, "rx align errors"}, ++ {DPMAC_CNT_ING_OVERSIZED, "rx oversized"}, ++ {DPMAC_CNT_ING_VALID_PAUSE_FRAME, "rx pause"}, ++ {DPMAC_CNT_ING_BYTE, "rx bytes"}, ++ {DPMAC_CNT_ENG_GOOD_FRAME, "tx frames ok"}, ++ {DPMAC_CNT_EGR_UCAST_FRAME, "tx u-cast"}, ++ {DPMAC_CNT_EGR_MCAST_FRAME, "tx m-cast"}, ++ {DPMAC_CNT_EGR_BCAST_FRAME, "tx b-cast"}, ++ {DPMAC_CNT_EGR_ERR_FRAME, "tx frame errors"}, ++ {DPMAC_CNT_EGR_UNDERSIZED, "tx undersized"}, ++ {DPMAC_CNT_EGR_VALID_PAUSE_FRAME, "tx b-pause"}, ++ {DPMAC_CNT_EGR_BYTE, "tx bytes"}, ++ ++}; ++ ++static void dpaa2_mac_get_strings(struct net_device *netdev, ++ u32 stringset, u8 *data) ++{ ++ int i; ++ ++ switch (stringset) { ++ case ETH_SS_STATS: ++ for (i = 0; i < ARRAY_SIZE(dpaa2_mac_counters); i++) ++ memcpy(data + i * ETH_GSTRING_LEN, ++ dpaa2_mac_counters[i].name, ++ ETH_GSTRING_LEN); ++ break; ++ } ++} ++ ++static void dpaa2_mac_get_ethtool_stats(struct net_device *netdev, ++ struct ethtool_stats *stats, ++ u64 *data) ++{ ++ struct dpaa2_mac_priv *priv = netdev_priv(netdev); ++ int i; ++ int err; ++ ++ for (i = 0; i < ARRAY_SIZE(dpaa2_mac_counters); i++) { ++ err = dpmac_get_counter(priv->mc_dev->mc_io, ++ 0, ++ priv->mc_dev->mc_handle, ++ dpaa2_mac_counters[i].id, &data[i]); ++ if (err) ++ netdev_err(netdev, "dpmac_get_counter[%s] err %d\n", ++ dpaa2_mac_counters[i].name, err); ++ } ++} ++ ++static int dpaa2_mac_get_sset_count(struct net_device *dev, int sset) ++{ ++ switch (sset) { ++ case ETH_SS_STATS: ++ return ARRAY_SIZE(dpaa2_mac_counters); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static const struct net_device_ops dpaa2_mac_ndo_ops = { ++ .ndo_start_xmit = &dpaa2_mac_drop_frame, ++ .ndo_open = &dpaa2_mac_open, ++ .ndo_stop = &dpaa2_mac_stop, ++ .ndo_get_stats64 = &dpaa2_mac_get_stats, ++}; ++ ++static const struct ethtool_ops dpaa2_mac_ethtool_ops = { ++ .get_settings = &dpaa2_mac_get_settings, ++ .set_settings = &dpaa2_mac_set_settings, ++ .get_strings = &dpaa2_mac_get_strings, ++ .get_ethtool_stats = &dpaa2_mac_get_ethtool_stats, ++ .get_sset_count = &dpaa2_mac_get_sset_count, ++}; ++#endif /* CONFIG_FSL_DPAA2_MAC_NETDEVS */ ++ ++static void configure_link(struct dpaa2_mac_priv *priv, ++ struct dpmac_link_cfg *cfg) ++{ ++ struct phy_device *phydev = priv->netdev->phydev; ++ ++ if (unlikely(!phydev)) ++ return; ++ ++ phydev->speed = cfg->rate; ++ phydev->duplex = !!(cfg->options & DPMAC_LINK_OPT_HALF_DUPLEX); ++ ++ if (cfg->options & DPMAC_LINK_OPT_AUTONEG) { ++ phydev->autoneg = 1; ++ phydev->advertising |= ADVERTISED_Autoneg; ++ } else { ++ phydev->autoneg = 0; ++ phydev->advertising &= ~ADVERTISED_Autoneg; ++ } ++ ++ phy_start_aneg(phydev); ++} ++ ++static irqreturn_t dpaa2_mac_irq_handler(int irq_num, void *arg) ++{ ++ struct device *dev = (struct device *)arg; ++ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); ++ struct dpaa2_mac_priv *priv = dev_get_drvdata(dev); ++ struct dpmac_link_cfg link_cfg; ++ u32 status; ++ int err; ++ ++ err = dpmac_get_irq_status(mc_dev->mc_io, 0, mc_dev->mc_handle, ++ DPMAC_IRQ_INDEX, &status); ++ if (unlikely(err || !status)) ++ return IRQ_NONE; ++ ++ /* DPNI-initiated link configuration; 'ifconfig up' also calls this */ ++ if (status & DPMAC_IRQ_EVENT_LINK_CFG_REQ) { ++ err = dpmac_get_link_cfg(mc_dev->mc_io, 0, mc_dev->mc_handle, ++ &link_cfg); ++ if (unlikely(err)) ++ goto out; ++ ++ configure_link(priv, &link_cfg); ++ } ++ ++out: ++ dpmac_clear_irq_status(mc_dev->mc_io, 0, mc_dev->mc_handle, ++ DPMAC_IRQ_INDEX, status); ++ ++ return IRQ_HANDLED; ++} ++ ++static int setup_irqs(struct fsl_mc_device *mc_dev) ++{ ++ int err = 0; ++ struct fsl_mc_device_irq *irq; ++ ++ err = fsl_mc_allocate_irqs(mc_dev); ++ if (err) { ++ dev_err(&mc_dev->dev, "fsl_mc_allocate_irqs err %d\n", err); ++ return err; ++ } ++ ++ irq = mc_dev->irqs[0]; ++ err = devm_request_threaded_irq(&mc_dev->dev, irq->msi_desc->irq, ++ NULL, &dpaa2_mac_irq_handler, ++ IRQF_NO_SUSPEND | IRQF_ONESHOT, ++ dev_name(&mc_dev->dev), &mc_dev->dev); ++ if (err) { ++ dev_err(&mc_dev->dev, "devm_request_threaded_irq err %d\n", ++ err); ++ goto free_irq; ++ } ++ ++ err = dpmac_set_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle, ++ DPMAC_IRQ_INDEX, DPMAC_IRQ_EVENT_LINK_CFG_REQ); ++ if (err) { ++ dev_err(&mc_dev->dev, "dpmac_set_irq_mask err %d\n", err); ++ goto free_irq; ++ } ++ err = dpmac_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle, ++ DPMAC_IRQ_INDEX, 1); ++ if (err) { ++ dev_err(&mc_dev->dev, "dpmac_set_irq_enable err %d\n", err); ++ goto free_irq; ++ } ++ ++ return 0; ++ ++free_irq: ++ fsl_mc_free_irqs(mc_dev); ++ ++ return err; ++} ++ ++static void teardown_irqs(struct fsl_mc_device *mc_dev) ++{ ++ int err; ++ ++ err = dpmac_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle, ++ DPMAC_IRQ_INDEX, 0); ++ if (err) ++ dev_err(&mc_dev->dev, "dpmac_set_irq_enable err %d\n", err); ++ ++ fsl_mc_free_irqs(mc_dev); ++} ++ ++static struct device_node *find_dpmac_node(struct device *dev, u16 dpmac_id) ++{ ++ struct device_node *dpmacs, *dpmac = NULL; ++ struct device_node *mc_node = dev->of_node; ++ u32 id; ++ int err; ++ ++ dpmacs = of_find_node_by_name(mc_node, "dpmacs"); ++ if (!dpmacs) { ++ dev_err(dev, "No dpmacs subnode in device-tree\n"); ++ return NULL; ++ } ++ ++ while ((dpmac = of_get_next_child(dpmacs, dpmac))) { ++ err = of_property_read_u32(dpmac, "reg", &id); ++ if (err) ++ continue; ++ if (id == dpmac_id) ++ return dpmac; ++ } ++ ++ return NULL; ++} ++ ++static int dpaa2_mac_probe(struct fsl_mc_device *mc_dev) ++{ ++ struct device *dev; ++ struct dpaa2_mac_priv *priv = NULL; ++ struct device_node *phy_node, *dpmac_node; ++ struct net_device *netdev; ++ phy_interface_t if_mode; ++ int err = 0; ++ ++ dev = &mc_dev->dev; ++ ++ /* prepare a net_dev structure to make the phy lib API happy */ ++ netdev = alloc_etherdev(sizeof(*priv)); ++ if (!netdev) { ++ dev_err(dev, "alloc_etherdev error\n"); ++ err = -ENOMEM; ++ goto err_exit; ++ } ++ priv = netdev_priv(netdev); ++ priv->mc_dev = mc_dev; ++ priv->netdev = netdev; ++ ++ SET_NETDEV_DEV(netdev, dev); ++ ++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS ++ snprintf(netdev->name, IFNAMSIZ, "mac%d", mc_dev->obj_desc.id); ++#endif ++ ++ dev_set_drvdata(dev, priv); ++ ++ err = fsl_mc_portal_allocate(mc_dev, 0, &mc_dev->mc_io); ++ if (err || !mc_dev->mc_io) { ++ dev_err(dev, "fsl_mc_portal_allocate error: %d\n", err); ++ err = -ENODEV; ++ goto err_free_netdev; ++ } ++ ++ err = dpmac_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id, ++ &mc_dev->mc_handle); ++ if (err || !mc_dev->mc_handle) { ++ dev_err(dev, "dpmac_open error: %d\n", err); ++ err = -ENODEV; ++ goto err_free_mcp; ++ } ++ ++ err = dpmac_get_attributes(mc_dev->mc_io, 0, ++ mc_dev->mc_handle, &priv->attr); ++ if (err) { ++ dev_err(dev, "dpmac_get_attributes err %d\n", err); ++ err = -EINVAL; ++ goto err_close; ++ } ++ ++ /* Look up the DPMAC node in the device-tree. */ ++ dpmac_node = find_dpmac_node(dev, priv->attr.id); ++ if (!dpmac_node) { ++ dev_err(dev, "No dpmac@%d subnode found.\n", priv->attr.id); ++ err = -ENODEV; ++ goto err_close; ++ } ++ ++ err = setup_irqs(mc_dev); ++ if (err) { ++ err = -EFAULT; ++ goto err_close; ++ } ++ ++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS ++ /* OPTIONAL, register netdev just to make it visible to the user */ ++ netdev->netdev_ops = &dpaa2_mac_ndo_ops; ++ netdev->ethtool_ops = &dpaa2_mac_ethtool_ops; ++ ++ /* phy starts up enabled so netdev should be up too */ ++ netdev->flags |= IFF_UP; ++ ++ err = register_netdev(priv->netdev); ++ if (err < 0) { ++ dev_err(dev, "register_netdev error %d\n", err); ++ err = -ENODEV; ++ goto err_free_irq; ++ } ++#endif /* CONFIG_FSL_DPAA2_MAC_NETDEVS */ ++ ++ /* probe the PHY as a fixed-link if the link type declared in DPC ++ * explicitly mandates this ++ */ ++ ++ phy_node = of_parse_phandle(dpmac_node, "phy-handle", 0); ++ if (!phy_node) { ++ goto probe_fixed_link; ++ } ++ ++ if (priv->attr.eth_if < ARRAY_SIZE(dpaa2_mac_iface_mode)) { ++ if_mode = dpaa2_mac_iface_mode[priv->attr.eth_if]; ++ dev_dbg(dev, "\tusing if mode %s for eth_if %d\n", ++ phy_modes(if_mode), priv->attr.eth_if); ++ } else { ++ dev_warn(dev, "Unexpected interface mode %d, will probe as fixed link\n", ++ priv->attr.eth_if); ++ goto probe_fixed_link; ++ } ++ ++ /* try to connect to the PHY */ ++ netdev->phydev = of_phy_connect(netdev, phy_node, ++ &dpaa2_mac_link_changed, 0, if_mode); ++ if (!netdev->phydev) { ++ /* No need for dev_err(); the kernel's loud enough as it is. */ ++ dev_dbg(dev, "Can't of_phy_connect() now.\n"); ++ /* We might be waiting for the MDIO MUX to probe, so defer ++ * our own probing. ++ */ ++ err = -EPROBE_DEFER; ++ goto err_defer; ++ } ++ dev_info(dev, "Connected to %s PHY.\n", phy_modes(if_mode)); ++ ++probe_fixed_link: ++ if (!netdev->phydev) { ++ struct fixed_phy_status status = { ++ .link = 1, ++ /* fixed-phys don't support 10Gbps speed for now */ ++ .speed = 1000, ++ .duplex = 1, ++ }; ++ ++ /* try to register a fixed link phy */ ++ netdev->phydev = fixed_phy_register(PHY_POLL, &status, -1, ++ NULL); ++ if (!netdev->phydev || IS_ERR(netdev->phydev)) { ++ dev_err(dev, "error trying to register fixed PHY\n"); ++ /* So we don't crash unregister_netdev() later on */ ++ netdev->phydev = NULL; ++ err = -EFAULT; ++ goto err_no_phy; ++ } ++ dev_info(dev, "Registered fixed PHY.\n"); ++ } ++ ++ /* start PHY state machine */ ++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS ++ dpaa2_mac_open(netdev); ++#else /* CONFIG_FSL_DPAA2_MAC_NETDEVS */ ++ phy_start(netdev->phydev); ++#endif /* CONFIG_FSL_DPAA2_MAC_NETDEVS */ ++ return 0; ++ ++err_defer: ++err_no_phy: ++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS ++ unregister_netdev(netdev); ++err_free_irq: ++#endif ++ teardown_irqs(mc_dev); ++err_close: ++ dpmac_close(mc_dev->mc_io, 0, mc_dev->mc_handle); ++err_free_mcp: ++ fsl_mc_portal_free(mc_dev->mc_io); ++err_free_netdev: ++ free_netdev(netdev); ++err_exit: ++ return err; ++} ++ ++static int dpaa2_mac_remove(struct fsl_mc_device *mc_dev) ++{ ++ struct device *dev = &mc_dev->dev; ++ struct dpaa2_mac_priv *priv = dev_get_drvdata(dev); ++ ++#ifdef CONFIG_FSL_DPAA2_MAC_NETDEVS ++ unregister_netdev(priv->netdev); ++#endif ++ teardown_irqs(priv->mc_dev); ++ dpmac_close(priv->mc_dev->mc_io, 0, priv->mc_dev->mc_handle); ++ fsl_mc_portal_free(priv->mc_dev->mc_io); ++ free_netdev(priv->netdev); ++ ++ dev_set_drvdata(dev, NULL); ++ kfree(priv); ++ ++ return 0; ++} ++ ++static const struct fsl_mc_device_id dpaa2_mac_match_id_table[] = { ++ { ++ .vendor = FSL_MC_VENDOR_FREESCALE, ++ .obj_type = "dpmac", ++ }, ++ { .vendor = 0x0 } ++}; ++MODULE_DEVICE_TABLE(fslmc, dpaa2_mac_match_id_table); ++ ++static struct fsl_mc_driver dpaa2_mac_drv = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = dpaa2_mac_probe, ++ .remove = dpaa2_mac_remove, ++ .match_id_table = dpaa2_mac_match_id_table, ++}; ++ ++module_fsl_mc_driver(dpaa2_mac_drv); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("DPAA2 PHY proxy interface driver"); +diff --git a/drivers/staging/fsl-dpaa2/rtc/Makefile b/drivers/staging/fsl-dpaa2/rtc/Makefile +new file mode 100644 +index 00000000..541a7acd +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/rtc/Makefile +@@ -0,0 +1,10 @@ ++ ++obj-$(CONFIG_PTP_1588_CLOCK_DPAA2) += dpaa2-rtc.o ++ ++dpaa2-rtc-objs := rtc.o dprtc.o ++ ++all: ++ make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules ++ ++clean: ++ make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean +diff --git a/drivers/staging/fsl-dpaa2/rtc/dprtc-cmd.h b/drivers/staging/fsl-dpaa2/rtc/dprtc-cmd.h +new file mode 100644 +index 00000000..618c7e54 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/rtc/dprtc-cmd.h +@@ -0,0 +1,160 @@ ++/* Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef _FSL_DPRTC_CMD_H ++#define _FSL_DPRTC_CMD_H ++ ++/* DPRTC Version */ ++#define DPRTC_VER_MAJOR 2 ++#define DPRTC_VER_MINOR 0 ++ ++/* Command versioning */ ++#define DPRTC_CMD_BASE_VERSION 1 ++#define DPRTC_CMD_ID_OFFSET 4 ++ ++#define DPRTC_CMD(id) (((id) << DPRTC_CMD_ID_OFFSET) | DPRTC_CMD_BASE_VERSION) ++ ++/* Command IDs */ ++#define DPRTC_CMDID_CLOSE DPRTC_CMD(0x800) ++#define DPRTC_CMDID_OPEN DPRTC_CMD(0x810) ++#define DPRTC_CMDID_CREATE DPRTC_CMD(0x910) ++#define DPRTC_CMDID_DESTROY DPRTC_CMD(0x990) ++#define DPRTC_CMDID_GET_API_VERSION DPRTC_CMD(0xa10) ++ ++#define DPRTC_CMDID_ENABLE DPRTC_CMD(0x002) ++#define DPRTC_CMDID_DISABLE DPRTC_CMD(0x003) ++#define DPRTC_CMDID_GET_ATTR DPRTC_CMD(0x004) ++#define DPRTC_CMDID_RESET DPRTC_CMD(0x005) ++#define DPRTC_CMDID_IS_ENABLED DPRTC_CMD(0x006) ++ ++#define DPRTC_CMDID_SET_IRQ_ENABLE DPRTC_CMD(0x012) ++#define DPRTC_CMDID_GET_IRQ_ENABLE DPRTC_CMD(0x013) ++#define DPRTC_CMDID_SET_IRQ_MASK DPRTC_CMD(0x014) ++#define DPRTC_CMDID_GET_IRQ_MASK DPRTC_CMD(0x015) ++#define DPRTC_CMDID_GET_IRQ_STATUS DPRTC_CMD(0x016) ++#define DPRTC_CMDID_CLEAR_IRQ_STATUS DPRTC_CMD(0x017) ++ ++#define DPRTC_CMDID_SET_CLOCK_OFFSET DPRTC_CMD(0x1d0) ++#define DPRTC_CMDID_SET_FREQ_COMPENSATION DPRTC_CMD(0x1d1) ++#define DPRTC_CMDID_GET_FREQ_COMPENSATION DPRTC_CMD(0x1d2) ++#define DPRTC_CMDID_GET_TIME DPRTC_CMD(0x1d3) ++#define DPRTC_CMDID_SET_TIME DPRTC_CMD(0x1d4) ++#define DPRTC_CMDID_SET_ALARM DPRTC_CMD(0x1d5) ++#define DPRTC_CMDID_SET_PERIODIC_PULSE DPRTC_CMD(0x1d6) ++#define DPRTC_CMDID_CLEAR_PERIODIC_PULSE DPRTC_CMD(0x1d7) ++#define DPRTC_CMDID_SET_EXT_TRIGGER DPRTC_CMD(0x1d8) ++#define DPRTC_CMDID_CLEAR_EXT_TRIGGER DPRTC_CMD(0x1d9) ++#define DPRTC_CMDID_GET_EXT_TRIGGER_TIMESTAMP DPRTC_CMD(0x1dA) ++ ++/* Macros for accessing command fields smaller than 1byte */ ++#define DPRTC_MASK(field) \ ++ GENMASK(DPRTC_##field##_SHIFT + DPRTC_##field##_SIZE - 1, \ ++ DPRTC_##field##_SHIFT) ++#define dprtc_get_field(var, field) \ ++ (((var) & DPRTC_MASK(field)) >> DPRTC_##field##_SHIFT) ++ ++#pragma pack(push, 1) ++struct dprtc_cmd_open { ++ uint32_t dprtc_id; ++}; ++ ++struct dprtc_cmd_destroy { ++ uint32_t object_id; ++}; ++ ++#define DPRTC_ENABLE_SHIFT 0 ++#define DPRTC_ENABLE_SIZE 1 ++ ++struct dprtc_rsp_is_enabled { ++ uint8_t en; ++}; ++ ++struct dprtc_cmd_get_irq { ++ uint32_t pad; ++ uint8_t irq_index; ++}; ++ ++struct dprtc_cmd_set_irq_enable { ++ uint8_t en; ++ uint8_t pad[3]; ++ uint8_t irq_index; ++}; ++ ++struct dprtc_rsp_get_irq_enable { ++ uint8_t en; ++}; ++ ++struct dprtc_cmd_set_irq_mask { ++ uint32_t mask; ++ uint8_t irq_index; ++}; ++ ++struct dprtc_rsp_get_irq_mask { ++ uint32_t mask; ++}; ++ ++struct dprtc_cmd_get_irq_status { ++ uint32_t status; ++ uint8_t irq_index; ++}; ++ ++struct dprtc_rsp_get_irq_status { ++ uint32_t status; ++}; ++ ++struct dprtc_cmd_clear_irq_status { ++ uint32_t status; ++ uint8_t irq_index; ++}; ++ ++struct dprtc_rsp_get_attributes { ++ uint32_t pad; ++ uint32_t id; ++}; ++ ++struct dprtc_cmd_set_clock_offset { ++ uint64_t offset; ++}; ++ ++struct dprtc_get_freq_compensation { ++ uint32_t freq_compensation; ++}; ++ ++struct dprtc_time { ++ uint64_t time; ++}; ++ ++struct dprtc_rsp_get_api_version { ++ uint16_t major; ++ uint16_t minor; ++}; ++#pragma pack(pop) ++#endif /* _FSL_DPRTC_CMD_H */ +diff --git a/drivers/staging/fsl-dpaa2/rtc/dprtc.c b/drivers/staging/fsl-dpaa2/rtc/dprtc.c +new file mode 100644 +index 00000000..399177e4 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/rtc/dprtc.c +@@ -0,0 +1,746 @@ ++/* Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#include "../../fsl-mc/include/mc-sys.h" ++#include "../../fsl-mc/include/mc-cmd.h" ++#include "dprtc.h" ++#include "dprtc-cmd.h" ++ ++/** ++ * dprtc_open() - Open a control session for the specified object. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @dprtc_id: DPRTC unique ID ++ * @token: Returned token; use in subsequent API calls ++ * ++ * This function can be used to open a control session for an ++ * already created object; an object may have been declared in ++ * the DPL or by calling the dprtc_create function. ++ * This function returns a unique authentication token, ++ * associated with the specific object ID and the specific MC ++ * portal; this token must be used in all subsequent commands for ++ * this specific object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprtc_open(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ int dprtc_id, ++ uint16_t *token) ++{ ++ struct dprtc_cmd_open *cmd_params; ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_OPEN, ++ cmd_flags, ++ 0); ++ cmd_params = (struct dprtc_cmd_open *)cmd.params; ++ cmd_params->dprtc_id = cpu_to_le32(dprtc_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *token = mc_cmd_hdr_read_token(&cmd); ++ ++ return err; ++} ++ ++/** ++ * dprtc_close() - Close the control session of the object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRTC object ++ * ++ * After this function is called, no further operations are ++ * allowed on the object without opening a new control session. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprtc_close(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_CLOSE, cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dprtc_create() - Create the DPRTC object. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @dprc_token: Parent container token; '0' for default container ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @cfg: Configuration structure ++ * @obj_id: Returned object id ++ * ++ * Create the DPRTC object, allocate required resources and ++ * perform required initialization. ++ * ++ * The function accepts an authentication token of a parent ++ * container that this object should be assigned to. The token ++ * can be '0' so the object will be assigned to the default container. ++ * The newly created object can be opened with the returned ++ * object id and using the container's associated tokens and MC portals. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprtc_create(struct fsl_mc_io *mc_io, ++ uint16_t dprc_token, ++ uint32_t cmd_flags, ++ const struct dprtc_cfg *cfg, ++ uint32_t *obj_id) ++{ ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ (void)(cfg); /* unused */ ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_CREATE, ++ cmd_flags, ++ dprc_token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *obj_id = mc_cmd_read_object_id(&cmd); ++ ++ return 0; ++} ++ ++/** ++ * dprtc_destroy() - Destroy the DPRTC object and release all its resources. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @dprc_token: Parent container token; '0' for default container ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @object_id: The object id; it must be a valid id within the container that ++ * created this object; ++ * ++ * The function accepts the authentication token of the parent container that ++ * created the object (not the one that currently owns the object). The object ++ * is searched within parent using the provided 'object_id'. ++ * All tokens to the object must be closed before calling destroy. ++ * ++ * Return: '0' on Success; error code otherwise. ++ */ ++int dprtc_destroy(struct fsl_mc_io *mc_io, ++ uint16_t dprc_token, ++ uint32_t cmd_flags, ++ uint32_t object_id) ++{ ++ struct dprtc_cmd_destroy *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_DESTROY, ++ cmd_flags, ++ dprc_token); ++ cmd_params = (struct dprtc_cmd_destroy *)cmd.params; ++ cmd_params->object_id = cpu_to_le32(object_id); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++int dprtc_enable(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_ENABLE, cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++int dprtc_disable(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_DISABLE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++int dprtc_is_enabled(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ int *en) ++{ ++ struct dprtc_rsp_is_enabled *rsp_params; ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_IS_ENABLED, cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dprtc_rsp_is_enabled *)cmd.params; ++ *en = dprtc_get_field(rsp_params->en, ENABLE); ++ ++ return 0; ++} ++ ++int dprtc_reset(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_RESET, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dprtc_set_irq_enable() - Set overall interrupt state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRTC object ++ * @irq_index: The interrupt index to configure ++ * @en: Interrupt state - enable = 1, disable = 0 ++ * ++ * Allows GPP software to control when interrupts are generated. ++ * Each interrupt can have up to 32 causes. The enable/disable control's the ++ * overall interrupt state. if the interrupt is disabled no causes will cause ++ * an interrupt. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprtc_set_irq_enable(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint8_t en) ++{ ++ struct dprtc_cmd_set_irq_enable *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_IRQ_ENABLE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dprtc_cmd_set_irq_enable *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ cmd_params->en = en; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dprtc_get_irq_enable() - Get overall interrupt state ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRTC object ++ * @irq_index: The interrupt index to configure ++ * @en: Returned interrupt state - enable = 1, disable = 0 ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprtc_get_irq_enable(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint8_t *en) ++{ ++ struct dprtc_rsp_get_irq_enable *rsp_params; ++ struct dprtc_cmd_get_irq *cmd_params; ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_IRQ_ENABLE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dprtc_cmd_get_irq *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dprtc_rsp_get_irq_enable *)cmd.params; ++ *en = rsp_params->en; ++ ++ return 0; ++} ++ ++/** ++ * dprtc_set_irq_mask() - Set interrupt mask. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRTC object ++ * @irq_index: The interrupt index to configure ++ * @mask: Event mask to trigger interrupt; ++ * each bit: ++ * 0 = ignore event ++ * 1 = consider event for asserting IRQ ++ * ++ * Every interrupt can have up to 32 causes and the interrupt model supports ++ * masking/unmasking each cause independently ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprtc_set_irq_mask(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint32_t mask) ++{ ++ struct dprtc_cmd_set_irq_mask *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_IRQ_MASK, ++ cmd_flags, ++ token); ++ cmd_params = (struct dprtc_cmd_set_irq_mask *)cmd.params; ++ cmd_params->mask = cpu_to_le32(mask); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dprtc_get_irq_mask() - Get interrupt mask. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRTC object ++ * @irq_index: The interrupt index to configure ++ * @mask: Returned event mask to trigger interrupt ++ * ++ * Every interrupt can have up to 32 causes and the interrupt model supports ++ * masking/unmasking each cause independently ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprtc_get_irq_mask(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint32_t *mask) ++{ ++ struct dprtc_rsp_get_irq_mask *rsp_params; ++ struct dprtc_cmd_get_irq *cmd_params; ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_IRQ_MASK, ++ cmd_flags, ++ token); ++ cmd_params = (struct dprtc_cmd_get_irq *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dprtc_rsp_get_irq_mask *)cmd.params; ++ *mask = le32_to_cpu(rsp_params->mask); ++ ++ return 0; ++} ++ ++/** ++ * dprtc_get_irq_status() - Get the current status of any pending interrupts. ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRTC object ++ * @irq_index: The interrupt index to configure ++ * @status: Returned interrupts status - one bit per cause: ++ * 0 = no interrupt pending ++ * 1 = interrupt pending ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprtc_get_irq_status(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint32_t *status) ++{ ++ struct dprtc_cmd_get_irq_status *cmd_params; ++ struct dprtc_rsp_get_irq_status *rsp_params; ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_IRQ_STATUS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dprtc_cmd_get_irq_status *)cmd.params; ++ cmd_params->status = cpu_to_le32(*status); ++ cmd_params->irq_index = irq_index; ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dprtc_rsp_get_irq_status *)cmd.params; ++ *status = rsp_params->status; ++ ++ return 0; ++} ++ ++/** ++ * dprtc_clear_irq_status() - Clear a pending interrupt's status ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRTC object ++ * @irq_index: The interrupt index to configure ++ * @status: Bits to clear (W1C) - one bit per cause: ++ * 0 = don't change ++ * 1 = clear status bit ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprtc_clear_irq_status(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint32_t status) ++{ ++ struct dprtc_cmd_clear_irq_status *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_CLEAR_IRQ_STATUS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dprtc_cmd_clear_irq_status *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ cmd_params->status = cpu_to_le32(status); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dprtc_get_attributes - Retrieve DPRTC attributes. ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRTC object ++ * @attr: Returned object's attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprtc_get_attributes(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ struct dprtc_attr *attr) ++{ ++ struct dprtc_rsp_get_attributes *rsp_params; ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_ATTR, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dprtc_rsp_get_attributes *)cmd.params; ++ attr->id = le32_to_cpu(rsp_params->id); ++ ++ return 0; ++} ++ ++/** ++ * dprtc_set_clock_offset() - Sets the clock's offset ++ * (usually relative to another clock). ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRTC object ++ * @offset: New clock offset (in nanoseconds). ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprtc_set_clock_offset(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ int64_t offset) ++{ ++ struct dprtc_cmd_set_clock_offset *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_CLOCK_OFFSET, ++ cmd_flags, ++ token); ++ cmd_params = (struct dprtc_cmd_set_clock_offset *)cmd.params; ++ cmd_params->offset = cpu_to_le64(offset); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dprtc_set_freq_compensation() - Sets a new frequency compensation value. ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRTC object ++ * @freq_compensation: The new frequency compensation value to set. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprtc_set_freq_compensation(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint32_t freq_compensation) ++{ ++ struct dprtc_get_freq_compensation *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_FREQ_COMPENSATION, ++ cmd_flags, ++ token); ++ cmd_params = (struct dprtc_get_freq_compensation *)cmd.params; ++ cmd_params->freq_compensation = cpu_to_le32(freq_compensation); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dprtc_get_freq_compensation() - Retrieves the frequency compensation value ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRTC object ++ * @freq_compensation: Frequency compensation value ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprtc_get_freq_compensation(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint32_t *freq_compensation) ++{ ++ struct dprtc_get_freq_compensation *rsp_params; ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_FREQ_COMPENSATION, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dprtc_get_freq_compensation *)cmd.params; ++ *freq_compensation = le32_to_cpu(rsp_params->freq_compensation); ++ ++ return 0; ++} ++ ++/** ++ * dprtc_get_time() - Returns the current RTC time. ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRTC object ++ * @time: Current RTC time. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprtc_get_time(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint64_t *time) ++{ ++ struct dprtc_time *rsp_params; ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_TIME, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ rsp_params = (struct dprtc_time *)cmd.params; ++ *time = le64_to_cpu(rsp_params->time); ++ ++ return 0; ++} ++ ++/** ++ * dprtc_set_time() - Updates current RTC time. ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRTC object ++ * @time: New RTC time. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprtc_set_time(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint64_t time) ++{ ++ struct dprtc_time *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_TIME, ++ cmd_flags, ++ token); ++ cmd_params = (struct dprtc_time *)cmd.params; ++ cmd_params->time = cpu_to_le64(time); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dprtc_set_alarm() - Defines and sets alarm. ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPRTC object ++ * @time: In nanoseconds, the time when the alarm ++ * should go off - must be a multiple of ++ * 1 microsecond ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprtc_set_alarm(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, uint64_t time) ++{ ++ struct dprtc_time *cmd_params; ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_ALARM, ++ cmd_flags, ++ token); ++ cmd_params = (struct dprtc_time *)cmd.params; ++ cmd_params->time = cpu_to_le64(time); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dprtc_get_api_version() - Get Data Path Real Time Counter API version ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @major_ver: Major version of data path real time counter API ++ * @minor_ver: Minor version of data path real time counter API ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dprtc_get_api_version(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t *major_ver, ++ uint16_t *minor_ver) ++{ ++ struct dprtc_rsp_get_api_version *rsp_params; ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_API_VERSION, ++ cmd_flags, ++ 0); ++ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ rsp_params = (struct dprtc_rsp_get_api_version *)cmd.params; ++ *major_ver = le16_to_cpu(rsp_params->major); ++ *minor_ver = le16_to_cpu(rsp_params->minor); ++ ++ return 0; ++} +diff --git a/drivers/staging/fsl-dpaa2/rtc/dprtc.h b/drivers/staging/fsl-dpaa2/rtc/dprtc.h +new file mode 100644 +index 00000000..fc96cac6 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/rtc/dprtc.h +@@ -0,0 +1,172 @@ ++/* Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef __FSL_DPRTC_H ++#define __FSL_DPRTC_H ++ ++/* Data Path Real Time Counter API ++ * Contains initialization APIs and runtime control APIs for RTC ++ */ ++ ++struct fsl_mc_io; ++ ++/** ++ * Number of irq's ++ */ ++#define DPRTC_MAX_IRQ_NUM 1 ++#define DPRTC_IRQ_INDEX 0 ++ ++/** ++ * Interrupt event masks: ++ */ ++ ++/** ++ * Interrupt event mask indicating alarm event had occurred ++ */ ++#define DPRTC_EVENT_ALARM 0x40000000 ++/** ++ * Interrupt event mask indicating periodic pulse event had occurred ++ */ ++#define DPRTC_EVENT_PPS 0x08000000 ++ ++int dprtc_open(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ int dprtc_id, ++ uint16_t *token); ++ ++int dprtc_close(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token); ++ ++/** ++ * struct dprtc_cfg - Structure representing DPRTC configuration ++ * @options: place holder ++ */ ++struct dprtc_cfg { ++ uint32_t options; ++}; ++ ++int dprtc_create(struct fsl_mc_io *mc_io, ++ uint16_t dprc_token, ++ uint32_t cmd_flags, ++ const struct dprtc_cfg *cfg, ++ uint32_t *obj_id); ++ ++int dprtc_destroy(struct fsl_mc_io *mc_io, ++ uint16_t dprc_token, ++ uint32_t cmd_flags, ++ uint32_t object_id); ++ ++int dprtc_set_clock_offset(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ int64_t offset); ++ ++int dprtc_set_freq_compensation(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint32_t freq_compensation); ++ ++int dprtc_get_freq_compensation(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint32_t *freq_compensation); ++ ++int dprtc_get_time(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint64_t *time); ++ ++int dprtc_set_time(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint64_t time); ++ ++int dprtc_set_alarm(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint64_t time); ++ ++int dprtc_set_irq_enable(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint8_t en); ++ ++int dprtc_get_irq_enable(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint8_t *en); ++ ++int dprtc_set_irq_mask(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint32_t mask); ++ ++int dprtc_get_irq_mask(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint32_t *mask); ++ ++int dprtc_get_irq_status(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint32_t *status); ++ ++int dprtc_clear_irq_status(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint32_t status); ++ ++/** ++ * struct dprtc_attr - Structure representing DPRTC attributes ++ * @id: DPRTC object ID ++ */ ++struct dprtc_attr { ++ int id; ++}; ++ ++int dprtc_get_attributes(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ struct dprtc_attr *attr); ++ ++int dprtc_get_api_version(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t *major_ver, ++ uint16_t *minor_ver); ++ ++#endif /* __FSL_DPRTC_H */ +diff --git a/drivers/staging/fsl-dpaa2/rtc/rtc.c b/drivers/staging/fsl-dpaa2/rtc/rtc.c +new file mode 100644 +index 00000000..0afc6538 +--- /dev/null ++++ b/drivers/staging/fsl-dpaa2/rtc/rtc.c +@@ -0,0 +1,243 @@ ++/* Copyright 2013-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include ++#include ++ ++#include "../../fsl-mc/include/mc.h" ++#include "../../fsl-mc/include/mc-sys.h" ++ ++#include "dprtc.h" ++#include "dprtc-cmd.h" ++ ++#define N_EXT_TS 2 ++ ++struct ptp_clock *clock; ++struct fsl_mc_device *rtc_mc_dev; ++u32 freqCompensation; ++ ++/* PTP clock operations */ ++static int ptp_dpaa2_adjfreq(struct ptp_clock_info *ptp, s32 ppb) ++{ ++ u64 adj; ++ u32 diff, tmr_add; ++ int neg_adj = 0; ++ int err = 0; ++ struct fsl_mc_device *mc_dev = rtc_mc_dev; ++ struct device *dev = &mc_dev->dev; ++ ++ if (ppb < 0) { ++ neg_adj = 1; ++ ppb = -ppb; ++ } ++ ++ tmr_add = freqCompensation; ++ adj = tmr_add; ++ adj *= ppb; ++ diff = div_u64(adj, 1000000000ULL); ++ ++ tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff; ++ ++ err = dprtc_set_freq_compensation(mc_dev->mc_io, 0, ++ mc_dev->mc_handle, tmr_add); ++ if (err) ++ dev_err(dev, "dprtc_set_freq_compensation err %d\n", err); ++ return 0; ++} ++ ++static int ptp_dpaa2_adjtime(struct ptp_clock_info *ptp, s64 delta) ++{ ++ s64 now; ++ int err = 0; ++ struct fsl_mc_device *mc_dev = rtc_mc_dev; ++ struct device *dev = &mc_dev->dev; ++ ++ err = dprtc_get_time(mc_dev->mc_io, 0, mc_dev->mc_handle, &now); ++ if (err) { ++ dev_err(dev, "dprtc_get_time err %d\n", err); ++ return 0; ++ } ++ ++ now += delta; ++ ++ err = dprtc_set_time(mc_dev->mc_io, 0, mc_dev->mc_handle, now); ++ if (err) { ++ dev_err(dev, "dprtc_set_time err %d\n", err); ++ return 0; ++ } ++ return 0; ++} ++ ++static int ptp_dpaa2_gettime(struct ptp_clock_info *ptp, struct timespec *ts) ++{ ++ u64 ns; ++ u32 remainder; ++ int err = 0; ++ struct fsl_mc_device *mc_dev = rtc_mc_dev; ++ struct device *dev = &mc_dev->dev; ++ ++ err = dprtc_get_time(mc_dev->mc_io, 0, mc_dev->mc_handle, &ns); ++ if (err) { ++ dev_err(dev, "dprtc_get_time err %d\n", err); ++ return 0; ++ } ++ ++ ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder); ++ ts->tv_nsec = remainder; ++ return 0; ++} ++ ++static int ptp_dpaa2_settime(struct ptp_clock_info *ptp, ++ const struct timespec *ts) ++{ ++ u64 ns; ++ int err = 0; ++ struct fsl_mc_device *mc_dev = rtc_mc_dev; ++ struct device *dev = &mc_dev->dev; ++ ++ ns = ts->tv_sec * 1000000000ULL; ++ ns += ts->tv_nsec; ++ ++ err = dprtc_set_time(mc_dev->mc_io, 0, mc_dev->mc_handle, ns); ++ if (err) ++ dev_err(dev, "dprtc_set_time err %d\n", err); ++ return 0; ++} ++ ++static struct ptp_clock_info ptp_dpaa2_caps = { ++ .owner = THIS_MODULE, ++ .name = "dpaa2 clock", ++ .max_adj = 512000, ++ .n_alarm = 0, ++ .n_ext_ts = N_EXT_TS, ++ .n_per_out = 0, ++ .n_pins = 0, ++ .pps = 1, ++ .adjfreq = ptp_dpaa2_adjfreq, ++ .adjtime = ptp_dpaa2_adjtime, ++ .gettime64 = ptp_dpaa2_gettime, ++ .settime64 = ptp_dpaa2_settime, ++}; ++ ++static int rtc_probe(struct fsl_mc_device *mc_dev) ++{ ++ struct device *dev; ++ int err = 0; ++ int dpaa2_phc_index; ++ u32 tmr_add = 0; ++ ++ if (!mc_dev) ++ return -EFAULT; ++ ++ dev = &mc_dev->dev; ++ ++ err = fsl_mc_portal_allocate(mc_dev, 0, &mc_dev->mc_io); ++ if (unlikely(err)) { ++ dev_err(dev, "fsl_mc_portal_allocate err %d\n", err); ++ goto err_exit; ++ } ++ if (!mc_dev->mc_io) { ++ dev_err(dev, ++ "fsl_mc_portal_allocate returned null handle but no error\n"); ++ err = -EFAULT; ++ goto err_exit; ++ } ++ ++ err = dprtc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id, ++ &mc_dev->mc_handle); ++ if (err) { ++ dev_err(dev, "dprtc_open err %d\n", err); ++ goto err_free_mcp; ++ } ++ if (!mc_dev->mc_handle) { ++ dev_err(dev, "dprtc_open returned null handle but no error\n"); ++ err = -EFAULT; ++ goto err_free_mcp; ++ } ++ ++ rtc_mc_dev = mc_dev; ++ ++ err = dprtc_get_freq_compensation(mc_dev->mc_io, 0, ++ mc_dev->mc_handle, &tmr_add); ++ if (err) { ++ dev_err(dev, "dprtc_get_freq_compensation err %d\n", err); ++ goto err_close; ++ } ++ freqCompensation = tmr_add; ++ ++ clock = ptp_clock_register(&ptp_dpaa2_caps, dev); ++ if (IS_ERR(clock)) { ++ err = PTR_ERR(clock); ++ goto err_close; ++ } ++ dpaa2_phc_index = ptp_clock_index(clock); ++ ++ return 0; ++err_close: ++ dprtc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); ++err_free_mcp: ++ fsl_mc_portal_free(mc_dev->mc_io); ++err_exit: ++ return err; ++} ++ ++static int rtc_remove(struct fsl_mc_device *mc_dev) ++{ ++ ptp_clock_unregister(clock); ++ dprtc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); ++ fsl_mc_portal_free(mc_dev->mc_io); ++ ++ return 0; ++} ++ ++static const struct fsl_mc_device_id rtc_match_id_table[] = { ++ { ++ .vendor = FSL_MC_VENDOR_FREESCALE, ++ .obj_type = "dprtc", ++ }, ++ {} ++}; ++ ++static struct fsl_mc_driver rtc_drv = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = rtc_probe, ++ .remove = rtc_remove, ++ .match_id_table = rtc_match_id_table, ++}; ++ ++module_fsl_mc_driver(rtc_drv); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("DPAA2 RTC (PTP 1588 clock) driver (prototype)"); +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/801-ata-support-layerscape.patch b/target/linux/layerscape/patches-4.9/801-ata-support-layerscape.patch new file mode 100644 index 0000000000..bc7641015c --- /dev/null +++ b/target/linux/layerscape/patches-4.9/801-ata-support-layerscape.patch @@ -0,0 +1,149 @@ +From 505eb62bdb7a4cc25b13491dd5c68d0741c5d6da Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 12:21:13 +0800 +Subject: [PATCH] ata: support layerscape + +This is a integrated patch for layerscape sata support. + +Signed-off-by: Tang Yuantian +Signed-off-by: Yangbo Lu +--- + drivers/ata/ahci_qoriq.c | 63 ++++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 56 insertions(+), 7 deletions(-) + +diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c +index 1eba8dff..2f30a39f 100644 +--- a/drivers/ata/ahci_qoriq.c ++++ b/drivers/ata/ahci_qoriq.c +@@ -1,7 +1,7 @@ + /* + * Freescale QorIQ AHCI SATA platform driver + * +- * Copyright 2015 Freescale, Inc. ++ * Copyright (C) 2015 Freescale Semiconductor, Inc. + * Tang Yuantian + * + * This program is free software; you can redistribute it and/or modify +@@ -46,23 +46,32 @@ + #define LS1021A_AXICC_ADDR 0xC0 + + #define SATA_ECC_DISABLE 0x00020000 ++#define ECC_DIS_ARMV8_CH2 0x80000000 ++#define ECC_DIS_LS1088A 0x40000000 + + enum ahci_qoriq_type { + AHCI_LS1021A, + AHCI_LS1043A, + AHCI_LS2080A, ++ AHCI_LS1046A, ++ AHCI_LS1088A, ++ AHCI_LS2088A, + }; + + struct ahci_qoriq_priv { + struct ccsr_ahci *reg_base; + enum ahci_qoriq_type type; + void __iomem *ecc_addr; ++ bool is_dmacoherent; + }; + + static const struct of_device_id ahci_qoriq_of_match[] = { + { .compatible = "fsl,ls1021a-ahci", .data = (void *)AHCI_LS1021A}, + { .compatible = "fsl,ls1043a-ahci", .data = (void *)AHCI_LS1043A}, + { .compatible = "fsl,ls2080a-ahci", .data = (void *)AHCI_LS2080A}, ++ { .compatible = "fsl,ls1046a-ahci", .data = (void *)AHCI_LS1046A}, ++ { .compatible = "fsl,ls1088a-ahci", .data = (void *)AHCI_LS1088A}, ++ { .compatible = "fsl,ls2088a-ahci", .data = (void *)AHCI_LS2088A}, + {}, + }; + MODULE_DEVICE_TABLE(of, ahci_qoriq_of_match); +@@ -154,6 +163,8 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv) + + switch (qpriv->type) { + case AHCI_LS1021A: ++ if (!qpriv->ecc_addr) ++ return -EINVAL; + writel(SATA_ECC_DISABLE, qpriv->ecc_addr); + writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); + writel(LS1021A_PORT_PHY2, reg_base + PORT_PHY2); +@@ -161,19 +172,56 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv) + writel(LS1021A_PORT_PHY4, reg_base + PORT_PHY4); + writel(LS1021A_PORT_PHY5, reg_base + PORT_PHY5); + writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); +- writel(AHCI_PORT_AXICC_CFG, reg_base + LS1021A_AXICC_ADDR); ++ if (qpriv->is_dmacoherent) ++ writel(AHCI_PORT_AXICC_CFG, ++ reg_base + LS1021A_AXICC_ADDR); + break; + + case AHCI_LS1043A: ++ if (!qpriv->ecc_addr) ++ return -EINVAL; ++ writel(readl(qpriv->ecc_addr) | ECC_DIS_ARMV8_CH2, ++ qpriv->ecc_addr); + writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); + writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); +- writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC); ++ if (qpriv->is_dmacoherent) ++ writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC); + break; + + case AHCI_LS2080A: + writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); + writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); +- writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC); ++ if (qpriv->is_dmacoherent) ++ writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC); ++ break; ++ ++ case AHCI_LS1046A: ++ if (!qpriv->ecc_addr) ++ return -EINVAL; ++ writel(readl(qpriv->ecc_addr) | ECC_DIS_ARMV8_CH2, ++ qpriv->ecc_addr); ++ writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); ++ writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); ++ if (qpriv->is_dmacoherent) ++ writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC); ++ break; ++ ++ case AHCI_LS1088A: ++ if (!qpriv->ecc_addr) ++ return -EINVAL; ++ writel(readl(qpriv->ecc_addr) | ECC_DIS_LS1088A, ++ qpriv->ecc_addr); ++ writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); ++ writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); ++ if (qpriv->is_dmacoherent) ++ writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC); ++ break; ++ ++ case AHCI_LS2088A: ++ writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); ++ writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); ++ if (qpriv->is_dmacoherent) ++ writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC); + break; + } + +@@ -204,13 +252,14 @@ static int ahci_qoriq_probe(struct platform_device *pdev) + + qoriq_priv->type = (enum ahci_qoriq_type)of_id->data; + +- if (qoriq_priv->type == AHCI_LS1021A) { +- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, +- "sata-ecc"); ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, ++ "sata-ecc"); ++ if (res) { + qoriq_priv->ecc_addr = devm_ioremap_resource(dev, res); + if (IS_ERR(qoriq_priv->ecc_addr)) + return PTR_ERR(qoriq_priv->ecc_addr); + } ++ qoriq_priv->is_dmacoherent = of_dma_is_coherent(np); + + rc = ahci_platform_enable_resources(hpriv); + if (rc) +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/802-clk-support-layerscape.patch b/target/linux/layerscape/patches-4.9/802-clk-support-layerscape.patch new file mode 100644 index 0000000000..881e3848b4 --- /dev/null +++ b/target/linux/layerscape/patches-4.9/802-clk-support-layerscape.patch @@ -0,0 +1,312 @@ +From bd3df6d053a28d5aa630524c9087c21def30e764 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 12:09:35 +0800 +Subject: [PATCH] clk: support layerscape + +This is a integrated patch for layerscape clock support. + +Signed-off-by: Yuantian Tang +Signed-off-by: Mingkai Hu +Signed-off-by: Scott Wood +Signed-off-by: Yangbo Lu +--- + drivers/clk/clk-qoriq.c | 170 ++++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 156 insertions(+), 14 deletions(-) + +diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c +index 80ae2a51..0e7de00a 100644 +--- a/drivers/clk/clk-qoriq.c ++++ b/drivers/clk/clk-qoriq.c +@@ -12,6 +12,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -87,7 +88,7 @@ struct clockgen { + struct device_node *node; + void __iomem *regs; + struct clockgen_chipinfo info; /* mutable copy */ +- struct clk *sysclk; ++ struct clk *sysclk, *coreclk; + struct clockgen_pll pll[6]; + struct clk *cmux[NUM_CMUX]; + struct clk *hwaccel[NUM_HWACCEL]; +@@ -266,6 +267,39 @@ static const struct clockgen_muxinfo ls1043a_hwa2 = { + }, + }; + ++static const struct clockgen_muxinfo ls1046a_hwa1 = { ++ { ++ {}, ++ {}, ++ { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, ++ { CLKSEL_VALID, CGA_PLL1, PLL_DIV3 }, ++ { CLKSEL_VALID, CGA_PLL1, PLL_DIV4 }, ++ { CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 }, ++ { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 }, ++ { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 }, ++ }, ++}; ++ ++static const struct clockgen_muxinfo ls1046a_hwa2 = { ++ { ++ {}, ++ { CLKSEL_VALID, CGA_PLL2, PLL_DIV1 }, ++ { CLKSEL_VALID, CGA_PLL2, PLL_DIV2 }, ++ { CLKSEL_VALID, CGA_PLL2, PLL_DIV3 }, ++ {}, ++ {}, ++ { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, ++ }, ++}; ++ ++static const struct clockgen_muxinfo ls1012a_cmux = { ++ { ++ [0] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV1 }, ++ {}, ++ [2] = { CLKSEL_VALID, CGA_PLL1, PLL_DIV2 }, ++ } ++}; ++ + static const struct clockgen_muxinfo t1023_hwa1 = { + { + {}, +@@ -488,6 +522,42 @@ static const struct clockgen_chipinfo chipinfo[] = { + .pll_mask = 0x07, + .flags = CG_PLL_8BIT, + }, ++ { ++ .compat = "fsl,ls1046a-clockgen", ++ .init_periph = t2080_init_periph, ++ .cmux_groups = { ++ &t1040_cmux ++ }, ++ .hwaccel = { ++ &ls1046a_hwa1, &ls1046a_hwa2 ++ }, ++ .cmux_to_group = { ++ 0, -1 ++ }, ++ .pll_mask = 0x07, ++ .flags = CG_PLL_8BIT, ++ }, ++ { ++ .compat = "fsl,ls1088a-clockgen", ++ .cmux_groups = { ++ &clockgen2_cmux_cga12 ++ }, ++ .cmux_to_group = { ++ 0, 0, -1 ++ }, ++ .pll_mask = 0x07, ++ .flags = CG_VER3 | CG_LITTLE_ENDIAN, ++ }, ++ { ++ .compat = "fsl,ls1012a-clockgen", ++ .cmux_groups = { ++ &ls1012a_cmux ++ }, ++ .cmux_to_group = { ++ 0, -1 ++ }, ++ .pll_mask = 0x03, ++ }, + { + .compat = "fsl,ls2080a-clockgen", + .cmux_groups = { +@@ -846,7 +916,12 @@ static void __init create_muxes(struct clockgen *cg) + + static void __init clockgen_init(struct device_node *np); + +-/* Legacy nodes may get probed before the parent clockgen node */ ++/* ++ * Legacy nodes may get probed before the parent clockgen node. ++ * It is assumed that device trees with legacy nodes will not ++ * contain a "clocks" property -- otherwise the input clocks may ++ * not be initialized at this point. ++ */ + static void __init legacy_init_clockgen(struct device_node *np) + { + if (!clockgen.node) +@@ -887,18 +962,13 @@ static struct clk __init + return clk_register_fixed_rate(NULL, name, NULL, 0, rate); + } + +-static struct clk *sysclk_from_parent(const char *name) ++static struct clk __init *input_clock(const char *name, struct clk *clk) + { +- struct clk *clk; +- const char *parent_name; +- +- clk = of_clk_get(clockgen.node, 0); +- if (IS_ERR(clk)) +- return clk; ++ const char *input_name; + + /* Register the input clock under the desired name. */ +- parent_name = __clk_get_name(clk); +- clk = clk_register_fixed_factor(NULL, name, parent_name, ++ input_name = __clk_get_name(clk); ++ clk = clk_register_fixed_factor(NULL, name, input_name, + 0, 1, 1); + if (IS_ERR(clk)) + pr_err("%s: Couldn't register %s: %ld\n", __func__, name, +@@ -907,6 +977,29 @@ static struct clk *sysclk_from_parent(const char *name) + return clk; + } + ++static struct clk __init *input_clock_by_name(const char *name, ++ const char *dtname) ++{ ++ struct clk *clk; ++ ++ clk = of_clk_get_by_name(clockgen.node, dtname); ++ if (IS_ERR(clk)) ++ return clk; ++ ++ return input_clock(name, clk); ++} ++ ++static struct clk __init *input_clock_by_index(const char *name, int idx) ++{ ++ struct clk *clk; ++ ++ clk = of_clk_get(clockgen.node, 0); ++ if (IS_ERR(clk)) ++ return clk; ++ ++ return input_clock(name, clk); ++} ++ + static struct clk * __init create_sysclk(const char *name) + { + struct device_node *sysclk; +@@ -916,7 +1009,11 @@ static struct clk * __init create_sysclk(const char *name) + if (!IS_ERR(clk)) + return clk; + +- clk = sysclk_from_parent(name); ++ clk = input_clock_by_name(name, "sysclk"); ++ if (!IS_ERR(clk)) ++ return clk; ++ ++ clk = input_clock_by_index(name, 0); + if (!IS_ERR(clk)) + return clk; + +@@ -927,7 +1024,27 @@ static struct clk * __init create_sysclk(const char *name) + return clk; + } + +- pr_err("%s: No input clock\n", __func__); ++ pr_err("%s: No input sysclk\n", __func__); ++ return NULL; ++} ++ ++static struct clk * __init create_coreclk(const char *name) ++{ ++ struct clk *clk; ++ ++ clk = input_clock_by_name(name, "coreclk"); ++ if (!IS_ERR(clk)) ++ return clk; ++ ++ /* ++ * This indicates a mix of legacy nodes with the new coreclk ++ * mechanism, which should never happen. If this error occurs, ++ * don't use the wrong input clock just because coreclk isn't ++ * ready yet. ++ */ ++ if (WARN_ON(PTR_ERR(clk) == -EPROBE_DEFER)) ++ return clk; ++ + return NULL; + } + +@@ -950,11 +1067,19 @@ static void __init create_one_pll(struct clockgen *cg, int idx) + u32 __iomem *reg; + u32 mult; + struct clockgen_pll *pll = &cg->pll[idx]; ++ const char *input = "cg-sysclk"; + int i; + + if (!(cg->info.pll_mask & (1 << idx))) + return; + ++ if (cg->coreclk && idx != PLATFORM_PLL) { ++ if (IS_ERR(cg->coreclk)) ++ return; ++ ++ input = "cg-coreclk"; ++ } ++ + if (cg->info.flags & CG_VER3) { + switch (idx) { + case PLATFORM_PLL: +@@ -1000,12 +1125,13 @@ static void __init create_one_pll(struct clockgen *cg, int idx) + + for (i = 0; i < ARRAY_SIZE(pll->div); i++) { + struct clk *clk; ++ int ret; + + snprintf(pll->div[i].name, sizeof(pll->div[i].name), + "cg-pll%d-div%d", idx, i + 1); + + clk = clk_register_fixed_factor(NULL, +- pll->div[i].name, "cg-sysclk", 0, mult, i + 1); ++ pll->div[i].name, input, 0, mult, i + 1); + if (IS_ERR(clk)) { + pr_err("%s: %s: register failed %ld\n", + __func__, pll->div[i].name, PTR_ERR(clk)); +@@ -1013,6 +1139,11 @@ static void __init create_one_pll(struct clockgen *cg, int idx) + } + + pll->div[i].clk = clk; ++ ret = clk_register_clkdev(clk, pll->div[i].name, NULL); ++ if (ret != 0) ++ pr_err("%s: %s: register to lookup table failed %ld\n", ++ __func__, pll->div[i].name, PTR_ERR(clk)); ++ + } + } + +@@ -1142,6 +1273,13 @@ static struct clk *clockgen_clk_get(struct of_phandle_args *clkspec, void *data) + goto bad_args; + clk = pll->div[idx].clk; + break; ++ case 5: ++ if (idx != 0) ++ goto bad_args; ++ clk = cg->coreclk; ++ if (IS_ERR(clk)) ++ clk = NULL; ++ break; + default: + goto bad_args; + } +@@ -1253,6 +1391,7 @@ static void __init clockgen_init(struct device_node *np) + clockgen.info.flags |= CG_CMUX_GE_PLAT; + + clockgen.sysclk = create_sysclk("cg-sysclk"); ++ clockgen.coreclk = create_coreclk("cg-coreclk"); + create_plls(&clockgen); + create_muxes(&clockgen); + +@@ -1273,8 +1412,11 @@ static void __init clockgen_init(struct device_node *np) + + CLK_OF_DECLARE(qoriq_clockgen_1, "fsl,qoriq-clockgen-1.0", clockgen_init); + CLK_OF_DECLARE(qoriq_clockgen_2, "fsl,qoriq-clockgen-2.0", clockgen_init); ++CLK_OF_DECLARE(qoriq_clockgen_ls1012a, "fsl,ls1012a-clockgen", clockgen_init); + CLK_OF_DECLARE(qoriq_clockgen_ls1021a, "fsl,ls1021a-clockgen", clockgen_init); + CLK_OF_DECLARE(qoriq_clockgen_ls1043a, "fsl,ls1043a-clockgen", clockgen_init); ++CLK_OF_DECLARE(qoriq_clockgen_ls1046a, "fsl,ls1046a-clockgen", clockgen_init); ++CLK_OF_DECLARE(qoriq_clockgen_ls1088a, "fsl,ls1088a-clockgen", clockgen_init); + CLK_OF_DECLARE(qoriq_clockgen_ls2080a, "fsl,ls2080a-clockgen", clockgen_init); + + /* Legacy nodes */ +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/803-cpufreq-support-layerscape.patch b/target/linux/layerscape/patches-4.9/803-cpufreq-support-layerscape.patch new file mode 100644 index 0000000000..9ea5c407dd --- /dev/null +++ b/target/linux/layerscape/patches-4.9/803-cpufreq-support-layerscape.patch @@ -0,0 +1,370 @@ +From a9ebdf9fa18fd317a4e97f46e8c5263898094864 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 12:20:10 +0800 +Subject: [PATCH] cpufreq: support layerscape + +This is a integrated patch for layerscape pm support. + +Signed-off-by: Tang Yuantian +Signed-off-by: Yangbo Lu +--- + drivers/cpufreq/Kconfig | 2 +- + drivers/cpufreq/qoriq-cpufreq.c | 176 +++++++++++++++------------------------- + drivers/firmware/psci.c | 12 ++- + 3 files changed, 77 insertions(+), 113 deletions(-) + +diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig +index d8b164a7..bc9264c7 100644 +--- a/drivers/cpufreq/Kconfig ++++ b/drivers/cpufreq/Kconfig +@@ -332,7 +332,7 @@ endif + + config QORIQ_CPUFREQ + tristate "CPU frequency scaling driver for Freescale QorIQ SoCs" +- depends on OF && COMMON_CLK && (PPC_E500MC || ARM) ++ depends on OF && COMMON_CLK && (PPC_E500MC || ARM || ARM64) + depends on !CPU_THERMAL || THERMAL + select CLK_QORIQ + help +diff --git a/drivers/cpufreq/qoriq-cpufreq.c b/drivers/cpufreq/qoriq-cpufreq.c +index 53d8c3fb..e2ea433a 100644 +--- a/drivers/cpufreq/qoriq-cpufreq.c ++++ b/drivers/cpufreq/qoriq-cpufreq.c +@@ -11,6 +11,7 @@ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + + #include ++#include + #include + #include + #include +@@ -22,10 +23,6 @@ + #include + #include + +-#if !defined(CONFIG_ARM) +-#include /* for get_hard_smp_processor_id() in UP configs */ +-#endif +- + /** + * struct cpu_data + * @pclk: the parent clock of cpu +@@ -37,73 +34,51 @@ struct cpu_data { + struct thermal_cooling_device *cdev; + }; + ++/* ++ * Don't use cpufreq on this SoC -- used when the SoC would have otherwise ++ * matched a more generic compatible. ++ */ ++#define SOC_BLACKLIST 1 ++ + /** + * struct soc_data - SoC specific data +- * @freq_mask: mask the disallowed frequencies +- * @flag: unique flags ++ * @flags: SOC_xxx + */ + struct soc_data { +- u32 freq_mask[4]; +- u32 flag; +-}; +- +-#define FREQ_MASK 1 +-/* see hardware specification for the allowed frqeuencies */ +-static const struct soc_data sdata[] = { +- { /* used by p2041 and p3041 */ +- .freq_mask = {0x8, 0x8, 0x2, 0x2}, +- .flag = FREQ_MASK, +- }, +- { /* used by p5020 */ +- .freq_mask = {0x8, 0x2}, +- .flag = FREQ_MASK, +- }, +- { /* used by p4080, p5040 */ +- .freq_mask = {0}, +- .flag = 0, +- }, ++ u32 flags; + }; + +-/* +- * the minimum allowed core frequency, in Hz +- * for chassis v1.0, >= platform frequency +- * for chassis v2.0, >= platform frequency / 2 +- */ +-static u32 min_cpufreq; +-static const u32 *fmask; +- +-#if defined(CONFIG_ARM) +-static int get_cpu_physical_id(int cpu) +-{ +- return topology_core_id(cpu); +-} +-#else +-static int get_cpu_physical_id(int cpu) +-{ +- return get_hard_smp_processor_id(cpu); +-} +-#endif +- + static u32 get_bus_freq(void) + { + struct device_node *soc; + u32 sysfreq; ++ struct clk *pltclk; ++ int ret; + ++ /* get platform freq by searching bus-frequency property */ + soc = of_find_node_by_type(NULL, "soc"); +- if (!soc) +- return 0; +- +- if (of_property_read_u32(soc, "bus-frequency", &sysfreq)) +- sysfreq = 0; ++ if (soc) { ++ ret = of_property_read_u32(soc, "bus-frequency", &sysfreq); ++ of_node_put(soc); ++ if (!ret) ++ return sysfreq; ++ } + +- of_node_put(soc); ++ /* get platform freq by its clock name */ ++ pltclk = clk_get(NULL, "cg-pll0-div1"); ++ if (IS_ERR(pltclk)) { ++ pr_err("%s: can't get bus frequency %ld\n", ++ __func__, PTR_ERR(pltclk)); ++ return PTR_ERR(pltclk); ++ } + +- return sysfreq; ++ return clk_get_rate(pltclk); + } + +-static struct device_node *cpu_to_clk_node(int cpu) ++static struct clk *cpu_to_clk(int cpu) + { +- struct device_node *np, *clk_np; ++ struct device_node *np; ++ struct clk *clk; + + if (!cpu_present(cpu)) + return NULL; +@@ -112,37 +87,28 @@ static struct device_node *cpu_to_clk_node(int cpu) + if (!np) + return NULL; + +- clk_np = of_parse_phandle(np, "clocks", 0); +- if (!clk_np) +- return NULL; +- ++ clk = of_clk_get(np, 0); + of_node_put(np); +- +- return clk_np; ++ return clk; + } + + /* traverse cpu nodes to get cpu mask of sharing clock wire */ + static void set_affected_cpus(struct cpufreq_policy *policy) + { +- struct device_node *np, *clk_np; + struct cpumask *dstp = policy->cpus; ++ struct clk *clk; + int i; + +- np = cpu_to_clk_node(policy->cpu); +- if (!np) +- return; +- + for_each_present_cpu(i) { +- clk_np = cpu_to_clk_node(i); +- if (!clk_np) ++ clk = cpu_to_clk(i); ++ if (IS_ERR(clk)) { ++ pr_err("%s: no clock for cpu %d\n", __func__, i); + continue; ++ } + +- if (clk_np == np) ++ if (clk_is_match(policy->clk, clk)) + cpumask_set_cpu(i, dstp); +- +- of_node_put(clk_np); + } +- of_node_put(np); + } + + /* reduce the duplicated frequencies in frequency table */ +@@ -198,10 +164,11 @@ static void freq_table_sort(struct cpufreq_frequency_table *freq_table, + + static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy) + { +- struct device_node *np, *pnode; ++ struct device_node *np; + int i, count, ret; +- u32 freq, mask; ++ u32 freq; + struct clk *clk; ++ const struct clk_hw *hwclk; + struct cpufreq_frequency_table *table; + struct cpu_data *data; + unsigned int cpu = policy->cpu; +@@ -221,17 +188,13 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy) + goto err_nomem2; + } + +- pnode = of_parse_phandle(np, "clocks", 0); +- if (!pnode) { +- pr_err("%s: could not get clock information\n", __func__); +- goto err_nomem2; +- } ++ hwclk = __clk_get_hw(policy->clk); ++ count = clk_hw_get_num_parents(hwclk); + +- count = of_property_count_strings(pnode, "clock-names"); + data->pclk = kcalloc(count, sizeof(struct clk *), GFP_KERNEL); + if (!data->pclk) { + pr_err("%s: no memory\n", __func__); +- goto err_node; ++ goto err_nomem2; + } + + table = kcalloc(count + 1, sizeof(*table), GFP_KERNEL); +@@ -240,23 +203,11 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy) + goto err_pclk; + } + +- if (fmask) +- mask = fmask[get_cpu_physical_id(cpu)]; +- else +- mask = 0x0; +- + for (i = 0; i < count; i++) { +- clk = of_clk_get(pnode, i); ++ clk = clk_hw_get_parent_by_index(hwclk, i)->clk; + data->pclk[i] = clk; + freq = clk_get_rate(clk); +- /* +- * the clock is valid if its frequency is not masked +- * and large than minimum allowed frequency. +- */ +- if (freq < min_cpufreq || (mask & (1 << i))) +- table[i].frequency = CPUFREQ_ENTRY_INVALID; +- else +- table[i].frequency = freq / 1000; ++ table[i].frequency = freq / 1000; + table[i].driver_data = i; + } + freq_table_redup(table, count); +@@ -282,7 +233,6 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy) + policy->cpuinfo.transition_latency = u64temp + 1; + + of_node_put(np); +- of_node_put(pnode); + + return 0; + +@@ -290,10 +240,7 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy) + kfree(table); + err_pclk: + kfree(data->pclk); +-err_node: +- of_node_put(pnode); + err_nomem2: +- policy->driver_data = NULL; + kfree(data); + err_np: + of_node_put(np); +@@ -357,12 +304,25 @@ static struct cpufreq_driver qoriq_cpufreq_driver = { + .attr = cpufreq_generic_attr, + }; + ++static const struct soc_data blacklist = { ++ .flags = SOC_BLACKLIST, ++}; ++ + static const struct of_device_id node_matches[] __initconst = { +- { .compatible = "fsl,p2041-clockgen", .data = &sdata[0], }, +- { .compatible = "fsl,p3041-clockgen", .data = &sdata[0], }, +- { .compatible = "fsl,p5020-clockgen", .data = &sdata[1], }, +- { .compatible = "fsl,p4080-clockgen", .data = &sdata[2], }, +- { .compatible = "fsl,p5040-clockgen", .data = &sdata[2], }, ++ /* e6500 cannot use cpufreq due to erratum A-008083 */ ++ { .compatible = "fsl,b4420-clockgen", &blacklist }, ++ { .compatible = "fsl,b4860-clockgen", &blacklist }, ++ { .compatible = "fsl,t2080-clockgen", &blacklist }, ++ { .compatible = "fsl,t4240-clockgen", &blacklist }, ++ ++ { .compatible = "fsl,ls1012a-clockgen", }, ++ { .compatible = "fsl,ls1021a-clockgen", }, ++ { .compatible = "fsl,ls1043a-clockgen", }, ++ { .compatible = "fsl,ls1046a-clockgen", }, ++ { .compatible = "fsl,ls1088a-clockgen", }, ++ { .compatible = "fsl,ls2080a-clockgen", }, ++ { .compatible = "fsl,p4080-clockgen", }, ++ { .compatible = "fsl,qoriq-clockgen-1.0", }, + { .compatible = "fsl,qoriq-clockgen-2.0", }, + {} + }; +@@ -380,16 +340,12 @@ static int __init qoriq_cpufreq_init(void) + + match = of_match_node(node_matches, np); + data = match->data; +- if (data) { +- if (data->flag) +- fmask = data->freq_mask; +- min_cpufreq = get_bus_freq(); +- } else { +- min_cpufreq = get_bus_freq() / 2; +- } + + of_node_put(np); + ++ if (data && data->flags & SOC_BLACKLIST) ++ return -ENODEV; ++ + ret = cpufreq_register_driver(&qoriq_cpufreq_driver); + if (!ret) + pr_info("Freescale QorIQ CPU frequency scaling driver\n"); +diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c +index 8263429e..323c9fc0 100644 +--- a/drivers/firmware/psci.c ++++ b/drivers/firmware/psci.c +@@ -418,8 +418,12 @@ CPUIDLE_METHOD_OF_DECLARE(psci, "psci", &psci_cpuidle_ops); + + static int psci_system_suspend(unsigned long unused) + { +- return invoke_psci_fn(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), +- virt_to_phys(cpu_resume), 0, 0); ++ u32 state; ++ ++ state = ( 2 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | ++ (1 << PSCI_0_2_POWER_STATE_TYPE_SHIFT); ++ ++ return psci_cpu_suspend(state, virt_to_phys(cpu_resume)); + } + + static int psci_system_suspend_enter(suspend_state_t state) +@@ -439,6 +443,8 @@ static void __init psci_init_system_suspend(void) + if (!IS_ENABLED(CONFIG_SUSPEND)) + return; + ++ suspend_set_ops(&psci_suspend_ops); ++ + ret = psci_features(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND)); + + if (ret != PSCI_RET_NOT_SUPPORTED) +@@ -516,6 +522,8 @@ static void __init psci_0_2_set_functions(void) + arm_pm_restart = psci_sys_reset; + + pm_power_off = psci_sys_poweroff; ++ psci_init_system_suspend(); ++ suspend_set_ops(&psci_suspend_ops); + } + + /* +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/804-crypto-support-layerscape.patch b/target/linux/layerscape/patches-4.9/804-crypto-support-layerscape.patch new file mode 100644 index 0000000000..4340247d6e --- /dev/null +++ b/target/linux/layerscape/patches-4.9/804-crypto-support-layerscape.patch @@ -0,0 +1,26853 @@ +From 0a5b97d1f524c1769b4059e3c7123b52755f7121 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Wed, 27 Sep 2017 15:02:01 +0800 +Subject: [PATCH] crypto: support layerscape +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is a integrated patch for layerscape sec support. + +Signed-off-by: Radu Alexe +Signed-off-by: Fabio Estevam +Signed-off-by: Arnd Bergmann +Signed-off-by: Radu Alexe +Signed-off-by: Tudor Ambarus +Signed-off-by: Eric Biggers +Signed-off-by: Giovanni Cabiddu +Signed-off-by: Xulin Sun +Signed-off-by: Ard Biesheuvel +Signed-off-by: Marcus Folkesson +Signed-off-by: Tudor Ambarus +Signed-off-by: Andrew Lutomirski +Signed-off-by: Wei Yongjun +Signed-off-by: Masahiro Yamada +Signed-off-by: Marcelo Cerri +Signed-off-by: Arvind Yadav +Signed-off-by: Herbert Xu +Signed-off-by: Laura Abbott +Signed-off-by: Horia Geantă +Signed-off-by: Yangbo Lu +--- + crypto/Kconfig | 30 + + crypto/Makefile | 4 + + crypto/acompress.c | 169 + + crypto/algboss.c | 12 +- + crypto/crypto_user.c | 19 + + crypto/scompress.c | 356 ++ + crypto/tcrypt.c | 17 +- + crypto/testmgr.c | 1701 ++++---- + crypto/testmgr.h | 1125 +++--- + crypto/tls.c | 607 +++ + drivers/crypto/caam/Kconfig | 72 +- + drivers/crypto/caam/Makefile | 15 +- + drivers/crypto/caam/caamalg.c | 2125 +++------- + drivers/crypto/caam/caamalg_desc.c | 1913 +++++++++ + drivers/crypto/caam/caamalg_desc.h | 127 + + drivers/crypto/caam/caamalg_qi.c | 2877 +++++++++++++ + drivers/crypto/caam/caamalg_qi2.c | 4428 +++++++++++++++++++++ + drivers/crypto/caam/caamalg_qi2.h | 265 ++ + drivers/crypto/caam/caamhash.c | 521 +-- + drivers/crypto/caam/caampkc.c | 471 ++- + drivers/crypto/caam/caampkc.h | 58 + + drivers/crypto/caam/caamrng.c | 16 +- + drivers/crypto/caam/compat.h | 1 + + drivers/crypto/caam/ctrl.c | 356 +- + drivers/crypto/caam/ctrl.h | 2 + + drivers/crypto/caam/desc.h | 52 +- + drivers/crypto/caam/desc_constr.h | 139 +- + drivers/crypto/caam/dpseci.c | 859 ++++ + drivers/crypto/caam/dpseci.h | 395 ++ + drivers/crypto/caam/dpseci_cmd.h | 261 ++ + drivers/crypto/caam/error.c | 127 +- + drivers/crypto/caam/error.h | 10 +- + drivers/crypto/caam/intern.h | 31 +- + drivers/crypto/caam/jr.c | 55 +- + drivers/crypto/caam/key_gen.c | 32 +- + drivers/crypto/caam/key_gen.h | 36 +- + drivers/crypto/caam/pdb.h | 62 + + drivers/crypto/caam/pkc_desc.c | 36 + + drivers/crypto/caam/qi.c | 797 ++++ + drivers/crypto/caam/qi.h | 204 + + drivers/crypto/caam/regs.h | 63 +- + drivers/crypto/caam/sg_sw_qm.h | 126 + + drivers/crypto/caam/sg_sw_qm2.h | 81 + + drivers/crypto/caam/sg_sw_sec4.h | 60 +- + drivers/net/wireless/rsi/rsi_91x_usb.c | 2 +- + drivers/staging/wilc1000/linux_wlan.c | 2 +- + drivers/staging/wilc1000/wilc_wfi_cfgoperations.c | 2 +- + include/crypto/acompress.h | 269 ++ + include/crypto/internal/acompress.h | 81 + + include/crypto/internal/scompress.h | 136 + + include/linux/crypto.h | 3 + + include/uapi/linux/cryptouser.h | 5 + + scripts/spelling.txt | 3 + + sound/soc/amd/acp-pcm-dma.c | 2 +- + 54 files changed, 17263 insertions(+), 3955 deletions(-) + create mode 100644 crypto/acompress.c + create mode 100644 crypto/scompress.c + create mode 100644 crypto/tls.c + create mode 100644 drivers/crypto/caam/caamalg_desc.c + create mode 100644 drivers/crypto/caam/caamalg_desc.h + create mode 100644 drivers/crypto/caam/caamalg_qi.c + create mode 100644 drivers/crypto/caam/caamalg_qi2.c + create mode 100644 drivers/crypto/caam/caamalg_qi2.h + create mode 100644 drivers/crypto/caam/dpseci.c + create mode 100644 drivers/crypto/caam/dpseci.h + create mode 100644 drivers/crypto/caam/dpseci_cmd.h + create mode 100644 drivers/crypto/caam/qi.c + create mode 100644 drivers/crypto/caam/qi.h + create mode 100644 drivers/crypto/caam/sg_sw_qm.h + create mode 100644 drivers/crypto/caam/sg_sw_qm2.h + create mode 100644 include/crypto/acompress.h + create mode 100644 include/crypto/internal/acompress.h + create mode 100644 include/crypto/internal/scompress.h + +diff --git a/crypto/Kconfig b/crypto/Kconfig +index 17be110a..00e145e2 100644 +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -102,6 +102,15 @@ config CRYPTO_KPP + select CRYPTO_ALGAPI + select CRYPTO_KPP2 + ++config CRYPTO_ACOMP2 ++ tristate ++ select CRYPTO_ALGAPI2 ++ ++config CRYPTO_ACOMP ++ tristate ++ select CRYPTO_ALGAPI ++ select CRYPTO_ACOMP2 ++ + config CRYPTO_RSA + tristate "RSA algorithm" + select CRYPTO_AKCIPHER +@@ -138,6 +147,7 @@ config CRYPTO_MANAGER2 + select CRYPTO_BLKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS + select CRYPTO_AKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS + select CRYPTO_KPP2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_ACOMP2 if !CRYPTO_MANAGER_DISABLE_TESTS + + config CRYPTO_USER + tristate "Userspace cryptographic algorithm configuration" +@@ -295,6 +305,26 @@ config CRYPTO_ECHAINIV + a sequence number xored with a salt. This is the default + algorithm for CBC. + ++config CRYPTO_TLS ++ tristate "TLS support" ++ select CRYPTO_AEAD ++ select CRYPTO_BLKCIPHER ++ select CRYPTO_MANAGER ++ select CRYPTO_HASH ++ select CRYPTO_NULL ++ select CRYPTO_AUTHENC ++ help ++ Support for TLS 1.0 record encryption and decryption ++ ++ This module adds support for encryption/decryption of TLS 1.0 frames ++ using blockcipher algorithms. The name of the resulting algorithm is ++ "tls10(hmac(),cbc())". By default, the generic base ++ algorithms are used (e.g. aes-generic, sha1-generic), but hardware ++ accelerated versions will be used automatically if available. ++ ++ User-space applications (OpenSSL, GnuTLS) can offload TLS 1.0 ++ operations through AF_ALG or cryptodev interfaces ++ + comment "Block modes" + + config CRYPTO_CBC +diff --git a/crypto/Makefile b/crypto/Makefile +index 9e52b3c5..936d2b73 100644 +--- a/crypto/Makefile ++++ b/crypto/Makefile +@@ -51,6 +51,9 @@ rsa_generic-y += rsa_helper.o + rsa_generic-y += rsa-pkcs1pad.o + obj-$(CONFIG_CRYPTO_RSA) += rsa_generic.o + ++obj-$(CONFIG_CRYPTO_ACOMP2) += acompress.o ++obj-$(CONFIG_CRYPTO_ACOMP2) += scompress.o ++ + cryptomgr-y := algboss.o testmgr.o + + obj-$(CONFIG_CRYPTO_MANAGER2) += cryptomgr.o +@@ -115,6 +118,7 @@ obj-$(CONFIG_CRYPTO_CRC32C) += crc32c_generic.o + obj-$(CONFIG_CRYPTO_CRC32) += crc32_generic.o + obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif_common.o crct10dif_generic.o + obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o ++obj-$(CONFIG_CRYPTO_TLS) += tls.o + obj-$(CONFIG_CRYPTO_LZO) += lzo.o + obj-$(CONFIG_CRYPTO_LZ4) += lz4.o + obj-$(CONFIG_CRYPTO_LZ4HC) += lz4hc.o +diff --git a/crypto/acompress.c b/crypto/acompress.c +new file mode 100644 +index 00000000..887783d8 +--- /dev/null ++++ b/crypto/acompress.c +@@ -0,0 +1,169 @@ ++/* ++ * Asynchronous Compression operations ++ * ++ * Copyright (c) 2016, Intel Corporation ++ * Authors: Weigang Li ++ * Giovanni Cabiddu ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "internal.h" ++ ++static const struct crypto_type crypto_acomp_type; ++ ++#ifdef CONFIG_NET ++static int crypto_acomp_report(struct sk_buff *skb, struct crypto_alg *alg) ++{ ++ struct crypto_report_acomp racomp; ++ ++ strncpy(racomp.type, "acomp", sizeof(racomp.type)); ++ ++ if (nla_put(skb, CRYPTOCFGA_REPORT_ACOMP, ++ sizeof(struct crypto_report_acomp), &racomp)) ++ goto nla_put_failure; ++ return 0; ++ ++nla_put_failure: ++ return -EMSGSIZE; ++} ++#else ++static int crypto_acomp_report(struct sk_buff *skb, struct crypto_alg *alg) ++{ ++ return -ENOSYS; ++} ++#endif ++ ++static void crypto_acomp_show(struct seq_file *m, struct crypto_alg *alg) ++ __attribute__ ((unused)); ++ ++static void crypto_acomp_show(struct seq_file *m, struct crypto_alg *alg) ++{ ++ seq_puts(m, "type : acomp\n"); ++} ++ ++static void crypto_acomp_exit_tfm(struct crypto_tfm *tfm) ++{ ++ struct crypto_acomp *acomp = __crypto_acomp_tfm(tfm); ++ struct acomp_alg *alg = crypto_acomp_alg(acomp); ++ ++ alg->exit(acomp); ++} ++ ++static int crypto_acomp_init_tfm(struct crypto_tfm *tfm) ++{ ++ struct crypto_acomp *acomp = __crypto_acomp_tfm(tfm); ++ struct acomp_alg *alg = crypto_acomp_alg(acomp); ++ ++ if (tfm->__crt_alg->cra_type != &crypto_acomp_type) ++ return crypto_init_scomp_ops_async(tfm); ++ ++ acomp->compress = alg->compress; ++ acomp->decompress = alg->decompress; ++ acomp->dst_free = alg->dst_free; ++ acomp->reqsize = alg->reqsize; ++ ++ if (alg->exit) ++ acomp->base.exit = crypto_acomp_exit_tfm; ++ ++ if (alg->init) ++ return alg->init(acomp); ++ ++ return 0; ++} ++ ++static unsigned int crypto_acomp_extsize(struct crypto_alg *alg) ++{ ++ int extsize = crypto_alg_extsize(alg); ++ ++ if (alg->cra_type != &crypto_acomp_type) ++ extsize += sizeof(struct crypto_scomp *); ++ ++ return extsize; ++} ++ ++static const struct crypto_type crypto_acomp_type = { ++ .extsize = crypto_acomp_extsize, ++ .init_tfm = crypto_acomp_init_tfm, ++#ifdef CONFIG_PROC_FS ++ .show = crypto_acomp_show, ++#endif ++ .report = crypto_acomp_report, ++ .maskclear = ~CRYPTO_ALG_TYPE_MASK, ++ .maskset = CRYPTO_ALG_TYPE_ACOMPRESS_MASK, ++ .type = CRYPTO_ALG_TYPE_ACOMPRESS, ++ .tfmsize = offsetof(struct crypto_acomp, base), ++}; ++ ++struct crypto_acomp *crypto_alloc_acomp(const char *alg_name, u32 type, ++ u32 mask) ++{ ++ return crypto_alloc_tfm(alg_name, &crypto_acomp_type, type, mask); ++} ++EXPORT_SYMBOL_GPL(crypto_alloc_acomp); ++ ++struct acomp_req *acomp_request_alloc(struct crypto_acomp *acomp) ++{ ++ struct crypto_tfm *tfm = crypto_acomp_tfm(acomp); ++ struct acomp_req *req; ++ ++ req = __acomp_request_alloc(acomp); ++ if (req && (tfm->__crt_alg->cra_type != &crypto_acomp_type)) ++ return crypto_acomp_scomp_alloc_ctx(req); ++ ++ return req; ++} ++EXPORT_SYMBOL_GPL(acomp_request_alloc); ++ ++void acomp_request_free(struct acomp_req *req) ++{ ++ struct crypto_acomp *acomp = crypto_acomp_reqtfm(req); ++ struct crypto_tfm *tfm = crypto_acomp_tfm(acomp); ++ ++ if (tfm->__crt_alg->cra_type != &crypto_acomp_type) ++ crypto_acomp_scomp_free_ctx(req); ++ ++ if (req->flags & CRYPTO_ACOMP_ALLOC_OUTPUT) { ++ acomp->dst_free(req->dst); ++ req->dst = NULL; ++ } ++ ++ __acomp_request_free(req); ++} ++EXPORT_SYMBOL_GPL(acomp_request_free); ++ ++int crypto_register_acomp(struct acomp_alg *alg) ++{ ++ struct crypto_alg *base = &alg->base; ++ ++ base->cra_type = &crypto_acomp_type; ++ base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; ++ base->cra_flags |= CRYPTO_ALG_TYPE_ACOMPRESS; ++ ++ return crypto_register_alg(base); ++} ++EXPORT_SYMBOL_GPL(crypto_register_acomp); ++ ++int crypto_unregister_acomp(struct acomp_alg *alg) ++{ ++ return crypto_unregister_alg(&alg->base); ++} ++EXPORT_SYMBOL_GPL(crypto_unregister_acomp); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Asynchronous compression type"); +diff --git a/crypto/algboss.c b/crypto/algboss.c +index 4bde25d6..ccb85e17 100644 +--- a/crypto/algboss.c ++++ b/crypto/algboss.c +@@ -247,17 +247,9 @@ static int cryptomgr_schedule_test(struct crypto_alg *alg) + memcpy(param->alg, alg->cra_name, sizeof(param->alg)); + type = alg->cra_flags; + +- /* This piece of crap needs to disappear into per-type test hooks. */ +-#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS +- type |= CRYPTO_ALG_TESTED; +-#else +- if (!((type ^ CRYPTO_ALG_TYPE_BLKCIPHER) & +- CRYPTO_ALG_TYPE_BLKCIPHER_MASK) && !(type & CRYPTO_ALG_GENIV) && +- ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == +- CRYPTO_ALG_TYPE_BLKCIPHER ? alg->cra_blkcipher.ivsize : +- alg->cra_ablkcipher.ivsize)) ++ /* Do not test internal algorithms. */ ++ if (type & CRYPTO_ALG_INTERNAL) + type |= CRYPTO_ALG_TESTED; +-#endif + + param->type = type; + +diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c +index 1c570548..a90404a0 100644 +--- a/crypto/crypto_user.c ++++ b/crypto/crypto_user.c +@@ -112,6 +112,21 @@ static int crypto_report_comp(struct sk_buff *skb, struct crypto_alg *alg) + return -EMSGSIZE; + } + ++static int crypto_report_acomp(struct sk_buff *skb, struct crypto_alg *alg) ++{ ++ struct crypto_report_acomp racomp; ++ ++ strncpy(racomp.type, "acomp", sizeof(racomp.type)); ++ ++ if (nla_put(skb, CRYPTOCFGA_REPORT_ACOMP, ++ sizeof(struct crypto_report_acomp), &racomp)) ++ goto nla_put_failure; ++ return 0; ++ ++nla_put_failure: ++ return -EMSGSIZE; ++} ++ + static int crypto_report_akcipher(struct sk_buff *skb, struct crypto_alg *alg) + { + struct crypto_report_akcipher rakcipher; +@@ -186,7 +201,11 @@ static int crypto_report_one(struct crypto_alg *alg, + goto nla_put_failure; + + break; ++ case CRYPTO_ALG_TYPE_ACOMPRESS: ++ if (crypto_report_acomp(skb, alg)) ++ goto nla_put_failure; + ++ break; + case CRYPTO_ALG_TYPE_AKCIPHER: + if (crypto_report_akcipher(skb, alg)) + goto nla_put_failure; +diff --git a/crypto/scompress.c b/crypto/scompress.c +new file mode 100644 +index 00000000..35e396d1 +--- /dev/null ++++ b/crypto/scompress.c +@@ -0,0 +1,356 @@ ++/* ++ * Synchronous Compression operations ++ * ++ * Copyright 2015 LG Electronics Inc. ++ * Copyright (c) 2016, Intel Corporation ++ * Author: Giovanni Cabiddu ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "internal.h" ++ ++static const struct crypto_type crypto_scomp_type; ++static void * __percpu *scomp_src_scratches; ++static void * __percpu *scomp_dst_scratches; ++static int scomp_scratch_users; ++static DEFINE_MUTEX(scomp_lock); ++ ++#ifdef CONFIG_NET ++static int crypto_scomp_report(struct sk_buff *skb, struct crypto_alg *alg) ++{ ++ struct crypto_report_comp rscomp; ++ ++ strncpy(rscomp.type, "scomp", sizeof(rscomp.type)); ++ ++ if (nla_put(skb, CRYPTOCFGA_REPORT_COMPRESS, ++ sizeof(struct crypto_report_comp), &rscomp)) ++ goto nla_put_failure; ++ return 0; ++ ++nla_put_failure: ++ return -EMSGSIZE; ++} ++#else ++static int crypto_scomp_report(struct sk_buff *skb, struct crypto_alg *alg) ++{ ++ return -ENOSYS; ++} ++#endif ++ ++static void crypto_scomp_show(struct seq_file *m, struct crypto_alg *alg) ++ __attribute__ ((unused)); ++ ++static void crypto_scomp_show(struct seq_file *m, struct crypto_alg *alg) ++{ ++ seq_puts(m, "type : scomp\n"); ++} ++ ++static int crypto_scomp_init_tfm(struct crypto_tfm *tfm) ++{ ++ return 0; ++} ++ ++static void crypto_scomp_free_scratches(void * __percpu *scratches) ++{ ++ int i; ++ ++ if (!scratches) ++ return; ++ ++ for_each_possible_cpu(i) ++ vfree(*per_cpu_ptr(scratches, i)); ++ ++ free_percpu(scratches); ++} ++ ++static void * __percpu *crypto_scomp_alloc_scratches(void) ++{ ++ void * __percpu *scratches; ++ int i; ++ ++ scratches = alloc_percpu(void *); ++ if (!scratches) ++ return NULL; ++ ++ for_each_possible_cpu(i) { ++ void *scratch; ++ ++ scratch = vmalloc_node(SCOMP_SCRATCH_SIZE, cpu_to_node(i)); ++ if (!scratch) ++ goto error; ++ *per_cpu_ptr(scratches, i) = scratch; ++ } ++ ++ return scratches; ++ ++error: ++ crypto_scomp_free_scratches(scratches); ++ return NULL; ++} ++ ++static void crypto_scomp_free_all_scratches(void) ++{ ++ if (!--scomp_scratch_users) { ++ crypto_scomp_free_scratches(scomp_src_scratches); ++ crypto_scomp_free_scratches(scomp_dst_scratches); ++ scomp_src_scratches = NULL; ++ scomp_dst_scratches = NULL; ++ } ++} ++ ++static int crypto_scomp_alloc_all_scratches(void) ++{ ++ if (!scomp_scratch_users++) { ++ scomp_src_scratches = crypto_scomp_alloc_scratches(); ++ if (!scomp_src_scratches) ++ return -ENOMEM; ++ scomp_dst_scratches = crypto_scomp_alloc_scratches(); ++ if (!scomp_dst_scratches) ++ return -ENOMEM; ++ } ++ return 0; ++} ++ ++static void crypto_scomp_sg_free(struct scatterlist *sgl) ++{ ++ int i, n; ++ struct page *page; ++ ++ if (!sgl) ++ return; ++ ++ n = sg_nents(sgl); ++ for_each_sg(sgl, sgl, n, i) { ++ page = sg_page(sgl); ++ if (page) ++ __free_page(page); ++ } ++ ++ kfree(sgl); ++} ++ ++static struct scatterlist *crypto_scomp_sg_alloc(size_t size, gfp_t gfp) ++{ ++ struct scatterlist *sgl; ++ struct page *page; ++ int i, n; ++ ++ n = ((size - 1) >> PAGE_SHIFT) + 1; ++ ++ sgl = kmalloc_array(n, sizeof(struct scatterlist), gfp); ++ if (!sgl) ++ return NULL; ++ ++ sg_init_table(sgl, n); ++ ++ for (i = 0; i < n; i++) { ++ page = alloc_page(gfp); ++ if (!page) ++ goto err; ++ sg_set_page(sgl + i, page, PAGE_SIZE, 0); ++ } ++ ++ return sgl; ++ ++err: ++ sg_mark_end(sgl + i); ++ crypto_scomp_sg_free(sgl); ++ return NULL; ++} ++ ++static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir) ++{ ++ struct crypto_acomp *tfm = crypto_acomp_reqtfm(req); ++ void **tfm_ctx = acomp_tfm_ctx(tfm); ++ struct crypto_scomp *scomp = *tfm_ctx; ++ void **ctx = acomp_request_ctx(req); ++ const int cpu = get_cpu(); ++ u8 *scratch_src = *per_cpu_ptr(scomp_src_scratches, cpu); ++ u8 *scratch_dst = *per_cpu_ptr(scomp_dst_scratches, cpu); ++ int ret; ++ ++ if (!req->src || !req->slen || req->slen > SCOMP_SCRATCH_SIZE) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ if (req->dst && !req->dlen) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ if (!req->dlen || req->dlen > SCOMP_SCRATCH_SIZE) ++ req->dlen = SCOMP_SCRATCH_SIZE; ++ ++ scatterwalk_map_and_copy(scratch_src, req->src, 0, req->slen, 0); ++ if (dir) ++ ret = crypto_scomp_compress(scomp, scratch_src, req->slen, ++ scratch_dst, &req->dlen, *ctx); ++ else ++ ret = crypto_scomp_decompress(scomp, scratch_src, req->slen, ++ scratch_dst, &req->dlen, *ctx); ++ if (!ret) { ++ if (!req->dst) { ++ req->dst = crypto_scomp_sg_alloc(req->dlen, ++ req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? ++ GFP_KERNEL : GFP_ATOMIC); ++ if (!req->dst) ++ goto out; ++ } ++ scatterwalk_map_and_copy(scratch_dst, req->dst, 0, req->dlen, ++ 1); ++ } ++out: ++ put_cpu(); ++ return ret; ++} ++ ++static int scomp_acomp_compress(struct acomp_req *req) ++{ ++ return scomp_acomp_comp_decomp(req, 1); ++} ++ ++static int scomp_acomp_decompress(struct acomp_req *req) ++{ ++ return scomp_acomp_comp_decomp(req, 0); ++} ++ ++static void crypto_exit_scomp_ops_async(struct crypto_tfm *tfm) ++{ ++ struct crypto_scomp **ctx = crypto_tfm_ctx(tfm); ++ ++ crypto_free_scomp(*ctx); ++} ++ ++int crypto_init_scomp_ops_async(struct crypto_tfm *tfm) ++{ ++ struct crypto_alg *calg = tfm->__crt_alg; ++ struct crypto_acomp *crt = __crypto_acomp_tfm(tfm); ++ struct crypto_scomp **ctx = crypto_tfm_ctx(tfm); ++ struct crypto_scomp *scomp; ++ ++ if (!crypto_mod_get(calg)) ++ return -EAGAIN; ++ ++ scomp = crypto_create_tfm(calg, &crypto_scomp_type); ++ if (IS_ERR(scomp)) { ++ crypto_mod_put(calg); ++ return PTR_ERR(scomp); ++ } ++ ++ *ctx = scomp; ++ tfm->exit = crypto_exit_scomp_ops_async; ++ ++ crt->compress = scomp_acomp_compress; ++ crt->decompress = scomp_acomp_decompress; ++ crt->dst_free = crypto_scomp_sg_free; ++ crt->reqsize = sizeof(void *); ++ ++ return 0; ++} ++ ++struct acomp_req *crypto_acomp_scomp_alloc_ctx(struct acomp_req *req) ++{ ++ struct crypto_acomp *acomp = crypto_acomp_reqtfm(req); ++ struct crypto_tfm *tfm = crypto_acomp_tfm(acomp); ++ struct crypto_scomp **tfm_ctx = crypto_tfm_ctx(tfm); ++ struct crypto_scomp *scomp = *tfm_ctx; ++ void *ctx; ++ ++ ctx = crypto_scomp_alloc_ctx(scomp); ++ if (IS_ERR(ctx)) { ++ kfree(req); ++ return NULL; ++ } ++ ++ *req->__ctx = ctx; ++ ++ return req; ++} ++ ++void crypto_acomp_scomp_free_ctx(struct acomp_req *req) ++{ ++ struct crypto_acomp *acomp = crypto_acomp_reqtfm(req); ++ struct crypto_tfm *tfm = crypto_acomp_tfm(acomp); ++ struct crypto_scomp **tfm_ctx = crypto_tfm_ctx(tfm); ++ struct crypto_scomp *scomp = *tfm_ctx; ++ void *ctx = *req->__ctx; ++ ++ if (ctx) ++ crypto_scomp_free_ctx(scomp, ctx); ++} ++ ++static const struct crypto_type crypto_scomp_type = { ++ .extsize = crypto_alg_extsize, ++ .init_tfm = crypto_scomp_init_tfm, ++#ifdef CONFIG_PROC_FS ++ .show = crypto_scomp_show, ++#endif ++ .report = crypto_scomp_report, ++ .maskclear = ~CRYPTO_ALG_TYPE_MASK, ++ .maskset = CRYPTO_ALG_TYPE_MASK, ++ .type = CRYPTO_ALG_TYPE_SCOMPRESS, ++ .tfmsize = offsetof(struct crypto_scomp, base), ++}; ++ ++int crypto_register_scomp(struct scomp_alg *alg) ++{ ++ struct crypto_alg *base = &alg->base; ++ int ret = -ENOMEM; ++ ++ mutex_lock(&scomp_lock); ++ if (crypto_scomp_alloc_all_scratches()) ++ goto error; ++ ++ base->cra_type = &crypto_scomp_type; ++ base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; ++ base->cra_flags |= CRYPTO_ALG_TYPE_SCOMPRESS; ++ ++ ret = crypto_register_alg(base); ++ if (ret) ++ goto error; ++ ++ mutex_unlock(&scomp_lock); ++ return ret; ++ ++error: ++ crypto_scomp_free_all_scratches(); ++ mutex_unlock(&scomp_lock); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(crypto_register_scomp); ++ ++int crypto_unregister_scomp(struct scomp_alg *alg) ++{ ++ int ret; ++ ++ mutex_lock(&scomp_lock); ++ ret = crypto_unregister_alg(&alg->base); ++ crypto_scomp_free_all_scratches(); ++ mutex_unlock(&scomp_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(crypto_unregister_scomp); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Synchronous compression type"); +diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c +index ae22f05d..bbb35eed 100644 +--- a/crypto/tcrypt.c ++++ b/crypto/tcrypt.c +@@ -74,7 +74,7 @@ static char *check[] = { + "khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", "fcrypt", + "camellia", "seed", "salsa20", "rmd128", "rmd160", "rmd256", "rmd320", + "lzo", "cts", "zlib", "sha3-224", "sha3-256", "sha3-384", "sha3-512", +- NULL ++ "rsa", NULL + }; + + struct tcrypt_result { +@@ -1329,6 +1329,10 @@ static int do_test(const char *alg, u32 type, u32 mask, int m) + ret += tcrypt_test("hmac(sha3-512)"); + break; + ++ case 115: ++ ret += tcrypt_test("rsa"); ++ break; ++ + case 150: + ret += tcrypt_test("ansi_cprng"); + break; +@@ -1390,6 +1394,9 @@ static int do_test(const char *alg, u32 type, u32 mask, int m) + case 190: + ret += tcrypt_test("authenc(hmac(sha512),cbc(des3_ede))"); + break; ++ case 191: ++ ret += tcrypt_test("tls10(hmac(sha1),cbc(aes))"); ++ break; + case 200: + test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0, + speed_template_16_24_32); +@@ -1404,9 +1411,9 @@ static int do_test(const char *alg, u32 type, u32 mask, int m) + test_cipher_speed("lrw(aes)", DECRYPT, sec, NULL, 0, + speed_template_32_40_48); + test_cipher_speed("xts(aes)", ENCRYPT, sec, NULL, 0, +- speed_template_32_48_64); ++ speed_template_32_64); + test_cipher_speed("xts(aes)", DECRYPT, sec, NULL, 0, +- speed_template_32_48_64); ++ speed_template_32_64); + test_cipher_speed("cts(cbc(aes))", ENCRYPT, sec, NULL, 0, + speed_template_16_24_32); + test_cipher_speed("cts(cbc(aes))", DECRYPT, sec, NULL, 0, +@@ -1837,9 +1844,9 @@ static int do_test(const char *alg, u32 type, u32 mask, int m) + test_acipher_speed("lrw(aes)", DECRYPT, sec, NULL, 0, + speed_template_32_40_48); + test_acipher_speed("xts(aes)", ENCRYPT, sec, NULL, 0, +- speed_template_32_48_64); ++ speed_template_32_64); + test_acipher_speed("xts(aes)", DECRYPT, sec, NULL, 0, +- speed_template_32_48_64); ++ speed_template_32_64); + test_acipher_speed("cts(cbc(aes))", ENCRYPT, sec, NULL, 0, + speed_template_16_24_32); + test_acipher_speed("cts(cbc(aes))", DECRYPT, sec, NULL, 0, +diff --git a/crypto/testmgr.c b/crypto/testmgr.c +index 62dffa00..73d91fba 100644 +--- a/crypto/testmgr.c ++++ b/crypto/testmgr.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + #include "internal.h" + +@@ -62,7 +63,7 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask) + */ + #define IDX1 32 + #define IDX2 32400 +-#define IDX3 1 ++#define IDX3 1511 + #define IDX4 8193 + #define IDX5 22222 + #define IDX6 17101 +@@ -82,47 +83,54 @@ struct tcrypt_result { + + struct aead_test_suite { + struct { +- struct aead_testvec *vecs; ++ const struct aead_testvec *vecs; + unsigned int count; + } enc, dec; + }; + + struct cipher_test_suite { + struct { +- struct cipher_testvec *vecs; ++ const struct cipher_testvec *vecs; + unsigned int count; + } enc, dec; + }; + + struct comp_test_suite { + struct { +- struct comp_testvec *vecs; ++ const struct comp_testvec *vecs; + unsigned int count; + } comp, decomp; + }; + + struct hash_test_suite { +- struct hash_testvec *vecs; ++ const struct hash_testvec *vecs; + unsigned int count; + }; + + struct cprng_test_suite { +- struct cprng_testvec *vecs; ++ const struct cprng_testvec *vecs; + unsigned int count; + }; + + struct drbg_test_suite { +- struct drbg_testvec *vecs; ++ const struct drbg_testvec *vecs; + unsigned int count; + }; + ++struct tls_test_suite { ++ struct { ++ struct tls_testvec *vecs; ++ unsigned int count; ++ } enc, dec; ++}; ++ + struct akcipher_test_suite { +- struct akcipher_testvec *vecs; ++ const struct akcipher_testvec *vecs; + unsigned int count; + }; + + struct kpp_test_suite { +- struct kpp_testvec *vecs; ++ const struct kpp_testvec *vecs; + unsigned int count; + }; + +@@ -139,12 +147,14 @@ struct alg_test_desc { + struct hash_test_suite hash; + struct cprng_test_suite cprng; + struct drbg_test_suite drbg; ++ struct tls_test_suite tls; + struct akcipher_test_suite akcipher; + struct kpp_test_suite kpp; + } suite; + }; + +-static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 }; ++static const unsigned int IDX[8] = { ++ IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 }; + + static void hexdump(unsigned char *buf, unsigned int len) + { +@@ -202,7 +212,7 @@ static int wait_async_op(struct tcrypt_result *tr, int ret) + } + + static int ahash_partial_update(struct ahash_request **preq, +- struct crypto_ahash *tfm, struct hash_testvec *template, ++ struct crypto_ahash *tfm, const struct hash_testvec *template, + void *hash_buff, int k, int temp, struct scatterlist *sg, + const char *algo, char *result, struct tcrypt_result *tresult) + { +@@ -259,11 +269,12 @@ static int ahash_partial_update(struct ahash_request **preq, + return ret; + } + +-static int __test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, +- unsigned int tcount, bool use_digest, +- const int align_offset) ++static int __test_hash(struct crypto_ahash *tfm, ++ const struct hash_testvec *template, unsigned int tcount, ++ bool use_digest, const int align_offset) + { + const char *algo = crypto_tfm_alg_driver_name(crypto_ahash_tfm(tfm)); ++ size_t digest_size = crypto_ahash_digestsize(tfm); + unsigned int i, j, k, temp; + struct scatterlist sg[8]; + char *result; +@@ -274,7 +285,7 @@ static int __test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, + char *xbuf[XBUFSIZE]; + int ret = -ENOMEM; + +- result = kmalloc(MAX_DIGEST_SIZE, GFP_KERNEL); ++ result = kmalloc(digest_size, GFP_KERNEL); + if (!result) + return ret; + key = kmalloc(MAX_KEYLEN, GFP_KERNEL); +@@ -304,7 +315,7 @@ static int __test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, + goto out; + + j++; +- memset(result, 0, MAX_DIGEST_SIZE); ++ memset(result, 0, digest_size); + + hash_buff = xbuf[0]; + hash_buff += align_offset; +@@ -379,7 +390,7 @@ static int __test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, + continue; + + j++; +- memset(result, 0, MAX_DIGEST_SIZE); ++ memset(result, 0, digest_size); + + temp = 0; + sg_init_table(sg, template[i].np); +@@ -457,7 +468,7 @@ static int __test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, + continue; + + j++; +- memset(result, 0, MAX_DIGEST_SIZE); ++ memset(result, 0, digest_size); + + ret = -EINVAL; + hash_buff = xbuf[0]; +@@ -536,7 +547,8 @@ static int __test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, + return ret; + } + +-static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, ++static int test_hash(struct crypto_ahash *tfm, ++ const struct hash_testvec *template, + unsigned int tcount, bool use_digest) + { + unsigned int alignmask; +@@ -564,7 +576,7 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, + } + + static int __test_aead(struct crypto_aead *tfm, int enc, +- struct aead_testvec *template, unsigned int tcount, ++ const struct aead_testvec *template, unsigned int tcount, + const bool diff_dst, const int align_offset) + { + const char *algo = crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)); +@@ -955,7 +967,7 @@ static int __test_aead(struct crypto_aead *tfm, int enc, + } + + static int test_aead(struct crypto_aead *tfm, int enc, +- struct aead_testvec *template, unsigned int tcount) ++ const struct aead_testvec *template, unsigned int tcount) + { + unsigned int alignmask; + int ret; +@@ -987,8 +999,236 @@ static int test_aead(struct crypto_aead *tfm, int enc, + return 0; + } + ++static int __test_tls(struct crypto_aead *tfm, int enc, ++ struct tls_testvec *template, unsigned int tcount, ++ const bool diff_dst) ++{ ++ const char *algo = crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)); ++ unsigned int i, k, authsize; ++ char *q; ++ struct aead_request *req; ++ struct scatterlist *sg; ++ struct scatterlist *sgout; ++ const char *e, *d; ++ struct tcrypt_result result; ++ void *input; ++ void *output; ++ void *assoc; ++ char *iv; ++ char *key; ++ char *xbuf[XBUFSIZE]; ++ char *xoutbuf[XBUFSIZE]; ++ char *axbuf[XBUFSIZE]; ++ int ret = -ENOMEM; ++ ++ if (testmgr_alloc_buf(xbuf)) ++ goto out_noxbuf; ++ ++ if (diff_dst && testmgr_alloc_buf(xoutbuf)) ++ goto out_nooutbuf; ++ ++ if (testmgr_alloc_buf(axbuf)) ++ goto out_noaxbuf; ++ ++ iv = kzalloc(MAX_IVLEN, GFP_KERNEL); ++ if (!iv) ++ goto out_noiv; ++ ++ key = kzalloc(MAX_KEYLEN, GFP_KERNEL); ++ if (!key) ++ goto out_nokey; ++ ++ sg = kmalloc(sizeof(*sg) * 8 * (diff_dst ? 2 : 1), GFP_KERNEL); ++ if (!sg) ++ goto out_nosg; ++ ++ sgout = sg + 8; ++ ++ d = diff_dst ? "-ddst" : ""; ++ e = enc ? "encryption" : "decryption"; ++ ++ init_completion(&result.completion); ++ ++ req = aead_request_alloc(tfm, GFP_KERNEL); ++ if (!req) { ++ pr_err("alg: tls%s: Failed to allocate request for %s\n", ++ d, algo); ++ goto out; ++ } ++ ++ aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, ++ tcrypt_complete, &result); ++ ++ for (i = 0; i < tcount; i++) { ++ input = xbuf[0]; ++ assoc = axbuf[0]; ++ ++ ret = -EINVAL; ++ if (WARN_ON(template[i].ilen > PAGE_SIZE || ++ template[i].alen > PAGE_SIZE)) ++ goto out; ++ ++ memcpy(assoc, template[i].assoc, template[i].alen); ++ memcpy(input, template[i].input, template[i].ilen); ++ ++ if (template[i].iv) ++ memcpy(iv, template[i].iv, MAX_IVLEN); ++ else ++ memset(iv, 0, MAX_IVLEN); ++ ++ crypto_aead_clear_flags(tfm, ~0); ++ ++ if (template[i].klen > MAX_KEYLEN) { ++ pr_err("alg: aead%s: setkey failed on test %d for %s: key size %d > %d\n", ++ d, i, algo, template[i].klen, MAX_KEYLEN); ++ ret = -EINVAL; ++ goto out; ++ } ++ memcpy(key, template[i].key, template[i].klen); ++ ++ ret = crypto_aead_setkey(tfm, key, template[i].klen); ++ if (!ret == template[i].fail) { ++ pr_err("alg: tls%s: setkey failed on test %d for %s: flags=%x\n", ++ d, i, algo, crypto_aead_get_flags(tfm)); ++ goto out; ++ } else if (ret) ++ continue; ++ ++ authsize = 20; ++ ret = crypto_aead_setauthsize(tfm, authsize); ++ if (ret) { ++ pr_err("alg: aead%s: Failed to set authsize to %u on test %d for %s\n", ++ d, authsize, i, algo); ++ goto out; ++ } ++ ++ k = !!template[i].alen; ++ sg_init_table(sg, k + 1); ++ sg_set_buf(&sg[0], assoc, template[i].alen); ++ sg_set_buf(&sg[k], input, (enc ? template[i].rlen : ++ template[i].ilen)); ++ output = input; ++ ++ if (diff_dst) { ++ sg_init_table(sgout, k + 1); ++ sg_set_buf(&sgout[0], assoc, template[i].alen); ++ ++ output = xoutbuf[0]; ++ sg_set_buf(&sgout[k], output, ++ (enc ? template[i].rlen : template[i].ilen)); ++ } ++ ++ aead_request_set_crypt(req, sg, (diff_dst) ? sgout : sg, ++ template[i].ilen, iv); ++ ++ aead_request_set_ad(req, template[i].alen); ++ ++ ret = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req); ++ ++ switch (ret) { ++ case 0: ++ if (template[i].novrfy) { ++ /* verification was supposed to fail */ ++ pr_err("alg: tls%s: %s failed on test %d for %s: ret was 0, expected -EBADMSG\n", ++ d, e, i, algo); ++ /* so really, we got a bad message */ ++ ret = -EBADMSG; ++ goto out; ++ } ++ break; ++ case -EINPROGRESS: ++ case -EBUSY: ++ wait_for_completion(&result.completion); ++ reinit_completion(&result.completion); ++ ret = result.err; ++ if (!ret) ++ break; ++ case -EBADMSG: ++ /* verification failure was expected */ ++ if (template[i].novrfy) ++ continue; ++ /* fall through */ ++ default: ++ pr_err("alg: tls%s: %s failed on test %d for %s: ret=%d\n", ++ d, e, i, algo, -ret); ++ goto out; ++ } ++ ++ q = output; ++ if (memcmp(q, template[i].result, template[i].rlen)) { ++ pr_err("alg: tls%s: Test %d failed on %s for %s\n", ++ d, i, e, algo); ++ hexdump(q, template[i].rlen); ++ pr_err("should be:\n"); ++ hexdump(template[i].result, template[i].rlen); ++ ret = -EINVAL; ++ goto out; ++ } ++ } ++ ++out: ++ aead_request_free(req); ++ ++ kfree(sg); ++out_nosg: ++ kfree(key); ++out_nokey: ++ kfree(iv); ++out_noiv: ++ testmgr_free_buf(axbuf); ++out_noaxbuf: ++ if (diff_dst) ++ testmgr_free_buf(xoutbuf); ++out_nooutbuf: ++ testmgr_free_buf(xbuf); ++out_noxbuf: ++ return ret; ++} ++ ++static int test_tls(struct crypto_aead *tfm, int enc, ++ struct tls_testvec *template, unsigned int tcount) ++{ ++ int ret; ++ /* test 'dst == src' case */ ++ ret = __test_tls(tfm, enc, template, tcount, false); ++ if (ret) ++ return ret; ++ /* test 'dst != src' case */ ++ return __test_tls(tfm, enc, template, tcount, true); ++} ++ ++static int alg_test_tls(const struct alg_test_desc *desc, const char *driver, ++ u32 type, u32 mask) ++{ ++ struct crypto_aead *tfm; ++ int err = 0; ++ ++ tfm = crypto_alloc_aead(driver, type, mask); ++ if (IS_ERR(tfm)) { ++ pr_err("alg: aead: Failed to load transform for %s: %ld\n", ++ driver, PTR_ERR(tfm)); ++ return PTR_ERR(tfm); ++ } ++ ++ if (desc->suite.tls.enc.vecs) { ++ err = test_tls(tfm, ENCRYPT, desc->suite.tls.enc.vecs, ++ desc->suite.tls.enc.count); ++ if (err) ++ goto out; ++ } ++ ++ if (!err && desc->suite.tls.dec.vecs) ++ err = test_tls(tfm, DECRYPT, desc->suite.tls.dec.vecs, ++ desc->suite.tls.dec.count); ++ ++out: ++ crypto_free_aead(tfm); ++ return err; ++} ++ + static int test_cipher(struct crypto_cipher *tfm, int enc, +- struct cipher_testvec *template, unsigned int tcount) ++ const struct cipher_testvec *template, ++ unsigned int tcount) + { + const char *algo = crypto_tfm_alg_driver_name(crypto_cipher_tfm(tfm)); + unsigned int i, j, k; +@@ -1066,7 +1306,8 @@ static int test_cipher(struct crypto_cipher *tfm, int enc, + } + + static int __test_skcipher(struct crypto_skcipher *tfm, int enc, +- struct cipher_testvec *template, unsigned int tcount, ++ const struct cipher_testvec *template, ++ unsigned int tcount, + const bool diff_dst, const int align_offset) + { + const char *algo = +@@ -1330,7 +1571,8 @@ static int __test_skcipher(struct crypto_skcipher *tfm, int enc, + } + + static int test_skcipher(struct crypto_skcipher *tfm, int enc, +- struct cipher_testvec *template, unsigned int tcount) ++ const struct cipher_testvec *template, ++ unsigned int tcount) + { + unsigned int alignmask; + int ret; +@@ -1362,8 +1604,10 @@ static int test_skcipher(struct crypto_skcipher *tfm, int enc, + return 0; + } + +-static int test_comp(struct crypto_comp *tfm, struct comp_testvec *ctemplate, +- struct comp_testvec *dtemplate, int ctcount, int dtcount) ++static int test_comp(struct crypto_comp *tfm, ++ const struct comp_testvec *ctemplate, ++ const struct comp_testvec *dtemplate, ++ int ctcount, int dtcount) + { + const char *algo = crypto_tfm_alg_driver_name(crypto_comp_tfm(tfm)); + unsigned int i; +@@ -1442,7 +1686,154 @@ static int test_comp(struct crypto_comp *tfm, struct comp_testvec *ctemplate, + return ret; + } + +-static int test_cprng(struct crypto_rng *tfm, struct cprng_testvec *template, ++static int test_acomp(struct crypto_acomp *tfm, ++ const struct comp_testvec *ctemplate, ++ const struct comp_testvec *dtemplate, ++ int ctcount, int dtcount) ++{ ++ const char *algo = crypto_tfm_alg_driver_name(crypto_acomp_tfm(tfm)); ++ unsigned int i; ++ char *output; ++ int ret; ++ struct scatterlist src, dst; ++ struct acomp_req *req; ++ struct tcrypt_result result; ++ ++ output = kmalloc(COMP_BUF_SIZE, GFP_KERNEL); ++ if (!output) ++ return -ENOMEM; ++ ++ for (i = 0; i < ctcount; i++) { ++ unsigned int dlen = COMP_BUF_SIZE; ++ int ilen = ctemplate[i].inlen; ++ void *input_vec; ++ ++ input_vec = kmemdup(ctemplate[i].input, ilen, GFP_KERNEL); ++ if (!input_vec) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ memset(output, 0, dlen); ++ init_completion(&result.completion); ++ sg_init_one(&src, input_vec, ilen); ++ sg_init_one(&dst, output, dlen); ++ ++ req = acomp_request_alloc(tfm); ++ if (!req) { ++ pr_err("alg: acomp: request alloc failed for %s\n", ++ algo); ++ kfree(input_vec); ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ acomp_request_set_params(req, &src, &dst, ilen, dlen); ++ acomp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, ++ tcrypt_complete, &result); ++ ++ ret = wait_async_op(&result, crypto_acomp_compress(req)); ++ if (ret) { ++ pr_err("alg: acomp: compression failed on test %d for %s: ret=%d\n", ++ i + 1, algo, -ret); ++ kfree(input_vec); ++ acomp_request_free(req); ++ goto out; ++ } ++ ++ if (req->dlen != ctemplate[i].outlen) { ++ pr_err("alg: acomp: Compression test %d failed for %s: output len = %d\n", ++ i + 1, algo, req->dlen); ++ ret = -EINVAL; ++ kfree(input_vec); ++ acomp_request_free(req); ++ goto out; ++ } ++ ++ if (memcmp(output, ctemplate[i].output, req->dlen)) { ++ pr_err("alg: acomp: Compression test %d failed for %s\n", ++ i + 1, algo); ++ hexdump(output, req->dlen); ++ ret = -EINVAL; ++ kfree(input_vec); ++ acomp_request_free(req); ++ goto out; ++ } ++ ++ kfree(input_vec); ++ acomp_request_free(req); ++ } ++ ++ for (i = 0; i < dtcount; i++) { ++ unsigned int dlen = COMP_BUF_SIZE; ++ int ilen = dtemplate[i].inlen; ++ void *input_vec; ++ ++ input_vec = kmemdup(dtemplate[i].input, ilen, GFP_KERNEL); ++ if (!input_vec) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ memset(output, 0, dlen); ++ init_completion(&result.completion); ++ sg_init_one(&src, input_vec, ilen); ++ sg_init_one(&dst, output, dlen); ++ ++ req = acomp_request_alloc(tfm); ++ if (!req) { ++ pr_err("alg: acomp: request alloc failed for %s\n", ++ algo); ++ kfree(input_vec); ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ acomp_request_set_params(req, &src, &dst, ilen, dlen); ++ acomp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, ++ tcrypt_complete, &result); ++ ++ ret = wait_async_op(&result, crypto_acomp_decompress(req)); ++ if (ret) { ++ pr_err("alg: acomp: decompression failed on test %d for %s: ret=%d\n", ++ i + 1, algo, -ret); ++ kfree(input_vec); ++ acomp_request_free(req); ++ goto out; ++ } ++ ++ if (req->dlen != dtemplate[i].outlen) { ++ pr_err("alg: acomp: Decompression test %d failed for %s: output len = %d\n", ++ i + 1, algo, req->dlen); ++ ret = -EINVAL; ++ kfree(input_vec); ++ acomp_request_free(req); ++ goto out; ++ } ++ ++ if (memcmp(output, dtemplate[i].output, req->dlen)) { ++ pr_err("alg: acomp: Decompression test %d failed for %s\n", ++ i + 1, algo); ++ hexdump(output, req->dlen); ++ ret = -EINVAL; ++ kfree(input_vec); ++ acomp_request_free(req); ++ goto out; ++ } ++ ++ kfree(input_vec); ++ acomp_request_free(req); ++ } ++ ++ ret = 0; ++ ++out: ++ kfree(output); ++ return ret; ++} ++ ++static int test_cprng(struct crypto_rng *tfm, ++ const struct cprng_testvec *template, + unsigned int tcount) + { + const char *algo = crypto_tfm_alg_driver_name(crypto_rng_tfm(tfm)); +@@ -1509,7 +1900,7 @@ static int alg_test_aead(const struct alg_test_desc *desc, const char *driver, + struct crypto_aead *tfm; + int err = 0; + +- tfm = crypto_alloc_aead(driver, type | CRYPTO_ALG_INTERNAL, mask); ++ tfm = crypto_alloc_aead(driver, type, mask); + if (IS_ERR(tfm)) { + printk(KERN_ERR "alg: aead: Failed to load transform for %s: " + "%ld\n", driver, PTR_ERR(tfm)); +@@ -1538,7 +1929,7 @@ static int alg_test_cipher(const struct alg_test_desc *desc, + struct crypto_cipher *tfm; + int err = 0; + +- tfm = crypto_alloc_cipher(driver, type | CRYPTO_ALG_INTERNAL, mask); ++ tfm = crypto_alloc_cipher(driver, type, mask); + if (IS_ERR(tfm)) { + printk(KERN_ERR "alg: cipher: Failed to load transform for " + "%s: %ld\n", driver, PTR_ERR(tfm)); +@@ -1567,7 +1958,7 @@ static int alg_test_skcipher(const struct alg_test_desc *desc, + struct crypto_skcipher *tfm; + int err = 0; + +- tfm = crypto_alloc_skcipher(driver, type | CRYPTO_ALG_INTERNAL, mask); ++ tfm = crypto_alloc_skcipher(driver, type, mask); + if (IS_ERR(tfm)) { + printk(KERN_ERR "alg: skcipher: Failed to load transform for " + "%s: %ld\n", driver, PTR_ERR(tfm)); +@@ -1593,22 +1984,38 @@ static int alg_test_skcipher(const struct alg_test_desc *desc, + static int alg_test_comp(const struct alg_test_desc *desc, const char *driver, + u32 type, u32 mask) + { +- struct crypto_comp *tfm; ++ struct crypto_comp *comp; ++ struct crypto_acomp *acomp; + int err; ++ u32 algo_type = type & CRYPTO_ALG_TYPE_ACOMPRESS_MASK; ++ ++ if (algo_type == CRYPTO_ALG_TYPE_ACOMPRESS) { ++ acomp = crypto_alloc_acomp(driver, type, mask); ++ if (IS_ERR(acomp)) { ++ pr_err("alg: acomp: Failed to load transform for %s: %ld\n", ++ driver, PTR_ERR(acomp)); ++ return PTR_ERR(acomp); ++ } ++ err = test_acomp(acomp, desc->suite.comp.comp.vecs, ++ desc->suite.comp.decomp.vecs, ++ desc->suite.comp.comp.count, ++ desc->suite.comp.decomp.count); ++ crypto_free_acomp(acomp); ++ } else { ++ comp = crypto_alloc_comp(driver, type, mask); ++ if (IS_ERR(comp)) { ++ pr_err("alg: comp: Failed to load transform for %s: %ld\n", ++ driver, PTR_ERR(comp)); ++ return PTR_ERR(comp); ++ } + +- tfm = crypto_alloc_comp(driver, type, mask); +- if (IS_ERR(tfm)) { +- printk(KERN_ERR "alg: comp: Failed to load transform for %s: " +- "%ld\n", driver, PTR_ERR(tfm)); +- return PTR_ERR(tfm); +- } +- +- err = test_comp(tfm, desc->suite.comp.comp.vecs, +- desc->suite.comp.decomp.vecs, +- desc->suite.comp.comp.count, +- desc->suite.comp.decomp.count); ++ err = test_comp(comp, desc->suite.comp.comp.vecs, ++ desc->suite.comp.decomp.vecs, ++ desc->suite.comp.comp.count, ++ desc->suite.comp.decomp.count); + +- crypto_free_comp(tfm); ++ crypto_free_comp(comp); ++ } + return err; + } + +@@ -1618,7 +2025,7 @@ static int alg_test_hash(const struct alg_test_desc *desc, const char *driver, + struct crypto_ahash *tfm; + int err; + +- tfm = crypto_alloc_ahash(driver, type | CRYPTO_ALG_INTERNAL, mask); ++ tfm = crypto_alloc_ahash(driver, type, mask); + if (IS_ERR(tfm)) { + printk(KERN_ERR "alg: hash: Failed to load transform for %s: " + "%ld\n", driver, PTR_ERR(tfm)); +@@ -1646,7 +2053,7 @@ static int alg_test_crc32c(const struct alg_test_desc *desc, + if (err) + goto out; + +- tfm = crypto_alloc_shash(driver, type | CRYPTO_ALG_INTERNAL, mask); ++ tfm = crypto_alloc_shash(driver, type, mask); + if (IS_ERR(tfm)) { + printk(KERN_ERR "alg: crc32c: Failed to load transform for %s: " + "%ld\n", driver, PTR_ERR(tfm)); +@@ -1688,7 +2095,7 @@ static int alg_test_cprng(const struct alg_test_desc *desc, const char *driver, + struct crypto_rng *rng; + int err; + +- rng = crypto_alloc_rng(driver, type | CRYPTO_ALG_INTERNAL, mask); ++ rng = crypto_alloc_rng(driver, type, mask); + if (IS_ERR(rng)) { + printk(KERN_ERR "alg: cprng: Failed to load transform for %s: " + "%ld\n", driver, PTR_ERR(rng)); +@@ -1703,7 +2110,7 @@ static int alg_test_cprng(const struct alg_test_desc *desc, const char *driver, + } + + +-static int drbg_cavs_test(struct drbg_testvec *test, int pr, ++static int drbg_cavs_test(const struct drbg_testvec *test, int pr, + const char *driver, u32 type, u32 mask) + { + int ret = -EAGAIN; +@@ -1715,7 +2122,7 @@ static int drbg_cavs_test(struct drbg_testvec *test, int pr, + if (!buf) + return -ENOMEM; + +- drng = crypto_alloc_rng(driver, type | CRYPTO_ALG_INTERNAL, mask); ++ drng = crypto_alloc_rng(driver, type, mask); + if (IS_ERR(drng)) { + printk(KERN_ERR "alg: drbg: could not allocate DRNG handle for " + "%s\n", driver); +@@ -1777,7 +2184,7 @@ static int alg_test_drbg(const struct alg_test_desc *desc, const char *driver, + int err = 0; + int pr = 0; + int i = 0; +- struct drbg_testvec *template = desc->suite.drbg.vecs; ++ const struct drbg_testvec *template = desc->suite.drbg.vecs; + unsigned int tcount = desc->suite.drbg.count; + + if (0 == memcmp(driver, "drbg_pr_", 8)) +@@ -1796,7 +2203,7 @@ static int alg_test_drbg(const struct alg_test_desc *desc, const char *driver, + + } + +-static int do_test_kpp(struct crypto_kpp *tfm, struct kpp_testvec *vec, ++static int do_test_kpp(struct crypto_kpp *tfm, const struct kpp_testvec *vec, + const char *alg) + { + struct kpp_request *req; +@@ -1888,7 +2295,7 @@ static int do_test_kpp(struct crypto_kpp *tfm, struct kpp_testvec *vec, + } + + static int test_kpp(struct crypto_kpp *tfm, const char *alg, +- struct kpp_testvec *vecs, unsigned int tcount) ++ const struct kpp_testvec *vecs, unsigned int tcount) + { + int ret, i; + +@@ -1909,7 +2316,7 @@ static int alg_test_kpp(const struct alg_test_desc *desc, const char *driver, + struct crypto_kpp *tfm; + int err = 0; + +- tfm = crypto_alloc_kpp(driver, type | CRYPTO_ALG_INTERNAL, mask); ++ tfm = crypto_alloc_kpp(driver, type, mask); + if (IS_ERR(tfm)) { + pr_err("alg: kpp: Failed to load tfm for %s: %ld\n", + driver, PTR_ERR(tfm)); +@@ -1924,7 +2331,7 @@ static int alg_test_kpp(const struct alg_test_desc *desc, const char *driver, + } + + static int test_akcipher_one(struct crypto_akcipher *tfm, +- struct akcipher_testvec *vecs) ++ const struct akcipher_testvec *vecs) + { + char *xbuf[XBUFSIZE]; + struct akcipher_request *req; +@@ -2044,7 +2451,8 @@ static int test_akcipher_one(struct crypto_akcipher *tfm, + } + + static int test_akcipher(struct crypto_akcipher *tfm, const char *alg, +- struct akcipher_testvec *vecs, unsigned int tcount) ++ const struct akcipher_testvec *vecs, ++ unsigned int tcount) + { + const char *algo = + crypto_tfm_alg_driver_name(crypto_akcipher_tfm(tfm)); +@@ -2068,7 +2476,7 @@ static int alg_test_akcipher(const struct alg_test_desc *desc, + struct crypto_akcipher *tfm; + int err = 0; + +- tfm = crypto_alloc_akcipher(driver, type | CRYPTO_ALG_INTERNAL, mask); ++ tfm = crypto_alloc_akcipher(driver, type, mask); + if (IS_ERR(tfm)) { + pr_err("alg: akcipher: Failed to load tfm for %s: %ld\n", + driver, PTR_ERR(tfm)); +@@ -2088,112 +2496,23 @@ static int alg_test_null(const struct alg_test_desc *desc, + return 0; + } + ++#define __VECS(tv) { .vecs = tv, .count = ARRAY_SIZE(tv) } ++ + /* Please keep this list sorted by algorithm name. */ + static const struct alg_test_desc alg_test_descs[] = { + { +- .alg = "__cbc-cast5-avx", +- .test = alg_test_null, +- }, { +- .alg = "__cbc-cast6-avx", +- .test = alg_test_null, +- }, { +- .alg = "__cbc-serpent-avx", +- .test = alg_test_null, +- }, { +- .alg = "__cbc-serpent-avx2", +- .test = alg_test_null, +- }, { +- .alg = "__cbc-serpent-sse2", +- .test = alg_test_null, +- }, { +- .alg = "__cbc-twofish-avx", +- .test = alg_test_null, +- }, { +- .alg = "__driver-cbc-aes-aesni", +- .test = alg_test_null, +- .fips_allowed = 1, +- }, { +- .alg = "__driver-cbc-camellia-aesni", +- .test = alg_test_null, +- }, { +- .alg = "__driver-cbc-camellia-aesni-avx2", +- .test = alg_test_null, +- }, { +- .alg = "__driver-cbc-cast5-avx", +- .test = alg_test_null, +- }, { +- .alg = "__driver-cbc-cast6-avx", +- .test = alg_test_null, +- }, { +- .alg = "__driver-cbc-serpent-avx", +- .test = alg_test_null, +- }, { +- .alg = "__driver-cbc-serpent-avx2", +- .test = alg_test_null, +- }, { +- .alg = "__driver-cbc-serpent-sse2", +- .test = alg_test_null, +- }, { +- .alg = "__driver-cbc-twofish-avx", +- .test = alg_test_null, +- }, { +- .alg = "__driver-ecb-aes-aesni", +- .test = alg_test_null, +- .fips_allowed = 1, +- }, { +- .alg = "__driver-ecb-camellia-aesni", +- .test = alg_test_null, +- }, { +- .alg = "__driver-ecb-camellia-aesni-avx2", +- .test = alg_test_null, +- }, { +- .alg = "__driver-ecb-cast5-avx", +- .test = alg_test_null, +- }, { +- .alg = "__driver-ecb-cast6-avx", +- .test = alg_test_null, +- }, { +- .alg = "__driver-ecb-serpent-avx", +- .test = alg_test_null, +- }, { +- .alg = "__driver-ecb-serpent-avx2", +- .test = alg_test_null, +- }, { +- .alg = "__driver-ecb-serpent-sse2", +- .test = alg_test_null, +- }, { +- .alg = "__driver-ecb-twofish-avx", +- .test = alg_test_null, +- }, { +- .alg = "__driver-gcm-aes-aesni", +- .test = alg_test_null, +- .fips_allowed = 1, +- }, { +- .alg = "__ghash-pclmulqdqni", +- .test = alg_test_null, +- .fips_allowed = 1, +- }, { + .alg = "ansi_cprng", + .test = alg_test_cprng, + .suite = { +- .cprng = { +- .vecs = ansi_cprng_aes_tv_template, +- .count = ANSI_CPRNG_AES_TEST_VECTORS +- } ++ .cprng = __VECS(ansi_cprng_aes_tv_template) + } + }, { + .alg = "authenc(hmac(md5),ecb(cipher_null))", + .test = alg_test_aead, + .suite = { + .aead = { +- .enc = { +- .vecs = hmac_md5_ecb_cipher_null_enc_tv_template, +- .count = HMAC_MD5_ECB_CIPHER_NULL_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = hmac_md5_ecb_cipher_null_dec_tv_template, +- .count = HMAC_MD5_ECB_CIPHER_NULL_DEC_TEST_VECTORS +- } ++ .enc = __VECS(hmac_md5_ecb_cipher_null_enc_tv_template), ++ .dec = __VECS(hmac_md5_ecb_cipher_null_dec_tv_template) + } + } + }, { +@@ -2201,12 +2520,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_aead, + .suite = { + .aead = { +- .enc = { +- .vecs = +- hmac_sha1_aes_cbc_enc_tv_temp, +- .count = +- HMAC_SHA1_AES_CBC_ENC_TEST_VEC +- } ++ .enc = __VECS(hmac_sha1_aes_cbc_enc_tv_temp) + } + } + }, { +@@ -2214,12 +2528,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_aead, + .suite = { + .aead = { +- .enc = { +- .vecs = +- hmac_sha1_des_cbc_enc_tv_temp, +- .count = +- HMAC_SHA1_DES_CBC_ENC_TEST_VEC +- } ++ .enc = __VECS(hmac_sha1_des_cbc_enc_tv_temp) + } + } + }, { +@@ -2228,12 +2537,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .aead = { +- .enc = { +- .vecs = +- hmac_sha1_des3_ede_cbc_enc_tv_temp, +- .count = +- HMAC_SHA1_DES3_EDE_CBC_ENC_TEST_VEC +- } ++ .enc = __VECS(hmac_sha1_des3_ede_cbc_enc_tv_temp) + } + } + }, { +@@ -2245,18 +2549,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_aead, + .suite = { + .aead = { +- .enc = { +- .vecs = +- hmac_sha1_ecb_cipher_null_enc_tv_temp, +- .count = +- HMAC_SHA1_ECB_CIPHER_NULL_ENC_TEST_VEC +- }, +- .dec = { +- .vecs = +- hmac_sha1_ecb_cipher_null_dec_tv_temp, +- .count = +- HMAC_SHA1_ECB_CIPHER_NULL_DEC_TEST_VEC +- } ++ .enc = __VECS(hmac_sha1_ecb_cipher_null_enc_tv_temp), ++ .dec = __VECS(hmac_sha1_ecb_cipher_null_dec_tv_temp) + } + } + }, { +@@ -2268,12 +2562,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_aead, + .suite = { + .aead = { +- .enc = { +- .vecs = +- hmac_sha224_des_cbc_enc_tv_temp, +- .count = +- HMAC_SHA224_DES_CBC_ENC_TEST_VEC +- } ++ .enc = __VECS(hmac_sha224_des_cbc_enc_tv_temp) + } + } + }, { +@@ -2282,12 +2571,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .aead = { +- .enc = { +- .vecs = +- hmac_sha224_des3_ede_cbc_enc_tv_temp, +- .count = +- HMAC_SHA224_DES3_EDE_CBC_ENC_TEST_VEC +- } ++ .enc = __VECS(hmac_sha224_des3_ede_cbc_enc_tv_temp) + } + } + }, { +@@ -2296,12 +2580,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .aead = { +- .enc = { +- .vecs = +- hmac_sha256_aes_cbc_enc_tv_temp, +- .count = +- HMAC_SHA256_AES_CBC_ENC_TEST_VEC +- } ++ .enc = __VECS(hmac_sha256_aes_cbc_enc_tv_temp) + } + } + }, { +@@ -2309,12 +2588,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_aead, + .suite = { + .aead = { +- .enc = { +- .vecs = +- hmac_sha256_des_cbc_enc_tv_temp, +- .count = +- HMAC_SHA256_DES_CBC_ENC_TEST_VEC +- } ++ .enc = __VECS(hmac_sha256_des_cbc_enc_tv_temp) + } + } + }, { +@@ -2323,12 +2597,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .aead = { +- .enc = { +- .vecs = +- hmac_sha256_des3_ede_cbc_enc_tv_temp, +- .count = +- HMAC_SHA256_DES3_EDE_CBC_ENC_TEST_VEC +- } ++ .enc = __VECS(hmac_sha256_des3_ede_cbc_enc_tv_temp) + } + } + }, { +@@ -2344,12 +2613,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_aead, + .suite = { + .aead = { +- .enc = { +- .vecs = +- hmac_sha384_des_cbc_enc_tv_temp, +- .count = +- HMAC_SHA384_DES_CBC_ENC_TEST_VEC +- } ++ .enc = __VECS(hmac_sha384_des_cbc_enc_tv_temp) + } + } + }, { +@@ -2358,12 +2622,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .aead = { +- .enc = { +- .vecs = +- hmac_sha384_des3_ede_cbc_enc_tv_temp, +- .count = +- HMAC_SHA384_DES3_EDE_CBC_ENC_TEST_VEC +- } ++ .enc = __VECS(hmac_sha384_des3_ede_cbc_enc_tv_temp) + } + } + }, { +@@ -2380,12 +2639,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_aead, + .suite = { + .aead = { +- .enc = { +- .vecs = +- hmac_sha512_aes_cbc_enc_tv_temp, +- .count = +- HMAC_SHA512_AES_CBC_ENC_TEST_VEC +- } ++ .enc = __VECS(hmac_sha512_aes_cbc_enc_tv_temp) + } + } + }, { +@@ -2393,12 +2647,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_aead, + .suite = { + .aead = { +- .enc = { +- .vecs = +- hmac_sha512_des_cbc_enc_tv_temp, +- .count = +- HMAC_SHA512_DES_CBC_ENC_TEST_VEC +- } ++ .enc = __VECS(hmac_sha512_des_cbc_enc_tv_temp) + } + } + }, { +@@ -2407,12 +2656,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .aead = { +- .enc = { +- .vecs = +- hmac_sha512_des3_ede_cbc_enc_tv_temp, +- .count = +- HMAC_SHA512_DES3_EDE_CBC_ENC_TEST_VEC +- } ++ .enc = __VECS(hmac_sha512_des3_ede_cbc_enc_tv_temp) + } + } + }, { +@@ -2429,14 +2673,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .cipher = { +- .enc = { +- .vecs = aes_cbc_enc_tv_template, +- .count = AES_CBC_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = aes_cbc_dec_tv_template, +- .count = AES_CBC_DEC_TEST_VECTORS +- } ++ .enc = __VECS(aes_cbc_enc_tv_template), ++ .dec = __VECS(aes_cbc_dec_tv_template) + } + } + }, { +@@ -2444,14 +2682,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = anubis_cbc_enc_tv_template, +- .count = ANUBIS_CBC_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = anubis_cbc_dec_tv_template, +- .count = ANUBIS_CBC_DEC_TEST_VECTORS +- } ++ .enc = __VECS(anubis_cbc_enc_tv_template), ++ .dec = __VECS(anubis_cbc_dec_tv_template) + } + } + }, { +@@ -2459,14 +2691,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = bf_cbc_enc_tv_template, +- .count = BF_CBC_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = bf_cbc_dec_tv_template, +- .count = BF_CBC_DEC_TEST_VECTORS +- } ++ .enc = __VECS(bf_cbc_enc_tv_template), ++ .dec = __VECS(bf_cbc_dec_tv_template) + } + } + }, { +@@ -2474,14 +2700,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = camellia_cbc_enc_tv_template, +- .count = CAMELLIA_CBC_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = camellia_cbc_dec_tv_template, +- .count = CAMELLIA_CBC_DEC_TEST_VECTORS +- } ++ .enc = __VECS(camellia_cbc_enc_tv_template), ++ .dec = __VECS(camellia_cbc_dec_tv_template) + } + } + }, { +@@ -2489,14 +2709,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = cast5_cbc_enc_tv_template, +- .count = CAST5_CBC_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = cast5_cbc_dec_tv_template, +- .count = CAST5_CBC_DEC_TEST_VECTORS +- } ++ .enc = __VECS(cast5_cbc_enc_tv_template), ++ .dec = __VECS(cast5_cbc_dec_tv_template) + } + } + }, { +@@ -2504,14 +2718,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = cast6_cbc_enc_tv_template, +- .count = CAST6_CBC_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = cast6_cbc_dec_tv_template, +- .count = CAST6_CBC_DEC_TEST_VECTORS +- } ++ .enc = __VECS(cast6_cbc_enc_tv_template), ++ .dec = __VECS(cast6_cbc_dec_tv_template) + } + } + }, { +@@ -2519,14 +2727,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = des_cbc_enc_tv_template, +- .count = DES_CBC_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = des_cbc_dec_tv_template, +- .count = DES_CBC_DEC_TEST_VECTORS +- } ++ .enc = __VECS(des_cbc_enc_tv_template), ++ .dec = __VECS(des_cbc_dec_tv_template) + } + } + }, { +@@ -2535,14 +2737,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .cipher = { +- .enc = { +- .vecs = des3_ede_cbc_enc_tv_template, +- .count = DES3_EDE_CBC_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = des3_ede_cbc_dec_tv_template, +- .count = DES3_EDE_CBC_DEC_TEST_VECTORS +- } ++ .enc = __VECS(des3_ede_cbc_enc_tv_template), ++ .dec = __VECS(des3_ede_cbc_dec_tv_template) + } + } + }, { +@@ -2550,14 +2746,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = serpent_cbc_enc_tv_template, +- .count = SERPENT_CBC_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = serpent_cbc_dec_tv_template, +- .count = SERPENT_CBC_DEC_TEST_VECTORS +- } ++ .enc = __VECS(serpent_cbc_enc_tv_template), ++ .dec = __VECS(serpent_cbc_dec_tv_template) + } + } + }, { +@@ -2565,30 +2755,25 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = tf_cbc_enc_tv_template, +- .count = TF_CBC_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = tf_cbc_dec_tv_template, +- .count = TF_CBC_DEC_TEST_VECTORS +- } ++ .enc = __VECS(tf_cbc_enc_tv_template), ++ .dec = __VECS(tf_cbc_dec_tv_template) + } + } ++ }, { ++ .alg = "cbcmac(aes)", ++ .fips_allowed = 1, ++ .test = alg_test_hash, ++ .suite = { ++ .hash = __VECS(aes_cbcmac_tv_template) ++ } + }, { + .alg = "ccm(aes)", + .test = alg_test_aead, + .fips_allowed = 1, + .suite = { + .aead = { +- .enc = { +- .vecs = aes_ccm_enc_tv_template, +- .count = AES_CCM_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = aes_ccm_dec_tv_template, +- .count = AES_CCM_DEC_TEST_VECTORS +- } ++ .enc = __VECS(aes_ccm_enc_tv_template), ++ .dec = __VECS(aes_ccm_dec_tv_template) + } + } + }, { +@@ -2596,14 +2781,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = chacha20_enc_tv_template, +- .count = CHACHA20_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = chacha20_enc_tv_template, +- .count = CHACHA20_ENC_TEST_VECTORS +- }, ++ .enc = __VECS(chacha20_enc_tv_template), ++ .dec = __VECS(chacha20_enc_tv_template), + } + } + }, { +@@ -2611,20 +2790,14 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = aes_cmac128_tv_template, +- .count = CMAC_AES_TEST_VECTORS +- } ++ .hash = __VECS(aes_cmac128_tv_template) + } + }, { + .alg = "cmac(des3_ede)", + .fips_allowed = 1, + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = des3_ede_cmac64_tv_template, +- .count = CMAC_DES3_EDE_TEST_VECTORS +- } ++ .hash = __VECS(des3_ede_cmac64_tv_template) + } + }, { + .alg = "compress_null", +@@ -2633,94 +2806,30 @@ static const struct alg_test_desc alg_test_descs[] = { + .alg = "crc32", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = crc32_tv_template, +- .count = CRC32_TEST_VECTORS +- } ++ .hash = __VECS(crc32_tv_template) + } + }, { + .alg = "crc32c", + .test = alg_test_crc32c, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = crc32c_tv_template, +- .count = CRC32C_TEST_VECTORS +- } ++ .hash = __VECS(crc32c_tv_template) + } + }, { + .alg = "crct10dif", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = crct10dif_tv_template, +- .count = CRCT10DIF_TEST_VECTORS +- } ++ .hash = __VECS(crct10dif_tv_template) + } +- }, { +- .alg = "cryptd(__driver-cbc-aes-aesni)", +- .test = alg_test_null, +- .fips_allowed = 1, +- }, { +- .alg = "cryptd(__driver-cbc-camellia-aesni)", +- .test = alg_test_null, +- }, { +- .alg = "cryptd(__driver-cbc-camellia-aesni-avx2)", +- .test = alg_test_null, +- }, { +- .alg = "cryptd(__driver-cbc-serpent-avx2)", +- .test = alg_test_null, +- }, { +- .alg = "cryptd(__driver-ecb-aes-aesni)", +- .test = alg_test_null, +- .fips_allowed = 1, +- }, { +- .alg = "cryptd(__driver-ecb-camellia-aesni)", +- .test = alg_test_null, +- }, { +- .alg = "cryptd(__driver-ecb-camellia-aesni-avx2)", +- .test = alg_test_null, +- }, { +- .alg = "cryptd(__driver-ecb-cast5-avx)", +- .test = alg_test_null, +- }, { +- .alg = "cryptd(__driver-ecb-cast6-avx)", +- .test = alg_test_null, +- }, { +- .alg = "cryptd(__driver-ecb-serpent-avx)", +- .test = alg_test_null, +- }, { +- .alg = "cryptd(__driver-ecb-serpent-avx2)", +- .test = alg_test_null, +- }, { +- .alg = "cryptd(__driver-ecb-serpent-sse2)", +- .test = alg_test_null, +- }, { +- .alg = "cryptd(__driver-ecb-twofish-avx)", +- .test = alg_test_null, +- }, { +- .alg = "cryptd(__driver-gcm-aes-aesni)", +- .test = alg_test_null, +- .fips_allowed = 1, +- }, { +- .alg = "cryptd(__ghash-pclmulqdqni)", +- .test = alg_test_null, +- .fips_allowed = 1, + }, { + .alg = "ctr(aes)", + .test = alg_test_skcipher, + .fips_allowed = 1, + .suite = { + .cipher = { +- .enc = { +- .vecs = aes_ctr_enc_tv_template, +- .count = AES_CTR_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = aes_ctr_dec_tv_template, +- .count = AES_CTR_DEC_TEST_VECTORS +- } ++ .enc = __VECS(aes_ctr_enc_tv_template), ++ .dec = __VECS(aes_ctr_dec_tv_template) + } + } + }, { +@@ -2728,14 +2837,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = bf_ctr_enc_tv_template, +- .count = BF_CTR_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = bf_ctr_dec_tv_template, +- .count = BF_CTR_DEC_TEST_VECTORS +- } ++ .enc = __VECS(bf_ctr_enc_tv_template), ++ .dec = __VECS(bf_ctr_dec_tv_template) + } + } + }, { +@@ -2743,14 +2846,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = camellia_ctr_enc_tv_template, +- .count = CAMELLIA_CTR_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = camellia_ctr_dec_tv_template, +- .count = CAMELLIA_CTR_DEC_TEST_VECTORS +- } ++ .enc = __VECS(camellia_ctr_enc_tv_template), ++ .dec = __VECS(camellia_ctr_dec_tv_template) + } + } + }, { +@@ -2758,14 +2855,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = cast5_ctr_enc_tv_template, +- .count = CAST5_CTR_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = cast5_ctr_dec_tv_template, +- .count = CAST5_CTR_DEC_TEST_VECTORS +- } ++ .enc = __VECS(cast5_ctr_enc_tv_template), ++ .dec = __VECS(cast5_ctr_dec_tv_template) + } + } + }, { +@@ -2773,14 +2864,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = cast6_ctr_enc_tv_template, +- .count = CAST6_CTR_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = cast6_ctr_dec_tv_template, +- .count = CAST6_CTR_DEC_TEST_VECTORS +- } ++ .enc = __VECS(cast6_ctr_enc_tv_template), ++ .dec = __VECS(cast6_ctr_dec_tv_template) + } + } + }, { +@@ -2788,29 +2873,18 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = des_ctr_enc_tv_template, +- .count = DES_CTR_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = des_ctr_dec_tv_template, +- .count = DES_CTR_DEC_TEST_VECTORS +- } ++ .enc = __VECS(des_ctr_enc_tv_template), ++ .dec = __VECS(des_ctr_dec_tv_template) + } + } + }, { + .alg = "ctr(des3_ede)", + .test = alg_test_skcipher, ++ .fips_allowed = 1, + .suite = { + .cipher = { +- .enc = { +- .vecs = des3_ede_ctr_enc_tv_template, +- .count = DES3_EDE_CTR_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = des3_ede_ctr_dec_tv_template, +- .count = DES3_EDE_CTR_DEC_TEST_VECTORS +- } ++ .enc = __VECS(des3_ede_ctr_enc_tv_template), ++ .dec = __VECS(des3_ede_ctr_dec_tv_template) + } + } + }, { +@@ -2818,14 +2892,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = serpent_ctr_enc_tv_template, +- .count = SERPENT_CTR_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = serpent_ctr_dec_tv_template, +- .count = SERPENT_CTR_DEC_TEST_VECTORS +- } ++ .enc = __VECS(serpent_ctr_enc_tv_template), ++ .dec = __VECS(serpent_ctr_dec_tv_template) + } + } + }, { +@@ -2833,14 +2901,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = tf_ctr_enc_tv_template, +- .count = TF_CTR_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = tf_ctr_dec_tv_template, +- .count = TF_CTR_DEC_TEST_VECTORS +- } ++ .enc = __VECS(tf_ctr_enc_tv_template), ++ .dec = __VECS(tf_ctr_dec_tv_template) + } + } + }, { +@@ -2848,14 +2910,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = cts_mode_enc_tv_template, +- .count = CTS_MODE_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = cts_mode_dec_tv_template, +- .count = CTS_MODE_DEC_TEST_VECTORS +- } ++ .enc = __VECS(cts_mode_enc_tv_template), ++ .dec = __VECS(cts_mode_dec_tv_template) + } + } + }, { +@@ -2864,14 +2920,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .comp = { +- .comp = { +- .vecs = deflate_comp_tv_template, +- .count = DEFLATE_COMP_TEST_VECTORS +- }, +- .decomp = { +- .vecs = deflate_decomp_tv_template, +- .count = DEFLATE_DECOMP_TEST_VECTORS +- } ++ .comp = __VECS(deflate_comp_tv_template), ++ .decomp = __VECS(deflate_decomp_tv_template) + } + } + }, { +@@ -2879,10 +2929,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_kpp, + .fips_allowed = 1, + .suite = { +- .kpp = { +- .vecs = dh_tv_template, +- .count = DH_TEST_VECTORS +- } ++ .kpp = __VECS(dh_tv_template) + } + }, { + .alg = "digest_null", +@@ -2892,30 +2939,21 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_drbg, + .fips_allowed = 1, + .suite = { +- .drbg = { +- .vecs = drbg_nopr_ctr_aes128_tv_template, +- .count = ARRAY_SIZE(drbg_nopr_ctr_aes128_tv_template) +- } ++ .drbg = __VECS(drbg_nopr_ctr_aes128_tv_template) + } + }, { + .alg = "drbg_nopr_ctr_aes192", + .test = alg_test_drbg, + .fips_allowed = 1, + .suite = { +- .drbg = { +- .vecs = drbg_nopr_ctr_aes192_tv_template, +- .count = ARRAY_SIZE(drbg_nopr_ctr_aes192_tv_template) +- } ++ .drbg = __VECS(drbg_nopr_ctr_aes192_tv_template) + } + }, { + .alg = "drbg_nopr_ctr_aes256", + .test = alg_test_drbg, + .fips_allowed = 1, + .suite = { +- .drbg = { +- .vecs = drbg_nopr_ctr_aes256_tv_template, +- .count = ARRAY_SIZE(drbg_nopr_ctr_aes256_tv_template) +- } ++ .drbg = __VECS(drbg_nopr_ctr_aes256_tv_template) + } + }, { + /* +@@ -2930,11 +2968,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_drbg, + .fips_allowed = 1, + .suite = { +- .drbg = { +- .vecs = drbg_nopr_hmac_sha256_tv_template, +- .count = +- ARRAY_SIZE(drbg_nopr_hmac_sha256_tv_template) +- } ++ .drbg = __VECS(drbg_nopr_hmac_sha256_tv_template) + } + }, { + /* covered by drbg_nopr_hmac_sha256 test */ +@@ -2954,10 +2988,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_drbg, + .fips_allowed = 1, + .suite = { +- .drbg = { +- .vecs = drbg_nopr_sha256_tv_template, +- .count = ARRAY_SIZE(drbg_nopr_sha256_tv_template) +- } ++ .drbg = __VECS(drbg_nopr_sha256_tv_template) + } + }, { + /* covered by drbg_nopr_sha256 test */ +@@ -2973,10 +3004,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_drbg, + .fips_allowed = 1, + .suite = { +- .drbg = { +- .vecs = drbg_pr_ctr_aes128_tv_template, +- .count = ARRAY_SIZE(drbg_pr_ctr_aes128_tv_template) +- } ++ .drbg = __VECS(drbg_pr_ctr_aes128_tv_template) + } + }, { + /* covered by drbg_pr_ctr_aes128 test */ +@@ -2996,10 +3024,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_drbg, + .fips_allowed = 1, + .suite = { +- .drbg = { +- .vecs = drbg_pr_hmac_sha256_tv_template, +- .count = ARRAY_SIZE(drbg_pr_hmac_sha256_tv_template) +- } ++ .drbg = __VECS(drbg_pr_hmac_sha256_tv_template) + } + }, { + /* covered by drbg_pr_hmac_sha256 test */ +@@ -3019,10 +3044,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_drbg, + .fips_allowed = 1, + .suite = { +- .drbg = { +- .vecs = drbg_pr_sha256_tv_template, +- .count = ARRAY_SIZE(drbg_pr_sha256_tv_template) +- } ++ .drbg = __VECS(drbg_pr_sha256_tv_template) + } + }, { + /* covered by drbg_pr_sha256 test */ +@@ -3033,24 +3055,14 @@ static const struct alg_test_desc alg_test_descs[] = { + .alg = "drbg_pr_sha512", + .fips_allowed = 1, + .test = alg_test_null, +- }, { +- .alg = "ecb(__aes-aesni)", +- .test = alg_test_null, +- .fips_allowed = 1, + }, { + .alg = "ecb(aes)", + .test = alg_test_skcipher, + .fips_allowed = 1, + .suite = { + .cipher = { +- .enc = { +- .vecs = aes_enc_tv_template, +- .count = AES_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = aes_dec_tv_template, +- .count = AES_DEC_TEST_VECTORS +- } ++ .enc = __VECS(aes_enc_tv_template), ++ .dec = __VECS(aes_dec_tv_template) + } + } + }, { +@@ -3058,14 +3070,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = anubis_enc_tv_template, +- .count = ANUBIS_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = anubis_dec_tv_template, +- .count = ANUBIS_DEC_TEST_VECTORS +- } ++ .enc = __VECS(anubis_enc_tv_template), ++ .dec = __VECS(anubis_dec_tv_template) + } + } + }, { +@@ -3073,14 +3079,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = arc4_enc_tv_template, +- .count = ARC4_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = arc4_dec_tv_template, +- .count = ARC4_DEC_TEST_VECTORS +- } ++ .enc = __VECS(arc4_enc_tv_template), ++ .dec = __VECS(arc4_dec_tv_template) + } + } + }, { +@@ -3088,14 +3088,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = bf_enc_tv_template, +- .count = BF_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = bf_dec_tv_template, +- .count = BF_DEC_TEST_VECTORS +- } ++ .enc = __VECS(bf_enc_tv_template), ++ .dec = __VECS(bf_dec_tv_template) + } + } + }, { +@@ -3103,14 +3097,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = camellia_enc_tv_template, +- .count = CAMELLIA_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = camellia_dec_tv_template, +- .count = CAMELLIA_DEC_TEST_VECTORS +- } ++ .enc = __VECS(camellia_enc_tv_template), ++ .dec = __VECS(camellia_dec_tv_template) + } + } + }, { +@@ -3118,14 +3106,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = cast5_enc_tv_template, +- .count = CAST5_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = cast5_dec_tv_template, +- .count = CAST5_DEC_TEST_VECTORS +- } ++ .enc = __VECS(cast5_enc_tv_template), ++ .dec = __VECS(cast5_dec_tv_template) + } + } + }, { +@@ -3133,14 +3115,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = cast6_enc_tv_template, +- .count = CAST6_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = cast6_dec_tv_template, +- .count = CAST6_DEC_TEST_VECTORS +- } ++ .enc = __VECS(cast6_enc_tv_template), ++ .dec = __VECS(cast6_dec_tv_template) + } + } + }, { +@@ -3151,14 +3127,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = des_enc_tv_template, +- .count = DES_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = des_dec_tv_template, +- .count = DES_DEC_TEST_VECTORS +- } ++ .enc = __VECS(des_enc_tv_template), ++ .dec = __VECS(des_dec_tv_template) + } + } + }, { +@@ -3167,14 +3137,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .cipher = { +- .enc = { +- .vecs = des3_ede_enc_tv_template, +- .count = DES3_EDE_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = des3_ede_dec_tv_template, +- .count = DES3_EDE_DEC_TEST_VECTORS +- } ++ .enc = __VECS(des3_ede_enc_tv_template), ++ .dec = __VECS(des3_ede_dec_tv_template) + } + } + }, { +@@ -3197,14 +3161,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = khazad_enc_tv_template, +- .count = KHAZAD_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = khazad_dec_tv_template, +- .count = KHAZAD_DEC_TEST_VECTORS +- } ++ .enc = __VECS(khazad_enc_tv_template), ++ .dec = __VECS(khazad_dec_tv_template) + } + } + }, { +@@ -3212,14 +3170,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = seed_enc_tv_template, +- .count = SEED_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = seed_dec_tv_template, +- .count = SEED_DEC_TEST_VECTORS +- } ++ .enc = __VECS(seed_enc_tv_template), ++ .dec = __VECS(seed_dec_tv_template) + } + } + }, { +@@ -3227,14 +3179,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = serpent_enc_tv_template, +- .count = SERPENT_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = serpent_dec_tv_template, +- .count = SERPENT_DEC_TEST_VECTORS +- } ++ .enc = __VECS(serpent_enc_tv_template), ++ .dec = __VECS(serpent_dec_tv_template) + } + } + }, { +@@ -3242,14 +3188,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = tea_enc_tv_template, +- .count = TEA_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = tea_dec_tv_template, +- .count = TEA_DEC_TEST_VECTORS +- } ++ .enc = __VECS(tea_enc_tv_template), ++ .dec = __VECS(tea_dec_tv_template) + } + } + }, { +@@ -3257,14 +3197,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = tnepres_enc_tv_template, +- .count = TNEPRES_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = tnepres_dec_tv_template, +- .count = TNEPRES_DEC_TEST_VECTORS +- } ++ .enc = __VECS(tnepres_enc_tv_template), ++ .dec = __VECS(tnepres_dec_tv_template) + } + } + }, { +@@ -3272,14 +3206,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = tf_enc_tv_template, +- .count = TF_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = tf_dec_tv_template, +- .count = TF_DEC_TEST_VECTORS +- } ++ .enc = __VECS(tf_enc_tv_template), ++ .dec = __VECS(tf_dec_tv_template) + } + } + }, { +@@ -3287,14 +3215,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = xeta_enc_tv_template, +- .count = XETA_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = xeta_dec_tv_template, +- .count = XETA_DEC_TEST_VECTORS +- } ++ .enc = __VECS(xeta_enc_tv_template), ++ .dec = __VECS(xeta_dec_tv_template) + } + } + }, { +@@ -3302,14 +3224,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = xtea_enc_tv_template, +- .count = XTEA_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = xtea_dec_tv_template, +- .count = XTEA_DEC_TEST_VECTORS +- } ++ .enc = __VECS(xtea_enc_tv_template), ++ .dec = __VECS(xtea_dec_tv_template) + } + } + }, { +@@ -3317,10 +3233,7 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_kpp, + .fips_allowed = 1, + .suite = { +- .kpp = { +- .vecs = ecdh_tv_template, +- .count = ECDH_TEST_VECTORS +- } ++ .kpp = __VECS(ecdh_tv_template) + } + }, { + .alg = "gcm(aes)", +@@ -3328,14 +3241,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .aead = { +- .enc = { +- .vecs = aes_gcm_enc_tv_template, +- .count = AES_GCM_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = aes_gcm_dec_tv_template, +- .count = AES_GCM_DEC_TEST_VECTORS +- } ++ .enc = __VECS(aes_gcm_enc_tv_template), ++ .dec = __VECS(aes_gcm_dec_tv_template) + } + } + }, { +@@ -3343,136 +3250,94 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = ghash_tv_template, +- .count = GHASH_TEST_VECTORS +- } ++ .hash = __VECS(ghash_tv_template) + } + }, { + .alg = "hmac(crc32)", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = bfin_crc_tv_template, +- .count = BFIN_CRC_TEST_VECTORS +- } ++ .hash = __VECS(bfin_crc_tv_template) + } + }, { + .alg = "hmac(md5)", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = hmac_md5_tv_template, +- .count = HMAC_MD5_TEST_VECTORS +- } ++ .hash = __VECS(hmac_md5_tv_template) + } + }, { + .alg = "hmac(rmd128)", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = hmac_rmd128_tv_template, +- .count = HMAC_RMD128_TEST_VECTORS +- } ++ .hash = __VECS(hmac_rmd128_tv_template) + } + }, { + .alg = "hmac(rmd160)", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = hmac_rmd160_tv_template, +- .count = HMAC_RMD160_TEST_VECTORS +- } ++ .hash = __VECS(hmac_rmd160_tv_template) + } + }, { + .alg = "hmac(sha1)", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = hmac_sha1_tv_template, +- .count = HMAC_SHA1_TEST_VECTORS +- } ++ .hash = __VECS(hmac_sha1_tv_template) + } + }, { + .alg = "hmac(sha224)", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = hmac_sha224_tv_template, +- .count = HMAC_SHA224_TEST_VECTORS +- } ++ .hash = __VECS(hmac_sha224_tv_template) + } + }, { + .alg = "hmac(sha256)", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = hmac_sha256_tv_template, +- .count = HMAC_SHA256_TEST_VECTORS +- } ++ .hash = __VECS(hmac_sha256_tv_template) + } + }, { + .alg = "hmac(sha3-224)", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = hmac_sha3_224_tv_template, +- .count = HMAC_SHA3_224_TEST_VECTORS +- } ++ .hash = __VECS(hmac_sha3_224_tv_template) + } + }, { + .alg = "hmac(sha3-256)", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = hmac_sha3_256_tv_template, +- .count = HMAC_SHA3_256_TEST_VECTORS +- } ++ .hash = __VECS(hmac_sha3_256_tv_template) + } + }, { + .alg = "hmac(sha3-384)", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = hmac_sha3_384_tv_template, +- .count = HMAC_SHA3_384_TEST_VECTORS +- } ++ .hash = __VECS(hmac_sha3_384_tv_template) + } + }, { + .alg = "hmac(sha3-512)", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = hmac_sha3_512_tv_template, +- .count = HMAC_SHA3_512_TEST_VECTORS +- } ++ .hash = __VECS(hmac_sha3_512_tv_template) + } + }, { + .alg = "hmac(sha384)", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = hmac_sha384_tv_template, +- .count = HMAC_SHA384_TEST_VECTORS +- } ++ .hash = __VECS(hmac_sha384_tv_template) + } + }, { + .alg = "hmac(sha512)", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = hmac_sha512_tv_template, +- .count = HMAC_SHA512_TEST_VECTORS +- } ++ .hash = __VECS(hmac_sha512_tv_template) + } + }, { + .alg = "jitterentropy_rng", +@@ -3484,14 +3349,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .cipher = { +- .enc = { +- .vecs = aes_kw_enc_tv_template, +- .count = ARRAY_SIZE(aes_kw_enc_tv_template) +- }, +- .dec = { +- .vecs = aes_kw_dec_tv_template, +- .count = ARRAY_SIZE(aes_kw_dec_tv_template) +- } ++ .enc = __VECS(aes_kw_enc_tv_template), ++ .dec = __VECS(aes_kw_dec_tv_template) + } + } + }, { +@@ -3499,14 +3358,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = aes_lrw_enc_tv_template, +- .count = AES_LRW_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = aes_lrw_dec_tv_template, +- .count = AES_LRW_DEC_TEST_VECTORS +- } ++ .enc = __VECS(aes_lrw_enc_tv_template), ++ .dec = __VECS(aes_lrw_dec_tv_template) + } + } + }, { +@@ -3514,14 +3367,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = camellia_lrw_enc_tv_template, +- .count = CAMELLIA_LRW_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = camellia_lrw_dec_tv_template, +- .count = CAMELLIA_LRW_DEC_TEST_VECTORS +- } ++ .enc = __VECS(camellia_lrw_enc_tv_template), ++ .dec = __VECS(camellia_lrw_dec_tv_template) + } + } + }, { +@@ -3529,14 +3376,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = cast6_lrw_enc_tv_template, +- .count = CAST6_LRW_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = cast6_lrw_dec_tv_template, +- .count = CAST6_LRW_DEC_TEST_VECTORS +- } ++ .enc = __VECS(cast6_lrw_enc_tv_template), ++ .dec = __VECS(cast6_lrw_dec_tv_template) + } + } + }, { +@@ -3544,14 +3385,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = serpent_lrw_enc_tv_template, +- .count = SERPENT_LRW_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = serpent_lrw_dec_tv_template, +- .count = SERPENT_LRW_DEC_TEST_VECTORS +- } ++ .enc = __VECS(serpent_lrw_enc_tv_template), ++ .dec = __VECS(serpent_lrw_dec_tv_template) + } + } + }, { +@@ -3559,14 +3394,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = tf_lrw_enc_tv_template, +- .count = TF_LRW_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = tf_lrw_dec_tv_template, +- .count = TF_LRW_DEC_TEST_VECTORS +- } ++ .enc = __VECS(tf_lrw_enc_tv_template), ++ .dec = __VECS(tf_lrw_dec_tv_template) + } + } + }, { +@@ -3575,14 +3404,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .comp = { +- .comp = { +- .vecs = lz4_comp_tv_template, +- .count = LZ4_COMP_TEST_VECTORS +- }, +- .decomp = { +- .vecs = lz4_decomp_tv_template, +- .count = LZ4_DECOMP_TEST_VECTORS +- } ++ .comp = __VECS(lz4_comp_tv_template), ++ .decomp = __VECS(lz4_decomp_tv_template) + } + } + }, { +@@ -3591,14 +3414,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .comp = { +- .comp = { +- .vecs = lz4hc_comp_tv_template, +- .count = LZ4HC_COMP_TEST_VECTORS +- }, +- .decomp = { +- .vecs = lz4hc_decomp_tv_template, +- .count = LZ4HC_DECOMP_TEST_VECTORS +- } ++ .comp = __VECS(lz4hc_comp_tv_template), ++ .decomp = __VECS(lz4hc_decomp_tv_template) + } + } + }, { +@@ -3607,42 +3424,27 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .comp = { +- .comp = { +- .vecs = lzo_comp_tv_template, +- .count = LZO_COMP_TEST_VECTORS +- }, +- .decomp = { +- .vecs = lzo_decomp_tv_template, +- .count = LZO_DECOMP_TEST_VECTORS +- } ++ .comp = __VECS(lzo_comp_tv_template), ++ .decomp = __VECS(lzo_decomp_tv_template) + } + } + }, { + .alg = "md4", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = md4_tv_template, +- .count = MD4_TEST_VECTORS +- } ++ .hash = __VECS(md4_tv_template) + } + }, { + .alg = "md5", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = md5_tv_template, +- .count = MD5_TEST_VECTORS +- } ++ .hash = __VECS(md5_tv_template) + } + }, { + .alg = "michael_mic", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = michael_mic_tv_template, +- .count = MICHAEL_MIC_TEST_VECTORS +- } ++ .hash = __VECS(michael_mic_tv_template) + } + }, { + .alg = "ofb(aes)", +@@ -3650,14 +3452,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .cipher = { +- .enc = { +- .vecs = aes_ofb_enc_tv_template, +- .count = AES_OFB_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = aes_ofb_dec_tv_template, +- .count = AES_OFB_DEC_TEST_VECTORS +- } ++ .enc = __VECS(aes_ofb_enc_tv_template), ++ .dec = __VECS(aes_ofb_dec_tv_template) + } + } + }, { +@@ -3665,24 +3461,15 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = fcrypt_pcbc_enc_tv_template, +- .count = FCRYPT_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = fcrypt_pcbc_dec_tv_template, +- .count = FCRYPT_DEC_TEST_VECTORS +- } ++ .enc = __VECS(fcrypt_pcbc_enc_tv_template), ++ .dec = __VECS(fcrypt_pcbc_dec_tv_template) + } + } + }, { + .alg = "poly1305", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = poly1305_tv_template, +- .count = POLY1305_TEST_VECTORS +- } ++ .hash = __VECS(poly1305_tv_template) + } + }, { + .alg = "rfc3686(ctr(aes))", +@@ -3690,14 +3477,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .cipher = { +- .enc = { +- .vecs = aes_ctr_rfc3686_enc_tv_template, +- .count = AES_CTR_3686_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = aes_ctr_rfc3686_dec_tv_template, +- .count = AES_CTR_3686_DEC_TEST_VECTORS +- } ++ .enc = __VECS(aes_ctr_rfc3686_enc_tv_template), ++ .dec = __VECS(aes_ctr_rfc3686_dec_tv_template) + } + } + }, { +@@ -3706,14 +3487,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .aead = { +- .enc = { +- .vecs = aes_gcm_rfc4106_enc_tv_template, +- .count = AES_GCM_4106_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = aes_gcm_rfc4106_dec_tv_template, +- .count = AES_GCM_4106_DEC_TEST_VECTORS +- } ++ .enc = __VECS(aes_gcm_rfc4106_enc_tv_template), ++ .dec = __VECS(aes_gcm_rfc4106_dec_tv_template) + } + } + }, { +@@ -3722,14 +3497,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .aead = { +- .enc = { +- .vecs = aes_ccm_rfc4309_enc_tv_template, +- .count = AES_CCM_4309_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = aes_ccm_rfc4309_dec_tv_template, +- .count = AES_CCM_4309_DEC_TEST_VECTORS +- } ++ .enc = __VECS(aes_ccm_rfc4309_enc_tv_template), ++ .dec = __VECS(aes_ccm_rfc4309_dec_tv_template) + } + } + }, { +@@ -3737,14 +3506,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_aead, + .suite = { + .aead = { +- .enc = { +- .vecs = aes_gcm_rfc4543_enc_tv_template, +- .count = AES_GCM_4543_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = aes_gcm_rfc4543_dec_tv_template, +- .count = AES_GCM_4543_DEC_TEST_VECTORS +- }, ++ .enc = __VECS(aes_gcm_rfc4543_enc_tv_template), ++ .dec = __VECS(aes_gcm_rfc4543_dec_tv_template), + } + } + }, { +@@ -3752,14 +3515,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_aead, + .suite = { + .aead = { +- .enc = { +- .vecs = rfc7539_enc_tv_template, +- .count = RFC7539_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = rfc7539_dec_tv_template, +- .count = RFC7539_DEC_TEST_VECTORS +- }, ++ .enc = __VECS(rfc7539_enc_tv_template), ++ .dec = __VECS(rfc7539_dec_tv_template), + } + } + }, { +@@ -3767,71 +3524,47 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_aead, + .suite = { + .aead = { +- .enc = { +- .vecs = rfc7539esp_enc_tv_template, +- .count = RFC7539ESP_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = rfc7539esp_dec_tv_template, +- .count = RFC7539ESP_DEC_TEST_VECTORS +- }, ++ .enc = __VECS(rfc7539esp_enc_tv_template), ++ .dec = __VECS(rfc7539esp_dec_tv_template), + } + } + }, { + .alg = "rmd128", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = rmd128_tv_template, +- .count = RMD128_TEST_VECTORS +- } ++ .hash = __VECS(rmd128_tv_template) + } + }, { + .alg = "rmd160", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = rmd160_tv_template, +- .count = RMD160_TEST_VECTORS +- } ++ .hash = __VECS(rmd160_tv_template) + } + }, { + .alg = "rmd256", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = rmd256_tv_template, +- .count = RMD256_TEST_VECTORS +- } ++ .hash = __VECS(rmd256_tv_template) + } + }, { + .alg = "rmd320", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = rmd320_tv_template, +- .count = RMD320_TEST_VECTORS +- } ++ .hash = __VECS(rmd320_tv_template) + } + }, { + .alg = "rsa", + .test = alg_test_akcipher, + .fips_allowed = 1, + .suite = { +- .akcipher = { +- .vecs = rsa_tv_template, +- .count = RSA_TEST_VECTORS +- } ++ .akcipher = __VECS(rsa_tv_template) + } + }, { + .alg = "salsa20", + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = salsa20_stream_enc_tv_template, +- .count = SALSA20_STREAM_ENC_TEST_VECTORS +- } ++ .enc = __VECS(salsa20_stream_enc_tv_template) + } + } + }, { +@@ -3839,162 +3572,120 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = sha1_tv_template, +- .count = SHA1_TEST_VECTORS +- } ++ .hash = __VECS(sha1_tv_template) + } + }, { + .alg = "sha224", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = sha224_tv_template, +- .count = SHA224_TEST_VECTORS +- } ++ .hash = __VECS(sha224_tv_template) + } + }, { + .alg = "sha256", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = sha256_tv_template, +- .count = SHA256_TEST_VECTORS +- } ++ .hash = __VECS(sha256_tv_template) + } + }, { + .alg = "sha3-224", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = sha3_224_tv_template, +- .count = SHA3_224_TEST_VECTORS +- } ++ .hash = __VECS(sha3_224_tv_template) + } + }, { + .alg = "sha3-256", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = sha3_256_tv_template, +- .count = SHA3_256_TEST_VECTORS +- } ++ .hash = __VECS(sha3_256_tv_template) + } + }, { + .alg = "sha3-384", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = sha3_384_tv_template, +- .count = SHA3_384_TEST_VECTORS +- } ++ .hash = __VECS(sha3_384_tv_template) + } + }, { + .alg = "sha3-512", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = sha3_512_tv_template, +- .count = SHA3_512_TEST_VECTORS +- } ++ .hash = __VECS(sha3_512_tv_template) + } + }, { + .alg = "sha384", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = sha384_tv_template, +- .count = SHA384_TEST_VECTORS +- } ++ .hash = __VECS(sha384_tv_template) + } + }, { + .alg = "sha512", + .test = alg_test_hash, + .fips_allowed = 1, + .suite = { +- .hash = { +- .vecs = sha512_tv_template, +- .count = SHA512_TEST_VECTORS +- } ++ .hash = __VECS(sha512_tv_template) + } + }, { + .alg = "tgr128", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = tgr128_tv_template, +- .count = TGR128_TEST_VECTORS +- } ++ .hash = __VECS(tgr128_tv_template) + } + }, { + .alg = "tgr160", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = tgr160_tv_template, +- .count = TGR160_TEST_VECTORS +- } ++ .hash = __VECS(tgr160_tv_template) + } + }, { + .alg = "tgr192", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = tgr192_tv_template, +- .count = TGR192_TEST_VECTORS ++ .hash = __VECS(tgr192_tv_template) ++ } ++ }, { ++ .alg = "tls10(hmac(sha1),cbc(aes))", ++ .test = alg_test_tls, ++ .suite = { ++ .tls = { ++ .enc = __VECS(tls_enc_tv_template), ++ .dec = __VECS(tls_dec_tv_template) + } + } + }, { + .alg = "vmac(aes)", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = aes_vmac128_tv_template, +- .count = VMAC_AES_TEST_VECTORS +- } ++ .hash = __VECS(aes_vmac128_tv_template) + } + }, { + .alg = "wp256", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = wp256_tv_template, +- .count = WP256_TEST_VECTORS +- } ++ .hash = __VECS(wp256_tv_template) + } + }, { + .alg = "wp384", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = wp384_tv_template, +- .count = WP384_TEST_VECTORS +- } ++ .hash = __VECS(wp384_tv_template) + } + }, { + .alg = "wp512", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = wp512_tv_template, +- .count = WP512_TEST_VECTORS +- } ++ .hash = __VECS(wp512_tv_template) + } + }, { + .alg = "xcbc(aes)", + .test = alg_test_hash, + .suite = { +- .hash = { +- .vecs = aes_xcbc128_tv_template, +- .count = XCBC_AES_TEST_VECTORS +- } ++ .hash = __VECS(aes_xcbc128_tv_template) + } + }, { + .alg = "xts(aes)", +@@ -4002,14 +3693,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .fips_allowed = 1, + .suite = { + .cipher = { +- .enc = { +- .vecs = aes_xts_enc_tv_template, +- .count = AES_XTS_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = aes_xts_dec_tv_template, +- .count = AES_XTS_DEC_TEST_VECTORS +- } ++ .enc = __VECS(aes_xts_enc_tv_template), ++ .dec = __VECS(aes_xts_dec_tv_template) + } + } + }, { +@@ -4017,14 +3702,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = camellia_xts_enc_tv_template, +- .count = CAMELLIA_XTS_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = camellia_xts_dec_tv_template, +- .count = CAMELLIA_XTS_DEC_TEST_VECTORS +- } ++ .enc = __VECS(camellia_xts_enc_tv_template), ++ .dec = __VECS(camellia_xts_dec_tv_template) + } + } + }, { +@@ -4032,14 +3711,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = cast6_xts_enc_tv_template, +- .count = CAST6_XTS_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = cast6_xts_dec_tv_template, +- .count = CAST6_XTS_DEC_TEST_VECTORS +- } ++ .enc = __VECS(cast6_xts_enc_tv_template), ++ .dec = __VECS(cast6_xts_dec_tv_template) + } + } + }, { +@@ -4047,14 +3720,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = serpent_xts_enc_tv_template, +- .count = SERPENT_XTS_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = serpent_xts_dec_tv_template, +- .count = SERPENT_XTS_DEC_TEST_VECTORS +- } ++ .enc = __VECS(serpent_xts_enc_tv_template), ++ .dec = __VECS(serpent_xts_dec_tv_template) + } + } + }, { +@@ -4062,14 +3729,8 @@ static const struct alg_test_desc alg_test_descs[] = { + .test = alg_test_skcipher, + .suite = { + .cipher = { +- .enc = { +- .vecs = tf_xts_enc_tv_template, +- .count = TF_XTS_ENC_TEST_VECTORS +- }, +- .dec = { +- .vecs = tf_xts_dec_tv_template, +- .count = TF_XTS_DEC_TEST_VECTORS +- } ++ .enc = __VECS(tf_xts_enc_tv_template), ++ .dec = __VECS(tf_xts_dec_tv_template) + } + } + } +diff --git a/crypto/testmgr.h b/crypto/testmgr.h +index 9033088c..ce9f4334 100644 +--- a/crypto/testmgr.h ++++ b/crypto/testmgr.h +@@ -34,9 +34,9 @@ + + struct hash_testvec { + /* only used with keyed hash algorithms */ +- char *key; +- char *plaintext; +- char *digest; ++ const char *key; ++ const char *plaintext; ++ const char *digest; + unsigned char tap[MAX_TAP]; + unsigned short psize; + unsigned char np; +@@ -63,11 +63,11 @@ struct hash_testvec { + */ + + struct cipher_testvec { +- char *key; +- char *iv; +- char *iv_out; +- char *input; +- char *result; ++ const char *key; ++ const char *iv; ++ const char *iv_out; ++ const char *input; ++ const char *result; + unsigned short tap[MAX_TAP]; + int np; + unsigned char also_non_np; +@@ -80,11 +80,11 @@ struct cipher_testvec { + }; + + struct aead_testvec { +- char *key; +- char *iv; +- char *input; +- char *assoc; +- char *result; ++ const char *key; ++ const char *iv; ++ const char *input; ++ const char *assoc; ++ const char *result; + unsigned char tap[MAX_TAP]; + unsigned char atap[MAX_TAP]; + int np; +@@ -99,10 +99,10 @@ struct aead_testvec { + }; + + struct cprng_testvec { +- char *key; +- char *dt; +- char *v; +- char *result; ++ const char *key; ++ const char *dt; ++ const char *v; ++ const char *result; + unsigned char klen; + unsigned short dtlen; + unsigned short vlen; +@@ -111,24 +111,38 @@ struct cprng_testvec { + }; + + struct drbg_testvec { +- unsigned char *entropy; ++ const unsigned char *entropy; + size_t entropylen; +- unsigned char *entpra; +- unsigned char *entprb; ++ const unsigned char *entpra; ++ const unsigned char *entprb; + size_t entprlen; +- unsigned char *addtla; +- unsigned char *addtlb; ++ const unsigned char *addtla; ++ const unsigned char *addtlb; + size_t addtllen; +- unsigned char *pers; ++ const unsigned char *pers; + size_t perslen; +- unsigned char *expected; ++ const unsigned char *expected; + size_t expectedlen; + }; + ++struct tls_testvec { ++ char *key; /* wrapped keys for encryption and authentication */ ++ char *iv; /* initialization vector */ ++ char *input; /* input data */ ++ char *assoc; /* associated data: seq num, type, version, input len */ ++ char *result; /* result data */ ++ unsigned char fail; /* the test failure is expected */ ++ unsigned char novrfy; /* dec verification failure expected */ ++ unsigned char klen; /* key length */ ++ unsigned short ilen; /* input data length */ ++ unsigned short alen; /* associated data length */ ++ unsigned short rlen; /* result length */ ++}; ++ + struct akcipher_testvec { +- unsigned char *key; +- unsigned char *m; +- unsigned char *c; ++ const unsigned char *key; ++ const unsigned char *m; ++ const unsigned char *c; + unsigned int key_len; + unsigned int m_size; + unsigned int c_size; +@@ -136,27 +150,227 @@ struct akcipher_testvec { + }; + + struct kpp_testvec { +- unsigned char *secret; +- unsigned char *b_public; +- unsigned char *expected_a_public; +- unsigned char *expected_ss; ++ const unsigned char *secret; ++ const unsigned char *b_public; ++ const unsigned char *expected_a_public; ++ const unsigned char *expected_ss; + unsigned short secret_size; + unsigned short b_public_size; + unsigned short expected_a_public_size; + unsigned short expected_ss_size; + }; + +-static char zeroed_string[48]; ++static const char zeroed_string[48]; + + /* +- * RSA test vectors. Borrowed from openSSL. ++ * TLS1.0 synthetic test vectors + */ +-#ifdef CONFIG_CRYPTO_FIPS +-#define RSA_TEST_VECTORS 2 ++static struct tls_testvec tls_enc_tv_template[] = { ++ { ++#ifdef __LITTLE_ENDIAN ++ .key = "\x08\x00" /* rta length */ ++ "\x01\x00" /* rta type */ ++#else ++ .key = "\x00\x08" /* rta length */ ++ "\x00\x01" /* rta type */ ++#endif ++ "\x00\x00\x00\x10" /* enc key length */ ++ "authenticationkey20benckeyis16_bytes", ++ .klen = 8 + 20 + 16, ++ .iv = "iv0123456789abcd", ++ .input = "Single block msg", ++ .ilen = 16, ++ .assoc = "\x00\x01\x02\x03\x04\x05\x06\x07" ++ "\x00\x03\x01\x00\x10", ++ .alen = 13, ++ .result = "\xd5\xac\xb\xd2\xac\xad\x3f\xb1" ++ "\x59\x79\x1e\x91\x5f\x52\x14\x9c" ++ "\xc0\x75\xd8\x4c\x97\x0f\x07\x73" ++ "\xdc\x89\x47\x49\x49\xcb\x30\x6b" ++ "\x1b\x45\x23\xa1\xd0\x51\xcf\x02" ++ "\x2e\xa8\x5d\xa0\xfe\xca\x82\x61", ++ .rlen = 16 + 20 + 12, ++ }, { ++#ifdef __LITTLE_ENDIAN ++ .key = "\x08\x00" /* rta length */ ++ "\x01\x00" /* rta type */ + #else +-#define RSA_TEST_VECTORS 5 ++ .key = "\x00\x08" /* rta length */ ++ "\x00\x01" /* rta type */ + #endif +-static struct akcipher_testvec rsa_tv_template[] = { ++ "\x00\x00\x00\x10" /* enc key length */ ++ "authenticationkey20benckeyis16_bytes", ++ .klen = 8 + 20 + 16, ++ .iv = "iv0123456789abcd", ++ .input = "", ++ .ilen = 0, ++ .assoc = "\x00\x01\x02\x03\x04\x05\x06\x07" ++ "\x00\x03\x01\x00\x00", ++ .alen = 13, ++ .result = "\x58\x2a\x11\xc\x86\x8e\x4b\x67" ++ "\x2d\x16\x26\x1a\xac\x4b\xe2\x1a" ++ "\xe9\x6a\xcc\x4d\x6f\x79\x8a\x45" ++ "\x1f\x4e\x27\xf2\xa7\x59\xb4\x5a", ++ .rlen = 20 + 12, ++ }, { ++#ifdef __LITTLE_ENDIAN ++ .key = "\x08\x00" /* rta length */ ++ "\x01\x00" /* rta type */ ++#else ++ .key = "\x00\x08" /* rta length */ ++ "\x00\x01" /* rta type */ ++#endif ++ "\x00\x00\x00\x10" /* enc key length */ ++ "authenticationkey20benckeyis16_bytes", ++ .klen = 8 + 20 + 16, ++ .iv = "iv0123456789abcd", ++ .input = "285 bytes plaintext285 bytes plaintext285 bytes" ++ " plaintext285 bytes plaintext285 bytes plaintext285" ++ " bytes plaintext285 bytes plaintext285 bytes" ++ " plaintext285 bytes plaintext285 bytes plaintext285" ++ " bytes plaintext285 bytes plaintext285 bytes" ++ " plaintext285 bytes plaintext285 bytes plaintext285" ++ " bytes plaintext285 bytes plaintext", ++ .ilen = 285, ++ .assoc = "\x00\x01\x02\x03\x04\x05\x06\x07" ++ "\x00\x03\x01\x01\x1d", ++ .alen = 13, ++ .result = "\x80\x23\x82\x44\x14\x2a\x1d\x94\xc\xc2\x1d\xd" ++ "\x3a\x32\x89\x4c\x57\x30\xa8\x89\x76\x46\xcc\x90" ++ "\x1d\x88\xb8\xa6\x1a\x58\xe\x2d\xeb\x2c\xc7\x3a" ++ "\x52\x4e\xdb\xb3\x1e\x83\x11\xf5\x3c\xce\x6e\x94" ++ "\xd3\x26\x6a\x9a\xd\xbd\xc7\x98\xb9\xb3\x3a\x51" ++ "\x1e\x4\x84\x8a\x8f\x54\x9a\x51\x69\x9c\xce\x31" ++ "\x8d\x5d\x8b\xee\x5f\x70\xc\xc9\xb8\x50\x54\xf8" ++ "\xb2\x4a\x7a\xcd\xeb\x7a\x82\x81\xc6\x41\xc8\x50" ++ "\x91\x8d\xc8\xed\xcd\x40\x8f\x55\xd1\xec\xc9\xac" ++ "\x15\x18\xf9\x20\xa0\xed\x18\xa1\xe3\x56\xe3\x14" ++ "\xe5\xe8\x66\x63\x20\xed\xe4\x62\x9d\xa3\xa4\x1d" ++ "\x81\x89\x18\xf2\x36\xae\xc8\x8a\x2b\xbc\xc3\xb8" ++ "\x80\xf\x97\x21\x36\x39\x8\x84\x23\x18\x9e\x9c" ++ "\x72\x32\x75\x2d\x2e\xf9\x60\xb\xe8\xcc\xd9\x74" ++ "\x4\x1b\x8e\x99\xc1\x94\xee\xd0\xac\x4e\xfc\x7e" ++ "\xf1\x96\xb3\xe7\x14\xb8\xf2\xc\x25\x97\x82\x6b" ++ "\xbd\x0\x65\xab\x5c\xe3\x16\xfb\x68\xef\xea\x9d" ++ "\xff\x44\x1d\x2a\x44\xf5\xc8\x56\x77\xb7\xbf\x13" ++ "\xc8\x54\xdb\x92\xfe\x16\x4c\xbe\x18\xe9\xb\x8d" ++ "\xb\xd4\x43\x58\x43\xaa\xf4\x3\x80\x97\x62\xd5" ++ "\xdf\x3c\x28\xaa\xee\x48\x4b\x55\x41\x1b\x31\x2" ++ "\xbe\xa0\x1c\xbd\xb7\x22\x2a\xe5\x53\x72\x73\x20" ++ "\x44\x4f\xe6\x1\x2b\x34\x33\x11\x7d\xfb\x10\xc1" ++ "\x66\x7c\xa6\xf4\x48\x36\x5e\x2\xda\x41\x4b\x3e" ++ "\xe7\x80\x17\x17\xce\xf1\x3e\x6a\x8e\x26\xf3\xb7" ++ "\x2b\x85\xd\x31\x8d\xba\x6c\x22\xb4\x28\x55\x7e" ++ "\x2a\x9e\x26\xf1\x3d\x21\xac\x65", ++ .rlen = 285 + 20 + 15, ++ } ++}; ++ ++static struct tls_testvec tls_dec_tv_template[] = { ++ { ++#ifdef __LITTLE_ENDIAN ++ .key = "\x08\x00" /* rta length */ ++ "\x01\x00" /* rta type */ ++#else ++ .key = "\x00\x08" /* rta length */ ++ "\x00\x01" /* rta type */ ++#endif ++ "\x00\x00\x00\x10" /* enc key length */ ++ "authenticationkey20benckeyis16_bytes", ++ .klen = 8 + 20 + 16, ++ .iv = "iv0123456789abcd", ++ .input = "\xd5\xac\xb\xd2\xac\xad\x3f\xb1" ++ "\x59\x79\x1e\x91\x5f\x52\x14\x9c" ++ "\xc0\x75\xd8\x4c\x97\x0f\x07\x73" ++ "\xdc\x89\x47\x49\x49\xcb\x30\x6b" ++ "\x1b\x45\x23\xa1\xd0\x51\xcf\x02" ++ "\x2e\xa8\x5d\xa0\xfe\xca\x82\x61", ++ .ilen = 16 + 20 + 12, ++ .assoc = "\x00\x01\x02\x03\x04\x05\x06\x07" ++ "\x00\x03\x01\x00\x30", ++ .alen = 13, ++ .result = "Single block msg", ++ .rlen = 16, ++ }, { ++#ifdef __LITTLE_ENDIAN ++ .key = "\x08\x00" /* rta length */ ++ "\x01\x00" /* rta type */ ++#else ++ .key = "\x00\x08" /* rta length */ ++ "\x00\x01" /* rta type */ ++#endif ++ "\x00\x00\x00\x10" /* enc key length */ ++ "authenticationkey20benckeyis16_bytes", ++ .klen = 8 + 20 + 16, ++ .iv = "iv0123456789abcd", ++ .input = "\x58\x2a\x11\xc\x86\x8e\x4b\x67" ++ "\x2d\x16\x26\x1a\xac\x4b\xe2\x1a" ++ "\xe9\x6a\xcc\x4d\x6f\x79\x8a\x45" ++ "\x1f\x4e\x27\xf2\xa7\x59\xb4\x5a", ++ .ilen = 20 + 12, ++ .assoc = "\x00\x01\x02\x03\x04\x05\x06\x07" ++ "\x00\x03\x01\x00\x20", ++ .alen = 13, ++ .result = "", ++ .rlen = 0, ++ }, { ++#ifdef __LITTLE_ENDIAN ++ .key = "\x08\x00" /* rta length */ ++ "\x01\x00" /* rta type */ ++#else ++ .key = "\x00\x08" /* rta length */ ++ "\x00\x01" /* rta type */ ++#endif ++ "\x00\x00\x00\x10" /* enc key length */ ++ "authenticationkey20benckeyis16_bytes", ++ .klen = 8 + 20 + 16, ++ .iv = "iv0123456789abcd", ++ .input = "\x80\x23\x82\x44\x14\x2a\x1d\x94\xc\xc2\x1d\xd" ++ "\x3a\x32\x89\x4c\x57\x30\xa8\x89\x76\x46\xcc\x90" ++ "\x1d\x88\xb8\xa6\x1a\x58\xe\x2d\xeb\x2c\xc7\x3a" ++ "\x52\x4e\xdb\xb3\x1e\x83\x11\xf5\x3c\xce\x6e\x94" ++ "\xd3\x26\x6a\x9a\xd\xbd\xc7\x98\xb9\xb3\x3a\x51" ++ "\x1e\x4\x84\x8a\x8f\x54\x9a\x51\x69\x9c\xce\x31" ++ "\x8d\x5d\x8b\xee\x5f\x70\xc\xc9\xb8\x50\x54\xf8" ++ "\xb2\x4a\x7a\xcd\xeb\x7a\x82\x81\xc6\x41\xc8\x50" ++ "\x91\x8d\xc8\xed\xcd\x40\x8f\x55\xd1\xec\xc9\xac" ++ "\x15\x18\xf9\x20\xa0\xed\x18\xa1\xe3\x56\xe3\x14" ++ "\xe5\xe8\x66\x63\x20\xed\xe4\x62\x9d\xa3\xa4\x1d" ++ "\x81\x89\x18\xf2\x36\xae\xc8\x8a\x2b\xbc\xc3\xb8" ++ "\x80\xf\x97\x21\x36\x39\x8\x84\x23\x18\x9e\x9c" ++ "\x72\x32\x75\x2d\x2e\xf9\x60\xb\xe8\xcc\xd9\x74" ++ "\x4\x1b\x8e\x99\xc1\x94\xee\xd0\xac\x4e\xfc\x7e" ++ "\xf1\x96\xb3\xe7\x14\xb8\xf2\xc\x25\x97\x82\x6b" ++ "\xbd\x0\x65\xab\x5c\xe3\x16\xfb\x68\xef\xea\x9d" ++ "\xff\x44\x1d\x2a\x44\xf5\xc8\x56\x77\xb7\xbf\x13" ++ "\xc8\x54\xdb\x92\xfe\x16\x4c\xbe\x18\xe9\xb\x8d" ++ "\xb\xd4\x43\x58\x43\xaa\xf4\x3\x80\x97\x62\xd5" ++ "\xdf\x3c\x28\xaa\xee\x48\x4b\x55\x41\x1b\x31\x2" ++ "\xbe\xa0\x1c\xbd\xb7\x22\x2a\xe5\x53\x72\x73\x20" ++ "\x44\x4f\xe6\x1\x2b\x34\x33\x11\x7d\xfb\x10\xc1" ++ "\x66\x7c\xa6\xf4\x48\x36\x5e\x2\xda\x41\x4b\x3e" ++ "\xe7\x80\x17\x17\xce\xf1\x3e\x6a\x8e\x26\xf3\xb7" ++ "\x2b\x85\xd\x31\x8d\xba\x6c\x22\xb4\x28\x55\x7e" ++ "\x2a\x9e\x26\xf1\x3d\x21\xac\x65", ++ ++ .ilen = 285 + 20 + 15, ++ .assoc = "\x00\x01\x02\x03\x04\x05\x06\x07" ++ "\x00\x03\x01\x01\x40", ++ .alen = 13, ++ .result = "285 bytes plaintext285 bytes plaintext285 bytes" ++ " plaintext285 bytes plaintext285 bytes plaintext285" ++ " bytes plaintext285 bytes plaintext285 bytes" ++ " plaintext285 bytes plaintext285 bytes plaintext285" ++ " bytes plaintext285 bytes plaintext285 bytes" ++ " plaintext285 bytes plaintext285 bytes plaintext", ++ .rlen = 285, ++ } ++}; ++ ++/* ++ * RSA test vectors. Borrowed from openSSL. ++ */ ++static const struct akcipher_testvec rsa_tv_template[] = { + { + #ifndef CONFIG_CRYPTO_FIPS + .key = +@@ -340,6 +554,7 @@ static struct akcipher_testvec rsa_tv_template[] = { + .m_size = 8, + .c_size = 256, + .public_key_vec = true, ++#ifndef CONFIG_CRYPTO_FIPS + }, { + .key = + "\x30\x82\x09\x29" /* sequence of 2345 bytes */ +@@ -538,12 +753,11 @@ static struct akcipher_testvec rsa_tv_template[] = { + .key_len = 2349, + .m_size = 8, + .c_size = 512, ++#endif + } + }; + +-#define DH_TEST_VECTORS 2 +- +-struct kpp_testvec dh_tv_template[] = { ++static const struct kpp_testvec dh_tv_template[] = { + { + .secret = + #ifdef __LITTLE_ENDIAN +@@ -760,12 +974,7 @@ struct kpp_testvec dh_tv_template[] = { + } + }; + +-#ifdef CONFIG_CRYPTO_FIPS +-#define ECDH_TEST_VECTORS 1 +-#else +-#define ECDH_TEST_VECTORS 2 +-#endif +-struct kpp_testvec ecdh_tv_template[] = { ++static const struct kpp_testvec ecdh_tv_template[] = { + { + #ifndef CONFIG_CRYPTO_FIPS + .secret = +@@ -856,9 +1065,7 @@ struct kpp_testvec ecdh_tv_template[] = { + /* + * MD4 test vectors from RFC1320 + */ +-#define MD4_TEST_VECTORS 7 +- +-static struct hash_testvec md4_tv_template [] = { ++static const struct hash_testvec md4_tv_template[] = { + { + .plaintext = "", + .digest = "\x31\xd6\xcf\xe0\xd1\x6a\xe9\x31" +@@ -899,8 +1106,7 @@ static struct hash_testvec md4_tv_template [] = { + }, + }; + +-#define SHA3_224_TEST_VECTORS 3 +-static struct hash_testvec sha3_224_tv_template[] = { ++static const struct hash_testvec sha3_224_tv_template[] = { + { + .plaintext = "", + .digest = "\x6b\x4e\x03\x42\x36\x67\xdb\xb7" +@@ -925,8 +1131,7 @@ static struct hash_testvec sha3_224_tv_template[] = { + }, + }; + +-#define SHA3_256_TEST_VECTORS 3 +-static struct hash_testvec sha3_256_tv_template[] = { ++static const struct hash_testvec sha3_256_tv_template[] = { + { + .plaintext = "", + .digest = "\xa7\xff\xc6\xf8\xbf\x1e\xd7\x66" +@@ -952,8 +1157,7 @@ static struct hash_testvec sha3_256_tv_template[] = { + }; + + +-#define SHA3_384_TEST_VECTORS 3 +-static struct hash_testvec sha3_384_tv_template[] = { ++static const struct hash_testvec sha3_384_tv_template[] = { + { + .plaintext = "", + .digest = "\x0c\x63\xa7\x5b\x84\x5e\x4f\x7d" +@@ -985,8 +1189,7 @@ static struct hash_testvec sha3_384_tv_template[] = { + }; + + +-#define SHA3_512_TEST_VECTORS 3 +-static struct hash_testvec sha3_512_tv_template[] = { ++static const struct hash_testvec sha3_512_tv_template[] = { + { + .plaintext = "", + .digest = "\xa6\x9f\x73\xcc\xa2\x3a\x9a\xc5" +@@ -1027,9 +1230,7 @@ static struct hash_testvec sha3_512_tv_template[] = { + /* + * MD5 test vectors from RFC1321 + */ +-#define MD5_TEST_VECTORS 7 +- +-static struct hash_testvec md5_tv_template[] = { ++static const struct hash_testvec md5_tv_template[] = { + { + .digest = "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04" + "\xe9\x80\x09\x98\xec\xf8\x42\x7e", +@@ -1073,9 +1274,7 @@ static struct hash_testvec md5_tv_template[] = { + /* + * RIPEMD-128 test vectors from ISO/IEC 10118-3:2004(E) + */ +-#define RMD128_TEST_VECTORS 10 +- +-static struct hash_testvec rmd128_tv_template[] = { ++static const struct hash_testvec rmd128_tv_template[] = { + { + .digest = "\xcd\xf2\x62\x13\xa1\x50\xdc\x3e" + "\xcb\x61\x0f\x18\xf6\xb3\x8b\x46", +@@ -1137,9 +1336,7 @@ static struct hash_testvec rmd128_tv_template[] = { + /* + * RIPEMD-160 test vectors from ISO/IEC 10118-3:2004(E) + */ +-#define RMD160_TEST_VECTORS 10 +- +-static struct hash_testvec rmd160_tv_template[] = { ++static const struct hash_testvec rmd160_tv_template[] = { + { + .digest = "\x9c\x11\x85\xa5\xc5\xe9\xfc\x54\x61\x28" + "\x08\x97\x7e\xe8\xf5\x48\xb2\x25\x8d\x31", +@@ -1201,9 +1398,7 @@ static struct hash_testvec rmd160_tv_template[] = { + /* + * RIPEMD-256 test vectors + */ +-#define RMD256_TEST_VECTORS 8 +- +-static struct hash_testvec rmd256_tv_template[] = { ++static const struct hash_testvec rmd256_tv_template[] = { + { + .digest = "\x02\xba\x4c\x4e\x5f\x8e\xcd\x18" + "\x77\xfc\x52\xd6\x4d\x30\xe3\x7a" +@@ -1269,9 +1464,7 @@ static struct hash_testvec rmd256_tv_template[] = { + /* + * RIPEMD-320 test vectors + */ +-#define RMD320_TEST_VECTORS 8 +- +-static struct hash_testvec rmd320_tv_template[] = { ++static const struct hash_testvec rmd320_tv_template[] = { + { + .digest = "\x22\xd6\x5d\x56\x61\x53\x6c\xdc\x75\xc1" + "\xfd\xf5\xc6\xde\x7b\x41\xb9\xf2\x73\x25" +@@ -1334,36 +1527,49 @@ static struct hash_testvec rmd320_tv_template[] = { + } + }; + +-#define CRCT10DIF_TEST_VECTORS 3 +-static struct hash_testvec crct10dif_tv_template[] = { ++static const struct hash_testvec crct10dif_tv_template[] = { + { +- .plaintext = "abc", +- .psize = 3, +-#ifdef __LITTLE_ENDIAN +- .digest = "\x3b\x44", +-#else +- .digest = "\x44\x3b", +-#endif +- }, { +- .plaintext = "1234567890123456789012345678901234567890" +- "123456789012345678901234567890123456789", +- .psize = 79, +-#ifdef __LITTLE_ENDIAN +- .digest = "\x70\x4b", +-#else +- .digest = "\x4b\x70", +-#endif +- }, { +- .plaintext = +- "abcddddddddddddddddddddddddddddddddddddddddddddddddddddd", +- .psize = 56, +-#ifdef __LITTLE_ENDIAN +- .digest = "\xe3\x9c", +-#else +- .digest = "\x9c\xe3", +-#endif +- .np = 2, +- .tap = { 28, 28 } ++ .plaintext = "abc", ++ .psize = 3, ++ .digest = (u8 *)(u16 []){ 0x443b }, ++ }, { ++ .plaintext = "1234567890123456789012345678901234567890" ++ "123456789012345678901234567890123456789", ++ .psize = 79, ++ .digest = (u8 *)(u16 []){ 0x4b70 }, ++ .np = 2, ++ .tap = { 63, 16 }, ++ }, { ++ .plaintext = "abcdddddddddddddddddddddddddddddddddddddddd" ++ "ddddddddddddd", ++ .psize = 56, ++ .digest = (u8 *)(u16 []){ 0x9ce3 }, ++ .np = 8, ++ .tap = { 1, 2, 28, 7, 6, 5, 4, 3 }, ++ }, { ++ .plaintext = "1234567890123456789012345678901234567890" ++ "1234567890123456789012345678901234567890" ++ "1234567890123456789012345678901234567890" ++ "1234567890123456789012345678901234567890" ++ "1234567890123456789012345678901234567890" ++ "1234567890123456789012345678901234567890" ++ "1234567890123456789012345678901234567890" ++ "123456789012345678901234567890123456789", ++ .psize = 319, ++ .digest = (u8 *)(u16 []){ 0x44c6 }, ++ }, { ++ .plaintext = "1234567890123456789012345678901234567890" ++ "1234567890123456789012345678901234567890" ++ "1234567890123456789012345678901234567890" ++ "1234567890123456789012345678901234567890" ++ "1234567890123456789012345678901234567890" ++ "1234567890123456789012345678901234567890" ++ "1234567890123456789012345678901234567890" ++ "123456789012345678901234567890123456789", ++ .psize = 319, ++ .digest = (u8 *)(u16 []){ 0x44c6 }, ++ .np = 4, ++ .tap = { 1, 255, 57, 6 }, + } + }; + +@@ -1371,9 +1577,7 @@ static struct hash_testvec crct10dif_tv_template[] = { + * SHA1 test vectors from from FIPS PUB 180-1 + * Long vector from CAVS 5.0 + */ +-#define SHA1_TEST_VECTORS 6 +- +-static struct hash_testvec sha1_tv_template[] = { ++static const struct hash_testvec sha1_tv_template[] = { + { + .plaintext = "", + .psize = 0, +@@ -1563,9 +1767,7 @@ static struct hash_testvec sha1_tv_template[] = { + /* + * SHA224 test vectors from from FIPS PUB 180-2 + */ +-#define SHA224_TEST_VECTORS 5 +- +-static struct hash_testvec sha224_tv_template[] = { ++static const struct hash_testvec sha224_tv_template[] = { + { + .plaintext = "", + .psize = 0, +@@ -1737,9 +1939,7 @@ static struct hash_testvec sha224_tv_template[] = { + /* + * SHA256 test vectors from from NIST + */ +-#define SHA256_TEST_VECTORS 5 +- +-static struct hash_testvec sha256_tv_template[] = { ++static const struct hash_testvec sha256_tv_template[] = { + { + .plaintext = "", + .psize = 0, +@@ -1910,9 +2110,7 @@ static struct hash_testvec sha256_tv_template[] = { + /* + * SHA384 test vectors from from NIST and kerneli + */ +-#define SHA384_TEST_VECTORS 6 +- +-static struct hash_testvec sha384_tv_template[] = { ++static const struct hash_testvec sha384_tv_template[] = { + { + .plaintext = "", + .psize = 0, +@@ -2104,9 +2302,7 @@ static struct hash_testvec sha384_tv_template[] = { + /* + * SHA512 test vectors from from NIST and kerneli + */ +-#define SHA512_TEST_VECTORS 6 +- +-static struct hash_testvec sha512_tv_template[] = { ++static const struct hash_testvec sha512_tv_template[] = { + { + .plaintext = "", + .psize = 0, +@@ -2313,9 +2509,7 @@ static struct hash_testvec sha512_tv_template[] = { + * by Vincent Rijmen and Paulo S. L. M. Barreto as part of the NESSIE + * submission + */ +-#define WP512_TEST_VECTORS 8 +- +-static struct hash_testvec wp512_tv_template[] = { ++static const struct hash_testvec wp512_tv_template[] = { + { + .plaintext = "", + .psize = 0, +@@ -2411,9 +2605,7 @@ static struct hash_testvec wp512_tv_template[] = { + }, + }; + +-#define WP384_TEST_VECTORS 8 +- +-static struct hash_testvec wp384_tv_template[] = { ++static const struct hash_testvec wp384_tv_template[] = { + { + .plaintext = "", + .psize = 0, +@@ -2493,9 +2685,7 @@ static struct hash_testvec wp384_tv_template[] = { + }, + }; + +-#define WP256_TEST_VECTORS 8 +- +-static struct hash_testvec wp256_tv_template[] = { ++static const struct hash_testvec wp256_tv_template[] = { + { + .plaintext = "", + .psize = 0, +@@ -2562,9 +2752,7 @@ static struct hash_testvec wp256_tv_template[] = { + /* + * TIGER test vectors from Tiger website + */ +-#define TGR192_TEST_VECTORS 6 +- +-static struct hash_testvec tgr192_tv_template[] = { ++static const struct hash_testvec tgr192_tv_template[] = { + { + .plaintext = "", + .psize = 0, +@@ -2607,9 +2795,7 @@ static struct hash_testvec tgr192_tv_template[] = { + }, + }; + +-#define TGR160_TEST_VECTORS 6 +- +-static struct hash_testvec tgr160_tv_template[] = { ++static const struct hash_testvec tgr160_tv_template[] = { + { + .plaintext = "", + .psize = 0, +@@ -2652,9 +2838,7 @@ static struct hash_testvec tgr160_tv_template[] = { + }, + }; + +-#define TGR128_TEST_VECTORS 6 +- +-static struct hash_testvec tgr128_tv_template[] = { ++static const struct hash_testvec tgr128_tv_template[] = { + { + .plaintext = "", + .psize = 0, +@@ -2691,9 +2875,7 @@ static struct hash_testvec tgr128_tv_template[] = { + }, + }; + +-#define GHASH_TEST_VECTORS 6 +- +-static struct hash_testvec ghash_tv_template[] = ++static const struct hash_testvec ghash_tv_template[] = + { + { + .key = "\xdf\xa6\xbf\x4d\xed\x81\xdb\x03" +@@ -2808,9 +2990,7 @@ static struct hash_testvec ghash_tv_template[] = + * HMAC-MD5 test vectors from RFC2202 + * (These need to be fixed to not use strlen). + */ +-#define HMAC_MD5_TEST_VECTORS 7 +- +-static struct hash_testvec hmac_md5_tv_template[] = ++static const struct hash_testvec hmac_md5_tv_template[] = + { + { + .key = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", +@@ -2890,9 +3070,7 @@ static struct hash_testvec hmac_md5_tv_template[] = + /* + * HMAC-RIPEMD128 test vectors from RFC2286 + */ +-#define HMAC_RMD128_TEST_VECTORS 7 +- +-static struct hash_testvec hmac_rmd128_tv_template[] = { ++static const struct hash_testvec hmac_rmd128_tv_template[] = { + { + .key = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + .ksize = 16, +@@ -2971,9 +3149,7 @@ static struct hash_testvec hmac_rmd128_tv_template[] = { + /* + * HMAC-RIPEMD160 test vectors from RFC2286 + */ +-#define HMAC_RMD160_TEST_VECTORS 7 +- +-static struct hash_testvec hmac_rmd160_tv_template[] = { ++static const struct hash_testvec hmac_rmd160_tv_template[] = { + { + .key = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + .ksize = 20, +@@ -3052,9 +3228,7 @@ static struct hash_testvec hmac_rmd160_tv_template[] = { + /* + * HMAC-SHA1 test vectors from RFC2202 + */ +-#define HMAC_SHA1_TEST_VECTORS 7 +- +-static struct hash_testvec hmac_sha1_tv_template[] = { ++static const struct hash_testvec hmac_sha1_tv_template[] = { + { + .key = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + .ksize = 20, +@@ -3135,9 +3309,7 @@ static struct hash_testvec hmac_sha1_tv_template[] = { + /* + * SHA224 HMAC test vectors from RFC4231 + */ +-#define HMAC_SHA224_TEST_VECTORS 4 +- +-static struct hash_testvec hmac_sha224_tv_template[] = { ++static const struct hash_testvec hmac_sha224_tv_template[] = { + { + .key = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" +@@ -3250,9 +3422,7 @@ static struct hash_testvec hmac_sha224_tv_template[] = { + * HMAC-SHA256 test vectors from + * draft-ietf-ipsec-ciph-sha-256-01.txt + */ +-#define HMAC_SHA256_TEST_VECTORS 10 +- +-static struct hash_testvec hmac_sha256_tv_template[] = { ++static const struct hash_testvec hmac_sha256_tv_template[] = { + { + .key = "\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" +@@ -3387,9 +3557,7 @@ static struct hash_testvec hmac_sha256_tv_template[] = { + }, + }; + +-#define CMAC_AES_TEST_VECTORS 6 +- +-static struct hash_testvec aes_cmac128_tv_template[] = { ++static const struct hash_testvec aes_cmac128_tv_template[] = { + { /* From NIST Special Publication 800-38B, AES-128 */ + .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" + "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", +@@ -3464,9 +3632,67 @@ static struct hash_testvec aes_cmac128_tv_template[] = { + } + }; + +-#define CMAC_DES3_EDE_TEST_VECTORS 4 ++static const struct hash_testvec aes_cbcmac_tv_template[] = { ++ { ++ .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" ++ "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", ++ .plaintext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" ++ "\xe9\x3d\x7e\x11\x73\x93\x17\x2a", ++ .digest = "\x3a\xd7\x7b\xb4\x0d\x7a\x36\x60" ++ "\xa8\x9e\xca\xf3\x24\x66\xef\x97", ++ .psize = 16, ++ .ksize = 16, ++ }, { ++ .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" ++ "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", ++ .plaintext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" ++ "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" ++ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" ++ "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" ++ "\x30", ++ .digest = "\x9d\x0d\xd0\x63\xfb\xcb\x24\x43" ++ "\xf8\xf2\x76\x03\xac\x39\xb0\x9d", ++ .psize = 33, ++ .ksize = 16, ++ .np = 2, ++ .tap = { 7, 26 }, ++ }, { ++ .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" ++ "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", ++ .plaintext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" ++ "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" ++ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" ++ "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" ++ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" ++ "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" ++ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" ++ "\xad\x2b\x41\x7b\xe6\x6c\x37", ++ .digest = "\xc0\x71\x73\xb8\xa0\x2c\x11\x7c" ++ "\xaf\xdc\xb2\xf8\x89\x32\xa3\x3a", ++ .psize = 63, ++ .ksize = 16, ++ }, { ++ .key = "\x60\x3d\xeb\x10\x15\xca\x71\xbe" ++ "\x2b\x73\xae\xf0\x85\x7d\x77\x81" ++ "\x1f\x35\x2c\x07\x3b\x61\x08\xd7" ++ "\x2d\x98\x10\xa3\x09\x14\xdf\xf4", ++ .plaintext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" ++ "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" ++ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" ++ "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" ++ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" ++ "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" ++ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" ++ "\xad\x2b\x41\x7b\xe6\x6c\x37\x10" ++ "\x1c", ++ .digest = "\x6a\x4e\xdb\x21\x47\x51\xdf\x4f" ++ "\xa8\x4d\x4c\x10\x3b\x72\x7d\xd6", ++ .psize = 65, ++ .ksize = 32, ++ } ++}; + +-static struct hash_testvec des3_ede_cmac64_tv_template[] = { ++static const struct hash_testvec des3_ede_cmac64_tv_template[] = { + /* + * From NIST Special Publication 800-38B, Three Key TDEA + * Corrected test vectors from: +@@ -3512,9 +3738,7 @@ static struct hash_testvec des3_ede_cmac64_tv_template[] = { + } + }; + +-#define XCBC_AES_TEST_VECTORS 6 +- +-static struct hash_testvec aes_xcbc128_tv_template[] = { ++static const struct hash_testvec aes_xcbc128_tv_template[] = { + { + .key = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", +@@ -3580,36 +3804,35 @@ static struct hash_testvec aes_xcbc128_tv_template[] = { + } + }; + +-#define VMAC_AES_TEST_VECTORS 11 +-static char vmac_string1[128] = {'\x01', '\x01', '\x01', '\x01', +- '\x02', '\x03', '\x02', '\x02', +- '\x02', '\x04', '\x01', '\x07', +- '\x04', '\x01', '\x04', '\x03',}; +-static char vmac_string2[128] = {'a', 'b', 'c',}; +-static char vmac_string3[128] = {'a', 'b', 'c', 'a', 'b', 'c', +- 'a', 'b', 'c', 'a', 'b', 'c', +- 'a', 'b', 'c', 'a', 'b', 'c', +- 'a', 'b', 'c', 'a', 'b', 'c', +- 'a', 'b', 'c', 'a', 'b', 'c', +- 'a', 'b', 'c', 'a', 'b', 'c', +- 'a', 'b', 'c', 'a', 'b', 'c', +- 'a', 'b', 'c', 'a', 'b', 'c', +- }; +- +-static char vmac_string4[17] = {'b', 'c', 'e', 'f', +- 'i', 'j', 'l', 'm', +- 'o', 'p', 'r', 's', +- 't', 'u', 'w', 'x', 'z'}; +- +-static char vmac_string5[127] = {'r', 'm', 'b', 't', 'c', +- 'o', 'l', 'k', ']', '%', +- '9', '2', '7', '!', 'A'}; +- +-static char vmac_string6[129] = {'p', 't', '*', '7', 'l', +- 'i', '!', '#', 'w', '0', +- 'z', '/', '4', 'A', 'n'}; +- +-static struct hash_testvec aes_vmac128_tv_template[] = { ++static const char vmac_string1[128] = {'\x01', '\x01', '\x01', '\x01', ++ '\x02', '\x03', '\x02', '\x02', ++ '\x02', '\x04', '\x01', '\x07', ++ '\x04', '\x01', '\x04', '\x03',}; ++static const char vmac_string2[128] = {'a', 'b', 'c',}; ++static const char vmac_string3[128] = {'a', 'b', 'c', 'a', 'b', 'c', ++ 'a', 'b', 'c', 'a', 'b', 'c', ++ 'a', 'b', 'c', 'a', 'b', 'c', ++ 'a', 'b', 'c', 'a', 'b', 'c', ++ 'a', 'b', 'c', 'a', 'b', 'c', ++ 'a', 'b', 'c', 'a', 'b', 'c', ++ 'a', 'b', 'c', 'a', 'b', 'c', ++ 'a', 'b', 'c', 'a', 'b', 'c', ++ }; ++ ++static const char vmac_string4[17] = {'b', 'c', 'e', 'f', ++ 'i', 'j', 'l', 'm', ++ 'o', 'p', 'r', 's', ++ 't', 'u', 'w', 'x', 'z'}; ++ ++static const char vmac_string5[127] = {'r', 'm', 'b', 't', 'c', ++ 'o', 'l', 'k', ']', '%', ++ '9', '2', '7', '!', 'A'}; ++ ++static const char vmac_string6[129] = {'p', 't', '*', '7', 'l', ++ 'i', '!', '#', 'w', '0', ++ 'z', '/', '4', 'A', 'n'}; ++ ++static const struct hash_testvec aes_vmac128_tv_template[] = { + { + .key = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", +@@ -3687,9 +3910,7 @@ static struct hash_testvec aes_vmac128_tv_template[] = { + * SHA384 HMAC test vectors from RFC4231 + */ + +-#define HMAC_SHA384_TEST_VECTORS 4 +- +-static struct hash_testvec hmac_sha384_tv_template[] = { ++static const struct hash_testvec hmac_sha384_tv_template[] = { + { + .key = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" +@@ -3787,9 +4008,7 @@ static struct hash_testvec hmac_sha384_tv_template[] = { + * SHA512 HMAC test vectors from RFC4231 + */ + +-#define HMAC_SHA512_TEST_VECTORS 4 +- +-static struct hash_testvec hmac_sha512_tv_template[] = { ++static const struct hash_testvec hmac_sha512_tv_template[] = { + { + .key = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" +@@ -3894,9 +4113,7 @@ static struct hash_testvec hmac_sha512_tv_template[] = { + }, + }; + +-#define HMAC_SHA3_224_TEST_VECTORS 4 +- +-static struct hash_testvec hmac_sha3_224_tv_template[] = { ++static const struct hash_testvec hmac_sha3_224_tv_template[] = { + { + .key = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" +@@ -3985,9 +4202,7 @@ static struct hash_testvec hmac_sha3_224_tv_template[] = { + }, + }; + +-#define HMAC_SHA3_256_TEST_VECTORS 4 +- +-static struct hash_testvec hmac_sha3_256_tv_template[] = { ++static const struct hash_testvec hmac_sha3_256_tv_template[] = { + { + .key = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" +@@ -4076,9 +4291,7 @@ static struct hash_testvec hmac_sha3_256_tv_template[] = { + }, + }; + +-#define HMAC_SHA3_384_TEST_VECTORS 4 +- +-static struct hash_testvec hmac_sha3_384_tv_template[] = { ++static const struct hash_testvec hmac_sha3_384_tv_template[] = { + { + .key = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" +@@ -4175,9 +4388,7 @@ static struct hash_testvec hmac_sha3_384_tv_template[] = { + }, + }; + +-#define HMAC_SHA3_512_TEST_VECTORS 4 +- +-static struct hash_testvec hmac_sha3_512_tv_template[] = { ++static const struct hash_testvec hmac_sha3_512_tv_template[] = { + { + .key = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" +@@ -4286,9 +4497,7 @@ static struct hash_testvec hmac_sha3_512_tv_template[] = { + * Poly1305 test vectors from RFC7539 A.3. + */ + +-#define POLY1305_TEST_VECTORS 11 +- +-static struct hash_testvec poly1305_tv_template[] = { ++static const struct hash_testvec poly1305_tv_template[] = { + { /* Test Vector #1 */ + .plaintext = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" +@@ -4533,20 +4742,7 @@ static struct hash_testvec poly1305_tv_template[] = { + /* + * DES test vectors. + */ +-#define DES_ENC_TEST_VECTORS 11 +-#define DES_DEC_TEST_VECTORS 5 +-#define DES_CBC_ENC_TEST_VECTORS 6 +-#define DES_CBC_DEC_TEST_VECTORS 5 +-#define DES_CTR_ENC_TEST_VECTORS 2 +-#define DES_CTR_DEC_TEST_VECTORS 2 +-#define DES3_EDE_ENC_TEST_VECTORS 4 +-#define DES3_EDE_DEC_TEST_VECTORS 4 +-#define DES3_EDE_CBC_ENC_TEST_VECTORS 2 +-#define DES3_EDE_CBC_DEC_TEST_VECTORS 2 +-#define DES3_EDE_CTR_ENC_TEST_VECTORS 2 +-#define DES3_EDE_CTR_DEC_TEST_VECTORS 2 +- +-static struct cipher_testvec des_enc_tv_template[] = { ++static const struct cipher_testvec des_enc_tv_template[] = { + { /* From Applied Cryptography */ + .key = "\x01\x23\x45\x67\x89\xab\xcd\xef", + .klen = 8, +@@ -4720,7 +4916,7 @@ static struct cipher_testvec des_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec des_dec_tv_template[] = { ++static const struct cipher_testvec des_dec_tv_template[] = { + { /* From Applied Cryptography */ + .key = "\x01\x23\x45\x67\x89\xab\xcd\xef", + .klen = 8, +@@ -4830,7 +5026,7 @@ static struct cipher_testvec des_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec des_cbc_enc_tv_template[] = { ++static const struct cipher_testvec des_cbc_enc_tv_template[] = { + { /* From OpenSSL */ + .key = "\x01\x23\x45\x67\x89\xab\xcd\xef", + .klen = 8, +@@ -4956,7 +5152,7 @@ static struct cipher_testvec des_cbc_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec des_cbc_dec_tv_template[] = { ++static const struct cipher_testvec des_cbc_dec_tv_template[] = { + { /* FIPS Pub 81 */ + .key = "\x01\x23\x45\x67\x89\xab\xcd\xef", + .klen = 8, +@@ -5065,7 +5261,7 @@ static struct cipher_testvec des_cbc_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec des_ctr_enc_tv_template[] = { ++static const struct cipher_testvec des_ctr_enc_tv_template[] = { + { /* Generated with Crypto++ */ + .key = "\xC9\x83\xA6\xC9\xEC\x0F\x32\x55", + .klen = 8, +@@ -5211,7 +5407,7 @@ static struct cipher_testvec des_ctr_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec des_ctr_dec_tv_template[] = { ++static const struct cipher_testvec des_ctr_dec_tv_template[] = { + { /* Generated with Crypto++ */ + .key = "\xC9\x83\xA6\xC9\xEC\x0F\x32\x55", + .klen = 8, +@@ -5357,7 +5553,7 @@ static struct cipher_testvec des_ctr_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec des3_ede_enc_tv_template[] = { ++static const struct cipher_testvec des3_ede_enc_tv_template[] = { + { /* These are from openssl */ + .key = "\x01\x23\x45\x67\x89\xab\xcd\xef" + "\x55\x55\x55\x55\x55\x55\x55\x55" +@@ -5522,7 +5718,7 @@ static struct cipher_testvec des3_ede_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec des3_ede_dec_tv_template[] = { ++static const struct cipher_testvec des3_ede_dec_tv_template[] = { + { /* These are from openssl */ + .key = "\x01\x23\x45\x67\x89\xab\xcd\xef" + "\x55\x55\x55\x55\x55\x55\x55\x55" +@@ -5687,7 +5883,7 @@ static struct cipher_testvec des3_ede_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec des3_ede_cbc_enc_tv_template[] = { ++static const struct cipher_testvec des3_ede_cbc_enc_tv_template[] = { + { /* Generated from openssl */ + .key = "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24" + "\x44\x4D\x99\x5A\x12\xD6\x40\xC0" +@@ -5867,7 +6063,7 @@ static struct cipher_testvec des3_ede_cbc_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec des3_ede_cbc_dec_tv_template[] = { ++static const struct cipher_testvec des3_ede_cbc_dec_tv_template[] = { + { /* Generated from openssl */ + .key = "\xE9\xC0\xFF\x2E\x76\x0B\x64\x24" + "\x44\x4D\x99\x5A\x12\xD6\x40\xC0" +@@ -6047,7 +6243,7 @@ static struct cipher_testvec des3_ede_cbc_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec des3_ede_ctr_enc_tv_template[] = { ++static const struct cipher_testvec des3_ede_ctr_enc_tv_template[] = { + { /* Generated with Crypto++ */ + .key = "\x9C\xD6\xF3\x9C\xB9\x5A\x67\x00" + "\x5A\x67\x00\x2D\xCE\xEB\x2D\xCE" +@@ -6325,7 +6521,7 @@ static struct cipher_testvec des3_ede_ctr_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec des3_ede_ctr_dec_tv_template[] = { ++static const struct cipher_testvec des3_ede_ctr_dec_tv_template[] = { + { /* Generated with Crypto++ */ + .key = "\x9C\xD6\xF3\x9C\xB9\x5A\x67\x00" + "\x5A\x67\x00\x2D\xCE\xEB\x2D\xCE" +@@ -6606,14 +6802,7 @@ static struct cipher_testvec des3_ede_ctr_dec_tv_template[] = { + /* + * Blowfish test vectors. + */ +-#define BF_ENC_TEST_VECTORS 7 +-#define BF_DEC_TEST_VECTORS 7 +-#define BF_CBC_ENC_TEST_VECTORS 2 +-#define BF_CBC_DEC_TEST_VECTORS 2 +-#define BF_CTR_ENC_TEST_VECTORS 2 +-#define BF_CTR_DEC_TEST_VECTORS 2 +- +-static struct cipher_testvec bf_enc_tv_template[] = { ++static const struct cipher_testvec bf_enc_tv_template[] = { + { /* DES test vectors from OpenSSL */ + .key = "\x00\x00\x00\x00\x00\x00\x00\x00", + .klen = 8, +@@ -6805,7 +6994,7 @@ static struct cipher_testvec bf_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec bf_dec_tv_template[] = { ++static const struct cipher_testvec bf_dec_tv_template[] = { + { /* DES test vectors from OpenSSL */ + .key = "\x00\x00\x00\x00\x00\x00\x00\x00", + .klen = 8, +@@ -6997,7 +7186,7 @@ static struct cipher_testvec bf_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec bf_cbc_enc_tv_template[] = { ++static const struct cipher_testvec bf_cbc_enc_tv_template[] = { + { /* From OpenSSL */ + .key = "\x01\x23\x45\x67\x89\xab\xcd\xef" + "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87", +@@ -7154,7 +7343,7 @@ static struct cipher_testvec bf_cbc_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec bf_cbc_dec_tv_template[] = { ++static const struct cipher_testvec bf_cbc_dec_tv_template[] = { + { /* From OpenSSL */ + .key = "\x01\x23\x45\x67\x89\xab\xcd\xef" + "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87", +@@ -7311,7 +7500,7 @@ static struct cipher_testvec bf_cbc_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec bf_ctr_enc_tv_template[] = { ++static const struct cipher_testvec bf_ctr_enc_tv_template[] = { + { /* Generated with Crypto++ */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" +@@ -7723,7 +7912,7 @@ static struct cipher_testvec bf_ctr_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec bf_ctr_dec_tv_template[] = { ++static const struct cipher_testvec bf_ctr_dec_tv_template[] = { + { /* Generated with Crypto++ */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" +@@ -8138,18 +8327,7 @@ static struct cipher_testvec bf_ctr_dec_tv_template[] = { + /* + * Twofish test vectors. + */ +-#define TF_ENC_TEST_VECTORS 4 +-#define TF_DEC_TEST_VECTORS 4 +-#define TF_CBC_ENC_TEST_VECTORS 5 +-#define TF_CBC_DEC_TEST_VECTORS 5 +-#define TF_CTR_ENC_TEST_VECTORS 2 +-#define TF_CTR_DEC_TEST_VECTORS 2 +-#define TF_LRW_ENC_TEST_VECTORS 8 +-#define TF_LRW_DEC_TEST_VECTORS 8 +-#define TF_XTS_ENC_TEST_VECTORS 5 +-#define TF_XTS_DEC_TEST_VECTORS 5 +- +-static struct cipher_testvec tf_enc_tv_template[] = { ++static const struct cipher_testvec tf_enc_tv_template[] = { + { + .key = zeroed_string, + .klen = 16, +@@ -8317,7 +8495,7 @@ static struct cipher_testvec tf_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec tf_dec_tv_template[] = { ++static const struct cipher_testvec tf_dec_tv_template[] = { + { + .key = zeroed_string, + .klen = 16, +@@ -8485,7 +8663,7 @@ static struct cipher_testvec tf_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec tf_cbc_enc_tv_template[] = { ++static const struct cipher_testvec tf_cbc_enc_tv_template[] = { + { /* Generated with Nettle */ + .key = zeroed_string, + .klen = 16, +@@ -8668,7 +8846,7 @@ static struct cipher_testvec tf_cbc_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec tf_cbc_dec_tv_template[] = { ++static const struct cipher_testvec tf_cbc_dec_tv_template[] = { + { /* Reverse of the first four above */ + .key = zeroed_string, + .klen = 16, +@@ -8851,7 +9029,7 @@ static struct cipher_testvec tf_cbc_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec tf_ctr_enc_tv_template[] = { ++static const struct cipher_testvec tf_ctr_enc_tv_template[] = { + { /* Generated with Crypto++ */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" +@@ -9262,7 +9440,7 @@ static struct cipher_testvec tf_ctr_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec tf_ctr_dec_tv_template[] = { ++static const struct cipher_testvec tf_ctr_dec_tv_template[] = { + { /* Generated with Crypto++ */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" +@@ -9673,7 +9851,7 @@ static struct cipher_testvec tf_ctr_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec tf_lrw_enc_tv_template[] = { ++static const struct cipher_testvec tf_lrw_enc_tv_template[] = { + /* Generated from AES-LRW test vectors */ + { + .key = "\x45\x62\xac\x25\xf8\x28\x17\x6d" +@@ -9925,7 +10103,7 @@ static struct cipher_testvec tf_lrw_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec tf_lrw_dec_tv_template[] = { ++static const struct cipher_testvec tf_lrw_dec_tv_template[] = { + /* Generated from AES-LRW test vectors */ + /* same as enc vectors with input and result reversed */ + { +@@ -10178,7 +10356,7 @@ static struct cipher_testvec tf_lrw_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec tf_xts_enc_tv_template[] = { ++static const struct cipher_testvec tf_xts_enc_tv_template[] = { + /* Generated from AES-XTS test vectors */ + { + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" +@@ -10520,7 +10698,7 @@ static struct cipher_testvec tf_xts_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec tf_xts_dec_tv_template[] = { ++static const struct cipher_testvec tf_xts_dec_tv_template[] = { + /* Generated from AES-XTS test vectors */ + /* same as enc vectors with input and result reversed */ + { +@@ -10867,25 +11045,7 @@ static struct cipher_testvec tf_xts_dec_tv_template[] = { + * Serpent test vectors. These are backwards because Serpent writes + * octet sequences in right-to-left mode. + */ +-#define SERPENT_ENC_TEST_VECTORS 5 +-#define SERPENT_DEC_TEST_VECTORS 5 +- +-#define TNEPRES_ENC_TEST_VECTORS 4 +-#define TNEPRES_DEC_TEST_VECTORS 4 +- +-#define SERPENT_CBC_ENC_TEST_VECTORS 1 +-#define SERPENT_CBC_DEC_TEST_VECTORS 1 +- +-#define SERPENT_CTR_ENC_TEST_VECTORS 2 +-#define SERPENT_CTR_DEC_TEST_VECTORS 2 +- +-#define SERPENT_LRW_ENC_TEST_VECTORS 8 +-#define SERPENT_LRW_DEC_TEST_VECTORS 8 +- +-#define SERPENT_XTS_ENC_TEST_VECTORS 5 +-#define SERPENT_XTS_DEC_TEST_VECTORS 5 +- +-static struct cipher_testvec serpent_enc_tv_template[] = { ++static const struct cipher_testvec serpent_enc_tv_template[] = { + { + .input = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", +@@ -11061,7 +11221,7 @@ static struct cipher_testvec serpent_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec tnepres_enc_tv_template[] = { ++static const struct cipher_testvec tnepres_enc_tv_template[] = { + { /* KeySize=128, PT=0, I=1 */ + .input = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", +@@ -11111,7 +11271,7 @@ static struct cipher_testvec tnepres_enc_tv_template[] = { + }; + + +-static struct cipher_testvec serpent_dec_tv_template[] = { ++static const struct cipher_testvec serpent_dec_tv_template[] = { + { + .input = "\x12\x07\xfc\xce\x9b\xd0\xd6\x47" + "\x6a\xe9\x8f\xbe\xd1\x43\xa0\xe2", +@@ -11287,7 +11447,7 @@ static struct cipher_testvec serpent_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec tnepres_dec_tv_template[] = { ++static const struct cipher_testvec tnepres_dec_tv_template[] = { + { + .input = "\x41\xcc\x6b\x31\x59\x31\x45\x97" + "\x6d\x6f\xbb\x38\x4b\x37\x21\x28", +@@ -11328,7 +11488,7 @@ static struct cipher_testvec tnepres_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec serpent_cbc_enc_tv_template[] = { ++static const struct cipher_testvec serpent_cbc_enc_tv_template[] = { + { /* Generated with Crypto++ */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" +@@ -11469,7 +11629,7 @@ static struct cipher_testvec serpent_cbc_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec serpent_cbc_dec_tv_template[] = { ++static const struct cipher_testvec serpent_cbc_dec_tv_template[] = { + { /* Generated with Crypto++ */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" +@@ -11610,7 +11770,7 @@ static struct cipher_testvec serpent_cbc_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec serpent_ctr_enc_tv_template[] = { ++static const struct cipher_testvec serpent_ctr_enc_tv_template[] = { + { /* Generated with Crypto++ */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" +@@ -12021,7 +12181,7 @@ static struct cipher_testvec serpent_ctr_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec serpent_ctr_dec_tv_template[] = { ++static const struct cipher_testvec serpent_ctr_dec_tv_template[] = { + { /* Generated with Crypto++ */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" +@@ -12432,7 +12592,7 @@ static struct cipher_testvec serpent_ctr_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec serpent_lrw_enc_tv_template[] = { ++static const struct cipher_testvec serpent_lrw_enc_tv_template[] = { + /* Generated from AES-LRW test vectors */ + { + .key = "\x45\x62\xac\x25\xf8\x28\x17\x6d" +@@ -12684,7 +12844,7 @@ static struct cipher_testvec serpent_lrw_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec serpent_lrw_dec_tv_template[] = { ++static const struct cipher_testvec serpent_lrw_dec_tv_template[] = { + /* Generated from AES-LRW test vectors */ + /* same as enc vectors with input and result reversed */ + { +@@ -12937,7 +13097,7 @@ static struct cipher_testvec serpent_lrw_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec serpent_xts_enc_tv_template[] = { ++static const struct cipher_testvec serpent_xts_enc_tv_template[] = { + /* Generated from AES-XTS test vectors */ + { + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" +@@ -13279,7 +13439,7 @@ static struct cipher_testvec serpent_xts_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec serpent_xts_dec_tv_template[] = { ++static const struct cipher_testvec serpent_xts_dec_tv_template[] = { + /* Generated from AES-XTS test vectors */ + /* same as enc vectors with input and result reversed */ + { +@@ -13623,18 +13783,7 @@ static struct cipher_testvec serpent_xts_dec_tv_template[] = { + }; + + /* Cast6 test vectors from RFC 2612 */ +-#define CAST6_ENC_TEST_VECTORS 4 +-#define CAST6_DEC_TEST_VECTORS 4 +-#define CAST6_CBC_ENC_TEST_VECTORS 1 +-#define CAST6_CBC_DEC_TEST_VECTORS 1 +-#define CAST6_CTR_ENC_TEST_VECTORS 2 +-#define CAST6_CTR_DEC_TEST_VECTORS 2 +-#define CAST6_LRW_ENC_TEST_VECTORS 1 +-#define CAST6_LRW_DEC_TEST_VECTORS 1 +-#define CAST6_XTS_ENC_TEST_VECTORS 1 +-#define CAST6_XTS_DEC_TEST_VECTORS 1 +- +-static struct cipher_testvec cast6_enc_tv_template[] = { ++static const struct cipher_testvec cast6_enc_tv_template[] = { + { + .key = "\x23\x42\xbb\x9e\xfa\x38\x54\x2c" + "\x0a\xf7\x56\x47\xf2\x9f\x61\x5d", +@@ -13805,7 +13954,7 @@ static struct cipher_testvec cast6_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec cast6_dec_tv_template[] = { ++static const struct cipher_testvec cast6_dec_tv_template[] = { + { + .key = "\x23\x42\xbb\x9e\xfa\x38\x54\x2c" + "\x0a\xf7\x56\x47\xf2\x9f\x61\x5d", +@@ -13976,7 +14125,7 @@ static struct cipher_testvec cast6_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec cast6_cbc_enc_tv_template[] = { ++static const struct cipher_testvec cast6_cbc_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" +@@ -14117,7 +14266,7 @@ static struct cipher_testvec cast6_cbc_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec cast6_cbc_dec_tv_template[] = { ++static const struct cipher_testvec cast6_cbc_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" +@@ -14258,7 +14407,7 @@ static struct cipher_testvec cast6_cbc_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec cast6_ctr_enc_tv_template[] = { ++static const struct cipher_testvec cast6_ctr_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" +@@ -14415,7 +14564,7 @@ static struct cipher_testvec cast6_ctr_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec cast6_ctr_dec_tv_template[] = { ++static const struct cipher_testvec cast6_ctr_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" +@@ -14572,7 +14721,7 @@ static struct cipher_testvec cast6_ctr_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec cast6_lrw_enc_tv_template[] = { ++static const struct cipher_testvec cast6_lrw_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c" + "\x23\x84\xcb\x1c\x77\xd6\x19\x5d" +@@ -14719,7 +14868,7 @@ static struct cipher_testvec cast6_lrw_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec cast6_lrw_dec_tv_template[] = { ++static const struct cipher_testvec cast6_lrw_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c" + "\x23\x84\xcb\x1c\x77\xd6\x19\x5d" +@@ -14866,7 +15015,7 @@ static struct cipher_testvec cast6_lrw_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec cast6_xts_enc_tv_template[] = { ++static const struct cipher_testvec cast6_xts_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" +@@ -15015,7 +15164,7 @@ static struct cipher_testvec cast6_xts_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec cast6_xts_dec_tv_template[] = { ++static const struct cipher_testvec cast6_xts_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x27\x18\x28\x18\x28\x45\x90\x45" + "\x23\x53\x60\x28\x74\x71\x35\x26" +@@ -15168,39 +15317,7 @@ static struct cipher_testvec cast6_xts_dec_tv_template[] = { + /* + * AES test vectors. + */ +-#define AES_ENC_TEST_VECTORS 4 +-#define AES_DEC_TEST_VECTORS 4 +-#define AES_CBC_ENC_TEST_VECTORS 5 +-#define AES_CBC_DEC_TEST_VECTORS 5 +-#define HMAC_MD5_ECB_CIPHER_NULL_ENC_TEST_VECTORS 2 +-#define HMAC_MD5_ECB_CIPHER_NULL_DEC_TEST_VECTORS 2 +-#define HMAC_SHA1_ECB_CIPHER_NULL_ENC_TEST_VEC 2 +-#define HMAC_SHA1_ECB_CIPHER_NULL_DEC_TEST_VEC 2 +-#define HMAC_SHA1_AES_CBC_ENC_TEST_VEC 7 +-#define HMAC_SHA256_AES_CBC_ENC_TEST_VEC 7 +-#define HMAC_SHA512_AES_CBC_ENC_TEST_VEC 7 +-#define AES_LRW_ENC_TEST_VECTORS 8 +-#define AES_LRW_DEC_TEST_VECTORS 8 +-#define AES_XTS_ENC_TEST_VECTORS 5 +-#define AES_XTS_DEC_TEST_VECTORS 5 +-#define AES_CTR_ENC_TEST_VECTORS 5 +-#define AES_CTR_DEC_TEST_VECTORS 5 +-#define AES_OFB_ENC_TEST_VECTORS 1 +-#define AES_OFB_DEC_TEST_VECTORS 1 +-#define AES_CTR_3686_ENC_TEST_VECTORS 7 +-#define AES_CTR_3686_DEC_TEST_VECTORS 6 +-#define AES_GCM_ENC_TEST_VECTORS 9 +-#define AES_GCM_DEC_TEST_VECTORS 8 +-#define AES_GCM_4106_ENC_TEST_VECTORS 23 +-#define AES_GCM_4106_DEC_TEST_VECTORS 23 +-#define AES_GCM_4543_ENC_TEST_VECTORS 1 +-#define AES_GCM_4543_DEC_TEST_VECTORS 2 +-#define AES_CCM_ENC_TEST_VECTORS 8 +-#define AES_CCM_DEC_TEST_VECTORS 7 +-#define AES_CCM_4309_ENC_TEST_VECTORS 7 +-#define AES_CCM_4309_DEC_TEST_VECTORS 10 +- +-static struct cipher_testvec aes_enc_tv_template[] = { ++static const struct cipher_testvec aes_enc_tv_template[] = { + { /* From FIPS-197 */ + .key = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", +@@ -15372,7 +15489,7 @@ static struct cipher_testvec aes_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec aes_dec_tv_template[] = { ++static const struct cipher_testvec aes_dec_tv_template[] = { + { /* From FIPS-197 */ + .key = "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", +@@ -15544,7 +15661,7 @@ static struct cipher_testvec aes_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec aes_cbc_enc_tv_template[] = { ++static const struct cipher_testvec aes_cbc_enc_tv_template[] = { + { /* From RFC 3602 */ + .key = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b" + "\x51\x2e\x03\xd5\x34\x12\x00\x06", +@@ -15766,7 +15883,7 @@ static struct cipher_testvec aes_cbc_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec aes_cbc_dec_tv_template[] = { ++static const struct cipher_testvec aes_cbc_dec_tv_template[] = { + { /* From RFC 3602 */ + .key = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b" + "\x51\x2e\x03\xd5\x34\x12\x00\x06", +@@ -15988,7 +16105,7 @@ static struct cipher_testvec aes_cbc_dec_tv_template[] = { + }, + }; + +-static struct aead_testvec hmac_md5_ecb_cipher_null_enc_tv_template[] = { ++static const struct aead_testvec hmac_md5_ecb_cipher_null_enc_tv_template[] = { + { /* Input data from RFC 2410 Case 1 */ + #ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ +@@ -16030,7 +16147,7 @@ static struct aead_testvec hmac_md5_ecb_cipher_null_enc_tv_template[] = { + }, + }; + +-static struct aead_testvec hmac_md5_ecb_cipher_null_dec_tv_template[] = { ++static const struct aead_testvec hmac_md5_ecb_cipher_null_dec_tv_template[] = { + { + #ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ +@@ -16072,7 +16189,7 @@ static struct aead_testvec hmac_md5_ecb_cipher_null_dec_tv_template[] = { + }, + }; + +-static struct aead_testvec hmac_sha1_aes_cbc_enc_tv_temp[] = { ++static const struct aead_testvec hmac_sha1_aes_cbc_enc_tv_temp[] = { + { /* RFC 3602 Case 1 */ + #ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ +@@ -16341,7 +16458,7 @@ static struct aead_testvec hmac_sha1_aes_cbc_enc_tv_temp[] = { + }, + }; + +-static struct aead_testvec hmac_sha1_ecb_cipher_null_enc_tv_temp[] = { ++static const struct aead_testvec hmac_sha1_ecb_cipher_null_enc_tv_temp[] = { + { /* Input data from RFC 2410 Case 1 */ + #ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ +@@ -16387,7 +16504,7 @@ static struct aead_testvec hmac_sha1_ecb_cipher_null_enc_tv_temp[] = { + }, + }; + +-static struct aead_testvec hmac_sha1_ecb_cipher_null_dec_tv_temp[] = { ++static const struct aead_testvec hmac_sha1_ecb_cipher_null_dec_tv_temp[] = { + { + #ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ +@@ -16433,7 +16550,7 @@ static struct aead_testvec hmac_sha1_ecb_cipher_null_dec_tv_temp[] = { + }, + }; + +-static struct aead_testvec hmac_sha256_aes_cbc_enc_tv_temp[] = { ++static const struct aead_testvec hmac_sha256_aes_cbc_enc_tv_temp[] = { + { /* RFC 3602 Case 1 */ + #ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ +@@ -16716,7 +16833,7 @@ static struct aead_testvec hmac_sha256_aes_cbc_enc_tv_temp[] = { + }, + }; + +-static struct aead_testvec hmac_sha512_aes_cbc_enc_tv_temp[] = { ++static const struct aead_testvec hmac_sha512_aes_cbc_enc_tv_temp[] = { + { /* RFC 3602 Case 1 */ + #ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ +@@ -17055,9 +17172,7 @@ static struct aead_testvec hmac_sha512_aes_cbc_enc_tv_temp[] = { + }, + }; + +-#define HMAC_SHA1_DES_CBC_ENC_TEST_VEC 1 +- +-static struct aead_testvec hmac_sha1_des_cbc_enc_tv_temp[] = { ++static const struct aead_testvec hmac_sha1_des_cbc_enc_tv_temp[] = { + { /*Generated with cryptopp*/ + #ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ +@@ -17116,9 +17231,7 @@ static struct aead_testvec hmac_sha1_des_cbc_enc_tv_temp[] = { + }, + }; + +-#define HMAC_SHA224_DES_CBC_ENC_TEST_VEC 1 +- +-static struct aead_testvec hmac_sha224_des_cbc_enc_tv_temp[] = { ++static const struct aead_testvec hmac_sha224_des_cbc_enc_tv_temp[] = { + { /*Generated with cryptopp*/ + #ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ +@@ -17177,9 +17290,7 @@ static struct aead_testvec hmac_sha224_des_cbc_enc_tv_temp[] = { + }, + }; + +-#define HMAC_SHA256_DES_CBC_ENC_TEST_VEC 1 +- +-static struct aead_testvec hmac_sha256_des_cbc_enc_tv_temp[] = { ++static const struct aead_testvec hmac_sha256_des_cbc_enc_tv_temp[] = { + { /*Generated with cryptopp*/ + #ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ +@@ -17240,9 +17351,7 @@ static struct aead_testvec hmac_sha256_des_cbc_enc_tv_temp[] = { + }, + }; + +-#define HMAC_SHA384_DES_CBC_ENC_TEST_VEC 1 +- +-static struct aead_testvec hmac_sha384_des_cbc_enc_tv_temp[] = { ++static const struct aead_testvec hmac_sha384_des_cbc_enc_tv_temp[] = { + { /*Generated with cryptopp*/ + #ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ +@@ -17307,9 +17416,7 @@ static struct aead_testvec hmac_sha384_des_cbc_enc_tv_temp[] = { + }, + }; + +-#define HMAC_SHA512_DES_CBC_ENC_TEST_VEC 1 +- +-static struct aead_testvec hmac_sha512_des_cbc_enc_tv_temp[] = { ++static const struct aead_testvec hmac_sha512_des_cbc_enc_tv_temp[] = { + { /*Generated with cryptopp*/ + #ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ +@@ -17378,9 +17485,7 @@ static struct aead_testvec hmac_sha512_des_cbc_enc_tv_temp[] = { + }, + }; + +-#define HMAC_SHA1_DES3_EDE_CBC_ENC_TEST_VEC 1 +- +-static struct aead_testvec hmac_sha1_des3_ede_cbc_enc_tv_temp[] = { ++static const struct aead_testvec hmac_sha1_des3_ede_cbc_enc_tv_temp[] = { + { /*Generated with cryptopp*/ + #ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ +@@ -17441,9 +17546,7 @@ static struct aead_testvec hmac_sha1_des3_ede_cbc_enc_tv_temp[] = { + }, + }; + +-#define HMAC_SHA224_DES3_EDE_CBC_ENC_TEST_VEC 1 +- +-static struct aead_testvec hmac_sha224_des3_ede_cbc_enc_tv_temp[] = { ++static const struct aead_testvec hmac_sha224_des3_ede_cbc_enc_tv_temp[] = { + { /*Generated with cryptopp*/ + #ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ +@@ -17504,9 +17607,7 @@ static struct aead_testvec hmac_sha224_des3_ede_cbc_enc_tv_temp[] = { + }, + }; + +-#define HMAC_SHA256_DES3_EDE_CBC_ENC_TEST_VEC 1 +- +-static struct aead_testvec hmac_sha256_des3_ede_cbc_enc_tv_temp[] = { ++static const struct aead_testvec hmac_sha256_des3_ede_cbc_enc_tv_temp[] = { + { /*Generated with cryptopp*/ + #ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ +@@ -17569,9 +17670,7 @@ static struct aead_testvec hmac_sha256_des3_ede_cbc_enc_tv_temp[] = { + }, + }; + +-#define HMAC_SHA384_DES3_EDE_CBC_ENC_TEST_VEC 1 +- +-static struct aead_testvec hmac_sha384_des3_ede_cbc_enc_tv_temp[] = { ++static const struct aead_testvec hmac_sha384_des3_ede_cbc_enc_tv_temp[] = { + { /*Generated with cryptopp*/ + #ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ +@@ -17638,9 +17737,7 @@ static struct aead_testvec hmac_sha384_des3_ede_cbc_enc_tv_temp[] = { + }, + }; + +-#define HMAC_SHA512_DES3_EDE_CBC_ENC_TEST_VEC 1 +- +-static struct aead_testvec hmac_sha512_des3_ede_cbc_enc_tv_temp[] = { ++static const struct aead_testvec hmac_sha512_des3_ede_cbc_enc_tv_temp[] = { + { /*Generated with cryptopp*/ + #ifdef __LITTLE_ENDIAN + .key = "\x08\x00" /* rta length */ +@@ -17711,7 +17808,7 @@ static struct aead_testvec hmac_sha512_des3_ede_cbc_enc_tv_temp[] = { + }, + }; + +-static struct cipher_testvec aes_lrw_enc_tv_template[] = { ++static const struct cipher_testvec aes_lrw_enc_tv_template[] = { + /* from http://grouper.ieee.org/groups/1619/email/pdf00017.pdf */ + { /* LRW-32-AES 1 */ + .key = "\x45\x62\xac\x25\xf8\x28\x17\x6d" +@@ -17964,7 +18061,7 @@ static struct cipher_testvec aes_lrw_enc_tv_template[] = { + } + }; + +-static struct cipher_testvec aes_lrw_dec_tv_template[] = { ++static const struct cipher_testvec aes_lrw_dec_tv_template[] = { + /* from http://grouper.ieee.org/groups/1619/email/pdf00017.pdf */ + /* same as enc vectors with input and result reversed */ + { /* LRW-32-AES 1 */ +@@ -18218,7 +18315,7 @@ static struct cipher_testvec aes_lrw_dec_tv_template[] = { + } + }; + +-static struct cipher_testvec aes_xts_enc_tv_template[] = { ++static const struct cipher_testvec aes_xts_enc_tv_template[] = { + /* http://grouper.ieee.org/groups/1619/email/pdf00086.pdf */ + { /* XTS-AES 1 */ + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" +@@ -18561,7 +18658,7 @@ static struct cipher_testvec aes_xts_enc_tv_template[] = { + } + }; + +-static struct cipher_testvec aes_xts_dec_tv_template[] = { ++static const struct cipher_testvec aes_xts_dec_tv_template[] = { + /* http://grouper.ieee.org/groups/1619/email/pdf00086.pdf */ + { /* XTS-AES 1 */ + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" +@@ -18905,7 +19002,7 @@ static struct cipher_testvec aes_xts_dec_tv_template[] = { + }; + + +-static struct cipher_testvec aes_ctr_enc_tv_template[] = { ++static const struct cipher_testvec aes_ctr_enc_tv_template[] = { + { /* From NIST Special Publication 800-38A, Appendix F.5 */ + .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" + "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", +@@ -19260,7 +19357,7 @@ static struct cipher_testvec aes_ctr_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec aes_ctr_dec_tv_template[] = { ++static const struct cipher_testvec aes_ctr_dec_tv_template[] = { + { /* From NIST Special Publication 800-38A, Appendix F.5 */ + .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" + "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", +@@ -19615,7 +19712,7 @@ static struct cipher_testvec aes_ctr_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec aes_ctr_rfc3686_enc_tv_template[] = { ++static const struct cipher_testvec aes_ctr_rfc3686_enc_tv_template[] = { + { /* From RFC 3686 */ + .key = "\xae\x68\x52\xf8\x12\x10\x67\xcc" + "\x4b\xf7\xa5\x76\x55\x77\xf3\x9e" +@@ -20747,7 +20844,7 @@ static struct cipher_testvec aes_ctr_rfc3686_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec aes_ctr_rfc3686_dec_tv_template[] = { ++static const struct cipher_testvec aes_ctr_rfc3686_dec_tv_template[] = { + { /* From RFC 3686 */ + .key = "\xae\x68\x52\xf8\x12\x10\x67\xcc" + "\x4b\xf7\xa5\x76\x55\x77\xf3\x9e" +@@ -20838,7 +20935,7 @@ static struct cipher_testvec aes_ctr_rfc3686_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec aes_ofb_enc_tv_template[] = { ++static const struct cipher_testvec aes_ofb_enc_tv_template[] = { + /* From NIST Special Publication 800-38A, Appendix F.5 */ + { + .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" +@@ -20867,7 +20964,7 @@ static struct cipher_testvec aes_ofb_enc_tv_template[] = { + } + }; + +-static struct cipher_testvec aes_ofb_dec_tv_template[] = { ++static const struct cipher_testvec aes_ofb_dec_tv_template[] = { + /* From NIST Special Publication 800-38A, Appendix F.5 */ + { + .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" +@@ -20896,7 +20993,7 @@ static struct cipher_testvec aes_ofb_dec_tv_template[] = { + } + }; + +-static struct aead_testvec aes_gcm_enc_tv_template[] = { ++static const struct aead_testvec aes_gcm_enc_tv_template[] = { + { /* From McGrew & Viega - http://citeseer.ist.psu.edu/656989.html */ + .key = zeroed_string, + .klen = 16, +@@ -21056,7 +21153,7 @@ static struct aead_testvec aes_gcm_enc_tv_template[] = { + } + }; + +-static struct aead_testvec aes_gcm_dec_tv_template[] = { ++static const struct aead_testvec aes_gcm_dec_tv_template[] = { + { /* From McGrew & Viega - http://citeseer.ist.psu.edu/656989.html */ + .key = zeroed_string, + .klen = 32, +@@ -21258,7 +21355,7 @@ static struct aead_testvec aes_gcm_dec_tv_template[] = { + } + }; + +-static struct aead_testvec aes_gcm_rfc4106_enc_tv_template[] = { ++static const struct aead_testvec aes_gcm_rfc4106_enc_tv_template[] = { + { /* Generated using Crypto++ */ + .key = zeroed_string, + .klen = 20, +@@ -21871,7 +21968,7 @@ static struct aead_testvec aes_gcm_rfc4106_enc_tv_template[] = { + } + }; + +-static struct aead_testvec aes_gcm_rfc4106_dec_tv_template[] = { ++static const struct aead_testvec aes_gcm_rfc4106_dec_tv_template[] = { + { /* Generated using Crypto++ */ + .key = zeroed_string, + .klen = 20, +@@ -22485,7 +22582,7 @@ static struct aead_testvec aes_gcm_rfc4106_dec_tv_template[] = { + } + }; + +-static struct aead_testvec aes_gcm_rfc4543_enc_tv_template[] = { ++static const struct aead_testvec aes_gcm_rfc4543_enc_tv_template[] = { + { /* From draft-mcgrew-gcm-test-01 */ + .key = "\x4c\x80\xcd\xef\xbb\x5d\x10\xda" + "\x90\x6a\xc7\x3c\x36\x13\xa6\x34" +@@ -22516,7 +22613,7 @@ static struct aead_testvec aes_gcm_rfc4543_enc_tv_template[] = { + } + }; + +-static struct aead_testvec aes_gcm_rfc4543_dec_tv_template[] = { ++static const struct aead_testvec aes_gcm_rfc4543_dec_tv_template[] = { + { /* From draft-mcgrew-gcm-test-01 */ + .key = "\x4c\x80\xcd\xef\xbb\x5d\x10\xda" + "\x90\x6a\xc7\x3c\x36\x13\xa6\x34" +@@ -22575,7 +22672,7 @@ static struct aead_testvec aes_gcm_rfc4543_dec_tv_template[] = { + }, + }; + +-static struct aead_testvec aes_ccm_enc_tv_template[] = { ++static const struct aead_testvec aes_ccm_enc_tv_template[] = { + { /* From RFC 3610 */ + .key = "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", +@@ -22859,7 +22956,7 @@ static struct aead_testvec aes_ccm_enc_tv_template[] = { + } + }; + +-static struct aead_testvec aes_ccm_dec_tv_template[] = { ++static const struct aead_testvec aes_ccm_dec_tv_template[] = { + { /* From RFC 3610 */ + .key = "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" + "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf", +@@ -23191,7 +23288,7 @@ static struct aead_testvec aes_ccm_dec_tv_template[] = { + * These vectors are copied/generated from the ones for rfc4106 with + * the key truncated by one byte.. + */ +-static struct aead_testvec aes_ccm_rfc4309_enc_tv_template[] = { ++static const struct aead_testvec aes_ccm_rfc4309_enc_tv_template[] = { + { /* Generated using Crypto++ */ + .key = zeroed_string, + .klen = 19, +@@ -23804,7 +23901,7 @@ static struct aead_testvec aes_ccm_rfc4309_enc_tv_template[] = { + } + }; + +-static struct aead_testvec aes_ccm_rfc4309_dec_tv_template[] = { ++static const struct aead_testvec aes_ccm_rfc4309_dec_tv_template[] = { + { /* Generated using Crypto++ */ + .key = zeroed_string, + .klen = 19, +@@ -24420,9 +24517,7 @@ static struct aead_testvec aes_ccm_rfc4309_dec_tv_template[] = { + /* + * ChaCha20-Poly1305 AEAD test vectors from RFC7539 2.8.2./A.5. + */ +-#define RFC7539_ENC_TEST_VECTORS 2 +-#define RFC7539_DEC_TEST_VECTORS 2 +-static struct aead_testvec rfc7539_enc_tv_template[] = { ++static const struct aead_testvec rfc7539_enc_tv_template[] = { + { + .key = "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" +@@ -24554,7 +24649,7 @@ static struct aead_testvec rfc7539_enc_tv_template[] = { + }, + }; + +-static struct aead_testvec rfc7539_dec_tv_template[] = { ++static const struct aead_testvec rfc7539_dec_tv_template[] = { + { + .key = "\x80\x81\x82\x83\x84\x85\x86\x87" + "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" +@@ -24689,9 +24784,7 @@ static struct aead_testvec rfc7539_dec_tv_template[] = { + /* + * draft-irtf-cfrg-chacha20-poly1305 + */ +-#define RFC7539ESP_DEC_TEST_VECTORS 1 +-#define RFC7539ESP_ENC_TEST_VECTORS 1 +-static struct aead_testvec rfc7539esp_enc_tv_template[] = { ++static const struct aead_testvec rfc7539esp_enc_tv_template[] = { + { + .key = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a" + "\xf3\x33\x88\x86\x04\xf6\xb5\xf0" +@@ -24779,7 +24872,7 @@ static struct aead_testvec rfc7539esp_enc_tv_template[] = { + }, + }; + +-static struct aead_testvec rfc7539esp_dec_tv_template[] = { ++static const struct aead_testvec rfc7539esp_dec_tv_template[] = { + { + .key = "\x1c\x92\x40\xa5\xeb\x55\xd3\x8a" + "\xf3\x33\x88\x86\x04\xf6\xb5\xf0" +@@ -24875,7 +24968,7 @@ static struct aead_testvec rfc7539esp_dec_tv_template[] = { + * semiblock of the ciphertext from the test vector. For decryption, iv is + * the first semiblock of the ciphertext. + */ +-static struct cipher_testvec aes_kw_enc_tv_template[] = { ++static const struct cipher_testvec aes_kw_enc_tv_template[] = { + { + .key = "\x75\x75\xda\x3a\x93\x60\x7c\xc2" + "\xbf\xd8\xce\xc7\xaa\xdf\xd9\xa6", +@@ -24890,7 +24983,7 @@ static struct cipher_testvec aes_kw_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec aes_kw_dec_tv_template[] = { ++static const struct cipher_testvec aes_kw_dec_tv_template[] = { + { + .key = "\x80\xaa\x99\x73\x27\xa4\x80\x6b" + "\x6a\x7a\x41\xa5\x2b\x86\xc3\x71" +@@ -24913,9 +25006,7 @@ static struct cipher_testvec aes_kw_dec_tv_template[] = { + * http://csrc.nist.gov/groups/STM/cavp/documents/rng/RNGVS.pdf + * Only AES-128 is supported at this time. + */ +-#define ANSI_CPRNG_AES_TEST_VECTORS 6 +- +-static struct cprng_testvec ansi_cprng_aes_tv_template[] = { ++static const struct cprng_testvec ansi_cprng_aes_tv_template[] = { + { + .key = "\xf3\xb1\x66\x6d\x13\x60\x72\x42" + "\xed\x06\x1c\xab\xb8\xd4\x62\x02", +@@ -25011,7 +25102,7 @@ static struct cprng_testvec ansi_cprng_aes_tv_template[] = { + * (Hash, HMAC, CTR) are tested with all permutations of use cases (w/ and + * w/o personalization string, w/ and w/o additional input string). + */ +-static struct drbg_testvec drbg_pr_sha256_tv_template[] = { ++static const struct drbg_testvec drbg_pr_sha256_tv_template[] = { + { + .entropy = (unsigned char *) + "\x72\x88\x4c\xcd\x6c\x85\x57\x70\xf7\x0b\x8b\x86" +@@ -25169,7 +25260,7 @@ static struct drbg_testvec drbg_pr_sha256_tv_template[] = { + }, + }; + +-static struct drbg_testvec drbg_pr_hmac_sha256_tv_template[] = { ++static const struct drbg_testvec drbg_pr_hmac_sha256_tv_template[] = { + { + .entropy = (unsigned char *) + "\x99\x69\xe5\x4b\x47\x03\xff\x31\x78\x5b\x87\x9a" +@@ -25327,7 +25418,7 @@ static struct drbg_testvec drbg_pr_hmac_sha256_tv_template[] = { + }, + }; + +-static struct drbg_testvec drbg_pr_ctr_aes128_tv_template[] = { ++static const struct drbg_testvec drbg_pr_ctr_aes128_tv_template[] = { + { + .entropy = (unsigned char *) + "\xd1\x44\xc6\x61\x81\x6d\xca\x9d\x15\x28\x8a\x42" +@@ -25451,7 +25542,7 @@ static struct drbg_testvec drbg_pr_ctr_aes128_tv_template[] = { + * (Hash, HMAC, CTR) are tested with all permutations of use cases (w/ and + * w/o personalization string, w/ and w/o additional input string). + */ +-static struct drbg_testvec drbg_nopr_sha256_tv_template[] = { ++static const struct drbg_testvec drbg_nopr_sha256_tv_template[] = { + { + .entropy = (unsigned char *) + "\xa6\x5a\xd0\xf3\x45\xdb\x4e\x0e\xff\xe8\x75\xc3" +@@ -25573,7 +25664,7 @@ static struct drbg_testvec drbg_nopr_sha256_tv_template[] = { + }, + }; + +-static struct drbg_testvec drbg_nopr_hmac_sha256_tv_template[] = { ++static const struct drbg_testvec drbg_nopr_hmac_sha256_tv_template[] = { + { + .entropy = (unsigned char *) + "\xca\x85\x19\x11\x34\x93\x84\xbf\xfe\x89\xde\x1c" +@@ -25695,7 +25786,7 @@ static struct drbg_testvec drbg_nopr_hmac_sha256_tv_template[] = { + }, + }; + +-static struct drbg_testvec drbg_nopr_ctr_aes192_tv_template[] = { ++static const struct drbg_testvec drbg_nopr_ctr_aes192_tv_template[] = { + { + .entropy = (unsigned char *) + "\xc3\x5c\x2f\xa2\xa8\x9d\x52\xa1\x1f\xa3\x2a\xa9" +@@ -25719,7 +25810,7 @@ static struct drbg_testvec drbg_nopr_ctr_aes192_tv_template[] = { + }, + }; + +-static struct drbg_testvec drbg_nopr_ctr_aes256_tv_template[] = { ++static const struct drbg_testvec drbg_nopr_ctr_aes256_tv_template[] = { + { + .entropy = (unsigned char *) + "\x36\x40\x19\x40\xfa\x8b\x1f\xba\x91\xa1\x66\x1f" +@@ -25743,7 +25834,7 @@ static struct drbg_testvec drbg_nopr_ctr_aes256_tv_template[] = { + }, + }; + +-static struct drbg_testvec drbg_nopr_ctr_aes128_tv_template[] = { ++static const struct drbg_testvec drbg_nopr_ctr_aes128_tv_template[] = { + { + .entropy = (unsigned char *) + "\x87\xe1\xc5\x32\x99\x7f\x57\xa3\x5c\x28\x6d\xe8" +@@ -25832,14 +25923,7 @@ static struct drbg_testvec drbg_nopr_ctr_aes128_tv_template[] = { + }; + + /* Cast5 test vectors from RFC 2144 */ +-#define CAST5_ENC_TEST_VECTORS 4 +-#define CAST5_DEC_TEST_VECTORS 4 +-#define CAST5_CBC_ENC_TEST_VECTORS 1 +-#define CAST5_CBC_DEC_TEST_VECTORS 1 +-#define CAST5_CTR_ENC_TEST_VECTORS 2 +-#define CAST5_CTR_DEC_TEST_VECTORS 2 +- +-static struct cipher_testvec cast5_enc_tv_template[] = { ++static const struct cipher_testvec cast5_enc_tv_template[] = { + { + .key = "\x01\x23\x45\x67\x12\x34\x56\x78" + "\x23\x45\x67\x89\x34\x56\x78\x9a", +@@ -26000,7 +26084,7 @@ static struct cipher_testvec cast5_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec cast5_dec_tv_template[] = { ++static const struct cipher_testvec cast5_dec_tv_template[] = { + { + .key = "\x01\x23\x45\x67\x12\x34\x56\x78" + "\x23\x45\x67\x89\x34\x56\x78\x9a", +@@ -26161,7 +26245,7 @@ static struct cipher_testvec cast5_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec cast5_cbc_enc_tv_template[] = { ++static const struct cipher_testvec cast5_cbc_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", +@@ -26299,7 +26383,7 @@ static struct cipher_testvec cast5_cbc_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec cast5_cbc_dec_tv_template[] = { ++static const struct cipher_testvec cast5_cbc_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", +@@ -26437,7 +26521,7 @@ static struct cipher_testvec cast5_cbc_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec cast5_ctr_enc_tv_template[] = { ++static const struct cipher_testvec cast5_ctr_enc_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", +@@ -26588,7 +26672,7 @@ static struct cipher_testvec cast5_ctr_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec cast5_ctr_dec_tv_template[] = { ++static const struct cipher_testvec cast5_ctr_dec_tv_template[] = { + { /* Generated from TF test vectors */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A", +@@ -26742,10 +26826,7 @@ static struct cipher_testvec cast5_ctr_dec_tv_template[] = { + /* + * ARC4 test vectors from OpenSSL + */ +-#define ARC4_ENC_TEST_VECTORS 7 +-#define ARC4_DEC_TEST_VECTORS 7 +- +-static struct cipher_testvec arc4_enc_tv_template[] = { ++static const struct cipher_testvec arc4_enc_tv_template[] = { + { + .key = "\x01\x23\x45\x67\x89\xab\xcd\xef", + .klen = 8, +@@ -26811,7 +26892,7 @@ static struct cipher_testvec arc4_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec arc4_dec_tv_template[] = { ++static const struct cipher_testvec arc4_dec_tv_template[] = { + { + .key = "\x01\x23\x45\x67\x89\xab\xcd\xef", + .klen = 8, +@@ -26880,10 +26961,7 @@ static struct cipher_testvec arc4_dec_tv_template[] = { + /* + * TEA test vectors + */ +-#define TEA_ENC_TEST_VECTORS 4 +-#define TEA_DEC_TEST_VECTORS 4 +- +-static struct cipher_testvec tea_enc_tv_template[] = { ++static const struct cipher_testvec tea_enc_tv_template[] = { + { + .key = zeroed_string, + .klen = 16, +@@ -26926,7 +27004,7 @@ static struct cipher_testvec tea_enc_tv_template[] = { + } + }; + +-static struct cipher_testvec tea_dec_tv_template[] = { ++static const struct cipher_testvec tea_dec_tv_template[] = { + { + .key = zeroed_string, + .klen = 16, +@@ -26972,10 +27050,7 @@ static struct cipher_testvec tea_dec_tv_template[] = { + /* + * XTEA test vectors + */ +-#define XTEA_ENC_TEST_VECTORS 4 +-#define XTEA_DEC_TEST_VECTORS 4 +- +-static struct cipher_testvec xtea_enc_tv_template[] = { ++static const struct cipher_testvec xtea_enc_tv_template[] = { + { + .key = zeroed_string, + .klen = 16, +@@ -27018,7 +27093,7 @@ static struct cipher_testvec xtea_enc_tv_template[] = { + } + }; + +-static struct cipher_testvec xtea_dec_tv_template[] = { ++static const struct cipher_testvec xtea_dec_tv_template[] = { + { + .key = zeroed_string, + .klen = 16, +@@ -27064,10 +27139,7 @@ static struct cipher_testvec xtea_dec_tv_template[] = { + /* + * KHAZAD test vectors. + */ +-#define KHAZAD_ENC_TEST_VECTORS 5 +-#define KHAZAD_DEC_TEST_VECTORS 5 +- +-static struct cipher_testvec khazad_enc_tv_template[] = { ++static const struct cipher_testvec khazad_enc_tv_template[] = { + { + .key = "\x80\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", +@@ -27113,7 +27185,7 @@ static struct cipher_testvec khazad_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec khazad_dec_tv_template[] = { ++static const struct cipher_testvec khazad_dec_tv_template[] = { + { + .key = "\x80\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", +@@ -27163,12 +27235,7 @@ static struct cipher_testvec khazad_dec_tv_template[] = { + * Anubis test vectors. + */ + +-#define ANUBIS_ENC_TEST_VECTORS 5 +-#define ANUBIS_DEC_TEST_VECTORS 5 +-#define ANUBIS_CBC_ENC_TEST_VECTORS 2 +-#define ANUBIS_CBC_DEC_TEST_VECTORS 2 +- +-static struct cipher_testvec anubis_enc_tv_template[] = { ++static const struct cipher_testvec anubis_enc_tv_template[] = { + { + .key = "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe" + "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe", +@@ -27231,7 +27298,7 @@ static struct cipher_testvec anubis_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec anubis_dec_tv_template[] = { ++static const struct cipher_testvec anubis_dec_tv_template[] = { + { + .key = "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe" + "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe", +@@ -27294,7 +27361,7 @@ static struct cipher_testvec anubis_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec anubis_cbc_enc_tv_template[] = { ++static const struct cipher_testvec anubis_cbc_enc_tv_template[] = { + { + .key = "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe" + "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe", +@@ -27329,7 +27396,7 @@ static struct cipher_testvec anubis_cbc_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec anubis_cbc_dec_tv_template[] = { ++static const struct cipher_testvec anubis_cbc_dec_tv_template[] = { + { + .key = "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe" + "\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe", +@@ -27367,10 +27434,7 @@ static struct cipher_testvec anubis_cbc_dec_tv_template[] = { + /* + * XETA test vectors + */ +-#define XETA_ENC_TEST_VECTORS 4 +-#define XETA_DEC_TEST_VECTORS 4 +- +-static struct cipher_testvec xeta_enc_tv_template[] = { ++static const struct cipher_testvec xeta_enc_tv_template[] = { + { + .key = zeroed_string, + .klen = 16, +@@ -27413,7 +27477,7 @@ static struct cipher_testvec xeta_enc_tv_template[] = { + } + }; + +-static struct cipher_testvec xeta_dec_tv_template[] = { ++static const struct cipher_testvec xeta_dec_tv_template[] = { + { + .key = zeroed_string, + .klen = 16, +@@ -27459,10 +27523,7 @@ static struct cipher_testvec xeta_dec_tv_template[] = { + /* + * FCrypt test vectors + */ +-#define FCRYPT_ENC_TEST_VECTORS ARRAY_SIZE(fcrypt_pcbc_enc_tv_template) +-#define FCRYPT_DEC_TEST_VECTORS ARRAY_SIZE(fcrypt_pcbc_dec_tv_template) +- +-static struct cipher_testvec fcrypt_pcbc_enc_tv_template[] = { ++static const struct cipher_testvec fcrypt_pcbc_enc_tv_template[] = { + { /* http://www.openafs.org/pipermail/openafs-devel/2000-December/005320.html */ + .key = "\x00\x00\x00\x00\x00\x00\x00\x00", + .klen = 8, +@@ -27523,7 +27584,7 @@ static struct cipher_testvec fcrypt_pcbc_enc_tv_template[] = { + } + }; + +-static struct cipher_testvec fcrypt_pcbc_dec_tv_template[] = { ++static const struct cipher_testvec fcrypt_pcbc_dec_tv_template[] = { + { /* http://www.openafs.org/pipermail/openafs-devel/2000-December/005320.html */ + .key = "\x00\x00\x00\x00\x00\x00\x00\x00", + .klen = 8, +@@ -27587,18 +27648,7 @@ static struct cipher_testvec fcrypt_pcbc_dec_tv_template[] = { + /* + * CAMELLIA test vectors. + */ +-#define CAMELLIA_ENC_TEST_VECTORS 4 +-#define CAMELLIA_DEC_TEST_VECTORS 4 +-#define CAMELLIA_CBC_ENC_TEST_VECTORS 3 +-#define CAMELLIA_CBC_DEC_TEST_VECTORS 3 +-#define CAMELLIA_CTR_ENC_TEST_VECTORS 2 +-#define CAMELLIA_CTR_DEC_TEST_VECTORS 2 +-#define CAMELLIA_LRW_ENC_TEST_VECTORS 8 +-#define CAMELLIA_LRW_DEC_TEST_VECTORS 8 +-#define CAMELLIA_XTS_ENC_TEST_VECTORS 5 +-#define CAMELLIA_XTS_DEC_TEST_VECTORS 5 +- +-static struct cipher_testvec camellia_enc_tv_template[] = { ++static const struct cipher_testvec camellia_enc_tv_template[] = { + { + .key = "\x01\x23\x45\x67\x89\xab\xcd\xef" + "\xfe\xdc\xba\x98\x76\x54\x32\x10", +@@ -27898,7 +27948,7 @@ static struct cipher_testvec camellia_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec camellia_dec_tv_template[] = { ++static const struct cipher_testvec camellia_dec_tv_template[] = { + { + .key = "\x01\x23\x45\x67\x89\xab\xcd\xef" + "\xfe\xdc\xba\x98\x76\x54\x32\x10", +@@ -28198,7 +28248,7 @@ static struct cipher_testvec camellia_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec camellia_cbc_enc_tv_template[] = { ++static const struct cipher_testvec camellia_cbc_enc_tv_template[] = { + { + .key = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b" + "\x51\x2e\x03\xd5\x34\x12\x00\x06", +@@ -28494,7 +28544,7 @@ static struct cipher_testvec camellia_cbc_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec camellia_cbc_dec_tv_template[] = { ++static const struct cipher_testvec camellia_cbc_dec_tv_template[] = { + { + .key = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b" + "\x51\x2e\x03\xd5\x34\x12\x00\x06", +@@ -28790,7 +28840,7 @@ static struct cipher_testvec camellia_cbc_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec camellia_ctr_enc_tv_template[] = { ++static const struct cipher_testvec camellia_ctr_enc_tv_template[] = { + { /* Generated with Crypto++ */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" +@@ -29457,7 +29507,7 @@ static struct cipher_testvec camellia_ctr_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec camellia_ctr_dec_tv_template[] = { ++static const struct cipher_testvec camellia_ctr_dec_tv_template[] = { + { /* Generated with Crypto++ */ + .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" + "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" +@@ -30124,7 +30174,7 @@ static struct cipher_testvec camellia_ctr_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec camellia_lrw_enc_tv_template[] = { ++static const struct cipher_testvec camellia_lrw_enc_tv_template[] = { + /* Generated from AES-LRW test vectors */ + { + .key = "\x45\x62\xac\x25\xf8\x28\x17\x6d" +@@ -30376,7 +30426,7 @@ static struct cipher_testvec camellia_lrw_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec camellia_lrw_dec_tv_template[] = { ++static const struct cipher_testvec camellia_lrw_dec_tv_template[] = { + /* Generated from AES-LRW test vectors */ + /* same as enc vectors with input and result reversed */ + { +@@ -30629,7 +30679,7 @@ static struct cipher_testvec camellia_lrw_dec_tv_template[] = { + }, + }; + +-static struct cipher_testvec camellia_xts_enc_tv_template[] = { ++static const struct cipher_testvec camellia_xts_enc_tv_template[] = { + /* Generated from AES-XTS test vectors */ + { + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" +@@ -30971,7 +31021,7 @@ static struct cipher_testvec camellia_xts_enc_tv_template[] = { + }, + }; + +-static struct cipher_testvec camellia_xts_dec_tv_template[] = { ++static const struct cipher_testvec camellia_xts_dec_tv_template[] = { + /* Generated from AES-XTS test vectors */ + /* same as enc vectors with input and result reversed */ + { +@@ -31317,10 +31367,7 @@ static struct cipher_testvec camellia_xts_dec_tv_template[] = { + /* + * SEED test vectors + */ +-#define SEED_ENC_TEST_VECTORS 4 +-#define SEED_DEC_TEST_VECTORS 4 +- +-static struct cipher_testvec seed_enc_tv_template[] = { ++static const struct cipher_testvec seed_enc_tv_template[] = { + { + .key = zeroed_string, + .klen = 16, +@@ -31362,7 +31409,7 @@ static struct cipher_testvec seed_enc_tv_template[] = { + } + }; + +-static struct cipher_testvec seed_dec_tv_template[] = { ++static const struct cipher_testvec seed_dec_tv_template[] = { + { + .key = zeroed_string, + .klen = 16, +@@ -31404,8 +31451,7 @@ static struct cipher_testvec seed_dec_tv_template[] = { + } + }; + +-#define SALSA20_STREAM_ENC_TEST_VECTORS 5 +-static struct cipher_testvec salsa20_stream_enc_tv_template[] = { ++static const struct cipher_testvec salsa20_stream_enc_tv_template[] = { + /* + * Testvectors from verified.test-vectors submitted to ECRYPT. + * They are truncated to size 39, 64, 111, 129 to test a variety +@@ -32574,8 +32620,7 @@ static struct cipher_testvec salsa20_stream_enc_tv_template[] = { + }, + }; + +-#define CHACHA20_ENC_TEST_VECTORS 4 +-static struct cipher_testvec chacha20_enc_tv_template[] = { ++static const struct cipher_testvec chacha20_enc_tv_template[] = { + { /* RFC7539 A.2. Test Vector #1 */ + .key = "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00" +@@ -33086,9 +33131,7 @@ static struct cipher_testvec chacha20_enc_tv_template[] = { + /* + * CTS (Cipher Text Stealing) mode tests + */ +-#define CTS_MODE_ENC_TEST_VECTORS 6 +-#define CTS_MODE_DEC_TEST_VECTORS 6 +-static struct cipher_testvec cts_mode_enc_tv_template[] = { ++static const struct cipher_testvec cts_mode_enc_tv_template[] = { + { /* from rfc3962 */ + .klen = 16, + .key = "\x63\x68\x69\x63\x6b\x65\x6e\x20" +@@ -33190,7 +33233,7 @@ static struct cipher_testvec cts_mode_enc_tv_template[] = { + } + }; + +-static struct cipher_testvec cts_mode_dec_tv_template[] = { ++static const struct cipher_testvec cts_mode_dec_tv_template[] = { + { /* from rfc3962 */ + .klen = 16, + .key = "\x63\x68\x69\x63\x6b\x65\x6e\x20" +@@ -33308,10 +33351,7 @@ struct comp_testvec { + * Params: winbits=-11, Z_DEFAULT_COMPRESSION, MAX_MEM_LEVEL. + */ + +-#define DEFLATE_COMP_TEST_VECTORS 2 +-#define DEFLATE_DECOMP_TEST_VECTORS 2 +- +-static struct comp_testvec deflate_comp_tv_template[] = { ++static const struct comp_testvec deflate_comp_tv_template[] = { + { + .inlen = 70, + .outlen = 38, +@@ -33347,7 +33387,7 @@ static struct comp_testvec deflate_comp_tv_template[] = { + }, + }; + +-static struct comp_testvec deflate_decomp_tv_template[] = { ++static const struct comp_testvec deflate_decomp_tv_template[] = { + { + .inlen = 122, + .outlen = 191, +@@ -33386,10 +33426,7 @@ static struct comp_testvec deflate_decomp_tv_template[] = { + /* + * LZO test vectors (null-terminated strings). + */ +-#define LZO_COMP_TEST_VECTORS 2 +-#define LZO_DECOMP_TEST_VECTORS 2 +- +-static struct comp_testvec lzo_comp_tv_template[] = { ++static const struct comp_testvec lzo_comp_tv_template[] = { + { + .inlen = 70, + .outlen = 57, +@@ -33429,7 +33466,7 @@ static struct comp_testvec lzo_comp_tv_template[] = { + }, + }; + +-static struct comp_testvec lzo_decomp_tv_template[] = { ++static const struct comp_testvec lzo_decomp_tv_template[] = { + { + .inlen = 133, + .outlen = 159, +@@ -33472,7 +33509,7 @@ static struct comp_testvec lzo_decomp_tv_template[] = { + */ + #define MICHAEL_MIC_TEST_VECTORS 6 + +-static struct hash_testvec michael_mic_tv_template[] = { ++static const struct hash_testvec michael_mic_tv_template[] = { + { + .key = "\x00\x00\x00\x00\x00\x00\x00\x00", + .ksize = 8, +@@ -33520,9 +33557,7 @@ static struct hash_testvec michael_mic_tv_template[] = { + /* + * CRC32 test vectors + */ +-#define CRC32_TEST_VECTORS 14 +- +-static struct hash_testvec crc32_tv_template[] = { ++static const struct hash_testvec crc32_tv_template[] = { + { + .key = "\x87\xa9\xcb\xed", + .ksize = 4, +@@ -33954,9 +33989,7 @@ static struct hash_testvec crc32_tv_template[] = { + /* + * CRC32C test vectors + */ +-#define CRC32C_TEST_VECTORS 15 +- +-static struct hash_testvec crc32c_tv_template[] = { ++static const struct hash_testvec crc32c_tv_template[] = { + { + .psize = 0, + .digest = "\x00\x00\x00\x00", +@@ -34392,9 +34425,7 @@ static struct hash_testvec crc32c_tv_template[] = { + /* + * Blakcifn CRC test vectors + */ +-#define BFIN_CRC_TEST_VECTORS 6 +- +-static struct hash_testvec bfin_crc_tv_template[] = { ++static const struct hash_testvec bfin_crc_tv_template[] = { + { + .psize = 0, + .digest = "\x00\x00\x00\x00", +@@ -34479,9 +34510,6 @@ static struct hash_testvec bfin_crc_tv_template[] = { + + }; + +-#define LZ4_COMP_TEST_VECTORS 1 +-#define LZ4_DECOMP_TEST_VECTORS 1 +- + static struct comp_testvec lz4_comp_tv_template[] = { + { + .inlen = 70, +@@ -34512,9 +34540,6 @@ static struct comp_testvec lz4_decomp_tv_template[] = { + }, + }; + +-#define LZ4HC_COMP_TEST_VECTORS 1 +-#define LZ4HC_DECOMP_TEST_VECTORS 1 +- + static struct comp_testvec lz4hc_comp_tv_template[] = { + { + .inlen = 70, +diff --git a/crypto/tls.c b/crypto/tls.c +new file mode 100644 +index 00000000..377226f5 +--- /dev/null ++++ b/crypto/tls.c +@@ -0,0 +1,607 @@ ++/* ++ * Copyright 2013 Freescale Semiconductor, Inc. ++ * Copyright 2017 NXP Semiconductor, 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct tls_instance_ctx { ++ struct crypto_ahash_spawn auth; ++ struct crypto_skcipher_spawn enc; ++}; ++ ++struct crypto_tls_ctx { ++ unsigned int reqoff; ++ struct crypto_ahash *auth; ++ struct crypto_skcipher *enc; ++ struct crypto_skcipher *null; ++}; ++ ++struct tls_request_ctx { ++ /* ++ * cryptlen holds the payload length in the case of encryption or ++ * payload_len + icv_len + padding_len in case of decryption ++ */ ++ unsigned int cryptlen; ++ /* working space for partial results */ ++ struct scatterlist tmp[2]; ++ struct scatterlist cipher[2]; ++ struct scatterlist dst[2]; ++ char tail[]; ++}; ++ ++struct async_op { ++ struct completion completion; ++ int err; ++}; ++ ++static void tls_async_op_done(struct crypto_async_request *req, int err) ++{ ++ struct async_op *areq = req->data; ++ ++ if (err == -EINPROGRESS) ++ return; ++ ++ areq->err = err; ++ complete(&areq->completion); ++} ++ ++static int crypto_tls_setkey(struct crypto_aead *tls, const u8 *key, ++ unsigned int keylen) ++{ ++ struct crypto_tls_ctx *ctx = crypto_aead_ctx(tls); ++ struct crypto_ahash *auth = ctx->auth; ++ struct crypto_skcipher *enc = ctx->enc; ++ struct crypto_authenc_keys keys; ++ int err = -EINVAL; ++ ++ if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) ++ goto badkey; ++ ++ crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK); ++ crypto_ahash_set_flags(auth, crypto_aead_get_flags(tls) & ++ CRYPTO_TFM_REQ_MASK); ++ err = crypto_ahash_setkey(auth, keys.authkey, keys.authkeylen); ++ crypto_aead_set_flags(tls, crypto_ahash_get_flags(auth) & ++ CRYPTO_TFM_RES_MASK); ++ ++ if (err) ++ goto out; ++ ++ crypto_skcipher_clear_flags(enc, CRYPTO_TFM_REQ_MASK); ++ crypto_skcipher_set_flags(enc, crypto_aead_get_flags(tls) & ++ CRYPTO_TFM_REQ_MASK); ++ err = crypto_skcipher_setkey(enc, keys.enckey, keys.enckeylen); ++ crypto_aead_set_flags(tls, crypto_skcipher_get_flags(enc) & ++ CRYPTO_TFM_RES_MASK); ++ ++out: ++ return err; ++ ++badkey: ++ crypto_aead_set_flags(tls, CRYPTO_TFM_RES_BAD_KEY_LEN); ++ goto out; ++} ++ ++/** ++ * crypto_tls_genicv - Calculate hmac digest for a TLS record ++ * @hash: (output) buffer to save the digest into ++ * @src: (input) scatterlist with the assoc and payload data ++ * @srclen: (input) size of the source buffer (assoclen + cryptlen) ++ * @req: (input) aead request ++ **/ ++static int crypto_tls_genicv(u8 *hash, struct scatterlist *src, ++ unsigned int srclen, struct aead_request *req) ++{ ++ struct crypto_aead *tls = crypto_aead_reqtfm(req); ++ struct crypto_tls_ctx *ctx = crypto_aead_ctx(tls); ++ struct tls_request_ctx *treq_ctx = aead_request_ctx(req); ++ struct async_op ahash_op; ++ struct ahash_request *ahreq = (void *)(treq_ctx->tail + ctx->reqoff); ++ unsigned int flags = CRYPTO_TFM_REQ_MAY_SLEEP; ++ int err = -EBADMSG; ++ ++ /* Bail out if the request assoc len is 0 */ ++ if (!req->assoclen) ++ return err; ++ ++ init_completion(&ahash_op.completion); ++ ++ /* the hash transform to be executed comes from the original request */ ++ ahash_request_set_tfm(ahreq, ctx->auth); ++ /* prepare the hash request with input data and result pointer */ ++ ahash_request_set_crypt(ahreq, src, hash, srclen); ++ /* set the notifier for when the async hash function returns */ ++ ahash_request_set_callback(ahreq, aead_request_flags(req) & flags, ++ tls_async_op_done, &ahash_op); ++ ++ /* Calculate the digest on the given data. The result is put in hash */ ++ err = crypto_ahash_digest(ahreq); ++ if (err == -EINPROGRESS) { ++ err = wait_for_completion_interruptible(&ahash_op.completion); ++ if (!err) ++ err = ahash_op.err; ++ } ++ ++ return err; ++} ++ ++/** ++ * crypto_tls_gen_padicv - Calculate and pad hmac digest for a TLS record ++ * @hash: (output) buffer to save the digest and padding into ++ * @phashlen: (output) the size of digest + padding ++ * @req: (input) aead request ++ **/ ++static int crypto_tls_gen_padicv(u8 *hash, unsigned int *phashlen, ++ struct aead_request *req) ++{ ++ struct crypto_aead *tls = crypto_aead_reqtfm(req); ++ unsigned int hash_size = crypto_aead_authsize(tls); ++ unsigned int block_size = crypto_aead_blocksize(tls); ++ unsigned int srclen = req->cryptlen + hash_size; ++ unsigned int icvlen = req->cryptlen + req->assoclen; ++ unsigned int padlen; ++ int err; ++ ++ err = crypto_tls_genicv(hash, req->src, icvlen, req); ++ if (err) ++ goto out; ++ ++ /* add padding after digest */ ++ padlen = block_size - (srclen % block_size); ++ memset(hash + hash_size, padlen - 1, padlen); ++ ++ *phashlen = hash_size + padlen; ++out: ++ return err; ++} ++ ++static int crypto_tls_copy_data(struct aead_request *req, ++ struct scatterlist *src, ++ struct scatterlist *dst, ++ unsigned int len) ++{ ++ struct crypto_aead *tls = crypto_aead_reqtfm(req); ++ struct crypto_tls_ctx *ctx = crypto_aead_ctx(tls); ++ SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null); ++ ++ skcipher_request_set_tfm(skreq, ctx->null); ++ skcipher_request_set_callback(skreq, aead_request_flags(req), ++ NULL, NULL); ++ skcipher_request_set_crypt(skreq, src, dst, len, NULL); ++ ++ return crypto_skcipher_encrypt(skreq); ++} ++ ++static int crypto_tls_encrypt(struct aead_request *req) ++{ ++ struct crypto_aead *tls = crypto_aead_reqtfm(req); ++ struct crypto_tls_ctx *ctx = crypto_aead_ctx(tls); ++ struct tls_request_ctx *treq_ctx = aead_request_ctx(req); ++ struct skcipher_request *skreq; ++ struct scatterlist *cipher = treq_ctx->cipher; ++ struct scatterlist *tmp = treq_ctx->tmp; ++ struct scatterlist *sg, *src, *dst; ++ unsigned int cryptlen, phashlen; ++ u8 *hash = treq_ctx->tail; ++ int err; ++ ++ /* ++ * The hash result is saved at the beginning of the tls request ctx ++ * and is aligned as required by the hash transform. Enough space was ++ * allocated in crypto_tls_init_tfm to accommodate the difference. The ++ * requests themselves start later at treq_ctx->tail + ctx->reqoff so ++ * the result is not overwritten by the second (cipher) request. ++ */ ++ hash = (u8 *)ALIGN((unsigned long)hash + ++ crypto_ahash_alignmask(ctx->auth), ++ crypto_ahash_alignmask(ctx->auth) + 1); ++ ++ /* ++ * STEP 1: create ICV together with necessary padding ++ */ ++ err = crypto_tls_gen_padicv(hash, &phashlen, req); ++ if (err) ++ return err; ++ ++ /* ++ * STEP 2: Hash and padding are combined with the payload ++ * depending on the form it arrives. Scatter tables must have at least ++ * one page of data before chaining with another table and can't have ++ * an empty data page. The following code addresses these requirements. ++ * ++ * If the payload is empty, only the hash is encrypted, otherwise the ++ * payload scatterlist is merged with the hash. A special merging case ++ * is when the payload has only one page of data. In that case the ++ * payload page is moved to another scatterlist and prepared there for ++ * encryption. ++ */ ++ if (req->cryptlen) { ++ src = scatterwalk_ffwd(tmp, req->src, req->assoclen); ++ ++ sg_init_table(cipher, 2); ++ sg_set_buf(cipher + 1, hash, phashlen); ++ ++ if (sg_is_last(src)) { ++ sg_set_page(cipher, sg_page(src), req->cryptlen, ++ src->offset); ++ src = cipher; ++ } else { ++ unsigned int rem_len = req->cryptlen; ++ ++ for (sg = src; rem_len > sg->length; sg = sg_next(sg)) ++ rem_len -= min(rem_len, sg->length); ++ ++ sg_set_page(cipher, sg_page(sg), rem_len, sg->offset); ++ sg_chain(sg, 1, cipher); ++ } ++ } else { ++ sg_init_one(cipher, hash, phashlen); ++ src = cipher; ++ } ++ ++ /** ++ * If src != dst copy the associated data from source to destination. ++ * In both cases fast-forward passed the associated data in the dest. ++ */ ++ if (req->src != req->dst) { ++ err = crypto_tls_copy_data(req, req->src, req->dst, ++ req->assoclen); ++ if (err) ++ return err; ++ } ++ dst = scatterwalk_ffwd(treq_ctx->dst, req->dst, req->assoclen); ++ ++ /* ++ * STEP 3: encrypt the frame and return the result ++ */ ++ cryptlen = req->cryptlen + phashlen; ++ ++ /* ++ * The hash and the cipher are applied at different times and their ++ * requests can use the same memory space without interference ++ */ ++ skreq = (void *)(treq_ctx->tail + ctx->reqoff); ++ skcipher_request_set_tfm(skreq, ctx->enc); ++ skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv); ++ skcipher_request_set_callback(skreq, aead_request_flags(req), ++ req->base.complete, req->base.data); ++ /* ++ * Apply the cipher transform. The result will be in req->dst when the ++ * asynchronuous call terminates ++ */ ++ err = crypto_skcipher_encrypt(skreq); ++ ++ return err; ++} ++ ++static int crypto_tls_decrypt(struct aead_request *req) ++{ ++ struct crypto_aead *tls = crypto_aead_reqtfm(req); ++ struct crypto_tls_ctx *ctx = crypto_aead_ctx(tls); ++ struct tls_request_ctx *treq_ctx = aead_request_ctx(req); ++ unsigned int cryptlen = req->cryptlen; ++ unsigned int hash_size = crypto_aead_authsize(tls); ++ unsigned int block_size = crypto_aead_blocksize(tls); ++ struct skcipher_request *skreq = (void *)(treq_ctx->tail + ctx->reqoff); ++ struct scatterlist *tmp = treq_ctx->tmp; ++ struct scatterlist *src, *dst; ++ ++ u8 padding[255]; /* padding can be 0-255 bytes */ ++ u8 pad_size; ++ u16 *len_field; ++ u8 *ihash, *hash = treq_ctx->tail; ++ ++ int paderr = 0; ++ int err = -EINVAL; ++ int i; ++ struct async_op ciph_op; ++ ++ /* ++ * Rule out bad packets. The input packet length must be at least one ++ * byte more than the hash_size ++ */ ++ if (cryptlen <= hash_size || cryptlen % block_size) ++ goto out; ++ ++ /* ++ * Step 1 - Decrypt the source. Fast-forward past the associated data ++ * to the encrypted data. The result will be overwritten in place so ++ * that the decrypted data will be adjacent to the associated data. The ++ * last step (computing the hash) will have it's input data already ++ * prepared and ready to be accessed at req->src. ++ */ ++ src = scatterwalk_ffwd(tmp, req->src, req->assoclen); ++ dst = src; ++ ++ init_completion(&ciph_op.completion); ++ skcipher_request_set_tfm(skreq, ctx->enc); ++ skcipher_request_set_callback(skreq, aead_request_flags(req), ++ tls_async_op_done, &ciph_op); ++ skcipher_request_set_crypt(skreq, src, dst, cryptlen, req->iv); ++ err = crypto_skcipher_decrypt(skreq); ++ if (err == -EINPROGRESS) { ++ err = wait_for_completion_interruptible(&ciph_op.completion); ++ if (!err) ++ err = ciph_op.err; ++ } ++ if (err) ++ goto out; ++ ++ /* ++ * Step 2 - Verify padding ++ * Retrieve the last byte of the payload; this is the padding size. ++ */ ++ cryptlen -= 1; ++ scatterwalk_map_and_copy(&pad_size, dst, cryptlen, 1, 0); ++ ++ /* RFC recommendation for invalid padding size. */ ++ if (cryptlen < pad_size + hash_size) { ++ pad_size = 0; ++ paderr = -EBADMSG; ++ } ++ cryptlen -= pad_size; ++ scatterwalk_map_and_copy(padding, dst, cryptlen, pad_size, 0); ++ ++ /* Padding content must be equal with pad_size. We verify it all */ ++ for (i = 0; i < pad_size; i++) ++ if (padding[i] != pad_size) ++ paderr = -EBADMSG; ++ ++ /* ++ * Step 3 - Verify hash ++ * Align the digest result as required by the hash transform. Enough ++ * space was allocated in crypto_tls_init_tfm ++ */ ++ hash = (u8 *)ALIGN((unsigned long)hash + ++ crypto_ahash_alignmask(ctx->auth), ++ crypto_ahash_alignmask(ctx->auth) + 1); ++ /* ++ * Two bytes at the end of the associated data make the length field. ++ * It must be updated with the length of the cleartext message before ++ * the hash is calculated. ++ */ ++ len_field = sg_virt(req->src) + req->assoclen - 2; ++ cryptlen -= hash_size; ++ *len_field = htons(cryptlen); ++ ++ /* This is the hash from the decrypted packet. Save it for later */ ++ ihash = hash + hash_size; ++ scatterwalk_map_and_copy(ihash, dst, cryptlen, hash_size, 0); ++ ++ /* Now compute and compare our ICV with the one from the packet */ ++ err = crypto_tls_genicv(hash, req->src, cryptlen + req->assoclen, req); ++ if (!err) ++ err = memcmp(hash, ihash, hash_size) ? -EBADMSG : 0; ++ ++ if (req->src != req->dst) { ++ err = crypto_tls_copy_data(req, req->src, req->dst, cryptlen + ++ req->assoclen); ++ if (err) ++ goto out; ++ } ++ ++ /* return the first found error */ ++ if (paderr) ++ err = paderr; ++ ++out: ++ aead_request_complete(req, err); ++ return err; ++} ++ ++static int crypto_tls_init_tfm(struct crypto_aead *tfm) ++{ ++ struct aead_instance *inst = aead_alg_instance(tfm); ++ struct tls_instance_ctx *ictx = aead_instance_ctx(inst); ++ struct crypto_tls_ctx *ctx = crypto_aead_ctx(tfm); ++ struct crypto_ahash *auth; ++ struct crypto_skcipher *enc; ++ struct crypto_skcipher *null; ++ int err; ++ ++ auth = crypto_spawn_ahash(&ictx->auth); ++ if (IS_ERR(auth)) ++ return PTR_ERR(auth); ++ ++ enc = crypto_spawn_skcipher(&ictx->enc); ++ err = PTR_ERR(enc); ++ if (IS_ERR(enc)) ++ goto err_free_ahash; ++ ++ null = crypto_get_default_null_skcipher2(); ++ err = PTR_ERR(null); ++ if (IS_ERR(null)) ++ goto err_free_skcipher; ++ ++ ctx->auth = auth; ++ ctx->enc = enc; ++ ctx->null = null; ++ ++ /* ++ * Allow enough space for two digests. The two digests will be compared ++ * during the decryption phase. One will come from the decrypted packet ++ * and the other will be calculated. For encryption, one digest is ++ * padded (up to a cipher blocksize) and chained with the payload ++ */ ++ ctx->reqoff = ALIGN(crypto_ahash_digestsize(auth) + ++ crypto_ahash_alignmask(auth), ++ crypto_ahash_alignmask(auth) + 1) + ++ max(crypto_ahash_digestsize(auth), ++ crypto_skcipher_blocksize(enc)); ++ ++ crypto_aead_set_reqsize(tfm, ++ sizeof(struct tls_request_ctx) + ++ ctx->reqoff + ++ max_t(unsigned int, ++ crypto_ahash_reqsize(auth) + ++ sizeof(struct ahash_request), ++ crypto_skcipher_reqsize(enc) + ++ sizeof(struct skcipher_request))); ++ ++ return 0; ++ ++err_free_skcipher: ++ crypto_free_skcipher(enc); ++err_free_ahash: ++ crypto_free_ahash(auth); ++ return err; ++} ++ ++static void crypto_tls_exit_tfm(struct crypto_aead *tfm) ++{ ++ struct crypto_tls_ctx *ctx = crypto_aead_ctx(tfm); ++ ++ crypto_free_ahash(ctx->auth); ++ crypto_free_skcipher(ctx->enc); ++ crypto_put_default_null_skcipher2(); ++} ++ ++static void crypto_tls_free(struct aead_instance *inst) ++{ ++ struct tls_instance_ctx *ctx = aead_instance_ctx(inst); ++ ++ crypto_drop_skcipher(&ctx->enc); ++ crypto_drop_ahash(&ctx->auth); ++ kfree(inst); ++} ++ ++static int crypto_tls_create(struct crypto_template *tmpl, struct rtattr **tb) ++{ ++ struct crypto_attr_type *algt; ++ struct aead_instance *inst; ++ struct hash_alg_common *auth; ++ struct crypto_alg *auth_base; ++ struct skcipher_alg *enc; ++ struct tls_instance_ctx *ctx; ++ const char *enc_name; ++ int err; ++ ++ algt = crypto_get_attr_type(tb); ++ if (IS_ERR(algt)) ++ return PTR_ERR(algt); ++ ++ if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) ++ return -EINVAL; ++ ++ auth = ahash_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH, ++ CRYPTO_ALG_TYPE_AHASH_MASK | ++ crypto_requires_sync(algt->type, algt->mask)); ++ if (IS_ERR(auth)) ++ return PTR_ERR(auth); ++ ++ auth_base = &auth->base; ++ ++ enc_name = crypto_attr_alg_name(tb[2]); ++ err = PTR_ERR(enc_name); ++ if (IS_ERR(enc_name)) ++ goto out_put_auth; ++ ++ inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); ++ err = -ENOMEM; ++ if (!inst) ++ goto out_put_auth; ++ ++ ctx = aead_instance_ctx(inst); ++ ++ err = crypto_init_ahash_spawn(&ctx->auth, auth, ++ aead_crypto_instance(inst)); ++ if (err) ++ goto err_free_inst; ++ ++ crypto_set_skcipher_spawn(&ctx->enc, aead_crypto_instance(inst)); ++ err = crypto_grab_skcipher(&ctx->enc, enc_name, 0, ++ crypto_requires_sync(algt->type, ++ algt->mask)); ++ if (err) ++ goto err_drop_auth; ++ ++ enc = crypto_spawn_skcipher_alg(&ctx->enc); ++ ++ err = -ENAMETOOLONG; ++ if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, ++ "tls10(%s,%s)", auth_base->cra_name, ++ enc->base.cra_name) >= CRYPTO_MAX_ALG_NAME) ++ goto err_drop_enc; ++ ++ if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, ++ "tls10(%s,%s)", auth_base->cra_driver_name, ++ enc->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME) ++ goto err_drop_enc; ++ ++ inst->alg.base.cra_flags = (auth_base->cra_flags | ++ enc->base.cra_flags) & CRYPTO_ALG_ASYNC; ++ inst->alg.base.cra_priority = enc->base.cra_priority * 10 + ++ auth_base->cra_priority; ++ inst->alg.base.cra_blocksize = enc->base.cra_blocksize; ++ inst->alg.base.cra_alignmask = auth_base->cra_alignmask | ++ enc->base.cra_alignmask; ++ inst->alg.base.cra_ctxsize = sizeof(struct crypto_tls_ctx); ++ ++ inst->alg.ivsize = crypto_skcipher_alg_ivsize(enc); ++ inst->alg.chunksize = crypto_skcipher_alg_chunksize(enc); ++ inst->alg.maxauthsize = auth->digestsize; ++ ++ inst->alg.init = crypto_tls_init_tfm; ++ inst->alg.exit = crypto_tls_exit_tfm; ++ ++ inst->alg.setkey = crypto_tls_setkey; ++ inst->alg.encrypt = crypto_tls_encrypt; ++ inst->alg.decrypt = crypto_tls_decrypt; ++ ++ inst->free = crypto_tls_free; ++ ++ err = aead_register_instance(tmpl, inst); ++ if (err) ++ goto err_drop_enc; ++ ++out: ++ crypto_mod_put(auth_base); ++ return err; ++ ++err_drop_enc: ++ crypto_drop_skcipher(&ctx->enc); ++err_drop_auth: ++ crypto_drop_ahash(&ctx->auth); ++err_free_inst: ++ kfree(inst); ++out_put_auth: ++ goto out; ++} ++ ++static struct crypto_template crypto_tls_tmpl = { ++ .name = "tls10", ++ .create = crypto_tls_create, ++ .module = THIS_MODULE, ++}; ++ ++static int __init crypto_tls_module_init(void) ++{ ++ return crypto_register_template(&crypto_tls_tmpl); ++} ++ ++static void __exit crypto_tls_module_exit(void) ++{ ++ crypto_unregister_template(&crypto_tls_tmpl); ++} ++ ++module_init(crypto_tls_module_init); ++module_exit(crypto_tls_module_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("TLS 1.0 record encryption"); +diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig +index 64bf3024..3831a6f7 100644 +--- a/drivers/crypto/caam/Kconfig ++++ b/drivers/crypto/caam/Kconfig +@@ -1,6 +1,11 @@ ++config CRYPTO_DEV_FSL_CAAM_COMMON ++ tristate ++ + config CRYPTO_DEV_FSL_CAAM +- tristate "Freescale CAAM-Multicore driver backend" ++ tristate "Freescale CAAM-Multicore platform driver backend" + depends on FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE ++ select CRYPTO_DEV_FSL_CAAM_COMMON ++ select SOC_BUS + help + Enables the driver module for Freescale's Cryptographic Accelerator + and Assurance Module (CAAM), also known as the SEC version 4 (SEC4). +@@ -11,9 +16,16 @@ config CRYPTO_DEV_FSL_CAAM + To compile this driver as a module, choose M here: the module + will be called caam. + ++if CRYPTO_DEV_FSL_CAAM ++ ++config CRYPTO_DEV_FSL_CAAM_DEBUG ++ bool "Enable debug output in CAAM driver" ++ help ++ Selecting this will enable printing of various debug ++ information in the CAAM driver. ++ + config CRYPTO_DEV_FSL_CAAM_JR + tristate "Freescale CAAM Job Ring driver backend" +- depends on CRYPTO_DEV_FSL_CAAM + default y + help + Enables the driver module for Job Rings which are part of +@@ -24,9 +36,10 @@ config CRYPTO_DEV_FSL_CAAM_JR + To compile this driver as a module, choose M here: the module + will be called caam_jr. + ++if CRYPTO_DEV_FSL_CAAM_JR ++ + config CRYPTO_DEV_FSL_CAAM_RINGSIZE + int "Job Ring size" +- depends on CRYPTO_DEV_FSL_CAAM_JR + range 2 9 + default "9" + help +@@ -44,7 +57,6 @@ config CRYPTO_DEV_FSL_CAAM_RINGSIZE + + config CRYPTO_DEV_FSL_CAAM_INTC + bool "Job Ring interrupt coalescing" +- depends on CRYPTO_DEV_FSL_CAAM_JR + help + Enable the Job Ring's interrupt coalescing feature. + +@@ -74,7 +86,6 @@ config CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD + + config CRYPTO_DEV_FSL_CAAM_CRYPTO_API + tristate "Register algorithm implementations with the Crypto API" +- depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR + default y + select CRYPTO_AEAD + select CRYPTO_AUTHENC +@@ -87,9 +98,25 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API + To compile this as a module, choose M here: the module + will be called caamalg. + ++config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI ++ tristate "Queue Interface as Crypto API backend" ++ depends on FSL_SDK_DPA && NET ++ default y ++ select CRYPTO_AUTHENC ++ select CRYPTO_BLKCIPHER ++ help ++ Selecting this will use CAAM Queue Interface (QI) for sending ++ & receiving crypto jobs to/from CAAM. This gives better performance ++ than job ring interface when the number of cores are more than the ++ number of job rings assigned to the kernel. The number of portals ++ assigned to the kernel should also be more than the number of ++ job rings. ++ ++ To compile this as a module, choose M here: the module ++ will be called caamalg_qi. ++ + config CRYPTO_DEV_FSL_CAAM_AHASH_API + tristate "Register hash algorithm implementations with Crypto API" +- depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR + default y + select CRYPTO_HASH + help +@@ -101,7 +128,6 @@ config CRYPTO_DEV_FSL_CAAM_AHASH_API + + config CRYPTO_DEV_FSL_CAAM_PKC_API + tristate "Register public key cryptography implementations with Crypto API" +- depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR + default y + select CRYPTO_RSA + help +@@ -113,7 +139,6 @@ config CRYPTO_DEV_FSL_CAAM_PKC_API + + config CRYPTO_DEV_FSL_CAAM_RNG_API + tristate "Register caam device for hwrng API" +- depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR + default y + select CRYPTO_RNG + select HW_RANDOM +@@ -124,13 +149,26 @@ config CRYPTO_DEV_FSL_CAAM_RNG_API + To compile this as a module, choose M here: the module + will be called caamrng. + +-config CRYPTO_DEV_FSL_CAAM_IMX +- def_bool SOC_IMX6 || SOC_IMX7D +- depends on CRYPTO_DEV_FSL_CAAM ++endif # CRYPTO_DEV_FSL_CAAM_JR + +-config CRYPTO_DEV_FSL_CAAM_DEBUG +- bool "Enable debug output in CAAM driver" +- depends on CRYPTO_DEV_FSL_CAAM +- help +- Selecting this will enable printing of various debug +- information in the CAAM driver. ++endif # CRYPTO_DEV_FSL_CAAM ++ ++config CRYPTO_DEV_FSL_DPAA2_CAAM ++ tristate "QorIQ DPAA2 CAAM (DPSECI) driver" ++ depends on FSL_MC_DPIO ++ select CRYPTO_DEV_FSL_CAAM_COMMON ++ select CRYPTO_BLKCIPHER ++ select CRYPTO_AUTHENC ++ select CRYPTO_AEAD ++ ---help--- ++ CAAM driver for QorIQ Data Path Acceleration Architecture 2. ++ It handles DPSECI DPAA2 objects that sit on the Management Complex ++ (MC) fsl-mc bus. ++ ++ To compile this as a module, choose M here: the module ++ will be called dpaa2_caam. ++ ++config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC ++ def_tristate (CRYPTO_DEV_FSL_CAAM_CRYPTO_API || \ ++ CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI || \ ++ CRYPTO_DEV_FSL_DPAA2_CAAM) +diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile +index 08bf5515..01f73a25 100644 +--- a/drivers/crypto/caam/Makefile ++++ b/drivers/crypto/caam/Makefile +@@ -5,13 +5,26 @@ ifeq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG), y) + ccflags-y := -DDEBUG + endif + ++ccflags-y += -DVERSION=\"\" ++ ++obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON) += error.o + obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam.o + obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR) += caam_jr.o + obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o ++obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += caamalg_qi.o ++obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC) += caamalg_desc.o + obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o + obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o + obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caam_pkc.o + + caam-objs := ctrl.o +-caam_jr-objs := jr.o key_gen.o error.o ++caam_jr-objs := jr.o key_gen.o + caam_pkc-y := caampkc.o pkc_desc.o ++ifneq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI),) ++ ccflags-y += -DCONFIG_CAAM_QI ++ caam-objs += qi.o ++endif ++ ++obj-$(CONFIG_CRYPTO_DEV_FSL_DPAA2_CAAM) += dpaa2_caam.o ++ ++dpaa2_caam-y := caamalg_qi2.o dpseci.o +diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c +index 0d743c63..abf2f52b 100644 +--- a/drivers/crypto/caam/caamalg.c ++++ b/drivers/crypto/caam/caamalg.c +@@ -2,6 +2,7 @@ + * caam - Freescale FSL CAAM support for crypto API + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * Copyright 2016 NXP + * + * Based on talitos crypto API driver. + * +@@ -53,6 +54,7 @@ + #include "error.h" + #include "sg_sw_sec4.h" + #include "key_gen.h" ++#include "caamalg_desc.h" + + /* + * crypto alg +@@ -62,8 +64,6 @@ + #define CAAM_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + \ + CTR_RFC3686_NONCE_SIZE + \ + SHA512_DIGEST_SIZE * 2) +-/* max IV is max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */ +-#define CAAM_MAX_IV_LENGTH 16 + + #define AEAD_DESC_JOB_IO_LEN (DESC_JOB_IO_LEN + CAAM_CMD_SZ * 2) + #define GCM_DESC_JOB_IO_LEN (AEAD_DESC_JOB_IO_LEN + \ +@@ -71,37 +71,6 @@ + #define AUTHENC_DESC_JOB_IO_LEN (AEAD_DESC_JOB_IO_LEN + \ + CAAM_CMD_SZ * 5) + +-/* length of descriptors text */ +-#define DESC_AEAD_BASE (4 * CAAM_CMD_SZ) +-#define DESC_AEAD_ENC_LEN (DESC_AEAD_BASE + 11 * CAAM_CMD_SZ) +-#define DESC_AEAD_DEC_LEN (DESC_AEAD_BASE + 15 * CAAM_CMD_SZ) +-#define DESC_AEAD_GIVENC_LEN (DESC_AEAD_ENC_LEN + 9 * CAAM_CMD_SZ) +- +-/* Note: Nonce is counted in enckeylen */ +-#define DESC_AEAD_CTR_RFC3686_LEN (4 * CAAM_CMD_SZ) +- +-#define DESC_AEAD_NULL_BASE (3 * CAAM_CMD_SZ) +-#define DESC_AEAD_NULL_ENC_LEN (DESC_AEAD_NULL_BASE + 11 * CAAM_CMD_SZ) +-#define DESC_AEAD_NULL_DEC_LEN (DESC_AEAD_NULL_BASE + 13 * CAAM_CMD_SZ) +- +-#define DESC_GCM_BASE (3 * CAAM_CMD_SZ) +-#define DESC_GCM_ENC_LEN (DESC_GCM_BASE + 16 * CAAM_CMD_SZ) +-#define DESC_GCM_DEC_LEN (DESC_GCM_BASE + 12 * CAAM_CMD_SZ) +- +-#define DESC_RFC4106_BASE (3 * CAAM_CMD_SZ) +-#define DESC_RFC4106_ENC_LEN (DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ) +-#define DESC_RFC4106_DEC_LEN (DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ) +- +-#define DESC_RFC4543_BASE (3 * CAAM_CMD_SZ) +-#define DESC_RFC4543_ENC_LEN (DESC_RFC4543_BASE + 11 * CAAM_CMD_SZ) +-#define DESC_RFC4543_DEC_LEN (DESC_RFC4543_BASE + 12 * CAAM_CMD_SZ) +- +-#define DESC_ABLKCIPHER_BASE (3 * CAAM_CMD_SZ) +-#define DESC_ABLKCIPHER_ENC_LEN (DESC_ABLKCIPHER_BASE + \ +- 20 * CAAM_CMD_SZ) +-#define DESC_ABLKCIPHER_DEC_LEN (DESC_ABLKCIPHER_BASE + \ +- 15 * CAAM_CMD_SZ) +- + #define DESC_MAX_USED_BYTES (CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN) + #define DESC_MAX_USED_LEN (DESC_MAX_USED_BYTES / CAAM_CMD_SZ) + +@@ -112,47 +81,11 @@ + #define debug(format, arg...) + #endif + +-#ifdef DEBUG +-#include +- +-static void dbg_dump_sg(const char *level, const char *prefix_str, +- int prefix_type, int rowsize, int groupsize, +- struct scatterlist *sg, size_t tlen, bool ascii, +- bool may_sleep) +-{ +- struct scatterlist *it; +- void *it_page; +- size_t len; +- void *buf; +- +- for (it = sg; it != NULL && tlen > 0 ; it = sg_next(sg)) { +- /* +- * make sure the scatterlist's page +- * has a valid virtual memory mapping +- */ +- it_page = kmap_atomic(sg_page(it)); +- if (unlikely(!it_page)) { +- printk(KERN_ERR "dbg_dump_sg: kmap failed\n"); +- return; +- } +- +- buf = it_page + it->offset; +- len = min_t(size_t, tlen, it->length); +- print_hex_dump(level, prefix_str, prefix_type, rowsize, +- groupsize, buf, len, ascii); +- tlen -= len; +- +- kunmap_atomic(it_page); +- } +-} +-#endif +- + static struct list_head alg_list; + + struct caam_alg_entry { + int class1_alg_type; + int class2_alg_type; +- int alg_op; + bool rfc3686; + bool geniv; + }; +@@ -163,302 +96,67 @@ struct caam_aead_alg { + bool registered; + }; + +-/* Set DK bit in class 1 operation if shared */ +-static inline void append_dec_op1(u32 *desc, u32 type) +-{ +- u32 *jump_cmd, *uncond_jump_cmd; +- +- /* DK bit is valid only for AES */ +- if ((type & OP_ALG_ALGSEL_MASK) != OP_ALG_ALGSEL_AES) { +- append_operation(desc, type | OP_ALG_AS_INITFINAL | +- OP_ALG_DECRYPT); +- return; +- } +- +- jump_cmd = append_jump(desc, JUMP_TEST_ALL | JUMP_COND_SHRD); +- append_operation(desc, type | OP_ALG_AS_INITFINAL | +- OP_ALG_DECRYPT); +- uncond_jump_cmd = append_jump(desc, JUMP_TEST_ALL); +- set_jump_tgt_here(desc, jump_cmd); +- append_operation(desc, type | OP_ALG_AS_INITFINAL | +- OP_ALG_DECRYPT | OP_ALG_AAI_DK); +- set_jump_tgt_here(desc, uncond_jump_cmd); +-} +- +-/* +- * For aead functions, read payload and write payload, +- * both of which are specified in req->src and req->dst +- */ +-static inline void aead_append_src_dst(u32 *desc, u32 msg_type) +-{ +- append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | +- KEY_VLF | msg_type | FIFOLD_TYPE_LASTBOTH); +-} +- +-/* +- * For ablkcipher encrypt and decrypt, read from req->src and +- * write to req->dst +- */ +-static inline void ablkcipher_append_src_dst(u32 *desc) +-{ +- append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); +- append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | +- KEY_VLF | FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); +- append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); +-} +- + /* + * per-session context + */ + struct caam_ctx { +- struct device *jrdev; + u32 sh_desc_enc[DESC_MAX_USED_LEN]; + u32 sh_desc_dec[DESC_MAX_USED_LEN]; + u32 sh_desc_givenc[DESC_MAX_USED_LEN]; ++ u8 key[CAAM_MAX_KEY_SIZE]; + dma_addr_t sh_desc_enc_dma; + dma_addr_t sh_desc_dec_dma; + dma_addr_t sh_desc_givenc_dma; +- u32 class1_alg_type; +- u32 class2_alg_type; +- u32 alg_op; +- u8 key[CAAM_MAX_KEY_SIZE]; + dma_addr_t key_dma; +- unsigned int enckeylen; +- unsigned int split_key_len; +- unsigned int split_key_pad_len; ++ struct device *jrdev; ++ struct alginfo adata; ++ struct alginfo cdata; + unsigned int authsize; + }; + +-static void append_key_aead(u32 *desc, struct caam_ctx *ctx, +- int keys_fit_inline, bool is_rfc3686) +-{ +- u32 *nonce; +- unsigned int enckeylen = ctx->enckeylen; +- +- /* +- * RFC3686 specific: +- * | ctx->key = {AUTH_KEY, ENC_KEY, NONCE} +- * | enckeylen = encryption key size + nonce size +- */ +- if (is_rfc3686) +- enckeylen -= CTR_RFC3686_NONCE_SIZE; +- +- if (keys_fit_inline) { +- append_key_as_imm(desc, ctx->key, ctx->split_key_pad_len, +- ctx->split_key_len, CLASS_2 | +- KEY_DEST_MDHA_SPLIT | KEY_ENC); +- append_key_as_imm(desc, (void *)ctx->key + +- ctx->split_key_pad_len, enckeylen, +- enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); +- } else { +- append_key(desc, ctx->key_dma, ctx->split_key_len, CLASS_2 | +- KEY_DEST_MDHA_SPLIT | KEY_ENC); +- append_key(desc, ctx->key_dma + ctx->split_key_pad_len, +- enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); +- } +- +- /* Load Counter into CONTEXT1 reg */ +- if (is_rfc3686) { +- nonce = (u32 *)((void *)ctx->key + ctx->split_key_pad_len + +- enckeylen); +- append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, +- LDST_CLASS_IND_CCB | +- LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); +- append_move(desc, +- MOVE_SRC_OUTFIFO | +- MOVE_DEST_CLASS1CTX | +- (16 << MOVE_OFFSET_SHIFT) | +- (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); +- } +-} +- +-static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx, +- int keys_fit_inline, bool is_rfc3686) +-{ +- u32 *key_jump_cmd; +- +- /* Note: Context registers are saved. */ +- init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); +- +- /* Skip if already shared */ +- key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | +- JUMP_COND_SHRD); +- +- append_key_aead(desc, ctx, keys_fit_inline, is_rfc3686); +- +- set_jump_tgt_here(desc, key_jump_cmd); +-} +- + static int aead_null_set_sh_desc(struct crypto_aead *aead) + { + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; +- bool keys_fit_inline = false; +- u32 *key_jump_cmd, *jump_cmd, *read_move_cmd, *write_move_cmd; + u32 *desc; ++ int rem_bytes = CAAM_DESC_BYTES_MAX - AEAD_DESC_JOB_IO_LEN - ++ ctx->adata.keylen_pad; + + /* + * Job Descriptor and Shared Descriptors + * must all fit into the 64-word Descriptor h/w Buffer + */ +- if (DESC_AEAD_NULL_ENC_LEN + AEAD_DESC_JOB_IO_LEN + +- ctx->split_key_pad_len <= CAAM_DESC_BYTES_MAX) +- keys_fit_inline = true; ++ if (rem_bytes >= DESC_AEAD_NULL_ENC_LEN) { ++ ctx->adata.key_inline = true; ++ ctx->adata.key_virt = ctx->key; ++ } else { ++ ctx->adata.key_inline = false; ++ ctx->adata.key_dma = ctx->key_dma; ++ } + + /* aead_encrypt shared descriptor */ + desc = ctx->sh_desc_enc; +- +- init_sh_desc(desc, HDR_SHARE_SERIAL); +- +- /* Skip if already shared */ +- key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | +- JUMP_COND_SHRD); +- if (keys_fit_inline) +- append_key_as_imm(desc, ctx->key, ctx->split_key_pad_len, +- ctx->split_key_len, CLASS_2 | +- KEY_DEST_MDHA_SPLIT | KEY_ENC); +- else +- append_key(desc, ctx->key_dma, ctx->split_key_len, CLASS_2 | +- KEY_DEST_MDHA_SPLIT | KEY_ENC); +- set_jump_tgt_here(desc, key_jump_cmd); +- +- /* assoclen + cryptlen = seqinlen */ +- append_math_sub(desc, REG3, SEQINLEN, REG0, CAAM_CMD_SZ); +- +- /* Prepare to read and write cryptlen + assoclen bytes */ +- append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); +- append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); +- +- /* +- * MOVE_LEN opcode is not available in all SEC HW revisions, +- * thus need to do some magic, i.e. self-patch the descriptor +- * buffer. +- */ +- read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | +- MOVE_DEST_MATH3 | +- (0x6 << MOVE_LEN_SHIFT)); +- write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | +- MOVE_DEST_DESCBUF | +- MOVE_WAITCOMP | +- (0x8 << MOVE_LEN_SHIFT)); +- +- /* Class 2 operation */ +- append_operation(desc, ctx->class2_alg_type | +- OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); +- +- /* Read and write cryptlen bytes */ +- aead_append_src_dst(desc, FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); +- +- set_move_tgt_here(desc, read_move_cmd); +- set_move_tgt_here(desc, write_move_cmd); +- append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); +- append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO | +- MOVE_AUX_LS); +- +- /* Write ICV */ +- append_seq_store(desc, ctx->authsize, LDST_CLASS_2_CCB | +- LDST_SRCDST_BYTE_CONTEXT); +- +- ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, +- desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } +-#ifdef DEBUG +- print_hex_dump(KERN_ERR, +- "aead null enc shdesc@"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, desc, +- desc_bytes(desc), 1); +-#endif ++ cnstr_shdsc_aead_null_encap(desc, &ctx->adata, ctx->authsize); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + /* + * Job Descriptor and Shared Descriptors + * must all fit into the 64-word Descriptor h/w Buffer + */ +- keys_fit_inline = false; +- if (DESC_AEAD_NULL_DEC_LEN + DESC_JOB_IO_LEN + +- ctx->split_key_pad_len <= CAAM_DESC_BYTES_MAX) +- keys_fit_inline = true; +- +- desc = ctx->sh_desc_dec; ++ if (rem_bytes >= DESC_AEAD_NULL_DEC_LEN) { ++ ctx->adata.key_inline = true; ++ ctx->adata.key_virt = ctx->key; ++ } else { ++ ctx->adata.key_inline = false; ++ ctx->adata.key_dma = ctx->key_dma; ++ } + + /* aead_decrypt shared descriptor */ +- init_sh_desc(desc, HDR_SHARE_SERIAL); +- +- /* Skip if already shared */ +- key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | +- JUMP_COND_SHRD); +- if (keys_fit_inline) +- append_key_as_imm(desc, ctx->key, ctx->split_key_pad_len, +- ctx->split_key_len, CLASS_2 | +- KEY_DEST_MDHA_SPLIT | KEY_ENC); +- else +- append_key(desc, ctx->key_dma, ctx->split_key_len, CLASS_2 | +- KEY_DEST_MDHA_SPLIT | KEY_ENC); +- set_jump_tgt_here(desc, key_jump_cmd); +- +- /* Class 2 operation */ +- append_operation(desc, ctx->class2_alg_type | +- OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); +- +- /* assoclen + cryptlen = seqoutlen */ +- append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ); +- +- /* Prepare to read and write cryptlen + assoclen bytes */ +- append_math_add(desc, VARSEQINLEN, ZERO, REG2, CAAM_CMD_SZ); +- append_math_add(desc, VARSEQOUTLEN, ZERO, REG2, CAAM_CMD_SZ); +- +- /* +- * MOVE_LEN opcode is not available in all SEC HW revisions, +- * thus need to do some magic, i.e. self-patch the descriptor +- * buffer. +- */ +- read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | +- MOVE_DEST_MATH2 | +- (0x6 << MOVE_LEN_SHIFT)); +- write_move_cmd = append_move(desc, MOVE_SRC_MATH2 | +- MOVE_DEST_DESCBUF | +- MOVE_WAITCOMP | +- (0x8 << MOVE_LEN_SHIFT)); +- +- /* Read and write cryptlen bytes */ +- aead_append_src_dst(desc, FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); +- +- /* +- * Insert a NOP here, since we need at least 4 instructions between +- * code patching the descriptor buffer and the location being patched. +- */ +- jump_cmd = append_jump(desc, JUMP_TEST_ALL); +- set_jump_tgt_here(desc, jump_cmd); +- +- set_move_tgt_here(desc, read_move_cmd); +- set_move_tgt_here(desc, write_move_cmd); +- append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); +- append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO | +- MOVE_AUX_LS); +- append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); +- +- /* Load ICV */ +- append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS2 | +- FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV); +- +- ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, +- desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_dec_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } +-#ifdef DEBUG +- print_hex_dump(KERN_ERR, +- "aead null dec shdesc@"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, desc, +- desc_bytes(desc), 1); +-#endif ++ desc = ctx->sh_desc_dec; ++ cnstr_shdsc_aead_null_decap(desc, &ctx->adata, ctx->authsize); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + return 0; + } +@@ -470,11 +168,11 @@ static int aead_set_sh_desc(struct crypto_aead *aead) + unsigned int ivsize = crypto_aead_ivsize(aead); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; +- bool keys_fit_inline; +- u32 geniv, moveiv; + u32 ctx1_iv_off = 0; +- u32 *desc; +- const bool ctr_mode = ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == ++ u32 *desc, *nonce = NULL; ++ u32 inl_mask; ++ unsigned int data_len[2]; ++ const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == + OP_ALG_AAI_CTR_MOD128); + const bool is_rfc3686 = alg->caam.rfc3686; + +@@ -482,7 +180,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead) + return 0; + + /* NULL encryption / decryption */ +- if (!ctx->enckeylen) ++ if (!ctx->cdata.keylen) + return aead_null_set_sh_desc(aead); + + /* +@@ -497,8 +195,14 @@ static int aead_set_sh_desc(struct crypto_aead *aead) + * RFC3686 specific: + * CONTEXT1[255:128] = {NONCE, IV, COUNTER} + */ +- if (is_rfc3686) ++ if (is_rfc3686) { + ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; ++ nonce = (u32 *)((void *)ctx->key + ctx->adata.keylen_pad + ++ ctx->cdata.keylen - CTR_RFC3686_NONCE_SIZE); ++ } ++ ++ data_len[0] = ctx->adata.keylen_pad; ++ data_len[1] = ctx->cdata.keylen; + + if (alg->caam.geniv) + goto skip_enc; +@@ -507,146 +211,64 @@ static int aead_set_sh_desc(struct crypto_aead *aead) + * Job Descriptor and Shared Descriptors + * must all fit into the 64-word Descriptor h/w Buffer + */ +- keys_fit_inline = false; +- if (DESC_AEAD_ENC_LEN + AUTHENC_DESC_JOB_IO_LEN + +- ctx->split_key_pad_len + ctx->enckeylen + +- (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0) <= +- CAAM_DESC_BYTES_MAX) +- keys_fit_inline = true; +- +- /* aead_encrypt shared descriptor */ +- desc = ctx->sh_desc_enc; +- +- /* Note: Context registers are saved. */ +- init_sh_desc_key_aead(desc, ctx, keys_fit_inline, is_rfc3686); +- +- /* Class 2 operation */ +- append_operation(desc, ctx->class2_alg_type | +- OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); ++ if (desc_inline_query(DESC_AEAD_ENC_LEN + ++ (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0), ++ AUTHENC_DESC_JOB_IO_LEN, data_len, &inl_mask, ++ ARRAY_SIZE(data_len)) < 0) ++ return -EINVAL; + +- /* Read and write assoclen bytes */ +- append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); +- append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); ++ if (inl_mask & 1) ++ ctx->adata.key_virt = ctx->key; ++ else ++ ctx->adata.key_dma = ctx->key_dma; + +- /* Skip assoc data */ +- append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); ++ if (inl_mask & 2) ++ ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; ++ else ++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; + +- /* read assoc before reading payload */ +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | +- FIFOLDST_VLF); ++ ctx->adata.key_inline = !!(inl_mask & 1); ++ ctx->cdata.key_inline = !!(inl_mask & 2); + +- /* Load Counter into CONTEXT1 reg */ +- if (is_rfc3686) +- append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | +- LDST_SRCDST_BYTE_CONTEXT | +- ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << +- LDST_OFFSET_SHIFT)); +- +- /* Class 1 operation */ +- append_operation(desc, ctx->class1_alg_type | +- OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); +- +- /* Read and write cryptlen bytes */ +- append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); +- append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); +- aead_append_src_dst(desc, FIFOLD_TYPE_MSG1OUT2); +- +- /* Write ICV */ +- append_seq_store(desc, ctx->authsize, LDST_CLASS_2_CCB | +- LDST_SRCDST_BYTE_CONTEXT); +- +- ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, +- desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } +-#ifdef DEBUG +- print_hex_dump(KERN_ERR, "aead enc shdesc@"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, desc, +- desc_bytes(desc), 1); +-#endif ++ /* aead_encrypt shared descriptor */ ++ desc = ctx->sh_desc_enc; ++ cnstr_shdsc_aead_encap(desc, &ctx->cdata, &ctx->adata, ivsize, ++ ctx->authsize, is_rfc3686, nonce, ctx1_iv_off, ++ false); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + skip_enc: + /* + * Job Descriptor and Shared Descriptors + * must all fit into the 64-word Descriptor h/w Buffer + */ +- keys_fit_inline = false; +- if (DESC_AEAD_DEC_LEN + AUTHENC_DESC_JOB_IO_LEN + +- ctx->split_key_pad_len + ctx->enckeylen + +- (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0) <= +- CAAM_DESC_BYTES_MAX) +- keys_fit_inline = true; +- +- /* aead_decrypt shared descriptor */ +- desc = ctx->sh_desc_dec; +- +- /* Note: Context registers are saved. */ +- init_sh_desc_key_aead(desc, ctx, keys_fit_inline, is_rfc3686); +- +- /* Class 2 operation */ +- append_operation(desc, ctx->class2_alg_type | +- OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); ++ if (desc_inline_query(DESC_AEAD_DEC_LEN + ++ (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0), ++ AUTHENC_DESC_JOB_IO_LEN, data_len, &inl_mask, ++ ARRAY_SIZE(data_len)) < 0) ++ return -EINVAL; + +- /* Read and write assoclen bytes */ +- append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); +- if (alg->caam.geniv) +- append_math_add_imm_u32(desc, VARSEQOUTLEN, REG3, IMM, ivsize); ++ if (inl_mask & 1) ++ ctx->adata.key_virt = ctx->key; + else +- append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); +- +- /* Skip assoc data */ +- append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); ++ ctx->adata.key_dma = ctx->key_dma; + +- /* read assoc before reading payload */ +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | +- KEY_VLF); +- +- if (alg->caam.geniv) { +- append_seq_load(desc, ivsize, LDST_CLASS_1_CCB | +- LDST_SRCDST_BYTE_CONTEXT | +- (ctx1_iv_off << LDST_OFFSET_SHIFT)); +- append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_CLASS2INFIFO | +- (ctx1_iv_off << MOVE_OFFSET_SHIFT) | ivsize); +- } +- +- /* Load Counter into CONTEXT1 reg */ +- if (is_rfc3686) +- append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | +- LDST_SRCDST_BYTE_CONTEXT | +- ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << +- LDST_OFFSET_SHIFT)); +- +- /* Choose operation */ +- if (ctr_mode) +- append_operation(desc, ctx->class1_alg_type | +- OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT); ++ if (inl_mask & 2) ++ ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; + else +- append_dec_op1(desc, ctx->class1_alg_type); ++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; + +- /* Read and write cryptlen bytes */ +- append_math_add(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); +- append_math_add(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); +- aead_append_src_dst(desc, FIFOLD_TYPE_MSG); ++ ctx->adata.key_inline = !!(inl_mask & 1); ++ ctx->cdata.key_inline = !!(inl_mask & 2); + +- /* Load ICV */ +- append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS2 | +- FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV); +- +- ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, +- desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_dec_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } +-#ifdef DEBUG +- print_hex_dump(KERN_ERR, "aead dec shdesc@"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, desc, +- desc_bytes(desc), 1); +-#endif ++ /* aead_decrypt shared descriptor */ ++ desc = ctx->sh_desc_dec; ++ cnstr_shdsc_aead_decap(desc, &ctx->cdata, &ctx->adata, ivsize, ++ ctx->authsize, alg->caam.geniv, is_rfc3686, ++ nonce, ctx1_iv_off, false); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + if (!alg->caam.geniv) + goto skip_givenc; +@@ -655,107 +277,32 @@ static int aead_set_sh_desc(struct crypto_aead *aead) + * Job Descriptor and Shared Descriptors + * must all fit into the 64-word Descriptor h/w Buffer + */ +- keys_fit_inline = false; +- if (DESC_AEAD_GIVENC_LEN + AUTHENC_DESC_JOB_IO_LEN + +- ctx->split_key_pad_len + ctx->enckeylen + +- (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0) <= +- CAAM_DESC_BYTES_MAX) +- keys_fit_inline = true; ++ if (desc_inline_query(DESC_AEAD_GIVENC_LEN + ++ (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0), ++ AUTHENC_DESC_JOB_IO_LEN, data_len, &inl_mask, ++ ARRAY_SIZE(data_len)) < 0) ++ return -EINVAL; + +- /* aead_givencrypt shared descriptor */ +- desc = ctx->sh_desc_enc; ++ if (inl_mask & 1) ++ ctx->adata.key_virt = ctx->key; ++ else ++ ctx->adata.key_dma = ctx->key_dma; + +- /* Note: Context registers are saved. */ +- init_sh_desc_key_aead(desc, ctx, keys_fit_inline, is_rfc3686); ++ if (inl_mask & 2) ++ ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; ++ else ++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; + +- if (is_rfc3686) +- goto copy_iv; +- +- /* Generate IV */ +- geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO | +- NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 | +- NFIFOENTRY_PTYPE_RND | (ivsize << NFIFOENTRY_DLEN_SHIFT); +- append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB | +- LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); +- append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); +- append_move(desc, MOVE_WAITCOMP | +- MOVE_SRC_INFIFO | MOVE_DEST_CLASS1CTX | +- (ctx1_iv_off << MOVE_OFFSET_SHIFT) | +- (ivsize << MOVE_LEN_SHIFT)); +- append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); +- +-copy_iv: +- /* Copy IV to class 1 context */ +- append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_OUTFIFO | +- (ctx1_iv_off << MOVE_OFFSET_SHIFT) | +- (ivsize << MOVE_LEN_SHIFT)); +- +- /* Return to encryption */ +- append_operation(desc, ctx->class2_alg_type | +- OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); +- +- /* Read and write assoclen bytes */ +- append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); +- append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); +- +- /* ivsize + cryptlen = seqoutlen - authsize */ +- append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize); +- +- /* Skip assoc data */ +- append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); +- +- /* read assoc before reading payload */ +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | +- KEY_VLF); +- +- /* Copy iv from outfifo to class 2 fifo */ +- moveiv = NFIFOENTRY_STYPE_OFIFO | NFIFOENTRY_DEST_CLASS2 | +- NFIFOENTRY_DTYPE_MSG | (ivsize << NFIFOENTRY_DLEN_SHIFT); +- append_load_imm_u32(desc, moveiv, LDST_CLASS_IND_CCB | +- LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); +- append_load_imm_u32(desc, ivsize, LDST_CLASS_2_CCB | +- LDST_SRCDST_WORD_DATASZ_REG | LDST_IMM); +- +- /* Load Counter into CONTEXT1 reg */ +- if (is_rfc3686) +- append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | +- LDST_SRCDST_BYTE_CONTEXT | +- ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << +- LDST_OFFSET_SHIFT)); +- +- /* Class 1 operation */ +- append_operation(desc, ctx->class1_alg_type | +- OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); +- +- /* Will write ivsize + cryptlen */ +- append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); +- +- /* Not need to reload iv */ +- append_seq_fifo_load(desc, ivsize, +- FIFOLD_CLASS_SKIP); +- +- /* Will read cryptlen */ +- append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | KEY_VLF | +- FIFOLD_TYPE_MSG1OUT2 | FIFOLD_TYPE_LASTBOTH); +- append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); +- +- /* Write ICV */ +- append_seq_store(desc, ctx->authsize, LDST_CLASS_2_CCB | +- LDST_SRCDST_BYTE_CONTEXT); +- +- ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, +- desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } +-#ifdef DEBUG +- print_hex_dump(KERN_ERR, "aead givenc shdesc@"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, desc, +- desc_bytes(desc), 1); +-#endif ++ ctx->adata.key_inline = !!(inl_mask & 1); ++ ctx->cdata.key_inline = !!(inl_mask & 2); ++ ++ /* aead_givencrypt shared descriptor */ ++ desc = ctx->sh_desc_enc; ++ cnstr_shdsc_aead_givencap(desc, &ctx->cdata, &ctx->adata, ivsize, ++ ctx->authsize, is_rfc3686, nonce, ++ ctx1_iv_off, false); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + skip_givenc: + return 0; +@@ -776,12 +323,12 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) + { + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; +- bool keys_fit_inline = false; +- u32 *key_jump_cmd, *zero_payload_jump_cmd, +- *zero_assoc_jump_cmd1, *zero_assoc_jump_cmd2; ++ unsigned int ivsize = crypto_aead_ivsize(aead); + u32 *desc; ++ int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN - ++ ctx->cdata.keylen; + +- if (!ctx->enckeylen || !ctx->authsize) ++ if (!ctx->cdata.keylen || !ctx->authsize) + return 0; + + /* +@@ -789,175 +336,35 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) + * Job Descriptor and Shared Descriptor + * must fit into the 64-word Descriptor h/w Buffer + */ +- if (DESC_GCM_ENC_LEN + GCM_DESC_JOB_IO_LEN + +- ctx->enckeylen <= CAAM_DESC_BYTES_MAX) +- keys_fit_inline = true; ++ if (rem_bytes >= DESC_GCM_ENC_LEN) { ++ ctx->cdata.key_inline = true; ++ ctx->cdata.key_virt = ctx->key; ++ } else { ++ ctx->cdata.key_inline = false; ++ ctx->cdata.key_dma = ctx->key_dma; ++ } + + desc = ctx->sh_desc_enc; +- +- init_sh_desc(desc, HDR_SHARE_SERIAL); +- +- /* skip key loading if they are loaded due to sharing */ +- key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | +- JUMP_COND_SHRD | JUMP_COND_SELF); +- if (keys_fit_inline) +- append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, +- ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); +- else +- append_key(desc, ctx->key_dma, ctx->enckeylen, +- CLASS_1 | KEY_DEST_CLASS_REG); +- set_jump_tgt_here(desc, key_jump_cmd); +- +- /* class 1 operation */ +- append_operation(desc, ctx->class1_alg_type | +- OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); +- +- /* if assoclen + cryptlen is ZERO, skip to ICV write */ +- append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); +- zero_assoc_jump_cmd2 = append_jump(desc, JUMP_TEST_ALL | +- JUMP_COND_MATH_Z); +- +- /* if assoclen is ZERO, skip reading the assoc data */ +- append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); +- zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL | +- JUMP_COND_MATH_Z); +- +- append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); +- +- /* skip assoc data */ +- append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); +- +- /* cryptlen = seqinlen - assoclen */ +- append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG3, CAAM_CMD_SZ); +- +- /* if cryptlen is ZERO jump to zero-payload commands */ +- zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL | +- JUMP_COND_MATH_Z); +- +- /* read assoc data */ +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | +- FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); +- set_jump_tgt_here(desc, zero_assoc_jump_cmd1); +- +- append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); +- +- /* write encrypted data */ +- append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); +- +- /* read payload data */ +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | +- FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); +- +- /* jump the zero-payload commands */ +- append_jump(desc, JUMP_TEST_ALL | 2); +- +- /* zero-payload commands */ +- set_jump_tgt_here(desc, zero_payload_jump_cmd); +- +- /* read assoc data */ +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | +- FIFOLD_TYPE_AAD | FIFOLD_TYPE_LAST1); +- +- /* There is no input data */ +- set_jump_tgt_here(desc, zero_assoc_jump_cmd2); +- +- /* write ICV */ +- append_seq_store(desc, ctx->authsize, LDST_CLASS_1_CCB | +- LDST_SRCDST_BYTE_CONTEXT); +- +- ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, +- desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } +-#ifdef DEBUG +- print_hex_dump(KERN_ERR, "gcm enc shdesc@"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, desc, +- desc_bytes(desc), 1); +-#endif ++ cnstr_shdsc_gcm_encap(desc, &ctx->cdata, ivsize, ctx->authsize, false); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + /* + * Job Descriptor and Shared Descriptors + * must all fit into the 64-word Descriptor h/w Buffer + */ +- keys_fit_inline = false; +- if (DESC_GCM_DEC_LEN + GCM_DESC_JOB_IO_LEN + +- ctx->enckeylen <= CAAM_DESC_BYTES_MAX) +- keys_fit_inline = true; ++ if (rem_bytes >= DESC_GCM_DEC_LEN) { ++ ctx->cdata.key_inline = true; ++ ctx->cdata.key_virt = ctx->key; ++ } else { ++ ctx->cdata.key_inline = false; ++ ctx->cdata.key_dma = ctx->key_dma; ++ } + + desc = ctx->sh_desc_dec; +- +- init_sh_desc(desc, HDR_SHARE_SERIAL); +- +- /* skip key loading if they are loaded due to sharing */ +- key_jump_cmd = append_jump(desc, JUMP_JSL | +- JUMP_TEST_ALL | JUMP_COND_SHRD | +- JUMP_COND_SELF); +- if (keys_fit_inline) +- append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, +- ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); +- else +- append_key(desc, ctx->key_dma, ctx->enckeylen, +- CLASS_1 | KEY_DEST_CLASS_REG); +- set_jump_tgt_here(desc, key_jump_cmd); +- +- /* class 1 operation */ +- append_operation(desc, ctx->class1_alg_type | +- OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); +- +- /* if assoclen is ZERO, skip reading the assoc data */ +- append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); +- zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL | +- JUMP_COND_MATH_Z); +- +- append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); +- +- /* skip assoc data */ +- append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); +- +- /* read assoc data */ +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | +- FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); +- +- set_jump_tgt_here(desc, zero_assoc_jump_cmd1); +- +- /* cryptlen = seqoutlen - assoclen */ +- append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); +- +- /* jump to zero-payload command if cryptlen is zero */ +- zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL | +- JUMP_COND_MATH_Z); +- +- append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); +- +- /* store encrypted data */ +- append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); +- +- /* read payload data */ +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | +- FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); +- +- /* zero-payload command */ +- set_jump_tgt_here(desc, zero_payload_jump_cmd); +- +- /* read ICV */ +- append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS1 | +- FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); +- +- ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, +- desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_dec_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } +-#ifdef DEBUG +- print_hex_dump(KERN_ERR, "gcm dec shdesc@"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, desc, +- desc_bytes(desc), 1); +-#endif ++ cnstr_shdsc_gcm_decap(desc, &ctx->cdata, ivsize, ctx->authsize, false); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + return 0; + } +@@ -976,11 +383,12 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) + { + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; +- bool keys_fit_inline = false; +- u32 *key_jump_cmd; ++ unsigned int ivsize = crypto_aead_ivsize(aead); + u32 *desc; ++ int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN - ++ ctx->cdata.keylen; + +- if (!ctx->enckeylen || !ctx->authsize) ++ if (!ctx->cdata.keylen || !ctx->authsize) + return 0; + + /* +@@ -988,148 +396,37 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) + * Job Descriptor and Shared Descriptor + * must fit into the 64-word Descriptor h/w Buffer + */ +- if (DESC_RFC4106_ENC_LEN + GCM_DESC_JOB_IO_LEN + +- ctx->enckeylen <= CAAM_DESC_BYTES_MAX) +- keys_fit_inline = true; ++ if (rem_bytes >= DESC_RFC4106_ENC_LEN) { ++ ctx->cdata.key_inline = true; ++ ctx->cdata.key_virt = ctx->key; ++ } else { ++ ctx->cdata.key_inline = false; ++ ctx->cdata.key_dma = ctx->key_dma; ++ } + + desc = ctx->sh_desc_enc; +- +- init_sh_desc(desc, HDR_SHARE_SERIAL); +- +- /* Skip key loading if it is loaded due to sharing */ +- key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | +- JUMP_COND_SHRD); +- if (keys_fit_inline) +- append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, +- ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); +- else +- append_key(desc, ctx->key_dma, ctx->enckeylen, +- CLASS_1 | KEY_DEST_CLASS_REG); +- set_jump_tgt_here(desc, key_jump_cmd); +- +- /* Class 1 operation */ +- append_operation(desc, ctx->class1_alg_type | +- OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); +- +- append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, 8); +- append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); +- +- /* Read assoc data */ +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | +- FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); +- +- /* Skip IV */ +- append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); +- +- /* Will read cryptlen bytes */ +- append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); +- +- /* Workaround for erratum A-005473 (simultaneous SEQ FIFO skips) */ +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_MSG); +- +- /* Skip assoc data */ +- append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); +- +- /* cryptlen = seqoutlen - assoclen */ +- append_math_sub(desc, VARSEQOUTLEN, VARSEQINLEN, REG0, CAAM_CMD_SZ); +- +- /* Write encrypted data */ +- append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); +- +- /* Read payload data */ +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | +- FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); +- +- /* Write ICV */ +- append_seq_store(desc, ctx->authsize, LDST_CLASS_1_CCB | +- LDST_SRCDST_BYTE_CONTEXT); +- +- ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, +- desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } +-#ifdef DEBUG +- print_hex_dump(KERN_ERR, "rfc4106 enc shdesc@"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, desc, +- desc_bytes(desc), 1); +-#endif ++ cnstr_shdsc_rfc4106_encap(desc, &ctx->cdata, ivsize, ctx->authsize, ++ false); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + /* + * Job Descriptor and Shared Descriptors + * must all fit into the 64-word Descriptor h/w Buffer + */ +- keys_fit_inline = false; +- if (DESC_RFC4106_DEC_LEN + DESC_JOB_IO_LEN + +- ctx->enckeylen <= CAAM_DESC_BYTES_MAX) +- keys_fit_inline = true; ++ if (rem_bytes >= DESC_RFC4106_DEC_LEN) { ++ ctx->cdata.key_inline = true; ++ ctx->cdata.key_virt = ctx->key; ++ } else { ++ ctx->cdata.key_inline = false; ++ ctx->cdata.key_dma = ctx->key_dma; ++ } + + desc = ctx->sh_desc_dec; +- +- init_sh_desc(desc, HDR_SHARE_SERIAL); +- +- /* Skip key loading if it is loaded due to sharing */ +- key_jump_cmd = append_jump(desc, JUMP_JSL | +- JUMP_TEST_ALL | JUMP_COND_SHRD); +- if (keys_fit_inline) +- append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, +- ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); +- else +- append_key(desc, ctx->key_dma, ctx->enckeylen, +- CLASS_1 | KEY_DEST_CLASS_REG); +- set_jump_tgt_here(desc, key_jump_cmd); +- +- /* Class 1 operation */ +- append_operation(desc, ctx->class1_alg_type | +- OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); +- +- append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, 8); +- append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); +- +- /* Read assoc data */ +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | +- FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); +- +- /* Skip IV */ +- append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); +- +- /* Will read cryptlen bytes */ +- append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG3, CAAM_CMD_SZ); +- +- /* Workaround for erratum A-005473 (simultaneous SEQ FIFO skips) */ +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_MSG); +- +- /* Skip assoc data */ +- append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); +- +- /* Will write cryptlen bytes */ +- append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); +- +- /* Store payload data */ +- append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); +- +- /* Read encrypted data */ +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | +- FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); +- +- /* Read ICV */ +- append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS1 | +- FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); +- +- ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, +- desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_dec_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } +-#ifdef DEBUG +- print_hex_dump(KERN_ERR, "rfc4106 dec shdesc@"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, desc, +- desc_bytes(desc), 1); +-#endif ++ cnstr_shdsc_rfc4106_decap(desc, &ctx->cdata, ivsize, ctx->authsize, ++ false); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + return 0; + } +@@ -1149,12 +446,12 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) + { + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; +- bool keys_fit_inline = false; +- u32 *key_jump_cmd; +- u32 *read_move_cmd, *write_move_cmd; ++ unsigned int ivsize = crypto_aead_ivsize(aead); + u32 *desc; ++ int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN - ++ ctx->cdata.keylen; + +- if (!ctx->enckeylen || !ctx->authsize) ++ if (!ctx->cdata.keylen || !ctx->authsize) + return 0; + + /* +@@ -1162,151 +459,37 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) + * Job Descriptor and Shared Descriptor + * must fit into the 64-word Descriptor h/w Buffer + */ +- if (DESC_RFC4543_ENC_LEN + GCM_DESC_JOB_IO_LEN + +- ctx->enckeylen <= CAAM_DESC_BYTES_MAX) +- keys_fit_inline = true; +- +- desc = ctx->sh_desc_enc; +- +- init_sh_desc(desc, HDR_SHARE_SERIAL); +- +- /* Skip key loading if it is loaded due to sharing */ +- key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | +- JUMP_COND_SHRD); +- if (keys_fit_inline) +- append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, +- ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); +- else +- append_key(desc, ctx->key_dma, ctx->enckeylen, +- CLASS_1 | KEY_DEST_CLASS_REG); +- set_jump_tgt_here(desc, key_jump_cmd); +- +- /* Class 1 operation */ +- append_operation(desc, ctx->class1_alg_type | +- OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); +- +- /* assoclen + cryptlen = seqinlen */ +- append_math_sub(desc, REG3, SEQINLEN, REG0, CAAM_CMD_SZ); +- +- /* +- * MOVE_LEN opcode is not available in all SEC HW revisions, +- * thus need to do some magic, i.e. self-patch the descriptor +- * buffer. +- */ +- read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH3 | +- (0x6 << MOVE_LEN_SHIFT)); +- write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | MOVE_DEST_DESCBUF | +- (0x8 << MOVE_LEN_SHIFT)); +- +- /* Will read assoclen + cryptlen bytes */ +- append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); +- +- /* Will write assoclen + cryptlen bytes */ +- append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); +- +- /* Read and write assoclen + cryptlen bytes */ +- aead_append_src_dst(desc, FIFOLD_TYPE_AAD); +- +- set_move_tgt_here(desc, read_move_cmd); +- set_move_tgt_here(desc, write_move_cmd); +- append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); +- /* Move payload data to OFIFO */ +- append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO); +- +- /* Write ICV */ +- append_seq_store(desc, ctx->authsize, LDST_CLASS_1_CCB | +- LDST_SRCDST_BYTE_CONTEXT); +- +- ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, +- desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; ++ if (rem_bytes >= DESC_RFC4543_ENC_LEN) { ++ ctx->cdata.key_inline = true; ++ ctx->cdata.key_virt = ctx->key; ++ } else { ++ ctx->cdata.key_inline = false; ++ ctx->cdata.key_dma = ctx->key_dma; + } +-#ifdef DEBUG +- print_hex_dump(KERN_ERR, "rfc4543 enc shdesc@"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, desc, +- desc_bytes(desc), 1); +-#endif ++ ++ desc = ctx->sh_desc_enc; ++ cnstr_shdsc_rfc4543_encap(desc, &ctx->cdata, ivsize, ctx->authsize, ++ false); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + /* + * Job Descriptor and Shared Descriptors + * must all fit into the 64-word Descriptor h/w Buffer + */ +- keys_fit_inline = false; +- if (DESC_RFC4543_DEC_LEN + GCM_DESC_JOB_IO_LEN + +- ctx->enckeylen <= CAAM_DESC_BYTES_MAX) +- keys_fit_inline = true; ++ if (rem_bytes >= DESC_RFC4543_DEC_LEN) { ++ ctx->cdata.key_inline = true; ++ ctx->cdata.key_virt = ctx->key; ++ } else { ++ ctx->cdata.key_inline = false; ++ ctx->cdata.key_dma = ctx->key_dma; ++ } + + desc = ctx->sh_desc_dec; +- +- init_sh_desc(desc, HDR_SHARE_SERIAL); +- +- /* Skip key loading if it is loaded due to sharing */ +- key_jump_cmd = append_jump(desc, JUMP_JSL | +- JUMP_TEST_ALL | JUMP_COND_SHRD); +- if (keys_fit_inline) +- append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, +- ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); +- else +- append_key(desc, ctx->key_dma, ctx->enckeylen, +- CLASS_1 | KEY_DEST_CLASS_REG); +- set_jump_tgt_here(desc, key_jump_cmd); +- +- /* Class 1 operation */ +- append_operation(desc, ctx->class1_alg_type | +- OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); +- +- /* assoclen + cryptlen = seqoutlen */ +- append_math_sub(desc, REG3, SEQOUTLEN, REG0, CAAM_CMD_SZ); +- +- /* +- * MOVE_LEN opcode is not available in all SEC HW revisions, +- * thus need to do some magic, i.e. self-patch the descriptor +- * buffer. +- */ +- read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH3 | +- (0x6 << MOVE_LEN_SHIFT)); +- write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | MOVE_DEST_DESCBUF | +- (0x8 << MOVE_LEN_SHIFT)); +- +- /* Will read assoclen + cryptlen bytes */ +- append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); +- +- /* Will write assoclen + cryptlen bytes */ +- append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); +- +- /* Store payload data */ +- append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); +- +- /* In-snoop assoclen + cryptlen data */ +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | FIFOLDST_VLF | +- FIFOLD_TYPE_AAD | FIFOLD_TYPE_LAST2FLUSH1); +- +- set_move_tgt_here(desc, read_move_cmd); +- set_move_tgt_here(desc, write_move_cmd); +- append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); +- /* Move payload data to OFIFO */ +- append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO); +- append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); +- +- /* Read ICV */ +- append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS1 | +- FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); +- +- ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, +- desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_dec_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } +-#ifdef DEBUG +- print_hex_dump(KERN_ERR, "rfc4543 dec shdesc@"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, desc, +- desc_bytes(desc), 1); +-#endif ++ cnstr_shdsc_rfc4543_decap(desc, &ctx->cdata, ivsize, ctx->authsize, ++ false); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + return 0; + } +@@ -1322,19 +505,9 @@ static int rfc4543_setauthsize(struct crypto_aead *authenc, + return 0; + } + +-static u32 gen_split_aead_key(struct caam_ctx *ctx, const u8 *key_in, +- u32 authkeylen) +-{ +- return gen_split_key(ctx->jrdev, ctx->key, ctx->split_key_len, +- ctx->split_key_pad_len, key_in, authkeylen, +- ctx->alg_op); +-} +- + static int aead_setkey(struct crypto_aead *aead, + const u8 *key, unsigned int keylen) + { +- /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */ +- static const u8 mdpadlen[] = { 16, 20, 32, 32, 64, 64 }; + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; + struct crypto_authenc_keys keys; +@@ -1343,53 +516,32 @@ static int aead_setkey(struct crypto_aead *aead, + if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) + goto badkey; + +- /* Pick class 2 key length from algorithm submask */ +- ctx->split_key_len = mdpadlen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >> +- OP_ALG_ALGSEL_SHIFT] * 2; +- ctx->split_key_pad_len = ALIGN(ctx->split_key_len, 16); +- +- if (ctx->split_key_pad_len + keys.enckeylen > CAAM_MAX_KEY_SIZE) +- goto badkey; +- + #ifdef DEBUG + printk(KERN_ERR "keylen %d enckeylen %d authkeylen %d\n", + keys.authkeylen + keys.enckeylen, keys.enckeylen, + keys.authkeylen); +- printk(KERN_ERR "split_key_len %d split_key_pad_len %d\n", +- ctx->split_key_len, ctx->split_key_pad_len); + print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); + #endif + +- ret = gen_split_aead_key(ctx, keys.authkey, keys.authkeylen); ++ ret = gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, keys.authkey, ++ keys.authkeylen, CAAM_MAX_KEY_SIZE - ++ keys.enckeylen); + if (ret) { + goto badkey; + } + + /* postpend encryption key to auth split key */ +- memcpy(ctx->key + ctx->split_key_pad_len, keys.enckey, keys.enckeylen); +- +- ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->split_key_pad_len + +- keys.enckeylen, DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->key_dma)) { +- dev_err(jrdev, "unable to map key i/o memory\n"); +- return -ENOMEM; +- } ++ memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen); ++ dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->adata.keylen_pad + ++ keys.enckeylen, DMA_TO_DEVICE); + #ifdef DEBUG + print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, +- ctx->split_key_pad_len + keys.enckeylen, 1); ++ ctx->adata.keylen_pad + keys.enckeylen, 1); + #endif +- +- ctx->enckeylen = keys.enckeylen; +- +- ret = aead_set_sh_desc(aead); +- if (ret) { +- dma_unmap_single(jrdev, ctx->key_dma, ctx->split_key_pad_len + +- keys.enckeylen, DMA_TO_DEVICE); +- } +- +- return ret; ++ ctx->cdata.keylen = keys.enckeylen; ++ return aead_set_sh_desc(aead); + badkey: + crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; +@@ -1400,7 +552,6 @@ static int gcm_setkey(struct crypto_aead *aead, + { + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; +- int ret = 0; + + #ifdef DEBUG + print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", +@@ -1408,21 +559,10 @@ static int gcm_setkey(struct crypto_aead *aead, + #endif + + memcpy(ctx->key, key, keylen); +- ctx->key_dma = dma_map_single(jrdev, ctx->key, keylen, +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->key_dma)) { +- dev_err(jrdev, "unable to map key i/o memory\n"); +- return -ENOMEM; +- } +- ctx->enckeylen = keylen; +- +- ret = gcm_set_sh_desc(aead); +- if (ret) { +- dma_unmap_single(jrdev, ctx->key_dma, ctx->enckeylen, +- DMA_TO_DEVICE); +- } ++ dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, DMA_TO_DEVICE); ++ ctx->cdata.keylen = keylen; + +- return ret; ++ return gcm_set_sh_desc(aead); + } + + static int rfc4106_setkey(struct crypto_aead *aead, +@@ -1430,7 +570,6 @@ static int rfc4106_setkey(struct crypto_aead *aead, + { + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; +- int ret = 0; + + if (keylen < 4) + return -EINVAL; +@@ -1446,22 +585,10 @@ static int rfc4106_setkey(struct crypto_aead *aead, + * The last four bytes of the key material are used as the salt value + * in the nonce. Update the AES key length. + */ +- ctx->enckeylen = keylen - 4; +- +- ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->enckeylen, +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->key_dma)) { +- dev_err(jrdev, "unable to map key i/o memory\n"); +- return -ENOMEM; +- } +- +- ret = rfc4106_set_sh_desc(aead); +- if (ret) { +- dma_unmap_single(jrdev, ctx->key_dma, ctx->enckeylen, +- DMA_TO_DEVICE); +- } +- +- return ret; ++ ctx->cdata.keylen = keylen - 4; ++ dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->cdata.keylen, ++ DMA_TO_DEVICE); ++ return rfc4106_set_sh_desc(aead); + } + + static int rfc4543_setkey(struct crypto_aead *aead, +@@ -1469,7 +596,6 @@ static int rfc4543_setkey(struct crypto_aead *aead, + { + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; +- int ret = 0; + + if (keylen < 4) + return -EINVAL; +@@ -1485,43 +611,28 @@ static int rfc4543_setkey(struct crypto_aead *aead, + * The last four bytes of the key material are used as the salt value + * in the nonce. Update the AES key length. + */ +- ctx->enckeylen = keylen - 4; +- +- ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->enckeylen, +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->key_dma)) { +- dev_err(jrdev, "unable to map key i/o memory\n"); +- return -ENOMEM; +- } +- +- ret = rfc4543_set_sh_desc(aead); +- if (ret) { +- dma_unmap_single(jrdev, ctx->key_dma, ctx->enckeylen, +- DMA_TO_DEVICE); +- } +- +- return ret; ++ ctx->cdata.keylen = keylen - 4; ++ dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->cdata.keylen, ++ DMA_TO_DEVICE); ++ return rfc4543_set_sh_desc(aead); + } + + static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, + const u8 *key, unsigned int keylen) + { + struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); +- struct ablkcipher_tfm *crt = &ablkcipher->base.crt_ablkcipher; + struct crypto_tfm *tfm = crypto_ablkcipher_tfm(ablkcipher); + const char *alg_name = crypto_tfm_alg_name(tfm); + struct device *jrdev = ctx->jrdev; +- int ret = 0; +- u32 *key_jump_cmd; ++ unsigned int ivsize = crypto_ablkcipher_ivsize(ablkcipher); + u32 *desc; +- u8 *nonce; +- u32 geniv; + u32 ctx1_iv_off = 0; +- const bool ctr_mode = ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == ++ const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == + OP_ALG_AAI_CTR_MOD128); + const bool is_rfc3686 = (ctr_mode && + (strstr(alg_name, "rfc3686") != NULL)); + ++ memcpy(ctx->key, key, keylen); + #ifdef DEBUG + print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); +@@ -1544,215 +655,33 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, + keylen -= CTR_RFC3686_NONCE_SIZE; + } + +- memcpy(ctx->key, key, keylen); +- ctx->key_dma = dma_map_single(jrdev, ctx->key, keylen, +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->key_dma)) { +- dev_err(jrdev, "unable to map key i/o memory\n"); +- return -ENOMEM; +- } +- ctx->enckeylen = keylen; ++ dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, DMA_TO_DEVICE); ++ ctx->cdata.keylen = keylen; ++ ctx->cdata.key_virt = ctx->key; ++ ctx->cdata.key_inline = true; + + /* ablkcipher_encrypt shared descriptor */ + desc = ctx->sh_desc_enc; +- init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); +- /* Skip if already shared */ +- key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | +- JUMP_COND_SHRD); +- +- /* Load class1 key only */ +- append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, +- ctx->enckeylen, CLASS_1 | +- KEY_DEST_CLASS_REG); +- +- /* Load nonce into CONTEXT1 reg */ +- if (is_rfc3686) { +- nonce = (u8 *)key + keylen; +- append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, +- LDST_CLASS_IND_CCB | +- LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); +- append_move(desc, MOVE_WAITCOMP | +- MOVE_SRC_OUTFIFO | +- MOVE_DEST_CLASS1CTX | +- (16 << MOVE_OFFSET_SHIFT) | +- (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); +- } +- +- set_jump_tgt_here(desc, key_jump_cmd); ++ cnstr_shdsc_ablkcipher_encap(desc, &ctx->cdata, ivsize, is_rfc3686, ++ ctx1_iv_off); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + +- /* Load iv */ +- append_seq_load(desc, crt->ivsize, LDST_SRCDST_BYTE_CONTEXT | +- LDST_CLASS_1_CCB | (ctx1_iv_off << LDST_OFFSET_SHIFT)); +- +- /* Load counter into CONTEXT1 reg */ +- if (is_rfc3686) +- append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | +- LDST_SRCDST_BYTE_CONTEXT | +- ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << +- LDST_OFFSET_SHIFT)); +- +- /* Load operation */ +- append_operation(desc, ctx->class1_alg_type | +- OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); +- +- /* Perform operation */ +- ablkcipher_append_src_dst(desc); +- +- ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, +- desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } +-#ifdef DEBUG +- print_hex_dump(KERN_ERR, +- "ablkcipher enc shdesc@"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, desc, +- desc_bytes(desc), 1); +-#endif + /* ablkcipher_decrypt shared descriptor */ + desc = ctx->sh_desc_dec; ++ cnstr_shdsc_ablkcipher_decap(desc, &ctx->cdata, ivsize, is_rfc3686, ++ ctx1_iv_off); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + +- init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); +- /* Skip if already shared */ +- key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | +- JUMP_COND_SHRD); +- +- /* Load class1 key only */ +- append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, +- ctx->enckeylen, CLASS_1 | +- KEY_DEST_CLASS_REG); +- +- /* Load nonce into CONTEXT1 reg */ +- if (is_rfc3686) { +- nonce = (u8 *)key + keylen; +- append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, +- LDST_CLASS_IND_CCB | +- LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); +- append_move(desc, MOVE_WAITCOMP | +- MOVE_SRC_OUTFIFO | +- MOVE_DEST_CLASS1CTX | +- (16 << MOVE_OFFSET_SHIFT) | +- (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); +- } +- +- set_jump_tgt_here(desc, key_jump_cmd); +- +- /* load IV */ +- append_seq_load(desc, crt->ivsize, LDST_SRCDST_BYTE_CONTEXT | +- LDST_CLASS_1_CCB | (ctx1_iv_off << LDST_OFFSET_SHIFT)); +- +- /* Load counter into CONTEXT1 reg */ +- if (is_rfc3686) +- append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | +- LDST_SRCDST_BYTE_CONTEXT | +- ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << +- LDST_OFFSET_SHIFT)); +- +- /* Choose operation */ +- if (ctr_mode) +- append_operation(desc, ctx->class1_alg_type | +- OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT); +- else +- append_dec_op1(desc, ctx->class1_alg_type); +- +- /* Perform operation */ +- ablkcipher_append_src_dst(desc); +- +- ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, +- desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_dec_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } +- +-#ifdef DEBUG +- print_hex_dump(KERN_ERR, +- "ablkcipher dec shdesc@"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, desc, +- desc_bytes(desc), 1); +-#endif + /* ablkcipher_givencrypt shared descriptor */ + desc = ctx->sh_desc_givenc; ++ cnstr_shdsc_ablkcipher_givencap(desc, &ctx->cdata, ivsize, is_rfc3686, ++ ctx1_iv_off); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_givenc_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + +- init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); +- /* Skip if already shared */ +- key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | +- JUMP_COND_SHRD); +- +- /* Load class1 key only */ +- append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, +- ctx->enckeylen, CLASS_1 | +- KEY_DEST_CLASS_REG); +- +- /* Load Nonce into CONTEXT1 reg */ +- if (is_rfc3686) { +- nonce = (u8 *)key + keylen; +- append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, +- LDST_CLASS_IND_CCB | +- LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); +- append_move(desc, MOVE_WAITCOMP | +- MOVE_SRC_OUTFIFO | +- MOVE_DEST_CLASS1CTX | +- (16 << MOVE_OFFSET_SHIFT) | +- (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); +- } +- set_jump_tgt_here(desc, key_jump_cmd); +- +- /* Generate IV */ +- geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO | +- NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 | +- NFIFOENTRY_PTYPE_RND | (crt->ivsize << NFIFOENTRY_DLEN_SHIFT); +- append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB | +- LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); +- append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); +- append_move(desc, MOVE_WAITCOMP | +- MOVE_SRC_INFIFO | +- MOVE_DEST_CLASS1CTX | +- (crt->ivsize << MOVE_LEN_SHIFT) | +- (ctx1_iv_off << MOVE_OFFSET_SHIFT)); +- append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); +- +- /* Copy generated IV to memory */ +- append_seq_store(desc, crt->ivsize, +- LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB | +- (ctx1_iv_off << LDST_OFFSET_SHIFT)); +- +- /* Load Counter into CONTEXT1 reg */ +- if (is_rfc3686) +- append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | +- LDST_SRCDST_BYTE_CONTEXT | +- ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << +- LDST_OFFSET_SHIFT)); +- +- if (ctx1_iv_off) +- append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_NCP | +- (1 << JUMP_OFFSET_SHIFT)); +- +- /* Load operation */ +- append_operation(desc, ctx->class1_alg_type | +- OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); +- +- /* Perform operation */ +- ablkcipher_append_src_dst(desc); +- +- ctx->sh_desc_givenc_dma = dma_map_single(jrdev, desc, +- desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_givenc_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } +-#ifdef DEBUG +- print_hex_dump(KERN_ERR, +- "ablkcipher givenc shdesc@" __stringify(__LINE__) ": ", +- DUMP_PREFIX_ADDRESS, 16, 4, desc, +- desc_bytes(desc), 1); +-#endif +- +- return ret; ++ return 0; + } + + static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, +@@ -1760,8 +689,7 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, + { + struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); + struct device *jrdev = ctx->jrdev; +- u32 *key_jump_cmd, *desc; +- __be64 sector_size = cpu_to_be64(512); ++ u32 *desc; + + if (keylen != 2 * AES_MIN_KEY_SIZE && keylen != 2 * AES_MAX_KEY_SIZE) { + crypto_ablkcipher_set_flags(ablkcipher, +@@ -1771,126 +699,38 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, + } + + memcpy(ctx->key, key, keylen); +- ctx->key_dma = dma_map_single(jrdev, ctx->key, keylen, DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->key_dma)) { +- dev_err(jrdev, "unable to map key i/o memory\n"); +- return -ENOMEM; +- } +- ctx->enckeylen = keylen; ++ dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, DMA_TO_DEVICE); ++ ctx->cdata.keylen = keylen; ++ ctx->cdata.key_virt = ctx->key; ++ ctx->cdata.key_inline = true; + + /* xts_ablkcipher_encrypt shared descriptor */ + desc = ctx->sh_desc_enc; +- init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); +- /* Skip if already shared */ +- key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | +- JUMP_COND_SHRD); +- +- /* Load class1 keys only */ +- append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, +- ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); +- +- /* Load sector size with index 40 bytes (0x28) */ +- append_cmd(desc, CMD_LOAD | IMMEDIATE | LDST_SRCDST_BYTE_CONTEXT | +- LDST_CLASS_1_CCB | (0x28 << LDST_OFFSET_SHIFT) | 8); +- append_data(desc, (void *)§or_size, 8); +- +- set_jump_tgt_here(desc, key_jump_cmd); +- +- /* +- * create sequence for loading the sector index +- * Upper 8B of IV - will be used as sector index +- * Lower 8B of IV - will be discarded +- */ +- append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | +- LDST_CLASS_1_CCB | (0x20 << LDST_OFFSET_SHIFT) | 8); +- append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); +- +- /* Load operation */ +- append_operation(desc, ctx->class1_alg_type | OP_ALG_AS_INITFINAL | +- OP_ALG_ENCRYPT); +- +- /* Perform operation */ +- ablkcipher_append_src_dst(desc); +- +- ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } +-#ifdef DEBUG +- print_hex_dump(KERN_ERR, +- "xts ablkcipher enc shdesc@" __stringify(__LINE__) ": ", +- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +-#endif ++ cnstr_shdsc_xts_ablkcipher_encap(desc, &ctx->cdata); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_enc_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + /* xts_ablkcipher_decrypt shared descriptor */ + desc = ctx->sh_desc_dec; +- +- init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); +- /* Skip if already shared */ +- key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | +- JUMP_COND_SHRD); +- +- /* Load class1 key only */ +- append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, +- ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); +- +- /* Load sector size with index 40 bytes (0x28) */ +- append_cmd(desc, CMD_LOAD | IMMEDIATE | LDST_SRCDST_BYTE_CONTEXT | +- LDST_CLASS_1_CCB | (0x28 << LDST_OFFSET_SHIFT) | 8); +- append_data(desc, (void *)§or_size, 8); +- +- set_jump_tgt_here(desc, key_jump_cmd); +- +- /* +- * create sequence for loading the sector index +- * Upper 8B of IV - will be used as sector index +- * Lower 8B of IV - will be discarded +- */ +- append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | +- LDST_CLASS_1_CCB | (0x20 << LDST_OFFSET_SHIFT) | 8); +- append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); +- +- /* Load operation */ +- append_dec_op1(desc, ctx->class1_alg_type); +- +- /* Perform operation */ +- ablkcipher_append_src_dst(desc); +- +- ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_dec_dma)) { +- dma_unmap_single(jrdev, ctx->sh_desc_enc_dma, +- desc_bytes(ctx->sh_desc_enc), DMA_TO_DEVICE); +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } +-#ifdef DEBUG +- print_hex_dump(KERN_ERR, +- "xts ablkcipher dec shdesc@" __stringify(__LINE__) ": ", +- DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +-#endif ++ cnstr_shdsc_xts_ablkcipher_decap(desc, &ctx->cdata); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_dec_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + + return 0; + } + + /* + * aead_edesc - s/w-extended aead descriptor +- * @assoc_nents: number of segments in associated data (SPI+Seq) scatterlist +- * @src_nents: number of segments in input scatterlist +- * @dst_nents: number of segments in output scatterlist +- * @iv_dma: dma address of iv for checking continuity and link table +- * @desc: h/w descriptor (variable length; must not exceed MAX_CAAM_DESCSIZE) ++ * @src_nents: number of segments in input s/w scatterlist ++ * @dst_nents: number of segments in output s/w scatterlist + * @sec4_sg_bytes: length of dma mapped sec4_sg space + * @sec4_sg_dma: bus physical mapped address of h/w link table ++ * @sec4_sg: pointer to h/w link table + * @hw_desc: the h/w job descriptor followed by any referenced link tables + */ + struct aead_edesc { +- int assoc_nents; + int src_nents; + int dst_nents; +- dma_addr_t iv_dma; + int sec4_sg_bytes; + dma_addr_t sec4_sg_dma; + struct sec4_sg_entry *sec4_sg; +@@ -1899,12 +739,12 @@ struct aead_edesc { + + /* + * ablkcipher_edesc - s/w-extended ablkcipher descriptor +- * @src_nents: number of segments in input scatterlist +- * @dst_nents: number of segments in output scatterlist ++ * @src_nents: number of segments in input s/w scatterlist ++ * @dst_nents: number of segments in output s/w scatterlist + * @iv_dma: dma address of iv for checking continuity and link table +- * @desc: h/w descriptor (variable length; must not exceed MAX_CAAM_DESCSIZE) + * @sec4_sg_bytes: length of dma mapped sec4_sg space + * @sec4_sg_dma: bus physical mapped address of h/w link table ++ * @sec4_sg: pointer to h/w link table + * @hw_desc: the h/w job descriptor followed by any referenced link tables + */ + struct ablkcipher_edesc { +@@ -1924,10 +764,11 @@ static void caam_unmap(struct device *dev, struct scatterlist *src, + int sec4_sg_bytes) + { + if (dst != src) { +- dma_unmap_sg(dev, src, src_nents ? : 1, DMA_TO_DEVICE); +- dma_unmap_sg(dev, dst, dst_nents ? : 1, DMA_FROM_DEVICE); ++ if (src_nents) ++ dma_unmap_sg(dev, src, src_nents, DMA_TO_DEVICE); ++ dma_unmap_sg(dev, dst, dst_nents, DMA_FROM_DEVICE); + } else { +- dma_unmap_sg(dev, src, src_nents ? : 1, DMA_BIDIRECTIONAL); ++ dma_unmap_sg(dev, src, src_nents, DMA_BIDIRECTIONAL); + } + + if (iv_dma) +@@ -2021,8 +862,7 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, + dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); + #endif + +- edesc = (struct ablkcipher_edesc *)((char *)desc - +- offsetof(struct ablkcipher_edesc, hw_desc)); ++ edesc = container_of(desc, struct ablkcipher_edesc, hw_desc[0]); + + if (err) + caam_jr_strstatus(jrdev, err); +@@ -2031,10 +871,10 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, + print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->info, + edesc->src_nents > 1 ? 100 : ivsize, 1); +- dbg_dump_sg(KERN_ERR, "dst @"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, req->dst, +- edesc->dst_nents > 1 ? 100 : req->nbytes, 1, true); + #endif ++ caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, req->dst, ++ edesc->dst_nents > 1 ? 100 : req->nbytes, 1); + + ablkcipher_unmap(jrdev, edesc, req); + +@@ -2062,8 +902,7 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, + dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); + #endif + +- edesc = (struct ablkcipher_edesc *)((char *)desc - +- offsetof(struct ablkcipher_edesc, hw_desc)); ++ edesc = container_of(desc, struct ablkcipher_edesc, hw_desc[0]); + if (err) + caam_jr_strstatus(jrdev, err); + +@@ -2071,10 +910,10 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, + print_hex_dump(KERN_ERR, "dstiv @"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->info, + ivsize, 1); +- dbg_dump_sg(KERN_ERR, "dst @"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, req->dst, +- edesc->dst_nents > 1 ? 100 : req->nbytes, 1, true); + #endif ++ caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, req->dst, ++ edesc->dst_nents > 1 ? 100 : req->nbytes, 1); + + ablkcipher_unmap(jrdev, edesc, req); + +@@ -2114,7 +953,7 @@ static void init_aead_job(struct aead_request *req, + init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE); + + if (all_contig) { +- src_dma = sg_dma_address(req->src); ++ src_dma = edesc->src_nents ? sg_dma_address(req->src) : 0; + in_options = 0; + } else { + src_dma = edesc->sec4_sg_dma; +@@ -2129,7 +968,7 @@ static void init_aead_job(struct aead_request *req, + out_options = in_options; + + if (unlikely(req->src != req->dst)) { +- if (!edesc->dst_nents) { ++ if (edesc->dst_nents == 1) { + dst_dma = sg_dma_address(req->dst); + } else { + dst_dma = edesc->sec4_sg_dma + +@@ -2175,7 +1014,7 @@ static void init_gcm_job(struct aead_request *req, + FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1 | 12 | last); + /* Append Salt */ + if (!generic_gcm) +- append_data(desc, ctx->key + ctx->enckeylen, 4); ++ append_data(desc, ctx->key + ctx->cdata.keylen, 4); + /* Append IV */ + append_data(desc, req->iv, ivsize); + /* End of blank commands */ +@@ -2190,7 +1029,7 @@ static void init_authenc_job(struct aead_request *req, + struct caam_aead_alg, aead); + unsigned int ivsize = crypto_aead_ivsize(aead); + struct caam_ctx *ctx = crypto_aead_ctx(aead); +- const bool ctr_mode = ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == ++ const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == + OP_ALG_AAI_CTR_MOD128); + const bool is_rfc3686 = alg->caam.rfc3686; + u32 *desc = edesc->hw_desc; +@@ -2236,16 +1075,15 @@ static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr, + int len, sec4_sg_index = 0; + + #ifdef DEBUG +- bool may_sleep = ((req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | +- CRYPTO_TFM_REQ_MAY_SLEEP)) != 0); + print_hex_dump(KERN_ERR, "presciv@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->info, + ivsize, 1); +- printk(KERN_ERR "asked=%d, nbytes%d\n", (int)edesc->src_nents ? 100 : req->nbytes, req->nbytes); +- dbg_dump_sg(KERN_ERR, "src @"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, req->src, +- edesc->src_nents ? 100 : req->nbytes, 1, may_sleep); ++ pr_err("asked=%d, nbytes%d\n", ++ (int)edesc->src_nents > 1 ? 100 : req->nbytes, req->nbytes); + #endif ++ caam_dump_sg(KERN_ERR, "src @" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, req->src, ++ edesc->src_nents > 1 ? 100 : req->nbytes, 1); + + len = desc_len(sh_desc); + init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE); +@@ -2261,7 +1099,7 @@ static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr, + append_seq_in_ptr(desc, src_dma, req->nbytes + ivsize, in_options); + + if (likely(req->src == req->dst)) { +- if (!edesc->src_nents && iv_contig) { ++ if (edesc->src_nents == 1 && iv_contig) { + dst_dma = sg_dma_address(req->src); + } else { + dst_dma = edesc->sec4_sg_dma + +@@ -2269,7 +1107,7 @@ static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr, + out_options = LDST_SGF; + } + } else { +- if (!edesc->dst_nents) { ++ if (edesc->dst_nents == 1) { + dst_dma = sg_dma_address(req->dst); + } else { + dst_dma = edesc->sec4_sg_dma + +@@ -2296,20 +1134,18 @@ static void init_ablkcipher_giv_job(u32 *sh_desc, dma_addr_t ptr, + int len, sec4_sg_index = 0; + + #ifdef DEBUG +- bool may_sleep = ((req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | +- CRYPTO_TFM_REQ_MAY_SLEEP)) != 0); + print_hex_dump(KERN_ERR, "presciv@" __stringify(__LINE__) ": ", + DUMP_PREFIX_ADDRESS, 16, 4, req->info, + ivsize, 1); +- dbg_dump_sg(KERN_ERR, "src @" __stringify(__LINE__) ": ", +- DUMP_PREFIX_ADDRESS, 16, 4, req->src, +- edesc->src_nents ? 100 : req->nbytes, 1, may_sleep); + #endif ++ caam_dump_sg(KERN_ERR, "src @" __stringify(__LINE__) ": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, req->src, ++ edesc->src_nents > 1 ? 100 : req->nbytes, 1); + + len = desc_len(sh_desc); + init_job_desc_shared(desc, ptr, len, HDR_SHARE_DEFER | HDR_REVERSE); + +- if (!edesc->src_nents) { ++ if (edesc->src_nents == 1) { + src_dma = sg_dma_address(req->src); + in_options = 0; + } else { +@@ -2340,87 +1176,100 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct caam_ctx *ctx = crypto_aead_ctx(aead); + struct device *jrdev = ctx->jrdev; +- gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | +- CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC; +- int src_nents, dst_nents = 0; ++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? ++ GFP_KERNEL : GFP_ATOMIC; ++ int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; + struct aead_edesc *edesc; +- int sgc; +- bool all_contig = true; +- int sec4_sg_index, sec4_sg_len = 0, sec4_sg_bytes; ++ int sec4_sg_index, sec4_sg_len, sec4_sg_bytes; + unsigned int authsize = ctx->authsize; + + if (unlikely(req->dst != req->src)) { +- src_nents = sg_count(req->src, req->assoclen + req->cryptlen); +- dst_nents = sg_count(req->dst, +- req->assoclen + req->cryptlen + +- (encrypt ? authsize : (-authsize))); +- } else { +- src_nents = sg_count(req->src, +- req->assoclen + req->cryptlen + +- (encrypt ? authsize : 0)); +- } +- +- /* Check if data are contiguous. */ +- all_contig = !src_nents; +- if (!all_contig) { +- src_nents = src_nents ? : 1; +- sec4_sg_len = src_nents; +- } +- +- sec4_sg_len += dst_nents; +- +- sec4_sg_bytes = sec4_sg_len * sizeof(struct sec4_sg_entry); ++ src_nents = sg_nents_for_len(req->src, req->assoclen + ++ req->cryptlen); ++ if (unlikely(src_nents < 0)) { ++ dev_err(jrdev, "Insufficient bytes (%d) in src S/G\n", ++ req->assoclen + req->cryptlen); ++ return ERR_PTR(src_nents); ++ } + +- /* allocate space for base edesc and hw desc commands, link tables */ +- edesc = kzalloc(sizeof(*edesc) + desc_bytes + sec4_sg_bytes, +- GFP_DMA | flags); +- if (!edesc) { +- dev_err(jrdev, "could not allocate extended descriptor\n"); +- return ERR_PTR(-ENOMEM); ++ dst_nents = sg_nents_for_len(req->dst, req->assoclen + ++ req->cryptlen + ++ (encrypt ? authsize : ++ (-authsize))); ++ if (unlikely(dst_nents < 0)) { ++ dev_err(jrdev, "Insufficient bytes (%d) in dst S/G\n", ++ req->assoclen + req->cryptlen + ++ (encrypt ? authsize : (-authsize))); ++ return ERR_PTR(dst_nents); ++ } ++ } else { ++ src_nents = sg_nents_for_len(req->src, req->assoclen + ++ req->cryptlen + ++ (encrypt ? authsize : 0)); ++ if (unlikely(src_nents < 0)) { ++ dev_err(jrdev, "Insufficient bytes (%d) in src S/G\n", ++ req->assoclen + req->cryptlen + ++ (encrypt ? authsize : 0)); ++ return ERR_PTR(src_nents); ++ } + } + + if (likely(req->src == req->dst)) { +- sgc = dma_map_sg(jrdev, req->src, src_nents ? : 1, +- DMA_BIDIRECTIONAL); +- if (unlikely(!sgc)) { ++ mapped_src_nents = dma_map_sg(jrdev, req->src, src_nents, ++ DMA_BIDIRECTIONAL); ++ if (unlikely(!mapped_src_nents)) { + dev_err(jrdev, "unable to map source\n"); +- kfree(edesc); + return ERR_PTR(-ENOMEM); + } + } else { +- sgc = dma_map_sg(jrdev, req->src, src_nents ? : 1, +- DMA_TO_DEVICE); +- if (unlikely(!sgc)) { +- dev_err(jrdev, "unable to map source\n"); +- kfree(edesc); +- return ERR_PTR(-ENOMEM); ++ /* Cover also the case of null (zero length) input data */ ++ if (src_nents) { ++ mapped_src_nents = dma_map_sg(jrdev, req->src, ++ src_nents, DMA_TO_DEVICE); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(jrdev, "unable to map source\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ } else { ++ mapped_src_nents = 0; + } + +- sgc = dma_map_sg(jrdev, req->dst, dst_nents ? : 1, +- DMA_FROM_DEVICE); +- if (unlikely(!sgc)) { ++ mapped_dst_nents = dma_map_sg(jrdev, req->dst, dst_nents, ++ DMA_FROM_DEVICE); ++ if (unlikely(!mapped_dst_nents)) { + dev_err(jrdev, "unable to map destination\n"); +- dma_unmap_sg(jrdev, req->src, src_nents ? : 1, +- DMA_TO_DEVICE); +- kfree(edesc); ++ dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE); + return ERR_PTR(-ENOMEM); + } + } + ++ sec4_sg_len = mapped_src_nents > 1 ? mapped_src_nents : 0; ++ sec4_sg_len += mapped_dst_nents > 1 ? mapped_dst_nents : 0; ++ sec4_sg_bytes = sec4_sg_len * sizeof(struct sec4_sg_entry); ++ ++ /* allocate space for base edesc and hw desc commands, link tables */ ++ edesc = kzalloc(sizeof(*edesc) + desc_bytes + sec4_sg_bytes, ++ GFP_DMA | flags); ++ if (!edesc) { ++ caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, ++ 0, 0, 0); ++ return ERR_PTR(-ENOMEM); ++ } ++ + edesc->src_nents = src_nents; + edesc->dst_nents = dst_nents; + edesc->sec4_sg = (void *)edesc + sizeof(struct aead_edesc) + + desc_bytes; +- *all_contig_ptr = all_contig; ++ *all_contig_ptr = !(mapped_src_nents > 1); + + sec4_sg_index = 0; +- if (!all_contig) { +- sg_to_sec4_sg_last(req->src, src_nents, +- edesc->sec4_sg + sec4_sg_index, 0); +- sec4_sg_index += src_nents; ++ if (mapped_src_nents > 1) { ++ sg_to_sec4_sg_last(req->src, mapped_src_nents, ++ edesc->sec4_sg + sec4_sg_index, 0); ++ sec4_sg_index += mapped_src_nents; + } +- if (dst_nents) { +- sg_to_sec4_sg_last(req->dst, dst_nents, ++ if (mapped_dst_nents > 1) { ++ sg_to_sec4_sg_last(req->dst, mapped_dst_nents, + edesc->sec4_sg + sec4_sg_index, 0); + } + +@@ -2573,13 +1422,9 @@ static int aead_decrypt(struct aead_request *req) + u32 *desc; + int ret = 0; + +-#ifdef DEBUG +- bool may_sleep = ((req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | +- CRYPTO_TFM_REQ_MAY_SLEEP)) != 0); +- dbg_dump_sg(KERN_ERR, "dec src@"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, req->src, +- req->assoclen + req->cryptlen, 1, may_sleep); +-#endif ++ caam_dump_sg(KERN_ERR, "dec src@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, req->src, ++ req->assoclen + req->cryptlen, 1); + + /* allocate extended descriptor */ + edesc = aead_edesc_alloc(req, AUTHENC_DESC_JOB_IO_LEN, +@@ -2619,51 +1464,80 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request + struct device *jrdev = ctx->jrdev; + gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC; +- int src_nents, dst_nents = 0, sec4_sg_bytes; ++ int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; + struct ablkcipher_edesc *edesc; + dma_addr_t iv_dma = 0; +- bool iv_contig = false; +- int sgc; ++ bool in_contig; + int ivsize = crypto_ablkcipher_ivsize(ablkcipher); +- int sec4_sg_index; ++ int dst_sg_idx, sec4_sg_ents, sec4_sg_bytes; + +- src_nents = sg_count(req->src, req->nbytes); ++ src_nents = sg_nents_for_len(req->src, req->nbytes); ++ if (unlikely(src_nents < 0)) { ++ dev_err(jrdev, "Insufficient bytes (%d) in src S/G\n", ++ req->nbytes); ++ return ERR_PTR(src_nents); ++ } + +- if (req->dst != req->src) +- dst_nents = sg_count(req->dst, req->nbytes); ++ if (req->dst != req->src) { ++ dst_nents = sg_nents_for_len(req->dst, req->nbytes); ++ if (unlikely(dst_nents < 0)) { ++ dev_err(jrdev, "Insufficient bytes (%d) in dst S/G\n", ++ req->nbytes); ++ return ERR_PTR(dst_nents); ++ } ++ } + + if (likely(req->src == req->dst)) { +- sgc = dma_map_sg(jrdev, req->src, src_nents ? : 1, +- DMA_BIDIRECTIONAL); ++ mapped_src_nents = dma_map_sg(jrdev, req->src, src_nents, ++ DMA_BIDIRECTIONAL); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(jrdev, "unable to map source\n"); ++ return ERR_PTR(-ENOMEM); ++ } + } else { +- sgc = dma_map_sg(jrdev, req->src, src_nents ? : 1, +- DMA_TO_DEVICE); +- sgc = dma_map_sg(jrdev, req->dst, dst_nents ? : 1, +- DMA_FROM_DEVICE); ++ mapped_src_nents = dma_map_sg(jrdev, req->src, src_nents, ++ DMA_TO_DEVICE); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(jrdev, "unable to map source\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ mapped_dst_nents = dma_map_sg(jrdev, req->dst, dst_nents, ++ DMA_FROM_DEVICE); ++ if (unlikely(!mapped_dst_nents)) { ++ dev_err(jrdev, "unable to map destination\n"); ++ dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE); ++ return ERR_PTR(-ENOMEM); ++ } + } + + iv_dma = dma_map_single(jrdev, req->info, ivsize, DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, iv_dma)) { + dev_err(jrdev, "unable to map IV\n"); ++ caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, ++ 0, 0, 0); + return ERR_PTR(-ENOMEM); + } + +- /* +- * Check if iv can be contiguous with source and destination. +- * If so, include it. If not, create scatterlist. +- */ +- if (!src_nents && iv_dma + ivsize == sg_dma_address(req->src)) +- iv_contig = true; +- else +- src_nents = src_nents ? : 1; +- sec4_sg_bytes = ((iv_contig ? 0 : 1) + src_nents + dst_nents) * +- sizeof(struct sec4_sg_entry); ++ if (mapped_src_nents == 1 && ++ iv_dma + ivsize == sg_dma_address(req->src)) { ++ in_contig = true; ++ sec4_sg_ents = 0; ++ } else { ++ in_contig = false; ++ sec4_sg_ents = 1 + mapped_src_nents; ++ } ++ dst_sg_idx = sec4_sg_ents; ++ sec4_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0; ++ sec4_sg_bytes = sec4_sg_ents * sizeof(struct sec4_sg_entry); + + /* allocate space for base edesc and hw desc commands, link tables */ + edesc = kzalloc(sizeof(*edesc) + desc_bytes + sec4_sg_bytes, + GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); ++ caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, 0, 0); + return ERR_PTR(-ENOMEM); + } + +@@ -2673,23 +1547,24 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request + edesc->sec4_sg = (void *)edesc + sizeof(struct ablkcipher_edesc) + + desc_bytes; + +- sec4_sg_index = 0; +- if (!iv_contig) { ++ if (!in_contig) { + dma_to_sec4_sg_one(edesc->sec4_sg, iv_dma, ivsize, 0); +- sg_to_sec4_sg_last(req->src, src_nents, ++ sg_to_sec4_sg_last(req->src, mapped_src_nents, + edesc->sec4_sg + 1, 0); +- sec4_sg_index += 1 + src_nents; + } + +- if (dst_nents) { +- sg_to_sec4_sg_last(req->dst, dst_nents, +- edesc->sec4_sg + sec4_sg_index, 0); ++ if (mapped_dst_nents > 1) { ++ sg_to_sec4_sg_last(req->dst, mapped_dst_nents, ++ edesc->sec4_sg + dst_sg_idx, 0); + } + + edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, + sec4_sg_bytes, DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { + dev_err(jrdev, "unable to map S/G table\n"); ++ caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, 0, 0); ++ kfree(edesc); + return ERR_PTR(-ENOMEM); + } + +@@ -2701,7 +1576,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request + sec4_sg_bytes, 1); + #endif + +- *iv_contig_out = iv_contig; ++ *iv_contig_out = in_contig; + return edesc; + } + +@@ -2792,30 +1667,54 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( + struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); + struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); + struct device *jrdev = ctx->jrdev; +- gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | +- CRYPTO_TFM_REQ_MAY_SLEEP)) ? ++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? + GFP_KERNEL : GFP_ATOMIC; +- int src_nents, dst_nents = 0, sec4_sg_bytes; ++ int src_nents, mapped_src_nents, dst_nents, mapped_dst_nents; + struct ablkcipher_edesc *edesc; + dma_addr_t iv_dma = 0; +- bool iv_contig = false; +- int sgc; ++ bool out_contig; + int ivsize = crypto_ablkcipher_ivsize(ablkcipher); +- int sec4_sg_index; ++ int dst_sg_idx, sec4_sg_ents, sec4_sg_bytes; + +- src_nents = sg_count(req->src, req->nbytes); +- +- if (unlikely(req->dst != req->src)) +- dst_nents = sg_count(req->dst, req->nbytes); ++ src_nents = sg_nents_for_len(req->src, req->nbytes); ++ if (unlikely(src_nents < 0)) { ++ dev_err(jrdev, "Insufficient bytes (%d) in src S/G\n", ++ req->nbytes); ++ return ERR_PTR(src_nents); ++ } + + if (likely(req->src == req->dst)) { +- sgc = dma_map_sg(jrdev, req->src, src_nents ? : 1, +- DMA_BIDIRECTIONAL); ++ mapped_src_nents = dma_map_sg(jrdev, req->src, src_nents, ++ DMA_BIDIRECTIONAL); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(jrdev, "unable to map source\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ dst_nents = src_nents; ++ mapped_dst_nents = src_nents; + } else { +- sgc = dma_map_sg(jrdev, req->src, src_nents ? : 1, +- DMA_TO_DEVICE); +- sgc = dma_map_sg(jrdev, req->dst, dst_nents ? : 1, +- DMA_FROM_DEVICE); ++ mapped_src_nents = dma_map_sg(jrdev, req->src, src_nents, ++ DMA_TO_DEVICE); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(jrdev, "unable to map source\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ dst_nents = sg_nents_for_len(req->dst, req->nbytes); ++ if (unlikely(dst_nents < 0)) { ++ dev_err(jrdev, "Insufficient bytes (%d) in dst S/G\n", ++ req->nbytes); ++ return ERR_PTR(dst_nents); ++ } ++ ++ mapped_dst_nents = dma_map_sg(jrdev, req->dst, dst_nents, ++ DMA_FROM_DEVICE); ++ if (unlikely(!mapped_dst_nents)) { ++ dev_err(jrdev, "unable to map destination\n"); ++ dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE); ++ return ERR_PTR(-ENOMEM); ++ } + } + + /* +@@ -2825,21 +1724,29 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( + iv_dma = dma_map_single(jrdev, greq->giv, ivsize, DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, iv_dma)) { + dev_err(jrdev, "unable to map IV\n"); ++ caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, ++ 0, 0, 0); + return ERR_PTR(-ENOMEM); + } + +- if (!dst_nents && iv_dma + ivsize == sg_dma_address(req->dst)) +- iv_contig = true; +- else +- dst_nents = dst_nents ? : 1; +- sec4_sg_bytes = ((iv_contig ? 0 : 1) + src_nents + dst_nents) * +- sizeof(struct sec4_sg_entry); ++ sec4_sg_ents = mapped_src_nents > 1 ? mapped_src_nents : 0; ++ dst_sg_idx = sec4_sg_ents; ++ if (mapped_dst_nents == 1 && ++ iv_dma + ivsize == sg_dma_address(req->dst)) { ++ out_contig = true; ++ } else { ++ out_contig = false; ++ sec4_sg_ents += 1 + mapped_dst_nents; ++ } + + /* allocate space for base edesc and hw desc commands, link tables */ ++ sec4_sg_bytes = sec4_sg_ents * sizeof(struct sec4_sg_entry); + edesc = kzalloc(sizeof(*edesc) + desc_bytes + sec4_sg_bytes, + GFP_DMA | flags); + if (!edesc) { + dev_err(jrdev, "could not allocate extended descriptor\n"); ++ caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, 0, 0); + return ERR_PTR(-ENOMEM); + } + +@@ -2849,24 +1756,24 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( + edesc->sec4_sg = (void *)edesc + sizeof(struct ablkcipher_edesc) + + desc_bytes; + +- sec4_sg_index = 0; +- if (src_nents) { +- sg_to_sec4_sg_last(req->src, src_nents, edesc->sec4_sg, 0); +- sec4_sg_index += src_nents; +- } ++ if (mapped_src_nents > 1) ++ sg_to_sec4_sg_last(req->src, mapped_src_nents, edesc->sec4_sg, ++ 0); + +- if (!iv_contig) { +- dma_to_sec4_sg_one(edesc->sec4_sg + sec4_sg_index, ++ if (!out_contig) { ++ dma_to_sec4_sg_one(edesc->sec4_sg + dst_sg_idx, + iv_dma, ivsize, 0); +- sec4_sg_index += 1; +- sg_to_sec4_sg_last(req->dst, dst_nents, +- edesc->sec4_sg + sec4_sg_index, 0); ++ sg_to_sec4_sg_last(req->dst, mapped_dst_nents, ++ edesc->sec4_sg + dst_sg_idx + 1, 0); + } + + edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, + sec4_sg_bytes, DMA_TO_DEVICE); + if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { + dev_err(jrdev, "unable to map S/G table\n"); ++ caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, 0, 0); ++ kfree(edesc); + return ERR_PTR(-ENOMEM); + } + edesc->iv_dma = iv_dma; +@@ -2878,7 +1785,7 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( + sec4_sg_bytes, 1); + #endif + +- *iv_contig_out = iv_contig; ++ *iv_contig_out = out_contig; + return edesc; + } + +@@ -2889,7 +1796,7 @@ static int ablkcipher_givencrypt(struct skcipher_givcrypt_request *creq) + struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); + struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); + struct device *jrdev = ctx->jrdev; +- bool iv_contig; ++ bool iv_contig = false; + u32 *desc; + int ret = 0; + +@@ -2933,7 +1840,6 @@ struct caam_alg_template { + } template_u; + u32 class1_alg_type; + u32 class2_alg_type; +- u32 alg_op; + }; + + static struct caam_alg_template driver_algs[] = { +@@ -3118,7 +2024,6 @@ static struct caam_aead_alg driver_aeads[] = { + .caam = { + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3140,7 +2045,6 @@ static struct caam_aead_alg driver_aeads[] = { + .caam = { + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3162,7 +2066,6 @@ static struct caam_aead_alg driver_aeads[] = { + .caam = { + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3184,7 +2087,6 @@ static struct caam_aead_alg driver_aeads[] = { + .caam = { + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3206,7 +2108,6 @@ static struct caam_aead_alg driver_aeads[] = { + .caam = { + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3228,7 +2129,6 @@ static struct caam_aead_alg driver_aeads[] = { + .caam = { + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3250,7 +2150,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3273,7 +2172,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, +@@ -3296,7 +2194,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3319,7 +2216,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, +@@ -3342,7 +2238,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3365,7 +2260,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, +@@ -3388,7 +2282,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3411,7 +2304,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, +@@ -3434,7 +2326,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3457,7 +2348,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, +@@ -3480,7 +2370,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3503,7 +2392,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, +@@ -3526,7 +2414,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + } + }, + { +@@ -3549,7 +2436,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + .geniv = true, + } + }, +@@ -3573,7 +2459,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3597,7 +2482,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, +@@ -3621,7 +2505,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3645,7 +2528,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, +@@ -3669,7 +2551,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3693,7 +2574,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, +@@ -3717,7 +2597,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3741,7 +2620,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, +@@ -3765,7 +2643,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3789,7 +2666,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, +@@ -3812,7 +2688,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3835,7 +2710,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, +@@ -3858,7 +2732,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3881,7 +2754,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, +@@ -3904,7 +2776,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3927,7 +2798,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, +@@ -3950,7 +2820,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -3973,7 +2842,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, +@@ -3996,7 +2864,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -4019,7 +2886,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, +@@ -4042,7 +2908,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + }, + }, + { +@@ -4065,7 +2930,6 @@ static struct caam_aead_alg driver_aeads[] = { + .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + .geniv = true, + }, + }, +@@ -4090,7 +2954,6 @@ static struct caam_aead_alg driver_aeads[] = { + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + }, + }, +@@ -4115,7 +2978,6 @@ static struct caam_aead_alg driver_aeads[] = { + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_MD5 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + .geniv = true, + }, +@@ -4141,7 +3003,6 @@ static struct caam_aead_alg driver_aeads[] = { + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + }, + }, +@@ -4166,7 +3027,6 @@ static struct caam_aead_alg driver_aeads[] = { + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA1 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + .geniv = true, + }, +@@ -4192,7 +3052,6 @@ static struct caam_aead_alg driver_aeads[] = { + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + }, + }, +@@ -4217,7 +3076,6 @@ static struct caam_aead_alg driver_aeads[] = { + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA224 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + .geniv = true, + }, +@@ -4243,7 +3101,6 @@ static struct caam_aead_alg driver_aeads[] = { + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + }, + }, +@@ -4268,7 +3125,6 @@ static struct caam_aead_alg driver_aeads[] = { + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA256 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + .geniv = true, + }, +@@ -4294,7 +3150,6 @@ static struct caam_aead_alg driver_aeads[] = { + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + }, + }, +@@ -4319,7 +3174,6 @@ static struct caam_aead_alg driver_aeads[] = { + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA384 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + .geniv = true, + }, +@@ -4345,7 +3199,6 @@ static struct caam_aead_alg driver_aeads[] = { + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + }, + }, +@@ -4370,7 +3223,6 @@ static struct caam_aead_alg driver_aeads[] = { + OP_ALG_AAI_CTR_MOD128, + .class2_alg_type = OP_ALG_ALGSEL_SHA512 | + OP_ALG_AAI_HMAC_PRECOMP, +- .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + .rfc3686 = true, + .geniv = true, + }, +@@ -4385,16 +3237,34 @@ struct caam_crypto_alg { + + static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam) + { ++ dma_addr_t dma_addr; ++ + ctx->jrdev = caam_jr_alloc(); + if (IS_ERR(ctx->jrdev)) { + pr_err("Job Ring Device allocation for transform failed\n"); + return PTR_ERR(ctx->jrdev); + } + ++ dma_addr = dma_map_single_attrs(ctx->jrdev, ctx->sh_desc_enc, ++ offsetof(struct caam_ctx, ++ sh_desc_enc_dma), ++ DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); ++ if (dma_mapping_error(ctx->jrdev, dma_addr)) { ++ dev_err(ctx->jrdev, "unable to map key, shared descriptors\n"); ++ caam_jr_free(ctx->jrdev); ++ return -ENOMEM; ++ } ++ ++ ctx->sh_desc_enc_dma = dma_addr; ++ ctx->sh_desc_dec_dma = dma_addr + offsetof(struct caam_ctx, ++ sh_desc_dec); ++ ctx->sh_desc_givenc_dma = dma_addr + offsetof(struct caam_ctx, ++ sh_desc_givenc); ++ ctx->key_dma = dma_addr + offsetof(struct caam_ctx, key); ++ + /* copy descriptor header template value */ +- ctx->class1_alg_type = OP_TYPE_CLASS1_ALG | caam->class1_alg_type; +- ctx->class2_alg_type = OP_TYPE_CLASS2_ALG | caam->class2_alg_type; +- ctx->alg_op = OP_TYPE_CLASS2_ALG | caam->alg_op; ++ ctx->cdata.algtype = OP_TYPE_CLASS1_ALG | caam->class1_alg_type; ++ ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam->class2_alg_type; + + return 0; + } +@@ -4421,25 +3291,9 @@ static int caam_aead_init(struct crypto_aead *tfm) + + static void caam_exit_common(struct caam_ctx *ctx) + { +- if (ctx->sh_desc_enc_dma && +- !dma_mapping_error(ctx->jrdev, ctx->sh_desc_enc_dma)) +- dma_unmap_single(ctx->jrdev, ctx->sh_desc_enc_dma, +- desc_bytes(ctx->sh_desc_enc), DMA_TO_DEVICE); +- if (ctx->sh_desc_dec_dma && +- !dma_mapping_error(ctx->jrdev, ctx->sh_desc_dec_dma)) +- dma_unmap_single(ctx->jrdev, ctx->sh_desc_dec_dma, +- desc_bytes(ctx->sh_desc_dec), DMA_TO_DEVICE); +- if (ctx->sh_desc_givenc_dma && +- !dma_mapping_error(ctx->jrdev, ctx->sh_desc_givenc_dma)) +- dma_unmap_single(ctx->jrdev, ctx->sh_desc_givenc_dma, +- desc_bytes(ctx->sh_desc_givenc), +- DMA_TO_DEVICE); +- if (ctx->key_dma && +- !dma_mapping_error(ctx->jrdev, ctx->key_dma)) +- dma_unmap_single(ctx->jrdev, ctx->key_dma, +- ctx->enckeylen + ctx->split_key_pad_len, +- DMA_TO_DEVICE); +- ++ dma_unmap_single_attrs(ctx->jrdev, ctx->sh_desc_enc_dma, ++ offsetof(struct caam_ctx, sh_desc_enc_dma), ++ DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); + caam_jr_free(ctx->jrdev); + } + +@@ -4515,7 +3369,6 @@ static struct caam_crypto_alg *caam_alg_alloc(struct caam_alg_template + + t_alg->caam.class1_alg_type = template->class1_alg_type; + t_alg->caam.class2_alg_type = template->class2_alg_type; +- t_alg->caam.alg_op = template->alg_op; + + return t_alg; + } +diff --git a/drivers/crypto/caam/caamalg_desc.c b/drivers/crypto/caam/caamalg_desc.c +new file mode 100644 +index 00000000..d162120a +--- /dev/null ++++ b/drivers/crypto/caam/caamalg_desc.c +@@ -0,0 +1,1913 @@ ++/* ++ * Shared descriptors for aead, ablkcipher algorithms ++ * ++ * Copyright 2016 NXP ++ */ ++ ++#include "compat.h" ++#include "desc_constr.h" ++#include "caamalg_desc.h" ++ ++/* ++ * For aead functions, read payload and write payload, ++ * both of which are specified in req->src and req->dst ++ */ ++static inline void aead_append_src_dst(u32 *desc, u32 msg_type) ++{ ++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | ++ KEY_VLF | msg_type | FIFOLD_TYPE_LASTBOTH); ++} ++ ++/* Set DK bit in class 1 operation if shared */ ++static inline void append_dec_op1(u32 *desc, u32 type) ++{ ++ u32 *jump_cmd, *uncond_jump_cmd; ++ ++ /* DK bit is valid only for AES */ ++ if ((type & OP_ALG_ALGSEL_MASK) != OP_ALG_ALGSEL_AES) { ++ append_operation(desc, type | OP_ALG_AS_INITFINAL | ++ OP_ALG_DECRYPT); ++ return; ++ } ++ ++ jump_cmd = append_jump(desc, JUMP_TEST_ALL | JUMP_COND_SHRD); ++ append_operation(desc, type | OP_ALG_AS_INITFINAL | ++ OP_ALG_DECRYPT); ++ uncond_jump_cmd = append_jump(desc, JUMP_TEST_ALL); ++ set_jump_tgt_here(desc, jump_cmd); ++ append_operation(desc, type | OP_ALG_AS_INITFINAL | ++ OP_ALG_DECRYPT | OP_ALG_AAI_DK); ++ set_jump_tgt_here(desc, uncond_jump_cmd); ++} ++ ++/** ++ * cnstr_shdsc_aead_null_encap - IPSec ESP encapsulation shared descriptor ++ * (non-protocol) with no (null) encryption. ++ * @desc: pointer to buffer used for descriptor construction ++ * @adata: pointer to authentication transform definitions. Note that since a ++ * split key is to be used, the size of the split key itself is ++ * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, ++ * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP. ++ * @icvsize: integrity check value (ICV) size (truncated or full) ++ * ++ * Note: Requires an MDHA split key. ++ */ ++void cnstr_shdsc_aead_null_encap(u32 * const desc, struct alginfo *adata, ++ unsigned int icvsize) ++{ ++ u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd; ++ ++ init_sh_desc(desc, HDR_SHARE_SERIAL); ++ ++ /* Skip if already shared */ ++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); ++ if (adata->key_inline) ++ append_key_as_imm(desc, adata->key_virt, adata->keylen_pad, ++ adata->keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT | ++ KEY_ENC); ++ else ++ append_key(desc, adata->key_dma, adata->keylen, CLASS_2 | ++ KEY_DEST_MDHA_SPLIT | KEY_ENC); ++ set_jump_tgt_here(desc, key_jump_cmd); ++ ++ /* assoclen + cryptlen = seqinlen */ ++ append_math_sub(desc, REG3, SEQINLEN, REG0, CAAM_CMD_SZ); ++ ++ /* Prepare to read and write cryptlen + assoclen bytes */ ++ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); ++ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); ++ ++ /* ++ * MOVE_LEN opcode is not available in all SEC HW revisions, ++ * thus need to do some magic, i.e. self-patch the descriptor ++ * buffer. ++ */ ++ read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | ++ MOVE_DEST_MATH3 | ++ (0x6 << MOVE_LEN_SHIFT)); ++ write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | ++ MOVE_DEST_DESCBUF | ++ MOVE_WAITCOMP | ++ (0x8 << MOVE_LEN_SHIFT)); ++ ++ /* Class 2 operation */ ++ append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_ENCRYPT); ++ ++ /* Read and write cryptlen bytes */ ++ aead_append_src_dst(desc, FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); ++ ++ set_move_tgt_here(desc, read_move_cmd); ++ set_move_tgt_here(desc, write_move_cmd); ++ append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); ++ append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO | ++ MOVE_AUX_LS); ++ ++ /* Write ICV */ ++ append_seq_store(desc, icvsize, LDST_CLASS_2_CCB | ++ LDST_SRCDST_BYTE_CONTEXT); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, ++ "aead null enc shdesc@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_aead_null_encap); ++ ++/** ++ * cnstr_shdsc_aead_null_decap - IPSec ESP decapsulation shared descriptor ++ * (non-protocol) with no (null) decryption. ++ * @desc: pointer to buffer used for descriptor construction ++ * @adata: pointer to authentication transform definitions. Note that since a ++ * split key is to be used, the size of the split key itself is ++ * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, ++ * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP. ++ * @icvsize: integrity check value (ICV) size (truncated or full) ++ * ++ * Note: Requires an MDHA split key. ++ */ ++void cnstr_shdsc_aead_null_decap(u32 * const desc, struct alginfo *adata, ++ unsigned int icvsize) ++{ ++ u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd, *jump_cmd; ++ ++ init_sh_desc(desc, HDR_SHARE_SERIAL); ++ ++ /* Skip if already shared */ ++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); ++ if (adata->key_inline) ++ append_key_as_imm(desc, adata->key_virt, adata->keylen_pad, ++ adata->keylen, CLASS_2 | ++ KEY_DEST_MDHA_SPLIT | KEY_ENC); ++ else ++ append_key(desc, adata->key_dma, adata->keylen, CLASS_2 | ++ KEY_DEST_MDHA_SPLIT | KEY_ENC); ++ set_jump_tgt_here(desc, key_jump_cmd); ++ ++ /* Class 2 operation */ ++ append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_DECRYPT | OP_ALG_ICV_ON); ++ ++ /* assoclen + cryptlen = seqoutlen */ ++ append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ); ++ ++ /* Prepare to read and write cryptlen + assoclen bytes */ ++ append_math_add(desc, VARSEQINLEN, ZERO, REG2, CAAM_CMD_SZ); ++ append_math_add(desc, VARSEQOUTLEN, ZERO, REG2, CAAM_CMD_SZ); ++ ++ /* ++ * MOVE_LEN opcode is not available in all SEC HW revisions, ++ * thus need to do some magic, i.e. self-patch the descriptor ++ * buffer. ++ */ ++ read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | ++ MOVE_DEST_MATH2 | ++ (0x6 << MOVE_LEN_SHIFT)); ++ write_move_cmd = append_move(desc, MOVE_SRC_MATH2 | ++ MOVE_DEST_DESCBUF | ++ MOVE_WAITCOMP | ++ (0x8 << MOVE_LEN_SHIFT)); ++ ++ /* Read and write cryptlen bytes */ ++ aead_append_src_dst(desc, FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); ++ ++ /* ++ * Insert a NOP here, since we need at least 4 instructions between ++ * code patching the descriptor buffer and the location being patched. ++ */ ++ jump_cmd = append_jump(desc, JUMP_TEST_ALL); ++ set_jump_tgt_here(desc, jump_cmd); ++ ++ set_move_tgt_here(desc, read_move_cmd); ++ set_move_tgt_here(desc, write_move_cmd); ++ append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); ++ append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO | ++ MOVE_AUX_LS); ++ append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); ++ ++ /* Load ICV */ ++ append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS2 | ++ FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, ++ "aead null dec shdesc@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_aead_null_decap); ++ ++static void init_sh_desc_key_aead(u32 * const desc, ++ struct alginfo * const cdata, ++ struct alginfo * const adata, ++ const bool is_rfc3686, u32 *nonce) ++{ ++ u32 *key_jump_cmd; ++ unsigned int enckeylen = cdata->keylen; ++ ++ /* Note: Context registers are saved. */ ++ init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); ++ ++ /* Skip if already shared */ ++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); ++ ++ /* ++ * RFC3686 specific: ++ * | key = {AUTH_KEY, ENC_KEY, NONCE} ++ * | enckeylen = encryption key size + nonce size ++ */ ++ if (is_rfc3686) ++ enckeylen -= CTR_RFC3686_NONCE_SIZE; ++ ++ if (adata->key_inline) ++ append_key_as_imm(desc, adata->key_virt, adata->keylen_pad, ++ adata->keylen, CLASS_2 | ++ KEY_DEST_MDHA_SPLIT | KEY_ENC); ++ else ++ append_key(desc, adata->key_dma, adata->keylen, CLASS_2 | ++ KEY_DEST_MDHA_SPLIT | KEY_ENC); ++ ++ if (cdata->key_inline) ++ append_key_as_imm(desc, cdata->key_virt, enckeylen, ++ enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); ++ else ++ append_key(desc, cdata->key_dma, enckeylen, CLASS_1 | ++ KEY_DEST_CLASS_REG); ++ ++ /* Load Counter into CONTEXT1 reg */ ++ if (is_rfc3686) { ++ append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, ++ LDST_CLASS_IND_CCB | ++ LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); ++ append_move(desc, ++ MOVE_SRC_OUTFIFO | ++ MOVE_DEST_CLASS1CTX | ++ (16 << MOVE_OFFSET_SHIFT) | ++ (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); ++ } ++ ++ set_jump_tgt_here(desc, key_jump_cmd); ++} ++ ++/** ++ * cnstr_shdsc_aead_encap - IPSec ESP encapsulation shared descriptor ++ * (non-protocol). ++ * @desc: pointer to buffer used for descriptor construction ++ * @cdata: pointer to block cipher transform definitions ++ * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed ++ * with OP_ALG_AAI_CBC or OP_ALG_AAI_CTR_MOD128. ++ * @adata: pointer to authentication transform definitions. Note that since a ++ * split key is to be used, the size of the split key itself is ++ * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, ++ * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP. ++ * @ivsize: initialization vector size ++ * @icvsize: integrity check value (ICV) size (truncated or full) ++ * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template ++ * @nonce: pointer to rfc3686 nonce ++ * @ctx1_iv_off: IV offset in CONTEXT1 register ++ * @is_qi: true when called from caam/qi ++ * ++ * Note: Requires an MDHA split key. ++ */ ++void cnstr_shdsc_aead_encap(u32 * const desc, struct alginfo *cdata, ++ struct alginfo *adata, unsigned int ivsize, ++ unsigned int icvsize, const bool is_rfc3686, ++ u32 *nonce, const u32 ctx1_iv_off, const bool is_qi) ++{ ++ /* Note: Context registers are saved. */ ++ init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce); ++ ++ /* Class 2 operation */ ++ append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_ENCRYPT); ++ ++ if (is_qi) { ++ u32 *wait_load_cmd; ++ ++ /* REG3 = assoclen */ ++ append_seq_load(desc, 4, LDST_CLASS_DECO | ++ LDST_SRCDST_WORD_DECO_MATH3 | ++ (4 << LDST_OFFSET_SHIFT)); ++ ++ wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_CALM | JUMP_COND_NCP | ++ JUMP_COND_NOP | JUMP_COND_NIP | ++ JUMP_COND_NIFP); ++ set_jump_tgt_here(desc, wait_load_cmd); ++ ++ append_seq_load(desc, ivsize, LDST_CLASS_1_CCB | ++ LDST_SRCDST_BYTE_CONTEXT | ++ (ctx1_iv_off << LDST_OFFSET_SHIFT)); ++ } ++ ++ /* Read and write assoclen bytes */ ++ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); ++ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); ++ ++ /* Skip assoc data */ ++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); ++ ++ /* read assoc before reading payload */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | ++ FIFOLDST_VLF); ++ ++ /* Load Counter into CONTEXT1 reg */ ++ if (is_rfc3686) ++ append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | ++ LDST_SRCDST_BYTE_CONTEXT | ++ ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << ++ LDST_OFFSET_SHIFT)); ++ ++ /* Class 1 operation */ ++ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_ENCRYPT); ++ ++ /* Read and write cryptlen bytes */ ++ append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); ++ append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); ++ aead_append_src_dst(desc, FIFOLD_TYPE_MSG1OUT2); ++ ++ /* Write ICV */ ++ append_seq_store(desc, icvsize, LDST_CLASS_2_CCB | ++ LDST_SRCDST_BYTE_CONTEXT); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "aead enc shdesc@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_aead_encap); ++ ++/** ++ * cnstr_shdsc_aead_decap - IPSec ESP decapsulation shared descriptor ++ * (non-protocol). ++ * @desc: pointer to buffer used for descriptor construction ++ * @cdata: pointer to block cipher transform definitions ++ * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed ++ * with OP_ALG_AAI_CBC or OP_ALG_AAI_CTR_MOD128. ++ * @adata: pointer to authentication transform definitions. Note that since a ++ * split key is to be used, the size of the split key itself is ++ * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, ++ * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP. ++ * @ivsize: initialization vector size ++ * @icvsize: integrity check value (ICV) size (truncated or full) ++ * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template ++ * @nonce: pointer to rfc3686 nonce ++ * @ctx1_iv_off: IV offset in CONTEXT1 register ++ * @is_qi: true when called from caam/qi ++ * ++ * Note: Requires an MDHA split key. ++ */ ++void cnstr_shdsc_aead_decap(u32 * const desc, struct alginfo *cdata, ++ struct alginfo *adata, unsigned int ivsize, ++ unsigned int icvsize, const bool geniv, ++ const bool is_rfc3686, u32 *nonce, ++ const u32 ctx1_iv_off, const bool is_qi) ++{ ++ /* Note: Context registers are saved. */ ++ init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce); ++ ++ /* Class 2 operation */ ++ append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_DECRYPT | OP_ALG_ICV_ON); ++ ++ if (is_qi) { ++ u32 *wait_load_cmd; ++ ++ /* REG3 = assoclen */ ++ append_seq_load(desc, 4, LDST_CLASS_DECO | ++ LDST_SRCDST_WORD_DECO_MATH3 | ++ (4 << LDST_OFFSET_SHIFT)); ++ ++ wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_CALM | JUMP_COND_NCP | ++ JUMP_COND_NOP | JUMP_COND_NIP | ++ JUMP_COND_NIFP); ++ set_jump_tgt_here(desc, wait_load_cmd); ++ ++ if (!geniv) ++ append_seq_load(desc, ivsize, LDST_CLASS_1_CCB | ++ LDST_SRCDST_BYTE_CONTEXT | ++ (ctx1_iv_off << LDST_OFFSET_SHIFT)); ++ } ++ ++ /* Read and write assoclen bytes */ ++ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); ++ if (geniv) ++ append_math_add_imm_u32(desc, VARSEQOUTLEN, REG3, IMM, ivsize); ++ else ++ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); ++ ++ /* Skip assoc data */ ++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); ++ ++ /* read assoc before reading payload */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | ++ KEY_VLF); ++ ++ if (geniv) { ++ append_seq_load(desc, ivsize, LDST_CLASS_1_CCB | ++ LDST_SRCDST_BYTE_CONTEXT | ++ (ctx1_iv_off << LDST_OFFSET_SHIFT)); ++ append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_CLASS2INFIFO | ++ (ctx1_iv_off << MOVE_OFFSET_SHIFT) | ivsize); ++ } ++ ++ /* Load Counter into CONTEXT1 reg */ ++ if (is_rfc3686) ++ append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | ++ LDST_SRCDST_BYTE_CONTEXT | ++ ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << ++ LDST_OFFSET_SHIFT)); ++ ++ /* Choose operation */ ++ if (ctx1_iv_off) ++ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_DECRYPT); ++ else ++ append_dec_op1(desc, cdata->algtype); ++ ++ /* Read and write cryptlen bytes */ ++ append_math_add(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); ++ append_math_add(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); ++ aead_append_src_dst(desc, FIFOLD_TYPE_MSG); ++ ++ /* Load ICV */ ++ append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS2 | ++ FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "aead dec shdesc@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_aead_decap); ++ ++/** ++ * cnstr_shdsc_aead_givencap - IPSec ESP encapsulation shared descriptor ++ * (non-protocol) with HW-generated initialization ++ * vector. ++ * @desc: pointer to buffer used for descriptor construction ++ * @cdata: pointer to block cipher transform definitions ++ * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed ++ * with OP_ALG_AAI_CBC or OP_ALG_AAI_CTR_MOD128. ++ * @adata: pointer to authentication transform definitions. Note that since a ++ * split key is to be used, the size of the split key itself is ++ * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, ++ * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP. ++ * @ivsize: initialization vector size ++ * @icvsize: integrity check value (ICV) size (truncated or full) ++ * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template ++ * @nonce: pointer to rfc3686 nonce ++ * @ctx1_iv_off: IV offset in CONTEXT1 register ++ * @is_qi: true when called from caam/qi ++ * ++ * Note: Requires an MDHA split key. ++ */ ++void cnstr_shdsc_aead_givencap(u32 * const desc, struct alginfo *cdata, ++ struct alginfo *adata, unsigned int ivsize, ++ unsigned int icvsize, const bool is_rfc3686, ++ u32 *nonce, const u32 ctx1_iv_off, ++ const bool is_qi) ++{ ++ u32 geniv, moveiv; ++ ++ /* Note: Context registers are saved. */ ++ init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce); ++ ++ if (is_qi) { ++ u32 *wait_load_cmd; ++ ++ /* REG3 = assoclen */ ++ append_seq_load(desc, 4, LDST_CLASS_DECO | ++ LDST_SRCDST_WORD_DECO_MATH3 | ++ (4 << LDST_OFFSET_SHIFT)); ++ ++ wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_CALM | JUMP_COND_NCP | ++ JUMP_COND_NOP | JUMP_COND_NIP | ++ JUMP_COND_NIFP); ++ set_jump_tgt_here(desc, wait_load_cmd); ++ } ++ ++ if (is_rfc3686) { ++ if (is_qi) ++ append_seq_load(desc, ivsize, LDST_CLASS_1_CCB | ++ LDST_SRCDST_BYTE_CONTEXT | ++ (ctx1_iv_off << LDST_OFFSET_SHIFT)); ++ ++ goto copy_iv; ++ } ++ ++ /* Generate IV */ ++ geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO | ++ NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 | ++ NFIFOENTRY_PTYPE_RND | (ivsize << NFIFOENTRY_DLEN_SHIFT); ++ append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB | ++ LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); ++ append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); ++ append_move(desc, MOVE_WAITCOMP | ++ MOVE_SRC_INFIFO | MOVE_DEST_CLASS1CTX | ++ (ctx1_iv_off << MOVE_OFFSET_SHIFT) | ++ (ivsize << MOVE_LEN_SHIFT)); ++ append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); ++ ++copy_iv: ++ /* Copy IV to class 1 context */ ++ append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_OUTFIFO | ++ (ctx1_iv_off << MOVE_OFFSET_SHIFT) | ++ (ivsize << MOVE_LEN_SHIFT)); ++ ++ /* Return to encryption */ ++ append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_ENCRYPT); ++ ++ /* Read and write assoclen bytes */ ++ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); ++ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); ++ ++ /* Skip assoc data */ ++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); ++ ++ /* read assoc before reading payload */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | ++ KEY_VLF); ++ ++ /* Copy iv from outfifo to class 2 fifo */ ++ moveiv = NFIFOENTRY_STYPE_OFIFO | NFIFOENTRY_DEST_CLASS2 | ++ NFIFOENTRY_DTYPE_MSG | (ivsize << NFIFOENTRY_DLEN_SHIFT); ++ append_load_imm_u32(desc, moveiv, LDST_CLASS_IND_CCB | ++ LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); ++ append_load_imm_u32(desc, ivsize, LDST_CLASS_2_CCB | ++ LDST_SRCDST_WORD_DATASZ_REG | LDST_IMM); ++ ++ /* Load Counter into CONTEXT1 reg */ ++ if (is_rfc3686) ++ append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | ++ LDST_SRCDST_BYTE_CONTEXT | ++ ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << ++ LDST_OFFSET_SHIFT)); ++ ++ /* Class 1 operation */ ++ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_ENCRYPT); ++ ++ /* Will write ivsize + cryptlen */ ++ append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); ++ ++ /* Not need to reload iv */ ++ append_seq_fifo_load(desc, ivsize, ++ FIFOLD_CLASS_SKIP); ++ ++ /* Will read cryptlen */ ++ append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | KEY_VLF | ++ FIFOLD_TYPE_MSG1OUT2 | FIFOLD_TYPE_LASTBOTH); ++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); ++ ++ /* Write ICV */ ++ append_seq_store(desc, icvsize, LDST_CLASS_2_CCB | ++ LDST_SRCDST_BYTE_CONTEXT); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, ++ "aead givenc shdesc@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_aead_givencap); ++ ++/** ++ * cnstr_shdsc_tls_encap - tls encapsulation shared descriptor ++ * @desc: pointer to buffer used for descriptor construction ++ * @cdata: pointer to block cipher transform definitions ++ * Valid algorithm values - one of OP_ALG_ALGSEL_AES ANDed ++ * with OP_ALG_AAI_CBC ++ * @adata: pointer to authentication transform definitions. Note that since a ++ * split key is to be used, the size of the split key itself is ++ * specified. Valid algorithm values OP_ALG_ALGSEL_SHA1 ANDed with ++ * OP_ALG_AAI_HMAC_PRECOMP. ++ * @assoclen: associated data length ++ * @ivsize: initialization vector size ++ * @authsize: authentication data size ++ * @blocksize: block cipher size ++ */ ++void cnstr_shdsc_tls_encap(u32 * const desc, struct alginfo *cdata, ++ struct alginfo *adata, unsigned int assoclen, ++ unsigned int ivsize, unsigned int authsize, ++ unsigned int blocksize) ++{ ++ u32 *key_jump_cmd, *zero_payload_jump_cmd; ++ u32 genpad, idx_ld_datasz, idx_ld_pad, stidx; ++ ++ /* ++ * Compute the index (in bytes) for the LOAD with destination of ++ * Class 1 Data Size Register and for the LOAD that generates padding ++ */ ++ if (adata->key_inline) { ++ idx_ld_datasz = DESC_TLS10_ENC_LEN + adata->keylen_pad + ++ cdata->keylen - 4 * CAAM_CMD_SZ; ++ idx_ld_pad = DESC_TLS10_ENC_LEN + adata->keylen_pad + ++ cdata->keylen - 2 * CAAM_CMD_SZ; ++ } else { ++ idx_ld_datasz = DESC_TLS10_ENC_LEN + 2 * CAAM_PTR_SZ - ++ 4 * CAAM_CMD_SZ; ++ idx_ld_pad = DESC_TLS10_ENC_LEN + 2 * CAAM_PTR_SZ - ++ 2 * CAAM_CMD_SZ; ++ } ++ ++ stidx = 1 << HDR_START_IDX_SHIFT; ++ init_sh_desc(desc, HDR_SHARE_SERIAL | stidx); ++ ++ /* skip key loading if they are loaded due to sharing */ ++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); ++ ++ if (adata->key_inline) ++ append_key_as_imm(desc, adata->key_virt, adata->keylen_pad, ++ adata->keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT | ++ KEY_ENC); ++ else ++ append_key(desc, adata->key_dma, adata->keylen, CLASS_2 | ++ KEY_DEST_MDHA_SPLIT | KEY_ENC); ++ ++ if (cdata->key_inline) ++ append_key_as_imm(desc, cdata->key_virt, cdata->keylen, ++ cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); ++ else ++ append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 | ++ KEY_DEST_CLASS_REG); ++ ++ set_jump_tgt_here(desc, key_jump_cmd); ++ ++ /* class 2 operation */ ++ append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_ENCRYPT); ++ /* class 1 operation */ ++ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_ENCRYPT); ++ ++ /* payloadlen = input data length - (assoclen + ivlen) */ ++ append_math_sub_imm_u32(desc, REG0, SEQINLEN, IMM, assoclen + ivsize); ++ ++ /* math1 = payloadlen + icvlen */ ++ append_math_add_imm_u32(desc, REG1, REG0, IMM, authsize); ++ ++ /* padlen = block_size - math1 % block_size */ ++ append_math_and_imm_u32(desc, REG3, REG1, IMM, blocksize - 1); ++ append_math_sub_imm_u32(desc, REG2, IMM, REG3, blocksize); ++ ++ /* cryptlen = payloadlen + icvlen + padlen */ ++ append_math_add(desc, VARSEQOUTLEN, REG1, REG2, 4); ++ ++ /* ++ * update immediate data with the padding length value ++ * for the LOAD in the class 1 data size register. ++ */ ++ append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH2 | ++ (idx_ld_datasz << MOVE_OFFSET_SHIFT) | 7); ++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH2 | MOVE_DEST_DESCBUF | ++ (idx_ld_datasz << MOVE_OFFSET_SHIFT) | 8); ++ ++ /* overwrite PL field for the padding iNFO FIFO entry */ ++ append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH2 | ++ (idx_ld_pad << MOVE_OFFSET_SHIFT) | 7); ++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH2 | MOVE_DEST_DESCBUF | ++ (idx_ld_pad << MOVE_OFFSET_SHIFT) | 8); ++ ++ /* store encrypted payload, icv and padding */ ++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | LDST_VLF); ++ ++ /* if payload length is zero, jump to zero-payload commands */ ++ append_math_add(desc, VARSEQINLEN, ZERO, REG0, 4); ++ zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL | ++ JUMP_COND_MATH_Z); ++ ++ /* load iv in context1 */ ++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_WORD_CLASS_CTX | ++ LDST_CLASS_1_CCB | ivsize); ++ ++ /* read assoc for authentication */ ++ append_seq_fifo_load(desc, assoclen, FIFOLD_CLASS_CLASS2 | ++ FIFOLD_TYPE_MSG); ++ /* insnoop payload */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | FIFOLD_TYPE_MSG | ++ FIFOLD_TYPE_LAST2 | FIFOLDST_VLF); ++ ++ /* jump the zero-payload commands */ ++ append_jump(desc, JUMP_TEST_ALL | 3); ++ ++ /* zero-payload commands */ ++ set_jump_tgt_here(desc, zero_payload_jump_cmd); ++ ++ /* load iv in context1 */ ++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_WORD_CLASS_CTX | ++ LDST_CLASS_1_CCB | ivsize); ++ ++ /* assoc data is the only data for authentication */ ++ append_seq_fifo_load(desc, assoclen, FIFOLD_CLASS_CLASS2 | ++ FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST2); ++ ++ /* send icv to encryption */ ++ append_move(desc, MOVE_SRC_CLASS2CTX | MOVE_DEST_CLASS1INFIFO | ++ authsize); ++ ++ /* update class 1 data size register with padding length */ ++ append_load_imm_u32(desc, 0, LDST_CLASS_1_CCB | ++ LDST_SRCDST_WORD_DATASZ_REG | LDST_IMM); ++ ++ /* generate padding and send it to encryption */ ++ genpad = NFIFOENTRY_DEST_CLASS1 | NFIFOENTRY_LC1 | NFIFOENTRY_FC1 | ++ NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_PTYPE_N; ++ append_load_imm_u32(desc, genpad, LDST_CLASS_IND_CCB | ++ LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "tls enc shdesc@" __stringify(__LINE__) ": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, ++ desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_tls_encap); ++ ++/** ++ * cnstr_shdsc_tls_decap - tls decapsulation shared descriptor ++ * @desc: pointer to buffer used for descriptor construction ++ * @cdata: pointer to block cipher transform definitions ++ * Valid algorithm values - one of OP_ALG_ALGSEL_AES ANDed ++ * with OP_ALG_AAI_CBC ++ * @adata: pointer to authentication transform definitions. Note that since a ++ * split key is to be used, the size of the split key itself is ++ * specified. Valid algorithm values OP_ALG_ALGSEL_ SHA1 ANDed with ++ * OP_ALG_AAI_HMAC_PRECOMP. ++ * @assoclen: associated data length ++ * @ivsize: initialization vector size ++ * @authsize: authentication data size ++ * @blocksize: block cipher size ++ */ ++void cnstr_shdsc_tls_decap(u32 * const desc, struct alginfo *cdata, ++ struct alginfo *adata, unsigned int assoclen, ++ unsigned int ivsize, unsigned int authsize, ++ unsigned int blocksize) ++{ ++ u32 stidx, jumpback; ++ u32 *key_jump_cmd, *zero_payload_jump_cmd, *skip_zero_jump_cmd; ++ /* ++ * Pointer Size bool determines the size of address pointers. ++ * false - Pointers fit in one 32-bit word. ++ * true - Pointers fit in two 32-bit words. ++ */ ++ static const bool ps = (CAAM_PTR_SZ != CAAM_CMD_SZ); ++ ++ stidx = 1 << HDR_START_IDX_SHIFT; ++ init_sh_desc(desc, HDR_SHARE_SERIAL | stidx); ++ ++ /* skip key loading if they are loaded due to sharing */ ++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); ++ ++ append_key(desc, adata->key_dma, adata->keylen, CLASS_2 | ++ KEY_DEST_MDHA_SPLIT | KEY_ENC); ++ ++ append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 | ++ KEY_DEST_CLASS_REG); ++ ++ set_jump_tgt_here(desc, key_jump_cmd); ++ ++ /* class 2 operation */ ++ append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_DECRYPT | OP_ALG_ICV_ON); ++ /* class 1 operation */ ++ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_DECRYPT); ++ ++ /* VSIL = input data length - 2 * block_size */ ++ append_math_sub_imm_u32(desc, VARSEQINLEN, SEQINLEN, IMM, 2 * ++ blocksize); ++ ++ /* ++ * payloadlen + icvlen + padlen = input data length - (assoclen + ++ * ivsize) ++ */ ++ append_math_sub_imm_u32(desc, REG3, SEQINLEN, IMM, assoclen + ivsize); ++ ++ /* skip data to the last but one cipher block */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_SKIP | LDST_VLF); ++ ++ /* load iv for the last cipher block */ ++ append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_WORD_CLASS_CTX | ++ LDST_CLASS_1_CCB | ivsize); ++ ++ /* read last cipher block */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_MSG | ++ FIFOLD_TYPE_LAST1 | blocksize); ++ ++ /* move decrypted block into math0 and math1 */ ++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_OUTFIFO | MOVE_DEST_MATH0 | ++ blocksize); ++ ++ /* reset AES CHA */ ++ append_load_imm_u32(desc, CCTRL_RESET_CHA_AESA, LDST_CLASS_IND_CCB | ++ LDST_SRCDST_WORD_CHACTRL | LDST_IMM); ++ ++ /* rewind input sequence */ ++ append_seq_in_ptr_intlen(desc, 0, 65535, SQIN_RTO); ++ ++ /* key1 is in decryption form */ ++ append_operation(desc, cdata->algtype | OP_ALG_AAI_DK | ++ OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT); ++ ++ /* load iv in context1 */ ++ append_cmd(desc, CMD_SEQ_LOAD | LDST_CLASS_1_CCB | ++ LDST_SRCDST_WORD_CLASS_CTX | ivsize); ++ ++ /* read sequence number */ ++ append_seq_fifo_load(desc, 8, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG); ++ /* load Type, Version and Len fields in math0 */ ++ append_cmd(desc, CMD_SEQ_LOAD | LDST_CLASS_DECO | ++ LDST_SRCDST_WORD_DECO_MATH0 | (3 << LDST_OFFSET_SHIFT) | 5); ++ ++ /* compute (padlen - 1) */ ++ append_math_and_imm_u64(desc, REG1, REG1, IMM, 255); ++ ++ /* math2 = icvlen + (padlen - 1) + 1 */ ++ append_math_add_imm_u32(desc, REG2, REG1, IMM, authsize + 1); ++ ++ append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM | 1); ++ ++ /* VSOL = payloadlen + icvlen + padlen */ ++ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, 4); ++ ++#ifdef __LITTLE_ENDIAN ++ append_moveb(desc, MOVE_WAITCOMP | ++ MOVE_SRC_MATH0 | MOVE_DEST_MATH0 | 8); ++#endif ++ /* update Len field */ ++ append_math_sub(desc, REG0, REG0, REG2, 8); ++ ++ /* store decrypted payload, icv and padding */ ++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | LDST_VLF); ++ ++ /* VSIL = (payloadlen + icvlen + padlen) - (icvlen + padlen)*/ ++ append_math_sub(desc, VARSEQINLEN, REG3, REG2, 4); ++ ++ zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL | ++ JUMP_COND_MATH_Z); ++ ++ /* send Type, Version and Len(pre ICV) fields to authentication */ ++ append_move(desc, MOVE_WAITCOMP | ++ MOVE_SRC_MATH0 | MOVE_DEST_CLASS2INFIFO | ++ (3 << MOVE_OFFSET_SHIFT) | 5); ++ ++ /* outsnooping payload */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | ++ FIFOLD_TYPE_MSG1OUT2 | FIFOLD_TYPE_LAST2 | ++ FIFOLDST_VLF); ++ skip_zero_jump_cmd = append_jump(desc, JUMP_TEST_ALL | 2); ++ ++ set_jump_tgt_here(desc, zero_payload_jump_cmd); ++ /* send Type, Version and Len(pre ICV) fields to authentication */ ++ append_move(desc, MOVE_WAITCOMP | MOVE_AUX_LS | ++ MOVE_SRC_MATH0 | MOVE_DEST_CLASS2INFIFO | ++ (3 << MOVE_OFFSET_SHIFT) | 5); ++ ++ set_jump_tgt_here(desc, skip_zero_jump_cmd); ++ append_math_add(desc, VARSEQINLEN, ZERO, REG2, 4); ++ ++ /* load icvlen and padlen */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_MSG | ++ FIFOLD_TYPE_LAST1 | FIFOLDST_VLF); ++ ++ /* VSIL = (payloadlen + icvlen + padlen) - icvlen + padlen */ ++ append_math_sub(desc, VARSEQINLEN, REG3, REG2, 4); ++ ++ /* ++ * Start a new input sequence using the SEQ OUT PTR command options, ++ * pointer and length used when the current output sequence was defined. ++ */ ++ if (ps) { ++ /* ++ * Move the lower 32 bits of Shared Descriptor address, the ++ * SEQ OUT PTR command, Output Pointer (2 words) and ++ * Output Length into math registers. ++ */ ++#ifdef __LITTLE_ENDIAN ++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_DESCBUF | ++ MOVE_DEST_MATH0 | (55 * 4 << MOVE_OFFSET_SHIFT) | ++ 20); ++#else ++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_DESCBUF | ++ MOVE_DEST_MATH0 | (54 * 4 << MOVE_OFFSET_SHIFT) | ++ 20); ++#endif ++ /* Transform SEQ OUT PTR command in SEQ IN PTR command */ ++ append_math_and_imm_u32(desc, REG0, REG0, IMM, ++ ~(CMD_SEQ_IN_PTR ^ CMD_SEQ_OUT_PTR)); ++ /* Append a JUMP command after the copied fields */ ++ jumpback = CMD_JUMP | (char)-9; ++ append_load_imm_u32(desc, jumpback, LDST_CLASS_DECO | LDST_IMM | ++ LDST_SRCDST_WORD_DECO_MATH2 | ++ (4 << LDST_OFFSET_SHIFT)); ++ append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM | 1); ++ /* Move the updated fields back to the Job Descriptor */ ++#ifdef __LITTLE_ENDIAN ++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH0 | ++ MOVE_DEST_DESCBUF | (55 * 4 << MOVE_OFFSET_SHIFT) | ++ 24); ++#else ++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH0 | ++ MOVE_DEST_DESCBUF | (54 * 4 << MOVE_OFFSET_SHIFT) | ++ 24); ++#endif ++ /* ++ * Read the new SEQ IN PTR command, Input Pointer, Input Length ++ * and then jump back to the next command from the ++ * Shared Descriptor. ++ */ ++ append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM | 6); ++ } else { ++ /* ++ * Move the SEQ OUT PTR command, Output Pointer (1 word) and ++ * Output Length into math registers. ++ */ ++#ifdef __LITTLE_ENDIAN ++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_DESCBUF | ++ MOVE_DEST_MATH0 | (54 * 4 << MOVE_OFFSET_SHIFT) | ++ 12); ++#else ++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_DESCBUF | ++ MOVE_DEST_MATH0 | (53 * 4 << MOVE_OFFSET_SHIFT) | ++ 12); ++#endif ++ /* Transform SEQ OUT PTR command in SEQ IN PTR command */ ++ append_math_and_imm_u64(desc, REG0, REG0, IMM, ++ ~(((u64)(CMD_SEQ_IN_PTR ^ ++ CMD_SEQ_OUT_PTR)) << 32)); ++ /* Append a JUMP command after the copied fields */ ++ jumpback = CMD_JUMP | (char)-7; ++ append_load_imm_u32(desc, jumpback, LDST_CLASS_DECO | LDST_IMM | ++ LDST_SRCDST_WORD_DECO_MATH1 | ++ (4 << LDST_OFFSET_SHIFT)); ++ append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM | 1); ++ /* Move the updated fields back to the Job Descriptor */ ++#ifdef __LITTLE_ENDIAN ++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH0 | ++ MOVE_DEST_DESCBUF | (54 * 4 << MOVE_OFFSET_SHIFT) | ++ 16); ++#else ++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_MATH0 | ++ MOVE_DEST_DESCBUF | (53 * 4 << MOVE_OFFSET_SHIFT) | ++ 16); ++#endif ++ /* ++ * Read the new SEQ IN PTR command, Input Pointer, Input Length ++ * and then jump back to the next command from the ++ * Shared Descriptor. ++ */ ++ append_jump(desc, JUMP_TEST_ALL | JUMP_COND_CALM | 5); ++ } ++ ++ /* skip payload */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_SKIP | FIFOLDST_VLF); ++ /* check icv */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_ICV | ++ FIFOLD_TYPE_LAST2 | authsize); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "tls dec shdesc@" __stringify(__LINE__) ": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, ++ desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_tls_decap); ++ ++/** ++ * cnstr_shdsc_gcm_encap - gcm encapsulation shared descriptor ++ * @desc: pointer to buffer used for descriptor construction ++ * @cdata: pointer to block cipher transform definitions ++ * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM. ++ * @ivsize: initialization vector size ++ * @icvsize: integrity check value (ICV) size (truncated or full) ++ * @is_qi: true when called from caam/qi ++ */ ++void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, unsigned int icvsize, ++ const bool is_qi) ++{ ++ u32 *key_jump_cmd, *zero_payload_jump_cmd, *zero_assoc_jump_cmd1, ++ *zero_assoc_jump_cmd2; ++ ++ init_sh_desc(desc, HDR_SHARE_SERIAL); ++ ++ /* skip key loading if they are loaded due to sharing */ ++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); ++ if (cdata->key_inline) ++ append_key_as_imm(desc, cdata->key_virt, cdata->keylen, ++ cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); ++ else ++ append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 | ++ KEY_DEST_CLASS_REG); ++ set_jump_tgt_here(desc, key_jump_cmd); ++ ++ /* class 1 operation */ ++ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_ENCRYPT); ++ ++ if (is_qi) { ++ u32 *wait_load_cmd; ++ ++ /* REG3 = assoclen */ ++ append_seq_load(desc, 4, LDST_CLASS_DECO | ++ LDST_SRCDST_WORD_DECO_MATH3 | ++ (4 << LDST_OFFSET_SHIFT)); ++ ++ wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_CALM | JUMP_COND_NCP | ++ JUMP_COND_NOP | JUMP_COND_NIP | ++ JUMP_COND_NIFP); ++ set_jump_tgt_here(desc, wait_load_cmd); ++ ++ append_math_sub_imm_u32(desc, VARSEQOUTLEN, SEQINLEN, IMM, ++ ivsize); ++ } else { ++ append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, ++ CAAM_CMD_SZ); ++ } ++ ++ /* if assoclen + cryptlen is ZERO, skip to ICV write */ ++ zero_assoc_jump_cmd2 = append_jump(desc, JUMP_TEST_ALL | ++ JUMP_COND_MATH_Z); ++ ++ if (is_qi) ++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 | ++ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1); ++ ++ /* if assoclen is ZERO, skip reading the assoc data */ ++ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); ++ zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL | ++ JUMP_COND_MATH_Z); ++ ++ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); ++ ++ /* skip assoc data */ ++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); ++ ++ /* cryptlen = seqinlen - assoclen */ ++ append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG3, CAAM_CMD_SZ); ++ ++ /* if cryptlen is ZERO jump to zero-payload commands */ ++ zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL | ++ JUMP_COND_MATH_Z); ++ ++ /* read assoc data */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | ++ FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); ++ set_jump_tgt_here(desc, zero_assoc_jump_cmd1); ++ ++ append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); ++ ++ /* write encrypted data */ ++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); ++ ++ /* read payload data */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | ++ FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); ++ ++ /* jump to ICV writing */ ++ if (is_qi) ++ append_jump(desc, JUMP_TEST_ALL | 4); ++ else ++ append_jump(desc, JUMP_TEST_ALL | 2); ++ ++ /* zero-payload commands */ ++ set_jump_tgt_here(desc, zero_payload_jump_cmd); ++ ++ /* read assoc data */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | ++ FIFOLD_TYPE_AAD | FIFOLD_TYPE_LAST1); ++ if (is_qi) ++ /* jump to ICV writing */ ++ append_jump(desc, JUMP_TEST_ALL | 2); ++ ++ /* There is no input data */ ++ set_jump_tgt_here(desc, zero_assoc_jump_cmd2); ++ ++ if (is_qi) ++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 | ++ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1 | ++ FIFOLD_TYPE_LAST1); ++ ++ /* write ICV */ ++ append_seq_store(desc, icvsize, LDST_CLASS_1_CCB | ++ LDST_SRCDST_BYTE_CONTEXT); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "gcm enc shdesc@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_gcm_encap); ++ ++/** ++ * cnstr_shdsc_gcm_decap - gcm decapsulation shared descriptor ++ * @desc: pointer to buffer used for descriptor construction ++ * @cdata: pointer to block cipher transform definitions ++ * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM. ++ * @ivsize: initialization vector size ++ * @icvsize: integrity check value (ICV) size (truncated or full) ++ * @is_qi: true when called from caam/qi ++ */ ++void cnstr_shdsc_gcm_decap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, unsigned int icvsize, ++ const bool is_qi) ++{ ++ u32 *key_jump_cmd, *zero_payload_jump_cmd, *zero_assoc_jump_cmd1; ++ ++ init_sh_desc(desc, HDR_SHARE_SERIAL); ++ ++ /* skip key loading if they are loaded due to sharing */ ++ key_jump_cmd = append_jump(desc, JUMP_JSL | ++ JUMP_TEST_ALL | JUMP_COND_SHRD); ++ if (cdata->key_inline) ++ append_key_as_imm(desc, cdata->key_virt, cdata->keylen, ++ cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); ++ else ++ append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 | ++ KEY_DEST_CLASS_REG); ++ set_jump_tgt_here(desc, key_jump_cmd); ++ ++ /* class 1 operation */ ++ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_DECRYPT | OP_ALG_ICV_ON); ++ ++ if (is_qi) { ++ u32 *wait_load_cmd; ++ ++ /* REG3 = assoclen */ ++ append_seq_load(desc, 4, LDST_CLASS_DECO | ++ LDST_SRCDST_WORD_DECO_MATH3 | ++ (4 << LDST_OFFSET_SHIFT)); ++ ++ wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_CALM | JUMP_COND_NCP | ++ JUMP_COND_NOP | JUMP_COND_NIP | ++ JUMP_COND_NIFP); ++ set_jump_tgt_here(desc, wait_load_cmd); ++ ++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 | ++ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1); ++ } ++ ++ /* if assoclen is ZERO, skip reading the assoc data */ ++ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); ++ zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL | ++ JUMP_COND_MATH_Z); ++ ++ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); ++ ++ /* skip assoc data */ ++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); ++ ++ /* read assoc data */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | ++ FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); ++ ++ set_jump_tgt_here(desc, zero_assoc_jump_cmd1); ++ ++ /* cryptlen = seqoutlen - assoclen */ ++ append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); ++ ++ /* jump to zero-payload command if cryptlen is zero */ ++ zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL | ++ JUMP_COND_MATH_Z); ++ ++ append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); ++ ++ /* store encrypted data */ ++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); ++ ++ /* read payload data */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | ++ FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); ++ ++ /* zero-payload command */ ++ set_jump_tgt_here(desc, zero_payload_jump_cmd); ++ ++ /* read ICV */ ++ append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS1 | ++ FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "gcm dec shdesc@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_gcm_decap); ++ ++/** ++ * cnstr_shdsc_rfc4106_encap - IPSec ESP gcm encapsulation shared descriptor ++ * (non-protocol). ++ * @desc: pointer to buffer used for descriptor construction ++ * @cdata: pointer to block cipher transform definitions ++ * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM. ++ * @ivsize: initialization vector size ++ * @icvsize: integrity check value (ICV) size (truncated or full) ++ * @is_qi: true when called from caam/qi ++ */ ++void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, unsigned int icvsize, ++ const bool is_qi) ++{ ++ u32 *key_jump_cmd; ++ ++ init_sh_desc(desc, HDR_SHARE_SERIAL); ++ ++ /* Skip key loading if it is loaded due to sharing */ ++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); ++ if (cdata->key_inline) ++ append_key_as_imm(desc, cdata->key_virt, cdata->keylen, ++ cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); ++ else ++ append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 | ++ KEY_DEST_CLASS_REG); ++ set_jump_tgt_here(desc, key_jump_cmd); ++ ++ /* Class 1 operation */ ++ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_ENCRYPT); ++ ++ if (is_qi) { ++ u32 *wait_load_cmd; ++ ++ /* REG3 = assoclen */ ++ append_seq_load(desc, 4, LDST_CLASS_DECO | ++ LDST_SRCDST_WORD_DECO_MATH3 | ++ (4 << LDST_OFFSET_SHIFT)); ++ ++ wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_CALM | JUMP_COND_NCP | ++ JUMP_COND_NOP | JUMP_COND_NIP | ++ JUMP_COND_NIFP); ++ set_jump_tgt_here(desc, wait_load_cmd); ++ ++ /* Read salt and IV */ ++ append_fifo_load_as_imm(desc, (void *)(cdata->key_virt + ++ cdata->keylen), 4, FIFOLD_CLASS_CLASS1 | ++ FIFOLD_TYPE_IV); ++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 | ++ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1); ++ } ++ ++ append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, ivsize); ++ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); ++ ++ /* Read assoc data */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | ++ FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); ++ ++ /* Skip IV */ ++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_SKIP); ++ ++ /* Will read cryptlen bytes */ ++ append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); ++ ++ /* Workaround for erratum A-005473 (simultaneous SEQ FIFO skips) */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_MSG); ++ ++ /* Skip assoc data */ ++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); ++ ++ /* cryptlen = seqoutlen - assoclen */ ++ append_math_sub(desc, VARSEQOUTLEN, VARSEQINLEN, REG0, CAAM_CMD_SZ); ++ ++ /* Write encrypted data */ ++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); ++ ++ /* Read payload data */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | ++ FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); ++ ++ /* Write ICV */ ++ append_seq_store(desc, icvsize, LDST_CLASS_1_CCB | ++ LDST_SRCDST_BYTE_CONTEXT); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, ++ "rfc4106 enc shdesc@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_rfc4106_encap); ++ ++/** ++ * cnstr_shdsc_rfc4106_decap - IPSec ESP gcm decapsulation shared descriptor ++ * (non-protocol). ++ * @desc: pointer to buffer used for descriptor construction ++ * @cdata: pointer to block cipher transform definitions ++ * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM. ++ * @ivsize: initialization vector size ++ * @icvsize: integrity check value (ICV) size (truncated or full) ++ * @is_qi: true when called from caam/qi ++ */ ++void cnstr_shdsc_rfc4106_decap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, unsigned int icvsize, ++ const bool is_qi) ++{ ++ u32 *key_jump_cmd; ++ ++ init_sh_desc(desc, HDR_SHARE_SERIAL); ++ ++ /* Skip key loading if it is loaded due to sharing */ ++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); ++ if (cdata->key_inline) ++ append_key_as_imm(desc, cdata->key_virt, cdata->keylen, ++ cdata->keylen, CLASS_1 | ++ KEY_DEST_CLASS_REG); ++ else ++ append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 | ++ KEY_DEST_CLASS_REG); ++ set_jump_tgt_here(desc, key_jump_cmd); ++ ++ /* Class 1 operation */ ++ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_DECRYPT | OP_ALG_ICV_ON); ++ ++ if (is_qi) { ++ u32 *wait_load_cmd; ++ ++ /* REG3 = assoclen */ ++ append_seq_load(desc, 4, LDST_CLASS_DECO | ++ LDST_SRCDST_WORD_DECO_MATH3 | ++ (4 << LDST_OFFSET_SHIFT)); ++ ++ wait_load_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_CALM | JUMP_COND_NCP | ++ JUMP_COND_NOP | JUMP_COND_NIP | ++ JUMP_COND_NIFP); ++ set_jump_tgt_here(desc, wait_load_cmd); ++ ++ /* Read salt and IV */ ++ append_fifo_load_as_imm(desc, (void *)(cdata->key_virt + ++ cdata->keylen), 4, FIFOLD_CLASS_CLASS1 | ++ FIFOLD_TYPE_IV); ++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 | ++ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1); ++ } ++ ++ append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, ivsize); ++ append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); ++ ++ /* Read assoc data */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | ++ FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); ++ ++ /* Skip IV */ ++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_SKIP); ++ ++ /* Will read cryptlen bytes */ ++ append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG3, CAAM_CMD_SZ); ++ ++ /* Workaround for erratum A-005473 (simultaneous SEQ FIFO skips) */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_MSG); ++ ++ /* Skip assoc data */ ++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); ++ ++ /* Will write cryptlen bytes */ ++ append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); ++ ++ /* Store payload data */ ++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); ++ ++ /* Read encrypted data */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | ++ FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); ++ ++ /* Read ICV */ ++ append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS1 | ++ FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, ++ "rfc4106 dec shdesc@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_rfc4106_decap); ++ ++/** ++ * cnstr_shdsc_rfc4543_encap - IPSec ESP gmac encapsulation shared descriptor ++ * (non-protocol). ++ * @desc: pointer to buffer used for descriptor construction ++ * @cdata: pointer to block cipher transform definitions ++ * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM. ++ * @ivsize: initialization vector size ++ * @icvsize: integrity check value (ICV) size (truncated or full) ++ * @is_qi: true when called from caam/qi ++ */ ++void cnstr_shdsc_rfc4543_encap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, unsigned int icvsize, ++ const bool is_qi) ++{ ++ u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd; ++ ++ init_sh_desc(desc, HDR_SHARE_SERIAL); ++ ++ /* Skip key loading if it is loaded due to sharing */ ++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); ++ if (cdata->key_inline) ++ append_key_as_imm(desc, cdata->key_virt, cdata->keylen, ++ cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); ++ else ++ append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 | ++ KEY_DEST_CLASS_REG); ++ set_jump_tgt_here(desc, key_jump_cmd); ++ ++ /* Class 1 operation */ ++ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_ENCRYPT); ++ ++ if (is_qi) { ++ /* assoclen is not needed, skip it */ ++ append_seq_fifo_load(desc, 4, FIFOLD_CLASS_SKIP); ++ ++ /* Read salt and IV */ ++ append_fifo_load_as_imm(desc, (void *)(cdata->key_virt + ++ cdata->keylen), 4, FIFOLD_CLASS_CLASS1 | ++ FIFOLD_TYPE_IV); ++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 | ++ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1); ++ } ++ ++ /* assoclen + cryptlen = seqinlen */ ++ append_math_sub(desc, REG3, SEQINLEN, REG0, CAAM_CMD_SZ); ++ ++ /* ++ * MOVE_LEN opcode is not available in all SEC HW revisions, ++ * thus need to do some magic, i.e. self-patch the descriptor ++ * buffer. ++ */ ++ read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH3 | ++ (0x6 << MOVE_LEN_SHIFT)); ++ write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | MOVE_DEST_DESCBUF | ++ (0x8 << MOVE_LEN_SHIFT)); ++ ++ /* Will read assoclen + cryptlen bytes */ ++ append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); ++ ++ /* Will write assoclen + cryptlen bytes */ ++ append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); ++ ++ /* Read and write assoclen + cryptlen bytes */ ++ aead_append_src_dst(desc, FIFOLD_TYPE_AAD); ++ ++ set_move_tgt_here(desc, read_move_cmd); ++ set_move_tgt_here(desc, write_move_cmd); ++ append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); ++ /* Move payload data to OFIFO */ ++ append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO); ++ ++ /* Write ICV */ ++ append_seq_store(desc, icvsize, LDST_CLASS_1_CCB | ++ LDST_SRCDST_BYTE_CONTEXT); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, ++ "rfc4543 enc shdesc@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_rfc4543_encap); ++ ++/** ++ * cnstr_shdsc_rfc4543_decap - IPSec ESP gmac decapsulation shared descriptor ++ * (non-protocol). ++ * @desc: pointer to buffer used for descriptor construction ++ * @cdata: pointer to block cipher transform definitions ++ * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM. ++ * @ivsize: initialization vector size ++ * @icvsize: integrity check value (ICV) size (truncated or full) ++ * @is_qi: true when called from caam/qi ++ */ ++void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, unsigned int icvsize, ++ const bool is_qi) ++{ ++ u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd; ++ ++ init_sh_desc(desc, HDR_SHARE_SERIAL); ++ ++ /* Skip key loading if it is loaded due to sharing */ ++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); ++ if (cdata->key_inline) ++ append_key_as_imm(desc, cdata->key_virt, cdata->keylen, ++ cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); ++ else ++ append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 | ++ KEY_DEST_CLASS_REG); ++ set_jump_tgt_here(desc, key_jump_cmd); ++ ++ /* Class 1 operation */ ++ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_DECRYPT | OP_ALG_ICV_ON); ++ ++ if (is_qi) { ++ /* assoclen is not needed, skip it */ ++ append_seq_fifo_load(desc, 4, FIFOLD_CLASS_SKIP); ++ ++ /* Read salt and IV */ ++ append_fifo_load_as_imm(desc, (void *)(cdata->key_virt + ++ cdata->keylen), 4, FIFOLD_CLASS_CLASS1 | ++ FIFOLD_TYPE_IV); ++ append_seq_fifo_load(desc, ivsize, FIFOLD_CLASS_CLASS1 | ++ FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1); ++ } ++ ++ /* assoclen + cryptlen = seqoutlen */ ++ append_math_sub(desc, REG3, SEQOUTLEN, REG0, CAAM_CMD_SZ); ++ ++ /* ++ * MOVE_LEN opcode is not available in all SEC HW revisions, ++ * thus need to do some magic, i.e. self-patch the descriptor ++ * buffer. ++ */ ++ read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH3 | ++ (0x6 << MOVE_LEN_SHIFT)); ++ write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | MOVE_DEST_DESCBUF | ++ (0x8 << MOVE_LEN_SHIFT)); ++ ++ /* Will read assoclen + cryptlen bytes */ ++ append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); ++ ++ /* Will write assoclen + cryptlen bytes */ ++ append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); ++ ++ /* Store payload data */ ++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); ++ ++ /* In-snoop assoclen + cryptlen data */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | FIFOLDST_VLF | ++ FIFOLD_TYPE_AAD | FIFOLD_TYPE_LAST2FLUSH1); ++ ++ set_move_tgt_here(desc, read_move_cmd); ++ set_move_tgt_here(desc, write_move_cmd); ++ append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); ++ /* Move payload data to OFIFO */ ++ append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO); ++ append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); ++ ++ /* Read ICV */ ++ append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS1 | ++ FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, ++ "rfc4543 dec shdesc@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_rfc4543_decap); ++ ++/* ++ * For ablkcipher encrypt and decrypt, read from req->src and ++ * write to req->dst ++ */ ++static inline void ablkcipher_append_src_dst(u32 *desc) ++{ ++ append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); ++ append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | ++ KEY_VLF | FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); ++ append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); ++} ++ ++/** ++ * cnstr_shdsc_ablkcipher_encap - ablkcipher encapsulation shared descriptor ++ * @desc: pointer to buffer used for descriptor construction ++ * @cdata: pointer to block cipher transform definitions ++ * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed ++ * with OP_ALG_AAI_CBC or OP_ALG_AAI_CTR_MOD128. ++ * @ivsize: initialization vector size ++ * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template ++ * @ctx1_iv_off: IV offset in CONTEXT1 register ++ */ ++void cnstr_shdsc_ablkcipher_encap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, const bool is_rfc3686, ++ const u32 ctx1_iv_off) ++{ ++ u32 *key_jump_cmd; ++ ++ init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); ++ /* Skip if already shared */ ++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); ++ ++ /* Load class1 key only */ ++ append_key_as_imm(desc, cdata->key_virt, cdata->keylen, ++ cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); ++ ++ /* Load nonce into CONTEXT1 reg */ ++ if (is_rfc3686) { ++ u8 *nonce = cdata->key_virt + cdata->keylen; ++ ++ append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, ++ LDST_CLASS_IND_CCB | ++ LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); ++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_OUTFIFO | ++ MOVE_DEST_CLASS1CTX | (16 << MOVE_OFFSET_SHIFT) | ++ (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); ++ } ++ ++ set_jump_tgt_here(desc, key_jump_cmd); ++ ++ /* Load iv */ ++ append_seq_load(desc, ivsize, LDST_SRCDST_BYTE_CONTEXT | ++ LDST_CLASS_1_CCB | (ctx1_iv_off << LDST_OFFSET_SHIFT)); ++ ++ /* Load counter into CONTEXT1 reg */ ++ if (is_rfc3686) ++ append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | ++ LDST_SRCDST_BYTE_CONTEXT | ++ ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << ++ LDST_OFFSET_SHIFT)); ++ ++ /* Load operation */ ++ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_ENCRYPT); ++ ++ /* Perform operation */ ++ ablkcipher_append_src_dst(desc); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, ++ "ablkcipher enc shdesc@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_ablkcipher_encap); ++ ++/** ++ * cnstr_shdsc_ablkcipher_decap - ablkcipher decapsulation shared descriptor ++ * @desc: pointer to buffer used for descriptor construction ++ * @cdata: pointer to block cipher transform definitions ++ * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed ++ * with OP_ALG_AAI_CBC or OP_ALG_AAI_CTR_MOD128. ++ * @ivsize: initialization vector size ++ * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template ++ * @ctx1_iv_off: IV offset in CONTEXT1 register ++ */ ++void cnstr_shdsc_ablkcipher_decap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, const bool is_rfc3686, ++ const u32 ctx1_iv_off) ++{ ++ u32 *key_jump_cmd; ++ ++ init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); ++ /* Skip if already shared */ ++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); ++ ++ /* Load class1 key only */ ++ append_key_as_imm(desc, cdata->key_virt, cdata->keylen, ++ cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); ++ ++ /* Load nonce into CONTEXT1 reg */ ++ if (is_rfc3686) { ++ u8 *nonce = cdata->key_virt + cdata->keylen; ++ ++ append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, ++ LDST_CLASS_IND_CCB | ++ LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); ++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_OUTFIFO | ++ MOVE_DEST_CLASS1CTX | (16 << MOVE_OFFSET_SHIFT) | ++ (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); ++ } ++ ++ set_jump_tgt_here(desc, key_jump_cmd); ++ ++ /* load IV */ ++ append_seq_load(desc, ivsize, LDST_SRCDST_BYTE_CONTEXT | ++ LDST_CLASS_1_CCB | (ctx1_iv_off << LDST_OFFSET_SHIFT)); ++ ++ /* Load counter into CONTEXT1 reg */ ++ if (is_rfc3686) ++ append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | ++ LDST_SRCDST_BYTE_CONTEXT | ++ ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << ++ LDST_OFFSET_SHIFT)); ++ ++ /* Choose operation */ ++ if (ctx1_iv_off) ++ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_DECRYPT); ++ else ++ append_dec_op1(desc, cdata->algtype); ++ ++ /* Perform operation */ ++ ablkcipher_append_src_dst(desc); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, ++ "ablkcipher dec shdesc@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_ablkcipher_decap); ++ ++/** ++ * cnstr_shdsc_ablkcipher_givencap - ablkcipher encapsulation shared descriptor ++ * with HW-generated initialization vector. ++ * @desc: pointer to buffer used for descriptor construction ++ * @cdata: pointer to block cipher transform definitions ++ * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed ++ * with OP_ALG_AAI_CBC. ++ * @ivsize: initialization vector size ++ * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template ++ * @ctx1_iv_off: IV offset in CONTEXT1 register ++ */ ++void cnstr_shdsc_ablkcipher_givencap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, const bool is_rfc3686, ++ const u32 ctx1_iv_off) ++{ ++ u32 *key_jump_cmd, geniv; ++ ++ init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); ++ /* Skip if already shared */ ++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); ++ ++ /* Load class1 key only */ ++ append_key_as_imm(desc, cdata->key_virt, cdata->keylen, ++ cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); ++ ++ /* Load Nonce into CONTEXT1 reg */ ++ if (is_rfc3686) { ++ u8 *nonce = cdata->key_virt + cdata->keylen; ++ ++ append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, ++ LDST_CLASS_IND_CCB | ++ LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); ++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_OUTFIFO | ++ MOVE_DEST_CLASS1CTX | (16 << MOVE_OFFSET_SHIFT) | ++ (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); ++ } ++ set_jump_tgt_here(desc, key_jump_cmd); ++ ++ /* Generate IV */ ++ geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO | ++ NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 | NFIFOENTRY_PTYPE_RND | ++ (ivsize << NFIFOENTRY_DLEN_SHIFT); ++ append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB | ++ LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); ++ append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); ++ append_move(desc, MOVE_WAITCOMP | MOVE_SRC_INFIFO | ++ MOVE_DEST_CLASS1CTX | (ivsize << MOVE_LEN_SHIFT) | ++ (ctx1_iv_off << MOVE_OFFSET_SHIFT)); ++ append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); ++ ++ /* Copy generated IV to memory */ ++ append_seq_store(desc, ivsize, LDST_SRCDST_BYTE_CONTEXT | ++ LDST_CLASS_1_CCB | (ctx1_iv_off << LDST_OFFSET_SHIFT)); ++ ++ /* Load Counter into CONTEXT1 reg */ ++ if (is_rfc3686) ++ append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | ++ LDST_SRCDST_BYTE_CONTEXT | ++ ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << ++ LDST_OFFSET_SHIFT)); ++ ++ if (ctx1_iv_off) ++ append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_NCP | ++ (1 << JUMP_OFFSET_SHIFT)); ++ ++ /* Load operation */ ++ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_ENCRYPT); ++ ++ /* Perform operation */ ++ ablkcipher_append_src_dst(desc); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, ++ "ablkcipher givenc shdesc@" __stringify(__LINE__) ": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_ablkcipher_givencap); ++ ++/** ++ * cnstr_shdsc_xts_ablkcipher_encap - xts ablkcipher encapsulation shared ++ * descriptor ++ * @desc: pointer to buffer used for descriptor construction ++ * @cdata: pointer to block cipher transform definitions ++ * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_XTS. ++ */ ++void cnstr_shdsc_xts_ablkcipher_encap(u32 * const desc, struct alginfo *cdata) ++{ ++ __be64 sector_size = cpu_to_be64(512); ++ u32 *key_jump_cmd; ++ ++ init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); ++ /* Skip if already shared */ ++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); ++ ++ /* Load class1 keys only */ ++ append_key_as_imm(desc, cdata->key_virt, cdata->keylen, ++ cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); ++ ++ /* Load sector size with index 40 bytes (0x28) */ ++ append_load_as_imm(desc, (void *)§or_size, 8, LDST_CLASS_1_CCB | ++ LDST_SRCDST_BYTE_CONTEXT | ++ (0x28 << LDST_OFFSET_SHIFT)); ++ ++ set_jump_tgt_here(desc, key_jump_cmd); ++ ++ /* ++ * create sequence for loading the sector index ++ * Upper 8B of IV - will be used as sector index ++ * Lower 8B of IV - will be discarded ++ */ ++ append_seq_load(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB | ++ (0x20 << LDST_OFFSET_SHIFT)); ++ append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); ++ ++ /* Load operation */ ++ append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | ++ OP_ALG_ENCRYPT); ++ ++ /* Perform operation */ ++ ablkcipher_append_src_dst(desc); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, ++ "xts ablkcipher enc shdesc@" __stringify(__LINE__) ": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_xts_ablkcipher_encap); ++ ++/** ++ * cnstr_shdsc_xts_ablkcipher_decap - xts ablkcipher decapsulation shared ++ * descriptor ++ * @desc: pointer to buffer used for descriptor construction ++ * @cdata: pointer to block cipher transform definitions ++ * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_XTS. ++ */ ++void cnstr_shdsc_xts_ablkcipher_decap(u32 * const desc, struct alginfo *cdata) ++{ ++ __be64 sector_size = cpu_to_be64(512); ++ u32 *key_jump_cmd; ++ ++ init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); ++ /* Skip if already shared */ ++ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); ++ ++ /* Load class1 key only */ ++ append_key_as_imm(desc, cdata->key_virt, cdata->keylen, ++ cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); ++ ++ /* Load sector size with index 40 bytes (0x28) */ ++ append_load_as_imm(desc, (void *)§or_size, 8, LDST_CLASS_1_CCB | ++ LDST_SRCDST_BYTE_CONTEXT | ++ (0x28 << LDST_OFFSET_SHIFT)); ++ ++ set_jump_tgt_here(desc, key_jump_cmd); ++ ++ /* ++ * create sequence for loading the sector index ++ * Upper 8B of IV - will be used as sector index ++ * Lower 8B of IV - will be discarded ++ */ ++ append_seq_load(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB | ++ (0x20 << LDST_OFFSET_SHIFT)); ++ append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); ++ ++ /* Load operation */ ++ append_dec_op1(desc, cdata->algtype); ++ ++ /* Perform operation */ ++ ablkcipher_append_src_dst(desc); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, ++ "xts ablkcipher dec shdesc@" __stringify(__LINE__) ": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++} ++EXPORT_SYMBOL(cnstr_shdsc_xts_ablkcipher_decap); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("FSL CAAM descriptor support"); ++MODULE_AUTHOR("Freescale Semiconductor - NMG/STC"); +diff --git a/drivers/crypto/caam/caamalg_desc.h b/drivers/crypto/caam/caamalg_desc.h +new file mode 100644 +index 00000000..6b436f65 +--- /dev/null ++++ b/drivers/crypto/caam/caamalg_desc.h +@@ -0,0 +1,127 @@ ++/* ++ * Shared descriptors for aead, ablkcipher algorithms ++ * ++ * Copyright 2016 NXP ++ */ ++ ++#ifndef _CAAMALG_DESC_H_ ++#define _CAAMALG_DESC_H_ ++ ++/* length of descriptors text */ ++#define DESC_AEAD_BASE (4 * CAAM_CMD_SZ) ++#define DESC_AEAD_ENC_LEN (DESC_AEAD_BASE + 11 * CAAM_CMD_SZ) ++#define DESC_AEAD_DEC_LEN (DESC_AEAD_BASE + 15 * CAAM_CMD_SZ) ++#define DESC_AEAD_GIVENC_LEN (DESC_AEAD_ENC_LEN + 7 * CAAM_CMD_SZ) ++#define DESC_QI_AEAD_ENC_LEN (DESC_AEAD_ENC_LEN + 3 * CAAM_CMD_SZ) ++#define DESC_QI_AEAD_DEC_LEN (DESC_AEAD_DEC_LEN + 3 * CAAM_CMD_SZ) ++#define DESC_QI_AEAD_GIVENC_LEN (DESC_AEAD_GIVENC_LEN + 3 * CAAM_CMD_SZ) ++ ++#define DESC_TLS_BASE (4 * CAAM_CMD_SZ) ++#define DESC_TLS10_ENC_LEN (DESC_TLS_BASE + 29 * CAAM_CMD_SZ) ++ ++/* Note: Nonce is counted in cdata.keylen */ ++#define DESC_AEAD_CTR_RFC3686_LEN (4 * CAAM_CMD_SZ) ++ ++#define DESC_AEAD_NULL_BASE (3 * CAAM_CMD_SZ) ++#define DESC_AEAD_NULL_ENC_LEN (DESC_AEAD_NULL_BASE + 11 * CAAM_CMD_SZ) ++#define DESC_AEAD_NULL_DEC_LEN (DESC_AEAD_NULL_BASE + 13 * CAAM_CMD_SZ) ++ ++#define DESC_GCM_BASE (3 * CAAM_CMD_SZ) ++#define DESC_GCM_ENC_LEN (DESC_GCM_BASE + 16 * CAAM_CMD_SZ) ++#define DESC_GCM_DEC_LEN (DESC_GCM_BASE + 12 * CAAM_CMD_SZ) ++#define DESC_QI_GCM_ENC_LEN (DESC_GCM_ENC_LEN + 6 * CAAM_CMD_SZ) ++#define DESC_QI_GCM_DEC_LEN (DESC_GCM_DEC_LEN + 3 * CAAM_CMD_SZ) ++ ++#define DESC_RFC4106_BASE (3 * CAAM_CMD_SZ) ++#define DESC_RFC4106_ENC_LEN (DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ) ++#define DESC_RFC4106_DEC_LEN (DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ) ++#define DESC_QI_RFC4106_ENC_LEN (DESC_RFC4106_ENC_LEN + 5 * CAAM_CMD_SZ) ++#define DESC_QI_RFC4106_DEC_LEN (DESC_RFC4106_DEC_LEN + 5 * CAAM_CMD_SZ) ++ ++#define DESC_RFC4543_BASE (3 * CAAM_CMD_SZ) ++#define DESC_RFC4543_ENC_LEN (DESC_RFC4543_BASE + 11 * CAAM_CMD_SZ) ++#define DESC_RFC4543_DEC_LEN (DESC_RFC4543_BASE + 12 * CAAM_CMD_SZ) ++#define DESC_QI_RFC4543_ENC_LEN (DESC_RFC4543_ENC_LEN + 4 * CAAM_CMD_SZ) ++#define DESC_QI_RFC4543_DEC_LEN (DESC_RFC4543_DEC_LEN + 4 * CAAM_CMD_SZ) ++ ++#define DESC_ABLKCIPHER_BASE (3 * CAAM_CMD_SZ) ++#define DESC_ABLKCIPHER_ENC_LEN (DESC_ABLKCIPHER_BASE + \ ++ 20 * CAAM_CMD_SZ) ++#define DESC_ABLKCIPHER_DEC_LEN (DESC_ABLKCIPHER_BASE + \ ++ 15 * CAAM_CMD_SZ) ++ ++void cnstr_shdsc_aead_null_encap(u32 * const desc, struct alginfo *adata, ++ unsigned int icvsize); ++ ++void cnstr_shdsc_aead_null_decap(u32 * const desc, struct alginfo *adata, ++ unsigned int icvsize); ++ ++void cnstr_shdsc_aead_encap(u32 * const desc, struct alginfo *cdata, ++ struct alginfo *adata, unsigned int ivsize, ++ unsigned int icvsize, const bool is_rfc3686, ++ u32 *nonce, const u32 ctx1_iv_off, ++ const bool is_qi); ++ ++void cnstr_shdsc_aead_decap(u32 * const desc, struct alginfo *cdata, ++ struct alginfo *adata, unsigned int ivsize, ++ unsigned int icvsize, const bool geniv, ++ const bool is_rfc3686, u32 *nonce, ++ const u32 ctx1_iv_off, const bool is_qi); ++ ++void cnstr_shdsc_aead_givencap(u32 * const desc, struct alginfo *cdata, ++ struct alginfo *adata, unsigned int ivsize, ++ unsigned int icvsize, const bool is_rfc3686, ++ u32 *nonce, const u32 ctx1_iv_off, ++ const bool is_qi); ++ ++void cnstr_shdsc_tls_encap(u32 *const desc, struct alginfo *cdata, ++ struct alginfo *adata, unsigned int assoclen, ++ unsigned int ivsize, unsigned int authsize, ++ unsigned int blocksize); ++ ++void cnstr_shdsc_tls_decap(u32 *const desc, struct alginfo *cdata, ++ struct alginfo *adata, unsigned int assoclen, ++ unsigned int ivsize, unsigned int authsize, ++ unsigned int blocksize); ++ ++void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, unsigned int icvsize, ++ const bool is_qi); ++ ++void cnstr_shdsc_gcm_decap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, unsigned int icvsize, ++ const bool is_qi); ++ ++void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, unsigned int icvsize, ++ const bool is_qi); ++ ++void cnstr_shdsc_rfc4106_decap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, unsigned int icvsize, ++ const bool is_qi); ++ ++void cnstr_shdsc_rfc4543_encap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, unsigned int icvsize, ++ const bool is_qi); ++ ++void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, unsigned int icvsize, ++ const bool is_qi); ++ ++void cnstr_shdsc_ablkcipher_encap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, const bool is_rfc3686, ++ const u32 ctx1_iv_off); ++ ++void cnstr_shdsc_ablkcipher_decap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, const bool is_rfc3686, ++ const u32 ctx1_iv_off); ++ ++void cnstr_shdsc_ablkcipher_givencap(u32 * const desc, struct alginfo *cdata, ++ unsigned int ivsize, const bool is_rfc3686, ++ const u32 ctx1_iv_off); ++ ++void cnstr_shdsc_xts_ablkcipher_encap(u32 * const desc, struct alginfo *cdata); ++ ++void cnstr_shdsc_xts_ablkcipher_decap(u32 * const desc, struct alginfo *cdata); ++ ++#endif /* _CAAMALG_DESC_H_ */ +diff --git a/drivers/crypto/caam/caamalg_qi.c b/drivers/crypto/caam/caamalg_qi.c +new file mode 100644 +index 00000000..d6a9b0c5 +--- /dev/null ++++ b/drivers/crypto/caam/caamalg_qi.c +@@ -0,0 +1,2877 @@ ++/* ++ * Freescale FSL CAAM support for crypto API over QI backend. ++ * Based on caamalg.c ++ * ++ * Copyright 2013-2016 Freescale Semiconductor, Inc. ++ * Copyright 2016-2017 NXP ++ */ ++ ++#include "compat.h" ++#include "ctrl.h" ++#include "regs.h" ++#include "intern.h" ++#include "desc_constr.h" ++#include "error.h" ++#include "sg_sw_qm.h" ++#include "key_gen.h" ++#include "qi.h" ++#include "jr.h" ++#include "caamalg_desc.h" ++ ++/* ++ * crypto alg ++ */ ++#define CAAM_CRA_PRIORITY 2000 ++/* max key is sum of AES_MAX_KEY_SIZE, max split key size */ ++#define CAAM_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + \ ++ SHA512_DIGEST_SIZE * 2) ++ ++#define DESC_MAX_USED_BYTES (DESC_QI_AEAD_GIVENC_LEN + \ ++ CAAM_MAX_KEY_SIZE) ++#define DESC_MAX_USED_LEN (DESC_MAX_USED_BYTES / CAAM_CMD_SZ) ++ ++struct caam_alg_entry { ++ int class1_alg_type; ++ int class2_alg_type; ++ bool rfc3686; ++ bool geniv; ++}; ++ ++struct caam_aead_alg { ++ struct aead_alg aead; ++ struct caam_alg_entry caam; ++ bool registered; ++}; ++ ++/* ++ * per-session context ++ */ ++struct caam_ctx { ++ struct device *jrdev; ++ u32 sh_desc_enc[DESC_MAX_USED_LEN]; ++ u32 sh_desc_dec[DESC_MAX_USED_LEN]; ++ u32 sh_desc_givenc[DESC_MAX_USED_LEN]; ++ u8 key[CAAM_MAX_KEY_SIZE]; ++ dma_addr_t key_dma; ++ struct alginfo adata; ++ struct alginfo cdata; ++ unsigned int authsize; ++ struct device *qidev; ++ spinlock_t lock; /* Protects multiple init of driver context */ ++ struct caam_drv_ctx *drv_ctx[NUM_OP]; ++}; ++ ++static int aead_set_sh_desc(struct crypto_aead *aead) ++{ ++ struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead), ++ typeof(*alg), aead); ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ unsigned int ivsize = crypto_aead_ivsize(aead); ++ u32 ctx1_iv_off = 0; ++ u32 *nonce = NULL; ++ unsigned int data_len[2]; ++ u32 inl_mask; ++ const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == ++ OP_ALG_AAI_CTR_MOD128); ++ const bool is_rfc3686 = alg->caam.rfc3686; ++ ++ if (!ctx->cdata.keylen || !ctx->authsize) ++ return 0; ++ ++ /* ++ * AES-CTR needs to load IV in CONTEXT1 reg ++ * at an offset of 128bits (16bytes) ++ * CONTEXT1[255:128] = IV ++ */ ++ if (ctr_mode) ++ ctx1_iv_off = 16; ++ ++ /* ++ * RFC3686 specific: ++ * CONTEXT1[255:128] = {NONCE, IV, COUNTER} ++ */ ++ if (is_rfc3686) { ++ ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; ++ nonce = (u32 *)((void *)ctx->key + ctx->adata.keylen_pad + ++ ctx->cdata.keylen - CTR_RFC3686_NONCE_SIZE); ++ } ++ ++ data_len[0] = ctx->adata.keylen_pad; ++ data_len[1] = ctx->cdata.keylen; ++ ++ if (alg->caam.geniv) ++ goto skip_enc; ++ ++ /* aead_encrypt shared descriptor */ ++ if (desc_inline_query(DESC_QI_AEAD_ENC_LEN + ++ (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0), ++ DESC_JOB_IO_LEN, data_len, &inl_mask, ++ ARRAY_SIZE(data_len)) < 0) ++ return -EINVAL; ++ ++ if (inl_mask & 1) ++ ctx->adata.key_virt = ctx->key; ++ else ++ ctx->adata.key_dma = ctx->key_dma; ++ ++ if (inl_mask & 2) ++ ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; ++ else ++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; ++ ++ ctx->adata.key_inline = !!(inl_mask & 1); ++ ctx->cdata.key_inline = !!(inl_mask & 2); ++ ++ cnstr_shdsc_aead_encap(ctx->sh_desc_enc, &ctx->cdata, &ctx->adata, ++ ivsize, ctx->authsize, is_rfc3686, nonce, ++ ctx1_iv_off, true); ++ ++skip_enc: ++ /* aead_decrypt shared descriptor */ ++ if (desc_inline_query(DESC_QI_AEAD_DEC_LEN + ++ (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0), ++ DESC_JOB_IO_LEN, data_len, &inl_mask, ++ ARRAY_SIZE(data_len)) < 0) ++ return -EINVAL; ++ ++ if (inl_mask & 1) ++ ctx->adata.key_virt = ctx->key; ++ else ++ ctx->adata.key_dma = ctx->key_dma; ++ ++ if (inl_mask & 2) ++ ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; ++ else ++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; ++ ++ ctx->adata.key_inline = !!(inl_mask & 1); ++ ctx->cdata.key_inline = !!(inl_mask & 2); ++ ++ cnstr_shdsc_aead_decap(ctx->sh_desc_dec, &ctx->cdata, &ctx->adata, ++ ivsize, ctx->authsize, alg->caam.geniv, ++ is_rfc3686, nonce, ctx1_iv_off, true); ++ ++ if (!alg->caam.geniv) ++ goto skip_givenc; ++ ++ /* aead_givencrypt shared descriptor */ ++ if (desc_inline_query(DESC_QI_AEAD_GIVENC_LEN + ++ (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0), ++ DESC_JOB_IO_LEN, data_len, &inl_mask, ++ ARRAY_SIZE(data_len)) < 0) ++ return -EINVAL; ++ ++ if (inl_mask & 1) ++ ctx->adata.key_virt = ctx->key; ++ else ++ ctx->adata.key_dma = ctx->key_dma; ++ ++ if (inl_mask & 2) ++ ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; ++ else ++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; ++ ++ ctx->adata.key_inline = !!(inl_mask & 1); ++ ctx->cdata.key_inline = !!(inl_mask & 2); ++ ++ cnstr_shdsc_aead_givencap(ctx->sh_desc_enc, &ctx->cdata, &ctx->adata, ++ ivsize, ctx->authsize, is_rfc3686, nonce, ++ ctx1_iv_off, true); ++ ++skip_givenc: ++ return 0; ++} ++ ++static int aead_setauthsize(struct crypto_aead *authenc, unsigned int authsize) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(authenc); ++ ++ ctx->authsize = authsize; ++ aead_set_sh_desc(authenc); ++ ++ return 0; ++} ++ ++static int aead_setkey(struct crypto_aead *aead, const u8 *key, ++ unsigned int keylen) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ struct device *jrdev = ctx->jrdev; ++ struct crypto_authenc_keys keys; ++ int ret = 0; ++ ++ if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) ++ goto badkey; ++ ++#ifdef DEBUG ++ dev_err(jrdev, "keylen %d enckeylen %d authkeylen %d\n", ++ keys.authkeylen + keys.enckeylen, keys.enckeylen, ++ keys.authkeylen); ++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); ++#endif ++ ++ ret = gen_split_key(jrdev, ctx->key, &ctx->adata, keys.authkey, ++ keys.authkeylen, CAAM_MAX_KEY_SIZE - ++ keys.enckeylen); ++ if (ret) ++ goto badkey; ++ ++ /* postpend encryption key to auth split key */ ++ memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen); ++ dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->adata.keylen_pad + ++ keys.enckeylen, DMA_TO_DEVICE); ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, ++ ctx->adata.keylen_pad + keys.enckeylen, 1); ++#endif ++ ++ ctx->cdata.keylen = keys.enckeylen; ++ ++ ret = aead_set_sh_desc(aead); ++ if (ret) ++ goto badkey; ++ ++ /* Now update the driver contexts with the new shared descriptor */ ++ if (ctx->drv_ctx[ENCRYPT]) { ++ ret = caam_drv_ctx_update(ctx->drv_ctx[ENCRYPT], ++ ctx->sh_desc_enc); ++ if (ret) { ++ dev_err(jrdev, "driver enc context update failed\n"); ++ goto badkey; ++ } ++ } ++ ++ if (ctx->drv_ctx[DECRYPT]) { ++ ret = caam_drv_ctx_update(ctx->drv_ctx[DECRYPT], ++ ctx->sh_desc_dec); ++ if (ret) { ++ dev_err(jrdev, "driver dec context update failed\n"); ++ goto badkey; ++ } ++ } ++ ++ return ret; ++badkey: ++ crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); ++ return -EINVAL; ++} ++ ++static int tls_set_sh_desc(struct crypto_aead *tls) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(tls); ++ unsigned int ivsize = crypto_aead_ivsize(tls); ++ unsigned int blocksize = crypto_aead_blocksize(tls); ++ unsigned int assoclen = 13; /* always 13 bytes for TLS */ ++ unsigned int data_len[2]; ++ u32 inl_mask; ++ ++ if (!ctx->cdata.keylen || !ctx->authsize) ++ return 0; ++ ++ /* ++ * TLS 1.0 encrypt shared descriptor ++ * Job Descriptor and Shared Descriptor ++ * must fit into the 64-word Descriptor h/w Buffer ++ */ ++ data_len[0] = ctx->adata.keylen_pad; ++ data_len[1] = ctx->cdata.keylen; ++ ++ if (desc_inline_query(DESC_TLS10_ENC_LEN, DESC_JOB_IO_LEN, data_len, ++ &inl_mask, ARRAY_SIZE(data_len)) < 0) ++ return -EINVAL; ++ ++ if (inl_mask & 1) ++ ctx->adata.key_virt = ctx->key; ++ else ++ ctx->adata.key_dma = ctx->key_dma; ++ ++ if (inl_mask & 2) ++ ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; ++ else ++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; ++ ++ ctx->adata.key_inline = !!(inl_mask & 1); ++ ctx->cdata.key_inline = !!(inl_mask & 2); ++ ++ cnstr_shdsc_tls_encap(ctx->sh_desc_enc, &ctx->cdata, &ctx->adata, ++ assoclen, ivsize, ctx->authsize, blocksize); ++ ++ /* ++ * TLS 1.0 decrypt shared descriptor ++ * Keys do not fit inline, regardless of algorithms used ++ */ ++ ctx->adata.key_dma = ctx->key_dma; ++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; ++ ++ cnstr_shdsc_tls_decap(ctx->sh_desc_dec, &ctx->cdata, &ctx->adata, ++ assoclen, ivsize, ctx->authsize, blocksize); ++ ++ return 0; ++} ++ ++static int tls_setauthsize(struct crypto_aead *tls, unsigned int authsize) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(tls); ++ ++ ctx->authsize = authsize; ++ tls_set_sh_desc(tls); ++ ++ return 0; ++} ++ ++static int tls_setkey(struct crypto_aead *tls, const u8 *key, ++ unsigned int keylen) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(tls); ++ struct device *jrdev = ctx->jrdev; ++ struct crypto_authenc_keys keys; ++ int ret = 0; ++ ++ if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) ++ goto badkey; ++ ++#ifdef DEBUG ++ dev_err(jrdev, "keylen %d enckeylen %d authkeylen %d\n", ++ keys.authkeylen + keys.enckeylen, keys.enckeylen, ++ keys.authkeylen); ++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); ++#endif ++ ++ ret = gen_split_key(jrdev, ctx->key, &ctx->adata, keys.authkey, ++ keys.authkeylen, CAAM_MAX_KEY_SIZE - ++ keys.enckeylen); ++ if (ret) ++ goto badkey; ++ ++ /* postpend encryption key to auth split key */ ++ memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen); ++ dma_sync_single_for_device(jrdev, ctx->key_dma, ctx->adata.keylen_pad + ++ keys.enckeylen, DMA_TO_DEVICE); ++ ++#ifdef DEBUG ++ dev_err(jrdev, "split keylen %d split keylen padded %d\n", ++ ctx->adata.keylen, ctx->adata.keylen_pad); ++ print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, ++ ctx->adata.keylen_pad + keys.enckeylen, 1); ++#endif ++ ++ ctx->cdata.keylen = keys.enckeylen; ++ ++ ret = tls_set_sh_desc(tls); ++ if (ret) ++ goto badkey; ++ ++ /* Now update the driver contexts with the new shared descriptor */ ++ if (ctx->drv_ctx[ENCRYPT]) { ++ ret = caam_drv_ctx_update(ctx->drv_ctx[ENCRYPT], ++ ctx->sh_desc_enc); ++ if (ret) { ++ dev_err(jrdev, "driver enc context update failed\n"); ++ goto badkey; ++ } ++ } ++ ++ if (ctx->drv_ctx[DECRYPT]) { ++ ret = caam_drv_ctx_update(ctx->drv_ctx[DECRYPT], ++ ctx->sh_desc_dec); ++ if (ret) { ++ dev_err(jrdev, "driver dec context update failed\n"); ++ goto badkey; ++ } ++ } ++ ++ return ret; ++badkey: ++ crypto_aead_set_flags(tls, CRYPTO_TFM_RES_BAD_KEY_LEN); ++ return -EINVAL; ++} ++ ++static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, ++ const u8 *key, unsigned int keylen) ++{ ++ struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); ++ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(ablkcipher); ++ const char *alg_name = crypto_tfm_alg_name(tfm); ++ struct device *jrdev = ctx->jrdev; ++ unsigned int ivsize = crypto_ablkcipher_ivsize(ablkcipher); ++ u32 ctx1_iv_off = 0; ++ const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == ++ OP_ALG_AAI_CTR_MOD128); ++ const bool is_rfc3686 = (ctr_mode && strstr(alg_name, "rfc3686")); ++ int ret = 0; ++ ++ memcpy(ctx->key, key, keylen); ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); ++#endif ++ /* ++ * AES-CTR needs to load IV in CONTEXT1 reg ++ * at an offset of 128bits (16bytes) ++ * CONTEXT1[255:128] = IV ++ */ ++ if (ctr_mode) ++ ctx1_iv_off = 16; ++ ++ /* ++ * RFC3686 specific: ++ * | CONTEXT1[255:128] = {NONCE, IV, COUNTER} ++ * | *key = {KEY, NONCE} ++ */ ++ if (is_rfc3686) { ++ ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; ++ keylen -= CTR_RFC3686_NONCE_SIZE; ++ } ++ ++ dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, DMA_TO_DEVICE); ++ ctx->cdata.keylen = keylen; ++ ctx->cdata.key_virt = ctx->key; ++ ctx->cdata.key_inline = true; ++ ++ /* ablkcipher encrypt, decrypt, givencrypt shared descriptors */ ++ cnstr_shdsc_ablkcipher_encap(ctx->sh_desc_enc, &ctx->cdata, ivsize, ++ is_rfc3686, ctx1_iv_off); ++ cnstr_shdsc_ablkcipher_decap(ctx->sh_desc_dec, &ctx->cdata, ivsize, ++ is_rfc3686, ctx1_iv_off); ++ cnstr_shdsc_ablkcipher_givencap(ctx->sh_desc_givenc, &ctx->cdata, ++ ivsize, is_rfc3686, ctx1_iv_off); ++ ++ /* Now update the driver contexts with the new shared descriptor */ ++ if (ctx->drv_ctx[ENCRYPT]) { ++ ret = caam_drv_ctx_update(ctx->drv_ctx[ENCRYPT], ++ ctx->sh_desc_enc); ++ if (ret) { ++ dev_err(jrdev, "driver enc context update failed\n"); ++ goto badkey; ++ } ++ } ++ ++ if (ctx->drv_ctx[DECRYPT]) { ++ ret = caam_drv_ctx_update(ctx->drv_ctx[DECRYPT], ++ ctx->sh_desc_dec); ++ if (ret) { ++ dev_err(jrdev, "driver dec context update failed\n"); ++ goto badkey; ++ } ++ } ++ ++ if (ctx->drv_ctx[GIVENCRYPT]) { ++ ret = caam_drv_ctx_update(ctx->drv_ctx[GIVENCRYPT], ++ ctx->sh_desc_givenc); ++ if (ret) { ++ dev_err(jrdev, "driver givenc context update failed\n"); ++ goto badkey; ++ } ++ } ++ ++ return ret; ++badkey: ++ crypto_ablkcipher_set_flags(ablkcipher, CRYPTO_TFM_RES_BAD_KEY_LEN); ++ return -EINVAL; ++} ++ ++static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, ++ const u8 *key, unsigned int keylen) ++{ ++ struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); ++ struct device *jrdev = ctx->jrdev; ++ int ret = 0; ++ ++ if (keylen != 2 * AES_MIN_KEY_SIZE && keylen != 2 * AES_MAX_KEY_SIZE) { ++ crypto_ablkcipher_set_flags(ablkcipher, ++ CRYPTO_TFM_RES_BAD_KEY_LEN); ++ dev_err(jrdev, "key size mismatch\n"); ++ return -EINVAL; ++ } ++ ++ memcpy(ctx->key, key, keylen); ++ dma_sync_single_for_device(jrdev, ctx->key_dma, keylen, DMA_TO_DEVICE); ++ ctx->cdata.keylen = keylen; ++ ctx->cdata.key_virt = ctx->key; ++ ctx->cdata.key_inline = true; ++ ++ /* xts ablkcipher encrypt, decrypt shared descriptors */ ++ cnstr_shdsc_xts_ablkcipher_encap(ctx->sh_desc_enc, &ctx->cdata); ++ cnstr_shdsc_xts_ablkcipher_decap(ctx->sh_desc_dec, &ctx->cdata); ++ ++ /* Now update the driver contexts with the new shared descriptor */ ++ if (ctx->drv_ctx[ENCRYPT]) { ++ ret = caam_drv_ctx_update(ctx->drv_ctx[ENCRYPT], ++ ctx->sh_desc_enc); ++ if (ret) { ++ dev_err(jrdev, "driver enc context update failed\n"); ++ goto badkey; ++ } ++ } ++ ++ if (ctx->drv_ctx[DECRYPT]) { ++ ret = caam_drv_ctx_update(ctx->drv_ctx[DECRYPT], ++ ctx->sh_desc_dec); ++ if (ret) { ++ dev_err(jrdev, "driver dec context update failed\n"); ++ goto badkey; ++ } ++ } ++ ++ return ret; ++badkey: ++ crypto_ablkcipher_set_flags(ablkcipher, CRYPTO_TFM_RES_BAD_KEY_LEN); ++ return 0; ++} ++ ++/* ++ * aead_edesc - s/w-extended aead descriptor ++ * @src_nents: number of segments in input scatterlist ++ * @dst_nents: number of segments in output scatterlist ++ * @iv_dma: dma address of iv for checking continuity and link table ++ * @qm_sg_bytes: length of dma mapped h/w link table ++ * @qm_sg_dma: bus physical mapped address of h/w link table ++ * @assoclen: associated data length, in CAAM endianness ++ * @assoclen_dma: bus physical mapped address of req->assoclen ++ * @drv_req: driver-specific request structure ++ * @sgt: the h/w link table ++ */ ++struct aead_edesc { ++ int src_nents; ++ int dst_nents; ++ dma_addr_t iv_dma; ++ int qm_sg_bytes; ++ dma_addr_t qm_sg_dma; ++ unsigned int assoclen; ++ dma_addr_t assoclen_dma; ++ struct caam_drv_req drv_req; ++#define CAAM_QI_MAX_AEAD_SG \ ++ ((CAAM_QI_MEMCACHE_SIZE - offsetof(struct aead_edesc, sgt)) / \ ++ sizeof(struct qm_sg_entry)) ++ struct qm_sg_entry sgt[0]; ++}; ++ ++/* ++ * tls_edesc - s/w-extended tls descriptor ++ * @src_nents: number of segments in input scatterlist ++ * @dst_nents: number of segments in output scatterlist ++ * @iv_dma: dma address of iv for checking continuity and link table ++ * @qm_sg_bytes: length of dma mapped h/w link table ++ * @tmp: array of scatterlists used by 'scatterwalk_ffwd' ++ * @qm_sg_dma: bus physical mapped address of h/w link table ++ * @drv_req: driver-specific request structure ++ * @sgt: the h/w link table ++ */ ++struct tls_edesc { ++ int src_nents; ++ int dst_nents; ++ dma_addr_t iv_dma; ++ int qm_sg_bytes; ++ dma_addr_t qm_sg_dma; ++ struct scatterlist tmp[2]; ++ struct scatterlist *dst; ++ struct caam_drv_req drv_req; ++ struct qm_sg_entry sgt[0]; ++}; ++ ++/* ++ * ablkcipher_edesc - s/w-extended ablkcipher descriptor ++ * @src_nents: number of segments in input scatterlist ++ * @dst_nents: number of segments in output scatterlist ++ * @iv_dma: dma address of iv for checking continuity and link table ++ * @qm_sg_bytes: length of dma mapped h/w link table ++ * @qm_sg_dma: bus physical mapped address of h/w link table ++ * @drv_req: driver-specific request structure ++ * @sgt: the h/w link table ++ */ ++struct ablkcipher_edesc { ++ int src_nents; ++ int dst_nents; ++ dma_addr_t iv_dma; ++ int qm_sg_bytes; ++ dma_addr_t qm_sg_dma; ++ struct caam_drv_req drv_req; ++#define CAAM_QI_MAX_ABLKCIPHER_SG \ ++ ((CAAM_QI_MEMCACHE_SIZE - offsetof(struct ablkcipher_edesc, sgt)) / \ ++ sizeof(struct qm_sg_entry)) ++ struct qm_sg_entry sgt[0]; ++}; ++ ++static struct caam_drv_ctx *get_drv_ctx(struct caam_ctx *ctx, ++ enum optype type) ++{ ++ /* ++ * This function is called on the fast path with values of 'type' ++ * known at compile time. Invalid arguments are not expected and ++ * thus no checks are made. ++ */ ++ struct caam_drv_ctx *drv_ctx = ctx->drv_ctx[type]; ++ u32 *desc; ++ ++ if (unlikely(!drv_ctx)) { ++ spin_lock(&ctx->lock); ++ ++ /* Read again to check if some other core init drv_ctx */ ++ drv_ctx = ctx->drv_ctx[type]; ++ if (!drv_ctx) { ++ int cpu; ++ ++ if (type == ENCRYPT) ++ desc = ctx->sh_desc_enc; ++ else if (type == DECRYPT) ++ desc = ctx->sh_desc_dec; ++ else /* (type == GIVENCRYPT) */ ++ desc = ctx->sh_desc_givenc; ++ ++ cpu = smp_processor_id(); ++ drv_ctx = caam_drv_ctx_init(ctx->qidev, &cpu, desc); ++ if (likely(!IS_ERR_OR_NULL(drv_ctx))) ++ drv_ctx->op_type = type; ++ ++ ctx->drv_ctx[type] = drv_ctx; ++ } ++ ++ spin_unlock(&ctx->lock); ++ } ++ ++ return drv_ctx; ++} ++ ++static void caam_unmap(struct device *dev, struct scatterlist *src, ++ struct scatterlist *dst, int src_nents, ++ int dst_nents, dma_addr_t iv_dma, int ivsize, ++ enum optype op_type, dma_addr_t qm_sg_dma, ++ int qm_sg_bytes) ++{ ++ if (dst != src) { ++ if (src_nents) ++ dma_unmap_sg(dev, src, src_nents, DMA_TO_DEVICE); ++ dma_unmap_sg(dev, dst, dst_nents, DMA_FROM_DEVICE); ++ } else { ++ dma_unmap_sg(dev, src, src_nents, DMA_BIDIRECTIONAL); ++ } ++ ++ if (iv_dma) ++ dma_unmap_single(dev, iv_dma, ivsize, ++ op_type == GIVENCRYPT ? DMA_FROM_DEVICE : ++ DMA_TO_DEVICE); ++ if (qm_sg_bytes) ++ dma_unmap_single(dev, qm_sg_dma, qm_sg_bytes, DMA_TO_DEVICE); ++} ++ ++static void aead_unmap(struct device *dev, ++ struct aead_edesc *edesc, ++ struct aead_request *req) ++{ ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ int ivsize = crypto_aead_ivsize(aead); ++ ++ caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents, ++ edesc->iv_dma, ivsize, edesc->drv_req.drv_ctx->op_type, ++ edesc->qm_sg_dma, edesc->qm_sg_bytes); ++ dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE); ++} ++ ++static void tls_unmap(struct device *dev, ++ struct tls_edesc *edesc, ++ struct aead_request *req) ++{ ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ int ivsize = crypto_aead_ivsize(aead); ++ ++ caam_unmap(dev, req->src, edesc->dst, edesc->src_nents, ++ edesc->dst_nents, edesc->iv_dma, ivsize, ++ edesc->drv_req.drv_ctx->op_type, edesc->qm_sg_dma, ++ edesc->qm_sg_bytes); ++} ++ ++static void ablkcipher_unmap(struct device *dev, ++ struct ablkcipher_edesc *edesc, ++ struct ablkcipher_request *req) ++{ ++ struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); ++ int ivsize = crypto_ablkcipher_ivsize(ablkcipher); ++ ++ caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents, ++ edesc->iv_dma, ivsize, edesc->drv_req.drv_ctx->op_type, ++ edesc->qm_sg_dma, edesc->qm_sg_bytes); ++} ++ ++static void aead_done(struct caam_drv_req *drv_req, u32 status) ++{ ++ struct device *qidev; ++ struct aead_edesc *edesc; ++ struct aead_request *aead_req = drv_req->app_ctx; ++ struct crypto_aead *aead = crypto_aead_reqtfm(aead_req); ++ struct caam_ctx *caam_ctx = crypto_aead_ctx(aead); ++ int ecode = 0; ++ ++ qidev = caam_ctx->qidev; ++ ++ if (unlikely(status)) { ++ caam_jr_strstatus(qidev, status); ++ ecode = -EIO; ++ } ++ ++ edesc = container_of(drv_req, typeof(*edesc), drv_req); ++ aead_unmap(qidev, edesc, aead_req); ++ ++ aead_request_complete(aead_req, ecode); ++ qi_cache_free(edesc); ++} ++ ++/* ++ * allocate and map the aead extended descriptor ++ */ ++static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, ++ bool encrypt) ++{ ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead), ++ typeof(*alg), aead); ++ struct device *qidev = ctx->qidev; ++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? ++ GFP_KERNEL : GFP_ATOMIC; ++ int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; ++ struct aead_edesc *edesc; ++ dma_addr_t qm_sg_dma, iv_dma = 0; ++ int ivsize = 0; ++ unsigned int authsize = ctx->authsize; ++ int qm_sg_index = 0, qm_sg_ents = 0, qm_sg_bytes; ++ int in_len, out_len; ++ struct qm_sg_entry *sg_table, *fd_sgt; ++ struct caam_drv_ctx *drv_ctx; ++ enum optype op_type = encrypt ? ENCRYPT : DECRYPT; ++ ++ drv_ctx = get_drv_ctx(ctx, op_type); ++ if (unlikely(IS_ERR_OR_NULL(drv_ctx))) ++ return (struct aead_edesc *)drv_ctx; ++ ++ /* allocate space for base edesc and hw desc commands, link tables */ ++ edesc = qi_cache_alloc(GFP_DMA | flags); ++ if (unlikely(!edesc)) { ++ dev_err(qidev, "could not allocate extended descriptor\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ if (likely(req->src == req->dst)) { ++ src_nents = sg_nents_for_len(req->src, req->assoclen + ++ req->cryptlen + ++ (encrypt ? authsize : 0)); ++ if (unlikely(src_nents < 0)) { ++ dev_err(qidev, "Insufficient bytes (%d) in src S/G\n", ++ req->assoclen + req->cryptlen + ++ (encrypt ? authsize : 0)); ++ qi_cache_free(edesc); ++ return ERR_PTR(src_nents); ++ } ++ ++ mapped_src_nents = dma_map_sg(qidev, req->src, src_nents, ++ DMA_BIDIRECTIONAL); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(qidev, "unable to map source\n"); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ } else { ++ src_nents = sg_nents_for_len(req->src, req->assoclen + ++ req->cryptlen); ++ if (unlikely(src_nents < 0)) { ++ dev_err(qidev, "Insufficient bytes (%d) in src S/G\n", ++ req->assoclen + req->cryptlen); ++ qi_cache_free(edesc); ++ return ERR_PTR(src_nents); ++ } ++ ++ dst_nents = sg_nents_for_len(req->dst, req->assoclen + ++ req->cryptlen + ++ (encrypt ? authsize : ++ (-authsize))); ++ if (unlikely(dst_nents < 0)) { ++ dev_err(qidev, "Insufficient bytes (%d) in dst S/G\n", ++ req->assoclen + req->cryptlen + ++ (encrypt ? authsize : (-authsize))); ++ qi_cache_free(edesc); ++ return ERR_PTR(dst_nents); ++ } ++ ++ if (src_nents) { ++ mapped_src_nents = dma_map_sg(qidev, req->src, ++ src_nents, DMA_TO_DEVICE); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(qidev, "unable to map source\n"); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ } else { ++ mapped_src_nents = 0; ++ } ++ ++ mapped_dst_nents = dma_map_sg(qidev, req->dst, dst_nents, ++ DMA_FROM_DEVICE); ++ if (unlikely(!mapped_dst_nents)) { ++ dev_err(qidev, "unable to map destination\n"); ++ dma_unmap_sg(qidev, req->src, src_nents, DMA_TO_DEVICE); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ } ++ ++ if ((alg->caam.rfc3686 && encrypt) || !alg->caam.geniv) { ++ ivsize = crypto_aead_ivsize(aead); ++ iv_dma = dma_map_single(qidev, req->iv, ivsize, DMA_TO_DEVICE); ++ if (dma_mapping_error(qidev, iv_dma)) { ++ dev_err(qidev, "unable to map IV\n"); ++ caam_unmap(qidev, req->src, req->dst, src_nents, ++ dst_nents, 0, 0, op_type, 0, 0); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ } ++ ++ /* ++ * Create S/G table: req->assoclen, [IV,] req->src [, req->dst]. ++ * Input is not contiguous. ++ */ ++ qm_sg_ents = 1 + !!ivsize + mapped_src_nents + ++ (mapped_dst_nents > 1 ? mapped_dst_nents : 0); ++ if (unlikely(qm_sg_ents > CAAM_QI_MAX_AEAD_SG)) { ++ dev_err(qidev, "Insufficient S/G entries: %d > %lu\n", ++ qm_sg_ents, CAAM_QI_MAX_AEAD_SG); ++ caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, op_type, 0, 0); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ sg_table = &edesc->sgt[0]; ++ qm_sg_bytes = qm_sg_ents * sizeof(*sg_table); ++ ++ edesc->src_nents = src_nents; ++ edesc->dst_nents = dst_nents; ++ edesc->iv_dma = iv_dma; ++ edesc->drv_req.app_ctx = req; ++ edesc->drv_req.cbk = aead_done; ++ edesc->drv_req.drv_ctx = drv_ctx; ++ ++ edesc->assoclen = cpu_to_caam32(req->assoclen); ++ edesc->assoclen_dma = dma_map_single(qidev, &edesc->assoclen, 4, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(qidev, edesc->assoclen_dma)) { ++ dev_err(qidev, "unable to map assoclen\n"); ++ caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, op_type, 0, 0); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ dma_to_qm_sg_one(sg_table, edesc->assoclen_dma, 4, 0); ++ qm_sg_index++; ++ if (ivsize) { ++ dma_to_qm_sg_one(sg_table + qm_sg_index, iv_dma, ivsize, 0); ++ qm_sg_index++; ++ } ++ sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + qm_sg_index, 0); ++ qm_sg_index += mapped_src_nents; ++ ++ if (mapped_dst_nents > 1) ++ sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + ++ qm_sg_index, 0); ++ ++ qm_sg_dma = dma_map_single(qidev, sg_table, qm_sg_bytes, DMA_TO_DEVICE); ++ if (dma_mapping_error(qidev, qm_sg_dma)) { ++ dev_err(qidev, "unable to map S/G table\n"); ++ dma_unmap_single(qidev, edesc->assoclen_dma, 4, DMA_TO_DEVICE); ++ caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, op_type, 0, 0); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ edesc->qm_sg_dma = qm_sg_dma; ++ edesc->qm_sg_bytes = qm_sg_bytes; ++ ++ out_len = req->assoclen + req->cryptlen + ++ (encrypt ? ctx->authsize : (-ctx->authsize)); ++ in_len = 4 + ivsize + req->assoclen + req->cryptlen; ++ ++ fd_sgt = &edesc->drv_req.fd_sgt[0]; ++ dma_to_qm_sg_one_last_ext(&fd_sgt[1], qm_sg_dma, in_len, 0); ++ ++ if (req->dst == req->src) { ++ if (mapped_src_nents == 1) ++ dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(req->src), ++ out_len, 0); ++ else ++ dma_to_qm_sg_one_ext(&fd_sgt[0], qm_sg_dma + ++ (1 + !!ivsize) * sizeof(*sg_table), ++ out_len, 0); ++ } else if (mapped_dst_nents == 1) { ++ dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(req->dst), out_len, ++ 0); ++ } else { ++ dma_to_qm_sg_one_ext(&fd_sgt[0], qm_sg_dma + sizeof(*sg_table) * ++ qm_sg_index, out_len, 0); ++ } ++ ++ return edesc; ++} ++ ++static inline int aead_crypt(struct aead_request *req, bool encrypt) ++{ ++ struct aead_edesc *edesc; ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ int ret; ++ ++ if (unlikely(caam_congested)) ++ return -EAGAIN; ++ ++ /* allocate extended descriptor */ ++ edesc = aead_edesc_alloc(req, encrypt); ++ if (IS_ERR_OR_NULL(edesc)) ++ return PTR_ERR(edesc); ++ ++ /* Create and submit job descriptor */ ++ ret = caam_qi_enqueue(ctx->qidev, &edesc->drv_req); ++ if (!ret) { ++ ret = -EINPROGRESS; ++ } else { ++ aead_unmap(ctx->qidev, edesc, req); ++ qi_cache_free(edesc); ++ } ++ ++ return ret; ++} ++ ++static int aead_encrypt(struct aead_request *req) ++{ ++ return aead_crypt(req, true); ++} ++ ++static int aead_decrypt(struct aead_request *req) ++{ ++ return aead_crypt(req, false); ++} ++ ++static void tls_done(struct caam_drv_req *drv_req, u32 status) ++{ ++ struct device *qidev; ++ struct tls_edesc *edesc; ++ struct aead_request *aead_req = drv_req->app_ctx; ++ struct crypto_aead *aead = crypto_aead_reqtfm(aead_req); ++ struct caam_ctx *caam_ctx = crypto_aead_ctx(aead); ++ int ecode = 0; ++ ++ qidev = caam_ctx->qidev; ++ ++ if (unlikely(status)) { ++ caam_jr_strstatus(qidev, status); ++ ecode = -EIO; ++ } ++ ++ edesc = container_of(drv_req, typeof(*edesc), drv_req); ++ tls_unmap(qidev, edesc, aead_req); ++ ++ aead_request_complete(aead_req, ecode); ++ qi_cache_free(edesc); ++} ++ ++/* ++ * allocate and map the tls extended descriptor ++ */ ++static struct tls_edesc *tls_edesc_alloc(struct aead_request *req, bool encrypt) ++{ ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ unsigned int blocksize = crypto_aead_blocksize(aead); ++ unsigned int padsize, authsize; ++ struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead), ++ typeof(*alg), aead); ++ struct device *qidev = ctx->qidev; ++ gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | ++ CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC; ++ int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; ++ struct tls_edesc *edesc; ++ dma_addr_t qm_sg_dma, iv_dma = 0; ++ int ivsize = 0; ++ int qm_sg_index, qm_sg_ents = 0, qm_sg_bytes; ++ int in_len, out_len; ++ struct qm_sg_entry *sg_table, *fd_sgt; ++ struct caam_drv_ctx *drv_ctx; ++ enum optype op_type = encrypt ? ENCRYPT : DECRYPT; ++ struct scatterlist *dst; ++ ++ if (encrypt) { ++ padsize = blocksize - ((req->cryptlen + ctx->authsize) % ++ blocksize); ++ authsize = ctx->authsize + padsize; ++ } else { ++ authsize = ctx->authsize; ++ } ++ ++ drv_ctx = get_drv_ctx(ctx, op_type); ++ if (unlikely(IS_ERR_OR_NULL(drv_ctx))) ++ return (struct tls_edesc *)drv_ctx; ++ ++ /* allocate space for base edesc and hw desc commands, link tables */ ++ edesc = qi_cache_alloc(GFP_DMA | flags); ++ if (unlikely(!edesc)) { ++ dev_err(qidev, "could not allocate extended descriptor\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ if (likely(req->src == req->dst)) { ++ src_nents = sg_nents_for_len(req->src, req->assoclen + ++ req->cryptlen + ++ (encrypt ? authsize : 0)); ++ if (unlikely(src_nents < 0)) { ++ dev_err(qidev, "Insufficient bytes (%d) in src S/G\n", ++ req->assoclen + req->cryptlen + ++ (encrypt ? authsize : 0)); ++ qi_cache_free(edesc); ++ return ERR_PTR(src_nents); ++ } ++ ++ mapped_src_nents = dma_map_sg(qidev, req->src, src_nents, ++ DMA_BIDIRECTIONAL); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(qidev, "unable to map source\n"); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ dst = req->dst; ++ } else { ++ src_nents = sg_nents_for_len(req->src, req->assoclen + ++ req->cryptlen); ++ if (unlikely(src_nents < 0)) { ++ dev_err(qidev, "Insufficient bytes (%d) in src S/G\n", ++ req->assoclen + req->cryptlen); ++ qi_cache_free(edesc); ++ return ERR_PTR(src_nents); ++ } ++ ++ dst = scatterwalk_ffwd(edesc->tmp, req->dst, req->assoclen); ++ dst_nents = sg_nents_for_len(dst, req->cryptlen + ++ (encrypt ? authsize : 0)); ++ if (unlikely(dst_nents < 0)) { ++ dev_err(qidev, "Insufficient bytes (%d) in dst S/G\n", ++ req->cryptlen + ++ (encrypt ? authsize : 0)); ++ qi_cache_free(edesc); ++ return ERR_PTR(dst_nents); ++ } ++ ++ if (src_nents) { ++ mapped_src_nents = dma_map_sg(qidev, req->src, ++ src_nents, DMA_TO_DEVICE); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(qidev, "unable to map source\n"); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ } else { ++ mapped_src_nents = 0; ++ } ++ ++ mapped_dst_nents = dma_map_sg(qidev, dst, dst_nents, ++ DMA_FROM_DEVICE); ++ if (unlikely(!mapped_dst_nents)) { ++ dev_err(qidev, "unable to map destination\n"); ++ dma_unmap_sg(qidev, req->src, src_nents, DMA_TO_DEVICE); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ } ++ ++ ivsize = crypto_aead_ivsize(aead); ++ iv_dma = dma_map_single(qidev, req->iv, ivsize, DMA_TO_DEVICE); ++ if (dma_mapping_error(qidev, iv_dma)) { ++ dev_err(qidev, "unable to map IV\n"); ++ caam_unmap(qidev, req->src, dst, src_nents, dst_nents, 0, 0, ++ op_type, 0, 0); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ /* ++ * Create S/G table: IV, src, dst. ++ * Input is not contiguous. ++ */ ++ qm_sg_ents = 1 + mapped_src_nents + ++ (mapped_dst_nents > 1 ? mapped_dst_nents : 0); ++ sg_table = &edesc->sgt[0]; ++ qm_sg_bytes = qm_sg_ents * sizeof(*sg_table); ++ ++ edesc->src_nents = src_nents; ++ edesc->dst_nents = dst_nents; ++ edesc->dst = dst; ++ edesc->iv_dma = iv_dma; ++ edesc->drv_req.app_ctx = req; ++ edesc->drv_req.cbk = tls_done; ++ edesc->drv_req.drv_ctx = drv_ctx; ++ ++ dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0); ++ qm_sg_index = 1; ++ ++ sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + qm_sg_index, 0); ++ qm_sg_index += mapped_src_nents; ++ ++ if (mapped_dst_nents > 1) ++ sg_to_qm_sg_last(dst, mapped_dst_nents, sg_table + ++ qm_sg_index, 0); ++ ++ qm_sg_dma = dma_map_single(qidev, sg_table, qm_sg_bytes, DMA_TO_DEVICE); ++ if (dma_mapping_error(qidev, qm_sg_dma)) { ++ dev_err(qidev, "unable to map S/G table\n"); ++ caam_unmap(qidev, req->src, dst, src_nents, dst_nents, iv_dma, ++ ivsize, op_type, 0, 0); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ edesc->qm_sg_dma = qm_sg_dma; ++ edesc->qm_sg_bytes = qm_sg_bytes; ++ ++ out_len = req->cryptlen + (encrypt ? authsize : 0); ++ in_len = ivsize + req->assoclen + req->cryptlen; ++ ++ fd_sgt = &edesc->drv_req.fd_sgt[0]; ++ ++ dma_to_qm_sg_one_last_ext(&fd_sgt[1], qm_sg_dma, in_len, 0); ++ ++ if (req->dst == req->src) ++ dma_to_qm_sg_one_ext(&fd_sgt[0], qm_sg_dma + ++ (sg_nents_for_len(req->src, req->assoclen) + ++ 1) * sizeof(*sg_table), out_len, 0); ++ else if (mapped_dst_nents == 1) ++ dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(dst), out_len, 0); ++ else ++ dma_to_qm_sg_one_ext(&fd_sgt[0], qm_sg_dma + sizeof(*sg_table) * ++ qm_sg_index, out_len, 0); ++ ++ return edesc; ++} ++ ++static int tls_crypt(struct aead_request *req, bool encrypt) ++{ ++ struct tls_edesc *edesc; ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ int ret; ++ ++ if (unlikely(caam_congested)) ++ return -EAGAIN; ++ ++ edesc = tls_edesc_alloc(req, encrypt); ++ if (IS_ERR_OR_NULL(edesc)) ++ return PTR_ERR(edesc); ++ ++ ret = caam_qi_enqueue(ctx->qidev, &edesc->drv_req); ++ if (!ret) { ++ ret = -EINPROGRESS; ++ } else { ++ tls_unmap(ctx->qidev, edesc, req); ++ qi_cache_free(edesc); ++ } ++ ++ return ret; ++} ++ ++static int tls_encrypt(struct aead_request *req) ++{ ++ return tls_crypt(req, true); ++} ++ ++static int tls_decrypt(struct aead_request *req) ++{ ++ return tls_crypt(req, false); ++} ++ ++static void ablkcipher_done(struct caam_drv_req *drv_req, u32 status) ++{ ++ struct ablkcipher_edesc *edesc; ++ struct ablkcipher_request *req = drv_req->app_ctx; ++ struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); ++ struct caam_ctx *caam_ctx = crypto_ablkcipher_ctx(ablkcipher); ++ struct device *qidev = caam_ctx->qidev; ++ int ivsize = crypto_ablkcipher_ivsize(ablkcipher); ++ ++#ifdef DEBUG ++ dev_err(qidev, "%s %d: status 0x%x\n", __func__, __LINE__, status); ++#endif ++ ++ edesc = container_of(drv_req, typeof(*edesc), drv_req); ++ ++ if (status) ++ caam_jr_strstatus(qidev, status); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "dstiv @" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, req->info, ++ edesc->src_nents > 1 ? 100 : ivsize, 1); ++ caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, req->dst, ++ edesc->dst_nents > 1 ? 100 : req->nbytes, 1); ++#endif ++ ++ ablkcipher_unmap(qidev, edesc, req); ++ qi_cache_free(edesc); ++ ++ /* ++ * The crypto API expects us to set the IV (req->info) to the last ++ * ciphertext block. This is used e.g. by the CTS mode. ++ */ ++ scatterwalk_map_and_copy(req->info, req->dst, req->nbytes - ivsize, ++ ivsize, 0); ++ ++ ablkcipher_request_complete(req, status); ++} ++ ++static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request ++ *req, bool encrypt) ++{ ++ struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); ++ struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); ++ struct device *qidev = ctx->qidev; ++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? ++ GFP_KERNEL : GFP_ATOMIC; ++ int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; ++ struct ablkcipher_edesc *edesc; ++ dma_addr_t iv_dma; ++ bool in_contig; ++ int ivsize = crypto_ablkcipher_ivsize(ablkcipher); ++ int dst_sg_idx, qm_sg_ents; ++ struct qm_sg_entry *sg_table, *fd_sgt; ++ struct caam_drv_ctx *drv_ctx; ++ enum optype op_type = encrypt ? ENCRYPT : DECRYPT; ++ ++ drv_ctx = get_drv_ctx(ctx, op_type); ++ if (unlikely(IS_ERR_OR_NULL(drv_ctx))) ++ return (struct ablkcipher_edesc *)drv_ctx; ++ ++ src_nents = sg_nents_for_len(req->src, req->nbytes); ++ if (unlikely(src_nents < 0)) { ++ dev_err(qidev, "Insufficient bytes (%d) in src S/G\n", ++ req->nbytes); ++ return ERR_PTR(src_nents); ++ } ++ ++ if (unlikely(req->src != req->dst)) { ++ dst_nents = sg_nents_for_len(req->dst, req->nbytes); ++ if (unlikely(dst_nents < 0)) { ++ dev_err(qidev, "Insufficient bytes (%d) in dst S/G\n", ++ req->nbytes); ++ return ERR_PTR(dst_nents); ++ } ++ ++ mapped_src_nents = dma_map_sg(qidev, req->src, src_nents, ++ DMA_TO_DEVICE); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(qidev, "unable to map source\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ mapped_dst_nents = dma_map_sg(qidev, req->dst, dst_nents, ++ DMA_FROM_DEVICE); ++ if (unlikely(!mapped_dst_nents)) { ++ dev_err(qidev, "unable to map destination\n"); ++ dma_unmap_sg(qidev, req->src, src_nents, DMA_TO_DEVICE); ++ return ERR_PTR(-ENOMEM); ++ } ++ } else { ++ mapped_src_nents = dma_map_sg(qidev, req->src, src_nents, ++ DMA_BIDIRECTIONAL); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(qidev, "unable to map source\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ } ++ ++ iv_dma = dma_map_single(qidev, req->info, ivsize, DMA_TO_DEVICE); ++ if (dma_mapping_error(qidev, iv_dma)) { ++ dev_err(qidev, "unable to map IV\n"); ++ caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, ++ 0, 0, 0, 0); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ if (mapped_src_nents == 1 && ++ iv_dma + ivsize == sg_dma_address(req->src)) { ++ in_contig = true; ++ qm_sg_ents = 0; ++ } else { ++ in_contig = false; ++ qm_sg_ents = 1 + mapped_src_nents; ++ } ++ dst_sg_idx = qm_sg_ents; ++ ++ qm_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0; ++ if (unlikely(qm_sg_ents > CAAM_QI_MAX_ABLKCIPHER_SG)) { ++ dev_err(qidev, "Insufficient S/G entries: %d > %lu\n", ++ qm_sg_ents, CAAM_QI_MAX_ABLKCIPHER_SG); ++ caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, op_type, 0, 0); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ /* allocate space for base edesc and link tables */ ++ edesc = qi_cache_alloc(GFP_DMA | flags); ++ if (unlikely(!edesc)) { ++ dev_err(qidev, "could not allocate extended descriptor\n"); ++ caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, op_type, 0, 0); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ edesc->src_nents = src_nents; ++ edesc->dst_nents = dst_nents; ++ edesc->iv_dma = iv_dma; ++ sg_table = &edesc->sgt[0]; ++ edesc->qm_sg_bytes = qm_sg_ents * sizeof(*sg_table); ++ edesc->drv_req.app_ctx = req; ++ edesc->drv_req.cbk = ablkcipher_done; ++ edesc->drv_req.drv_ctx = drv_ctx; ++ ++ if (!in_contig) { ++ dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0); ++ sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + 1, 0); ++ } ++ ++ if (mapped_dst_nents > 1) ++ sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + ++ dst_sg_idx, 0); ++ ++ edesc->qm_sg_dma = dma_map_single(qidev, sg_table, edesc->qm_sg_bytes, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(qidev, edesc->qm_sg_dma)) { ++ dev_err(qidev, "unable to map S/G table\n"); ++ caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, op_type, 0, 0); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ fd_sgt = &edesc->drv_req.fd_sgt[0]; ++ ++ if (!in_contig) ++ dma_to_qm_sg_one_last_ext(&fd_sgt[1], edesc->qm_sg_dma, ++ ivsize + req->nbytes, 0); ++ else ++ dma_to_qm_sg_one_last(&fd_sgt[1], iv_dma, ivsize + req->nbytes, ++ 0); ++ ++ if (req->src == req->dst) { ++ if (!in_contig) ++ dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + ++ sizeof(*sg_table), req->nbytes, 0); ++ else ++ dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(req->src), ++ req->nbytes, 0); ++ } else if (mapped_dst_nents > 1) { ++ dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + dst_sg_idx * ++ sizeof(*sg_table), req->nbytes, 0); ++ } else { ++ dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(req->dst), ++ req->nbytes, 0); ++ } ++ ++ return edesc; ++} ++ ++static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( ++ struct skcipher_givcrypt_request *creq) ++{ ++ struct ablkcipher_request *req = &creq->creq; ++ struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); ++ struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); ++ struct device *qidev = ctx->qidev; ++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? ++ GFP_KERNEL : GFP_ATOMIC; ++ int src_nents, mapped_src_nents, dst_nents, mapped_dst_nents; ++ struct ablkcipher_edesc *edesc; ++ dma_addr_t iv_dma; ++ bool out_contig; ++ int ivsize = crypto_ablkcipher_ivsize(ablkcipher); ++ struct qm_sg_entry *sg_table, *fd_sgt; ++ int dst_sg_idx, qm_sg_ents; ++ struct caam_drv_ctx *drv_ctx; ++ ++ drv_ctx = get_drv_ctx(ctx, GIVENCRYPT); ++ if (unlikely(IS_ERR_OR_NULL(drv_ctx))) ++ return (struct ablkcipher_edesc *)drv_ctx; ++ ++ src_nents = sg_nents_for_len(req->src, req->nbytes); ++ if (unlikely(src_nents < 0)) { ++ dev_err(qidev, "Insufficient bytes (%d) in src S/G\n", ++ req->nbytes); ++ return ERR_PTR(src_nents); ++ } ++ ++ if (unlikely(req->src != req->dst)) { ++ dst_nents = sg_nents_for_len(req->dst, req->nbytes); ++ if (unlikely(dst_nents < 0)) { ++ dev_err(qidev, "Insufficient bytes (%d) in dst S/G\n", ++ req->nbytes); ++ return ERR_PTR(dst_nents); ++ } ++ ++ mapped_src_nents = dma_map_sg(qidev, req->src, src_nents, ++ DMA_TO_DEVICE); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(qidev, "unable to map source\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ mapped_dst_nents = dma_map_sg(qidev, req->dst, dst_nents, ++ DMA_FROM_DEVICE); ++ if (unlikely(!mapped_dst_nents)) { ++ dev_err(qidev, "unable to map destination\n"); ++ dma_unmap_sg(qidev, req->src, src_nents, DMA_TO_DEVICE); ++ return ERR_PTR(-ENOMEM); ++ } ++ } else { ++ mapped_src_nents = dma_map_sg(qidev, req->src, src_nents, ++ DMA_BIDIRECTIONAL); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(qidev, "unable to map source\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ dst_nents = src_nents; ++ mapped_dst_nents = src_nents; ++ } ++ ++ iv_dma = dma_map_single(qidev, creq->giv, ivsize, DMA_FROM_DEVICE); ++ if (dma_mapping_error(qidev, iv_dma)) { ++ dev_err(qidev, "unable to map IV\n"); ++ caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, 0, ++ 0, 0, 0, 0); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ qm_sg_ents = mapped_src_nents > 1 ? mapped_src_nents : 0; ++ dst_sg_idx = qm_sg_ents; ++ if (mapped_dst_nents == 1 && ++ iv_dma + ivsize == sg_dma_address(req->dst)) { ++ out_contig = true; ++ } else { ++ out_contig = false; ++ qm_sg_ents += 1 + mapped_dst_nents; ++ } ++ ++ if (unlikely(qm_sg_ents > CAAM_QI_MAX_ABLKCIPHER_SG)) { ++ dev_err(qidev, "Insufficient S/G entries: %d > %lu\n", ++ qm_sg_ents, CAAM_QI_MAX_ABLKCIPHER_SG); ++ caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, GIVENCRYPT, 0, 0); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ /* allocate space for base edesc and link tables */ ++ edesc = qi_cache_alloc(GFP_DMA | flags); ++ if (!edesc) { ++ dev_err(qidev, "could not allocate extended descriptor\n"); ++ caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, GIVENCRYPT, 0, 0); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ edesc->src_nents = src_nents; ++ edesc->dst_nents = dst_nents; ++ edesc->iv_dma = iv_dma; ++ sg_table = &edesc->sgt[0]; ++ edesc->qm_sg_bytes = qm_sg_ents * sizeof(*sg_table); ++ edesc->drv_req.app_ctx = req; ++ edesc->drv_req.cbk = ablkcipher_done; ++ edesc->drv_req.drv_ctx = drv_ctx; ++ ++ if (mapped_src_nents > 1) ++ sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table, 0); ++ ++ if (!out_contig) { ++ dma_to_qm_sg_one(sg_table + dst_sg_idx, iv_dma, ivsize, 0); ++ sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + ++ dst_sg_idx + 1, 0); ++ } ++ ++ edesc->qm_sg_dma = dma_map_single(qidev, sg_table, edesc->qm_sg_bytes, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(qidev, edesc->qm_sg_dma)) { ++ dev_err(qidev, "unable to map S/G table\n"); ++ caam_unmap(qidev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, GIVENCRYPT, 0, 0); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ fd_sgt = &edesc->drv_req.fd_sgt[0]; ++ ++ if (mapped_src_nents > 1) ++ dma_to_qm_sg_one_ext(&fd_sgt[1], edesc->qm_sg_dma, req->nbytes, ++ 0); ++ else ++ dma_to_qm_sg_one(&fd_sgt[1], sg_dma_address(req->src), ++ req->nbytes, 0); ++ ++ if (!out_contig) ++ dma_to_qm_sg_one_ext(&fd_sgt[0], edesc->qm_sg_dma + dst_sg_idx * ++ sizeof(*sg_table), ivsize + req->nbytes, ++ 0); ++ else ++ dma_to_qm_sg_one(&fd_sgt[0], sg_dma_address(req->dst), ++ ivsize + req->nbytes, 0); ++ ++ return edesc; ++} ++ ++static inline int ablkcipher_crypt(struct ablkcipher_request *req, bool encrypt) ++{ ++ struct ablkcipher_edesc *edesc; ++ struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); ++ struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); ++ int ret; ++ ++ if (unlikely(caam_congested)) ++ return -EAGAIN; ++ ++ /* allocate extended descriptor */ ++ edesc = ablkcipher_edesc_alloc(req, encrypt); ++ if (IS_ERR(edesc)) ++ return PTR_ERR(edesc); ++ ++ ret = caam_qi_enqueue(ctx->qidev, &edesc->drv_req); ++ if (!ret) { ++ ret = -EINPROGRESS; ++ } else { ++ ablkcipher_unmap(ctx->qidev, edesc, req); ++ qi_cache_free(edesc); ++ } ++ ++ return ret; ++} ++ ++static int ablkcipher_encrypt(struct ablkcipher_request *req) ++{ ++ return ablkcipher_crypt(req, true); ++} ++ ++static int ablkcipher_decrypt(struct ablkcipher_request *req) ++{ ++ return ablkcipher_crypt(req, false); ++} ++ ++static int ablkcipher_givencrypt(struct skcipher_givcrypt_request *creq) ++{ ++ struct ablkcipher_request *req = &creq->creq; ++ struct ablkcipher_edesc *edesc; ++ struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); ++ struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); ++ int ret; ++ ++ if (unlikely(caam_congested)) ++ return -EAGAIN; ++ ++ /* allocate extended descriptor */ ++ edesc = ablkcipher_giv_edesc_alloc(creq); ++ if (IS_ERR(edesc)) ++ return PTR_ERR(edesc); ++ ++ ret = caam_qi_enqueue(ctx->qidev, &edesc->drv_req); ++ if (!ret) { ++ ret = -EINPROGRESS; ++ } else { ++ ablkcipher_unmap(ctx->qidev, edesc, req); ++ qi_cache_free(edesc); ++ } ++ ++ return ret; ++} ++ ++#define template_ablkcipher template_u.ablkcipher ++struct caam_alg_template { ++ char name[CRYPTO_MAX_ALG_NAME]; ++ char driver_name[CRYPTO_MAX_ALG_NAME]; ++ unsigned int blocksize; ++ u32 type; ++ union { ++ struct ablkcipher_alg ablkcipher; ++ } template_u; ++ u32 class1_alg_type; ++ u32 class2_alg_type; ++}; ++ ++static struct caam_alg_template driver_algs[] = { ++ /* ablkcipher descriptor */ ++ { ++ .name = "cbc(aes)", ++ .driver_name = "cbc-aes-caam-qi", ++ .blocksize = AES_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_GIVCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .givencrypt = ablkcipher_givencrypt, ++ .geniv = "", ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ }, ++ { ++ .name = "cbc(des3_ede)", ++ .driver_name = "cbc-3des-caam-qi", ++ .blocksize = DES3_EDE_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_GIVCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .givencrypt = ablkcipher_givencrypt, ++ .geniv = "", ++ .min_keysize = DES3_EDE_KEY_SIZE, ++ .max_keysize = DES3_EDE_KEY_SIZE, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ }, ++ { ++ .name = "cbc(des)", ++ .driver_name = "cbc-des-caam-qi", ++ .blocksize = DES_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_GIVCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .givencrypt = ablkcipher_givencrypt, ++ .geniv = "", ++ .min_keysize = DES_KEY_SIZE, ++ .max_keysize = DES_KEY_SIZE, ++ .ivsize = DES_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ }, ++ { ++ .name = "ctr(aes)", ++ .driver_name = "ctr-aes-caam-qi", ++ .blocksize = 1, ++ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "chainiv", ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, ++ }, ++ { ++ .name = "rfc3686(ctr(aes))", ++ .driver_name = "rfc3686-ctr-aes-caam-qi", ++ .blocksize = 1, ++ .type = CRYPTO_ALG_TYPE_GIVCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .givencrypt = ablkcipher_givencrypt, ++ .geniv = "", ++ .min_keysize = AES_MIN_KEY_SIZE + ++ CTR_RFC3686_NONCE_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE + ++ CTR_RFC3686_NONCE_SIZE, ++ .ivsize = CTR_RFC3686_IV_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, ++ }, ++ { ++ .name = "xts(aes)", ++ .driver_name = "xts-aes-caam-qi", ++ .blocksize = AES_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .template_ablkcipher = { ++ .setkey = xts_ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "eseqiv", ++ .min_keysize = 2 * AES_MIN_KEY_SIZE, ++ .max_keysize = 2 * AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XTS, ++ }, ++}; ++ ++static struct caam_aead_alg driver_aeads[] = { ++ /* single-pass ipsec_esp descriptor */ ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(md5),cbc(aes))", ++ .cra_driver_name = "authenc-hmac-md5-" ++ "cbc-aes-caam-qi", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = MD5_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_MD5 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(md5)," ++ "cbc(aes)))", ++ .cra_driver_name = "echainiv-authenc-hmac-md5-" ++ "cbc-aes-caam-qi", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = MD5_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_MD5 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha1),cbc(aes))", ++ .cra_driver_name = "authenc-hmac-sha1-" ++ "cbc-aes-caam-qi", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA1_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha1)," ++ "cbc(aes)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha1-cbc-aes-caam-qi", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA1_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha224),cbc(aes))", ++ .cra_driver_name = "authenc-hmac-sha224-" ++ "cbc-aes-caam-qi", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA224_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha224)," ++ "cbc(aes)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha224-cbc-aes-caam-qi", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA224_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha256),cbc(aes))", ++ .cra_driver_name = "authenc-hmac-sha256-" ++ "cbc-aes-caam-qi", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA256_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha256)," ++ "cbc(aes)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha256-cbc-aes-" ++ "caam-qi", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA256_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha384),cbc(aes))", ++ .cra_driver_name = "authenc-hmac-sha384-" ++ "cbc-aes-caam-qi", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA384_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha384)," ++ "cbc(aes)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha384-cbc-aes-" ++ "caam-qi", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA384_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha512),cbc(aes))", ++ .cra_driver_name = "authenc-hmac-sha512-" ++ "cbc-aes-caam-qi", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA512_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha512)," ++ "cbc(aes)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha512-cbc-aes-" ++ "caam-qi", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA512_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(md5),cbc(des3_ede))", ++ .cra_driver_name = "authenc-hmac-md5-" ++ "cbc-des3_ede-caam-qi", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = MD5_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_MD5 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(md5)," ++ "cbc(des3_ede)))", ++ .cra_driver_name = "echainiv-authenc-hmac-md5-" ++ "cbc-des3_ede-caam-qi", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = MD5_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_MD5 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha1)," ++ "cbc(des3_ede))", ++ .cra_driver_name = "authenc-hmac-sha1-" ++ "cbc-des3_ede-caam-qi", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA1_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha1)," ++ "cbc(des3_ede)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha1-" ++ "cbc-des3_ede-caam-qi", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA1_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha224)," ++ "cbc(des3_ede))", ++ .cra_driver_name = "authenc-hmac-sha224-" ++ "cbc-des3_ede-caam-qi", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA224_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha224)," ++ "cbc(des3_ede)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha224-" ++ "cbc-des3_ede-caam-qi", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA224_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha256)," ++ "cbc(des3_ede))", ++ .cra_driver_name = "authenc-hmac-sha256-" ++ "cbc-des3_ede-caam-qi", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA256_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha256)," ++ "cbc(des3_ede)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha256-" ++ "cbc-des3_ede-caam-qi", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA256_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha384)," ++ "cbc(des3_ede))", ++ .cra_driver_name = "authenc-hmac-sha384-" ++ "cbc-des3_ede-caam-qi", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA384_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha384)," ++ "cbc(des3_ede)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha384-" ++ "cbc-des3_ede-caam-qi", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA384_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha512)," ++ "cbc(des3_ede))", ++ .cra_driver_name = "authenc-hmac-sha512-" ++ "cbc-des3_ede-caam-qi", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA512_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha512)," ++ "cbc(des3_ede)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha512-" ++ "cbc-des3_ede-caam-qi", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA512_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(md5),cbc(des))", ++ .cra_driver_name = "authenc-hmac-md5-" ++ "cbc-des-caam-qi", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = MD5_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_MD5 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(md5)," ++ "cbc(des)))", ++ .cra_driver_name = "echainiv-authenc-hmac-md5-" ++ "cbc-des-caam-qi", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = MD5_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_MD5 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha1),cbc(des))", ++ .cra_driver_name = "authenc-hmac-sha1-" ++ "cbc-des-caam-qi", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA1_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha1)," ++ "cbc(des)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha1-cbc-des-caam-qi", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA1_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha224),cbc(des))", ++ .cra_driver_name = "authenc-hmac-sha224-" ++ "cbc-des-caam-qi", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA224_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha224)," ++ "cbc(des)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha224-cbc-des-" ++ "caam-qi", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA224_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha256),cbc(des))", ++ .cra_driver_name = "authenc-hmac-sha256-" ++ "cbc-des-caam-qi", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA256_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha256)," ++ "cbc(des)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha256-cbc-des-" ++ "caam-qi", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA256_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha384),cbc(des))", ++ .cra_driver_name = "authenc-hmac-sha384-" ++ "cbc-des-caam-qi", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA384_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha384)," ++ "cbc(des)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha384-cbc-des-" ++ "caam-qi", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA384_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha512),cbc(des))", ++ .cra_driver_name = "authenc-hmac-sha512-" ++ "cbc-des-caam-qi", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA512_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha512)," ++ "cbc(des)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha512-cbc-des-" ++ "caam-qi", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA512_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "tls10(hmac(sha1),cbc(aes))", ++ .cra_driver_name = "tls10-hmac-sha1-cbc-aes-caam-qi", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = tls_setkey, ++ .setauthsize = tls_setauthsize, ++ .encrypt = tls_encrypt, ++ .decrypt = tls_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA1_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ } ++ } ++}; ++ ++struct caam_crypto_alg { ++ struct list_head entry; ++ struct crypto_alg crypto_alg; ++ struct caam_alg_entry caam; ++}; ++ ++static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam) ++{ ++ struct caam_drv_private *priv; ++ /* Digest sizes for MD5, SHA1, SHA-224, SHA-256, SHA-384, SHA-512 */ ++ static const u8 digest_size[] = { ++ MD5_DIGEST_SIZE, ++ SHA1_DIGEST_SIZE, ++ SHA224_DIGEST_SIZE, ++ SHA256_DIGEST_SIZE, ++ SHA384_DIGEST_SIZE, ++ SHA512_DIGEST_SIZE ++ }; ++ u8 op_id; ++ ++ /* ++ * distribute tfms across job rings to ensure in-order ++ * crypto request processing per tfm ++ */ ++ ctx->jrdev = caam_jr_alloc(); ++ if (IS_ERR(ctx->jrdev)) { ++ pr_err("Job Ring Device allocation for transform failed\n"); ++ return PTR_ERR(ctx->jrdev); ++ } ++ ++ ctx->key_dma = dma_map_single(ctx->jrdev, ctx->key, sizeof(ctx->key), ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(ctx->jrdev, ctx->key_dma)) { ++ dev_err(ctx->jrdev, "unable to map key\n"); ++ caam_jr_free(ctx->jrdev); ++ return -ENOMEM; ++ } ++ ++ /* copy descriptor header template value */ ++ ctx->cdata.algtype = OP_TYPE_CLASS1_ALG | caam->class1_alg_type; ++ ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam->class2_alg_type; ++ ++ if (ctx->adata.algtype) { ++ op_id = (ctx->adata.algtype & OP_ALG_ALGSEL_SUBMASK) ++ >> OP_ALG_ALGSEL_SHIFT; ++ if (op_id < ARRAY_SIZE(digest_size)) { ++ ctx->authsize = digest_size[op_id]; ++ } else { ++ dev_err(ctx->jrdev, ++ "incorrect op_id %d; must be less than %zu\n", ++ op_id, ARRAY_SIZE(digest_size)); ++ caam_jr_free(ctx->jrdev); ++ return -EINVAL; ++ } ++ } else { ++ ctx->authsize = 0; ++ } ++ ++ priv = dev_get_drvdata(ctx->jrdev->parent); ++ ctx->qidev = priv->qidev; ++ ++ spin_lock_init(&ctx->lock); ++ ctx->drv_ctx[ENCRYPT] = NULL; ++ ctx->drv_ctx[DECRYPT] = NULL; ++ ctx->drv_ctx[GIVENCRYPT] = NULL; ++ ++ return 0; ++} ++ ++static int caam_cra_init(struct crypto_tfm *tfm) ++{ ++ struct crypto_alg *alg = tfm->__crt_alg; ++ struct caam_crypto_alg *caam_alg = container_of(alg, typeof(*caam_alg), ++ crypto_alg); ++ struct caam_ctx *ctx = crypto_tfm_ctx(tfm); ++ ++ return caam_init_common(ctx, &caam_alg->caam); ++} ++ ++static int caam_aead_init(struct crypto_aead *tfm) ++{ ++ struct aead_alg *alg = crypto_aead_alg(tfm); ++ struct caam_aead_alg *caam_alg = container_of(alg, typeof(*caam_alg), ++ aead); ++ struct caam_ctx *ctx = crypto_aead_ctx(tfm); ++ ++ return caam_init_common(ctx, &caam_alg->caam); ++} ++ ++static void caam_exit_common(struct caam_ctx *ctx) ++{ ++ caam_drv_ctx_rel(ctx->drv_ctx[ENCRYPT]); ++ caam_drv_ctx_rel(ctx->drv_ctx[DECRYPT]); ++ caam_drv_ctx_rel(ctx->drv_ctx[GIVENCRYPT]); ++ ++ dma_unmap_single(ctx->jrdev, ctx->key_dma, sizeof(ctx->key), ++ DMA_TO_DEVICE); ++ ++ caam_jr_free(ctx->jrdev); ++} ++ ++static void caam_cra_exit(struct crypto_tfm *tfm) ++{ ++ caam_exit_common(crypto_tfm_ctx(tfm)); ++} ++ ++static void caam_aead_exit(struct crypto_aead *tfm) ++{ ++ caam_exit_common(crypto_aead_ctx(tfm)); ++} ++ ++static struct list_head alg_list; ++static void __exit caam_qi_algapi_exit(void) ++{ ++ struct caam_crypto_alg *t_alg, *n; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) { ++ struct caam_aead_alg *t_alg = driver_aeads + i; ++ ++ if (t_alg->registered) ++ crypto_unregister_aead(&t_alg->aead); ++ } ++ ++ if (!alg_list.next) ++ return; ++ ++ list_for_each_entry_safe(t_alg, n, &alg_list, entry) { ++ crypto_unregister_alg(&t_alg->crypto_alg); ++ list_del(&t_alg->entry); ++ kfree(t_alg); ++ } ++} ++ ++static struct caam_crypto_alg *caam_alg_alloc(struct caam_alg_template ++ *template) ++{ ++ struct caam_crypto_alg *t_alg; ++ struct crypto_alg *alg; ++ ++ t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL); ++ if (!t_alg) ++ return ERR_PTR(-ENOMEM); ++ ++ alg = &t_alg->crypto_alg; ++ ++ snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name); ++ snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", ++ template->driver_name); ++ alg->cra_module = THIS_MODULE; ++ alg->cra_init = caam_cra_init; ++ alg->cra_exit = caam_cra_exit; ++ alg->cra_priority = CAAM_CRA_PRIORITY; ++ alg->cra_blocksize = template->blocksize; ++ alg->cra_alignmask = 0; ++ alg->cra_ctxsize = sizeof(struct caam_ctx); ++ alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | ++ template->type; ++ switch (template->type) { ++ case CRYPTO_ALG_TYPE_GIVCIPHER: ++ alg->cra_type = &crypto_givcipher_type; ++ alg->cra_ablkcipher = template->template_ablkcipher; ++ break; ++ case CRYPTO_ALG_TYPE_ABLKCIPHER: ++ alg->cra_type = &crypto_ablkcipher_type; ++ alg->cra_ablkcipher = template->template_ablkcipher; ++ break; ++ } ++ ++ t_alg->caam.class1_alg_type = template->class1_alg_type; ++ t_alg->caam.class2_alg_type = template->class2_alg_type; ++ ++ return t_alg; ++} ++ ++static void caam_aead_alg_init(struct caam_aead_alg *t_alg) ++{ ++ struct aead_alg *alg = &t_alg->aead; ++ ++ alg->base.cra_module = THIS_MODULE; ++ alg->base.cra_priority = CAAM_CRA_PRIORITY; ++ alg->base.cra_ctxsize = sizeof(struct caam_ctx); ++ alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY; ++ ++ alg->init = caam_aead_init; ++ alg->exit = caam_aead_exit; ++} ++ ++static int __init caam_qi_algapi_init(void) ++{ ++ struct device_node *dev_node; ++ struct platform_device *pdev; ++ struct device *ctrldev; ++ struct caam_drv_private *priv; ++ int i = 0, err = 0; ++ u32 cha_vid, cha_inst, des_inst, aes_inst, md_inst; ++ unsigned int md_limit = SHA512_DIGEST_SIZE; ++ bool registered = false; ++ ++ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0"); ++ if (!dev_node) { ++ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0"); ++ if (!dev_node) ++ return -ENODEV; ++ } ++ ++ pdev = of_find_device_by_node(dev_node); ++ of_node_put(dev_node); ++ if (!pdev) ++ return -ENODEV; ++ ++ ctrldev = &pdev->dev; ++ priv = dev_get_drvdata(ctrldev); ++ ++ /* ++ * If priv is NULL, it's probably because the caam driver wasn't ++ * properly initialized (e.g. RNG4 init failed). Thus, bail out here. ++ */ ++ if (!priv || !priv->qi_present) ++ return -ENODEV; ++ ++ if (caam_dpaa2) { ++ dev_info(ctrldev, "caam/qi frontend driver not suitable for DPAA 2.x, aborting...\n"); ++ return -ENODEV; ++ } ++ ++ INIT_LIST_HEAD(&alg_list); ++ ++ /* ++ * Register crypto algorithms the device supports. ++ * First, detect presence and attributes of DES, AES, and MD blocks. ++ */ ++ cha_vid = rd_reg32(&priv->ctrl->perfmon.cha_id_ls); ++ cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls); ++ des_inst = (cha_inst & CHA_ID_LS_DES_MASK) >> CHA_ID_LS_DES_SHIFT; ++ aes_inst = (cha_inst & CHA_ID_LS_AES_MASK) >> CHA_ID_LS_AES_SHIFT; ++ md_inst = (cha_inst & CHA_ID_LS_MD_MASK) >> CHA_ID_LS_MD_SHIFT; ++ ++ /* If MD is present, limit digest size based on LP256 */ ++ if (md_inst && ((cha_vid & CHA_ID_LS_MD_MASK) == CHA_ID_LS_MD_LP256)) ++ md_limit = SHA256_DIGEST_SIZE; ++ ++ for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { ++ struct caam_crypto_alg *t_alg; ++ struct caam_alg_template *alg = driver_algs + i; ++ u32 alg_sel = alg->class1_alg_type & OP_ALG_ALGSEL_MASK; ++ ++ /* Skip DES algorithms if not supported by device */ ++ if (!des_inst && ++ ((alg_sel == OP_ALG_ALGSEL_3DES) || ++ (alg_sel == OP_ALG_ALGSEL_DES))) ++ continue; ++ ++ /* Skip AES algorithms if not supported by device */ ++ if (!aes_inst && (alg_sel == OP_ALG_ALGSEL_AES)) ++ continue; ++ ++ t_alg = caam_alg_alloc(alg); ++ if (IS_ERR(t_alg)) { ++ err = PTR_ERR(t_alg); ++ dev_warn(priv->qidev, "%s alg allocation failed\n", ++ alg->driver_name); ++ continue; ++ } ++ ++ err = crypto_register_alg(&t_alg->crypto_alg); ++ if (err) { ++ dev_warn(priv->qidev, "%s alg registration failed\n", ++ t_alg->crypto_alg.cra_driver_name); ++ kfree(t_alg); ++ continue; ++ } ++ ++ list_add_tail(&t_alg->entry, &alg_list); ++ registered = true; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) { ++ struct caam_aead_alg *t_alg = driver_aeads + i; ++ u32 c1_alg_sel = t_alg->caam.class1_alg_type & ++ OP_ALG_ALGSEL_MASK; ++ u32 c2_alg_sel = t_alg->caam.class2_alg_type & ++ OP_ALG_ALGSEL_MASK; ++ u32 alg_aai = t_alg->caam.class1_alg_type & OP_ALG_AAI_MASK; ++ ++ /* Skip DES algorithms if not supported by device */ ++ if (!des_inst && ++ ((c1_alg_sel == OP_ALG_ALGSEL_3DES) || ++ (c1_alg_sel == OP_ALG_ALGSEL_DES))) ++ continue; ++ ++ /* Skip AES algorithms if not supported by device */ ++ if (!aes_inst && (c1_alg_sel == OP_ALG_ALGSEL_AES)) ++ continue; ++ ++ /* ++ * Check support for AES algorithms not available ++ * on LP devices. ++ */ ++ if (((cha_vid & CHA_ID_LS_AES_MASK) == CHA_ID_LS_AES_LP) && ++ (alg_aai == OP_ALG_AAI_GCM)) ++ continue; ++ ++ /* ++ * Skip algorithms requiring message digests ++ * if MD or MD size is not supported by device. ++ */ ++ if (c2_alg_sel && ++ (!md_inst || (t_alg->aead.maxauthsize > md_limit))) ++ continue; ++ ++ caam_aead_alg_init(t_alg); ++ ++ err = crypto_register_aead(&t_alg->aead); ++ if (err) { ++ pr_warn("%s alg registration failed\n", ++ t_alg->aead.base.cra_driver_name); ++ continue; ++ } ++ ++ t_alg->registered = true; ++ registered = true; ++ } ++ ++ if (registered) ++ dev_info(priv->qidev, "algorithms registered in /proc/crypto\n"); ++ ++ return err; ++} ++ ++module_init(caam_qi_algapi_init); ++module_exit(caam_qi_algapi_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Support for crypto API using CAAM-QI backend"); ++MODULE_AUTHOR("Freescale Semiconductor"); +diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c +new file mode 100644 +index 00000000..f0316346 +--- /dev/null ++++ b/drivers/crypto/caam/caamalg_qi2.c +@@ -0,0 +1,4428 @@ ++/* ++ * Copyright 2015-2016 Freescale Semiconductor Inc. ++ * Copyright 2017 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the names of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "compat.h" ++#include "regs.h" ++#include "caamalg_qi2.h" ++#include "dpseci_cmd.h" ++#include "desc_constr.h" ++#include "error.h" ++#include "sg_sw_sec4.h" ++#include "sg_sw_qm2.h" ++#include "key_gen.h" ++#include "caamalg_desc.h" ++#include "../../../drivers/staging/fsl-mc/include/mc.h" ++#include "../../../drivers/staging/fsl-mc/include/dpaa2-io.h" ++#include "../../../drivers/staging/fsl-mc/include/dpaa2-fd.h" ++ ++#define CAAM_CRA_PRIORITY 2000 ++ ++/* max key is sum of AES_MAX_KEY_SIZE, max split key size */ ++#define CAAM_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + CTR_RFC3686_NONCE_SIZE + \ ++ SHA512_DIGEST_SIZE * 2) ++ ++#ifndef CONFIG_CRYPTO_DEV_FSL_CAAM ++bool caam_little_end; ++EXPORT_SYMBOL(caam_little_end); ++bool caam_imx; ++EXPORT_SYMBOL(caam_imx); ++#endif ++ ++/* ++ * This is a a cache of buffers, from which the users of CAAM QI driver ++ * can allocate short buffers. It's speedier than doing kmalloc on the hotpath. ++ * NOTE: A more elegant solution would be to have some headroom in the frames ++ * being processed. This can be added by the dpaa2-eth driver. This would ++ * pose a problem for userspace application processing which cannot ++ * know of this limitation. So for now, this will work. ++ * NOTE: The memcache is SMP-safe. No need to handle spinlocks in-here ++ */ ++static struct kmem_cache *qi_cache; ++ ++struct caam_alg_entry { ++ struct device *dev; ++ int class1_alg_type; ++ int class2_alg_type; ++ bool rfc3686; ++ bool geniv; ++}; ++ ++struct caam_aead_alg { ++ struct aead_alg aead; ++ struct caam_alg_entry caam; ++ bool registered; ++}; ++ ++/** ++ * caam_ctx - per-session context ++ * @flc: Flow Contexts array ++ * @key: virtual address of the key(s): [authentication key], encryption key ++ * @key_dma: I/O virtual address of the key ++ * @dev: dpseci device ++ * @adata: authentication algorithm details ++ * @cdata: encryption algorithm details ++ * @authsize: authentication tag (a.k.a. ICV / MAC) size ++ */ ++struct caam_ctx { ++ struct caam_flc flc[NUM_OP]; ++ u8 key[CAAM_MAX_KEY_SIZE]; ++ dma_addr_t key_dma; ++ struct device *dev; ++ struct alginfo adata; ++ struct alginfo cdata; ++ unsigned int authsize; ++}; ++ ++void *dpaa2_caam_iova_to_virt(struct dpaa2_caam_priv *priv, ++ dma_addr_t iova_addr) ++{ ++ phys_addr_t phys_addr; ++ ++ phys_addr = priv->domain ? iommu_iova_to_phys(priv->domain, iova_addr) : ++ iova_addr; ++ ++ return phys_to_virt(phys_addr); ++} ++ ++/* ++ * qi_cache_alloc - Allocate buffers from CAAM-QI cache ++ * ++ * Allocate data on the hotpath. Instead of using kmalloc, one can use the ++ * services of the CAAM QI memory cache (backed by kmem_cache). The buffers ++ * will have a size of CAAM_QI_MEMCACHE_SIZE, which should be sufficient for ++ * hosting 16 SG entries. ++ * ++ * @flags - flags that would be used for the equivalent kmalloc(..) call ++ * ++ * Returns a pointer to a retrieved buffer on success or NULL on failure. ++ */ ++static inline void *qi_cache_alloc(gfp_t flags) ++{ ++ return kmem_cache_alloc(qi_cache, flags); ++} ++ ++/* ++ * qi_cache_free - Frees buffers allocated from CAAM-QI cache ++ * ++ * @obj - buffer previously allocated by qi_cache_alloc ++ * ++ * No checking is being done, the call is a passthrough call to ++ * kmem_cache_free(...) ++ */ ++static inline void qi_cache_free(void *obj) ++{ ++ kmem_cache_free(qi_cache, obj); ++} ++ ++static struct caam_request *to_caam_req(struct crypto_async_request *areq) ++{ ++ switch (crypto_tfm_alg_type(areq->tfm)) { ++ case CRYPTO_ALG_TYPE_ABLKCIPHER: ++ case CRYPTO_ALG_TYPE_GIVCIPHER: ++ return ablkcipher_request_ctx(ablkcipher_request_cast(areq)); ++ case CRYPTO_ALG_TYPE_AEAD: ++ return aead_request_ctx(container_of(areq, struct aead_request, ++ base)); ++ default: ++ return ERR_PTR(-EINVAL); ++ } ++} ++ ++static void caam_unmap(struct device *dev, struct scatterlist *src, ++ struct scatterlist *dst, int src_nents, ++ int dst_nents, dma_addr_t iv_dma, int ivsize, ++ enum optype op_type, dma_addr_t qm_sg_dma, ++ int qm_sg_bytes) ++{ ++ if (dst != src) { ++ if (src_nents) ++ dma_unmap_sg(dev, src, src_nents, DMA_TO_DEVICE); ++ dma_unmap_sg(dev, dst, dst_nents, DMA_FROM_DEVICE); ++ } else { ++ dma_unmap_sg(dev, src, src_nents, DMA_BIDIRECTIONAL); ++ } ++ ++ if (iv_dma) ++ dma_unmap_single(dev, iv_dma, ivsize, ++ op_type == GIVENCRYPT ? DMA_FROM_DEVICE : ++ DMA_TO_DEVICE); ++ ++ if (qm_sg_bytes) ++ dma_unmap_single(dev, qm_sg_dma, qm_sg_bytes, DMA_TO_DEVICE); ++} ++ ++static int aead_set_sh_desc(struct crypto_aead *aead) ++{ ++ struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead), ++ typeof(*alg), aead); ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ unsigned int ivsize = crypto_aead_ivsize(aead); ++ struct device *dev = ctx->dev; ++ struct caam_flc *flc; ++ u32 *desc; ++ u32 ctx1_iv_off = 0; ++ u32 *nonce = NULL; ++ unsigned int data_len[2]; ++ u32 inl_mask; ++ const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == ++ OP_ALG_AAI_CTR_MOD128); ++ const bool is_rfc3686 = alg->caam.rfc3686; ++ ++ if (!ctx->cdata.keylen || !ctx->authsize) ++ return 0; ++ ++ /* ++ * AES-CTR needs to load IV in CONTEXT1 reg ++ * at an offset of 128bits (16bytes) ++ * CONTEXT1[255:128] = IV ++ */ ++ if (ctr_mode) ++ ctx1_iv_off = 16; ++ ++ /* ++ * RFC3686 specific: ++ * CONTEXT1[255:128] = {NONCE, IV, COUNTER} ++ */ ++ if (is_rfc3686) { ++ ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; ++ nonce = (u32 *)((void *)ctx->key + ctx->adata.keylen_pad + ++ ctx->cdata.keylen - CTR_RFC3686_NONCE_SIZE); ++ } ++ ++ data_len[0] = ctx->adata.keylen_pad; ++ data_len[1] = ctx->cdata.keylen; ++ ++ /* aead_encrypt shared descriptor */ ++ if (desc_inline_query((alg->caam.geniv ? DESC_QI_AEAD_GIVENC_LEN : ++ DESC_QI_AEAD_ENC_LEN) + ++ (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0), ++ DESC_JOB_IO_LEN, data_len, &inl_mask, ++ ARRAY_SIZE(data_len)) < 0) ++ return -EINVAL; ++ ++ if (inl_mask & 1) ++ ctx->adata.key_virt = ctx->key; ++ else ++ ctx->adata.key_dma = ctx->key_dma; ++ ++ if (inl_mask & 2) ++ ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; ++ else ++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; ++ ++ ctx->adata.key_inline = !!(inl_mask & 1); ++ ctx->cdata.key_inline = !!(inl_mask & 2); ++ ++ flc = &ctx->flc[ENCRYPT]; ++ desc = flc->sh_desc; ++ ++ if (alg->caam.geniv) ++ cnstr_shdsc_aead_givencap(desc, &ctx->cdata, &ctx->adata, ++ ivsize, ctx->authsize, is_rfc3686, ++ nonce, ctx1_iv_off, true); ++ else ++ cnstr_shdsc_aead_encap(desc, &ctx->cdata, &ctx->adata, ++ ivsize, ctx->authsize, is_rfc3686, nonce, ++ ctx1_iv_off, true); ++ ++ flc->flc[1] = desc_len(desc); /* SDL */ ++ flc->flc_dma = dma_map_single(dev, flc, sizeof(flc->flc) + ++ desc_bytes(desc), DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, flc->flc_dma)) { ++ dev_err(dev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++ ++ /* aead_decrypt shared descriptor */ ++ if (desc_inline_query(DESC_QI_AEAD_DEC_LEN + ++ (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0), ++ DESC_JOB_IO_LEN, data_len, &inl_mask, ++ ARRAY_SIZE(data_len)) < 0) ++ return -EINVAL; ++ ++ if (inl_mask & 1) ++ ctx->adata.key_virt = ctx->key; ++ else ++ ctx->adata.key_dma = ctx->key_dma; ++ ++ if (inl_mask & 2) ++ ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; ++ else ++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; ++ ++ ctx->adata.key_inline = !!(inl_mask & 1); ++ ctx->cdata.key_inline = !!(inl_mask & 2); ++ ++ flc = &ctx->flc[DECRYPT]; ++ desc = flc->sh_desc; ++ ++ cnstr_shdsc_aead_decap(desc, &ctx->cdata, &ctx->adata, ++ ivsize, ctx->authsize, alg->caam.geniv, ++ is_rfc3686, nonce, ctx1_iv_off, true); ++ ++ flc->flc[1] = desc_len(desc); /* SDL */ ++ flc->flc_dma = dma_map_single(dev, flc, sizeof(flc->flc) + ++ desc_bytes(desc), DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, flc->flc_dma)) { ++ dev_err(dev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static int aead_setauthsize(struct crypto_aead *authenc, unsigned int authsize) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(authenc); ++ ++ ctx->authsize = authsize; ++ aead_set_sh_desc(authenc); ++ ++ return 0; ++} ++ ++struct split_key_sh_result { ++ struct completion completion; ++ int err; ++ struct device *dev; ++}; ++ ++static void split_key_sh_done(void *cbk_ctx, u32 err) ++{ ++ struct split_key_sh_result *res = cbk_ctx; ++ ++#ifdef DEBUG ++ dev_err(res->dev, "%s %d: err 0x%x\n", __func__, __LINE__, err); ++#endif ++ ++ if (err) ++ caam_qi2_strstatus(res->dev, err); ++ ++ res->err = err; ++ complete(&res->completion); ++} ++ ++static int gen_split_key_sh(struct device *dev, u8 *key_out, ++ struct alginfo * const adata, const u8 *key_in, ++ u32 keylen) ++{ ++ struct caam_request *req_ctx; ++ u32 *desc; ++ struct split_key_sh_result result; ++ dma_addr_t dma_addr_in, dma_addr_out; ++ struct caam_flc *flc; ++ struct dpaa2_fl_entry *in_fle, *out_fle; ++ int ret = -ENOMEM; ++ ++ req_ctx = kzalloc(sizeof(*req_ctx), GFP_KERNEL | GFP_DMA); ++ if (!req_ctx) ++ return -ENOMEM; ++ ++ in_fle = &req_ctx->fd_flt[1]; ++ out_fle = &req_ctx->fd_flt[0]; ++ ++ flc = kzalloc(sizeof(*flc), GFP_KERNEL | GFP_DMA); ++ if (!flc) ++ goto err_flc; ++ ++ dma_addr_in = dma_map_single(dev, (void *)key_in, keylen, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, dma_addr_in)) { ++ dev_err(dev, "unable to map key input memory\n"); ++ goto err_dma_addr_in; ++ } ++ ++ dma_addr_out = dma_map_single(dev, key_out, adata->keylen_pad, ++ DMA_FROM_DEVICE); ++ if (dma_mapping_error(dev, dma_addr_out)) { ++ dev_err(dev, "unable to map key output memory\n"); ++ goto err_dma_addr_out; ++ } ++ ++ desc = flc->sh_desc; ++ ++ init_sh_desc(desc, 0); ++ append_key(desc, dma_addr_in, keylen, CLASS_2 | KEY_DEST_CLASS_REG); ++ ++ /* Sets MDHA up into an HMAC-INIT */ ++ append_operation(desc, (adata->algtype & OP_ALG_ALGSEL_MASK) | ++ OP_ALG_AAI_HMAC | OP_TYPE_CLASS2_ALG | OP_ALG_DECRYPT | ++ OP_ALG_AS_INIT); ++ ++ /* ++ * do a FIFO_LOAD of zero, this will trigger the internal key expansion ++ * into both pads inside MDHA ++ */ ++ append_fifo_load_as_imm(desc, NULL, 0, LDST_CLASS_2_CCB | ++ FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST2); ++ ++ /* ++ * FIFO_STORE with the explicit split-key content store ++ * (0x26 output type) ++ */ ++ append_fifo_store(desc, dma_addr_out, adata->keylen, ++ LDST_CLASS_2_CCB | FIFOST_TYPE_SPLIT_KEK); ++ ++ flc->flc[1] = desc_len(desc); /* SDL */ ++ flc->flc_dma = dma_map_single(dev, flc, sizeof(flc->flc) + ++ desc_bytes(desc), DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, flc->flc_dma)) { ++ dev_err(dev, "unable to map shared descriptor\n"); ++ goto err_flc_dma; ++ } ++ ++ dpaa2_fl_set_final(in_fle, true); ++ dpaa2_fl_set_format(in_fle, dpaa2_fl_single); ++ dpaa2_fl_set_addr(in_fle, dma_addr_in); ++ dpaa2_fl_set_len(in_fle, keylen); ++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single); ++ dpaa2_fl_set_addr(out_fle, dma_addr_out); ++ dpaa2_fl_set_len(out_fle, adata->keylen_pad); ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, key_in, keylen, 1); ++ print_hex_dump(KERN_ERR, "desc@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); ++#endif ++ ++ result.err = 0; ++ init_completion(&result.completion); ++ result.dev = dev; ++ ++ req_ctx->flc = flc; ++ req_ctx->cbk = split_key_sh_done; ++ req_ctx->ctx = &result; ++ ++ ret = dpaa2_caam_enqueue(dev, req_ctx); ++ if (ret == -EINPROGRESS) { ++ /* in progress */ ++ wait_for_completion(&result.completion); ++ ret = result.err; ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, key_out, ++ adata->keylen_pad, 1); ++#endif ++ } ++ ++ dma_unmap_single(dev, flc->flc_dma, sizeof(flc->flc) + desc_bytes(desc), ++ DMA_TO_DEVICE); ++err_flc_dma: ++ dma_unmap_single(dev, dma_addr_out, adata->keylen_pad, DMA_FROM_DEVICE); ++err_dma_addr_out: ++ dma_unmap_single(dev, dma_addr_in, keylen, DMA_TO_DEVICE); ++err_dma_addr_in: ++ kfree(flc); ++err_flc: ++ kfree(req_ctx); ++ return ret; ++} ++ ++static int gen_split_aead_key(struct caam_ctx *ctx, const u8 *key_in, ++ u32 authkeylen) ++{ ++ return gen_split_key_sh(ctx->dev, ctx->key, &ctx->adata, key_in, ++ authkeylen); ++} ++ ++static int aead_setkey(struct crypto_aead *aead, const u8 *key, ++ unsigned int keylen) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ struct device *dev = ctx->dev; ++ struct crypto_authenc_keys keys; ++ int ret; ++ ++ if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) ++ goto badkey; ++ ++#ifdef DEBUG ++ dev_err(dev, "keylen %d enckeylen %d authkeylen %d\n", ++ keys.authkeylen + keys.enckeylen, keys.enckeylen, ++ keys.authkeylen); ++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); ++#endif ++ ++ ctx->adata.keylen = split_key_len(ctx->adata.algtype & ++ OP_ALG_ALGSEL_MASK); ++ ctx->adata.keylen_pad = split_key_pad_len(ctx->adata.algtype & ++ OP_ALG_ALGSEL_MASK); ++ ++#ifdef DEBUG ++ dev_err(dev, "split keylen %d split keylen padded %d\n", ++ ctx->adata.keylen, ctx->adata.keylen_pad); ++ print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, keys.authkey, keylen, 1); ++#endif ++ ++ if (ctx->adata.keylen_pad + keys.enckeylen > CAAM_MAX_KEY_SIZE) ++ goto badkey; ++ ++ ret = gen_split_aead_key(ctx, keys.authkey, keys.authkeylen); ++ if (ret) ++ goto badkey; ++ ++ /* postpend encryption key to auth split key */ ++ memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen); ++ ++ ctx->key_dma = dma_map_single(dev, ctx->key, ctx->adata.keylen_pad + ++ keys.enckeylen, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, ctx->key_dma)) { ++ dev_err(dev, "unable to map key i/o memory\n"); ++ return -ENOMEM; ++ } ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, ++ ctx->adata.keylen_pad + keys.enckeylen, 1); ++#endif ++ ++ ctx->cdata.keylen = keys.enckeylen; ++ ++ ret = aead_set_sh_desc(aead); ++ if (ret) ++ dma_unmap_single(dev, ctx->key_dma, ctx->adata.keylen_pad + ++ keys.enckeylen, DMA_TO_DEVICE); ++ ++ return ret; ++badkey: ++ crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN); ++ return -EINVAL; ++} ++ ++static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, ++ bool encrypt) ++{ ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ struct caam_request *req_ctx = aead_request_ctx(req); ++ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1]; ++ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0]; ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ struct caam_aead_alg *alg = container_of(crypto_aead_alg(aead), ++ typeof(*alg), aead); ++ struct device *dev = ctx->dev; ++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? ++ GFP_KERNEL : GFP_ATOMIC; ++ int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; ++ struct aead_edesc *edesc; ++ dma_addr_t qm_sg_dma, iv_dma = 0; ++ int ivsize = 0; ++ unsigned int authsize = ctx->authsize; ++ int qm_sg_index = 0, qm_sg_nents = 0, qm_sg_bytes; ++ int in_len, out_len; ++ struct dpaa2_sg_entry *sg_table; ++ enum optype op_type = encrypt ? ENCRYPT : DECRYPT; ++ ++ /* allocate space for base edesc and link tables */ ++ edesc = qi_cache_alloc(GFP_DMA | flags); ++ if (unlikely(!edesc)) { ++ dev_err(dev, "could not allocate extended descriptor\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ if (unlikely(req->dst != req->src)) { ++ src_nents = sg_nents_for_len(req->src, req->assoclen + ++ req->cryptlen); ++ if (unlikely(src_nents < 0)) { ++ dev_err(dev, "Insufficient bytes (%d) in src S/G\n", ++ req->assoclen + req->cryptlen); ++ qi_cache_free(edesc); ++ return ERR_PTR(src_nents); ++ } ++ ++ dst_nents = sg_nents_for_len(req->dst, req->assoclen + ++ req->cryptlen + ++ (encrypt ? authsize : ++ (-authsize))); ++ if (unlikely(dst_nents < 0)) { ++ dev_err(dev, "Insufficient bytes (%d) in dst S/G\n", ++ req->assoclen + req->cryptlen + ++ (encrypt ? authsize : (-authsize))); ++ qi_cache_free(edesc); ++ return ERR_PTR(dst_nents); ++ } ++ ++ if (src_nents) { ++ mapped_src_nents = dma_map_sg(dev, req->src, src_nents, ++ DMA_TO_DEVICE); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(dev, "unable to map source\n"); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ } else { ++ mapped_src_nents = 0; ++ } ++ ++ mapped_dst_nents = dma_map_sg(dev, req->dst, dst_nents, ++ DMA_FROM_DEVICE); ++ if (unlikely(!mapped_dst_nents)) { ++ dev_err(dev, "unable to map destination\n"); ++ dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ } else { ++ src_nents = sg_nents_for_len(req->src, req->assoclen + ++ req->cryptlen + ++ (encrypt ? authsize : 0)); ++ if (unlikely(src_nents < 0)) { ++ dev_err(dev, "Insufficient bytes (%d) in src S/G\n", ++ req->assoclen + req->cryptlen + ++ (encrypt ? authsize : 0)); ++ qi_cache_free(edesc); ++ return ERR_PTR(src_nents); ++ } ++ ++ mapped_src_nents = dma_map_sg(dev, req->src, src_nents, ++ DMA_BIDIRECTIONAL); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(dev, "unable to map source\n"); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ } ++ ++ if ((alg->caam.rfc3686 && encrypt) || !alg->caam.geniv) { ++ ivsize = crypto_aead_ivsize(aead); ++ iv_dma = dma_map_single(dev, req->iv, ivsize, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, iv_dma)) { ++ dev_err(dev, "unable to map IV\n"); ++ caam_unmap(dev, req->src, req->dst, src_nents, ++ dst_nents, 0, 0, op_type, 0, 0); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ } ++ ++ /* ++ * Create S/G table: req->assoclen, [IV,] req->src [, req->dst]. ++ * Input is not contiguous. ++ */ ++ qm_sg_nents = 1 + !!ivsize + mapped_src_nents + ++ (mapped_dst_nents > 1 ? mapped_dst_nents : 0); ++ if (unlikely(qm_sg_nents > CAAM_QI_MAX_AEAD_SG)) { ++ dev_err(dev, "Insufficient S/G entries: %d > %lu\n", ++ qm_sg_nents, CAAM_QI_MAX_AEAD_SG); ++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, op_type, 0, 0); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ sg_table = &edesc->sgt[0]; ++ qm_sg_bytes = qm_sg_nents * sizeof(*sg_table); ++ ++ edesc->src_nents = src_nents; ++ edesc->dst_nents = dst_nents; ++ edesc->iv_dma = iv_dma; ++ ++ edesc->assoclen_dma = dma_map_single(dev, &req->assoclen, 4, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, edesc->assoclen_dma)) { ++ dev_err(dev, "unable to map assoclen\n"); ++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, op_type, 0, 0); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ dma_to_qm_sg_one(sg_table, edesc->assoclen_dma, 4, 0); ++ qm_sg_index++; ++ if (ivsize) { ++ dma_to_qm_sg_one(sg_table + qm_sg_index, iv_dma, ivsize, 0); ++ qm_sg_index++; ++ } ++ sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + qm_sg_index, 0); ++ qm_sg_index += mapped_src_nents; ++ ++ if (mapped_dst_nents > 1) ++ sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + ++ qm_sg_index, 0); ++ ++ qm_sg_dma = dma_map_single(dev, sg_table, qm_sg_bytes, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, qm_sg_dma)) { ++ dev_err(dev, "unable to map S/G table\n"); ++ dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE); ++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, op_type, 0, 0); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ edesc->qm_sg_dma = qm_sg_dma; ++ edesc->qm_sg_bytes = qm_sg_bytes; ++ ++ out_len = req->assoclen + req->cryptlen + ++ (encrypt ? ctx->authsize : (-ctx->authsize)); ++ in_len = 4 + ivsize + req->assoclen + req->cryptlen; ++ ++ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt)); ++ dpaa2_fl_set_final(in_fle, true); ++ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg); ++ dpaa2_fl_set_addr(in_fle, qm_sg_dma); ++ dpaa2_fl_set_len(in_fle, in_len); ++ ++ if (req->dst == req->src) { ++ if (mapped_src_nents == 1) { ++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single); ++ dpaa2_fl_set_addr(out_fle, sg_dma_address(req->src)); ++ } else { ++ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg); ++ dpaa2_fl_set_addr(out_fle, qm_sg_dma + ++ (1 + !!ivsize) * sizeof(*sg_table)); ++ } ++ } else if (mapped_dst_nents == 1) { ++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single); ++ dpaa2_fl_set_addr(out_fle, sg_dma_address(req->dst)); ++ } else { ++ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg); ++ dpaa2_fl_set_addr(out_fle, qm_sg_dma + qm_sg_index * ++ sizeof(*sg_table)); ++ } ++ ++ dpaa2_fl_set_len(out_fle, out_len); ++ ++ return edesc; ++} ++ ++static struct tls_edesc *tls_edesc_alloc(struct aead_request *req, ++ bool encrypt) ++{ ++ struct crypto_aead *tls = crypto_aead_reqtfm(req); ++ unsigned int blocksize = crypto_aead_blocksize(tls); ++ unsigned int padsize, authsize; ++ struct caam_request *req_ctx = aead_request_ctx(req); ++ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1]; ++ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0]; ++ struct caam_ctx *ctx = crypto_aead_ctx(tls); ++ struct caam_aead_alg *alg = container_of(crypto_aead_alg(tls), ++ typeof(*alg), aead); ++ struct device *dev = ctx->dev; ++ gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | ++ CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC; ++ int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; ++ struct tls_edesc *edesc; ++ dma_addr_t qm_sg_dma, iv_dma = 0; ++ int ivsize = 0; ++ int qm_sg_index, qm_sg_ents = 0, qm_sg_bytes; ++ int in_len, out_len; ++ struct dpaa2_sg_entry *sg_table; ++ enum optype op_type = encrypt ? ENCRYPT : DECRYPT; ++ struct scatterlist *dst; ++ ++ if (encrypt) { ++ padsize = blocksize - ((req->cryptlen + ctx->authsize) % ++ blocksize); ++ authsize = ctx->authsize + padsize; ++ } else { ++ authsize = ctx->authsize; ++ } ++ ++ /* allocate space for base edesc and link tables */ ++ edesc = qi_cache_alloc(GFP_DMA | flags); ++ if (unlikely(!edesc)) { ++ dev_err(dev, "could not allocate extended descriptor\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ if (likely(req->src == req->dst)) { ++ src_nents = sg_nents_for_len(req->src, req->assoclen + ++ req->cryptlen + ++ (encrypt ? authsize : 0)); ++ if (unlikely(src_nents < 0)) { ++ dev_err(dev, "Insufficient bytes (%d) in src S/G\n", ++ req->assoclen + req->cryptlen + ++ (encrypt ? authsize : 0)); ++ qi_cache_free(edesc); ++ return ERR_PTR(src_nents); ++ } ++ ++ mapped_src_nents = dma_map_sg(dev, req->src, src_nents, ++ DMA_BIDIRECTIONAL); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(dev, "unable to map source\n"); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ dst = req->dst; ++ } else { ++ src_nents = sg_nents_for_len(req->src, req->assoclen + ++ req->cryptlen); ++ if (unlikely(src_nents < 0)) { ++ dev_err(dev, "Insufficient bytes (%d) in src S/G\n", ++ req->assoclen + req->cryptlen); ++ qi_cache_free(edesc); ++ return ERR_PTR(src_nents); ++ } ++ ++ dst = scatterwalk_ffwd(edesc->tmp, req->dst, req->assoclen); ++ dst_nents = sg_nents_for_len(dst, req->cryptlen + ++ (encrypt ? authsize : 0)); ++ if (unlikely(dst_nents < 0)) { ++ dev_err(dev, "Insufficient bytes (%d) in dst S/G\n", ++ req->cryptlen + ++ (encrypt ? authsize : 0)); ++ qi_cache_free(edesc); ++ return ERR_PTR(dst_nents); ++ } ++ ++ if (src_nents) { ++ mapped_src_nents = dma_map_sg(dev, req->src, ++ src_nents, DMA_TO_DEVICE); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(dev, "unable to map source\n"); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ } else { ++ mapped_src_nents = 0; ++ } ++ ++ mapped_dst_nents = dma_map_sg(dev, dst, dst_nents, ++ DMA_FROM_DEVICE); ++ if (unlikely(!mapped_dst_nents)) { ++ dev_err(dev, "unable to map destination\n"); ++ dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ } ++ ++ ivsize = crypto_aead_ivsize(tls); ++ iv_dma = dma_map_single(dev, req->iv, ivsize, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, iv_dma)) { ++ dev_err(dev, "unable to map IV\n"); ++ caam_unmap(dev, req->src, dst, src_nents, dst_nents, 0, 0, ++ op_type, 0, 0); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ /* ++ * Create S/G table: IV, src, dst. ++ * Input is not contiguous. ++ */ ++ qm_sg_ents = 1 + mapped_src_nents + ++ (mapped_dst_nents > 1 ? mapped_dst_nents : 0); ++ sg_table = &edesc->sgt[0]; ++ qm_sg_bytes = qm_sg_ents * sizeof(*sg_table); ++ ++ edesc->src_nents = src_nents; ++ edesc->dst_nents = dst_nents; ++ edesc->dst = dst; ++ edesc->iv_dma = iv_dma; ++ ++ dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0); ++ qm_sg_index = 1; ++ ++ sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + qm_sg_index, 0); ++ qm_sg_index += mapped_src_nents; ++ ++ if (mapped_dst_nents > 1) ++ sg_to_qm_sg_last(dst, mapped_dst_nents, sg_table + ++ qm_sg_index, 0); ++ ++ qm_sg_dma = dma_map_single(dev, sg_table, qm_sg_bytes, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, qm_sg_dma)) { ++ dev_err(dev, "unable to map S/G table\n"); ++ caam_unmap(dev, req->src, dst, src_nents, dst_nents, iv_dma, ++ ivsize, op_type, 0, 0); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ edesc->qm_sg_dma = qm_sg_dma; ++ edesc->qm_sg_bytes = qm_sg_bytes; ++ ++ out_len = req->cryptlen + (encrypt ? authsize : 0); ++ in_len = ivsize + req->assoclen + req->cryptlen; ++ ++ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt)); ++ dpaa2_fl_set_final(in_fle, true); ++ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg); ++ dpaa2_fl_set_addr(in_fle, qm_sg_dma); ++ dpaa2_fl_set_len(in_fle, in_len); ++ ++ if (req->dst == req->src) { ++ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg); ++ dpaa2_fl_set_addr(out_fle, qm_sg_dma + ++ (sg_nents_for_len(req->src, req->assoclen) + ++ 1) * sizeof(*sg_table)); ++ } else if (mapped_dst_nents == 1) { ++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single); ++ dpaa2_fl_set_addr(out_fle, sg_dma_address(dst)); ++ } else { ++ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg); ++ dpaa2_fl_set_addr(out_fle, qm_sg_dma + qm_sg_index * ++ sizeof(*sg_table)); ++ } ++ ++ dpaa2_fl_set_len(out_fle, out_len); ++ ++ return edesc; ++} ++ ++static int tls_set_sh_desc(struct crypto_aead *tls) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(tls); ++ unsigned int ivsize = crypto_aead_ivsize(tls); ++ unsigned int blocksize = crypto_aead_blocksize(tls); ++ struct device *dev = ctx->dev; ++ struct caam_flc *flc; ++ u32 *desc; ++ unsigned int assoclen = 13; /* always 13 bytes for TLS */ ++ unsigned int data_len[2]; ++ u32 inl_mask; ++ ++ if (!ctx->cdata.keylen || !ctx->authsize) ++ return 0; ++ ++ /* ++ * TLS 1.0 encrypt shared descriptor ++ * Job Descriptor and Shared Descriptor ++ * must fit into the 64-word Descriptor h/w Buffer ++ */ ++ data_len[0] = ctx->adata.keylen_pad; ++ data_len[1] = ctx->cdata.keylen; ++ ++ if (desc_inline_query(DESC_TLS10_ENC_LEN, DESC_JOB_IO_LEN, data_len, ++ &inl_mask, ARRAY_SIZE(data_len)) < 0) ++ return -EINVAL; ++ ++ if (inl_mask & 1) ++ ctx->adata.key_virt = ctx->key; ++ else ++ ctx->adata.key_dma = ctx->key_dma; ++ ++ if (inl_mask & 2) ++ ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; ++ else ++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; ++ ++ ctx->adata.key_inline = !!(inl_mask & 1); ++ ctx->cdata.key_inline = !!(inl_mask & 2); ++ ++ flc = &ctx->flc[ENCRYPT]; ++ desc = flc->sh_desc; ++ ++ cnstr_shdsc_tls_encap(desc, &ctx->cdata, &ctx->adata, ++ assoclen, ivsize, ctx->authsize, blocksize); ++ ++ flc->flc[1] = desc_len(desc); ++ flc->flc_dma = dma_map_single(dev, flc, sizeof(flc->flc) + ++ desc_bytes(desc), DMA_TO_DEVICE); ++ ++ if (dma_mapping_error(dev, flc->flc_dma)) { ++ dev_err(dev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++ ++ /* ++ * TLS 1.0 decrypt shared descriptor ++ * Keys do not fit inline, regardless of algorithms used ++ */ ++ ctx->adata.key_dma = ctx->key_dma; ++ ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; ++ ++ flc = &ctx->flc[DECRYPT]; ++ desc = flc->sh_desc; ++ ++ cnstr_shdsc_tls_decap(desc, &ctx->cdata, &ctx->adata, assoclen, ivsize, ++ ctx->authsize, blocksize); ++ ++ flc->flc[1] = desc_len(desc); /* SDL */ ++ flc->flc_dma = dma_map_single(dev, flc, sizeof(flc->flc) + ++ desc_bytes(desc), DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, flc->flc_dma)) { ++ dev_err(dev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static int tls_setkey(struct crypto_aead *tls, const u8 *key, ++ unsigned int keylen) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(tls); ++ struct device *dev = ctx->dev; ++ struct crypto_authenc_keys keys; ++ int ret; ++ ++ if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) ++ goto badkey; ++ ++#ifdef DEBUG ++ dev_err(dev, "keylen %d enckeylen %d authkeylen %d\n", ++ keys.authkeylen + keys.enckeylen, keys.enckeylen, ++ keys.authkeylen); ++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); ++#endif ++ ++ ctx->adata.keylen = split_key_len(ctx->adata.algtype & ++ OP_ALG_ALGSEL_MASK); ++ ctx->adata.keylen_pad = split_key_pad_len(ctx->adata.algtype & ++ OP_ALG_ALGSEL_MASK); ++ ++#ifdef DEBUG ++ dev_err(dev, "split keylen %d split keylen padded %d\n", ++ ctx->adata.keylen, ctx->adata.keylen_pad); ++ print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, keys.authkey, ++ keys.authkeylen + keys.enckeylen, 1); ++#endif ++ ++ if (ctx->adata.keylen_pad + keys.enckeylen > CAAM_MAX_KEY_SIZE) ++ goto badkey; ++ ++ ret = gen_split_aead_key(ctx, keys.authkey, keys.authkeylen); ++ if (ret) ++ goto badkey; ++ ++ /* postpend encryption key to auth split key */ ++ memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen); ++ ++ ctx->key_dma = dma_map_single(dev, ctx->key, ctx->adata.keylen_pad + ++ keys.enckeylen, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, ctx->key_dma)) { ++ dev_err(dev, "unable to map key i/o memory\n"); ++ return -ENOMEM; ++ } ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, ++ ctx->adata.keylen_pad + keys.enckeylen, 1); ++#endif ++ ++ ctx->cdata.keylen = keys.enckeylen; ++ ++ ret = tls_set_sh_desc(tls); ++ if (ret) ++ dma_unmap_single(dev, ctx->key_dma, ctx->adata.keylen_pad + ++ keys.enckeylen, DMA_TO_DEVICE); ++ ++ return ret; ++badkey: ++ crypto_aead_set_flags(tls, CRYPTO_TFM_RES_BAD_KEY_LEN); ++ return -EINVAL; ++} ++ ++static int tls_setauthsize(struct crypto_aead *tls, unsigned int authsize) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(tls); ++ ++ ctx->authsize = authsize; ++ tls_set_sh_desc(tls); ++ ++ return 0; ++} ++ ++static int gcm_set_sh_desc(struct crypto_aead *aead) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ struct device *dev = ctx->dev; ++ unsigned int ivsize = crypto_aead_ivsize(aead); ++ struct caam_flc *flc; ++ u32 *desc; ++ int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN - ++ ctx->cdata.keylen; ++ ++ if (!ctx->cdata.keylen || !ctx->authsize) ++ return 0; ++ ++ /* ++ * AES GCM encrypt shared descriptor ++ * Job Descriptor and Shared Descriptor ++ * must fit into the 64-word Descriptor h/w Buffer ++ */ ++ if (rem_bytes >= DESC_QI_GCM_ENC_LEN) { ++ ctx->cdata.key_inline = true; ++ ctx->cdata.key_virt = ctx->key; ++ } else { ++ ctx->cdata.key_inline = false; ++ ctx->cdata.key_dma = ctx->key_dma; ++ } ++ ++ flc = &ctx->flc[ENCRYPT]; ++ desc = flc->sh_desc; ++ cnstr_shdsc_gcm_encap(desc, &ctx->cdata, ivsize, ctx->authsize, true); ++ ++ flc->flc[1] = desc_len(desc); /* SDL */ ++ flc->flc_dma = dma_map_single(dev, flc, sizeof(flc->flc) + ++ desc_bytes(desc), DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, flc->flc_dma)) { ++ dev_err(dev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++ ++ /* ++ * Job Descriptor and Shared Descriptors ++ * must all fit into the 64-word Descriptor h/w Buffer ++ */ ++ if (rem_bytes >= DESC_QI_GCM_DEC_LEN) { ++ ctx->cdata.key_inline = true; ++ ctx->cdata.key_virt = ctx->key; ++ } else { ++ ctx->cdata.key_inline = false; ++ ctx->cdata.key_dma = ctx->key_dma; ++ } ++ ++ flc = &ctx->flc[DECRYPT]; ++ desc = flc->sh_desc; ++ cnstr_shdsc_gcm_decap(desc, &ctx->cdata, ivsize, ctx->authsize, true); ++ ++ flc->flc[1] = desc_len(desc); /* SDL */ ++ flc->flc_dma = dma_map_single(dev, flc, sizeof(flc->flc) + ++ desc_bytes(desc), DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, flc->flc_dma)) { ++ dev_err(dev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static int gcm_setauthsize(struct crypto_aead *authenc, unsigned int authsize) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(authenc); ++ ++ ctx->authsize = authsize; ++ gcm_set_sh_desc(authenc); ++ ++ return 0; ++} ++ ++static int gcm_setkey(struct crypto_aead *aead, ++ const u8 *key, unsigned int keylen) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ struct device *dev = ctx->dev; ++ int ret; ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); ++#endif ++ ++ memcpy(ctx->key, key, keylen); ++ ctx->key_dma = dma_map_single(dev, ctx->key, keylen, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, ctx->key_dma)) { ++ dev_err(dev, "unable to map key i/o memory\n"); ++ return -ENOMEM; ++ } ++ ctx->cdata.keylen = keylen; ++ ++ ret = gcm_set_sh_desc(aead); ++ if (ret) ++ dma_unmap_single(dev, ctx->key_dma, ctx->cdata.keylen, ++ DMA_TO_DEVICE); ++ ++ return ret; ++} ++ ++static int rfc4106_set_sh_desc(struct crypto_aead *aead) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ struct device *dev = ctx->dev; ++ unsigned int ivsize = crypto_aead_ivsize(aead); ++ struct caam_flc *flc; ++ u32 *desc; ++ int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN - ++ ctx->cdata.keylen; ++ ++ if (!ctx->cdata.keylen || !ctx->authsize) ++ return 0; ++ ++ ctx->cdata.key_virt = ctx->key; ++ ++ /* ++ * RFC4106 encrypt shared descriptor ++ * Job Descriptor and Shared Descriptor ++ * must fit into the 64-word Descriptor h/w Buffer ++ */ ++ if (rem_bytes >= DESC_QI_RFC4106_ENC_LEN) { ++ ctx->cdata.key_inline = true; ++ } else { ++ ctx->cdata.key_inline = false; ++ ctx->cdata.key_dma = ctx->key_dma; ++ } ++ ++ flc = &ctx->flc[ENCRYPT]; ++ desc = flc->sh_desc; ++ cnstr_shdsc_rfc4106_encap(desc, &ctx->cdata, ivsize, ctx->authsize, ++ true); ++ ++ flc->flc[1] = desc_len(desc); /* SDL */ ++ flc->flc_dma = dma_map_single(dev, flc, sizeof(flc->flc) + ++ desc_bytes(desc), DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, flc->flc_dma)) { ++ dev_err(dev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++ ++ /* ++ * Job Descriptor and Shared Descriptors ++ * must all fit into the 64-word Descriptor h/w Buffer ++ */ ++ if (rem_bytes >= DESC_QI_RFC4106_DEC_LEN) { ++ ctx->cdata.key_inline = true; ++ } else { ++ ctx->cdata.key_inline = false; ++ ctx->cdata.key_dma = ctx->key_dma; ++ } ++ ++ flc = &ctx->flc[DECRYPT]; ++ desc = flc->sh_desc; ++ cnstr_shdsc_rfc4106_decap(desc, &ctx->cdata, ivsize, ctx->authsize, ++ true); ++ ++ flc->flc[1] = desc_len(desc); /* SDL */ ++ flc->flc_dma = dma_map_single(dev, flc, sizeof(flc->flc) + ++ desc_bytes(desc), DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, flc->flc_dma)) { ++ dev_err(dev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static int rfc4106_setauthsize(struct crypto_aead *authenc, ++ unsigned int authsize) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(authenc); ++ ++ ctx->authsize = authsize; ++ rfc4106_set_sh_desc(authenc); ++ ++ return 0; ++} ++ ++static int rfc4106_setkey(struct crypto_aead *aead, ++ const u8 *key, unsigned int keylen) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ struct device *dev = ctx->dev; ++ int ret; ++ ++ if (keylen < 4) ++ return -EINVAL; ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); ++#endif ++ ++ memcpy(ctx->key, key, keylen); ++ /* ++ * The last four bytes of the key material are used as the salt value ++ * in the nonce. Update the AES key length. ++ */ ++ ctx->cdata.keylen = keylen - 4; ++ ctx->key_dma = dma_map_single(dev, ctx->key, ctx->cdata.keylen, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, ctx->key_dma)) { ++ dev_err(dev, "unable to map key i/o memory\n"); ++ return -ENOMEM; ++ } ++ ++ ret = rfc4106_set_sh_desc(aead); ++ if (ret) ++ dma_unmap_single(dev, ctx->key_dma, ctx->cdata.keylen, ++ DMA_TO_DEVICE); ++ ++ return ret; ++} ++ ++static int rfc4543_set_sh_desc(struct crypto_aead *aead) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ struct device *dev = ctx->dev; ++ unsigned int ivsize = crypto_aead_ivsize(aead); ++ struct caam_flc *flc; ++ u32 *desc; ++ int rem_bytes = CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN - ++ ctx->cdata.keylen; ++ ++ if (!ctx->cdata.keylen || !ctx->authsize) ++ return 0; ++ ++ ctx->cdata.key_virt = ctx->key; ++ ++ /* ++ * RFC4543 encrypt shared descriptor ++ * Job Descriptor and Shared Descriptor ++ * must fit into the 64-word Descriptor h/w Buffer ++ */ ++ if (rem_bytes >= DESC_QI_RFC4543_ENC_LEN) { ++ ctx->cdata.key_inline = true; ++ } else { ++ ctx->cdata.key_inline = false; ++ ctx->cdata.key_dma = ctx->key_dma; ++ } ++ ++ flc = &ctx->flc[ENCRYPT]; ++ desc = flc->sh_desc; ++ cnstr_shdsc_rfc4543_encap(desc, &ctx->cdata, ivsize, ctx->authsize, ++ true); ++ ++ flc->flc[1] = desc_len(desc); /* SDL */ ++ flc->flc_dma = dma_map_single(dev, flc, sizeof(flc->flc) + ++ desc_bytes(desc), DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, flc->flc_dma)) { ++ dev_err(dev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++ ++ /* ++ * Job Descriptor and Shared Descriptors ++ * must all fit into the 64-word Descriptor h/w Buffer ++ */ ++ if (rem_bytes >= DESC_QI_RFC4543_DEC_LEN) { ++ ctx->cdata.key_inline = true; ++ } else { ++ ctx->cdata.key_inline = false; ++ ctx->cdata.key_dma = ctx->key_dma; ++ } ++ ++ flc = &ctx->flc[DECRYPT]; ++ desc = flc->sh_desc; ++ cnstr_shdsc_rfc4543_decap(desc, &ctx->cdata, ivsize, ctx->authsize, ++ true); ++ ++ flc->flc[1] = desc_len(desc); /* SDL */ ++ flc->flc_dma = dma_map_single(dev, flc, sizeof(flc->flc) + ++ desc_bytes(desc), DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, flc->flc_dma)) { ++ dev_err(dev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static int rfc4543_setauthsize(struct crypto_aead *authenc, ++ unsigned int authsize) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(authenc); ++ ++ ctx->authsize = authsize; ++ rfc4543_set_sh_desc(authenc); ++ ++ return 0; ++} ++ ++static int rfc4543_setkey(struct crypto_aead *aead, ++ const u8 *key, unsigned int keylen) ++{ ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ struct device *dev = ctx->dev; ++ int ret; ++ ++ if (keylen < 4) ++ return -EINVAL; ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); ++#endif ++ ++ memcpy(ctx->key, key, keylen); ++ /* ++ * The last four bytes of the key material are used as the salt value ++ * in the nonce. Update the AES key length. ++ */ ++ ctx->cdata.keylen = keylen - 4; ++ ctx->key_dma = dma_map_single(dev, ctx->key, ctx->cdata.keylen, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, ctx->key_dma)) { ++ dev_err(dev, "unable to map key i/o memory\n"); ++ return -ENOMEM; ++ } ++ ++ ret = rfc4543_set_sh_desc(aead); ++ if (ret) ++ dma_unmap_single(dev, ctx->key_dma, ctx->cdata.keylen, ++ DMA_TO_DEVICE); ++ ++ return ret; ++} ++ ++static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, ++ const u8 *key, unsigned int keylen) ++{ ++ struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); ++ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(ablkcipher); ++ const char *alg_name = crypto_tfm_alg_name(tfm); ++ struct device *dev = ctx->dev; ++ struct caam_flc *flc; ++ unsigned int ivsize = crypto_ablkcipher_ivsize(ablkcipher); ++ u32 *desc; ++ u32 ctx1_iv_off = 0; ++ const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == ++ OP_ALG_AAI_CTR_MOD128); ++ const bool is_rfc3686 = (ctr_mode && strstr(alg_name, "rfc3686")); ++ ++ memcpy(ctx->key, key, keylen); ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "key in @" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); ++#endif ++ /* ++ * AES-CTR needs to load IV in CONTEXT1 reg ++ * at an offset of 128bits (16bytes) ++ * CONTEXT1[255:128] = IV ++ */ ++ if (ctr_mode) ++ ctx1_iv_off = 16; ++ ++ /* ++ * RFC3686 specific: ++ * | CONTEXT1[255:128] = {NONCE, IV, COUNTER} ++ * | *key = {KEY, NONCE} ++ */ ++ if (is_rfc3686) { ++ ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; ++ keylen -= CTR_RFC3686_NONCE_SIZE; ++ } ++ ++ ctx->key_dma = dma_map_single(dev, ctx->key, keylen, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, ctx->key_dma)) { ++ dev_err(dev, "unable to map key i/o memory\n"); ++ return -ENOMEM; ++ } ++ ctx->cdata.keylen = keylen; ++ ctx->cdata.key_virt = ctx->key; ++ ctx->cdata.key_inline = true; ++ ++ /* ablkcipher_encrypt shared descriptor */ ++ flc = &ctx->flc[ENCRYPT]; ++ desc = flc->sh_desc; ++ ++ cnstr_shdsc_ablkcipher_encap(desc, &ctx->cdata, ivsize, ++ is_rfc3686, ctx1_iv_off); ++ ++ flc->flc[1] = desc_len(desc); /* SDL */ ++ flc->flc_dma = dma_map_single(dev, flc, sizeof(flc->flc) + ++ desc_bytes(desc), DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, flc->flc_dma)) { ++ dev_err(dev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++ ++ /* ablkcipher_decrypt shared descriptor */ ++ flc = &ctx->flc[DECRYPT]; ++ desc = flc->sh_desc; ++ ++ cnstr_shdsc_ablkcipher_decap(desc, &ctx->cdata, ivsize, ++ is_rfc3686, ctx1_iv_off); ++ ++ flc->flc[1] = desc_len(desc); /* SDL */ ++ flc->flc_dma = dma_map_single(dev, flc, sizeof(flc->flc) + ++ desc_bytes(desc), DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, flc->flc_dma)) { ++ dev_err(dev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++ ++ /* ablkcipher_givencrypt shared descriptor */ ++ flc = &ctx->flc[GIVENCRYPT]; ++ desc = flc->sh_desc; ++ ++ cnstr_shdsc_ablkcipher_givencap(desc, &ctx->cdata, ++ ivsize, is_rfc3686, ctx1_iv_off); ++ ++ flc->flc[1] = desc_len(desc); /* SDL */ ++ flc->flc_dma = dma_map_single(dev, flc, sizeof(flc->flc) + ++ desc_bytes(desc), DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, flc->flc_dma)) { ++ dev_err(dev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, ++ const u8 *key, unsigned int keylen) ++{ ++ struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); ++ struct device *dev = ctx->dev; ++ struct caam_flc *flc; ++ u32 *desc; ++ ++ if (keylen != 2 * AES_MIN_KEY_SIZE && keylen != 2 * AES_MAX_KEY_SIZE) { ++ dev_err(dev, "key size mismatch\n"); ++ crypto_ablkcipher_set_flags(ablkcipher, ++ CRYPTO_TFM_RES_BAD_KEY_LEN); ++ return -EINVAL; ++ } ++ ++ memcpy(ctx->key, key, keylen); ++ ctx->key_dma = dma_map_single(dev, ctx->key, keylen, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, ctx->key_dma)) { ++ dev_err(dev, "unable to map key i/o memory\n"); ++ return -ENOMEM; ++ } ++ ctx->cdata.keylen = keylen; ++ ctx->cdata.key_virt = ctx->key; ++ ctx->cdata.key_inline = true; ++ ++ /* xts_ablkcipher_encrypt shared descriptor */ ++ flc = &ctx->flc[ENCRYPT]; ++ desc = flc->sh_desc; ++ cnstr_shdsc_xts_ablkcipher_encap(desc, &ctx->cdata); ++ ++ flc->flc[1] = desc_len(desc); /* SDL */ ++ flc->flc_dma = dma_map_single(dev, flc, sizeof(flc->flc) + ++ desc_bytes(desc), DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, flc->flc_dma)) { ++ dev_err(dev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++ ++ /* xts_ablkcipher_decrypt shared descriptor */ ++ flc = &ctx->flc[DECRYPT]; ++ desc = flc->sh_desc; ++ ++ cnstr_shdsc_xts_ablkcipher_decap(desc, &ctx->cdata); ++ ++ flc->flc[1] = desc_len(desc); /* SDL */ ++ flc->flc_dma = dma_map_single(dev, flc, sizeof(flc->flc) + ++ desc_bytes(desc), DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, flc->flc_dma)) { ++ dev_err(dev, "unable to map shared descriptor\n"); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request ++ *req, bool encrypt) ++{ ++ struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); ++ struct caam_request *req_ctx = ablkcipher_request_ctx(req); ++ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1]; ++ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0]; ++ struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); ++ struct device *dev = ctx->dev; ++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? ++ GFP_KERNEL : GFP_ATOMIC; ++ int src_nents, mapped_src_nents, dst_nents = 0, mapped_dst_nents = 0; ++ struct ablkcipher_edesc *edesc; ++ dma_addr_t iv_dma; ++ bool in_contig; ++ int ivsize = crypto_ablkcipher_ivsize(ablkcipher); ++ int dst_sg_idx, qm_sg_ents; ++ struct dpaa2_sg_entry *sg_table; ++ enum optype op_type = encrypt ? ENCRYPT : DECRYPT; ++ ++ src_nents = sg_nents_for_len(req->src, req->nbytes); ++ if (unlikely(src_nents < 0)) { ++ dev_err(dev, "Insufficient bytes (%d) in src S/G\n", ++ req->nbytes); ++ return ERR_PTR(src_nents); ++ } ++ ++ if (unlikely(req->dst != req->src)) { ++ dst_nents = sg_nents_for_len(req->dst, req->nbytes); ++ if (unlikely(dst_nents < 0)) { ++ dev_err(dev, "Insufficient bytes (%d) in dst S/G\n", ++ req->nbytes); ++ return ERR_PTR(dst_nents); ++ } ++ ++ mapped_src_nents = dma_map_sg(dev, req->src, src_nents, ++ DMA_TO_DEVICE); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(dev, "unable to map source\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ mapped_dst_nents = dma_map_sg(dev, req->dst, dst_nents, ++ DMA_FROM_DEVICE); ++ if (unlikely(!mapped_dst_nents)) { ++ dev_err(dev, "unable to map destination\n"); ++ dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE); ++ return ERR_PTR(-ENOMEM); ++ } ++ } else { ++ mapped_src_nents = dma_map_sg(dev, req->src, src_nents, ++ DMA_BIDIRECTIONAL); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(dev, "unable to map source\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ } ++ ++ iv_dma = dma_map_single(dev, req->info, ivsize, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, iv_dma)) { ++ dev_err(dev, "unable to map IV\n"); ++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0, ++ 0, 0, 0, 0); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ if (mapped_src_nents == 1 && ++ iv_dma + ivsize == sg_dma_address(req->src)) { ++ in_contig = true; ++ qm_sg_ents = 0; ++ } else { ++ in_contig = false; ++ qm_sg_ents = 1 + mapped_src_nents; ++ } ++ dst_sg_idx = qm_sg_ents; ++ ++ qm_sg_ents += mapped_dst_nents > 1 ? mapped_dst_nents : 0; ++ if (unlikely(qm_sg_ents > CAAM_QI_MAX_ABLKCIPHER_SG)) { ++ dev_err(dev, "Insufficient S/G entries: %d > %lu\n", ++ qm_sg_ents, CAAM_QI_MAX_ABLKCIPHER_SG); ++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, op_type, 0, 0); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ /* allocate space for base edesc and link tables */ ++ edesc = qi_cache_alloc(GFP_DMA | flags); ++ if (unlikely(!edesc)) { ++ dev_err(dev, "could not allocate extended descriptor\n"); ++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, op_type, 0, 0); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ edesc->src_nents = src_nents; ++ edesc->dst_nents = dst_nents; ++ edesc->iv_dma = iv_dma; ++ sg_table = &edesc->sgt[0]; ++ edesc->qm_sg_bytes = qm_sg_ents * sizeof(*sg_table); ++ ++ if (!in_contig) { ++ dma_to_qm_sg_one(sg_table, iv_dma, ivsize, 0); ++ sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table + 1, 0); ++ } ++ ++ if (mapped_dst_nents > 1) ++ sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + ++ dst_sg_idx, 0); ++ ++ edesc->qm_sg_dma = dma_map_single(dev, sg_table, edesc->qm_sg_bytes, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, edesc->qm_sg_dma)) { ++ dev_err(dev, "unable to map S/G table\n"); ++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, op_type, 0, 0); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt)); ++ dpaa2_fl_set_final(in_fle, true); ++ dpaa2_fl_set_len(in_fle, req->nbytes + ivsize); ++ dpaa2_fl_set_len(out_fle, req->nbytes); ++ ++ if (!in_contig) { ++ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg); ++ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma); ++ } else { ++ dpaa2_fl_set_format(in_fle, dpaa2_fl_single); ++ dpaa2_fl_set_addr(in_fle, iv_dma); ++ } ++ ++ if (req->src == req->dst) { ++ if (!in_contig) { ++ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg); ++ dpaa2_fl_set_addr(out_fle, edesc->qm_sg_dma + ++ sizeof(*sg_table)); ++ } else { ++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single); ++ dpaa2_fl_set_addr(out_fle, sg_dma_address(req->src)); ++ } ++ } else if (mapped_dst_nents > 1) { ++ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg); ++ dpaa2_fl_set_addr(out_fle, edesc->qm_sg_dma + dst_sg_idx * ++ sizeof(*sg_table)); ++ } else { ++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single); ++ dpaa2_fl_set_addr(out_fle, sg_dma_address(req->dst)); ++ } ++ ++ return edesc; ++} ++ ++static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( ++ struct skcipher_givcrypt_request *greq) ++{ ++ struct ablkcipher_request *req = &greq->creq; ++ struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); ++ struct caam_request *req_ctx = ablkcipher_request_ctx(req); ++ struct dpaa2_fl_entry *in_fle = &req_ctx->fd_flt[1]; ++ struct dpaa2_fl_entry *out_fle = &req_ctx->fd_flt[0]; ++ struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); ++ struct device *dev = ctx->dev; ++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? ++ GFP_KERNEL : GFP_ATOMIC; ++ int src_nents, mapped_src_nents, dst_nents, mapped_dst_nents; ++ struct ablkcipher_edesc *edesc; ++ dma_addr_t iv_dma; ++ bool out_contig; ++ int ivsize = crypto_ablkcipher_ivsize(ablkcipher); ++ struct dpaa2_sg_entry *sg_table; ++ int dst_sg_idx, qm_sg_ents; ++ ++ src_nents = sg_nents_for_len(req->src, req->nbytes); ++ if (unlikely(src_nents < 0)) { ++ dev_err(dev, "Insufficient bytes (%d) in src S/G\n", ++ req->nbytes); ++ return ERR_PTR(src_nents); ++ } ++ ++ if (unlikely(req->dst != req->src)) { ++ dst_nents = sg_nents_for_len(req->dst, req->nbytes); ++ if (unlikely(dst_nents < 0)) { ++ dev_err(dev, "Insufficient bytes (%d) in dst S/G\n", ++ req->nbytes); ++ return ERR_PTR(dst_nents); ++ } ++ ++ mapped_src_nents = dma_map_sg(dev, req->src, src_nents, ++ DMA_TO_DEVICE); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(dev, "unable to map source\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ mapped_dst_nents = dma_map_sg(dev, req->dst, dst_nents, ++ DMA_FROM_DEVICE); ++ if (unlikely(!mapped_dst_nents)) { ++ dev_err(dev, "unable to map destination\n"); ++ dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE); ++ return ERR_PTR(-ENOMEM); ++ } ++ } else { ++ mapped_src_nents = dma_map_sg(dev, req->src, src_nents, ++ DMA_BIDIRECTIONAL); ++ if (unlikely(!mapped_src_nents)) { ++ dev_err(dev, "unable to map source\n"); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ dst_nents = src_nents; ++ mapped_dst_nents = src_nents; ++ } ++ ++ iv_dma = dma_map_single(dev, greq->giv, ivsize, DMA_FROM_DEVICE); ++ if (dma_mapping_error(dev, iv_dma)) { ++ dev_err(dev, "unable to map IV\n"); ++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, 0, ++ 0, 0, 0, 0); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ qm_sg_ents = mapped_src_nents > 1 ? mapped_src_nents : 0; ++ dst_sg_idx = qm_sg_ents; ++ if (mapped_dst_nents == 1 && ++ iv_dma + ivsize == sg_dma_address(req->dst)) { ++ out_contig = true; ++ } else { ++ out_contig = false; ++ qm_sg_ents += 1 + mapped_dst_nents; ++ } ++ ++ if (unlikely(qm_sg_ents > CAAM_QI_MAX_ABLKCIPHER_SG)) { ++ dev_err(dev, "Insufficient S/G entries: %d > %lu\n", ++ qm_sg_ents, CAAM_QI_MAX_ABLKCIPHER_SG); ++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, GIVENCRYPT, 0, 0); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ /* allocate space for base edesc and link tables */ ++ edesc = qi_cache_alloc(GFP_DMA | flags); ++ if (!edesc) { ++ dev_err(dev, "could not allocate extended descriptor\n"); ++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, GIVENCRYPT, 0, 0); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ edesc->src_nents = src_nents; ++ edesc->dst_nents = dst_nents; ++ edesc->iv_dma = iv_dma; ++ sg_table = &edesc->sgt[0]; ++ edesc->qm_sg_bytes = qm_sg_ents * sizeof(*sg_table); ++ ++ if (mapped_src_nents > 1) ++ sg_to_qm_sg_last(req->src, mapped_src_nents, sg_table, 0); ++ ++ if (!out_contig) { ++ dma_to_qm_sg_one(sg_table + dst_sg_idx, iv_dma, ivsize, 0); ++ sg_to_qm_sg_last(req->dst, mapped_dst_nents, sg_table + ++ dst_sg_idx + 1, 0); ++ } ++ ++ edesc->qm_sg_dma = dma_map_single(dev, sg_table, edesc->qm_sg_bytes, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, edesc->qm_sg_dma)) { ++ dev_err(dev, "unable to map S/G table\n"); ++ caam_unmap(dev, req->src, req->dst, src_nents, dst_nents, ++ iv_dma, ivsize, GIVENCRYPT, 0, 0); ++ qi_cache_free(edesc); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ memset(&req_ctx->fd_flt, 0, sizeof(req_ctx->fd_flt)); ++ dpaa2_fl_set_final(in_fle, true); ++ dpaa2_fl_set_len(in_fle, req->nbytes); ++ dpaa2_fl_set_len(out_fle, ivsize + req->nbytes); ++ ++ if (mapped_src_nents > 1) { ++ dpaa2_fl_set_format(in_fle, dpaa2_fl_sg); ++ dpaa2_fl_set_addr(in_fle, edesc->qm_sg_dma); ++ } else { ++ dpaa2_fl_set_format(in_fle, dpaa2_fl_single); ++ dpaa2_fl_set_addr(in_fle, sg_dma_address(req->src)); ++ } ++ ++ if (!out_contig) { ++ dpaa2_fl_set_format(out_fle, dpaa2_fl_sg); ++ dpaa2_fl_set_addr(out_fle, edesc->qm_sg_dma + dst_sg_idx * ++ sizeof(*sg_table)); ++ } else { ++ dpaa2_fl_set_format(out_fle, dpaa2_fl_single); ++ dpaa2_fl_set_addr(out_fle, sg_dma_address(req->dst)); ++ } ++ ++ return edesc; ++} ++ ++static void aead_unmap(struct device *dev, struct aead_edesc *edesc, ++ struct aead_request *req) ++{ ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ int ivsize = crypto_aead_ivsize(aead); ++ struct caam_request *caam_req = aead_request_ctx(req); ++ ++ caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents, ++ edesc->iv_dma, ivsize, caam_req->op_type, ++ edesc->qm_sg_dma, edesc->qm_sg_bytes); ++ dma_unmap_single(dev, edesc->assoclen_dma, 4, DMA_TO_DEVICE); ++} ++ ++static void tls_unmap(struct device *dev, struct tls_edesc *edesc, ++ struct aead_request *req) ++{ ++ struct crypto_aead *tls = crypto_aead_reqtfm(req); ++ int ivsize = crypto_aead_ivsize(tls); ++ struct caam_request *caam_req = aead_request_ctx(req); ++ ++ caam_unmap(dev, req->src, edesc->dst, edesc->src_nents, ++ edesc->dst_nents, edesc->iv_dma, ivsize, caam_req->op_type, ++ edesc->qm_sg_dma, edesc->qm_sg_bytes); ++} ++ ++static void ablkcipher_unmap(struct device *dev, ++ struct ablkcipher_edesc *edesc, ++ struct ablkcipher_request *req) ++{ ++ struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); ++ int ivsize = crypto_ablkcipher_ivsize(ablkcipher); ++ struct caam_request *caam_req = ablkcipher_request_ctx(req); ++ ++ caam_unmap(dev, req->src, req->dst, edesc->src_nents, edesc->dst_nents, ++ edesc->iv_dma, ivsize, caam_req->op_type, ++ edesc->qm_sg_dma, edesc->qm_sg_bytes); ++} ++ ++static void aead_encrypt_done(void *cbk_ctx, u32 status) ++{ ++ struct crypto_async_request *areq = cbk_ctx; ++ struct aead_request *req = container_of(areq, struct aead_request, ++ base); ++ struct caam_request *req_ctx = to_caam_req(areq); ++ struct aead_edesc *edesc = req_ctx->edesc; ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ int ecode = 0; ++ ++#ifdef DEBUG ++ dev_err(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); ++#endif ++ ++ if (unlikely(status)) { ++ caam_qi2_strstatus(ctx->dev, status); ++ ecode = -EIO; ++ } ++ ++ aead_unmap(ctx->dev, edesc, req); ++ qi_cache_free(edesc); ++ aead_request_complete(req, ecode); ++} ++ ++static void aead_decrypt_done(void *cbk_ctx, u32 status) ++{ ++ struct crypto_async_request *areq = cbk_ctx; ++ struct aead_request *req = container_of(areq, struct aead_request, ++ base); ++ struct caam_request *req_ctx = to_caam_req(areq); ++ struct aead_edesc *edesc = req_ctx->edesc; ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ int ecode = 0; ++ ++#ifdef DEBUG ++ dev_err(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); ++#endif ++ ++ if (unlikely(status)) { ++ caam_qi2_strstatus(ctx->dev, status); ++ /* ++ * verify hw auth check passed else return -EBADMSG ++ */ ++ if ((status & JRSTA_CCBERR_ERRID_MASK) == ++ JRSTA_CCBERR_ERRID_ICVCHK) ++ ecode = -EBADMSG; ++ else ++ ecode = -EIO; ++ } ++ ++ aead_unmap(ctx->dev, edesc, req); ++ qi_cache_free(edesc); ++ aead_request_complete(req, ecode); ++} ++ ++static int aead_encrypt(struct aead_request *req) ++{ ++ struct aead_edesc *edesc; ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ struct caam_request *caam_req = aead_request_ctx(req); ++ int ret; ++ ++ /* allocate extended descriptor */ ++ edesc = aead_edesc_alloc(req, true); ++ if (IS_ERR(edesc)) ++ return PTR_ERR(edesc); ++ ++ caam_req->flc = &ctx->flc[ENCRYPT]; ++ caam_req->op_type = ENCRYPT; ++ caam_req->cbk = aead_encrypt_done; ++ caam_req->ctx = &req->base; ++ caam_req->edesc = edesc; ++ ret = dpaa2_caam_enqueue(ctx->dev, caam_req); ++ if (ret != -EINPROGRESS && ++ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { ++ aead_unmap(ctx->dev, edesc, req); ++ qi_cache_free(edesc); ++ } ++ ++ return ret; ++} ++ ++static int aead_decrypt(struct aead_request *req) ++{ ++ struct aead_edesc *edesc; ++ struct crypto_aead *aead = crypto_aead_reqtfm(req); ++ struct caam_ctx *ctx = crypto_aead_ctx(aead); ++ struct caam_request *caam_req = aead_request_ctx(req); ++ int ret; ++ ++ /* allocate extended descriptor */ ++ edesc = aead_edesc_alloc(req, false); ++ if (IS_ERR(edesc)) ++ return PTR_ERR(edesc); ++ ++ caam_req->flc = &ctx->flc[DECRYPT]; ++ caam_req->op_type = DECRYPT; ++ caam_req->cbk = aead_decrypt_done; ++ caam_req->ctx = &req->base; ++ caam_req->edesc = edesc; ++ ret = dpaa2_caam_enqueue(ctx->dev, caam_req); ++ if (ret != -EINPROGRESS && ++ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { ++ aead_unmap(ctx->dev, edesc, req); ++ qi_cache_free(edesc); ++ } ++ ++ return ret; ++} ++ ++static void tls_encrypt_done(void *cbk_ctx, u32 status) ++{ ++ struct crypto_async_request *areq = cbk_ctx; ++ struct aead_request *req = container_of(areq, struct aead_request, ++ base); ++ struct caam_request *req_ctx = to_caam_req(areq); ++ struct tls_edesc *edesc = req_ctx->edesc; ++ struct crypto_aead *tls = crypto_aead_reqtfm(req); ++ struct caam_ctx *ctx = crypto_aead_ctx(tls); ++ int ecode = 0; ++ ++#ifdef DEBUG ++ dev_err(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); ++#endif ++ ++ if (unlikely(status)) { ++ caam_qi2_strstatus(ctx->dev, status); ++ ecode = -EIO; ++ } ++ ++ tls_unmap(ctx->dev, edesc, req); ++ qi_cache_free(edesc); ++ aead_request_complete(req, ecode); ++} ++ ++static void tls_decrypt_done(void *cbk_ctx, u32 status) ++{ ++ struct crypto_async_request *areq = cbk_ctx; ++ struct aead_request *req = container_of(areq, struct aead_request, ++ base); ++ struct caam_request *req_ctx = to_caam_req(areq); ++ struct tls_edesc *edesc = req_ctx->edesc; ++ struct crypto_aead *tls = crypto_aead_reqtfm(req); ++ struct caam_ctx *ctx = crypto_aead_ctx(tls); ++ int ecode = 0; ++ ++#ifdef DEBUG ++ dev_err(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); ++#endif ++ ++ if (unlikely(status)) { ++ caam_qi2_strstatus(ctx->dev, status); ++ /* ++ * verify hw auth check passed else return -EBADMSG ++ */ ++ if ((status & JRSTA_CCBERR_ERRID_MASK) == ++ JRSTA_CCBERR_ERRID_ICVCHK) ++ ecode = -EBADMSG; ++ else ++ ecode = -EIO; ++ } ++ ++ tls_unmap(ctx->dev, edesc, req); ++ qi_cache_free(edesc); ++ aead_request_complete(req, ecode); ++} ++ ++static int tls_encrypt(struct aead_request *req) ++{ ++ struct tls_edesc *edesc; ++ struct crypto_aead *tls = crypto_aead_reqtfm(req); ++ struct caam_ctx *ctx = crypto_aead_ctx(tls); ++ struct caam_request *caam_req = aead_request_ctx(req); ++ int ret; ++ ++ /* allocate extended descriptor */ ++ edesc = tls_edesc_alloc(req, true); ++ if (IS_ERR(edesc)) ++ return PTR_ERR(edesc); ++ ++ caam_req->flc = &ctx->flc[ENCRYPT]; ++ caam_req->op_type = ENCRYPT; ++ caam_req->cbk = tls_encrypt_done; ++ caam_req->ctx = &req->base; ++ caam_req->edesc = edesc; ++ ret = dpaa2_caam_enqueue(ctx->dev, caam_req); ++ if (ret != -EINPROGRESS && ++ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { ++ tls_unmap(ctx->dev, edesc, req); ++ qi_cache_free(edesc); ++ } ++ ++ return ret; ++} ++ ++static int tls_decrypt(struct aead_request *req) ++{ ++ struct tls_edesc *edesc; ++ struct crypto_aead *tls = crypto_aead_reqtfm(req); ++ struct caam_ctx *ctx = crypto_aead_ctx(tls); ++ struct caam_request *caam_req = aead_request_ctx(req); ++ int ret; ++ ++ /* allocate extended descriptor */ ++ edesc = tls_edesc_alloc(req, false); ++ if (IS_ERR(edesc)) ++ return PTR_ERR(edesc); ++ ++ caam_req->flc = &ctx->flc[DECRYPT]; ++ caam_req->op_type = DECRYPT; ++ caam_req->cbk = tls_decrypt_done; ++ caam_req->ctx = &req->base; ++ caam_req->edesc = edesc; ++ ret = dpaa2_caam_enqueue(ctx->dev, caam_req); ++ if (ret != -EINPROGRESS && ++ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { ++ tls_unmap(ctx->dev, edesc, req); ++ qi_cache_free(edesc); ++ } ++ ++ return ret; ++} ++ ++static int ipsec_gcm_encrypt(struct aead_request *req) ++{ ++ if (req->assoclen < 8) ++ return -EINVAL; ++ ++ return aead_encrypt(req); ++} ++ ++static int ipsec_gcm_decrypt(struct aead_request *req) ++{ ++ if (req->assoclen < 8) ++ return -EINVAL; ++ ++ return aead_decrypt(req); ++} ++ ++static void ablkcipher_done(void *cbk_ctx, u32 status) ++{ ++ struct crypto_async_request *areq = cbk_ctx; ++ struct ablkcipher_request *req = ablkcipher_request_cast(areq); ++ struct caam_request *req_ctx = to_caam_req(areq); ++ struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); ++ struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); ++ struct ablkcipher_edesc *edesc = req_ctx->edesc; ++ int ecode = 0; ++ int ivsize = crypto_ablkcipher_ivsize(ablkcipher); ++ ++#ifdef DEBUG ++ dev_err(ctx->dev, "%s %d: err 0x%x\n", __func__, __LINE__, status); ++#endif ++ ++ if (unlikely(status)) { ++ caam_qi2_strstatus(ctx->dev, status); ++ ecode = -EIO; ++ } ++ ++#ifdef DEBUG ++ print_hex_dump(KERN_ERR, "dstiv @" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, req->info, ++ edesc->src_nents > 1 ? 100 : ivsize, 1); ++ caam_dump_sg(KERN_ERR, "dst @" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, req->dst, ++ edesc->dst_nents > 1 ? 100 : req->nbytes, 1); ++#endif ++ ++ ablkcipher_unmap(ctx->dev, edesc, req); ++ qi_cache_free(edesc); ++ ++ /* ++ * The crypto API expects us to set the IV (req->info) to the last ++ * ciphertext block. This is used e.g. by the CTS mode. ++ */ ++ scatterwalk_map_and_copy(req->info, req->dst, req->nbytes - ivsize, ++ ivsize, 0); ++ ++ ablkcipher_request_complete(req, ecode); ++} ++ ++static int ablkcipher_encrypt(struct ablkcipher_request *req) ++{ ++ struct ablkcipher_edesc *edesc; ++ struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); ++ struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); ++ struct caam_request *caam_req = ablkcipher_request_ctx(req); ++ int ret; ++ ++ /* allocate extended descriptor */ ++ edesc = ablkcipher_edesc_alloc(req, true); ++ if (IS_ERR(edesc)) ++ return PTR_ERR(edesc); ++ ++ caam_req->flc = &ctx->flc[ENCRYPT]; ++ caam_req->op_type = ENCRYPT; ++ caam_req->cbk = ablkcipher_done; ++ caam_req->ctx = &req->base; ++ caam_req->edesc = edesc; ++ ret = dpaa2_caam_enqueue(ctx->dev, caam_req); ++ if (ret != -EINPROGRESS && ++ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { ++ ablkcipher_unmap(ctx->dev, edesc, req); ++ qi_cache_free(edesc); ++ } ++ ++ return ret; ++} ++ ++static int ablkcipher_givencrypt(struct skcipher_givcrypt_request *greq) ++{ ++ struct ablkcipher_request *req = &greq->creq; ++ struct ablkcipher_edesc *edesc; ++ struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); ++ struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); ++ struct caam_request *caam_req = ablkcipher_request_ctx(req); ++ int ret; ++ ++ /* allocate extended descriptor */ ++ edesc = ablkcipher_giv_edesc_alloc(greq); ++ if (IS_ERR(edesc)) ++ return PTR_ERR(edesc); ++ ++ caam_req->flc = &ctx->flc[GIVENCRYPT]; ++ caam_req->op_type = GIVENCRYPT; ++ caam_req->cbk = ablkcipher_done; ++ caam_req->ctx = &req->base; ++ caam_req->edesc = edesc; ++ ret = dpaa2_caam_enqueue(ctx->dev, caam_req); ++ if (ret != -EINPROGRESS && ++ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { ++ ablkcipher_unmap(ctx->dev, edesc, req); ++ qi_cache_free(edesc); ++ } ++ ++ return ret; ++} ++ ++static int ablkcipher_decrypt(struct ablkcipher_request *req) ++{ ++ struct ablkcipher_edesc *edesc; ++ struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req); ++ struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); ++ struct caam_request *caam_req = ablkcipher_request_ctx(req); ++ int ret; ++ ++ /* allocate extended descriptor */ ++ edesc = ablkcipher_edesc_alloc(req, false); ++ if (IS_ERR(edesc)) ++ return PTR_ERR(edesc); ++ ++ caam_req->flc = &ctx->flc[DECRYPT]; ++ caam_req->op_type = DECRYPT; ++ caam_req->cbk = ablkcipher_done; ++ caam_req->ctx = &req->base; ++ caam_req->edesc = edesc; ++ ret = dpaa2_caam_enqueue(ctx->dev, caam_req); ++ if (ret != -EINPROGRESS && ++ !(ret == -EBUSY && req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) { ++ ablkcipher_unmap(ctx->dev, edesc, req); ++ qi_cache_free(edesc); ++ } ++ ++ return ret; ++} ++ ++struct caam_crypto_alg { ++ struct list_head entry; ++ struct crypto_alg crypto_alg; ++ struct caam_alg_entry caam; ++}; ++ ++static int caam_cra_init(struct crypto_tfm *tfm) ++{ ++ struct crypto_alg *alg = tfm->__crt_alg; ++ struct caam_crypto_alg *caam_alg = container_of(alg, typeof(*caam_alg), ++ crypto_alg); ++ struct caam_ctx *ctx = crypto_tfm_ctx(tfm); ++ ++ /* copy descriptor header template value */ ++ ctx->cdata.algtype = OP_TYPE_CLASS1_ALG | ++ caam_alg->caam.class1_alg_type; ++ ctx->adata.algtype = OP_TYPE_CLASS2_ALG | ++ caam_alg->caam.class2_alg_type; ++ ++ ctx->dev = caam_alg->caam.dev; ++ ++ return 0; ++} ++ ++static int caam_cra_init_ablkcipher(struct crypto_tfm *tfm) ++{ ++ struct ablkcipher_tfm *ablkcipher_tfm = ++ crypto_ablkcipher_crt(__crypto_ablkcipher_cast(tfm)); ++ ++ ablkcipher_tfm->reqsize = sizeof(struct caam_request); ++ return caam_cra_init(tfm); ++} ++ ++static int caam_cra_init_aead(struct crypto_aead *tfm) ++{ ++ crypto_aead_set_reqsize(tfm, sizeof(struct caam_request)); ++ return caam_cra_init(crypto_aead_tfm(tfm)); ++} ++ ++static void caam_exit_common(struct caam_ctx *ctx) ++{ ++ int i; ++ ++ for (i = 0; i < NUM_OP; i++) { ++ if (!ctx->flc[i].flc_dma) ++ continue; ++ dma_unmap_single(ctx->dev, ctx->flc[i].flc_dma, ++ sizeof(ctx->flc[i].flc) + ++ desc_bytes(ctx->flc[i].sh_desc), ++ DMA_TO_DEVICE); ++ } ++ ++ if (ctx->key_dma) ++ dma_unmap_single(ctx->dev, ctx->key_dma, ++ ctx->cdata.keylen + ctx->adata.keylen_pad, ++ DMA_TO_DEVICE); ++} ++ ++static void caam_cra_exit(struct crypto_tfm *tfm) ++{ ++ caam_exit_common(crypto_tfm_ctx(tfm)); ++} ++ ++static void caam_cra_exit_aead(struct crypto_aead *tfm) ++{ ++ caam_exit_common(crypto_aead_ctx(tfm)); ++} ++ ++#define template_ablkcipher template_u.ablkcipher ++struct caam_alg_template { ++ char name[CRYPTO_MAX_ALG_NAME]; ++ char driver_name[CRYPTO_MAX_ALG_NAME]; ++ unsigned int blocksize; ++ u32 type; ++ union { ++ struct ablkcipher_alg ablkcipher; ++ } template_u; ++ u32 class1_alg_type; ++ u32 class2_alg_type; ++}; ++ ++static struct caam_alg_template driver_algs[] = { ++ /* ablkcipher descriptor */ ++ { ++ .name = "cbc(aes)", ++ .driver_name = "cbc-aes-caam-qi2", ++ .blocksize = AES_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_GIVCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .givencrypt = ablkcipher_givencrypt, ++ .geniv = "", ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ }, ++ { ++ .name = "cbc(des3_ede)", ++ .driver_name = "cbc-3des-caam-qi2", ++ .blocksize = DES3_EDE_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_GIVCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .givencrypt = ablkcipher_givencrypt, ++ .geniv = "", ++ .min_keysize = DES3_EDE_KEY_SIZE, ++ .max_keysize = DES3_EDE_KEY_SIZE, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ }, ++ { ++ .name = "cbc(des)", ++ .driver_name = "cbc-des-caam-qi2", ++ .blocksize = DES_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_GIVCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .givencrypt = ablkcipher_givencrypt, ++ .geniv = "", ++ .min_keysize = DES_KEY_SIZE, ++ .max_keysize = DES_KEY_SIZE, ++ .ivsize = DES_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ }, ++ { ++ .name = "ctr(aes)", ++ .driver_name = "ctr-aes-caam-qi2", ++ .blocksize = 1, ++ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "chainiv", ++ .min_keysize = AES_MIN_KEY_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, ++ }, ++ { ++ .name = "rfc3686(ctr(aes))", ++ .driver_name = "rfc3686-ctr-aes-caam-qi2", ++ .blocksize = 1, ++ .type = CRYPTO_ALG_TYPE_GIVCIPHER, ++ .template_ablkcipher = { ++ .setkey = ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .givencrypt = ablkcipher_givencrypt, ++ .geniv = "", ++ .min_keysize = AES_MIN_KEY_SIZE + ++ CTR_RFC3686_NONCE_SIZE, ++ .max_keysize = AES_MAX_KEY_SIZE + ++ CTR_RFC3686_NONCE_SIZE, ++ .ivsize = CTR_RFC3686_IV_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CTR_MOD128, ++ }, ++ { ++ .name = "xts(aes)", ++ .driver_name = "xts-aes-caam-qi2", ++ .blocksize = AES_BLOCK_SIZE, ++ .type = CRYPTO_ALG_TYPE_ABLKCIPHER, ++ .template_ablkcipher = { ++ .setkey = xts_ablkcipher_setkey, ++ .encrypt = ablkcipher_encrypt, ++ .decrypt = ablkcipher_decrypt, ++ .geniv = "eseqiv", ++ .min_keysize = 2 * AES_MIN_KEY_SIZE, ++ .max_keysize = 2 * AES_MAX_KEY_SIZE, ++ .ivsize = AES_BLOCK_SIZE, ++ }, ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XTS, ++ } ++}; ++ ++static struct caam_aead_alg driver_aeads[] = { ++ { ++ .aead = { ++ .base = { ++ .cra_name = "rfc4106(gcm(aes))", ++ .cra_driver_name = "rfc4106-gcm-aes-caam-qi2", ++ .cra_blocksize = 1, ++ }, ++ .setkey = rfc4106_setkey, ++ .setauthsize = rfc4106_setauthsize, ++ .encrypt = ipsec_gcm_encrypt, ++ .decrypt = ipsec_gcm_decrypt, ++ .ivsize = 8, ++ .maxauthsize = AES_BLOCK_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "rfc4543(gcm(aes))", ++ .cra_driver_name = "rfc4543-gcm-aes-caam-qi2", ++ .cra_blocksize = 1, ++ }, ++ .setkey = rfc4543_setkey, ++ .setauthsize = rfc4543_setauthsize, ++ .encrypt = ipsec_gcm_encrypt, ++ .decrypt = ipsec_gcm_decrypt, ++ .ivsize = 8, ++ .maxauthsize = AES_BLOCK_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM, ++ }, ++ }, ++ /* Galois Counter Mode */ ++ { ++ .aead = { ++ .base = { ++ .cra_name = "gcm(aes)", ++ .cra_driver_name = "gcm-aes-caam-qi2", ++ .cra_blocksize = 1, ++ }, ++ .setkey = gcm_setkey, ++ .setauthsize = gcm_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = 12, ++ .maxauthsize = AES_BLOCK_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_GCM, ++ } ++ }, ++ /* single-pass ipsec_esp descriptor */ ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(md5),cbc(aes))", ++ .cra_driver_name = "authenc-hmac-md5-" ++ "cbc-aes-caam-qi2", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = MD5_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_MD5 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(md5)," ++ "cbc(aes)))", ++ .cra_driver_name = "echainiv-authenc-hmac-md5-" ++ "cbc-aes-caam-qi2", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = MD5_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_MD5 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha1),cbc(aes))", ++ .cra_driver_name = "authenc-hmac-sha1-" ++ "cbc-aes-caam-qi2", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA1_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha1)," ++ "cbc(aes)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha1-cbc-aes-caam-qi2", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA1_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha224),cbc(aes))", ++ .cra_driver_name = "authenc-hmac-sha224-" ++ "cbc-aes-caam-qi2", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA224_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha224)," ++ "cbc(aes)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha224-cbc-aes-caam-qi2", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA224_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha256),cbc(aes))", ++ .cra_driver_name = "authenc-hmac-sha256-" ++ "cbc-aes-caam-qi2", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA256_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha256)," ++ "cbc(aes)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha256-cbc-aes-" ++ "caam-qi2", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA256_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha384),cbc(aes))", ++ .cra_driver_name = "authenc-hmac-sha384-" ++ "cbc-aes-caam-qi2", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA384_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha384)," ++ "cbc(aes)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha384-cbc-aes-" ++ "caam-qi2", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA384_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha512),cbc(aes))", ++ .cra_driver_name = "authenc-hmac-sha512-" ++ "cbc-aes-caam-qi2", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA512_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha512)," ++ "cbc(aes)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha512-cbc-aes-" ++ "caam-qi2", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA512_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(md5),cbc(des3_ede))", ++ .cra_driver_name = "authenc-hmac-md5-" ++ "cbc-des3_ede-caam-qi2", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = MD5_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_MD5 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(md5)," ++ "cbc(des3_ede)))", ++ .cra_driver_name = "echainiv-authenc-hmac-md5-" ++ "cbc-des3_ede-caam-qi2", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = MD5_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_MD5 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha1)," ++ "cbc(des3_ede))", ++ .cra_driver_name = "authenc-hmac-sha1-" ++ "cbc-des3_ede-caam-qi2", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA1_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha1)," ++ "cbc(des3_ede)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha1-" ++ "cbc-des3_ede-caam-qi2", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA1_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha224)," ++ "cbc(des3_ede))", ++ .cra_driver_name = "authenc-hmac-sha224-" ++ "cbc-des3_ede-caam-qi2", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA224_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha224)," ++ "cbc(des3_ede)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha224-" ++ "cbc-des3_ede-caam-qi2", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA224_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha256)," ++ "cbc(des3_ede))", ++ .cra_driver_name = "authenc-hmac-sha256-" ++ "cbc-des3_ede-caam-qi2", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA256_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha256)," ++ "cbc(des3_ede)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha256-" ++ "cbc-des3_ede-caam-qi2", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA256_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha384)," ++ "cbc(des3_ede))", ++ .cra_driver_name = "authenc-hmac-sha384-" ++ "cbc-des3_ede-caam-qi2", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA384_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha384)," ++ "cbc(des3_ede)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha384-" ++ "cbc-des3_ede-caam-qi2", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA384_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha512)," ++ "cbc(des3_ede))", ++ .cra_driver_name = "authenc-hmac-sha512-" ++ "cbc-des3_ede-caam-qi2", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA512_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha512)," ++ "cbc(des3_ede)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha512-" ++ "cbc-des3_ede-caam-qi2", ++ .cra_blocksize = DES3_EDE_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES3_EDE_BLOCK_SIZE, ++ .maxauthsize = SHA512_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(md5),cbc(des))", ++ .cra_driver_name = "authenc-hmac-md5-" ++ "cbc-des-caam-qi2", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = MD5_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_MD5 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(md5)," ++ "cbc(des)))", ++ .cra_driver_name = "echainiv-authenc-hmac-md5-" ++ "cbc-des-caam-qi2", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = MD5_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_MD5 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha1),cbc(des))", ++ .cra_driver_name = "authenc-hmac-sha1-" ++ "cbc-des-caam-qi2", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA1_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha1)," ++ "cbc(des)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha1-cbc-des-caam-qi2", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA1_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha224),cbc(des))", ++ .cra_driver_name = "authenc-hmac-sha224-" ++ "cbc-des-caam-qi2", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA224_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha224)," ++ "cbc(des)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha224-cbc-des-" ++ "caam-qi2", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA224_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha256),cbc(des))", ++ .cra_driver_name = "authenc-hmac-sha256-" ++ "cbc-des-caam-qi2", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA256_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha256)," ++ "cbc(des)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha256-cbc-desi-" ++ "caam-qi2", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA256_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha384),cbc(des))", ++ .cra_driver_name = "authenc-hmac-sha384-" ++ "cbc-des-caam-qi2", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA384_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha384)," ++ "cbc(des)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha384-cbc-des-" ++ "caam-qi2", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA384_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha512),cbc(des))", ++ .cra_driver_name = "authenc-hmac-sha512-" ++ "cbc-des-caam-qi2", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA512_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "echainiv(authenc(hmac(sha512)," ++ "cbc(des)))", ++ .cra_driver_name = "echainiv-authenc-" ++ "hmac-sha512-cbc-des-" ++ "caam-qi2", ++ .cra_blocksize = DES_BLOCK_SIZE, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = DES_BLOCK_SIZE, ++ .maxauthsize = SHA512_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .geniv = true, ++ } ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(md5)," ++ "rfc3686(ctr(aes)))", ++ .cra_driver_name = "authenc-hmac-md5-" ++ "rfc3686-ctr-aes-caam-qi2", ++ .cra_blocksize = 1, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = CTR_RFC3686_IV_SIZE, ++ .maxauthsize = MD5_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | ++ OP_ALG_AAI_CTR_MOD128, ++ .class2_alg_type = OP_ALG_ALGSEL_MD5 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .rfc3686 = true, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "seqiv(authenc(" ++ "hmac(md5),rfc3686(ctr(aes))))", ++ .cra_driver_name = "seqiv-authenc-hmac-md5-" ++ "rfc3686-ctr-aes-caam-qi2", ++ .cra_blocksize = 1, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = CTR_RFC3686_IV_SIZE, ++ .maxauthsize = MD5_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | ++ OP_ALG_AAI_CTR_MOD128, ++ .class2_alg_type = OP_ALG_ALGSEL_MD5 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .rfc3686 = true, ++ .geniv = true, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha1)," ++ "rfc3686(ctr(aes)))", ++ .cra_driver_name = "authenc-hmac-sha1-" ++ "rfc3686-ctr-aes-caam-qi2", ++ .cra_blocksize = 1, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = CTR_RFC3686_IV_SIZE, ++ .maxauthsize = SHA1_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | ++ OP_ALG_AAI_CTR_MOD128, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .rfc3686 = true, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "seqiv(authenc(" ++ "hmac(sha1),rfc3686(ctr(aes))))", ++ .cra_driver_name = "seqiv-authenc-hmac-sha1-" ++ "rfc3686-ctr-aes-caam-qi2", ++ .cra_blocksize = 1, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = CTR_RFC3686_IV_SIZE, ++ .maxauthsize = SHA1_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | ++ OP_ALG_AAI_CTR_MOD128, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .rfc3686 = true, ++ .geniv = true, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha224)," ++ "rfc3686(ctr(aes)))", ++ .cra_driver_name = "authenc-hmac-sha224-" ++ "rfc3686-ctr-aes-caam-qi2", ++ .cra_blocksize = 1, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = CTR_RFC3686_IV_SIZE, ++ .maxauthsize = SHA224_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | ++ OP_ALG_AAI_CTR_MOD128, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .rfc3686 = true, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "seqiv(authenc(" ++ "hmac(sha224),rfc3686(ctr(aes))))", ++ .cra_driver_name = "seqiv-authenc-hmac-sha224-" ++ "rfc3686-ctr-aes-caam-qi2", ++ .cra_blocksize = 1, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = CTR_RFC3686_IV_SIZE, ++ .maxauthsize = SHA224_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | ++ OP_ALG_AAI_CTR_MOD128, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA224 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .rfc3686 = true, ++ .geniv = true, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha256)," ++ "rfc3686(ctr(aes)))", ++ .cra_driver_name = "authenc-hmac-sha256-" ++ "rfc3686-ctr-aes-caam-qi2", ++ .cra_blocksize = 1, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = CTR_RFC3686_IV_SIZE, ++ .maxauthsize = SHA256_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | ++ OP_ALG_AAI_CTR_MOD128, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .rfc3686 = true, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "seqiv(authenc(hmac(sha256)," ++ "rfc3686(ctr(aes))))", ++ .cra_driver_name = "seqiv-authenc-hmac-sha256-" ++ "rfc3686-ctr-aes-caam-qi2", ++ .cra_blocksize = 1, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = CTR_RFC3686_IV_SIZE, ++ .maxauthsize = SHA256_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | ++ OP_ALG_AAI_CTR_MOD128, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA256 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .rfc3686 = true, ++ .geniv = true, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha384)," ++ "rfc3686(ctr(aes)))", ++ .cra_driver_name = "authenc-hmac-sha384-" ++ "rfc3686-ctr-aes-caam-qi2", ++ .cra_blocksize = 1, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = CTR_RFC3686_IV_SIZE, ++ .maxauthsize = SHA384_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | ++ OP_ALG_AAI_CTR_MOD128, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .rfc3686 = true, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "seqiv(authenc(hmac(sha384)," ++ "rfc3686(ctr(aes))))", ++ .cra_driver_name = "seqiv-authenc-hmac-sha384-" ++ "rfc3686-ctr-aes-caam-qi2", ++ .cra_blocksize = 1, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = CTR_RFC3686_IV_SIZE, ++ .maxauthsize = SHA384_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | ++ OP_ALG_AAI_CTR_MOD128, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA384 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .rfc3686 = true, ++ .geniv = true, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "authenc(hmac(sha512)," ++ "rfc3686(ctr(aes)))", ++ .cra_driver_name = "authenc-hmac-sha512-" ++ "rfc3686-ctr-aes-caam-qi2", ++ .cra_blocksize = 1, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = CTR_RFC3686_IV_SIZE, ++ .maxauthsize = SHA512_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | ++ OP_ALG_AAI_CTR_MOD128, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .rfc3686 = true, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "seqiv(authenc(hmac(sha512)," ++ "rfc3686(ctr(aes))))", ++ .cra_driver_name = "seqiv-authenc-hmac-sha512-" ++ "rfc3686-ctr-aes-caam-qi2", ++ .cra_blocksize = 1, ++ }, ++ .setkey = aead_setkey, ++ .setauthsize = aead_setauthsize, ++ .encrypt = aead_encrypt, ++ .decrypt = aead_decrypt, ++ .ivsize = CTR_RFC3686_IV_SIZE, ++ .maxauthsize = SHA512_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | ++ OP_ALG_AAI_CTR_MOD128, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA512 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ .rfc3686 = true, ++ .geniv = true, ++ }, ++ }, ++ { ++ .aead = { ++ .base = { ++ .cra_name = "tls10(hmac(sha1),cbc(aes))", ++ .cra_driver_name = "tls10-hmac-sha1-cbc-aes-caam-qi2", ++ .cra_blocksize = AES_BLOCK_SIZE, ++ }, ++ .setkey = tls_setkey, ++ .setauthsize = tls_setauthsize, ++ .encrypt = tls_encrypt, ++ .decrypt = tls_decrypt, ++ .ivsize = AES_BLOCK_SIZE, ++ .maxauthsize = SHA1_DIGEST_SIZE, ++ }, ++ .caam = { ++ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, ++ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | ++ OP_ALG_AAI_HMAC_PRECOMP, ++ }, ++ }, ++}; ++ ++static struct caam_crypto_alg *caam_alg_alloc(struct caam_alg_template ++ *template) ++{ ++ struct caam_crypto_alg *t_alg; ++ struct crypto_alg *alg; ++ ++ t_alg = kzalloc(sizeof(*t_alg), GFP_KERNEL); ++ if (!t_alg) ++ return ERR_PTR(-ENOMEM); ++ ++ alg = &t_alg->crypto_alg; ++ ++ snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name); ++ snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", ++ template->driver_name); ++ alg->cra_module = THIS_MODULE; ++ alg->cra_exit = caam_cra_exit; ++ alg->cra_priority = CAAM_CRA_PRIORITY; ++ alg->cra_blocksize = template->blocksize; ++ alg->cra_alignmask = 0; ++ alg->cra_ctxsize = sizeof(struct caam_ctx); ++ alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | ++ template->type; ++ switch (template->type) { ++ case CRYPTO_ALG_TYPE_GIVCIPHER: ++ alg->cra_init = caam_cra_init_ablkcipher; ++ alg->cra_type = &crypto_givcipher_type; ++ alg->cra_ablkcipher = template->template_ablkcipher; ++ break; ++ case CRYPTO_ALG_TYPE_ABLKCIPHER: ++ alg->cra_init = caam_cra_init_ablkcipher; ++ alg->cra_type = &crypto_ablkcipher_type; ++ alg->cra_ablkcipher = template->template_ablkcipher; ++ break; ++ } ++ ++ t_alg->caam.class1_alg_type = template->class1_alg_type; ++ t_alg->caam.class2_alg_type = template->class2_alg_type; ++ ++ return t_alg; ++} ++ ++static void caam_aead_alg_init(struct caam_aead_alg *t_alg) ++{ ++ struct aead_alg *alg = &t_alg->aead; ++ ++ alg->base.cra_module = THIS_MODULE; ++ alg->base.cra_priority = CAAM_CRA_PRIORITY; ++ alg->base.cra_ctxsize = sizeof(struct caam_ctx); ++ alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY; ++ ++ alg->init = caam_cra_init_aead; ++ alg->exit = caam_cra_exit_aead; ++} ++ ++static void dpaa2_caam_fqdan_cb(struct dpaa2_io_notification_ctx *nctx) ++{ ++ struct dpaa2_caam_priv_per_cpu *ppriv; ++ ++ ppriv = container_of(nctx, struct dpaa2_caam_priv_per_cpu, nctx); ++ napi_schedule_irqoff(&ppriv->napi); ++} ++ ++static int __cold dpaa2_dpseci_dpio_setup(struct dpaa2_caam_priv *priv) ++{ ++ struct device *dev = priv->dev; ++ struct dpaa2_io_notification_ctx *nctx; ++ struct dpaa2_caam_priv_per_cpu *ppriv; ++ int err, i = 0, cpu; ++ ++ for_each_online_cpu(cpu) { ++ ppriv = per_cpu_ptr(priv->ppriv, cpu); ++ ppriv->priv = priv; ++ nctx = &ppriv->nctx; ++ nctx->is_cdan = 0; ++ nctx->id = ppriv->rsp_fqid; ++ nctx->desired_cpu = cpu; ++ nctx->cb = dpaa2_caam_fqdan_cb; ++ ++ /* Register notification callbacks */ ++ err = dpaa2_io_service_register(NULL, nctx); ++ if (unlikely(err)) { ++ dev_err(dev, "notification register failed\n"); ++ nctx->cb = NULL; ++ goto err; ++ } ++ ++ ppriv->store = dpaa2_io_store_create(DPAA2_CAAM_STORE_SIZE, ++ dev); ++ if (unlikely(!ppriv->store)) { ++ dev_err(dev, "dpaa2_io_store_create() failed\n"); ++ goto err; ++ } ++ ++ if (++i == priv->num_pairs) ++ break; ++ } ++ ++ return 0; ++ ++err: ++ for_each_online_cpu(cpu) { ++ ppriv = per_cpu_ptr(priv->ppriv, cpu); ++ if (!ppriv->nctx.cb) ++ break; ++ dpaa2_io_service_deregister(NULL, &ppriv->nctx); ++ } ++ ++ for_each_online_cpu(cpu) { ++ ppriv = per_cpu_ptr(priv->ppriv, cpu); ++ if (!ppriv->store) ++ break; ++ dpaa2_io_store_destroy(ppriv->store); ++ } ++ ++ return err; ++} ++ ++static void __cold dpaa2_dpseci_dpio_free(struct dpaa2_caam_priv *priv) ++{ ++ struct dpaa2_caam_priv_per_cpu *ppriv; ++ int i = 0, cpu; ++ ++ for_each_online_cpu(cpu) { ++ ppriv = per_cpu_ptr(priv->ppriv, cpu); ++ dpaa2_io_service_deregister(NULL, &ppriv->nctx); ++ dpaa2_io_store_destroy(ppriv->store); ++ ++ if (++i == priv->num_pairs) ++ return; ++ } ++} ++ ++static int dpaa2_dpseci_bind(struct dpaa2_caam_priv *priv) ++{ ++ struct dpseci_rx_queue_cfg rx_queue_cfg; ++ struct device *dev = priv->dev; ++ struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev); ++ struct dpaa2_caam_priv_per_cpu *ppriv; ++ int err = 0, i = 0, cpu; ++ ++ /* Configure Rx queues */ ++ for_each_online_cpu(cpu) { ++ ppriv = per_cpu_ptr(priv->ppriv, cpu); ++ ++ rx_queue_cfg.options = DPSECI_QUEUE_OPT_DEST | ++ DPSECI_QUEUE_OPT_USER_CTX; ++ rx_queue_cfg.order_preservation_en = 0; ++ rx_queue_cfg.dest_cfg.dest_type = DPSECI_DEST_DPIO; ++ rx_queue_cfg.dest_cfg.dest_id = ppriv->nctx.dpio_id; ++ /* ++ * Rx priority (WQ) doesn't really matter, since we use ++ * pull mode, i.e. volatile dequeues from specific FQs ++ */ ++ rx_queue_cfg.dest_cfg.priority = 0; ++ rx_queue_cfg.user_ctx = ppriv->nctx.qman64; ++ ++ err = dpseci_set_rx_queue(priv->mc_io, 0, ls_dev->mc_handle, i, ++ &rx_queue_cfg); ++ if (err) { ++ dev_err(dev, "dpseci_set_rx_queue() failed with err %d\n", ++ err); ++ return err; ++ } ++ ++ if (++i == priv->num_pairs) ++ break; ++ } ++ ++ return err; ++} ++ ++static void dpaa2_dpseci_congestion_free(struct dpaa2_caam_priv *priv) ++{ ++ struct device *dev = priv->dev; ++ ++ if (!priv->cscn_mem) ++ return; ++ ++ dma_unmap_single(dev, priv->cscn_dma, DPAA2_CSCN_SIZE, DMA_FROM_DEVICE); ++ kfree(priv->cscn_mem); ++} ++ ++static void dpaa2_dpseci_free(struct dpaa2_caam_priv *priv) ++{ ++ struct device *dev = priv->dev; ++ struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev); ++ ++ dpaa2_dpseci_congestion_free(priv); ++ dpseci_close(priv->mc_io, 0, ls_dev->mc_handle); ++} ++ ++static void dpaa2_caam_process_fd(struct dpaa2_caam_priv *priv, ++ const struct dpaa2_fd *fd) ++{ ++ struct caam_request *req; ++ u32 fd_err; ++ ++ if (dpaa2_fd_get_format(fd) != dpaa2_fd_list) { ++ dev_err(priv->dev, "Only Frame List FD format is supported!\n"); ++ return; ++ } ++ ++ fd_err = dpaa2_fd_get_ctrl(fd) & FD_CTRL_ERR_MASK; ++ if (unlikely(fd_err)) ++ dev_err(priv->dev, "FD error: %08x\n", fd_err); ++ ++ /* ++ * FD[ADDR] is guaranteed to be valid, irrespective of errors reported ++ * in FD[ERR] or FD[FRC]. ++ */ ++ req = dpaa2_caam_iova_to_virt(priv, dpaa2_fd_get_addr(fd)); ++ dma_unmap_single(priv->dev, req->fd_flt_dma, sizeof(req->fd_flt), ++ DMA_BIDIRECTIONAL); ++ req->cbk(req->ctx, dpaa2_fd_get_frc(fd)); ++} ++ ++static int dpaa2_caam_pull_fq(struct dpaa2_caam_priv_per_cpu *ppriv) ++{ ++ int err; ++ ++ /* Retry while portal is busy */ ++ do { ++ err = dpaa2_io_service_pull_fq(NULL, ppriv->rsp_fqid, ++ ppriv->store); ++ } while (err == -EBUSY); ++ ++ if (unlikely(err)) ++ dev_err(ppriv->priv->dev, "dpaa2_io_service_pull err %d", err); ++ ++ return err; ++} ++ ++static int dpaa2_caam_store_consume(struct dpaa2_caam_priv_per_cpu *ppriv) ++{ ++ struct dpaa2_dq *dq; ++ int cleaned = 0, is_last; ++ ++ do { ++ dq = dpaa2_io_store_next(ppriv->store, &is_last); ++ if (unlikely(!dq)) { ++ if (unlikely(!is_last)) { ++ dev_dbg(ppriv->priv->dev, ++ "FQ %d returned no valid frames\n", ++ ppriv->rsp_fqid); ++ /* ++ * MUST retry until we get some sort of ++ * valid response token (be it "empty dequeue" ++ * or a valid frame). ++ */ ++ continue; ++ } ++ break; ++ } ++ ++ /* Process FD */ ++ dpaa2_caam_process_fd(ppriv->priv, dpaa2_dq_fd(dq)); ++ cleaned++; ++ } while (!is_last); ++ ++ return cleaned; ++} ++ ++static int dpaa2_dpseci_poll(struct napi_struct *napi, int budget) ++{ ++ struct dpaa2_caam_priv_per_cpu *ppriv; ++ struct dpaa2_caam_priv *priv; ++ int err, cleaned = 0, store_cleaned; ++ ++ ppriv = container_of(napi, struct dpaa2_caam_priv_per_cpu, napi); ++ priv = ppriv->priv; ++ ++ if (unlikely(dpaa2_caam_pull_fq(ppriv))) ++ return 0; ++ ++ do { ++ store_cleaned = dpaa2_caam_store_consume(ppriv); ++ cleaned += store_cleaned; ++ ++ if (store_cleaned == 0 || ++ cleaned > budget - DPAA2_CAAM_STORE_SIZE) ++ break; ++ ++ /* Try to dequeue some more */ ++ err = dpaa2_caam_pull_fq(ppriv); ++ if (unlikely(err)) ++ break; ++ } while (1); ++ ++ if (cleaned < budget) { ++ napi_complete_done(napi, cleaned); ++ err = dpaa2_io_service_rearm(NULL, &ppriv->nctx); ++ if (unlikely(err)) ++ dev_err(priv->dev, "Notification rearm failed: %d\n", ++ err); ++ } ++ ++ return cleaned; ++} ++ ++static int dpaa2_dpseci_congestion_setup(struct dpaa2_caam_priv *priv, ++ u16 token) ++{ ++ struct dpseci_congestion_notification_cfg cong_notif_cfg = { 0 }; ++ struct device *dev = priv->dev; ++ int err; ++ ++ /* ++ * Congestion group feature supported starting with DPSECI API v5.1 ++ * and only when object has been created with this capability. ++ */ ++ if ((DPSECI_VER(priv->major_ver, priv->minor_ver) < DPSECI_VER(5, 1)) || ++ !(priv->dpseci_attr.options & DPSECI_OPT_HAS_CG)) ++ return 0; ++ ++ priv->cscn_mem = kzalloc(DPAA2_CSCN_SIZE + DPAA2_CSCN_ALIGN, ++ GFP_KERNEL | GFP_DMA); ++ if (!priv->cscn_mem) ++ return -ENOMEM; ++ ++ priv->cscn_mem_aligned = PTR_ALIGN(priv->cscn_mem, DPAA2_CSCN_ALIGN); ++ priv->cscn_dma = dma_map_single(dev, priv->cscn_mem_aligned, ++ DPAA2_CSCN_SIZE, DMA_FROM_DEVICE); ++ if (dma_mapping_error(dev, priv->cscn_dma)) { ++ dev_err(dev, "Error mapping CSCN memory area\n"); ++ err = -ENOMEM; ++ goto err_dma_map; ++ } ++ ++ cong_notif_cfg.units = DPSECI_CONGESTION_UNIT_BYTES; ++ cong_notif_cfg.threshold_entry = DPAA2_SEC_CONG_ENTRY_THRESH; ++ cong_notif_cfg.threshold_exit = DPAA2_SEC_CONG_EXIT_THRESH; ++ cong_notif_cfg.message_ctx = (u64)priv; ++ cong_notif_cfg.message_iova = priv->cscn_dma; ++ cong_notif_cfg.notification_mode = DPSECI_CGN_MODE_WRITE_MEM_ON_ENTER | ++ DPSECI_CGN_MODE_WRITE_MEM_ON_EXIT | ++ DPSECI_CGN_MODE_COHERENT_WRITE; ++ ++ err = dpseci_set_congestion_notification(priv->mc_io, 0, token, ++ &cong_notif_cfg); ++ if (err) { ++ dev_err(dev, "dpseci_set_congestion_notification failed\n"); ++ goto err_set_cong; ++ } ++ ++ return 0; ++ ++err_set_cong: ++ dma_unmap_single(dev, priv->cscn_dma, DPAA2_CSCN_SIZE, DMA_FROM_DEVICE); ++err_dma_map: ++ kfree(priv->cscn_mem); ++ ++ return err; ++} ++ ++static int __cold dpaa2_dpseci_setup(struct fsl_mc_device *ls_dev) ++{ ++ struct device *dev = &ls_dev->dev; ++ struct dpaa2_caam_priv *priv; ++ struct dpaa2_caam_priv_per_cpu *ppriv; ++ int err, cpu; ++ u8 i; ++ ++ priv = dev_get_drvdata(dev); ++ ++ priv->dev = dev; ++ priv->dpsec_id = ls_dev->obj_desc.id; ++ ++ /* Get a handle for the DPSECI this interface is associate with */ ++ err = dpseci_open(priv->mc_io, 0, priv->dpsec_id, &ls_dev->mc_handle); ++ if (err) { ++ dev_err(dev, "dpsec_open() failed: %d\n", err); ++ goto err_open; ++ } ++ ++ dev_info(dev, "Opened dpseci object successfully\n"); ++ ++ err = dpseci_get_api_version(priv->mc_io, 0, &priv->major_ver, ++ &priv->minor_ver); ++ if (err) { ++ dev_err(dev, "dpseci_get_api_version() failed\n"); ++ goto err_get_vers; ++ } ++ ++ err = dpseci_get_attributes(priv->mc_io, 0, ls_dev->mc_handle, ++ &priv->dpseci_attr); ++ if (err) { ++ dev_err(dev, "dpseci_get_attributes() failed\n"); ++ goto err_get_vers; ++ } ++ ++ err = dpseci_get_sec_attr(priv->mc_io, 0, ls_dev->mc_handle, ++ &priv->sec_attr); ++ if (err) { ++ dev_err(dev, "dpseci_get_sec_attr() failed\n"); ++ goto err_get_vers; ++ } ++ ++ err = dpaa2_dpseci_congestion_setup(priv, ls_dev->mc_handle); ++ if (err) { ++ dev_err(dev, "setup_congestion() failed\n"); ++ goto err_get_vers; ++ } ++ ++ priv->num_pairs = min(priv->dpseci_attr.num_rx_queues, ++ priv->dpseci_attr.num_tx_queues); ++ if (priv->num_pairs > num_online_cpus()) { ++ dev_warn(dev, "%d queues won't be used\n", ++ priv->num_pairs - num_online_cpus()); ++ priv->num_pairs = num_online_cpus(); ++ } ++ ++ for (i = 0; i < priv->dpseci_attr.num_rx_queues; i++) { ++ err = dpseci_get_rx_queue(priv->mc_io, 0, ls_dev->mc_handle, i, ++ &priv->rx_queue_attr[i]); ++ if (err) { ++ dev_err(dev, "dpseci_get_rx_queue() failed\n"); ++ goto err_get_rx_queue; ++ } ++ } ++ ++ for (i = 0; i < priv->dpseci_attr.num_tx_queues; i++) { ++ err = dpseci_get_tx_queue(priv->mc_io, 0, ls_dev->mc_handle, i, ++ &priv->tx_queue_attr[i]); ++ if (err) { ++ dev_err(dev, "dpseci_get_tx_queue() failed\n"); ++ goto err_get_rx_queue; ++ } ++ } ++ ++ i = 0; ++ for_each_online_cpu(cpu) { ++ dev_info(dev, "prio %d: rx queue %d, tx queue %d\n", i, ++ priv->rx_queue_attr[i].fqid, ++ priv->tx_queue_attr[i].fqid); ++ ++ ppriv = per_cpu_ptr(priv->ppriv, cpu); ++ ppriv->req_fqid = priv->tx_queue_attr[i].fqid; ++ ppriv->rsp_fqid = priv->rx_queue_attr[i].fqid; ++ ppriv->prio = i; ++ ++ ppriv->net_dev.dev = *dev; ++ INIT_LIST_HEAD(&ppriv->net_dev.napi_list); ++ netif_napi_add(&ppriv->net_dev, &ppriv->napi, dpaa2_dpseci_poll, ++ DPAA2_CAAM_NAPI_WEIGHT); ++ if (++i == priv->num_pairs) ++ break; ++ } ++ ++ return 0; ++ ++err_get_rx_queue: ++ dpaa2_dpseci_congestion_free(priv); ++err_get_vers: ++ dpseci_close(priv->mc_io, 0, ls_dev->mc_handle); ++err_open: ++ return err; ++} ++ ++static int dpaa2_dpseci_enable(struct dpaa2_caam_priv *priv) ++{ ++ struct device *dev = priv->dev; ++ struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev); ++ struct dpaa2_caam_priv_per_cpu *ppriv; ++ int err, i; ++ ++ for (i = 0; i < priv->num_pairs; i++) { ++ ppriv = per_cpu_ptr(priv->ppriv, i); ++ napi_enable(&ppriv->napi); ++ } ++ ++ err = dpseci_enable(priv->mc_io, 0, ls_dev->mc_handle); ++ if (err) { ++ dev_err(dev, "dpseci_enable() failed\n"); ++ return err; ++ } ++ ++ dev_info(dev, "DPSECI version %d.%d\n", ++ priv->major_ver, ++ priv->minor_ver); ++ ++ return 0; ++} ++ ++static int __cold dpaa2_dpseci_disable(struct dpaa2_caam_priv *priv) ++{ ++ struct device *dev = priv->dev; ++ struct dpaa2_caam_priv_per_cpu *ppriv; ++ struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev); ++ int i, err = 0, enabled; ++ ++ err = dpseci_disable(priv->mc_io, 0, ls_dev->mc_handle); ++ if (err) { ++ dev_err(dev, "dpseci_disable() failed\n"); ++ return err; ++ } ++ ++ err = dpseci_is_enabled(priv->mc_io, 0, ls_dev->mc_handle, &enabled); ++ if (err) { ++ dev_err(dev, "dpseci_is_enabled() failed\n"); ++ return err; ++ } ++ ++ dev_dbg(dev, "disable: %s\n", enabled ? "false" : "true"); ++ ++ for (i = 0; i < priv->num_pairs; i++) { ++ ppriv = per_cpu_ptr(priv->ppriv, i); ++ napi_disable(&ppriv->napi); ++ netif_napi_del(&ppriv->napi); ++ } ++ ++ return 0; ++} ++ ++static struct list_head alg_list; ++ ++static int dpaa2_caam_probe(struct fsl_mc_device *dpseci_dev) ++{ ++ struct device *dev; ++ struct dpaa2_caam_priv *priv; ++ int i, err = 0; ++ bool registered = false; ++ ++ /* ++ * There is no way to get CAAM endianness - there is no direct register ++ * space access and MC f/w does not provide this attribute. ++ * All DPAA2-based SoCs have little endian CAAM, thus hard-code this ++ * property. ++ */ ++ caam_little_end = true; ++ ++ caam_imx = false; ++ ++ dev = &dpseci_dev->dev; ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ dev_set_drvdata(dev, priv); ++ ++ priv->domain = iommu_get_domain_for_dev(dev); ++ ++ qi_cache = kmem_cache_create("dpaa2_caamqicache", CAAM_QI_MEMCACHE_SIZE, ++ 0, SLAB_CACHE_DMA, NULL); ++ if (!qi_cache) { ++ dev_err(dev, "Can't allocate SEC cache\n"); ++ err = -ENOMEM; ++ goto err_qicache; ++ } ++ ++ err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(49)); ++ if (err) { ++ dev_err(dev, "dma_set_mask_and_coherent() failed\n"); ++ goto err_dma_mask; ++ } ++ ++ /* Obtain a MC portal */ ++ err = fsl_mc_portal_allocate(dpseci_dev, 0, &priv->mc_io); ++ if (err) { ++ dev_err(dev, "MC portal allocation failed\n"); ++ goto err_dma_mask; ++ } ++ ++ priv->ppriv = alloc_percpu(*priv->ppriv); ++ if (!priv->ppriv) { ++ dev_err(dev, "alloc_percpu() failed\n"); ++ goto err_alloc_ppriv; ++ } ++ ++ /* DPSECI initialization */ ++ err = dpaa2_dpseci_setup(dpseci_dev); ++ if (err < 0) { ++ dev_err(dev, "dpaa2_dpseci_setup() failed\n"); ++ goto err_dpseci_setup; ++ } ++ ++ /* DPIO */ ++ err = dpaa2_dpseci_dpio_setup(priv); ++ if (err) { ++ dev_err(dev, "dpaa2_dpseci_dpio_setup() failed\n"); ++ goto err_dpio_setup; ++ } ++ ++ /* DPSECI binding to DPIO */ ++ err = dpaa2_dpseci_bind(priv); ++ if (err) { ++ dev_err(dev, "dpaa2_dpseci_bind() failed\n"); ++ goto err_bind; ++ } ++ ++ /* DPSECI enable */ ++ err = dpaa2_dpseci_enable(priv); ++ if (err) { ++ dev_err(dev, "dpaa2_dpseci_enable() failed"); ++ goto err_bind; ++ } ++ ++ /* register crypto algorithms the device supports */ ++ INIT_LIST_HEAD(&alg_list); ++ for (i = 0; i < ARRAY_SIZE(driver_algs); i++) { ++ struct caam_crypto_alg *t_alg; ++ struct caam_alg_template *alg = driver_algs + i; ++ u32 alg_sel = alg->class1_alg_type & OP_ALG_ALGSEL_MASK; ++ ++ /* Skip DES algorithms if not supported by device */ ++ if (!priv->sec_attr.des_acc_num && ++ ((alg_sel == OP_ALG_ALGSEL_3DES) || ++ (alg_sel == OP_ALG_ALGSEL_DES))) ++ continue; ++ ++ /* Skip AES algorithms if not supported by device */ ++ if (!priv->sec_attr.aes_acc_num && ++ (alg_sel == OP_ALG_ALGSEL_AES)) ++ continue; ++ ++ t_alg = caam_alg_alloc(alg); ++ if (IS_ERR(t_alg)) { ++ err = PTR_ERR(t_alg); ++ dev_warn(dev, "%s alg allocation failed: %d\n", ++ alg->driver_name, err); ++ continue; ++ } ++ t_alg->caam.dev = dev; ++ ++ err = crypto_register_alg(&t_alg->crypto_alg); ++ if (err) { ++ dev_warn(dev, "%s alg registration failed: %d\n", ++ t_alg->crypto_alg.cra_driver_name, err); ++ kfree(t_alg); ++ continue; ++ } ++ ++ list_add_tail(&t_alg->entry, &alg_list); ++ registered = true; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) { ++ struct caam_aead_alg *t_alg = driver_aeads + i; ++ u32 c1_alg_sel = t_alg->caam.class1_alg_type & ++ OP_ALG_ALGSEL_MASK; ++ u32 c2_alg_sel = t_alg->caam.class2_alg_type & ++ OP_ALG_ALGSEL_MASK; ++ ++ /* Skip DES algorithms if not supported by device */ ++ if (!priv->sec_attr.des_acc_num && ++ ((c1_alg_sel == OP_ALG_ALGSEL_3DES) || ++ (c1_alg_sel == OP_ALG_ALGSEL_DES))) ++ continue; ++ ++ /* Skip AES algorithms if not supported by device */ ++ if (!priv->sec_attr.aes_acc_num && ++ (c1_alg_sel == OP_ALG_ALGSEL_AES)) ++ continue; ++ ++ /* ++ * Skip algorithms requiring message digests ++ * if MD not supported by device. ++ */ ++ if (!priv->sec_attr.md_acc_num && c2_alg_sel) ++ continue; ++ ++ t_alg->caam.dev = dev; ++ caam_aead_alg_init(t_alg); ++ ++ err = crypto_register_aead(&t_alg->aead); ++ if (err) { ++ dev_warn(dev, "%s alg registration failed: %d\n", ++ t_alg->aead.base.cra_driver_name, err); ++ continue; ++ } ++ ++ t_alg->registered = true; ++ registered = true; ++ } ++ if (registered) ++ dev_info(dev, "algorithms registered in /proc/crypto\n"); ++ ++ return err; ++ ++err_bind: ++ dpaa2_dpseci_dpio_free(priv); ++err_dpio_setup: ++ dpaa2_dpseci_free(priv); ++err_dpseci_setup: ++ free_percpu(priv->ppriv); ++err_alloc_ppriv: ++ fsl_mc_portal_free(priv->mc_io); ++err_dma_mask: ++ kmem_cache_destroy(qi_cache); ++err_qicache: ++ dev_set_drvdata(dev, NULL); ++ ++ return err; ++} ++ ++static int __cold dpaa2_caam_remove(struct fsl_mc_device *ls_dev) ++{ ++ struct device *dev; ++ struct dpaa2_caam_priv *priv; ++ int i; ++ ++ dev = &ls_dev->dev; ++ priv = dev_get_drvdata(dev); ++ ++ for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) { ++ struct caam_aead_alg *t_alg = driver_aeads + i; ++ ++ if (t_alg->registered) ++ crypto_unregister_aead(&t_alg->aead); ++ } ++ ++ if (alg_list.next) { ++ struct caam_crypto_alg *t_alg, *n; ++ ++ list_for_each_entry_safe(t_alg, n, &alg_list, entry) { ++ crypto_unregister_alg(&t_alg->crypto_alg); ++ list_del(&t_alg->entry); ++ kfree(t_alg); ++ } ++ } ++ ++ dpaa2_dpseci_disable(priv); ++ dpaa2_dpseci_dpio_free(priv); ++ dpaa2_dpseci_free(priv); ++ free_percpu(priv->ppriv); ++ fsl_mc_portal_free(priv->mc_io); ++ dev_set_drvdata(dev, NULL); ++ kmem_cache_destroy(qi_cache); ++ ++ return 0; ++} ++ ++int dpaa2_caam_enqueue(struct device *dev, struct caam_request *req) ++{ ++ struct dpaa2_fd fd; ++ struct dpaa2_caam_priv *priv = dev_get_drvdata(dev); ++ int err = 0, i, id; ++ ++ if (IS_ERR(req)) ++ return PTR_ERR(req); ++ ++ if (priv->cscn_mem) { ++ dma_sync_single_for_cpu(priv->dev, priv->cscn_dma, ++ DPAA2_CSCN_SIZE, ++ DMA_FROM_DEVICE); ++ if (unlikely(dpaa2_cscn_state_congested(priv->cscn_mem_aligned))) { ++ dev_dbg_ratelimited(dev, "Dropping request\n"); ++ return -EBUSY; ++ } ++ } ++ ++ dpaa2_fl_set_flc(&req->fd_flt[1], req->flc->flc_dma); ++ ++ req->fd_flt_dma = dma_map_single(dev, req->fd_flt, sizeof(req->fd_flt), ++ DMA_BIDIRECTIONAL); ++ if (dma_mapping_error(dev, req->fd_flt_dma)) { ++ dev_err(dev, "DMA mapping error for QI enqueue request\n"); ++ goto err_out; ++ } ++ ++ memset(&fd, 0, sizeof(fd)); ++ dpaa2_fd_set_format(&fd, dpaa2_fd_list); ++ dpaa2_fd_set_addr(&fd, req->fd_flt_dma); ++ dpaa2_fd_set_len(&fd, req->fd_flt[1].len); ++ dpaa2_fd_set_flc(&fd, req->flc->flc_dma); ++ ++ /* ++ * There is no guarantee that preemption is disabled here, ++ * thus take action. ++ */ ++ preempt_disable(); ++ id = smp_processor_id() % priv->dpseci_attr.num_tx_queues; ++ for (i = 0; i < (priv->dpseci_attr.num_tx_queues << 1); i++) { ++ err = dpaa2_io_service_enqueue_fq(NULL, ++ priv->tx_queue_attr[id].fqid, ++ &fd); ++ if (err != -EBUSY) ++ break; ++ } ++ preempt_enable(); ++ ++ if (unlikely(err < 0)) { ++ dev_err(dev, "Error enqueuing frame: %d\n", err); ++ goto err_out; ++ } ++ ++ return -EINPROGRESS; ++ ++err_out: ++ dma_unmap_single(dev, req->fd_flt_dma, sizeof(req->fd_flt), ++ DMA_BIDIRECTIONAL); ++ return -EIO; ++} ++EXPORT_SYMBOL(dpaa2_caam_enqueue); ++ ++const struct fsl_mc_device_id dpaa2_caam_match_id_table[] = { ++ { ++ .vendor = FSL_MC_VENDOR_FREESCALE, ++ .obj_type = "dpseci", ++ }, ++ { .vendor = 0x0 } ++}; ++ ++static struct fsl_mc_driver dpaa2_caam_driver = { ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = dpaa2_caam_probe, ++ .remove = dpaa2_caam_remove, ++ .match_id_table = dpaa2_caam_match_id_table ++}; ++ ++MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_AUTHOR("Freescale Semiconductor, Inc"); ++MODULE_DESCRIPTION("Freescale DPAA2 CAAM Driver"); ++ ++module_fsl_mc_driver(dpaa2_caam_driver); +diff --git a/drivers/crypto/caam/caamalg_qi2.h b/drivers/crypto/caam/caamalg_qi2.h +new file mode 100644 +index 00000000..2ba179db +--- /dev/null ++++ b/drivers/crypto/caam/caamalg_qi2.h +@@ -0,0 +1,265 @@ ++/* ++ * Copyright 2015-2016 Freescale Semiconductor Inc. ++ * Copyright 2017 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the names of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef _CAAMALG_QI2_H_ ++#define _CAAMALG_QI2_H_ ++ ++#include "../../../drivers/staging/fsl-mc/include/dpaa2-io.h" ++#include "../../../drivers/staging/fsl-mc/include/dpaa2-fd.h" ++#include ++#include "dpseci.h" ++#include "desc_constr.h" ++ ++#define DPAA2_CAAM_STORE_SIZE 16 ++/* NAPI weight *must* be a multiple of the store size. */ ++#define DPAA2_CAAM_NAPI_WEIGHT 64 ++ ++/* The congestion entrance threshold was chosen so that on LS2088 ++ * we support the maximum throughput for the available memory ++ */ ++#define DPAA2_SEC_CONG_ENTRY_THRESH (128 * 1024 * 1024) ++#define DPAA2_SEC_CONG_EXIT_THRESH (DPAA2_SEC_CONG_ENTRY_THRESH * 9 / 10) ++ ++/** ++ * dpaa2_caam_priv - driver private data ++ * @dpseci_id: DPSECI object unique ID ++ * @major_ver: DPSECI major version ++ * @minor_ver: DPSECI minor version ++ * @dpseci_attr: DPSECI attributes ++ * @sec_attr: SEC engine attributes ++ * @rx_queue_attr: array of Rx queue attributes ++ * @tx_queue_attr: array of Tx queue attributes ++ * @cscn_mem: pointer to memory region containing the ++ * dpaa2_cscn struct; it's size is larger than ++ * sizeof(struct dpaa2_cscn) to accommodate alignment ++ * @cscn_mem_aligned: pointer to struct dpaa2_cscn; it is computed ++ * as PTR_ALIGN(cscn_mem, DPAA2_CSCN_ALIGN) ++ * @cscn_dma: dma address used by the QMAN to write CSCN messages ++ * @dev: device associated with the DPSECI object ++ * @mc_io: pointer to MC portal's I/O object ++ * @domain: IOMMU domain ++ * @ppriv: per CPU pointers to privata data ++ */ ++struct dpaa2_caam_priv { ++ int dpsec_id; ++ ++ u16 major_ver; ++ u16 minor_ver; ++ ++ struct dpseci_attr dpseci_attr; ++ struct dpseci_sec_attr sec_attr; ++ struct dpseci_rx_queue_attr rx_queue_attr[DPSECI_PRIO_NUM]; ++ struct dpseci_tx_queue_attr tx_queue_attr[DPSECI_PRIO_NUM]; ++ int num_pairs; ++ ++ /* congestion */ ++ void *cscn_mem; ++ void *cscn_mem_aligned; ++ dma_addr_t cscn_dma; ++ ++ struct device *dev; ++ struct fsl_mc_io *mc_io; ++ struct iommu_domain *domain; ++ ++ struct dpaa2_caam_priv_per_cpu __percpu *ppriv; ++}; ++ ++/** ++ * dpaa2_caam_priv_per_cpu - per CPU private data ++ * @napi: napi structure ++ * @net_dev: netdev used by napi ++ * @req_fqid: (virtual) request (Tx / enqueue) FQID ++ * @rsp_fqid: (virtual) response (Rx / dequeue) FQID ++ * @prio: internal queue number - index for dpaa2_caam_priv.*_queue_attr ++ * @nctx: notification context of response FQ ++ * @store: where dequeued frames are stored ++ * @priv: backpointer to dpaa2_caam_priv ++ */ ++struct dpaa2_caam_priv_per_cpu { ++ struct napi_struct napi; ++ struct net_device net_dev; ++ int req_fqid; ++ int rsp_fqid; ++ int prio; ++ struct dpaa2_io_notification_ctx nctx; ++ struct dpaa2_io_store *store; ++ struct dpaa2_caam_priv *priv; ++}; ++ ++/* ++ * The CAAM QI hardware constructs a job descriptor which points ++ * to shared descriptor (as pointed by context_a of FQ to CAAM). ++ * When the job descriptor is executed by deco, the whole job ++ * descriptor together with shared descriptor gets loaded in ++ * deco buffer which is 64 words long (each 32-bit). ++ * ++ * The job descriptor constructed by QI hardware has layout: ++ * ++ * HEADER (1 word) ++ * Shdesc ptr (1 or 2 words) ++ * SEQ_OUT_PTR (1 word) ++ * Out ptr (1 or 2 words) ++ * Out length (1 word) ++ * SEQ_IN_PTR (1 word) ++ * In ptr (1 or 2 words) ++ * In length (1 word) ++ * ++ * The shdesc ptr is used to fetch shared descriptor contents ++ * into deco buffer. ++ * ++ * Apart from shdesc contents, the total number of words that ++ * get loaded in deco buffer are '8' or '11'. The remaining words ++ * in deco buffer can be used for storing shared descriptor. ++ */ ++#define MAX_SDLEN ((CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN) / CAAM_CMD_SZ) ++ ++/* Length of a single buffer in the QI driver memory cache */ ++#define CAAM_QI_MEMCACHE_SIZE 512 ++ ++/* ++ * aead_edesc - s/w-extended aead descriptor ++ * @src_nents: number of segments in input scatterlist ++ * @dst_nents: number of segments in output scatterlist ++ * @iv_dma: dma address of iv for checking continuity and link table ++ * @qm_sg_bytes: length of dma mapped h/w link table ++ * @qm_sg_dma: bus physical mapped address of h/w link table ++ * @assoclen_dma: bus physical mapped address of req->assoclen ++ * @sgt: the h/w link table ++ */ ++struct aead_edesc { ++ int src_nents; ++ int dst_nents; ++ dma_addr_t iv_dma; ++ int qm_sg_bytes; ++ dma_addr_t qm_sg_dma; ++ dma_addr_t assoclen_dma; ++#define CAAM_QI_MAX_AEAD_SG \ ++ ((CAAM_QI_MEMCACHE_SIZE - offsetof(struct aead_edesc, sgt)) / \ ++ sizeof(struct dpaa2_sg_entry)) ++ struct dpaa2_sg_entry sgt[0]; ++}; ++ ++/* ++ * tls_edesc - s/w-extended tls descriptor ++ * @src_nents: number of segments in input scatterlist ++ * @dst_nents: number of segments in output scatterlist ++ * @iv_dma: dma address of iv for checking continuity and link table ++ * @qm_sg_bytes: length of dma mapped h/w link table ++ * @qm_sg_dma: bus physical mapped address of h/w link table ++ * @tmp: array of scatterlists used by 'scatterwalk_ffwd' ++ * @dst: pointer to output scatterlist, usefull for unmapping ++ * @sgt: the h/w link table ++ */ ++struct tls_edesc { ++ int src_nents; ++ int dst_nents; ++ dma_addr_t iv_dma; ++ int qm_sg_bytes; ++ dma_addr_t qm_sg_dma; ++ struct scatterlist tmp[2]; ++ struct scatterlist *dst; ++ struct dpaa2_sg_entry sgt[0]; ++}; ++ ++/* ++ * ablkcipher_edesc - s/w-extended ablkcipher descriptor ++ * @src_nents: number of segments in input scatterlist ++ * @dst_nents: number of segments in output scatterlist ++ * @iv_dma: dma address of iv for checking continuity and link table ++ * @qm_sg_bytes: length of dma mapped qm_sg space ++ * @qm_sg_dma: I/O virtual address of h/w link table ++ * @sgt: the h/w link table ++ */ ++struct ablkcipher_edesc { ++ int src_nents; ++ int dst_nents; ++ dma_addr_t iv_dma; ++ int qm_sg_bytes; ++ dma_addr_t qm_sg_dma; ++#define CAAM_QI_MAX_ABLKCIPHER_SG \ ++ ((CAAM_QI_MEMCACHE_SIZE - offsetof(struct ablkcipher_edesc, sgt)) / \ ++ sizeof(struct dpaa2_sg_entry)) ++ struct dpaa2_sg_entry sgt[0]; ++}; ++ ++/** ++ * caam_flc - Flow Context (FLC) ++ * @flc: Flow Context options ++ * @sh_desc: Shared Descriptor ++ * @flc_dma: DMA address of the Flow Context ++ */ ++struct caam_flc { ++ u32 flc[16]; ++ u32 sh_desc[MAX_SDLEN]; ++ dma_addr_t flc_dma; ++} ____cacheline_aligned; ++ ++enum optype { ++ ENCRYPT = 0, ++ DECRYPT, ++ GIVENCRYPT, ++ NUM_OP ++}; ++ ++/** ++ * caam_request - the request structure the driver application should fill while ++ * submitting a job to driver. ++ * @fd_flt: Frame list table defining input and output ++ * fd_flt[0] - FLE pointing to output buffer ++ * fd_flt[1] - FLE pointing to input buffer ++ * @fd_flt_dma: DMA address for the frame list table ++ * @flc: Flow Context ++ * @op_type: operation type ++ * @cbk: Callback function to invoke when job is completed ++ * @ctx: arbit context attached with request by the application ++ * @edesc: extended descriptor; points to one of {ablkcipher,aead}_edesc ++ */ ++struct caam_request { ++ struct dpaa2_fl_entry fd_flt[2]; ++ dma_addr_t fd_flt_dma; ++ struct caam_flc *flc; ++ enum optype op_type; ++ void (*cbk)(void *ctx, u32 err); ++ void *ctx; ++ void *edesc; ++}; ++ ++/** ++ * dpaa2_caam_enqueue() - enqueue a crypto request ++ * @dev: device associated with the DPSECI object ++ * @req: pointer to caam_request ++ */ ++int dpaa2_caam_enqueue(struct device *dev, struct caam_request *req); ++ ++#endif /* _CAAMALG_QI2_H_ */ +diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c +index 631337c2..698580b6 100644 +--- a/drivers/crypto/caam/caamhash.c ++++ b/drivers/crypto/caam/caamhash.c +@@ -72,7 +72,7 @@ + #define CAAM_MAX_HASH_DIGEST_SIZE SHA512_DIGEST_SIZE + + /* length of descriptors text */ +-#define DESC_AHASH_BASE (4 * CAAM_CMD_SZ) ++#define DESC_AHASH_BASE (3 * CAAM_CMD_SZ) + #define DESC_AHASH_UPDATE_LEN (6 * CAAM_CMD_SZ) + #define DESC_AHASH_UPDATE_FIRST_LEN (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ) + #define DESC_AHASH_FINAL_LEN (DESC_AHASH_BASE + 5 * CAAM_CMD_SZ) +@@ -103,20 +103,14 @@ struct caam_hash_ctx { + u32 sh_desc_update_first[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned; + u32 sh_desc_fin[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned; + u32 sh_desc_digest[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned; +- u32 sh_desc_finup[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned; + dma_addr_t sh_desc_update_dma ____cacheline_aligned; + dma_addr_t sh_desc_update_first_dma; + dma_addr_t sh_desc_fin_dma; + dma_addr_t sh_desc_digest_dma; +- dma_addr_t sh_desc_finup_dma; + struct device *jrdev; +- u32 alg_type; +- u32 alg_op; + u8 key[CAAM_MAX_HASH_KEY_SIZE]; +- dma_addr_t key_dma; + int ctx_len; +- unsigned int split_key_len; +- unsigned int split_key_pad_len; ++ struct alginfo adata; + }; + + /* ahash state */ +@@ -143,6 +137,31 @@ struct caam_export_state { + int (*finup)(struct ahash_request *req); + }; + ++static inline void switch_buf(struct caam_hash_state *state) ++{ ++ state->current_buf ^= 1; ++} ++ ++static inline u8 *current_buf(struct caam_hash_state *state) ++{ ++ return state->current_buf ? state->buf_1 : state->buf_0; ++} ++ ++static inline u8 *alt_buf(struct caam_hash_state *state) ++{ ++ return state->current_buf ? state->buf_0 : state->buf_1; ++} ++ ++static inline int *current_buflen(struct caam_hash_state *state) ++{ ++ return state->current_buf ? &state->buflen_1 : &state->buflen_0; ++} ++ ++static inline int *alt_buflen(struct caam_hash_state *state) ++{ ++ return state->current_buf ? &state->buflen_0 : &state->buflen_1; ++} ++ + /* Common job descriptor seq in/out ptr routines */ + + /* Map state->caam_ctx, and append seq_out_ptr command that points to it */ +@@ -175,36 +194,27 @@ static inline dma_addr_t map_seq_out_ptr_result(u32 *desc, struct device *jrdev, + return dst_dma; + } + +-/* Map current buffer in state and put it in link table */ +-static inline dma_addr_t buf_map_to_sec4_sg(struct device *jrdev, +- struct sec4_sg_entry *sec4_sg, +- u8 *buf, int buflen) ++/* Map current buffer in state (if length > 0) and put it in link table */ ++static inline int buf_map_to_sec4_sg(struct device *jrdev, ++ struct sec4_sg_entry *sec4_sg, ++ struct caam_hash_state *state) + { +- dma_addr_t buf_dma; ++ int buflen = *current_buflen(state); + +- buf_dma = dma_map_single(jrdev, buf, buflen, DMA_TO_DEVICE); +- dma_to_sec4_sg_one(sec4_sg, buf_dma, buflen, 0); ++ if (!buflen) ++ return 0; + +- return buf_dma; +-} ++ state->buf_dma = dma_map_single(jrdev, current_buf(state), buflen, ++ DMA_TO_DEVICE); ++ if (dma_mapping_error(jrdev, state->buf_dma)) { ++ dev_err(jrdev, "unable to map buf\n"); ++ state->buf_dma = 0; ++ return -ENOMEM; ++ } + +-/* +- * Only put buffer in link table if it contains data, which is possible, +- * since a buffer has previously been used, and needs to be unmapped, +- */ +-static inline dma_addr_t +-try_buf_map_to_sec4_sg(struct device *jrdev, struct sec4_sg_entry *sec4_sg, +- u8 *buf, dma_addr_t buf_dma, int buflen, +- int last_buflen) +-{ +- if (buf_dma && !dma_mapping_error(jrdev, buf_dma)) +- dma_unmap_single(jrdev, buf_dma, last_buflen, DMA_TO_DEVICE); +- if (buflen) +- buf_dma = buf_map_to_sec4_sg(jrdev, sec4_sg, buf, buflen); +- else +- buf_dma = 0; +- +- return buf_dma; ++ dma_to_sec4_sg_one(sec4_sg, state->buf_dma, buflen, 0); ++ ++ return 0; + } + + /* Map state->caam_ctx, and add it to link table */ +@@ -224,89 +234,54 @@ static inline int ctx_map_to_sec4_sg(u32 *desc, struct device *jrdev, + return 0; + } + +-/* Common shared descriptor commands */ +-static inline void append_key_ahash(u32 *desc, struct caam_hash_ctx *ctx) +-{ +- append_key_as_imm(desc, ctx->key, ctx->split_key_pad_len, +- ctx->split_key_len, CLASS_2 | +- KEY_DEST_MDHA_SPLIT | KEY_ENC); +-} +- +-/* Append key if it has been set */ +-static inline void init_sh_desc_key_ahash(u32 *desc, struct caam_hash_ctx *ctx) +-{ +- u32 *key_jump_cmd; +- +- init_sh_desc(desc, HDR_SHARE_SERIAL); +- +- if (ctx->split_key_len) { +- /* Skip if already shared */ +- key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | +- JUMP_COND_SHRD); +- +- append_key_ahash(desc, ctx); +- +- set_jump_tgt_here(desc, key_jump_cmd); +- } +- +- /* Propagate errors from shared to job descriptor */ +- append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); +-} +- + /* +- * For ahash read data from seqin following state->caam_ctx, +- * and write resulting class2 context to seqout, which may be state->caam_ctx +- * or req->result ++ * For ahash update, final and finup (import_ctx = true) ++ * import context, read and write to seqout ++ * For ahash firsts and digest (import_ctx = false) ++ * read and write to seqout + */ +-static inline void ahash_append_load_str(u32 *desc, int digestsize) ++static inline void ahash_gen_sh_desc(u32 *desc, u32 state, int digestsize, ++ struct caam_hash_ctx *ctx, bool import_ctx) + { +- /* Calculate remaining bytes to read */ +- append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); +- +- /* Read remaining bytes */ +- append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_LAST2 | +- FIFOLD_TYPE_MSG | KEY_VLF); ++ u32 op = ctx->adata.algtype; ++ u32 *skip_key_load; + +- /* Store class2 context bytes */ +- append_seq_store(desc, digestsize, LDST_CLASS_2_CCB | +- LDST_SRCDST_BYTE_CONTEXT); +-} ++ init_sh_desc(desc, HDR_SHARE_SERIAL); + +-/* +- * For ahash update, final and finup, import context, read and write to seqout +- */ +-static inline void ahash_ctx_data_to_out(u32 *desc, u32 op, u32 state, +- int digestsize, +- struct caam_hash_ctx *ctx) +-{ +- init_sh_desc_key_ahash(desc, ctx); ++ /* Append key if it has been set; ahash update excluded */ ++ if ((state != OP_ALG_AS_UPDATE) && (ctx->adata.keylen)) { ++ /* Skip key loading if already shared */ ++ skip_key_load = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | ++ JUMP_COND_SHRD); + +- /* Import context from software */ +- append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | +- LDST_CLASS_2_CCB | ctx->ctx_len); ++ append_key_as_imm(desc, ctx->key, ctx->adata.keylen_pad, ++ ctx->adata.keylen, CLASS_2 | ++ KEY_DEST_MDHA_SPLIT | KEY_ENC); + +- /* Class 2 operation */ +- append_operation(desc, op | state | OP_ALG_ENCRYPT); ++ set_jump_tgt_here(desc, skip_key_load); + +- /* +- * Load from buf and/or src and write to req->result or state->context +- */ +- ahash_append_load_str(desc, digestsize); +-} ++ op |= OP_ALG_AAI_HMAC_PRECOMP; ++ } + +-/* For ahash firsts and digest, read and write to seqout */ +-static inline void ahash_data_to_out(u32 *desc, u32 op, u32 state, +- int digestsize, struct caam_hash_ctx *ctx) +-{ +- init_sh_desc_key_ahash(desc, ctx); ++ /* If needed, import context from software */ ++ if (import_ctx) ++ append_seq_load(desc, ctx->ctx_len, LDST_CLASS_2_CCB | ++ LDST_SRCDST_BYTE_CONTEXT); + + /* Class 2 operation */ + append_operation(desc, op | state | OP_ALG_ENCRYPT); + + /* + * Load from buf and/or src and write to req->result or state->context ++ * Calculate remaining bytes to read + */ +- ahash_append_load_str(desc, digestsize); ++ append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); ++ /* Read remaining bytes */ ++ append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_LAST2 | ++ FIFOLD_TYPE_MSG | KEY_VLF); ++ /* Store class2 context bytes */ ++ append_seq_store(desc, digestsize, LDST_CLASS_2_CCB | ++ LDST_SRCDST_BYTE_CONTEXT); + } + + static int ahash_set_sh_desc(struct crypto_ahash *ahash) +@@ -314,34 +289,13 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + int digestsize = crypto_ahash_digestsize(ahash); + struct device *jrdev = ctx->jrdev; +- u32 have_key = 0; + u32 *desc; + +- if (ctx->split_key_len) +- have_key = OP_ALG_AAI_HMAC_PRECOMP; +- + /* ahash_update shared descriptor */ + desc = ctx->sh_desc_update; +- +- init_sh_desc(desc, HDR_SHARE_SERIAL); +- +- /* Import context from software */ +- append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | +- LDST_CLASS_2_CCB | ctx->ctx_len); +- +- /* Class 2 operation */ +- append_operation(desc, ctx->alg_type | OP_ALG_AS_UPDATE | +- OP_ALG_ENCRYPT); +- +- /* Load data and write to result or context */ +- ahash_append_load_str(desc, ctx->ctx_len); +- +- ctx->sh_desc_update_dma = dma_map_single(jrdev, desc, desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_update_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } ++ ahash_gen_sh_desc(desc, OP_ALG_AS_UPDATE, ctx->ctx_len, ctx, true); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_update_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + #ifdef DEBUG + print_hex_dump(KERN_ERR, + "ahash update shdesc@"__stringify(__LINE__)": ", +@@ -350,17 +304,9 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) + + /* ahash_update_first shared descriptor */ + desc = ctx->sh_desc_update_first; +- +- ahash_data_to_out(desc, have_key | ctx->alg_type, OP_ALG_AS_INIT, +- ctx->ctx_len, ctx); +- +- ctx->sh_desc_update_first_dma = dma_map_single(jrdev, desc, +- desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_update_first_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } ++ ahash_gen_sh_desc(desc, OP_ALG_AS_INIT, ctx->ctx_len, ctx, false); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + #ifdef DEBUG + print_hex_dump(KERN_ERR, + "ahash update first shdesc@"__stringify(__LINE__)": ", +@@ -369,53 +315,20 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) + + /* ahash_final shared descriptor */ + desc = ctx->sh_desc_fin; +- +- ahash_ctx_data_to_out(desc, have_key | ctx->alg_type, +- OP_ALG_AS_FINALIZE, digestsize, ctx); +- +- ctx->sh_desc_fin_dma = dma_map_single(jrdev, desc, desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_fin_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } ++ ahash_gen_sh_desc(desc, OP_ALG_AS_FINALIZE, digestsize, ctx, true); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + #ifdef DEBUG + print_hex_dump(KERN_ERR, "ahash final shdesc@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, + desc_bytes(desc), 1); + #endif + +- /* ahash_finup shared descriptor */ +- desc = ctx->sh_desc_finup; +- +- ahash_ctx_data_to_out(desc, have_key | ctx->alg_type, +- OP_ALG_AS_FINALIZE, digestsize, ctx); +- +- ctx->sh_desc_finup_dma = dma_map_single(jrdev, desc, desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_finup_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } +-#ifdef DEBUG +- print_hex_dump(KERN_ERR, "ahash finup shdesc@"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, desc, +- desc_bytes(desc), 1); +-#endif +- + /* ahash_digest shared descriptor */ + desc = ctx->sh_desc_digest; +- +- ahash_data_to_out(desc, have_key | ctx->alg_type, OP_ALG_AS_INITFINAL, +- digestsize, ctx); +- +- ctx->sh_desc_digest_dma = dma_map_single(jrdev, desc, +- desc_bytes(desc), +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->sh_desc_digest_dma)) { +- dev_err(jrdev, "unable to map shared descriptor\n"); +- return -ENOMEM; +- } ++ ahash_gen_sh_desc(desc, OP_ALG_AS_INITFINAL, digestsize, ctx, false); ++ dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma, ++ desc_bytes(desc), DMA_TO_DEVICE); + #ifdef DEBUG + print_hex_dump(KERN_ERR, + "ahash digest shdesc@"__stringify(__LINE__)": ", +@@ -426,14 +339,6 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) + return 0; + } + +-static int gen_split_hash_key(struct caam_hash_ctx *ctx, const u8 *key_in, +- u32 keylen) +-{ +- return gen_split_key(ctx->jrdev, ctx->key, ctx->split_key_len, +- ctx->split_key_pad_len, key_in, keylen, +- ctx->alg_op); +-} +- + /* Digest hash size if it is too large */ + static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in, + u32 *keylen, u8 *key_out, u32 digestsize) +@@ -469,7 +374,7 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in, + } + + /* Job descriptor to perform unkeyed hash on key_in */ +- append_operation(desc, ctx->alg_type | OP_ALG_ENCRYPT | ++ append_operation(desc, ctx->adata.algtype | OP_ALG_ENCRYPT | + OP_ALG_AS_INITFINAL); + append_seq_in_ptr(desc, src_dma, *keylen, 0); + append_seq_fifo_load(desc, *keylen, FIFOLD_CLASS_CLASS2 | +@@ -513,10 +418,7 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in, + static int ahash_setkey(struct crypto_ahash *ahash, + const u8 *key, unsigned int keylen) + { +- /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */ +- static const u8 mdpadlen[] = { 16, 20, 32, 32, 64, 64 }; + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); +- struct device *jrdev = ctx->jrdev; + int blocksize = crypto_tfm_alg_blocksize(&ahash->base); + int digestsize = crypto_ahash_digestsize(ahash); + int ret; +@@ -539,43 +441,19 @@ static int ahash_setkey(struct crypto_ahash *ahash, + key = hashed_key; + } + +- /* Pick class 2 key length from algorithm submask */ +- ctx->split_key_len = mdpadlen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >> +- OP_ALG_ALGSEL_SHIFT] * 2; +- ctx->split_key_pad_len = ALIGN(ctx->split_key_len, 16); +- +-#ifdef DEBUG +- printk(KERN_ERR "split_key_len %d split_key_pad_len %d\n", +- ctx->split_key_len, ctx->split_key_pad_len); +- print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", +- DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); +-#endif +- +- ret = gen_split_hash_key(ctx, key, keylen); ++ ret = gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, key, keylen, ++ CAAM_MAX_HASH_KEY_SIZE); + if (ret) + goto bad_free_key; + +- ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->split_key_pad_len, +- DMA_TO_DEVICE); +- if (dma_mapping_error(jrdev, ctx->key_dma)) { +- dev_err(jrdev, "unable to map key i/o memory\n"); +- ret = -ENOMEM; +- goto error_free_key; +- } + #ifdef DEBUG + print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, +- ctx->split_key_pad_len, 1); ++ ctx->adata.keylen_pad, 1); + #endif + +- ret = ahash_set_sh_desc(ahash); +- if (ret) { +- dma_unmap_single(jrdev, ctx->key_dma, ctx->split_key_pad_len, +- DMA_TO_DEVICE); +- } +- error_free_key: + kfree(hashed_key); +- return ret; ++ return ahash_set_sh_desc(ahash); + bad_free_key: + kfree(hashed_key); + crypto_ahash_set_flags(ahash, CRYPTO_TFM_RES_BAD_KEY_LEN); +@@ -604,6 +482,8 @@ static inline void ahash_unmap(struct device *dev, + struct ahash_edesc *edesc, + struct ahash_request *req, int dst_len) + { ++ struct caam_hash_state *state = ahash_request_ctx(req); ++ + if (edesc->src_nents) + dma_unmap_sg(dev, req->src, edesc->src_nents, DMA_TO_DEVICE); + if (edesc->dst_dma) +@@ -612,6 +492,12 @@ static inline void ahash_unmap(struct device *dev, + if (edesc->sec4_sg_bytes) + dma_unmap_single(dev, edesc->sec4_sg_dma, + edesc->sec4_sg_bytes, DMA_TO_DEVICE); ++ ++ if (state->buf_dma) { ++ dma_unmap_single(dev, state->buf_dma, *current_buflen(state), ++ DMA_TO_DEVICE); ++ state->buf_dma = 0; ++ } + } + + static inline void ahash_unmap_ctx(struct device *dev, +@@ -643,8 +529,7 @@ static void ahash_done(struct device *jrdev, u32 *desc, u32 err, + dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); + #endif + +- edesc = (struct ahash_edesc *)((char *)desc - +- offsetof(struct ahash_edesc, hw_desc)); ++ edesc = container_of(desc, struct ahash_edesc, hw_desc[0]); + if (err) + caam_jr_strstatus(jrdev, err); + +@@ -671,19 +556,19 @@ static void ahash_done_bi(struct device *jrdev, u32 *desc, u32 err, + struct ahash_edesc *edesc; + struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); +-#ifdef DEBUG + struct caam_hash_state *state = ahash_request_ctx(req); ++#ifdef DEBUG + int digestsize = crypto_ahash_digestsize(ahash); + + dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); + #endif + +- edesc = (struct ahash_edesc *)((char *)desc - +- offsetof(struct ahash_edesc, hw_desc)); ++ edesc = container_of(desc, struct ahash_edesc, hw_desc[0]); + if (err) + caam_jr_strstatus(jrdev, err); + + ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, DMA_BIDIRECTIONAL); ++ switch_buf(state); + kfree(edesc); + + #ifdef DEBUG +@@ -713,8 +598,7 @@ static void ahash_done_ctx_src(struct device *jrdev, u32 *desc, u32 err, + dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); + #endif + +- edesc = (struct ahash_edesc *)((char *)desc - +- offsetof(struct ahash_edesc, hw_desc)); ++ edesc = container_of(desc, struct ahash_edesc, hw_desc[0]); + if (err) + caam_jr_strstatus(jrdev, err); + +@@ -741,19 +625,19 @@ static void ahash_done_ctx_dst(struct device *jrdev, u32 *desc, u32 err, + struct ahash_edesc *edesc; + struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); +-#ifdef DEBUG + struct caam_hash_state *state = ahash_request_ctx(req); ++#ifdef DEBUG + int digestsize = crypto_ahash_digestsize(ahash); + + dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); + #endif + +- edesc = (struct ahash_edesc *)((char *)desc - +- offsetof(struct ahash_edesc, hw_desc)); ++ edesc = container_of(desc, struct ahash_edesc, hw_desc[0]); + if (err) + caam_jr_strstatus(jrdev, err); + + ahash_unmap_ctx(jrdev, edesc, req, ctx->ctx_len, DMA_FROM_DEVICE); ++ switch_buf(state); + kfree(edesc); + + #ifdef DEBUG +@@ -835,13 +719,12 @@ static int ahash_update_ctx(struct ahash_request *req) + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + struct device *jrdev = ctx->jrdev; +- gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | +- CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC; +- u8 *buf = state->current_buf ? state->buf_1 : state->buf_0; +- int *buflen = state->current_buf ? &state->buflen_1 : &state->buflen_0; +- u8 *next_buf = state->current_buf ? state->buf_0 : state->buf_1; +- int *next_buflen = state->current_buf ? &state->buflen_0 : +- &state->buflen_1, last_buflen; ++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? ++ GFP_KERNEL : GFP_ATOMIC; ++ u8 *buf = current_buf(state); ++ int *buflen = current_buflen(state); ++ u8 *next_buf = alt_buf(state); ++ int *next_buflen = alt_buflen(state), last_buflen; + int in_len = *buflen + req->nbytes, to_hash; + u32 *desc; + int src_nents, mapped_nents, sec4_sg_bytes, sec4_sg_src_index; +@@ -895,10 +778,9 @@ static int ahash_update_ctx(struct ahash_request *req) + if (ret) + goto unmap_ctx; + +- state->buf_dma = try_buf_map_to_sec4_sg(jrdev, +- edesc->sec4_sg + 1, +- buf, state->buf_dma, +- *buflen, last_buflen); ++ ret = buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1, state); ++ if (ret) ++ goto unmap_ctx; + + if (mapped_nents) { + sg_to_sec4_sg_last(req->src, mapped_nents, +@@ -909,12 +791,10 @@ static int ahash_update_ctx(struct ahash_request *req) + to_hash - *buflen, + *next_buflen, 0); + } else { +- (edesc->sec4_sg + sec4_sg_src_index - 1)->len |= +- cpu_to_caam32(SEC4_SG_LEN_FIN); ++ sg_to_sec4_set_last(edesc->sec4_sg + sec4_sg_src_index - ++ 1); + } + +- state->current_buf = !state->current_buf; +- + desc = edesc->hw_desc; + + edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, +@@ -969,12 +849,9 @@ static int ahash_final_ctx(struct ahash_request *req) + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + struct device *jrdev = ctx->jrdev; +- gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | +- CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC; +- u8 *buf = state->current_buf ? state->buf_1 : state->buf_0; +- int buflen = state->current_buf ? state->buflen_1 : state->buflen_0; +- int last_buflen = state->current_buf ? state->buflen_0 : +- state->buflen_1; ++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? ++ GFP_KERNEL : GFP_ATOMIC; ++ int buflen = *current_buflen(state); + u32 *desc; + int sec4_sg_bytes, sec4_sg_src_index; + int digestsize = crypto_ahash_digestsize(ahash); +@@ -1001,11 +878,11 @@ static int ahash_final_ctx(struct ahash_request *req) + if (ret) + goto unmap_ctx; + +- state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1, +- buf, state->buf_dma, buflen, +- last_buflen); +- (edesc->sec4_sg + sec4_sg_src_index - 1)->len |= +- cpu_to_caam32(SEC4_SG_LEN_FIN); ++ ret = buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1, state); ++ if (ret) ++ goto unmap_ctx; ++ ++ sg_to_sec4_set_last(edesc->sec4_sg + sec4_sg_src_index - 1); + + edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, + sec4_sg_bytes, DMA_TO_DEVICE); +@@ -1048,12 +925,9 @@ static int ahash_finup_ctx(struct ahash_request *req) + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + struct device *jrdev = ctx->jrdev; +- gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | +- CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC; +- u8 *buf = state->current_buf ? state->buf_1 : state->buf_0; +- int buflen = state->current_buf ? state->buflen_1 : state->buflen_0; +- int last_buflen = state->current_buf ? state->buflen_0 : +- state->buflen_1; ++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? ++ GFP_KERNEL : GFP_ATOMIC; ++ int buflen = *current_buflen(state); + u32 *desc; + int sec4_sg_src_index; + int src_nents, mapped_nents; +@@ -1082,7 +956,7 @@ static int ahash_finup_ctx(struct ahash_request *req) + + /* allocate space for base edesc and hw desc commands, link tables */ + edesc = ahash_edesc_alloc(ctx, sec4_sg_src_index + mapped_nents, +- ctx->sh_desc_finup, ctx->sh_desc_finup_dma, ++ ctx->sh_desc_fin, ctx->sh_desc_fin_dma, + flags); + if (!edesc) { + dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE); +@@ -1098,9 +972,9 @@ static int ahash_finup_ctx(struct ahash_request *req) + if (ret) + goto unmap_ctx; + +- state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1, +- buf, state->buf_dma, buflen, +- last_buflen); ++ ret = buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1, state); ++ if (ret) ++ goto unmap_ctx; + + ret = ahash_edesc_add_src(ctx, edesc, req, mapped_nents, + sec4_sg_src_index, ctx->ctx_len + buflen, +@@ -1136,15 +1010,18 @@ static int ahash_digest(struct ahash_request *req) + { + struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); ++ struct caam_hash_state *state = ahash_request_ctx(req); + struct device *jrdev = ctx->jrdev; +- gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | +- CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC; ++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? ++ GFP_KERNEL : GFP_ATOMIC; + u32 *desc; + int digestsize = crypto_ahash_digestsize(ahash); + int src_nents, mapped_nents; + struct ahash_edesc *edesc; + int ret; + ++ state->buf_dma = 0; ++ + src_nents = sg_nents_for_len(req->src, req->nbytes); + if (src_nents < 0) { + dev_err(jrdev, "Invalid number of src SG.\n"); +@@ -1215,10 +1092,10 @@ static int ahash_final_no_ctx(struct ahash_request *req) + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + struct device *jrdev = ctx->jrdev; +- gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | +- CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC; +- u8 *buf = state->current_buf ? state->buf_1 : state->buf_0; +- int buflen = state->current_buf ? state->buflen_1 : state->buflen_0; ++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? ++ GFP_KERNEL : GFP_ATOMIC; ++ u8 *buf = current_buf(state); ++ int buflen = *current_buflen(state); + u32 *desc; + int digestsize = crypto_ahash_digestsize(ahash); + struct ahash_edesc *edesc; +@@ -1276,13 +1153,12 @@ static int ahash_update_no_ctx(struct ahash_request *req) + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + struct device *jrdev = ctx->jrdev; +- gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | +- CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC; +- u8 *buf = state->current_buf ? state->buf_1 : state->buf_0; +- int *buflen = state->current_buf ? &state->buflen_1 : &state->buflen_0; +- u8 *next_buf = state->current_buf ? state->buf_0 : state->buf_1; +- int *next_buflen = state->current_buf ? &state->buflen_0 : +- &state->buflen_1; ++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? ++ GFP_KERNEL : GFP_ATOMIC; ++ u8 *buf = current_buf(state); ++ int *buflen = current_buflen(state); ++ u8 *next_buf = alt_buf(state); ++ int *next_buflen = alt_buflen(state); + int in_len = *buflen + req->nbytes, to_hash; + int sec4_sg_bytes, src_nents, mapped_nents; + struct ahash_edesc *edesc; +@@ -1331,8 +1207,10 @@ static int ahash_update_no_ctx(struct ahash_request *req) + edesc->sec4_sg_bytes = sec4_sg_bytes; + edesc->dst_dma = 0; + +- state->buf_dma = buf_map_to_sec4_sg(jrdev, edesc->sec4_sg, +- buf, *buflen); ++ ret = buf_map_to_sec4_sg(jrdev, edesc->sec4_sg, state); ++ if (ret) ++ goto unmap_ctx; ++ + sg_to_sec4_sg_last(req->src, mapped_nents, + edesc->sec4_sg + 1, 0); + +@@ -1342,8 +1220,6 @@ static int ahash_update_no_ctx(struct ahash_request *req) + *next_buflen, 0); + } + +- state->current_buf = !state->current_buf; +- + desc = edesc->hw_desc; + + edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, +@@ -1403,12 +1279,9 @@ static int ahash_finup_no_ctx(struct ahash_request *req) + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + struct device *jrdev = ctx->jrdev; +- gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | +- CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC; +- u8 *buf = state->current_buf ? state->buf_1 : state->buf_0; +- int buflen = state->current_buf ? state->buflen_1 : state->buflen_0; +- int last_buflen = state->current_buf ? state->buflen_0 : +- state->buflen_1; ++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? ++ GFP_KERNEL : GFP_ATOMIC; ++ int buflen = *current_buflen(state); + u32 *desc; + int sec4_sg_bytes, sec4_sg_src_index, src_nents, mapped_nents; + int digestsize = crypto_ahash_digestsize(ahash); +@@ -1450,9 +1323,9 @@ static int ahash_finup_no_ctx(struct ahash_request *req) + edesc->src_nents = src_nents; + edesc->sec4_sg_bytes = sec4_sg_bytes; + +- state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg, buf, +- state->buf_dma, buflen, +- last_buflen); ++ ret = buf_map_to_sec4_sg(jrdev, edesc->sec4_sg, state); ++ if (ret) ++ goto unmap; + + ret = ahash_edesc_add_src(ctx, edesc, req, mapped_nents, 1, buflen, + req->nbytes); +@@ -1496,11 +1369,10 @@ static int ahash_update_first(struct ahash_request *req) + struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); + struct caam_hash_state *state = ahash_request_ctx(req); + struct device *jrdev = ctx->jrdev; +- gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | +- CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC; +- u8 *next_buf = state->current_buf ? state->buf_1 : state->buf_0; +- int *next_buflen = state->current_buf ? +- &state->buflen_1 : &state->buflen_0; ++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? ++ GFP_KERNEL : GFP_ATOMIC; ++ u8 *next_buf = alt_buf(state); ++ int *next_buflen = alt_buflen(state); + int to_hash; + u32 *desc; + int src_nents, mapped_nents; +@@ -1582,6 +1454,7 @@ static int ahash_update_first(struct ahash_request *req) + state->final = ahash_final_no_ctx; + scatterwalk_map_and_copy(next_buf, req->src, 0, + req->nbytes, 0); ++ switch_buf(state); + } + #ifdef DEBUG + print_hex_dump(KERN_ERR, "next buf@"__stringify(__LINE__)": ", +@@ -1688,7 +1561,6 @@ struct caam_hash_template { + unsigned int blocksize; + struct ahash_alg template_ahash; + u32 alg_type; +- u32 alg_op; + }; + + /* ahash descriptors */ +@@ -1714,7 +1586,6 @@ static struct caam_hash_template driver_hash[] = { + }, + }, + .alg_type = OP_ALG_ALGSEL_SHA1, +- .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, + }, { + .name = "sha224", + .driver_name = "sha224-caam", +@@ -1736,7 +1607,6 @@ static struct caam_hash_template driver_hash[] = { + }, + }, + .alg_type = OP_ALG_ALGSEL_SHA224, +- .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, + }, { + .name = "sha256", + .driver_name = "sha256-caam", +@@ -1758,7 +1628,6 @@ static struct caam_hash_template driver_hash[] = { + }, + }, + .alg_type = OP_ALG_ALGSEL_SHA256, +- .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, + }, { + .name = "sha384", + .driver_name = "sha384-caam", +@@ -1780,7 +1649,6 @@ static struct caam_hash_template driver_hash[] = { + }, + }, + .alg_type = OP_ALG_ALGSEL_SHA384, +- .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, + }, { + .name = "sha512", + .driver_name = "sha512-caam", +@@ -1802,7 +1670,6 @@ static struct caam_hash_template driver_hash[] = { + }, + }, + .alg_type = OP_ALG_ALGSEL_SHA512, +- .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, + }, { + .name = "md5", + .driver_name = "md5-caam", +@@ -1824,14 +1691,12 @@ static struct caam_hash_template driver_hash[] = { + }, + }, + .alg_type = OP_ALG_ALGSEL_MD5, +- .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, + }, + }; + + struct caam_hash_alg { + struct list_head entry; + int alg_type; +- int alg_op; + struct ahash_alg ahash_alg; + }; + +@@ -1853,6 +1718,7 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) + HASH_MSG_LEN + SHA256_DIGEST_SIZE, + HASH_MSG_LEN + 64, + HASH_MSG_LEN + SHA512_DIGEST_SIZE }; ++ dma_addr_t dma_addr; + + /* + * Get a Job ring from Job Ring driver to ensure in-order +@@ -1863,11 +1729,31 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) + pr_err("Job Ring Device allocation for transform failed\n"); + return PTR_ERR(ctx->jrdev); + } ++ ++ dma_addr = dma_map_single_attrs(ctx->jrdev, ctx->sh_desc_update, ++ offsetof(struct caam_hash_ctx, ++ sh_desc_update_dma), ++ DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); ++ if (dma_mapping_error(ctx->jrdev, dma_addr)) { ++ dev_err(ctx->jrdev, "unable to map shared descriptors\n"); ++ caam_jr_free(ctx->jrdev); ++ return -ENOMEM; ++ } ++ ++ ctx->sh_desc_update_dma = dma_addr; ++ ctx->sh_desc_update_first_dma = dma_addr + ++ offsetof(struct caam_hash_ctx, ++ sh_desc_update_first); ++ ctx->sh_desc_fin_dma = dma_addr + offsetof(struct caam_hash_ctx, ++ sh_desc_fin); ++ ctx->sh_desc_digest_dma = dma_addr + offsetof(struct caam_hash_ctx, ++ sh_desc_digest); ++ + /* copy descriptor header template value */ +- ctx->alg_type = OP_TYPE_CLASS2_ALG | caam_hash->alg_type; +- ctx->alg_op = OP_TYPE_CLASS2_ALG | caam_hash->alg_op; ++ ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam_hash->alg_type; + +- ctx->ctx_len = runninglen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >> ++ ctx->ctx_len = runninglen[(ctx->adata.algtype & ++ OP_ALG_ALGSEL_SUBMASK) >> + OP_ALG_ALGSEL_SHIFT]; + + crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), +@@ -1879,30 +1765,10 @@ static void caam_hash_cra_exit(struct crypto_tfm *tfm) + { + struct caam_hash_ctx *ctx = crypto_tfm_ctx(tfm); + +- if (ctx->sh_desc_update_dma && +- !dma_mapping_error(ctx->jrdev, ctx->sh_desc_update_dma)) +- dma_unmap_single(ctx->jrdev, ctx->sh_desc_update_dma, +- desc_bytes(ctx->sh_desc_update), +- DMA_TO_DEVICE); +- if (ctx->sh_desc_update_first_dma && +- !dma_mapping_error(ctx->jrdev, ctx->sh_desc_update_first_dma)) +- dma_unmap_single(ctx->jrdev, ctx->sh_desc_update_first_dma, +- desc_bytes(ctx->sh_desc_update_first), +- DMA_TO_DEVICE); +- if (ctx->sh_desc_fin_dma && +- !dma_mapping_error(ctx->jrdev, ctx->sh_desc_fin_dma)) +- dma_unmap_single(ctx->jrdev, ctx->sh_desc_fin_dma, +- desc_bytes(ctx->sh_desc_fin), DMA_TO_DEVICE); +- if (ctx->sh_desc_digest_dma && +- !dma_mapping_error(ctx->jrdev, ctx->sh_desc_digest_dma)) +- dma_unmap_single(ctx->jrdev, ctx->sh_desc_digest_dma, +- desc_bytes(ctx->sh_desc_digest), +- DMA_TO_DEVICE); +- if (ctx->sh_desc_finup_dma && +- !dma_mapping_error(ctx->jrdev, ctx->sh_desc_finup_dma)) +- dma_unmap_single(ctx->jrdev, ctx->sh_desc_finup_dma, +- desc_bytes(ctx->sh_desc_finup), DMA_TO_DEVICE); +- ++ dma_unmap_single_attrs(ctx->jrdev, ctx->sh_desc_update_dma, ++ offsetof(struct caam_hash_ctx, ++ sh_desc_update_dma), ++ DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); + caam_jr_free(ctx->jrdev); + } + +@@ -1961,7 +1827,6 @@ caam_hash_alloc(struct caam_hash_template *template, + alg->cra_type = &crypto_ahash_type; + + t_alg->alg_type = template->alg_type; +- t_alg->alg_op = template->alg_op; + + return t_alg; + } +diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c +index 354a16ab..4fcb378e 100644 +--- a/drivers/crypto/caam/caampkc.c ++++ b/drivers/crypto/caam/caampkc.c +@@ -18,6 +18,10 @@ + #define DESC_RSA_PUB_LEN (2 * CAAM_CMD_SZ + sizeof(struct rsa_pub_pdb)) + #define DESC_RSA_PRIV_F1_LEN (2 * CAAM_CMD_SZ + \ + sizeof(struct rsa_priv_f1_pdb)) ++#define DESC_RSA_PRIV_F2_LEN (2 * CAAM_CMD_SZ + \ ++ sizeof(struct rsa_priv_f2_pdb)) ++#define DESC_RSA_PRIV_F3_LEN (2 * CAAM_CMD_SZ + \ ++ sizeof(struct rsa_priv_f3_pdb)) + + static void rsa_io_unmap(struct device *dev, struct rsa_edesc *edesc, + struct akcipher_request *req) +@@ -54,6 +58,42 @@ static void rsa_priv_f1_unmap(struct device *dev, struct rsa_edesc *edesc, + dma_unmap_single(dev, pdb->d_dma, key->d_sz, DMA_TO_DEVICE); + } + ++static void rsa_priv_f2_unmap(struct device *dev, struct rsa_edesc *edesc, ++ struct akcipher_request *req) ++{ ++ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); ++ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); ++ struct caam_rsa_key *key = &ctx->key; ++ struct rsa_priv_f2_pdb *pdb = &edesc->pdb.priv_f2; ++ size_t p_sz = key->p_sz; ++ size_t q_sz = key->p_sz; ++ ++ dma_unmap_single(dev, pdb->d_dma, key->d_sz, DMA_TO_DEVICE); ++ dma_unmap_single(dev, pdb->p_dma, p_sz, DMA_TO_DEVICE); ++ dma_unmap_single(dev, pdb->q_dma, q_sz, DMA_TO_DEVICE); ++ dma_unmap_single(dev, pdb->tmp1_dma, p_sz, DMA_TO_DEVICE); ++ dma_unmap_single(dev, pdb->tmp2_dma, q_sz, DMA_TO_DEVICE); ++} ++ ++static void rsa_priv_f3_unmap(struct device *dev, struct rsa_edesc *edesc, ++ struct akcipher_request *req) ++{ ++ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); ++ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); ++ struct caam_rsa_key *key = &ctx->key; ++ struct rsa_priv_f3_pdb *pdb = &edesc->pdb.priv_f3; ++ size_t p_sz = key->p_sz; ++ size_t q_sz = key->p_sz; ++ ++ dma_unmap_single(dev, pdb->p_dma, p_sz, DMA_TO_DEVICE); ++ dma_unmap_single(dev, pdb->q_dma, q_sz, DMA_TO_DEVICE); ++ dma_unmap_single(dev, pdb->dp_dma, p_sz, DMA_TO_DEVICE); ++ dma_unmap_single(dev, pdb->dq_dma, q_sz, DMA_TO_DEVICE); ++ dma_unmap_single(dev, pdb->c_dma, p_sz, DMA_TO_DEVICE); ++ dma_unmap_single(dev, pdb->tmp1_dma, p_sz, DMA_TO_DEVICE); ++ dma_unmap_single(dev, pdb->tmp2_dma, q_sz, DMA_TO_DEVICE); ++} ++ + /* RSA Job Completion handler */ + static void rsa_pub_done(struct device *dev, u32 *desc, u32 err, void *context) + { +@@ -90,6 +130,42 @@ static void rsa_priv_f1_done(struct device *dev, u32 *desc, u32 err, + akcipher_request_complete(req, err); + } + ++static void rsa_priv_f2_done(struct device *dev, u32 *desc, u32 err, ++ void *context) ++{ ++ struct akcipher_request *req = context; ++ struct rsa_edesc *edesc; ++ ++ if (err) ++ caam_jr_strstatus(dev, err); ++ ++ edesc = container_of(desc, struct rsa_edesc, hw_desc[0]); ++ ++ rsa_priv_f2_unmap(dev, edesc, req); ++ rsa_io_unmap(dev, edesc, req); ++ kfree(edesc); ++ ++ akcipher_request_complete(req, err); ++} ++ ++static void rsa_priv_f3_done(struct device *dev, u32 *desc, u32 err, ++ void *context) ++{ ++ struct akcipher_request *req = context; ++ struct rsa_edesc *edesc; ++ ++ if (err) ++ caam_jr_strstatus(dev, err); ++ ++ edesc = container_of(desc, struct rsa_edesc, hw_desc[0]); ++ ++ rsa_priv_f3_unmap(dev, edesc, req); ++ rsa_io_unmap(dev, edesc, req); ++ kfree(edesc); ++ ++ akcipher_request_complete(req, err); ++} ++ + static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req, + size_t desclen) + { +@@ -97,8 +173,8 @@ static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req, + struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); + struct device *dev = ctx->dev; + struct rsa_edesc *edesc; +- gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | +- CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC; ++ gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? ++ GFP_KERNEL : GFP_ATOMIC; + int sgc; + int sec4_sg_index, sec4_sg_len = 0, sec4_sg_bytes; + int src_nents, dst_nents; +@@ -258,6 +334,172 @@ static int set_rsa_priv_f1_pdb(struct akcipher_request *req, + return 0; + } + ++static int set_rsa_priv_f2_pdb(struct akcipher_request *req, ++ struct rsa_edesc *edesc) ++{ ++ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); ++ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); ++ struct caam_rsa_key *key = &ctx->key; ++ struct device *dev = ctx->dev; ++ struct rsa_priv_f2_pdb *pdb = &edesc->pdb.priv_f2; ++ int sec4_sg_index = 0; ++ size_t p_sz = key->p_sz; ++ size_t q_sz = key->p_sz; ++ ++ pdb->d_dma = dma_map_single(dev, key->d, key->d_sz, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, pdb->d_dma)) { ++ dev_err(dev, "Unable to map RSA private exponent memory\n"); ++ return -ENOMEM; ++ } ++ ++ pdb->p_dma = dma_map_single(dev, key->p, p_sz, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, pdb->p_dma)) { ++ dev_err(dev, "Unable to map RSA prime factor p memory\n"); ++ goto unmap_d; ++ } ++ ++ pdb->q_dma = dma_map_single(dev, key->q, q_sz, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, pdb->q_dma)) { ++ dev_err(dev, "Unable to map RSA prime factor q memory\n"); ++ goto unmap_p; ++ } ++ ++ pdb->tmp1_dma = dma_map_single(dev, key->tmp1, p_sz, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, pdb->tmp1_dma)) { ++ dev_err(dev, "Unable to map RSA tmp1 memory\n"); ++ goto unmap_q; ++ } ++ ++ pdb->tmp2_dma = dma_map_single(dev, key->tmp2, q_sz, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, pdb->tmp2_dma)) { ++ dev_err(dev, "Unable to map RSA tmp2 memory\n"); ++ goto unmap_tmp1; ++ } ++ ++ if (edesc->src_nents > 1) { ++ pdb->sgf |= RSA_PRIV_PDB_SGF_G; ++ pdb->g_dma = edesc->sec4_sg_dma; ++ sec4_sg_index += edesc->src_nents; ++ } else { ++ pdb->g_dma = sg_dma_address(req->src); ++ } ++ ++ if (edesc->dst_nents > 1) { ++ pdb->sgf |= RSA_PRIV_PDB_SGF_F; ++ pdb->f_dma = edesc->sec4_sg_dma + ++ sec4_sg_index * sizeof(struct sec4_sg_entry); ++ } else { ++ pdb->f_dma = sg_dma_address(req->dst); ++ } ++ ++ pdb->sgf |= (key->d_sz << RSA_PDB_D_SHIFT) | key->n_sz; ++ pdb->p_q_len = (q_sz << RSA_PDB_Q_SHIFT) | p_sz; ++ ++ return 0; ++ ++unmap_tmp1: ++ dma_unmap_single(dev, pdb->tmp1_dma, p_sz, DMA_TO_DEVICE); ++unmap_q: ++ dma_unmap_single(dev, pdb->q_dma, q_sz, DMA_TO_DEVICE); ++unmap_p: ++ dma_unmap_single(dev, pdb->p_dma, p_sz, DMA_TO_DEVICE); ++unmap_d: ++ dma_unmap_single(dev, pdb->d_dma, key->d_sz, DMA_TO_DEVICE); ++ ++ return -ENOMEM; ++} ++ ++static int set_rsa_priv_f3_pdb(struct akcipher_request *req, ++ struct rsa_edesc *edesc) ++{ ++ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); ++ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); ++ struct caam_rsa_key *key = &ctx->key; ++ struct device *dev = ctx->dev; ++ struct rsa_priv_f3_pdb *pdb = &edesc->pdb.priv_f3; ++ int sec4_sg_index = 0; ++ size_t p_sz = key->p_sz; ++ size_t q_sz = key->p_sz; ++ ++ pdb->p_dma = dma_map_single(dev, key->p, p_sz, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, pdb->p_dma)) { ++ dev_err(dev, "Unable to map RSA prime factor p memory\n"); ++ return -ENOMEM; ++ } ++ ++ pdb->q_dma = dma_map_single(dev, key->q, q_sz, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, pdb->q_dma)) { ++ dev_err(dev, "Unable to map RSA prime factor q memory\n"); ++ goto unmap_p; ++ } ++ ++ pdb->dp_dma = dma_map_single(dev, key->dp, p_sz, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, pdb->dp_dma)) { ++ dev_err(dev, "Unable to map RSA exponent dp memory\n"); ++ goto unmap_q; ++ } ++ ++ pdb->dq_dma = dma_map_single(dev, key->dq, q_sz, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, pdb->dq_dma)) { ++ dev_err(dev, "Unable to map RSA exponent dq memory\n"); ++ goto unmap_dp; ++ } ++ ++ pdb->c_dma = dma_map_single(dev, key->qinv, p_sz, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, pdb->c_dma)) { ++ dev_err(dev, "Unable to map RSA CRT coefficient qinv memory\n"); ++ goto unmap_dq; ++ } ++ ++ pdb->tmp1_dma = dma_map_single(dev, key->tmp1, p_sz, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, pdb->tmp1_dma)) { ++ dev_err(dev, "Unable to map RSA tmp1 memory\n"); ++ goto unmap_qinv; ++ } ++ ++ pdb->tmp2_dma = dma_map_single(dev, key->tmp2, q_sz, DMA_TO_DEVICE); ++ if (dma_mapping_error(dev, pdb->tmp2_dma)) { ++ dev_err(dev, "Unable to map RSA tmp2 memory\n"); ++ goto unmap_tmp1; ++ } ++ ++ if (edesc->src_nents > 1) { ++ pdb->sgf |= RSA_PRIV_PDB_SGF_G; ++ pdb->g_dma = edesc->sec4_sg_dma; ++ sec4_sg_index += edesc->src_nents; ++ } else { ++ pdb->g_dma = sg_dma_address(req->src); ++ } ++ ++ if (edesc->dst_nents > 1) { ++ pdb->sgf |= RSA_PRIV_PDB_SGF_F; ++ pdb->f_dma = edesc->sec4_sg_dma + ++ sec4_sg_index * sizeof(struct sec4_sg_entry); ++ } else { ++ pdb->f_dma = sg_dma_address(req->dst); ++ } ++ ++ pdb->sgf |= key->n_sz; ++ pdb->p_q_len = (q_sz << RSA_PDB_Q_SHIFT) | p_sz; ++ ++ return 0; ++ ++unmap_tmp1: ++ dma_unmap_single(dev, pdb->tmp1_dma, p_sz, DMA_TO_DEVICE); ++unmap_qinv: ++ dma_unmap_single(dev, pdb->c_dma, p_sz, DMA_TO_DEVICE); ++unmap_dq: ++ dma_unmap_single(dev, pdb->dq_dma, q_sz, DMA_TO_DEVICE); ++unmap_dp: ++ dma_unmap_single(dev, pdb->dp_dma, p_sz, DMA_TO_DEVICE); ++unmap_q: ++ dma_unmap_single(dev, pdb->q_dma, q_sz, DMA_TO_DEVICE); ++unmap_p: ++ dma_unmap_single(dev, pdb->p_dma, p_sz, DMA_TO_DEVICE); ++ ++ return -ENOMEM; ++} ++ + static int caam_rsa_enc(struct akcipher_request *req) + { + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); +@@ -301,24 +543,14 @@ static int caam_rsa_enc(struct akcipher_request *req) + return ret; + } + +-static int caam_rsa_dec(struct akcipher_request *req) ++static int caam_rsa_dec_priv_f1(struct akcipher_request *req) + { + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); +- struct caam_rsa_key *key = &ctx->key; + struct device *jrdev = ctx->dev; + struct rsa_edesc *edesc; + int ret; + +- if (unlikely(!key->n || !key->d)) +- return -EINVAL; +- +- if (req->dst_len < key->n_sz) { +- req->dst_len = key->n_sz; +- dev_err(jrdev, "Output buffer length less than parameter n\n"); +- return -EOVERFLOW; +- } +- + /* Allocate extended descriptor */ + edesc = rsa_edesc_alloc(req, DESC_RSA_PRIV_F1_LEN); + if (IS_ERR(edesc)) +@@ -344,17 +576,147 @@ static int caam_rsa_dec(struct akcipher_request *req) + return ret; + } + ++static int caam_rsa_dec_priv_f2(struct akcipher_request *req) ++{ ++ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); ++ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); ++ struct device *jrdev = ctx->dev; ++ struct rsa_edesc *edesc; ++ int ret; ++ ++ /* Allocate extended descriptor */ ++ edesc = rsa_edesc_alloc(req, DESC_RSA_PRIV_F2_LEN); ++ if (IS_ERR(edesc)) ++ return PTR_ERR(edesc); ++ ++ /* Set RSA Decrypt Protocol Data Block - Private Key Form #2 */ ++ ret = set_rsa_priv_f2_pdb(req, edesc); ++ if (ret) ++ goto init_fail; ++ ++ /* Initialize Job Descriptor */ ++ init_rsa_priv_f2_desc(edesc->hw_desc, &edesc->pdb.priv_f2); ++ ++ ret = caam_jr_enqueue(jrdev, edesc->hw_desc, rsa_priv_f2_done, req); ++ if (!ret) ++ return -EINPROGRESS; ++ ++ rsa_priv_f2_unmap(jrdev, edesc, req); ++ ++init_fail: ++ rsa_io_unmap(jrdev, edesc, req); ++ kfree(edesc); ++ return ret; ++} ++ ++static int caam_rsa_dec_priv_f3(struct akcipher_request *req) ++{ ++ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); ++ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); ++ struct device *jrdev = ctx->dev; ++ struct rsa_edesc *edesc; ++ int ret; ++ ++ /* Allocate extended descriptor */ ++ edesc = rsa_edesc_alloc(req, DESC_RSA_PRIV_F3_LEN); ++ if (IS_ERR(edesc)) ++ return PTR_ERR(edesc); ++ ++ /* Set RSA Decrypt Protocol Data Block - Private Key Form #3 */ ++ ret = set_rsa_priv_f3_pdb(req, edesc); ++ if (ret) ++ goto init_fail; ++ ++ /* Initialize Job Descriptor */ ++ init_rsa_priv_f3_desc(edesc->hw_desc, &edesc->pdb.priv_f3); ++ ++ ret = caam_jr_enqueue(jrdev, edesc->hw_desc, rsa_priv_f3_done, req); ++ if (!ret) ++ return -EINPROGRESS; ++ ++ rsa_priv_f3_unmap(jrdev, edesc, req); ++ ++init_fail: ++ rsa_io_unmap(jrdev, edesc, req); ++ kfree(edesc); ++ return ret; ++} ++ ++static int caam_rsa_dec(struct akcipher_request *req) ++{ ++ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); ++ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); ++ struct caam_rsa_key *key = &ctx->key; ++ int ret; ++ ++ if (unlikely(!key->n || !key->d)) ++ return -EINVAL; ++ ++ if (req->dst_len < key->n_sz) { ++ req->dst_len = key->n_sz; ++ dev_err(ctx->dev, "Output buffer length less than parameter n\n"); ++ return -EOVERFLOW; ++ } ++ ++ if (key->priv_form == FORM3) ++ ret = caam_rsa_dec_priv_f3(req); ++ else if (key->priv_form == FORM2) ++ ret = caam_rsa_dec_priv_f2(req); ++ else ++ ret = caam_rsa_dec_priv_f1(req); ++ ++ return ret; ++} ++ + static void caam_rsa_free_key(struct caam_rsa_key *key) + { + kzfree(key->d); ++ kzfree(key->p); ++ kzfree(key->q); ++ kzfree(key->dp); ++ kzfree(key->dq); ++ kzfree(key->qinv); ++ kzfree(key->tmp1); ++ kzfree(key->tmp2); + kfree(key->e); + kfree(key->n); +- key->d = NULL; +- key->e = NULL; +- key->n = NULL; +- key->d_sz = 0; +- key->e_sz = 0; +- key->n_sz = 0; ++ memset(key, 0, sizeof(*key)); ++} ++ ++static void caam_rsa_drop_leading_zeros(const u8 **ptr, size_t *nbytes) ++{ ++ while (!**ptr && *nbytes) { ++ (*ptr)++; ++ (*nbytes)--; ++ } ++} ++ ++/** ++ * caam_read_rsa_crt - Used for reading dP, dQ, qInv CRT members. ++ * dP, dQ and qInv could decode to less than corresponding p, q length, as the ++ * BER-encoding requires that the minimum number of bytes be used to encode the ++ * integer. dP, dQ, qInv decoded values have to be zero-padded to appropriate ++ * length. ++ * ++ * @ptr : pointer to {dP, dQ, qInv} CRT member ++ * @nbytes: length in bytes of {dP, dQ, qInv} CRT member ++ * @dstlen: length in bytes of corresponding p or q prime factor ++ */ ++static u8 *caam_read_rsa_crt(const u8 *ptr, size_t nbytes, size_t dstlen) ++{ ++ u8 *dst; ++ ++ caam_rsa_drop_leading_zeros(&ptr, &nbytes); ++ if (!nbytes) ++ return NULL; ++ ++ dst = kzalloc(dstlen, GFP_DMA | GFP_KERNEL); ++ if (!dst) ++ return NULL; ++ ++ memcpy(dst + (dstlen - nbytes), ptr, nbytes); ++ ++ return dst; + } + + /** +@@ -370,10 +732,9 @@ static inline u8 *caam_read_raw_data(const u8 *buf, size_t *nbytes) + { + u8 *val; + +- while (!*buf && *nbytes) { +- buf++; +- (*nbytes)--; +- } ++ caam_rsa_drop_leading_zeros(&buf, nbytes); ++ if (!*nbytes) ++ return NULL; + + val = kzalloc(*nbytes, GFP_DMA | GFP_KERNEL); + if (!val) +@@ -395,7 +756,7 @@ static int caam_rsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, + unsigned int keylen) + { + struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); +- struct rsa_key raw_key = {0}; ++ struct rsa_key raw_key = {NULL}; + struct caam_rsa_key *rsa_key = &ctx->key; + int ret; + +@@ -437,11 +798,69 @@ static int caam_rsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, + return -ENOMEM; + } + ++static void caam_rsa_set_priv_key_form(struct caam_rsa_ctx *ctx, ++ struct rsa_key *raw_key) ++{ ++ struct caam_rsa_key *rsa_key = &ctx->key; ++ size_t p_sz = raw_key->p_sz; ++ size_t q_sz = raw_key->q_sz; ++ ++ rsa_key->p = caam_read_raw_data(raw_key->p, &p_sz); ++ if (!rsa_key->p) ++ return; ++ rsa_key->p_sz = p_sz; ++ ++ rsa_key->q = caam_read_raw_data(raw_key->q, &q_sz); ++ if (!rsa_key->q) ++ goto free_p; ++ rsa_key->q_sz = q_sz; ++ ++ rsa_key->tmp1 = kzalloc(raw_key->p_sz, GFP_DMA | GFP_KERNEL); ++ if (!rsa_key->tmp1) ++ goto free_q; ++ ++ rsa_key->tmp2 = kzalloc(raw_key->q_sz, GFP_DMA | GFP_KERNEL); ++ if (!rsa_key->tmp2) ++ goto free_tmp1; ++ ++ rsa_key->priv_form = FORM2; ++ ++ rsa_key->dp = caam_read_rsa_crt(raw_key->dp, raw_key->dp_sz, p_sz); ++ if (!rsa_key->dp) ++ goto free_tmp2; ++ ++ rsa_key->dq = caam_read_rsa_crt(raw_key->dq, raw_key->dq_sz, q_sz); ++ if (!rsa_key->dq) ++ goto free_dp; ++ ++ rsa_key->qinv = caam_read_rsa_crt(raw_key->qinv, raw_key->qinv_sz, ++ q_sz); ++ if (!rsa_key->qinv) ++ goto free_dq; ++ ++ rsa_key->priv_form = FORM3; ++ ++ return; ++ ++free_dq: ++ kzfree(rsa_key->dq); ++free_dp: ++ kzfree(rsa_key->dp); ++free_tmp2: ++ kzfree(rsa_key->tmp2); ++free_tmp1: ++ kzfree(rsa_key->tmp1); ++free_q: ++ kzfree(rsa_key->q); ++free_p: ++ kzfree(rsa_key->p); ++} ++ + static int caam_rsa_set_priv_key(struct crypto_akcipher *tfm, const void *key, + unsigned int keylen) + { + struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); +- struct rsa_key raw_key = {0}; ++ struct rsa_key raw_key = {NULL}; + struct caam_rsa_key *rsa_key = &ctx->key; + int ret; + +@@ -483,6 +902,8 @@ static int caam_rsa_set_priv_key(struct crypto_akcipher *tfm, const void *key, + memcpy(rsa_key->d, raw_key.d, raw_key.d_sz); + memcpy(rsa_key->e, raw_key.e, raw_key.e_sz); + ++ caam_rsa_set_priv_key_form(ctx, &raw_key); ++ + return 0; + + err: +diff --git a/drivers/crypto/caam/caampkc.h b/drivers/crypto/caam/caampkc.h +index f595d159..87ab75e9 100644 +--- a/drivers/crypto/caam/caampkc.h ++++ b/drivers/crypto/caam/caampkc.h +@@ -12,22 +12,76 @@ + #include "compat.h" + #include "pdb.h" + ++/** ++ * caam_priv_key_form - CAAM RSA private key representation ++ * CAAM RSA private key may have either of three forms. ++ * ++ * 1. The first representation consists of the pair (n, d), where the ++ * components have the following meanings: ++ * n the RSA modulus ++ * d the RSA private exponent ++ * ++ * 2. The second representation consists of the triplet (p, q, d), where the ++ * components have the following meanings: ++ * p the first prime factor of the RSA modulus n ++ * q the second prime factor of the RSA modulus n ++ * d the RSA private exponent ++ * ++ * 3. The third representation consists of the quintuple (p, q, dP, dQ, qInv), ++ * where the components have the following meanings: ++ * p the first prime factor of the RSA modulus n ++ * q the second prime factor of the RSA modulus n ++ * dP the first factors's CRT exponent ++ * dQ the second factors's CRT exponent ++ * qInv the (first) CRT coefficient ++ * ++ * The benefit of using the third or the second key form is lower computational ++ * cost for the decryption and signature operations. ++ */ ++enum caam_priv_key_form { ++ FORM1, ++ FORM2, ++ FORM3 ++}; ++ + /** + * caam_rsa_key - CAAM RSA key structure. Keys are allocated in DMA zone. + * @n : RSA modulus raw byte stream + * @e : RSA public exponent raw byte stream + * @d : RSA private exponent raw byte stream ++ * @p : RSA prime factor p of RSA modulus n ++ * @q : RSA prime factor q of RSA modulus n ++ * @dp : RSA CRT exponent of p ++ * @dp : RSA CRT exponent of q ++ * @qinv : RSA CRT coefficient ++ * @tmp1 : CAAM uses this temporary buffer as internal state buffer. ++ * It is assumed to be as long as p. ++ * @tmp2 : CAAM uses this temporary buffer as internal state buffer. ++ * It is assumed to be as long as q. + * @n_sz : length in bytes of RSA modulus n + * @e_sz : length in bytes of RSA public exponent + * @d_sz : length in bytes of RSA private exponent ++ * @p_sz : length in bytes of RSA prime factor p of RSA modulus n ++ * @q_sz : length in bytes of RSA prime factor q of RSA modulus n ++ * @priv_form : CAAM RSA private key representation + */ + struct caam_rsa_key { + u8 *n; + u8 *e; + u8 *d; ++ u8 *p; ++ u8 *q; ++ u8 *dp; ++ u8 *dq; ++ u8 *qinv; ++ u8 *tmp1; ++ u8 *tmp2; + size_t n_sz; + size_t e_sz; + size_t d_sz; ++ size_t p_sz; ++ size_t q_sz; ++ enum caam_priv_key_form priv_form; + }; + + /** +@@ -59,6 +113,8 @@ struct rsa_edesc { + union { + struct rsa_pub_pdb pub; + struct rsa_priv_f1_pdb priv_f1; ++ struct rsa_priv_f2_pdb priv_f2; ++ struct rsa_priv_f3_pdb priv_f3; + } pdb; + u32 hw_desc[]; + }; +@@ -66,5 +122,7 @@ struct rsa_edesc { + /* Descriptor construction primitives. */ + void init_rsa_pub_desc(u32 *desc, struct rsa_pub_pdb *pdb); + void init_rsa_priv_f1_desc(u32 *desc, struct rsa_priv_f1_pdb *pdb); ++void init_rsa_priv_f2_desc(u32 *desc, struct rsa_priv_f2_pdb *pdb); ++void init_rsa_priv_f3_desc(u32 *desc, struct rsa_priv_f3_pdb *pdb); + + #endif +diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c +index 9b92af2c..fde07d4f 100644 +--- a/drivers/crypto/caam/caamrng.c ++++ b/drivers/crypto/caam/caamrng.c +@@ -52,7 +52,7 @@ + + /* length of descriptors */ + #define DESC_JOB_O_LEN (CAAM_CMD_SZ * 2 + CAAM_PTR_SZ * 2) +-#define DESC_RNG_LEN (4 * CAAM_CMD_SZ) ++#define DESC_RNG_LEN (3 * CAAM_CMD_SZ) + + /* Buffer, its dma address and lock */ + struct buf_data { +@@ -100,8 +100,7 @@ static void rng_done(struct device *jrdev, u32 *desc, u32 err, void *context) + { + struct buf_data *bd; + +- bd = (struct buf_data *)((char *)desc - +- offsetof(struct buf_data, hw_desc)); ++ bd = container_of(desc, struct buf_data, hw_desc[0]); + + if (err) + caam_jr_strstatus(jrdev, err); +@@ -196,9 +195,6 @@ static inline int rng_create_sh_desc(struct caam_rng_ctx *ctx) + + init_sh_desc(desc, HDR_SHARE_SERIAL); + +- /* Propagate errors from shared to job descriptor */ +- append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); +- + /* Generate random bytes */ + append_operation(desc, OP_ALG_ALGSEL_RNG | OP_TYPE_CLASS1_ALG); + +@@ -289,11 +285,7 @@ static int caam_init_rng(struct caam_rng_ctx *ctx, struct device *jrdev) + if (err) + return err; + +- err = caam_init_buf(ctx, 1); +- if (err) +- return err; +- +- return 0; ++ return caam_init_buf(ctx, 1); + } + + static struct hwrng caam_rng = { +@@ -351,7 +343,7 @@ static int __init caam_rng_init(void) + pr_err("Job Ring Device allocation for transform failed\n"); + return PTR_ERR(dev); + } +- rng_ctx = kmalloc(sizeof(*rng_ctx), GFP_DMA); ++ rng_ctx = kmalloc(sizeof(*rng_ctx), GFP_DMA | GFP_KERNEL); + if (!rng_ctx) { + err = -ENOMEM; + goto free_caam_alloc; +diff --git a/drivers/crypto/caam/compat.h b/drivers/crypto/caam/compat.h +index 7149cd24..4e084f51 100644 +--- a/drivers/crypto/caam/compat.h ++++ b/drivers/crypto/caam/compat.h +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c +index 98468b96..8f9642c6 100644 +--- a/drivers/crypto/caam/ctrl.c ++++ b/drivers/crypto/caam/ctrl.c +@@ -2,40 +2,41 @@ + * Controller-level driver, kernel property detection, initialization + * + * Copyright 2008-2012 Freescale Semiconductor, Inc. ++ * Copyright 2017 NXP + */ + + #include + #include + #include ++#include + + #include "compat.h" + #include "regs.h" + #include "intern.h" + #include "jr.h" + #include "desc_constr.h" +-#include "error.h" + #include "ctrl.h" + + bool caam_little_end; + EXPORT_SYMBOL(caam_little_end); ++bool caam_imx; ++EXPORT_SYMBOL(caam_imx); ++bool caam_dpaa2; ++EXPORT_SYMBOL(caam_dpaa2); ++ ++#ifdef CONFIG_CAAM_QI ++#include "qi.h" ++#endif + + /* + * i.MX targets tend to have clock control subsystems that can + * enable/disable clocking to our device. + */ +-#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_IMX +-static inline struct clk *caam_drv_identify_clk(struct device *dev, +- char *clk_name) +-{ +- return devm_clk_get(dev, clk_name); +-} +-#else + static inline struct clk *caam_drv_identify_clk(struct device *dev, + char *clk_name) + { +- return NULL; ++ return caam_imx ? devm_clk_get(dev, clk_name) : NULL; + } +-#endif + + /* + * Descriptor to instantiate RNG State Handle 0 in normal mode and +@@ -270,7 +271,7 @@ static int deinstantiate_rng(struct device *ctrldev, int state_handle_mask) + /* + * If the corresponding bit is set, then it means the state + * handle was initialized by us, and thus it needs to be +- * deintialized as well ++ * deinitialized as well + */ + if ((1 << sh_idx) & state_handle_mask) { + /* +@@ -303,20 +304,24 @@ static int caam_remove(struct platform_device *pdev) + struct device *ctrldev; + struct caam_drv_private *ctrlpriv; + struct caam_ctrl __iomem *ctrl; +- int ring; + + ctrldev = &pdev->dev; + ctrlpriv = dev_get_drvdata(ctrldev); + ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl; + +- /* Remove platform devices for JobRs */ +- for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) { +- if (ctrlpriv->jrpdev[ring]) +- of_device_unregister(ctrlpriv->jrpdev[ring]); +- } ++ /* Remove platform devices under the crypto node */ ++ of_platform_depopulate(ctrldev); ++ ++#ifdef CONFIG_CAAM_QI ++ if (ctrlpriv->qidev) ++ caam_qi_shutdown(ctrlpriv->qidev); ++#endif + +- /* De-initialize RNG state handles initialized by this driver. */ +- if (ctrlpriv->rng4_sh_init) ++ /* ++ * De-initialize RNG state handles initialized by this driver. ++ * In case of DPAA 2.x, RNG is managed by MC firmware. ++ */ ++ if (!caam_dpaa2 && ctrlpriv->rng4_sh_init) + deinstantiate_rng(ctrldev, ctrlpriv->rng4_sh_init); + + /* Shut down debug views */ +@@ -331,8 +336,8 @@ static int caam_remove(struct platform_device *pdev) + clk_disable_unprepare(ctrlpriv->caam_ipg); + clk_disable_unprepare(ctrlpriv->caam_mem); + clk_disable_unprepare(ctrlpriv->caam_aclk); +- clk_disable_unprepare(ctrlpriv->caam_emi_slow); +- ++ if (ctrlpriv->caam_emi_slow) ++ clk_disable_unprepare(ctrlpriv->caam_emi_slow); + return 0; + } + +@@ -366,11 +371,8 @@ static void kick_trng(struct platform_device *pdev, int ent_delay) + */ + val = (rd_reg32(&r4tst->rtsdctl) & RTSDCTL_ENT_DLY_MASK) + >> RTSDCTL_ENT_DLY_SHIFT; +- if (ent_delay <= val) { +- /* put RNG4 into run mode */ +- clrsetbits_32(&r4tst->rtmctl, RTMCTL_PRGM, 0); +- return; +- } ++ if (ent_delay <= val) ++ goto start_rng; + + val = rd_reg32(&r4tst->rtsdctl); + val = (val & ~RTSDCTL_ENT_DLY_MASK) | +@@ -382,15 +384,12 @@ static void kick_trng(struct platform_device *pdev, int ent_delay) + wr_reg32(&r4tst->rtfrqmax, RTFRQMAX_DISABLE); + /* read the control register */ + val = rd_reg32(&r4tst->rtmctl); ++start_rng: + /* + * select raw sampling in both entropy shifter +- * and statistical checker ++ * and statistical checker; ; put RNG4 into run mode + */ +- clrsetbits_32(&val, 0, RTMCTL_SAMP_MODE_RAW_ES_SC); +- /* put RNG4 into run mode */ +- clrsetbits_32(&val, RTMCTL_PRGM, 0); +- /* write back the control register */ +- wr_reg32(&r4tst->rtmctl, val); ++ clrsetbits_32(&r4tst->rtmctl, RTMCTL_PRGM, RTMCTL_SAMP_MODE_RAW_ES_SC); + } + + /** +@@ -411,28 +410,26 @@ int caam_get_era(void) + } + EXPORT_SYMBOL(caam_get_era); + +-#ifdef CONFIG_DEBUG_FS +-static int caam_debugfs_u64_get(void *data, u64 *val) +-{ +- *val = caam64_to_cpu(*(u64 *)data); +- return 0; +-} +- +-static int caam_debugfs_u32_get(void *data, u64 *val) +-{ +- *val = caam32_to_cpu(*(u32 *)data); +- return 0; +-} +- +-DEFINE_SIMPLE_ATTRIBUTE(caam_fops_u32_ro, caam_debugfs_u32_get, NULL, "%llu\n"); +-DEFINE_SIMPLE_ATTRIBUTE(caam_fops_u64_ro, caam_debugfs_u64_get, NULL, "%llu\n"); +-#endif ++static const struct of_device_id caam_match[] = { ++ { ++ .compatible = "fsl,sec-v4.0", ++ }, ++ { ++ .compatible = "fsl,sec4.0", ++ }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, caam_match); + + /* Probe routine for CAAM top (controller) level */ + static int caam_probe(struct platform_device *pdev) + { +- int ret, ring, rspec, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN; ++ int ret, ring, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN; + u64 caam_id; ++ static const struct soc_device_attribute imx_soc[] = { ++ {.family = "Freescale i.MX"}, ++ {}, ++ }; + struct device *dev; + struct device_node *nprop, *np; + struct caam_ctrl __iomem *ctrl; +@@ -452,9 +449,10 @@ static int caam_probe(struct platform_device *pdev) + + dev = &pdev->dev; + dev_set_drvdata(dev, ctrlpriv); +- ctrlpriv->pdev = pdev; + nprop = pdev->dev.of_node; + ++ caam_imx = (bool)soc_device_match(imx_soc); ++ + /* Enable clocking */ + clk = caam_drv_identify_clk(&pdev->dev, "ipg"); + if (IS_ERR(clk)) { +@@ -483,14 +481,16 @@ static int caam_probe(struct platform_device *pdev) + } + ctrlpriv->caam_aclk = clk; + +- clk = caam_drv_identify_clk(&pdev->dev, "emi_slow"); +- if (IS_ERR(clk)) { +- ret = PTR_ERR(clk); +- dev_err(&pdev->dev, +- "can't identify CAAM emi_slow clk: %d\n", ret); +- return ret; ++ if (!of_machine_is_compatible("fsl,imx6ul")) { ++ clk = caam_drv_identify_clk(&pdev->dev, "emi_slow"); ++ if (IS_ERR(clk)) { ++ ret = PTR_ERR(clk); ++ dev_err(&pdev->dev, ++ "can't identify CAAM emi_slow clk: %d\n", ret); ++ return ret; ++ } ++ ctrlpriv->caam_emi_slow = clk; + } +- ctrlpriv->caam_emi_slow = clk; + + ret = clk_prepare_enable(ctrlpriv->caam_ipg); + if (ret < 0) { +@@ -511,11 +511,13 @@ static int caam_probe(struct platform_device *pdev) + goto disable_caam_mem; + } + +- ret = clk_prepare_enable(ctrlpriv->caam_emi_slow); +- if (ret < 0) { +- dev_err(&pdev->dev, "can't enable CAAM emi slow clock: %d\n", +- ret); +- goto disable_caam_aclk; ++ if (ctrlpriv->caam_emi_slow) { ++ ret = clk_prepare_enable(ctrlpriv->caam_emi_slow); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "can't enable CAAM emi slow clock: %d\n", ++ ret); ++ goto disable_caam_aclk; ++ } + } + + /* Get configuration properties from device tree */ +@@ -542,13 +544,13 @@ static int caam_probe(struct platform_device *pdev) + else + BLOCK_OFFSET = PG_SIZE_64K; + +- ctrlpriv->ctrl = (struct caam_ctrl __force *)ctrl; +- ctrlpriv->assure = (struct caam_assurance __force *) +- ((uint8_t *)ctrl + ++ ctrlpriv->ctrl = (struct caam_ctrl __iomem __force *)ctrl; ++ ctrlpriv->assure = (struct caam_assurance __iomem __force *) ++ ((__force uint8_t *)ctrl + + BLOCK_OFFSET * ASSURE_BLOCK_NUMBER + ); +- ctrlpriv->deco = (struct caam_deco __force *) +- ((uint8_t *)ctrl + ++ ctrlpriv->deco = (struct caam_deco __iomem __force *) ++ ((__force uint8_t *)ctrl + + BLOCK_OFFSET * DECO_BLOCK_NUMBER + ); + +@@ -557,12 +559,17 @@ static int caam_probe(struct platform_device *pdev) + + /* + * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel, +- * long pointers in master configuration register ++ * long pointers in master configuration register. ++ * In case of DPAA 2.x, Management Complex firmware performs ++ * the configuration. + */ +- clrsetbits_32(&ctrl->mcr, MCFGR_AWCACHE_MASK | MCFGR_LONG_PTR, +- MCFGR_AWCACHE_CACH | MCFGR_AWCACHE_BUFF | +- MCFGR_WDENABLE | MCFGR_LARGE_BURST | +- (sizeof(dma_addr_t) == sizeof(u64) ? MCFGR_LONG_PTR : 0)); ++ caam_dpaa2 = !!(comp_params & CTPR_MS_DPAA2); ++ if (!caam_dpaa2) ++ clrsetbits_32(&ctrl->mcr, MCFGR_AWCACHE_MASK | MCFGR_LONG_PTR, ++ MCFGR_AWCACHE_CACH | MCFGR_AWCACHE_BUFF | ++ MCFGR_WDENABLE | MCFGR_LARGE_BURST | ++ (sizeof(dma_addr_t) == sizeof(u64) ? ++ MCFGR_LONG_PTR : 0)); + + /* + * Read the Compile Time paramters and SCFGR to determine +@@ -590,64 +597,67 @@ static int caam_probe(struct platform_device *pdev) + JRSTART_JR1_START | JRSTART_JR2_START | + JRSTART_JR3_START); + +- if (sizeof(dma_addr_t) == sizeof(u64)) +- if (of_device_is_compatible(nprop, "fsl,sec-v5.0")) +- dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); ++ if (sizeof(dma_addr_t) == sizeof(u64)) { ++ if (caam_dpaa2) ++ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(49)); ++ else if (of_device_is_compatible(nprop, "fsl,sec-v5.0")) ++ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); + else +- dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36)); +- else +- dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); +- +- /* +- * Detect and enable JobRs +- * First, find out how many ring spec'ed, allocate references +- * for all, then go probe each one. +- */ +- rspec = 0; +- for_each_available_child_of_node(nprop, np) +- if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") || +- of_device_is_compatible(np, "fsl,sec4.0-job-ring")) +- rspec++; ++ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36)); ++ } else { ++ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); ++ } ++ if (ret) { ++ dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret); ++ goto iounmap_ctrl; ++ } + +- ctrlpriv->jrpdev = devm_kcalloc(&pdev->dev, rspec, +- sizeof(*ctrlpriv->jrpdev), GFP_KERNEL); +- if (ctrlpriv->jrpdev == NULL) { +- ret = -ENOMEM; ++ ret = of_platform_populate(nprop, caam_match, NULL, dev); ++ if (ret) { ++ dev_err(dev, "JR platform devices creation error\n"); + goto iounmap_ctrl; + } + ++#ifdef CONFIG_DEBUG_FS ++ /* ++ * FIXME: needs better naming distinction, as some amalgamation of ++ * "caam" and nprop->full_name. The OF name isn't distinctive, ++ * but does separate instances ++ */ ++ perfmon = (struct caam_perfmon __force *)&ctrl->perfmon; ++ ++ ctrlpriv->dfs_root = debugfs_create_dir(dev_name(dev), NULL); ++ ctrlpriv->ctl = debugfs_create_dir("ctl", ctrlpriv->dfs_root); ++#endif + ring = 0; +- ctrlpriv->total_jobrs = 0; + for_each_available_child_of_node(nprop, np) + if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") || + of_device_is_compatible(np, "fsl,sec4.0-job-ring")) { +- ctrlpriv->jrpdev[ring] = +- of_platform_device_create(np, NULL, dev); +- if (!ctrlpriv->jrpdev[ring]) { +- pr_warn("JR%d Platform device creation error\n", +- ring); +- continue; +- } +- ctrlpriv->jr[ring] = (struct caam_job_ring __force *) +- ((uint8_t *)ctrl + ++ ctrlpriv->jr[ring] = (struct caam_job_ring __iomem __force *) ++ ((__force uint8_t *)ctrl + + (ring + JR_BLOCK_NUMBER) * + BLOCK_OFFSET + ); + ctrlpriv->total_jobrs++; + ring++; +- } ++ } + +- /* Check to see if QI present. If so, enable */ +- ctrlpriv->qi_present = +- !!(rd_reg32(&ctrl->perfmon.comp_parms_ms) & +- CTPR_MS_QI_MASK); +- if (ctrlpriv->qi_present) { +- ctrlpriv->qi = (struct caam_queue_if __force *) +- ((uint8_t *)ctrl + ++ /* Check to see if (DPAA 1.x) QI present. If so, enable */ ++ ctrlpriv->qi_present = !!(comp_params & CTPR_MS_QI_MASK); ++ if (ctrlpriv->qi_present && !caam_dpaa2) { ++ ctrlpriv->qi = (struct caam_queue_if __iomem __force *) ++ ((__force uint8_t *)ctrl + + BLOCK_OFFSET * QI_BLOCK_NUMBER + ); + /* This is all that's required to physically enable QI */ + wr_reg32(&ctrlpriv->qi->qi_control_lo, QICTL_DQEN); ++ ++ /* If QMAN driver is present, init CAAM-QI backend */ ++#ifdef CONFIG_CAAM_QI ++ ret = caam_qi_init(pdev); ++ if (ret) ++ dev_err(dev, "caam qi i/f init failed: %d\n", ret); ++#endif + } + + /* If no QI and no rings specified, quit and go home */ +@@ -662,8 +672,10 @@ static int caam_probe(struct platform_device *pdev) + /* + * If SEC has RNG version >= 4 and RNG state handle has not been + * already instantiated, do RNG instantiation ++ * In case of DPAA 2.x, RNG is managed by MC firmware. + */ +- if ((cha_vid_ls & CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT >= 4) { ++ if (!caam_dpaa2 && ++ (cha_vid_ls & CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT >= 4) { + ctrlpriv->rng4_sh_init = + rd_reg32(&ctrl->r4tst[0].rdsta); + /* +@@ -731,77 +743,46 @@ static int caam_probe(struct platform_device *pdev) + /* Report "alive" for developer to see */ + dev_info(dev, "device ID = 0x%016llx (Era %d)\n", caam_id, + caam_get_era()); +- dev_info(dev, "job rings = %d, qi = %d\n", +- ctrlpriv->total_jobrs, ctrlpriv->qi_present); ++ dev_info(dev, "job rings = %d, qi = %d, dpaa2 = %s\n", ++ ctrlpriv->total_jobrs, ctrlpriv->qi_present, ++ caam_dpaa2 ? "yes" : "no"); + + #ifdef CONFIG_DEBUG_FS +- /* +- * FIXME: needs better naming distinction, as some amalgamation of +- * "caam" and nprop->full_name. The OF name isn't distinctive, +- * but does separate instances +- */ +- perfmon = (struct caam_perfmon __force *)&ctrl->perfmon; +- +- ctrlpriv->dfs_root = debugfs_create_dir(dev_name(dev), NULL); +- ctrlpriv->ctl = debugfs_create_dir("ctl", ctrlpriv->dfs_root); +- +- /* Controller-level - performance monitor counters */ +- +- ctrlpriv->ctl_rq_dequeued = +- debugfs_create_file("rq_dequeued", +- S_IRUSR | S_IRGRP | S_IROTH, +- ctrlpriv->ctl, &perfmon->req_dequeued, +- &caam_fops_u64_ro); +- ctrlpriv->ctl_ob_enc_req = +- debugfs_create_file("ob_rq_encrypted", +- S_IRUSR | S_IRGRP | S_IROTH, +- ctrlpriv->ctl, &perfmon->ob_enc_req, +- &caam_fops_u64_ro); +- ctrlpriv->ctl_ib_dec_req = +- debugfs_create_file("ib_rq_decrypted", +- S_IRUSR | S_IRGRP | S_IROTH, +- ctrlpriv->ctl, &perfmon->ib_dec_req, +- &caam_fops_u64_ro); +- ctrlpriv->ctl_ob_enc_bytes = +- debugfs_create_file("ob_bytes_encrypted", +- S_IRUSR | S_IRGRP | S_IROTH, +- ctrlpriv->ctl, &perfmon->ob_enc_bytes, +- &caam_fops_u64_ro); +- ctrlpriv->ctl_ob_prot_bytes = +- debugfs_create_file("ob_bytes_protected", +- S_IRUSR | S_IRGRP | S_IROTH, +- ctrlpriv->ctl, &perfmon->ob_prot_bytes, +- &caam_fops_u64_ro); +- ctrlpriv->ctl_ib_dec_bytes = +- debugfs_create_file("ib_bytes_decrypted", +- S_IRUSR | S_IRGRP | S_IROTH, +- ctrlpriv->ctl, &perfmon->ib_dec_bytes, +- &caam_fops_u64_ro); +- ctrlpriv->ctl_ib_valid_bytes = +- debugfs_create_file("ib_bytes_validated", +- S_IRUSR | S_IRGRP | S_IROTH, +- ctrlpriv->ctl, &perfmon->ib_valid_bytes, +- &caam_fops_u64_ro); ++ debugfs_create_file("rq_dequeued", S_IRUSR | S_IRGRP | S_IROTH, ++ ctrlpriv->ctl, &perfmon->req_dequeued, ++ &caam_fops_u64_ro); ++ debugfs_create_file("ob_rq_encrypted", S_IRUSR | S_IRGRP | S_IROTH, ++ ctrlpriv->ctl, &perfmon->ob_enc_req, ++ &caam_fops_u64_ro); ++ debugfs_create_file("ib_rq_decrypted", S_IRUSR | S_IRGRP | S_IROTH, ++ ctrlpriv->ctl, &perfmon->ib_dec_req, ++ &caam_fops_u64_ro); ++ debugfs_create_file("ob_bytes_encrypted", S_IRUSR | S_IRGRP | S_IROTH, ++ ctrlpriv->ctl, &perfmon->ob_enc_bytes, ++ &caam_fops_u64_ro); ++ debugfs_create_file("ob_bytes_protected", S_IRUSR | S_IRGRP | S_IROTH, ++ ctrlpriv->ctl, &perfmon->ob_prot_bytes, ++ &caam_fops_u64_ro); ++ debugfs_create_file("ib_bytes_decrypted", S_IRUSR | S_IRGRP | S_IROTH, ++ ctrlpriv->ctl, &perfmon->ib_dec_bytes, ++ &caam_fops_u64_ro); ++ debugfs_create_file("ib_bytes_validated", S_IRUSR | S_IRGRP | S_IROTH, ++ ctrlpriv->ctl, &perfmon->ib_valid_bytes, ++ &caam_fops_u64_ro); + + /* Controller level - global status values */ +- ctrlpriv->ctl_faultaddr = +- debugfs_create_file("fault_addr", +- S_IRUSR | S_IRGRP | S_IROTH, +- ctrlpriv->ctl, &perfmon->faultaddr, +- &caam_fops_u32_ro); +- ctrlpriv->ctl_faultdetail = +- debugfs_create_file("fault_detail", +- S_IRUSR | S_IRGRP | S_IROTH, +- ctrlpriv->ctl, &perfmon->faultdetail, +- &caam_fops_u32_ro); +- ctrlpriv->ctl_faultstatus = +- debugfs_create_file("fault_status", +- S_IRUSR | S_IRGRP | S_IROTH, +- ctrlpriv->ctl, &perfmon->status, +- &caam_fops_u32_ro); ++ debugfs_create_file("fault_addr", S_IRUSR | S_IRGRP | S_IROTH, ++ ctrlpriv->ctl, &perfmon->faultaddr, ++ &caam_fops_u32_ro); ++ debugfs_create_file("fault_detail", S_IRUSR | S_IRGRP | S_IROTH, ++ ctrlpriv->ctl, &perfmon->faultdetail, ++ &caam_fops_u32_ro); ++ debugfs_create_file("fault_status", S_IRUSR | S_IRGRP | S_IROTH, ++ ctrlpriv->ctl, &perfmon->status, ++ &caam_fops_u32_ro); + + /* Internal covering keys (useful in non-secure mode only) */ +- ctrlpriv->ctl_kek_wrap.data = &ctrlpriv->ctrl->kek[0]; ++ ctrlpriv->ctl_kek_wrap.data = (__force void *)&ctrlpriv->ctrl->kek[0]; + ctrlpriv->ctl_kek_wrap.size = KEK_KEY_SIZE * sizeof(u32); + ctrlpriv->ctl_kek = debugfs_create_blob("kek", + S_IRUSR | +@@ -809,7 +790,7 @@ static int caam_probe(struct platform_device *pdev) + ctrlpriv->ctl, + &ctrlpriv->ctl_kek_wrap); + +- ctrlpriv->ctl_tkek_wrap.data = &ctrlpriv->ctrl->tkek[0]; ++ ctrlpriv->ctl_tkek_wrap.data = (__force void *)&ctrlpriv->ctrl->tkek[0]; + ctrlpriv->ctl_tkek_wrap.size = KEK_KEY_SIZE * sizeof(u32); + ctrlpriv->ctl_tkek = debugfs_create_blob("tkek", + S_IRUSR | +@@ -817,7 +798,7 @@ static int caam_probe(struct platform_device *pdev) + ctrlpriv->ctl, + &ctrlpriv->ctl_tkek_wrap); + +- ctrlpriv->ctl_tdsk_wrap.data = &ctrlpriv->ctrl->tdsk[0]; ++ ctrlpriv->ctl_tdsk_wrap.data = (__force void *)&ctrlpriv->ctrl->tdsk[0]; + ctrlpriv->ctl_tdsk_wrap.size = KEK_KEY_SIZE * sizeof(u32); + ctrlpriv->ctl_tdsk = debugfs_create_blob("tdsk", + S_IRUSR | +@@ -828,13 +809,17 @@ static int caam_probe(struct platform_device *pdev) + return 0; + + caam_remove: ++#ifdef CONFIG_DEBUG_FS ++ debugfs_remove_recursive(ctrlpriv->dfs_root); ++#endif + caam_remove(pdev); + return ret; + + iounmap_ctrl: + iounmap(ctrl); + disable_caam_emi_slow: +- clk_disable_unprepare(ctrlpriv->caam_emi_slow); ++ if (ctrlpriv->caam_emi_slow) ++ clk_disable_unprepare(ctrlpriv->caam_emi_slow); + disable_caam_aclk: + clk_disable_unprepare(ctrlpriv->caam_aclk); + disable_caam_mem: +@@ -844,17 +829,6 @@ static int caam_probe(struct platform_device *pdev) + return ret; + } + +-static struct of_device_id caam_match[] = { +- { +- .compatible = "fsl,sec-v4.0", +- }, +- { +- .compatible = "fsl,sec4.0", +- }, +- {}, +-}; +-MODULE_DEVICE_TABLE(of, caam_match); +- + static struct platform_driver caam_driver = { + .driver = { + .name = "caam", +diff --git a/drivers/crypto/caam/ctrl.h b/drivers/crypto/caam/ctrl.h +index cac5402a..7e7bf68c 100644 +--- a/drivers/crypto/caam/ctrl.h ++++ b/drivers/crypto/caam/ctrl.h +@@ -10,4 +10,6 @@ + /* Prototypes for backend-level services exposed to APIs */ + int caam_get_era(void); + ++extern bool caam_dpaa2; ++ + #endif /* CTRL_H */ +diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h +index 513b6646..6ec6f8c3 100644 +--- a/drivers/crypto/caam/desc.h ++++ b/drivers/crypto/caam/desc.h +@@ -22,12 +22,6 @@ + #define SEC4_SG_LEN_MASK 0x3fffffff /* Excludes EXT and FINAL */ + #define SEC4_SG_OFFSET_MASK 0x00001fff + +-struct sec4_sg_entry { +- u64 ptr; +- u32 len; +- u32 bpid_offset; +-}; +- + /* Max size of any CAAM descriptor in 32-bit words, inclusive of header */ + #define MAX_CAAM_DESCSIZE 64 + +@@ -47,6 +41,7 @@ struct sec4_sg_entry { + #define CMD_SEQ_LOAD (0x03 << CMD_SHIFT) + #define CMD_FIFO_LOAD (0x04 << CMD_SHIFT) + #define CMD_SEQ_FIFO_LOAD (0x05 << CMD_SHIFT) ++#define CMD_MOVEB (0x07 << CMD_SHIFT) + #define CMD_STORE (0x0a << CMD_SHIFT) + #define CMD_SEQ_STORE (0x0b << CMD_SHIFT) + #define CMD_FIFO_STORE (0x0c << CMD_SHIFT) +@@ -90,8 +85,8 @@ struct sec4_sg_entry { + #define HDR_ZRO 0x00008000 + + /* Start Index or SharedDesc Length */ +-#define HDR_START_IDX_MASK 0x3f + #define HDR_START_IDX_SHIFT 16 ++#define HDR_START_IDX_MASK (0x3f << HDR_START_IDX_SHIFT) + + /* If shared descriptor header, 6-bit length */ + #define HDR_DESCLEN_SHR_MASK 0x3f +@@ -121,10 +116,10 @@ struct sec4_sg_entry { + #define HDR_PROP_DNR 0x00000800 + + /* JobDesc/SharedDesc share property */ +-#define HDR_SD_SHARE_MASK 0x03 + #define HDR_SD_SHARE_SHIFT 8 +-#define HDR_JD_SHARE_MASK 0x07 ++#define HDR_SD_SHARE_MASK (0x03 << HDR_SD_SHARE_SHIFT) + #define HDR_JD_SHARE_SHIFT 8 ++#define HDR_JD_SHARE_MASK (0x07 << HDR_JD_SHARE_SHIFT) + + #define HDR_SHARE_NEVER (0x00 << HDR_SD_SHARE_SHIFT) + #define HDR_SHARE_WAIT (0x01 << HDR_SD_SHARE_SHIFT) +@@ -235,7 +230,7 @@ struct sec4_sg_entry { + #define LDST_SRCDST_WORD_DECO_MATH2 (0x0a << LDST_SRCDST_SHIFT) + #define LDST_SRCDST_WORD_DECO_AAD_SZ (0x0b << LDST_SRCDST_SHIFT) + #define LDST_SRCDST_WORD_DECO_MATH3 (0x0b << LDST_SRCDST_SHIFT) +-#define LDST_SRCDST_WORD_CLASS1_ICV_SZ (0x0c << LDST_SRCDST_SHIFT) ++#define LDST_SRCDST_WORD_CLASS1_IV_SZ (0x0c << LDST_SRCDST_SHIFT) + #define LDST_SRCDST_WORD_ALTDS_CLASS1 (0x0f << LDST_SRCDST_SHIFT) + #define LDST_SRCDST_WORD_PKHA_A_SZ (0x10 << LDST_SRCDST_SHIFT) + #define LDST_SRCDST_WORD_PKHA_B_SZ (0x11 << LDST_SRCDST_SHIFT) +@@ -400,7 +395,7 @@ struct sec4_sg_entry { + #define FIFOST_TYPE_PKHA_N (0x08 << FIFOST_TYPE_SHIFT) + #define FIFOST_TYPE_PKHA_A (0x0c << FIFOST_TYPE_SHIFT) + #define FIFOST_TYPE_PKHA_B (0x0d << FIFOST_TYPE_SHIFT) +-#define FIFOST_TYPE_AF_SBOX_JKEK (0x10 << FIFOST_TYPE_SHIFT) ++#define FIFOST_TYPE_AF_SBOX_JKEK (0x20 << FIFOST_TYPE_SHIFT) + #define FIFOST_TYPE_AF_SBOX_TKEK (0x21 << FIFOST_TYPE_SHIFT) + #define FIFOST_TYPE_PKHA_E_JKEK (0x22 << FIFOST_TYPE_SHIFT) + #define FIFOST_TYPE_PKHA_E_TKEK (0x23 << FIFOST_TYPE_SHIFT) +@@ -1107,8 +1102,8 @@ struct sec4_sg_entry { + /* For non-protocol/alg-only op commands */ + #define OP_ALG_TYPE_SHIFT 24 + #define OP_ALG_TYPE_MASK (0x7 << OP_ALG_TYPE_SHIFT) +-#define OP_ALG_TYPE_CLASS1 2 +-#define OP_ALG_TYPE_CLASS2 4 ++#define OP_ALG_TYPE_CLASS1 (2 << OP_ALG_TYPE_SHIFT) ++#define OP_ALG_TYPE_CLASS2 (4 << OP_ALG_TYPE_SHIFT) + + #define OP_ALG_ALGSEL_SHIFT 16 + #define OP_ALG_ALGSEL_MASK (0xff << OP_ALG_ALGSEL_SHIFT) +@@ -1249,7 +1244,7 @@ struct sec4_sg_entry { + #define OP_ALG_PKMODE_MOD_PRIMALITY 0x00f + + /* PKHA mode copy-memory functions */ +-#define OP_ALG_PKMODE_SRC_REG_SHIFT 13 ++#define OP_ALG_PKMODE_SRC_REG_SHIFT 17 + #define OP_ALG_PKMODE_SRC_REG_MASK (7 << OP_ALG_PKMODE_SRC_REG_SHIFT) + #define OP_ALG_PKMODE_DST_REG_SHIFT 10 + #define OP_ALG_PKMODE_DST_REG_MASK (7 << OP_ALG_PKMODE_DST_REG_SHIFT) +@@ -1445,7 +1440,7 @@ struct sec4_sg_entry { + #define MATH_SRC1_REG2 (0x02 << MATH_SRC1_SHIFT) + #define MATH_SRC1_REG3 (0x03 << MATH_SRC1_SHIFT) + #define MATH_SRC1_IMM (0x04 << MATH_SRC1_SHIFT) +-#define MATH_SRC1_DPOVRD (0x07 << MATH_SRC0_SHIFT) ++#define MATH_SRC1_DPOVRD (0x07 << MATH_SRC1_SHIFT) + #define MATH_SRC1_INFIFO (0x0a << MATH_SRC1_SHIFT) + #define MATH_SRC1_OUTFIFO (0x0b << MATH_SRC1_SHIFT) + #define MATH_SRC1_ONE (0x0c << MATH_SRC1_SHIFT) +@@ -1629,4 +1624,31 @@ struct sec4_sg_entry { + /* Frame Descriptor Command for Replacement Job Descriptor */ + #define FD_CMD_REPLACE_JOB_DESC 0x20000000 + ++/* CHA Control Register bits */ ++#define CCTRL_RESET_CHA_ALL 0x1 ++#define CCTRL_RESET_CHA_AESA 0x2 ++#define CCTRL_RESET_CHA_DESA 0x4 ++#define CCTRL_RESET_CHA_AFHA 0x8 ++#define CCTRL_RESET_CHA_KFHA 0x10 ++#define CCTRL_RESET_CHA_SF8A 0x20 ++#define CCTRL_RESET_CHA_PKHA 0x40 ++#define CCTRL_RESET_CHA_MDHA 0x80 ++#define CCTRL_RESET_CHA_CRCA 0x100 ++#define CCTRL_RESET_CHA_RNG 0x200 ++#define CCTRL_RESET_CHA_SF9A 0x400 ++#define CCTRL_RESET_CHA_ZUCE 0x800 ++#define CCTRL_RESET_CHA_ZUCA 0x1000 ++#define CCTRL_UNLOAD_PK_A0 0x10000 ++#define CCTRL_UNLOAD_PK_A1 0x20000 ++#define CCTRL_UNLOAD_PK_A2 0x40000 ++#define CCTRL_UNLOAD_PK_A3 0x80000 ++#define CCTRL_UNLOAD_PK_B0 0x100000 ++#define CCTRL_UNLOAD_PK_B1 0x200000 ++#define CCTRL_UNLOAD_PK_B2 0x400000 ++#define CCTRL_UNLOAD_PK_B3 0x800000 ++#define CCTRL_UNLOAD_PK_N 0x1000000 ++#define CCTRL_UNLOAD_PK_A 0x4000000 ++#define CCTRL_UNLOAD_PK_B 0x8000000 ++#define CCTRL_UNLOAD_SBOX 0x10000000 ++ + #endif /* DESC_H */ +diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h +index a8cd8a78..2d9dbeca 100644 +--- a/drivers/crypto/caam/desc_constr.h ++++ b/drivers/crypto/caam/desc_constr.h +@@ -4,6 +4,9 @@ + * Copyright 2008-2012 Freescale Semiconductor, Inc. + */ + ++#ifndef DESC_CONSTR_H ++#define DESC_CONSTR_H ++ + #include "desc.h" + #include "regs.h" + +@@ -33,38 +36,39 @@ + + extern bool caam_little_end; + +-static inline int desc_len(u32 *desc) ++static inline int desc_len(u32 * const desc) + { + return caam32_to_cpu(*desc) & HDR_DESCLEN_MASK; + } + +-static inline int desc_bytes(void *desc) ++static inline int desc_bytes(void * const desc) + { + return desc_len(desc) * CAAM_CMD_SZ; + } + +-static inline u32 *desc_end(u32 *desc) ++static inline u32 *desc_end(u32 * const desc) + { + return desc + desc_len(desc); + } + +-static inline void *sh_desc_pdb(u32 *desc) ++static inline void *sh_desc_pdb(u32 * const desc) + { + return desc + 1; + } + +-static inline void init_desc(u32 *desc, u32 options) ++static inline void init_desc(u32 * const desc, u32 options) + { + *desc = cpu_to_caam32((options | HDR_ONE) + 1); + } + +-static inline void init_sh_desc(u32 *desc, u32 options) ++static inline void init_sh_desc(u32 * const desc, u32 options) + { + PRINT_POS; + init_desc(desc, CMD_SHARED_DESC_HDR | options); + } + +-static inline void init_sh_desc_pdb(u32 *desc, u32 options, size_t pdb_bytes) ++static inline void init_sh_desc_pdb(u32 * const desc, u32 options, ++ size_t pdb_bytes) + { + u32 pdb_len = (pdb_bytes + CAAM_CMD_SZ - 1) / CAAM_CMD_SZ; + +@@ -72,19 +76,20 @@ static inline void init_sh_desc_pdb(u32 *desc, u32 options, size_t pdb_bytes) + options); + } + +-static inline void init_job_desc(u32 *desc, u32 options) ++static inline void init_job_desc(u32 * const desc, u32 options) + { + init_desc(desc, CMD_DESC_HDR | options); + } + +-static inline void init_job_desc_pdb(u32 *desc, u32 options, size_t pdb_bytes) ++static inline void init_job_desc_pdb(u32 * const desc, u32 options, ++ size_t pdb_bytes) + { + u32 pdb_len = (pdb_bytes + CAAM_CMD_SZ - 1) / CAAM_CMD_SZ; + + init_job_desc(desc, (((pdb_len + 1) << HDR_START_IDX_SHIFT)) | options); + } + +-static inline void append_ptr(u32 *desc, dma_addr_t ptr) ++static inline void append_ptr(u32 * const desc, dma_addr_t ptr) + { + dma_addr_t *offset = (dma_addr_t *)desc_end(desc); + +@@ -94,8 +99,8 @@ static inline void append_ptr(u32 *desc, dma_addr_t ptr) + CAAM_PTR_SZ / CAAM_CMD_SZ); + } + +-static inline void init_job_desc_shared(u32 *desc, dma_addr_t ptr, int len, +- u32 options) ++static inline void init_job_desc_shared(u32 * const desc, dma_addr_t ptr, ++ int len, u32 options) + { + PRINT_POS; + init_job_desc(desc, HDR_SHARED | options | +@@ -103,7 +108,7 @@ static inline void init_job_desc_shared(u32 *desc, dma_addr_t ptr, int len, + append_ptr(desc, ptr); + } + +-static inline void append_data(u32 *desc, void *data, int len) ++static inline void append_data(u32 * const desc, void *data, int len) + { + u32 *offset = desc_end(desc); + +@@ -114,7 +119,7 @@ static inline void append_data(u32 *desc, void *data, int len) + (len + CAAM_CMD_SZ - 1) / CAAM_CMD_SZ); + } + +-static inline void append_cmd(u32 *desc, u32 command) ++static inline void append_cmd(u32 * const desc, u32 command) + { + u32 *cmd = desc_end(desc); + +@@ -125,7 +130,7 @@ static inline void append_cmd(u32 *desc, u32 command) + + #define append_u32 append_cmd + +-static inline void append_u64(u32 *desc, u64 data) ++static inline void append_u64(u32 * const desc, u64 data) + { + u32 *offset = desc_end(desc); + +@@ -142,14 +147,14 @@ static inline void append_u64(u32 *desc, u64 data) + } + + /* Write command without affecting header, and return pointer to next word */ +-static inline u32 *write_cmd(u32 *desc, u32 command) ++static inline u32 *write_cmd(u32 * const desc, u32 command) + { + *desc = cpu_to_caam32(command); + + return desc + 1; + } + +-static inline void append_cmd_ptr(u32 *desc, dma_addr_t ptr, int len, ++static inline void append_cmd_ptr(u32 * const desc, dma_addr_t ptr, int len, + u32 command) + { + append_cmd(desc, command | len); +@@ -157,7 +162,7 @@ static inline void append_cmd_ptr(u32 *desc, dma_addr_t ptr, int len, + } + + /* Write length after pointer, rather than inside command */ +-static inline void append_cmd_ptr_extlen(u32 *desc, dma_addr_t ptr, ++static inline void append_cmd_ptr_extlen(u32 * const desc, dma_addr_t ptr, + unsigned int len, u32 command) + { + append_cmd(desc, command); +@@ -166,7 +171,7 @@ static inline void append_cmd_ptr_extlen(u32 *desc, dma_addr_t ptr, + append_cmd(desc, len); + } + +-static inline void append_cmd_data(u32 *desc, void *data, int len, ++static inline void append_cmd_data(u32 * const desc, void *data, int len, + u32 command) + { + append_cmd(desc, command | IMMEDIATE | len); +@@ -174,7 +179,7 @@ static inline void append_cmd_data(u32 *desc, void *data, int len, + } + + #define APPEND_CMD_RET(cmd, op) \ +-static inline u32 *append_##cmd(u32 *desc, u32 options) \ ++static inline u32 *append_##cmd(u32 * const desc, u32 options) \ + { \ + u32 *cmd = desc_end(desc); \ + PRINT_POS; \ +@@ -183,14 +188,15 @@ static inline u32 *append_##cmd(u32 *desc, u32 options) \ + } + APPEND_CMD_RET(jump, JUMP) + APPEND_CMD_RET(move, MOVE) ++APPEND_CMD_RET(moveb, MOVEB) + +-static inline void set_jump_tgt_here(u32 *desc, u32 *jump_cmd) ++static inline void set_jump_tgt_here(u32 * const desc, u32 *jump_cmd) + { + *jump_cmd = cpu_to_caam32(caam32_to_cpu(*jump_cmd) | + (desc_len(desc) - (jump_cmd - desc))); + } + +-static inline void set_move_tgt_here(u32 *desc, u32 *move_cmd) ++static inline void set_move_tgt_here(u32 * const desc, u32 *move_cmd) + { + u32 val = caam32_to_cpu(*move_cmd); + +@@ -200,7 +206,7 @@ static inline void set_move_tgt_here(u32 *desc, u32 *move_cmd) + } + + #define APPEND_CMD(cmd, op) \ +-static inline void append_##cmd(u32 *desc, u32 options) \ ++static inline void append_##cmd(u32 * const desc, u32 options) \ + { \ + PRINT_POS; \ + append_cmd(desc, CMD_##op | options); \ +@@ -208,7 +214,8 @@ static inline void append_##cmd(u32 *desc, u32 options) \ + APPEND_CMD(operation, OPERATION) + + #define APPEND_CMD_LEN(cmd, op) \ +-static inline void append_##cmd(u32 *desc, unsigned int len, u32 options) \ ++static inline void append_##cmd(u32 * const desc, unsigned int len, \ ++ u32 options) \ + { \ + PRINT_POS; \ + append_cmd(desc, CMD_##op | len | options); \ +@@ -220,8 +227,8 @@ APPEND_CMD_LEN(seq_fifo_load, SEQ_FIFO_LOAD) + APPEND_CMD_LEN(seq_fifo_store, SEQ_FIFO_STORE) + + #define APPEND_CMD_PTR(cmd, op) \ +-static inline void append_##cmd(u32 *desc, dma_addr_t ptr, unsigned int len, \ +- u32 options) \ ++static inline void append_##cmd(u32 * const desc, dma_addr_t ptr, \ ++ unsigned int len, u32 options) \ + { \ + PRINT_POS; \ + append_cmd_ptr(desc, ptr, len, CMD_##op | options); \ +@@ -231,8 +238,8 @@ APPEND_CMD_PTR(load, LOAD) + APPEND_CMD_PTR(fifo_load, FIFO_LOAD) + APPEND_CMD_PTR(fifo_store, FIFO_STORE) + +-static inline void append_store(u32 *desc, dma_addr_t ptr, unsigned int len, +- u32 options) ++static inline void append_store(u32 * const desc, dma_addr_t ptr, ++ unsigned int len, u32 options) + { + u32 cmd_src; + +@@ -249,7 +256,8 @@ static inline void append_store(u32 *desc, dma_addr_t ptr, unsigned int len, + } + + #define APPEND_SEQ_PTR_INTLEN(cmd, op) \ +-static inline void append_seq_##cmd##_ptr_intlen(u32 *desc, dma_addr_t ptr, \ ++static inline void append_seq_##cmd##_ptr_intlen(u32 * const desc, \ ++ dma_addr_t ptr, \ + unsigned int len, \ + u32 options) \ + { \ +@@ -263,7 +271,7 @@ APPEND_SEQ_PTR_INTLEN(in, IN) + APPEND_SEQ_PTR_INTLEN(out, OUT) + + #define APPEND_CMD_PTR_TO_IMM(cmd, op) \ +-static inline void append_##cmd##_as_imm(u32 *desc, void *data, \ ++static inline void append_##cmd##_as_imm(u32 * const desc, void *data, \ + unsigned int len, u32 options) \ + { \ + PRINT_POS; \ +@@ -273,7 +281,7 @@ APPEND_CMD_PTR_TO_IMM(load, LOAD); + APPEND_CMD_PTR_TO_IMM(fifo_load, FIFO_LOAD); + + #define APPEND_CMD_PTR_EXTLEN(cmd, op) \ +-static inline void append_##cmd##_extlen(u32 *desc, dma_addr_t ptr, \ ++static inline void append_##cmd##_extlen(u32 * const desc, dma_addr_t ptr, \ + unsigned int len, u32 options) \ + { \ + PRINT_POS; \ +@@ -287,7 +295,7 @@ APPEND_CMD_PTR_EXTLEN(seq_out_ptr, SEQ_OUT_PTR) + * the size of its type + */ + #define APPEND_CMD_PTR_LEN(cmd, op, type) \ +-static inline void append_##cmd(u32 *desc, dma_addr_t ptr, \ ++static inline void append_##cmd(u32 * const desc, dma_addr_t ptr, \ + type len, u32 options) \ + { \ + PRINT_POS; \ +@@ -304,7 +312,7 @@ APPEND_CMD_PTR_LEN(seq_out_ptr, SEQ_OUT_PTR, u32) + * from length of immediate data provided, e.g., split keys + */ + #define APPEND_CMD_PTR_TO_IMM2(cmd, op) \ +-static inline void append_##cmd##_as_imm(u32 *desc, void *data, \ ++static inline void append_##cmd##_as_imm(u32 * const desc, void *data, \ + unsigned int data_len, \ + unsigned int len, u32 options) \ + { \ +@@ -315,7 +323,7 @@ static inline void append_##cmd##_as_imm(u32 *desc, void *data, \ + APPEND_CMD_PTR_TO_IMM2(key, KEY); + + #define APPEND_CMD_RAW_IMM(cmd, op, type) \ +-static inline void append_##cmd##_imm_##type(u32 *desc, type immediate, \ ++static inline void append_##cmd##_imm_##type(u32 * const desc, type immediate, \ + u32 options) \ + { \ + PRINT_POS; \ +@@ -426,3 +434,66 @@ do { \ + APPEND_MATH_IMM_u64(LSHIFT, desc, dest, src0, src1, data) + #define append_math_rshift_imm_u64(desc, dest, src0, src1, data) \ + APPEND_MATH_IMM_u64(RSHIFT, desc, dest, src0, src1, data) ++ ++/** ++ * struct alginfo - Container for algorithm details ++ * @algtype: algorithm selector; for valid values, see documentation of the ++ * functions where it is used. ++ * @keylen: length of the provided algorithm key, in bytes ++ * @keylen_pad: padded length of the provided algorithm key, in bytes ++ * @key: address where algorithm key resides; virtual address if key_inline ++ * is true, dma (bus) address if key_inline is false. ++ * @key_inline: true - key can be inlined in the descriptor; false - key is ++ * referenced by the descriptor ++ */ ++struct alginfo { ++ u32 algtype; ++ unsigned int keylen; ++ unsigned int keylen_pad; ++ union { ++ dma_addr_t key_dma; ++ void *key_virt; ++ }; ++ bool key_inline; ++}; ++ ++/** ++ * desc_inline_query() - Provide indications on which data items can be inlined ++ * and which shall be referenced in a shared descriptor. ++ * @sd_base_len: Shared descriptor base length - bytes consumed by the commands, ++ * excluding the data items to be inlined (or corresponding ++ * pointer if an item is not inlined). Each cnstr_* function that ++ * generates descriptors should have a define mentioning ++ * corresponding length. ++ * @jd_len: Maximum length of the job descriptor(s) that will be used ++ * together with the shared descriptor. ++ * @data_len: Array of lengths of the data items trying to be inlined ++ * @inl_mask: 32bit mask with bit x = 1 if data item x can be inlined, 0 ++ * otherwise. ++ * @count: Number of data items (size of @data_len array); must be <= 32 ++ * ++ * Return: 0 if data can be inlined / referenced, negative value if not. If 0, ++ * check @inl_mask for details. ++ */ ++static inline int desc_inline_query(unsigned int sd_base_len, ++ unsigned int jd_len, unsigned int *data_len, ++ u32 *inl_mask, unsigned int count) ++{ ++ int rem_bytes = (int)(CAAM_DESC_BYTES_MAX - sd_base_len - jd_len); ++ unsigned int i; ++ ++ *inl_mask = 0; ++ for (i = 0; (i < count) && (rem_bytes > 0); i++) { ++ if (rem_bytes - (int)(data_len[i] + ++ (count - i - 1) * CAAM_PTR_SZ) >= 0) { ++ rem_bytes -= data_len[i]; ++ *inl_mask |= (1 << i); ++ } else { ++ rem_bytes -= CAAM_PTR_SZ; ++ } ++ } ++ ++ return (rem_bytes >= 0) ? 0 : -1; ++} ++ ++#endif /* DESC_CONSTR_H */ +diff --git a/drivers/crypto/caam/dpseci.c b/drivers/crypto/caam/dpseci.c +new file mode 100644 +index 00000000..410cd790 +--- /dev/null ++++ b/drivers/crypto/caam/dpseci.c +@@ -0,0 +1,859 @@ ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. ++ * Copyright 2017 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the names of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#include "../../../drivers/staging/fsl-mc/include/mc-sys.h" ++#include "../../../drivers/staging/fsl-mc/include/mc-cmd.h" ++#include "../../../drivers/staging/fsl-mc/include/dpopr.h" ++#include "dpseci.h" ++#include "dpseci_cmd.h" ++ ++/** ++ * dpseci_open() - Open a control session for the specified object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @dpseci_id: DPSECI unique ID ++ * @token: Returned token; use in subsequent API calls ++ * ++ * This function can be used to open a control session for an already created ++ * object; an object may have been declared in the DPL or by calling the ++ * dpseci_create() function. ++ * This function returns a unique authentication token, associated with the ++ * specific object ID and the specific MC portal; this token must be used in all ++ * subsequent commands for this specific object. ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int dpseci_id, ++ u16 *token) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_cmd_open *cmd_params; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_OPEN, ++ cmd_flags, ++ 0); ++ cmd_params = (struct dpseci_cmd_open *)cmd.params; ++ cmd_params->dpseci_id = cpu_to_le32(dpseci_id); ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ *token = mc_cmd_hdr_read_token(&cmd); ++ ++ return 0; ++} ++ ++/** ++ * dpseci_close() - Close the control session of the object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * ++ * After this function is called, no further operations are allowed on the ++ * object without opening a new control session. ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_CLOSE, ++ cmd_flags, ++ token); ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpseci_create() - Create the DPSECI object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @dprc_token: Parent container token; '0' for default container ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @cfg: Configuration structure ++ * @obj_id: returned object id ++ * ++ * Create the DPSECI object, allocate required resources and perform required ++ * initialization. ++ * ++ * The object can be created either by declaring it in the DPL file, or by ++ * calling this function. ++ * ++ * The function accepts an authentication token of a parent container that this ++ * object should be assigned to. The token can be '0' so the object will be ++ * assigned to the default container. ++ * The newly created object can be opened with the returned object id and using ++ * the container's associated tokens and MC portals. ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_create(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags, ++ const struct dpseci_cfg *cfg, u32 *obj_id) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_cmd_create *cmd_params; ++ int i, err; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_CREATE, ++ cmd_flags, ++ dprc_token); ++ cmd_params = (struct dpseci_cmd_create *)cmd.params; ++ for (i = 0; i < 8; i++) ++ cmd_params->priorities[i] = cfg->priorities[i]; ++ cmd_params->num_tx_queues = cfg->num_tx_queues; ++ cmd_params->num_rx_queues = cfg->num_rx_queues; ++ cmd_params->options = cpu_to_le32(cfg->options); ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ *obj_id = mc_cmd_read_object_id(&cmd); ++ ++ return 0; ++} ++ ++/** ++ * dpseci_destroy() - Destroy the DPSECI object and release all its resources ++ * @mc_io: Pointer to MC portal's I/O object ++ * @dprc_token: Parent container token; '0' for default container ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @object_id: The object id; it must be a valid id within the container that ++ * created this object ++ * ++ * The function accepts the authentication token of the parent container that ++ * created the object (not the one that currently owns the object). The object ++ * is searched within parent using the provided 'object_id'. ++ * All tokens to the object must be closed before calling destroy. ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_destroy(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags, ++ u32 object_id) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_cmd_destroy *cmd_params; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_DESTROY, ++ cmd_flags, ++ dprc_token); ++ cmd_params = (struct dpseci_cmd_destroy *)cmd.params; ++ cmd_params->object_id = cpu_to_le32(object_id); ++ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpseci_enable() - Enable the DPSECI, allow sending and receiving frames ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_ENABLE, ++ cmd_flags, ++ token); ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpseci_disable() - Disable the DPSECI, stop sending and receiving frames ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_DISABLE, ++ cmd_flags, ++ token); ++ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpseci_is_enabled() - Check if the DPSECI is enabled. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * @en: Returns '1' if object is enabled; '0' otherwise ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_is_enabled(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ int *en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_rsp_is_enabled *rsp_params; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_IS_ENABLED, ++ cmd_flags, ++ token); ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ rsp_params = (struct dpseci_rsp_is_enabled *)cmd.params; ++ *en = le32_to_cpu(rsp_params->is_enabled); ++ ++ return 0; ++} ++ ++/** ++ * dpseci_reset() - Reset the DPSECI, returns the object to initial state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_RESET, ++ cmd_flags, ++ token); ++ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpseci_get_irq_enable() - Get overall interrupt state ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * @irq_index: The interrupt index to configure ++ * @en: Returned Interrupt state - enable = 1, disable = 0 ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_get_irq_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 irq_index, u8 *en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_cmd_irq_enable *cmd_params; ++ struct dpseci_rsp_get_irq_enable *rsp_params; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_IRQ_ENABLE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpseci_cmd_irq_enable *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ rsp_params = (struct dpseci_rsp_get_irq_enable *)cmd.params; ++ *en = rsp_params->enable_state; ++ ++ return 0; ++} ++ ++/** ++ * dpseci_set_irq_enable() - Set overall interrupt state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * @irq_index: The interrupt index to configure ++ * @en: Interrupt state - enable = 1, disable = 0 ++ * ++ * Allows GPP software to control when interrupts are generated. ++ * Each interrupt can have up to 32 causes. The enable/disable control's the ++ * overall interrupt state. If the interrupt is disabled no causes will cause ++ * an interrupt. ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_set_irq_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 irq_index, u8 en) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_cmd_irq_enable *cmd_params; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_SET_IRQ_ENABLE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpseci_cmd_irq_enable *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ cmd_params->enable_state = en; ++ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpseci_get_irq_mask() - Get interrupt mask. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * @irq_index: The interrupt index to configure ++ * @mask: Returned event mask to trigger interrupt ++ * ++ * Every interrupt can have up to 32 causes and the interrupt model supports ++ * masking/unmasking each cause independently. ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_get_irq_mask(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 irq_index, u32 *mask) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_cmd_irq_mask *cmd_params; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_IRQ_MASK, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpseci_cmd_irq_mask *)cmd.params; ++ cmd_params->irq_index = irq_index; ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ *mask = le32_to_cpu(cmd_params->mask); ++ ++ return 0; ++} ++ ++/** ++ * dpseci_set_irq_mask() - Set interrupt mask. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * @irq_index: The interrupt index to configure ++ * @mask: event mask to trigger interrupt; ++ * each bit: ++ * 0 = ignore event ++ * 1 = consider event for asserting IRQ ++ * ++ * Every interrupt can have up to 32 causes and the interrupt model supports ++ * masking/unmasking each cause independently ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_set_irq_mask(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 irq_index, u32 mask) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_cmd_irq_mask *cmd_params; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_SET_IRQ_MASK, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpseci_cmd_irq_mask *)cmd.params; ++ cmd_params->mask = cpu_to_le32(mask); ++ cmd_params->irq_index = irq_index; ++ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpseci_get_irq_status() - Get the current status of any pending interrupts ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * @irq_index: The interrupt index to configure ++ * @status: Returned interrupts status - one bit per cause: ++ * 0 = no interrupt pending ++ * 1 = interrupt pending ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_get_irq_status(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 irq_index, u32 *status) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_cmd_irq_status *cmd_params; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_IRQ_STATUS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpseci_cmd_irq_status *)cmd.params; ++ cmd_params->status = cpu_to_le32(*status); ++ cmd_params->irq_index = irq_index; ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ *status = le32_to_cpu(cmd_params->status); ++ ++ return 0; ++} ++ ++/** ++ * dpseci_clear_irq_status() - Clear a pending interrupt's status ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * @irq_index: The interrupt index to configure ++ * @status: bits to clear (W1C) - one bit per cause: ++ * 0 = don't change ++ * 1 = clear status bit ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_clear_irq_status(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 irq_index, u32 status) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_cmd_irq_status *cmd_params; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_CLEAR_IRQ_STATUS, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpseci_cmd_irq_status *)cmd.params; ++ cmd_params->status = cpu_to_le32(status); ++ cmd_params->irq_index = irq_index; ++ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpseci_get_attributes() - Retrieve DPSECI attributes ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * @attr: Returned object's attributes ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ struct dpseci_attr *attr) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_rsp_get_attributes *rsp_params; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_ATTR, ++ cmd_flags, ++ token); ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ rsp_params = (struct dpseci_rsp_get_attributes *)cmd.params; ++ attr->id = le32_to_cpu(rsp_params->id); ++ attr->num_tx_queues = rsp_params->num_tx_queues; ++ attr->num_rx_queues = rsp_params->num_rx_queues; ++ attr->options = le32_to_cpu(rsp_params->options); ++ ++ return 0; ++} ++ ++/** ++ * dpseci_set_rx_queue() - Set Rx queue configuration ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * @queue: Select the queue relative to number of priorities configured at ++ * DPSECI creation; use DPSECI_ALL_QUEUES to configure all ++ * Rx queues identically. ++ * @cfg: Rx queue configuration ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_set_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 queue, const struct dpseci_rx_queue_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_cmd_queue *cmd_params; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_SET_RX_QUEUE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpseci_cmd_queue *)cmd.params; ++ cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id); ++ cmd_params->priority = cfg->dest_cfg.priority; ++ cmd_params->queue = queue; ++ cmd_params->dest_type = cfg->dest_cfg.dest_type; ++ cmd_params->user_ctx = cpu_to_le64(cfg->user_ctx); ++ cmd_params->options = cpu_to_le32(cfg->options); ++ cmd_params->order_preservation_en = ++ cpu_to_le32(cfg->order_preservation_en); ++ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpseci_get_rx_queue() - Retrieve Rx queue attributes ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * @queue: Select the queue relative to number of priorities configured at ++ * DPSECI creation ++ * @attr: Returned Rx queue attributes ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_get_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 queue, struct dpseci_rx_queue_attr *attr) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_cmd_queue *cmd_params; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_RX_QUEUE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpseci_cmd_queue *)cmd.params; ++ cmd_params->queue = queue; ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ attr->dest_cfg.dest_id = le32_to_cpu(cmd_params->dest_id); ++ attr->dest_cfg.priority = cmd_params->priority; ++ attr->dest_cfg.dest_type = cmd_params->dest_type; ++ attr->user_ctx = le64_to_cpu(cmd_params->user_ctx); ++ attr->fqid = le32_to_cpu(cmd_params->fqid); ++ attr->order_preservation_en = ++ le32_to_cpu(cmd_params->order_preservation_en); ++ ++ return 0; ++} ++ ++/** ++ * dpseci_get_tx_queue() - Retrieve Tx queue attributes ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * @queue: Select the queue relative to number of priorities configured at ++ * DPSECI creation ++ * @attr: Returned Tx queue attributes ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_get_tx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 queue, struct dpseci_tx_queue_attr *attr) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_cmd_queue *cmd_params; ++ struct dpseci_rsp_get_tx_queue *rsp_params; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_TX_QUEUE, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpseci_cmd_queue *)cmd.params; ++ cmd_params->queue = queue; ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ rsp_params = (struct dpseci_rsp_get_tx_queue *)cmd.params; ++ attr->fqid = le32_to_cpu(rsp_params->fqid); ++ attr->priority = rsp_params->priority; ++ ++ return 0; ++} ++ ++/** ++ * dpseci_get_sec_attr() - Retrieve SEC accelerator attributes ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * @attr: Returned SEC attributes ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_get_sec_attr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ struct dpseci_sec_attr *attr) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_rsp_get_sec_attr *rsp_params; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_SEC_ATTR, ++ cmd_flags, ++ token); ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ rsp_params = (struct dpseci_rsp_get_sec_attr *)cmd.params; ++ attr->ip_id = le16_to_cpu(rsp_params->ip_id); ++ attr->major_rev = rsp_params->major_rev; ++ attr->minor_rev = rsp_params->minor_rev; ++ attr->era = rsp_params->era; ++ attr->deco_num = rsp_params->deco_num; ++ attr->zuc_auth_acc_num = rsp_params->zuc_auth_acc_num; ++ attr->zuc_enc_acc_num = rsp_params->zuc_enc_acc_num; ++ attr->snow_f8_acc_num = rsp_params->snow_f8_acc_num; ++ attr->snow_f9_acc_num = rsp_params->snow_f9_acc_num; ++ attr->crc_acc_num = rsp_params->crc_acc_num; ++ attr->pk_acc_num = rsp_params->pk_acc_num; ++ attr->kasumi_acc_num = rsp_params->kasumi_acc_num; ++ attr->rng_acc_num = rsp_params->rng_acc_num; ++ attr->md_acc_num = rsp_params->md_acc_num; ++ attr->arc4_acc_num = rsp_params->arc4_acc_num; ++ attr->des_acc_num = rsp_params->des_acc_num; ++ attr->aes_acc_num = rsp_params->aes_acc_num; ++ ++ return 0; ++} ++ ++/** ++ * dpseci_get_sec_counters() - Retrieve SEC accelerator counters ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * @counters: Returned SEC counters ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_get_sec_counters(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ struct dpseci_sec_counters *counters) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_rsp_get_sec_counters *rsp_params; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_SEC_COUNTERS, ++ cmd_flags, ++ token); ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ rsp_params = (struct dpseci_rsp_get_sec_counters *)cmd.params; ++ counters->dequeued_requests = ++ le64_to_cpu(rsp_params->dequeued_requests); ++ counters->ob_enc_requests = le64_to_cpu(rsp_params->ob_enc_requests); ++ counters->ib_dec_requests = le64_to_cpu(rsp_params->ib_dec_requests); ++ counters->ob_enc_bytes = le64_to_cpu(rsp_params->ob_enc_bytes); ++ counters->ob_prot_bytes = le64_to_cpu(rsp_params->ob_prot_bytes); ++ counters->ib_dec_bytes = le64_to_cpu(rsp_params->ib_dec_bytes); ++ counters->ib_valid_bytes = le64_to_cpu(rsp_params->ib_valid_bytes); ++ ++ return 0; ++} ++ ++/** ++ * dpseci_get_api_version() - Get Data Path SEC Interface API version ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @major_ver: Major version of data path sec API ++ * @minor_ver: Minor version of data path sec API ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_get_api_version(struct fsl_mc_io *mc_io, u32 cmd_flags, ++ u16 *major_ver, u16 *minor_ver) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_rsp_get_api_version *rsp_params; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_API_VERSION, ++ cmd_flags, 0); ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ rsp_params = (struct dpseci_rsp_get_api_version *)cmd.params; ++ *major_ver = le16_to_cpu(rsp_params->major); ++ *minor_ver = le16_to_cpu(rsp_params->minor); ++ ++ return 0; ++} ++ ++/** ++ * dpseci_set_opr() - Set Order Restoration configuration ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * @index: The queue index ++ * @options: Configuration mode options; can be OPR_OPT_CREATE or ++ * OPR_OPT_RETIRE ++ * @cfg: Configuration options for the OPR ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_set_opr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u8 index, ++ u8 options, struct opr_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_cmd_opr *cmd_params; ++ ++ cmd.header = mc_encode_cmd_header( ++ DPSECI_CMDID_SET_OPR, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpseci_cmd_opr *)cmd.params; ++ cmd_params->index = index; ++ cmd_params->options = options; ++ cmd_params->oloe = cfg->oloe; ++ cmd_params->oeane = cfg->oeane; ++ cmd_params->olws = cfg->olws; ++ cmd_params->oa = cfg->oa; ++ cmd_params->oprrws = cfg->oprrws; ++ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpseci_get_opr() - Retrieve Order Restoration config and query ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * @index: The queue index ++ * @cfg: Returned OPR configuration ++ * @qry: Returned OPR query ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_get_opr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u8 index, ++ struct opr_cfg *cfg, struct opr_qry *qry) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_cmd_opr *cmd_params; ++ struct dpseci_rsp_get_opr *rsp_params; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header(DPSECI_CMDID_GET_OPR, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpseci_cmd_opr *)cmd.params; ++ cmd_params->index = index; ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ rsp_params = (struct dpseci_rsp_get_opr *)cmd.params; ++ qry->rip = dpseci_get_field(rsp_params->rip_enable, OPR_RIP); ++ qry->enable = dpseci_get_field(rsp_params->rip_enable, OPR_ENABLE); ++ cfg->oloe = rsp_params->oloe; ++ cfg->oeane = rsp_params->oeane; ++ cfg->olws = rsp_params->olws; ++ cfg->oa = rsp_params->oa; ++ cfg->oprrws = rsp_params->oprrws; ++ qry->nesn = le16_to_cpu(rsp_params->nesn); ++ qry->ndsn = le16_to_cpu(rsp_params->ndsn); ++ qry->ea_tseq = le16_to_cpu(rsp_params->ea_tseq); ++ qry->tseq_nlis = dpseci_get_field(rsp_params->tseq_nlis, OPR_TSEQ_NLIS); ++ qry->ea_hseq = le16_to_cpu(rsp_params->ea_hseq); ++ qry->hseq_nlis = dpseci_get_field(rsp_params->tseq_nlis, OPR_HSEQ_NLIS); ++ qry->ea_hptr = le16_to_cpu(rsp_params->ea_hptr); ++ qry->ea_tptr = le16_to_cpu(rsp_params->ea_tptr); ++ qry->opr_vid = le16_to_cpu(rsp_params->opr_vid); ++ qry->opr_id = le16_to_cpu(rsp_params->opr_id); ++ ++ return 0; ++} ++ ++/** ++ * dpseci_set_congestion_notification() - Set congestion group ++ * notification configuration ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * @cfg: congestion notification configuration ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_set_congestion_notification(struct fsl_mc_io *mc_io, u32 cmd_flags, ++ u16 token, const struct dpseci_congestion_notification_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_cmd_congestion_notification *cmd_params; ++ ++ cmd.header = mc_encode_cmd_header( ++ DPSECI_CMDID_SET_CONGESTION_NOTIFICATION, ++ cmd_flags, ++ token); ++ cmd_params = (struct dpseci_cmd_congestion_notification *)cmd.params; ++ cmd_params->dest_id = cpu_to_le32(cfg->dest_cfg.dest_id); ++ cmd_params->notification_mode = cpu_to_le16(cfg->notification_mode); ++ cmd_params->priority = cfg->dest_cfg.priority; ++ dpseci_set_field(cmd_params->options, CGN_DEST_TYPE, ++ cfg->dest_cfg.dest_type); ++ dpseci_set_field(cmd_params->options, CGN_UNITS, cfg->units); ++ cmd_params->message_iova = cpu_to_le64(cfg->message_iova); ++ cmd_params->message_ctx = cpu_to_le64(cfg->message_ctx); ++ cmd_params->threshold_entry = cpu_to_le32(cfg->threshold_entry); ++ cmd_params->threshold_exit = cpu_to_le32(cfg->threshold_exit); ++ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++/** ++ * dpseci_get_congestion_notification() - Get congestion group notification ++ * configuration ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPSECI object ++ * @cfg: congestion notification configuration ++ * ++ * Return: '0' on success, error code otherwise ++ */ ++int dpseci_get_congestion_notification(struct fsl_mc_io *mc_io, u32 cmd_flags, ++ u16 token, struct dpseci_congestion_notification_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ struct dpseci_cmd_congestion_notification *rsp_params; ++ int err; ++ ++ cmd.header = mc_encode_cmd_header( ++ DPSECI_CMDID_GET_CONGESTION_NOTIFICATION, ++ cmd_flags, ++ token); ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ rsp_params = (struct dpseci_cmd_congestion_notification *)cmd.params; ++ cfg->dest_cfg.dest_id = le32_to_cpu(rsp_params->dest_id); ++ cfg->notification_mode = le16_to_cpu(rsp_params->notification_mode); ++ cfg->dest_cfg.priority = rsp_params->priority; ++ cfg->dest_cfg.dest_type = dpseci_get_field(rsp_params->options, ++ CGN_DEST_TYPE); ++ cfg->units = dpseci_get_field(rsp_params->options, CGN_UNITS); ++ cfg->message_iova = le64_to_cpu(rsp_params->message_iova); ++ cfg->message_ctx = le64_to_cpu(rsp_params->message_ctx); ++ cfg->threshold_entry = le32_to_cpu(rsp_params->threshold_entry); ++ cfg->threshold_exit = le32_to_cpu(rsp_params->threshold_exit); ++ ++ return 0; ++} +diff --git a/drivers/crypto/caam/dpseci.h b/drivers/crypto/caam/dpseci.h +new file mode 100644 +index 00000000..d37489c6 +--- /dev/null ++++ b/drivers/crypto/caam/dpseci.h +@@ -0,0 +1,395 @@ ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. ++ * Copyright 2017 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the names of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef _DPSECI_H_ ++#define _DPSECI_H_ ++ ++/* ++ * Data Path SEC Interface API ++ * Contains initialization APIs and runtime control APIs for DPSECI ++ */ ++ ++struct fsl_mc_io; ++struct opr_cfg; ++struct opr_qry; ++ ++/** ++ * General DPSECI macros ++ */ ++ ++/** ++ * Maximum number of Tx/Rx priorities per DPSECI object ++ */ ++#define DPSECI_PRIO_NUM 8 ++ ++/** ++ * All queues considered; see dpseci_set_rx_queue() ++ */ ++#define DPSECI_ALL_QUEUES (u8)(-1) ++ ++int dpseci_open(struct fsl_mc_io *mc_io, u32 cmd_flags, int dpseci_id, ++ u16 *token); ++ ++int dpseci_close(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); ++ ++/** ++ * Enable the Congestion Group support ++ */ ++#define DPSECI_OPT_HAS_CG 0x000020 ++ ++/** ++ * Enable the Order Restoration support ++ */ ++#define DPSECI_OPT_HAS_OPR 0x000040 ++ ++/** ++ * Order Point Records are shared for the entire DPSECI ++ */ ++#define DPSECI_OPT_OPR_SHARED 0x000080 ++ ++/** ++ * struct dpseci_cfg - Structure representing DPSECI configuration ++ * @options: Any combination of the following options: ++ * DPSECI_OPT_HAS_CG ++ * DPSECI_OPT_HAS_OPR ++ * DPSECI_OPT_OPR_SHARED ++ * @num_tx_queues: num of queues towards the SEC ++ * @num_rx_queues: num of queues back from the SEC ++ * @priorities: Priorities for the SEC hardware processing; ++ * each place in the array is the priority of the tx queue ++ * towards the SEC; ++ * valid priorities are configured with values 1-8; ++ */ ++struct dpseci_cfg { ++ u32 options; ++ u8 num_tx_queues; ++ u8 num_rx_queues; ++ u8 priorities[DPSECI_PRIO_NUM]; ++}; ++ ++int dpseci_create(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags, ++ const struct dpseci_cfg *cfg, u32 *obj_id); ++ ++int dpseci_destroy(struct fsl_mc_io *mc_io, u16 dprc_token, u32 cmd_flags, ++ u32 object_id); ++ ++int dpseci_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); ++ ++int dpseci_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); ++ ++int dpseci_is_enabled(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ int *en); ++ ++int dpseci_reset(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token); ++ ++int dpseci_get_irq_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 irq_index, u8 *en); ++ ++int dpseci_set_irq_enable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 irq_index, u8 en); ++ ++int dpseci_get_irq_mask(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 irq_index, u32 *mask); ++ ++int dpseci_set_irq_mask(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 irq_index, u32 mask); ++ ++int dpseci_get_irq_status(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 irq_index, u32 *status); ++ ++int dpseci_clear_irq_status(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 irq_index, u32 status); ++ ++/** ++ * struct dpseci_attr - Structure representing DPSECI attributes ++ * @id: DPSECI object ID ++ * @num_tx_queues: number of queues towards the SEC ++ * @num_rx_queues: number of queues back from the SEC ++ * @options: any combination of the following options: ++ * DPSECI_OPT_HAS_CG ++ * DPSECI_OPT_HAS_OPR ++ * DPSECI_OPT_OPR_SHARED ++ */ ++struct dpseci_attr { ++ int id; ++ u8 num_tx_queues; ++ u8 num_rx_queues; ++ u32 options; ++}; ++ ++int dpseci_get_attributes(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ struct dpseci_attr *attr); ++ ++/** ++ * enum dpseci_dest - DPSECI destination types ++ * @DPSECI_DEST_NONE: Unassigned destination; The queue is set in parked mode ++ * and does not generate FQDAN notifications; user is expected to dequeue ++ * from the queue based on polling or other user-defined method ++ * @DPSECI_DEST_DPIO: The queue is set in schedule mode and generates FQDAN ++ * notifications to the specified DPIO; user is expected to dequeue from ++ * the queue only after notification is received ++ * @DPSECI_DEST_DPCON: The queue is set in schedule mode and does not generate ++ * FQDAN notifications, but is connected to the specified DPCON object; ++ * user is expected to dequeue from the DPCON channel ++ */ ++enum dpseci_dest { ++ DPSECI_DEST_NONE = 0, ++ DPSECI_DEST_DPIO, ++ DPSECI_DEST_DPCON ++}; ++ ++/** ++ * struct dpseci_dest_cfg - Structure representing DPSECI destination parameters ++ * @dest_type: Destination type ++ * @dest_id: Either DPIO ID or DPCON ID, depending on the destination type ++ * @priority: Priority selection within the DPIO or DPCON channel; valid values ++ * are 0-1 or 0-7, depending on the number of priorities in that channel; ++ * not relevant for 'DPSECI_DEST_NONE' option ++ */ ++struct dpseci_dest_cfg { ++ enum dpseci_dest dest_type; ++ int dest_id; ++ u8 priority; ++}; ++ ++/** ++ * DPSECI queue modification options ++ */ ++ ++/** ++ * Select to modify the user's context associated with the queue ++ */ ++#define DPSECI_QUEUE_OPT_USER_CTX 0x00000001 ++ ++/** ++ * Select to modify the queue's destination ++ */ ++#define DPSECI_QUEUE_OPT_DEST 0x00000002 ++ ++/** ++ * Select to modify the queue's order preservation ++ */ ++#define DPSECI_QUEUE_OPT_ORDER_PRESERVATION 0x00000004 ++ ++/** ++ * struct dpseci_rx_queue_cfg - DPSECI RX queue configuration ++ * @options: Flags representing the suggested modifications to the queue; ++ * Use any combination of 'DPSECI_QUEUE_OPT_' flags ++ * @order_preservation_en: order preservation configuration for the rx queue ++ * valid only if 'DPSECI_QUEUE_OPT_ORDER_PRESERVATION' is contained in 'options' ++ * @user_ctx: User context value provided in the frame descriptor of each ++ * dequeued frame; valid only if 'DPSECI_QUEUE_OPT_USER_CTX' is contained ++ * in 'options' ++ * @dest_cfg: Queue destination parameters; valid only if ++ * 'DPSECI_QUEUE_OPT_DEST' is contained in 'options' ++ */ ++struct dpseci_rx_queue_cfg { ++ u32 options; ++ int order_preservation_en; ++ u64 user_ctx; ++ struct dpseci_dest_cfg dest_cfg; ++}; ++ ++int dpseci_set_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 queue, const struct dpseci_rx_queue_cfg *cfg); ++ ++/** ++ * struct dpseci_rx_queue_attr - Structure representing attributes of Rx queues ++ * @user_ctx: User context value provided in the frame descriptor of each ++ * dequeued frame ++ * @order_preservation_en: Status of the order preservation configuration on the ++ * queue ++ * @dest_cfg: Queue destination configuration ++ * @fqid: Virtual FQID value to be used for dequeue operations ++ */ ++struct dpseci_rx_queue_attr { ++ u64 user_ctx; ++ int order_preservation_en; ++ struct dpseci_dest_cfg dest_cfg; ++ u32 fqid; ++}; ++ ++int dpseci_get_rx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 queue, struct dpseci_rx_queue_attr *attr); ++ ++/** ++ * struct dpseci_tx_queue_attr - Structure representing attributes of Tx queues ++ * @fqid: Virtual FQID to be used for sending frames to SEC hardware ++ * @priority: SEC hardware processing priority for the queue ++ */ ++struct dpseci_tx_queue_attr { ++ u32 fqid; ++ u8 priority; ++}; ++ ++int dpseci_get_tx_queue(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ u8 queue, struct dpseci_tx_queue_attr *attr); ++ ++/** ++ * struct dpseci_sec_attr - Structure representing attributes of the SEC ++ * hardware accelerator ++ * @ip_id: ID for SEC ++ * @major_rev: Major revision number for SEC ++ * @minor_rev: Minor revision number for SEC ++ * @era: SEC Era ++ * @deco_num: The number of copies of the DECO that are implemented in this ++ * version of SEC ++ * @zuc_auth_acc_num: The number of copies of ZUCA that are implemented in this ++ * version of SEC ++ * @zuc_enc_acc_num: The number of copies of ZUCE that are implemented in this ++ * version of SEC ++ * @snow_f8_acc_num: The number of copies of the SNOW-f8 module that are ++ * implemented in this version of SEC ++ * @snow_f9_acc_num: The number of copies of the SNOW-f9 module that are ++ * implemented in this version of SEC ++ * @crc_acc_num: The number of copies of the CRC module that are implemented in ++ * this version of SEC ++ * @pk_acc_num: The number of copies of the Public Key module that are ++ * implemented in this version of SEC ++ * @kasumi_acc_num: The number of copies of the Kasumi module that are ++ * implemented in this version of SEC ++ * @rng_acc_num: The number of copies of the Random Number Generator that are ++ * implemented in this version of SEC ++ * @md_acc_num: The number of copies of the MDHA (Hashing module) that are ++ * implemented in this version of SEC ++ * @arc4_acc_num: The number of copies of the ARC4 module that are implemented ++ * in this version of SEC ++ * @des_acc_num: The number of copies of the DES module that are implemented in ++ * this version of SEC ++ * @aes_acc_num: The number of copies of the AES module that are implemented in ++ * this version of SEC ++ **/ ++struct dpseci_sec_attr { ++ u16 ip_id; ++ u8 major_rev; ++ u8 minor_rev; ++ u8 era; ++ u8 deco_num; ++ u8 zuc_auth_acc_num; ++ u8 zuc_enc_acc_num; ++ u8 snow_f8_acc_num; ++ u8 snow_f9_acc_num; ++ u8 crc_acc_num; ++ u8 pk_acc_num; ++ u8 kasumi_acc_num; ++ u8 rng_acc_num; ++ u8 md_acc_num; ++ u8 arc4_acc_num; ++ u8 des_acc_num; ++ u8 aes_acc_num; ++}; ++ ++int dpseci_get_sec_attr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ struct dpseci_sec_attr *attr); ++ ++/** ++ * struct dpseci_sec_counters - Structure representing global SEC counters and ++ * not per dpseci counters ++ * @dequeued_requests: Number of Requests Dequeued ++ * @ob_enc_requests: Number of Outbound Encrypt Requests ++ * @ib_dec_requests: Number of Inbound Decrypt Requests ++ * @ob_enc_bytes: Number of Outbound Bytes Encrypted ++ * @ob_prot_bytes: Number of Outbound Bytes Protected ++ * @ib_dec_bytes: Number of Inbound Bytes Decrypted ++ * @ib_valid_bytes: Number of Inbound Bytes Validated ++ */ ++struct dpseci_sec_counters { ++ u64 dequeued_requests; ++ u64 ob_enc_requests; ++ u64 ib_dec_requests; ++ u64 ob_enc_bytes; ++ u64 ob_prot_bytes; ++ u64 ib_dec_bytes; ++ u64 ib_valid_bytes; ++}; ++ ++int dpseci_get_sec_counters(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ++ struct dpseci_sec_counters *counters); ++ ++int dpseci_get_api_version(struct fsl_mc_io *mc_io, u32 cmd_flags, ++ u16 *major_ver, u16 *minor_ver); ++ ++int dpseci_set_opr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u8 index, ++ u8 options, struct opr_cfg *cfg); ++ ++int dpseci_get_opr(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u8 index, ++ struct opr_cfg *cfg, struct opr_qry *qry); ++ ++/** ++ * enum dpseci_congestion_unit - DPSECI congestion units ++ * @DPSECI_CONGESTION_UNIT_BYTES: bytes units ++ * @DPSECI_CONGESTION_UNIT_FRAMES: frames units ++ */ ++enum dpseci_congestion_unit { ++ DPSECI_CONGESTION_UNIT_BYTES = 0, ++ DPSECI_CONGESTION_UNIT_FRAMES ++}; ++ ++#define DPSECI_CGN_MODE_WRITE_MEM_ON_ENTER 0x00000001 ++#define DPSECI_CGN_MODE_WRITE_MEM_ON_EXIT 0x00000002 ++#define DPSECI_CGN_MODE_COHERENT_WRITE 0x00000004 ++#define DPSECI_CGN_MODE_NOTIFY_DEST_ON_ENTER 0x00000008 ++#define DPSECI_CGN_MODE_NOTIFY_DEST_ON_EXIT 0x00000010 ++#define DPSECI_CGN_MODE_INTR_COALESCING_DISABLED 0x00000020 ++ ++/** ++ * struct dpseci_congestion_notification_cfg - congestion notification ++ * configuration ++ * @units: units type ++ * @threshold_entry: above this threshold we enter a congestion state. ++ * set it to '0' to disable it ++ * @threshold_exit: below this threshold we exit the congestion state. ++ * @message_ctx: The context that will be part of the CSCN message ++ * @message_iova: I/O virtual address (must be in DMA-able memory), ++ * must be 16B aligned; ++ * @dest_cfg: CSCN can be send to either DPIO or DPCON WQ channel ++ * @notification_mode: Mask of available options; use 'DPSECI_CGN_MODE_' ++ * values ++ */ ++struct dpseci_congestion_notification_cfg { ++ enum dpseci_congestion_unit units; ++ u32 threshold_entry; ++ u32 threshold_exit; ++ u64 message_ctx; ++ u64 message_iova; ++ struct dpseci_dest_cfg dest_cfg; ++ u16 notification_mode; ++}; ++ ++int dpseci_set_congestion_notification(struct fsl_mc_io *mc_io, u32 cmd_flags, ++ u16 token, const struct dpseci_congestion_notification_cfg *cfg); ++ ++int dpseci_get_congestion_notification(struct fsl_mc_io *mc_io, u32 cmd_flags, ++ u16 token, struct dpseci_congestion_notification_cfg *cfg); ++ ++#endif /* _DPSECI_H_ */ +diff --git a/drivers/crypto/caam/dpseci_cmd.h b/drivers/crypto/caam/dpseci_cmd.h +new file mode 100644 +index 00000000..7624315e +--- /dev/null ++++ b/drivers/crypto/caam/dpseci_cmd.h +@@ -0,0 +1,261 @@ ++/* ++ * Copyright 2013-2016 Freescale Semiconductor Inc. ++ * Copyright 2017 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the names of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef _DPSECI_CMD_H_ ++#define _DPSECI_CMD_H_ ++ ++/* DPSECI Version */ ++#define DPSECI_VER_MAJOR 5 ++#define DPSECI_VER_MINOR 1 ++ ++#define DPSECI_VER(maj, min) (((maj) << 16) | (min)) ++#define DPSECI_VERSION DPSECI_VER(DPSECI_VER_MAJOR, DPSECI_VER_MINOR) ++ ++/* Command IDs */ ++ ++#define DPSECI_CMDID_CLOSE 0x8001 ++#define DPSECI_CMDID_OPEN 0x8091 ++#define DPSECI_CMDID_CREATE 0x9092 ++#define DPSECI_CMDID_DESTROY 0x9891 ++#define DPSECI_CMDID_GET_API_VERSION 0xa091 ++ ++#define DPSECI_CMDID_ENABLE 0x0021 ++#define DPSECI_CMDID_DISABLE 0x0031 ++#define DPSECI_CMDID_GET_ATTR 0x0041 ++#define DPSECI_CMDID_RESET 0x0051 ++#define DPSECI_CMDID_IS_ENABLED 0x0061 ++ ++#define DPSECI_CMDID_SET_IRQ_ENABLE 0x0121 ++#define DPSECI_CMDID_GET_IRQ_ENABLE 0x0131 ++#define DPSECI_CMDID_SET_IRQ_MASK 0x0141 ++#define DPSECI_CMDID_GET_IRQ_MASK 0x0151 ++#define DPSECI_CMDID_GET_IRQ_STATUS 0x0161 ++#define DPSECI_CMDID_CLEAR_IRQ_STATUS 0x0171 ++ ++#define DPSECI_CMDID_SET_RX_QUEUE 0x1941 ++#define DPSECI_CMDID_GET_RX_QUEUE 0x1961 ++#define DPSECI_CMDID_GET_TX_QUEUE 0x1971 ++#define DPSECI_CMDID_GET_SEC_ATTR 0x1981 ++#define DPSECI_CMDID_GET_SEC_COUNTERS 0x1991 ++#define DPSECI_CMDID_SET_OPR 0x19A1 ++#define DPSECI_CMDID_GET_OPR 0x19B1 ++ ++#define DPSECI_CMDID_SET_CONGESTION_NOTIFICATION 0x1701 ++#define DPSECI_CMDID_GET_CONGESTION_NOTIFICATION 0x1711 ++ ++/* Macros for accessing command fields smaller than 1 byte */ ++#define DPSECI_MASK(field) \ ++ GENMASK(DPSECI_##field##_SHIFT + DPSECI_##field##_SIZE - 1, \ ++ DPSECI_##field##_SHIFT) ++ ++#define dpseci_set_field(var, field, val) \ ++ ((var) |= (((val) << DPSECI_##field##_SHIFT) & DPSECI_MASK(field))) ++ ++#define dpseci_get_field(var, field) \ ++ (((var) & DPSECI_MASK(field)) >> DPSECI_##field##_SHIFT) ++ ++struct dpseci_cmd_open { ++ __le32 dpseci_id; ++}; ++ ++struct dpseci_cmd_create { ++ u8 priorities[8]; ++ u8 num_tx_queues; ++ u8 num_rx_queues; ++ __le16 pad; ++ __le32 options; ++}; ++ ++struct dpseci_cmd_destroy { ++ __le32 object_id; ++}; ++ ++struct dpseci_rsp_is_enabled { ++ __le32 is_enabled; ++}; ++ ++struct dpseci_cmd_irq_enable { ++ u8 enable_state; ++ u8 pad[3]; ++ u8 irq_index; ++}; ++ ++struct dpseci_rsp_get_irq_enable { ++ u8 enable_state; ++}; ++ ++struct dpseci_cmd_irq_mask { ++ __le32 mask; ++ u8 irq_index; ++}; ++ ++struct dpseci_cmd_irq_status { ++ __le32 status; ++ u8 irq_index; ++}; ++ ++struct dpseci_rsp_get_attributes { ++ __le32 id; ++ __le32 pad0; ++ u8 num_tx_queues; ++ u8 num_rx_queues; ++ u8 pad1[6]; ++ __le32 options; ++}; ++ ++struct dpseci_cmd_queue { ++ __le32 dest_id; ++ u8 priority; ++ u8 queue; ++ u8 dest_type; ++ u8 pad; ++ __le64 user_ctx; ++ union { ++ __le32 options; ++ __le32 fqid; ++ }; ++ __le32 order_preservation_en; ++}; ++ ++struct dpseci_rsp_get_tx_queue { ++ __le32 pad; ++ __le32 fqid; ++ u8 priority; ++}; ++ ++struct dpseci_rsp_get_sec_attr { ++ __le16 ip_id; ++ u8 major_rev; ++ u8 minor_rev; ++ u8 era; ++ u8 pad0[3]; ++ u8 deco_num; ++ u8 zuc_auth_acc_num; ++ u8 zuc_enc_acc_num; ++ u8 pad1; ++ u8 snow_f8_acc_num; ++ u8 snow_f9_acc_num; ++ u8 crc_acc_num; ++ u8 pad2; ++ u8 pk_acc_num; ++ u8 kasumi_acc_num; ++ u8 rng_acc_num; ++ u8 pad3; ++ u8 md_acc_num; ++ u8 arc4_acc_num; ++ u8 des_acc_num; ++ u8 aes_acc_num; ++}; ++ ++struct dpseci_rsp_get_sec_counters { ++ __le64 dequeued_requests; ++ __le64 ob_enc_requests; ++ __le64 ib_dec_requests; ++ __le64 ob_enc_bytes; ++ __le64 ob_prot_bytes; ++ __le64 ib_dec_bytes; ++ __le64 ib_valid_bytes; ++}; ++ ++struct dpseci_rsp_get_api_version { ++ __le16 major; ++ __le16 minor; ++}; ++ ++struct dpseci_cmd_opr { ++ __le16 pad; ++ u8 index; ++ u8 options; ++ u8 pad1[7]; ++ u8 oloe; ++ u8 oeane; ++ u8 olws; ++ u8 oa; ++ u8 oprrws; ++}; ++ ++#define DPSECI_OPR_RIP_SHIFT 0 ++#define DPSECI_OPR_RIP_SIZE 1 ++#define DPSECI_OPR_ENABLE_SHIFT 1 ++#define DPSECI_OPR_ENABLE_SIZE 1 ++#define DPSECI_OPR_TSEQ_NLIS_SHIFT 1 ++#define DPSECI_OPR_TSEQ_NLIS_SIZE 1 ++#define DPSECI_OPR_HSEQ_NLIS_SHIFT 1 ++#define DPSECI_OPR_HSEQ_NLIS_SIZE 1 ++ ++struct dpseci_rsp_get_opr { ++ __le64 pad; ++ u8 rip_enable; ++ u8 pad0[2]; ++ u8 oloe; ++ u8 oeane; ++ u8 olws; ++ u8 oa; ++ u8 oprrws; ++ __le16 nesn; ++ __le16 pad1; ++ __le16 ndsn; ++ __le16 pad2; ++ __le16 ea_tseq; ++ u8 tseq_nlis; ++ u8 pad3; ++ __le16 ea_hseq; ++ u8 hseq_nlis; ++ u8 pad4; ++ __le16 ea_hptr; ++ __le16 pad5; ++ __le16 ea_tptr; ++ __le16 pad6; ++ __le16 opr_vid; ++ __le16 pad7; ++ __le16 opr_id; ++}; ++ ++#define DPSECI_CGN_DEST_TYPE_SHIFT 0 ++#define DPSECI_CGN_DEST_TYPE_SIZE 4 ++#define DPSECI_CGN_UNITS_SHIFT 4 ++#define DPSECI_CGN_UNITS_SIZE 2 ++ ++struct dpseci_cmd_congestion_notification { ++ __le32 dest_id; ++ __le16 notification_mode; ++ u8 priority; ++ u8 options; ++ __le64 message_iova; ++ __le64 message_ctx; ++ __le32 threshold_entry; ++ __le32 threshold_exit; ++}; ++ ++#endif /* _DPSECI_CMD_H_ */ +diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c +index 33e41ea8..31963397 100644 +--- a/drivers/crypto/caam/error.c ++++ b/drivers/crypto/caam/error.c +@@ -6,11 +6,54 @@ + + #include "compat.h" + #include "regs.h" +-#include "intern.h" + #include "desc.h" +-#include "jr.h" + #include "error.h" + ++#ifdef DEBUG ++ ++#include ++ ++void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type, ++ int rowsize, int groupsize, struct scatterlist *sg, ++ size_t tlen, bool ascii) ++{ ++ struct scatterlist *it; ++ void *it_page; ++ size_t len; ++ void *buf; ++ ++ for (it = sg; it && tlen > 0 ; it = sg_next(sg)) { ++ /* ++ * make sure the scatterlist's page ++ * has a valid virtual memory mapping ++ */ ++ it_page = kmap_atomic(sg_page(it)); ++ if (unlikely(!it_page)) { ++ pr_err("caam_dump_sg: kmap failed\n"); ++ return; ++ } ++ ++ buf = it_page + it->offset; ++ len = min_t(size_t, tlen, it->length); ++ print_hex_dump(level, prefix_str, prefix_type, rowsize, ++ groupsize, buf, len, ascii); ++ tlen -= len; ++ ++ kunmap_atomic(it_page); ++ } ++} ++ ++#else ++ ++void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type, ++ int rowsize, int groupsize, struct scatterlist *sg, ++ size_t tlen, bool ascii) ++{} ++ ++#endif ++ ++EXPORT_SYMBOL(caam_dump_sg); ++ + static const struct { + u8 value; + const char *error_text; +@@ -69,6 +112,54 @@ static const struct { + { 0xF1, "3GPP HFN matches or exceeds the Threshold" }, + }; + ++static const struct { ++ u8 value; ++ const char *error_text; ++} qi_error_list[] = { ++ { 0x1F, "Job terminated by FQ or ICID flush" }, ++ { 0x20, "FD format error"}, ++ { 0x21, "FD command format error"}, ++ { 0x23, "FL format error"}, ++ { 0x25, "CRJD specified in FD, but not enabled in FLC"}, ++ { 0x30, "Max. buffer size too small"}, ++ { 0x31, "DHR exceeds max. buffer size (allocate mode, S/G format)"}, ++ { 0x32, "SGT exceeds max. buffer size (allocate mode, S/G format"}, ++ { 0x33, "Size over/underflow (allocate mode)"}, ++ { 0x34, "Size over/underflow (reuse mode)"}, ++ { 0x35, "Length exceeds max. short length (allocate mode, S/G/ format)"}, ++ { 0x36, "Memory footprint exceeds max. value (allocate mode, S/G/ format)"}, ++ { 0x41, "SBC frame format not supported (allocate mode)"}, ++ { 0x42, "Pool 0 invalid / pool 1 size < pool 0 size (allocate mode)"}, ++ { 0x43, "Annotation output enabled but ASAR = 0 (allocate mode)"}, ++ { 0x44, "Unsupported or reserved frame format or SGHR = 1 (reuse mode)"}, ++ { 0x45, "DHR correction underflow (reuse mode, single buffer format)"}, ++ { 0x46, "Annotation length exceeds offset (reuse mode)"}, ++ { 0x48, "Annotation output enabled but ASA limited by ASAR (reuse mode)"}, ++ { 0x49, "Data offset correction exceeds input frame data length (reuse mode)"}, ++ { 0x4B, "Annotation output enabled but ASA cannote be expanded (frame list)"}, ++ { 0x51, "Unsupported IF reuse mode"}, ++ { 0x52, "Unsupported FL use mode"}, ++ { 0x53, "Unsupported RJD use mode"}, ++ { 0x54, "Unsupported inline descriptor use mode"}, ++ { 0xC0, "Table buffer pool 0 depletion"}, ++ { 0xC1, "Table buffer pool 1 depletion"}, ++ { 0xC2, "Data buffer pool 0 depletion, no OF allocated"}, ++ { 0xC3, "Data buffer pool 1 depletion, no OF allocated"}, ++ { 0xC4, "Data buffer pool 0 depletion, partial OF allocated"}, ++ { 0xC5, "Data buffer pool 1 depletion, partial OF allocated"}, ++ { 0xD0, "FLC read error"}, ++ { 0xD1, "FL read error"}, ++ { 0xD2, "FL write error"}, ++ { 0xD3, "OF SGT write error"}, ++ { 0xD4, "PTA read error"}, ++ { 0xD5, "PTA write error"}, ++ { 0xD6, "OF SGT F-bit write error"}, ++ { 0xD7, "ASA write error"}, ++ { 0xE1, "FLC[ICR]=0 ICID error"}, ++ { 0xE2, "FLC[ICR]=1 ICID error"}, ++ { 0xE4, "source of ICID flush not trusted (BDI = 0)"}, ++}; ++ + static const char * const cha_id_list[] = { + "", + "AES", +@@ -146,10 +237,9 @@ static void report_ccb_status(struct device *jrdev, const u32 status, + strlen(rng_err_id_list[err_id])) { + /* RNG-only error */ + err_str = rng_err_id_list[err_id]; +- } else if (err_id < ARRAY_SIZE(err_id_list)) ++ } else { + err_str = err_id_list[err_id]; +- else +- snprintf(err_err_code, sizeof(err_err_code), "%02x", err_id); ++ } + + /* + * CCB ICV check failures are part of normal operation life; +@@ -198,6 +288,27 @@ static void report_deco_status(struct device *jrdev, const u32 status, + status, error, idx_str, idx, err_str, err_err_code); + } + ++static void report_qi_status(struct device *qidev, const u32 status, ++ const char *error) ++{ ++ u8 err_id = status & JRSTA_QIERR_ERROR_MASK; ++ const char *err_str = "unidentified error value 0x"; ++ char err_err_code[3] = { 0 }; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(qi_error_list); i++) ++ if (qi_error_list[i].value == err_id) ++ break; ++ ++ if (i != ARRAY_SIZE(qi_error_list) && qi_error_list[i].error_text) ++ err_str = qi_error_list[i].error_text; ++ else ++ snprintf(err_err_code, sizeof(err_err_code), "%02x", err_id); ++ ++ dev_err(qidev, "%08x: %s: %s%s\n", ++ status, error, err_str, err_err_code); ++} ++ + static void report_jr_status(struct device *jrdev, const u32 status, + const char *error) + { +@@ -212,7 +323,7 @@ static void report_cond_code_status(struct device *jrdev, const u32 status, + status, error, __func__); + } + +-void caam_jr_strstatus(struct device *jrdev, u32 status) ++void caam_strstatus(struct device *jrdev, u32 status, bool qi_v2) + { + static const struct stat_src { + void (*report_ssed)(struct device *jrdev, const u32 status, +@@ -224,7 +335,7 @@ void caam_jr_strstatus(struct device *jrdev, u32 status) + { report_ccb_status, "CCB" }, + { report_jump_status, "Jump" }, + { report_deco_status, "DECO" }, +- { NULL, "Queue Manager Interface" }, ++ { report_qi_status, "Queue Manager Interface" }, + { report_jr_status, "Job Ring" }, + { report_cond_code_status, "Condition Code" }, + { NULL, NULL }, +@@ -250,4 +361,4 @@ void caam_jr_strstatus(struct device *jrdev, u32 status) + else + dev_err(jrdev, "%d: unknown error source\n", ssrc); + } +-EXPORT_SYMBOL(caam_jr_strstatus); ++EXPORT_SYMBOL(caam_strstatus); +diff --git a/drivers/crypto/caam/error.h b/drivers/crypto/caam/error.h +index b6350b0d..751ddcac 100644 +--- a/drivers/crypto/caam/error.h ++++ b/drivers/crypto/caam/error.h +@@ -7,5 +7,13 @@ + #ifndef CAAM_ERROR_H + #define CAAM_ERROR_H + #define CAAM_ERROR_STR_MAX 302 +-void caam_jr_strstatus(struct device *jrdev, u32 status); ++ ++void caam_strstatus(struct device *dev, u32 status, bool qi_v2); ++ ++#define caam_jr_strstatus(jrdev, status) caam_strstatus(jrdev, status, false) ++#define caam_qi2_strstatus(qidev, status) caam_strstatus(qidev, status, true) ++ ++void caam_dump_sg(const char *level, const char *prefix_str, int prefix_type, ++ int rowsize, int groupsize, struct scatterlist *sg, ++ size_t tlen, bool ascii); + #endif /* CAAM_ERROR_H */ +diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h +index 5d4c0507..a5236125 100644 +--- a/drivers/crypto/caam/intern.h ++++ b/drivers/crypto/caam/intern.h +@@ -41,6 +41,7 @@ struct caam_drv_private_jr { + struct device *dev; + int ridx; + struct caam_job_ring __iomem *rregs; /* JobR's register space */ ++ struct tasklet_struct irqtask; + int irq; /* One per queue */ + + /* Number of scatterlist crypt transforms active on the JobR */ +@@ -63,10 +64,9 @@ struct caam_drv_private_jr { + * Driver-private storage for a single CAAM block instance + */ + struct caam_drv_private { +- +- struct device *dev; +- struct platform_device **jrpdev; /* Alloc'ed array per sub-device */ +- struct platform_device *pdev; ++#ifdef CONFIG_CAAM_QI ++ struct device *qidev; ++#endif + + /* Physical-presence section */ + struct caam_ctrl __iomem *ctrl; /* controller region */ +@@ -102,11 +102,6 @@ struct caam_drv_private { + #ifdef CONFIG_DEBUG_FS + struct dentry *dfs_root; + struct dentry *ctl; /* controller dir */ +- struct dentry *ctl_rq_dequeued, *ctl_ob_enc_req, *ctl_ib_dec_req; +- struct dentry *ctl_ob_enc_bytes, *ctl_ob_prot_bytes; +- struct dentry *ctl_ib_dec_bytes, *ctl_ib_valid_bytes; +- struct dentry *ctl_faultaddr, *ctl_faultdetail, *ctl_faultstatus; +- + struct debugfs_blob_wrapper ctl_kek_wrap, ctl_tkek_wrap, ctl_tdsk_wrap; + struct dentry *ctl_kek, *ctl_tkek, *ctl_tdsk; + #endif +@@ -114,4 +109,22 @@ struct caam_drv_private { + + void caam_jr_algapi_init(struct device *dev); + void caam_jr_algapi_remove(struct device *dev); ++ ++#ifdef CONFIG_DEBUG_FS ++static int caam_debugfs_u64_get(void *data, u64 *val) ++{ ++ *val = caam64_to_cpu(*(u64 *)data); ++ return 0; ++} ++ ++static int caam_debugfs_u32_get(void *data, u64 *val) ++{ ++ *val = caam32_to_cpu(*(u32 *)data); ++ return 0; ++} ++ ++DEFINE_SIMPLE_ATTRIBUTE(caam_fops_u32_ro, caam_debugfs_u32_get, NULL, "%llu\n"); ++DEFINE_SIMPLE_ATTRIBUTE(caam_fops_u64_ro, caam_debugfs_u64_get, NULL, "%llu\n"); ++#endif ++ + #endif /* INTERN_H */ +diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c +index 757c27f9..d258953f 100644 +--- a/drivers/crypto/caam/jr.c ++++ b/drivers/crypto/caam/jr.c +@@ -9,6 +9,7 @@ + #include + + #include "compat.h" ++#include "ctrl.h" + #include "regs.h" + #include "jr.h" + #include "desc.h" +@@ -73,6 +74,8 @@ static int caam_jr_shutdown(struct device *dev) + + ret = caam_reset_hw_jr(dev); + ++ tasklet_kill(&jrp->irqtask); ++ + /* Release interrupt */ + free_irq(jrp->irq, dev); + +@@ -128,7 +131,7 @@ static irqreturn_t caam_jr_interrupt(int irq, void *st_dev) + + /* + * Check the output ring for ready responses, kick +- * the threaded irq if jobs done. ++ * tasklet if jobs done. + */ + irqstate = rd_reg32(&jrp->rregs->jrintstatus); + if (!irqstate) +@@ -150,13 +153,18 @@ static irqreturn_t caam_jr_interrupt(int irq, void *st_dev) + /* Have valid interrupt at this point, just ACK and trigger */ + wr_reg32(&jrp->rregs->jrintstatus, irqstate); + +- return IRQ_WAKE_THREAD; ++ preempt_disable(); ++ tasklet_schedule(&jrp->irqtask); ++ preempt_enable(); ++ ++ return IRQ_HANDLED; + } + +-static irqreturn_t caam_jr_threadirq(int irq, void *st_dev) ++/* Deferred service handler, run as interrupt-fired tasklet */ ++static void caam_jr_dequeue(unsigned long devarg) + { + int hw_idx, sw_idx, i, head, tail; +- struct device *dev = st_dev; ++ struct device *dev = (struct device *)devarg; + struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); + void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg); + u32 *userdesc, userstatus; +@@ -230,8 +238,6 @@ static irqreturn_t caam_jr_threadirq(int irq, void *st_dev) + + /* reenable / unmask IRQs */ + clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0); +- +- return IRQ_HANDLED; + } + + /** +@@ -389,10 +395,11 @@ static int caam_jr_init(struct device *dev) + + jrp = dev_get_drvdata(dev); + ++ tasklet_init(&jrp->irqtask, caam_jr_dequeue, (unsigned long)dev); ++ + /* Connect job ring interrupt handler. */ +- error = request_threaded_irq(jrp->irq, caam_jr_interrupt, +- caam_jr_threadirq, IRQF_SHARED, +- dev_name(dev), dev); ++ error = request_irq(jrp->irq, caam_jr_interrupt, IRQF_SHARED, ++ dev_name(dev), dev); + if (error) { + dev_err(dev, "can't connect JobR %d interrupt (%d)\n", + jrp->ridx, jrp->irq); +@@ -454,6 +461,7 @@ static int caam_jr_init(struct device *dev) + out_free_irq: + free_irq(jrp->irq, dev); + out_kill_deq: ++ tasklet_kill(&jrp->irqtask); + return error; + } + +@@ -489,15 +497,28 @@ static int caam_jr_probe(struct platform_device *pdev) + return -ENOMEM; + } + +- jrpriv->rregs = (struct caam_job_ring __force *)ctrl; ++ jrpriv->rregs = (struct caam_job_ring __iomem __force *)ctrl; + +- if (sizeof(dma_addr_t) == sizeof(u64)) +- if (of_device_is_compatible(nprop, "fsl,sec-v5.0-job-ring")) +- dma_set_mask_and_coherent(jrdev, DMA_BIT_MASK(40)); ++ if (sizeof(dma_addr_t) == sizeof(u64)) { ++ if (caam_dpaa2) ++ error = dma_set_mask_and_coherent(jrdev, ++ DMA_BIT_MASK(49)); ++ else if (of_device_is_compatible(nprop, ++ "fsl,sec-v5.0-job-ring")) ++ error = dma_set_mask_and_coherent(jrdev, ++ DMA_BIT_MASK(40)); + else +- dma_set_mask_and_coherent(jrdev, DMA_BIT_MASK(36)); +- else +- dma_set_mask_and_coherent(jrdev, DMA_BIT_MASK(32)); ++ error = dma_set_mask_and_coherent(jrdev, ++ DMA_BIT_MASK(36)); ++ } else { ++ error = dma_set_mask_and_coherent(jrdev, DMA_BIT_MASK(32)); ++ } ++ if (error) { ++ dev_err(jrdev, "dma_set_mask_and_coherent failed (%d)\n", ++ error); ++ iounmap(ctrl); ++ return error; ++ } + + /* Identify the interrupt */ + jrpriv->irq = irq_of_parse_and_map(nprop, 0); +@@ -520,7 +541,7 @@ static int caam_jr_probe(struct platform_device *pdev) + return 0; + } + +-static struct of_device_id caam_jr_match[] = { ++static const struct of_device_id caam_jr_match[] = { + { + .compatible = "fsl,sec-v4.0-job-ring", + }, +diff --git a/drivers/crypto/caam/key_gen.c b/drivers/crypto/caam/key_gen.c +index 3ce1d5cd..a523ed77 100644 +--- a/drivers/crypto/caam/key_gen.c ++++ b/drivers/crypto/caam/key_gen.c +@@ -41,15 +41,29 @@ Split key generation----------------------------------------------- + [06] 0x64260028 fifostr: class2 mdsplit-jdk len=40 + @0xffe04000 + */ +-int gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len, +- int split_key_pad_len, const u8 *key_in, u32 keylen, +- u32 alg_op) ++int gen_split_key(struct device *jrdev, u8 *key_out, ++ struct alginfo * const adata, const u8 *key_in, u32 keylen, ++ int max_keylen) + { + u32 *desc; + struct split_key_result result; + dma_addr_t dma_addr_in, dma_addr_out; + int ret = -ENOMEM; + ++ adata->keylen = split_key_len(adata->algtype & OP_ALG_ALGSEL_MASK); ++ adata->keylen_pad = split_key_pad_len(adata->algtype & ++ OP_ALG_ALGSEL_MASK); ++ ++#ifdef DEBUG ++ dev_err(jrdev, "split keylen %d split keylen padded %d\n", ++ adata->keylen, adata->keylen_pad); ++ print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ", ++ DUMP_PREFIX_ADDRESS, 16, 4, key_in, keylen, 1); ++#endif ++ ++ if (adata->keylen_pad > max_keylen) ++ return -EINVAL; ++ + desc = kmalloc(CAAM_CMD_SZ * 6 + CAAM_PTR_SZ * 2, GFP_KERNEL | GFP_DMA); + if (!desc) { + dev_err(jrdev, "unable to allocate key input memory\n"); +@@ -63,7 +77,7 @@ int gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len, + goto out_free; + } + +- dma_addr_out = dma_map_single(jrdev, key_out, split_key_pad_len, ++ dma_addr_out = dma_map_single(jrdev, key_out, adata->keylen_pad, + DMA_FROM_DEVICE); + if (dma_mapping_error(jrdev, dma_addr_out)) { + dev_err(jrdev, "unable to map key output memory\n"); +@@ -74,7 +88,9 @@ int gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len, + append_key(desc, dma_addr_in, keylen, CLASS_2 | KEY_DEST_CLASS_REG); + + /* Sets MDHA up into an HMAC-INIT */ +- append_operation(desc, alg_op | OP_ALG_DECRYPT | OP_ALG_AS_INIT); ++ append_operation(desc, (adata->algtype & OP_ALG_ALGSEL_MASK) | ++ OP_ALG_AAI_HMAC | OP_TYPE_CLASS2_ALG | OP_ALG_DECRYPT | ++ OP_ALG_AS_INIT); + + /* + * do a FIFO_LOAD of zero, this will trigger the internal key expansion +@@ -87,7 +103,7 @@ int gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len, + * FIFO_STORE with the explicit split-key content store + * (0x26 output type) + */ +- append_fifo_store(desc, dma_addr_out, split_key_len, ++ append_fifo_store(desc, dma_addr_out, adata->keylen, + LDST_CLASS_2_CCB | FIFOST_TYPE_SPLIT_KEK); + + #ifdef DEBUG +@@ -108,11 +124,11 @@ int gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len, + #ifdef DEBUG + print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key_out, +- split_key_pad_len, 1); ++ adata->keylen_pad, 1); + #endif + } + +- dma_unmap_single(jrdev, dma_addr_out, split_key_pad_len, ++ dma_unmap_single(jrdev, dma_addr_out, adata->keylen_pad, + DMA_FROM_DEVICE); + out_unmap_in: + dma_unmap_single(jrdev, dma_addr_in, keylen, DMA_TO_DEVICE); +diff --git a/drivers/crypto/caam/key_gen.h b/drivers/crypto/caam/key_gen.h +index c5588f6d..851a7c86 100644 +--- a/drivers/crypto/caam/key_gen.h ++++ b/drivers/crypto/caam/key_gen.h +@@ -5,6 +5,36 @@ + * + */ + ++/** ++ * split_key_len - Compute MDHA split key length for a given algorithm ++ * @hash: Hashing algorithm selection, one of OP_ALG_ALGSEL_* - MD5, SHA1, ++ * SHA224, SHA384, SHA512. ++ * ++ * Return: MDHA split key length ++ */ ++static inline u32 split_key_len(u32 hash) ++{ ++ /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */ ++ static const u8 mdpadlen[] = { 16, 20, 32, 32, 64, 64 }; ++ u32 idx; ++ ++ idx = (hash & OP_ALG_ALGSEL_SUBMASK) >> OP_ALG_ALGSEL_SHIFT; ++ ++ return (u32)(mdpadlen[idx] * 2); ++} ++ ++/** ++ * split_key_pad_len - Compute MDHA split key pad length for a given algorithm ++ * @hash: Hashing algorithm selection, one of OP_ALG_ALGSEL_* - MD5, SHA1, ++ * SHA224, SHA384, SHA512. ++ * ++ * Return: MDHA split key pad length ++ */ ++static inline u32 split_key_pad_len(u32 hash) ++{ ++ return ALIGN(split_key_len(hash), 16); ++} ++ + struct split_key_result { + struct completion completion; + int err; +@@ -12,6 +42,6 @@ struct split_key_result { + + void split_key_done(struct device *dev, u32 *desc, u32 err, void *context); + +-int gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len, +- int split_key_pad_len, const u8 *key_in, u32 keylen, +- u32 alg_op); ++int gen_split_key(struct device *jrdev, u8 *key_out, ++ struct alginfo * const adata, const u8 *key_in, u32 keylen, ++ int max_keylen); +diff --git a/drivers/crypto/caam/pdb.h b/drivers/crypto/caam/pdb.h +index aaa00dd1..31e59963 100644 +--- a/drivers/crypto/caam/pdb.h ++++ b/drivers/crypto/caam/pdb.h +@@ -483,6 +483,8 @@ struct dsa_verify_pdb { + #define RSA_PDB_E_MASK (0xFFF << RSA_PDB_E_SHIFT) + #define RSA_PDB_D_SHIFT 12 + #define RSA_PDB_D_MASK (0xFFF << RSA_PDB_D_SHIFT) ++#define RSA_PDB_Q_SHIFT 12 ++#define RSA_PDB_Q_MASK (0xFFF << RSA_PDB_Q_SHIFT) + + #define RSA_PDB_SGF_F (0x8 << RSA_PDB_SGF_SHIFT) + #define RSA_PDB_SGF_G (0x4 << RSA_PDB_SGF_SHIFT) +@@ -490,6 +492,8 @@ struct dsa_verify_pdb { + #define RSA_PRIV_PDB_SGF_G (0x8 << RSA_PDB_SGF_SHIFT) + + #define RSA_PRIV_KEY_FRM_1 0 ++#define RSA_PRIV_KEY_FRM_2 1 ++#define RSA_PRIV_KEY_FRM_3 2 + + /** + * RSA Encrypt Protocol Data Block +@@ -525,4 +529,62 @@ struct rsa_priv_f1_pdb { + dma_addr_t d_dma; + } __packed; + ++/** ++ * RSA Decrypt PDB - Private Key Form #2 ++ * @sgf : scatter-gather field ++ * @g_dma : dma address of encrypted input data ++ * @f_dma : dma address of output data ++ * @d_dma : dma address of RSA private exponent ++ * @p_dma : dma address of RSA prime factor p of RSA modulus n ++ * @q_dma : dma address of RSA prime factor q of RSA modulus n ++ * @tmp1_dma: dma address of temporary buffer. CAAM uses this temporary buffer ++ * as internal state buffer. It is assumed to be as long as p. ++ * @tmp2_dma: dma address of temporary buffer. CAAM uses this temporary buffer ++ * as internal state buffer. It is assumed to be as long as q. ++ * @p_q_len : length in bytes of first two prime factors of the RSA modulus n ++ */ ++struct rsa_priv_f2_pdb { ++ u32 sgf; ++ dma_addr_t g_dma; ++ dma_addr_t f_dma; ++ dma_addr_t d_dma; ++ dma_addr_t p_dma; ++ dma_addr_t q_dma; ++ dma_addr_t tmp1_dma; ++ dma_addr_t tmp2_dma; ++ u32 p_q_len; ++} __packed; ++ ++/** ++ * RSA Decrypt PDB - Private Key Form #3 ++ * This is the RSA Chinese Reminder Theorem (CRT) form for two prime factors of ++ * the RSA modulus. ++ * @sgf : scatter-gather field ++ * @g_dma : dma address of encrypted input data ++ * @f_dma : dma address of output data ++ * @c_dma : dma address of RSA CRT coefficient ++ * @p_dma : dma address of RSA prime factor p of RSA modulus n ++ * @q_dma : dma address of RSA prime factor q of RSA modulus n ++ * @dp_dma : dma address of RSA CRT exponent of RSA prime factor p ++ * @dp_dma : dma address of RSA CRT exponent of RSA prime factor q ++ * @tmp1_dma: dma address of temporary buffer. CAAM uses this temporary buffer ++ * as internal state buffer. It is assumed to be as long as p. ++ * @tmp2_dma: dma address of temporary buffer. CAAM uses this temporary buffer ++ * as internal state buffer. It is assumed to be as long as q. ++ * @p_q_len : length in bytes of first two prime factors of the RSA modulus n ++ */ ++struct rsa_priv_f3_pdb { ++ u32 sgf; ++ dma_addr_t g_dma; ++ dma_addr_t f_dma; ++ dma_addr_t c_dma; ++ dma_addr_t p_dma; ++ dma_addr_t q_dma; ++ dma_addr_t dp_dma; ++ dma_addr_t dq_dma; ++ dma_addr_t tmp1_dma; ++ dma_addr_t tmp2_dma; ++ u32 p_q_len; ++} __packed; ++ + #endif +diff --git a/drivers/crypto/caam/pkc_desc.c b/drivers/crypto/caam/pkc_desc.c +index 4e4183e6..9e2ce6fe 100644 +--- a/drivers/crypto/caam/pkc_desc.c ++++ b/drivers/crypto/caam/pkc_desc.c +@@ -34,3 +34,39 @@ void init_rsa_priv_f1_desc(u32 *desc, struct rsa_priv_f1_pdb *pdb) + append_operation(desc, OP_TYPE_UNI_PROTOCOL | OP_PCLID_RSADEC_PRVKEY | + RSA_PRIV_KEY_FRM_1); + } ++ ++/* Descriptor for RSA Private operation - Private Key Form #2 */ ++void init_rsa_priv_f2_desc(u32 *desc, struct rsa_priv_f2_pdb *pdb) ++{ ++ init_job_desc_pdb(desc, 0, sizeof(*pdb)); ++ append_cmd(desc, pdb->sgf); ++ append_ptr(desc, pdb->g_dma); ++ append_ptr(desc, pdb->f_dma); ++ append_ptr(desc, pdb->d_dma); ++ append_ptr(desc, pdb->p_dma); ++ append_ptr(desc, pdb->q_dma); ++ append_ptr(desc, pdb->tmp1_dma); ++ append_ptr(desc, pdb->tmp2_dma); ++ append_cmd(desc, pdb->p_q_len); ++ append_operation(desc, OP_TYPE_UNI_PROTOCOL | OP_PCLID_RSADEC_PRVKEY | ++ RSA_PRIV_KEY_FRM_2); ++} ++ ++/* Descriptor for RSA Private operation - Private Key Form #3 */ ++void init_rsa_priv_f3_desc(u32 *desc, struct rsa_priv_f3_pdb *pdb) ++{ ++ init_job_desc_pdb(desc, 0, sizeof(*pdb)); ++ append_cmd(desc, pdb->sgf); ++ append_ptr(desc, pdb->g_dma); ++ append_ptr(desc, pdb->f_dma); ++ append_ptr(desc, pdb->c_dma); ++ append_ptr(desc, pdb->p_dma); ++ append_ptr(desc, pdb->q_dma); ++ append_ptr(desc, pdb->dp_dma); ++ append_ptr(desc, pdb->dq_dma); ++ append_ptr(desc, pdb->tmp1_dma); ++ append_ptr(desc, pdb->tmp2_dma); ++ append_cmd(desc, pdb->p_q_len); ++ append_operation(desc, OP_TYPE_UNI_PROTOCOL | OP_PCLID_RSADEC_PRVKEY | ++ RSA_PRIV_KEY_FRM_3); ++} +diff --git a/drivers/crypto/caam/qi.c b/drivers/crypto/caam/qi.c +new file mode 100644 +index 00000000..48185d55 +--- /dev/null ++++ b/drivers/crypto/caam/qi.c +@@ -0,0 +1,797 @@ ++/* ++ * CAAM/SEC 4.x QI transport/backend driver ++ * Queue Interface backend functionality ++ * ++ * Copyright 2013-2016 Freescale Semiconductor, Inc. ++ * Copyright 2016-2017 NXP ++ */ ++ ++#include ++#include ++#include ++ ++#include "regs.h" ++#include "qi.h" ++#include "desc.h" ++#include "intern.h" ++#include "desc_constr.h" ++ ++#define PREHDR_RSLS_SHIFT 31 ++ ++/* ++ * Use a reasonable backlog of frames (per CPU) as congestion threshold, ++ * so that resources used by the in-flight buffers do not become a memory hog. ++ */ ++#define MAX_RSP_FQ_BACKLOG_PER_CPU 256 ++ ++#define CAAM_QI_ENQUEUE_RETRIES 10000 ++ ++#define CAAM_NAPI_WEIGHT 63 ++ ++/* ++ * caam_napi - struct holding CAAM NAPI-related params ++ * @irqtask: IRQ task for QI backend ++ * @p: QMan portal ++ */ ++struct caam_napi { ++ struct napi_struct irqtask; ++ struct qman_portal *p; ++}; ++ ++/* ++ * caam_qi_pcpu_priv - percpu private data structure to main list of pending ++ * responses expected on each cpu. ++ * @caam_napi: CAAM NAPI params ++ * @net_dev: netdev used by NAPI ++ * @rsp_fq: response FQ from CAAM ++ */ ++struct caam_qi_pcpu_priv { ++ struct caam_napi caam_napi; ++ struct net_device net_dev; ++ struct qman_fq *rsp_fq; ++} ____cacheline_aligned; ++ ++static DEFINE_PER_CPU(struct caam_qi_pcpu_priv, pcpu_qipriv); ++static DEFINE_PER_CPU(int, last_cpu); ++ ++/* ++ * caam_qi_priv - CAAM QI backend private params ++ * @cgr: QMan congestion group ++ * @qi_pdev: platform device for QI backend ++ */ ++struct caam_qi_priv { ++ struct qman_cgr cgr; ++ struct platform_device *qi_pdev; ++}; ++ ++static struct caam_qi_priv qipriv ____cacheline_aligned; ++ ++/* ++ * This is written by only one core - the one that initialized the CGR - and ++ * read by multiple cores (all the others). ++ */ ++bool caam_congested __read_mostly; ++EXPORT_SYMBOL(caam_congested); ++ ++#ifdef CONFIG_DEBUG_FS ++/* ++ * This is a counter for the number of times the congestion group (where all ++ * the request and response queueus are) reached congestion. Incremented ++ * each time the congestion callback is called with congested == true. ++ */ ++static u64 times_congested; ++#endif ++ ++/* ++ * CPU from where the module initialised. This is required because QMan driver ++ * requires CGRs to be removed from same CPU from where they were originally ++ * allocated. ++ */ ++static int mod_init_cpu; ++ ++/* ++ * This is a a cache of buffers, from which the users of CAAM QI driver ++ * can allocate short (CAAM_QI_MEMCACHE_SIZE) buffers. It's faster than ++ * doing malloc on the hotpath. ++ * NOTE: A more elegant solution would be to have some headroom in the frames ++ * being processed. This could be added by the dpaa-ethernet driver. ++ * This would pose a problem for userspace application processing which ++ * cannot know of this limitation. So for now, this will work. ++ * NOTE: The memcache is SMP-safe. No need to handle spinlocks in-here ++ */ ++static struct kmem_cache *qi_cache; ++ ++int caam_qi_enqueue(struct device *qidev, struct caam_drv_req *req) ++{ ++ struct qm_fd fd; ++ int ret; ++ int num_retries = 0; ++ ++ fd.cmd = 0; ++ fd.format = qm_fd_compound; ++ fd.cong_weight = req->fd_sgt[1].length; ++ fd.addr = dma_map_single(qidev, req->fd_sgt, sizeof(req->fd_sgt), ++ DMA_BIDIRECTIONAL); ++ if (dma_mapping_error(qidev, fd.addr)) { ++ dev_err(qidev, "DMA mapping error for QI enqueue request\n"); ++ return -EIO; ++ } ++ ++ do { ++ ret = qman_enqueue(req->drv_ctx->req_fq, &fd, 0); ++ if (likely(!ret)) ++ return 0; ++ ++ if (ret != -EBUSY) ++ break; ++ num_retries++; ++ } while (num_retries < CAAM_QI_ENQUEUE_RETRIES); ++ ++ dev_err(qidev, "qman_enqueue failed: %d\n", ret); ++ ++ return ret; ++} ++EXPORT_SYMBOL(caam_qi_enqueue); ++ ++static void caam_fq_ern_cb(struct qman_portal *qm, struct qman_fq *fq, ++ const struct qm_mr_entry *msg) ++{ ++ const struct qm_fd *fd; ++ struct caam_drv_req *drv_req; ++ struct device *qidev = &(raw_cpu_ptr(&pcpu_qipriv)->net_dev.dev); ++ ++ fd = &msg->ern.fd; ++ ++ if (fd->format != qm_fd_compound) { ++ dev_err(qidev, "Non-compound FD from CAAM\n"); ++ return; ++ } ++ ++ drv_req = (struct caam_drv_req *)phys_to_virt(qm_fd_addr_get64(fd)); ++ if (!drv_req) { ++ dev_err(qidev, ++ "Can't find original request for CAAM response\n"); ++ return; ++ } ++ ++ dma_unmap_single(drv_req->drv_ctx->qidev, qm_fd_addr(fd), ++ sizeof(drv_req->fd_sgt), DMA_BIDIRECTIONAL); ++ ++ drv_req->cbk(drv_req, -EIO); ++} ++ ++static struct qman_fq *create_caam_req_fq(struct device *qidev, ++ struct qman_fq *rsp_fq, ++ dma_addr_t hwdesc, ++ int fq_sched_flag) ++{ ++ int ret; ++ struct qman_fq *req_fq; ++ struct qm_mcc_initfq opts; ++ ++ req_fq = kzalloc(sizeof(*req_fq), GFP_ATOMIC); ++ if (!req_fq) ++ return ERR_PTR(-ENOMEM); ++ ++ req_fq->cb.ern = caam_fq_ern_cb; ++ req_fq->cb.fqs = NULL; ++ ++ ret = qman_create_fq(0, QMAN_FQ_FLAG_DYNAMIC_FQID | ++ QMAN_FQ_FLAG_TO_DCPORTAL | QMAN_FQ_FLAG_LOCKED, ++ req_fq); ++ if (ret) { ++ dev_err(qidev, "Failed to create session req FQ\n"); ++ goto create_req_fq_fail; ++ } ++ ++ opts.we_mask = QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_DESTWQ | ++ QM_INITFQ_WE_CONTEXTB | QM_INITFQ_WE_CONTEXTA | ++ QM_INITFQ_WE_CGID; ++ opts.fqd.fq_ctrl = QM_FQCTRL_CPCSTASH | QM_FQCTRL_CGE; ++ opts.fqd.dest.channel = qm_channel_caam; ++ opts.fqd.dest.wq = 2; ++ opts.fqd.context_b = qman_fq_fqid(rsp_fq); ++ opts.fqd.context_a.hi = upper_32_bits(hwdesc); ++ opts.fqd.context_a.lo = lower_32_bits(hwdesc); ++ opts.fqd.cgid = qipriv.cgr.cgrid; ++ ++ ret = qman_init_fq(req_fq, fq_sched_flag, &opts); ++ if (ret) { ++ dev_err(qidev, "Failed to init session req FQ\n"); ++ goto init_req_fq_fail; ++ } ++ ++ dev_dbg(qidev, "Allocated request FQ %u for CPU %u\n", req_fq->fqid, ++ smp_processor_id()); ++ return req_fq; ++ ++init_req_fq_fail: ++ qman_destroy_fq(req_fq, 0); ++create_req_fq_fail: ++ kfree(req_fq); ++ return ERR_PTR(ret); ++} ++ ++static int empty_retired_fq(struct device *qidev, struct qman_fq *fq) ++{ ++ int ret; ++ ++ ret = qman_volatile_dequeue(fq, QMAN_VOLATILE_FLAG_WAIT_INT | ++ QMAN_VOLATILE_FLAG_FINISH, ++ QM_VDQCR_PRECEDENCE_VDQCR | ++ QM_VDQCR_NUMFRAMES_TILLEMPTY); ++ if (ret) { ++ dev_err(qidev, "Volatile dequeue fail for FQ: %u\n", fq->fqid); ++ return ret; ++ } ++ ++ do { ++ struct qman_portal *p; ++ ++ p = qman_get_affine_portal(smp_processor_id()); ++ qman_p_poll_dqrr(p, 16); ++ } while (fq->flags & QMAN_FQ_STATE_NE); ++ ++ return 0; ++} ++ ++static int kill_fq(struct device *qidev, struct qman_fq *fq) ++{ ++ u32 flags; ++ int ret; ++ ++ ret = qman_retire_fq(fq, &flags); ++ if (ret < 0) { ++ dev_err(qidev, "qman_retire_fq failed: %d\n", ret); ++ return ret; ++ } ++ ++ if (!ret) ++ goto empty_fq; ++ ++ /* Async FQ retirement condition */ ++ if (ret == 1) { ++ /* Retry till FQ gets in retired state */ ++ do { ++ msleep(20); ++ } while (fq->state != qman_fq_state_retired); ++ ++ WARN_ON(fq->flags & QMAN_FQ_STATE_BLOCKOOS); ++ WARN_ON(fq->flags & QMAN_FQ_STATE_ORL); ++ } ++ ++empty_fq: ++ if (fq->flags & QMAN_FQ_STATE_NE) { ++ ret = empty_retired_fq(qidev, fq); ++ if (ret) { ++ dev_err(qidev, "empty_retired_fq fail for FQ: %u\n", ++ fq->fqid); ++ return ret; ++ } ++ } ++ ++ ret = qman_oos_fq(fq); ++ if (ret) ++ dev_err(qidev, "OOS of FQID: %u failed\n", fq->fqid); ++ ++ qman_destroy_fq(fq, 0); ++ kfree(fq); ++ ++ return ret; ++} ++ ++static int empty_caam_fq(struct qman_fq *fq) ++{ ++ int ret; ++ struct qm_mcr_queryfq_np np; ++ ++ /* Wait till the older CAAM FQ get empty */ ++ do { ++ ret = qman_query_fq_np(fq, &np); ++ if (ret) ++ return ret; ++ ++ if (!np.frm_cnt) ++ break; ++ ++ msleep(20); ++ } while (1); ++ ++ /* ++ * Give extra time for pending jobs from this FQ in holding tanks ++ * to get processed ++ */ ++ msleep(20); ++ return 0; ++} ++ ++int caam_drv_ctx_update(struct caam_drv_ctx *drv_ctx, u32 *sh_desc) ++{ ++ int ret; ++ u32 num_words; ++ struct qman_fq *new_fq, *old_fq; ++ struct device *qidev = drv_ctx->qidev; ++ ++ num_words = desc_len(sh_desc); ++ if (num_words > MAX_SDLEN) { ++ dev_err(qidev, "Invalid descriptor len: %d words\n", num_words); ++ return -EINVAL; ++ } ++ ++ /* Note down older req FQ */ ++ old_fq = drv_ctx->req_fq; ++ ++ /* Create a new req FQ in parked state */ ++ new_fq = create_caam_req_fq(drv_ctx->qidev, drv_ctx->rsp_fq, ++ drv_ctx->context_a, 0); ++ if (unlikely(IS_ERR_OR_NULL(new_fq))) { ++ dev_err(qidev, "FQ allocation for shdesc update failed\n"); ++ return PTR_ERR(new_fq); ++ } ++ ++ /* Hook up new FQ to context so that new requests keep queuing */ ++ drv_ctx->req_fq = new_fq; ++ ++ /* Empty and remove the older FQ */ ++ ret = empty_caam_fq(old_fq); ++ if (ret) { ++ dev_err(qidev, "Old CAAM FQ empty failed: %d\n", ret); ++ ++ /* We can revert to older FQ */ ++ drv_ctx->req_fq = old_fq; ++ ++ if (kill_fq(qidev, new_fq)) ++ dev_warn(qidev, "New CAAM FQ kill failed\n"); ++ ++ return ret; ++ } ++ ++ /* ++ * Re-initialise pre-header. Set RSLS and SDLEN. ++ * Update the shared descriptor for driver context. ++ */ ++ drv_ctx->prehdr[0] = cpu_to_caam32((1 << PREHDR_RSLS_SHIFT) | ++ num_words); ++ memcpy(drv_ctx->sh_desc, sh_desc, desc_bytes(sh_desc)); ++ dma_sync_single_for_device(qidev, drv_ctx->context_a, ++ sizeof(drv_ctx->sh_desc) + ++ sizeof(drv_ctx->prehdr), ++ DMA_BIDIRECTIONAL); ++ ++ /* Put the new FQ in scheduled state */ ++ ret = qman_schedule_fq(new_fq); ++ if (ret) { ++ dev_err(qidev, "Fail to sched new CAAM FQ, ecode = %d\n", ret); ++ ++ /* ++ * We can kill new FQ and revert to old FQ. ++ * Since the desc is already modified, it is success case ++ */ ++ ++ drv_ctx->req_fq = old_fq; ++ ++ if (kill_fq(qidev, new_fq)) ++ dev_warn(qidev, "New CAAM FQ kill failed\n"); ++ } else if (kill_fq(qidev, old_fq)) { ++ dev_warn(qidev, "Old CAAM FQ kill failed\n"); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(caam_drv_ctx_update); ++ ++struct caam_drv_ctx *caam_drv_ctx_init(struct device *qidev, ++ int *cpu, ++ u32 *sh_desc) ++{ ++ size_t size; ++ u32 num_words; ++ dma_addr_t hwdesc; ++ struct caam_drv_ctx *drv_ctx; ++ const cpumask_t *cpus = qman_affine_cpus(); ++ ++ num_words = desc_len(sh_desc); ++ if (num_words > MAX_SDLEN) { ++ dev_err(qidev, "Invalid descriptor len: %d words\n", ++ num_words); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ drv_ctx = kzalloc(sizeof(*drv_ctx), GFP_ATOMIC); ++ if (!drv_ctx) ++ return ERR_PTR(-ENOMEM); ++ ++ /* ++ * Initialise pre-header - set RSLS and SDLEN - and shared descriptor ++ * and dma-map them. ++ */ ++ drv_ctx->prehdr[0] = cpu_to_caam32((1 << PREHDR_RSLS_SHIFT) | ++ num_words); ++ memcpy(drv_ctx->sh_desc, sh_desc, desc_bytes(sh_desc)); ++ size = sizeof(drv_ctx->prehdr) + sizeof(drv_ctx->sh_desc); ++ hwdesc = dma_map_single(qidev, drv_ctx->prehdr, size, ++ DMA_BIDIRECTIONAL); ++ if (dma_mapping_error(qidev, hwdesc)) { ++ dev_err(qidev, "DMA map error for preheader + shdesc\n"); ++ kfree(drv_ctx); ++ return ERR_PTR(-ENOMEM); ++ } ++ drv_ctx->context_a = hwdesc; ++ ++ /* If given CPU does not own the portal, choose another one that does */ ++ if (!cpumask_test_cpu(*cpu, cpus)) { ++ int *pcpu = &get_cpu_var(last_cpu); ++ ++ *pcpu = cpumask_next(*pcpu, cpus); ++ if (*pcpu >= nr_cpu_ids) ++ *pcpu = cpumask_first(cpus); ++ *cpu = *pcpu; ++ ++ put_cpu_var(last_cpu); ++ } ++ drv_ctx->cpu = *cpu; ++ ++ /* Find response FQ hooked with this CPU */ ++ drv_ctx->rsp_fq = per_cpu(pcpu_qipriv.rsp_fq, drv_ctx->cpu); ++ ++ /* Attach request FQ */ ++ drv_ctx->req_fq = create_caam_req_fq(qidev, drv_ctx->rsp_fq, hwdesc, ++ QMAN_INITFQ_FLAG_SCHED); ++ if (unlikely(IS_ERR_OR_NULL(drv_ctx->req_fq))) { ++ dev_err(qidev, "create_caam_req_fq failed\n"); ++ dma_unmap_single(qidev, hwdesc, size, DMA_BIDIRECTIONAL); ++ kfree(drv_ctx); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ drv_ctx->qidev = qidev; ++ return drv_ctx; ++} ++EXPORT_SYMBOL(caam_drv_ctx_init); ++ ++void *qi_cache_alloc(gfp_t flags) ++{ ++ return kmem_cache_alloc(qi_cache, flags); ++} ++EXPORT_SYMBOL(qi_cache_alloc); ++ ++void qi_cache_free(void *obj) ++{ ++ kmem_cache_free(qi_cache, obj); ++} ++EXPORT_SYMBOL(qi_cache_free); ++ ++static int caam_qi_poll(struct napi_struct *napi, int budget) ++{ ++ struct caam_napi *np = container_of(napi, struct caam_napi, irqtask); ++ ++ int cleaned = qman_p_poll_dqrr(np->p, budget); ++ ++ if (cleaned < budget) { ++ napi_complete(napi); ++ qman_p_irqsource_add(np->p, QM_PIRQ_DQRI); ++ } ++ ++ return cleaned; ++} ++ ++void caam_drv_ctx_rel(struct caam_drv_ctx *drv_ctx) ++{ ++ if (IS_ERR_OR_NULL(drv_ctx)) ++ return; ++ ++ /* Remove request FQ */ ++ if (kill_fq(drv_ctx->qidev, drv_ctx->req_fq)) ++ dev_err(drv_ctx->qidev, "Crypto session req FQ kill failed\n"); ++ ++ dma_unmap_single(drv_ctx->qidev, drv_ctx->context_a, ++ sizeof(drv_ctx->sh_desc) + sizeof(drv_ctx->prehdr), ++ DMA_BIDIRECTIONAL); ++ kfree(drv_ctx); ++} ++EXPORT_SYMBOL(caam_drv_ctx_rel); ++ ++int caam_qi_shutdown(struct device *qidev) ++{ ++ int i, ret; ++ struct caam_qi_priv *priv = dev_get_drvdata(qidev); ++ const cpumask_t *cpus = qman_affine_cpus(); ++ struct cpumask old_cpumask = current->cpus_allowed; ++ ++ for_each_cpu(i, cpus) { ++ struct napi_struct *irqtask; ++ ++ irqtask = &per_cpu_ptr(&pcpu_qipriv.caam_napi, i)->irqtask; ++ napi_disable(irqtask); ++ netif_napi_del(irqtask); ++ ++ if (kill_fq(qidev, per_cpu(pcpu_qipriv.rsp_fq, i))) ++ dev_err(qidev, "Rsp FQ kill failed, cpu: %d\n", i); ++ } ++ ++ /* ++ * QMan driver requires CGRs to be deleted from same CPU from where they ++ * were instantiated. Hence we get the module removal execute from the ++ * same CPU from where it was originally inserted. ++ */ ++ set_cpus_allowed_ptr(current, get_cpu_mask(mod_init_cpu)); ++ ++ ret = qman_delete_cgr(&priv->cgr); ++ if (ret) ++ dev_err(qidev, "Deletion of CGR failed: %d\n", ret); ++ else ++ qman_release_cgrid(priv->cgr.cgrid); ++ ++ kmem_cache_destroy(qi_cache); ++ ++ /* Now that we're done with the CGRs, restore the cpus allowed mask */ ++ set_cpus_allowed_ptr(current, &old_cpumask); ++ ++ platform_device_unregister(priv->qi_pdev); ++ return ret; ++} ++ ++static void cgr_cb(struct qman_portal *qm, struct qman_cgr *cgr, int congested) ++{ ++ caam_congested = congested; ++ ++ if (congested) { ++#ifdef CONFIG_DEBUG_FS ++ times_congested++; ++#endif ++ pr_debug_ratelimited("CAAM entered congestion\n"); ++ ++ } else { ++ pr_debug_ratelimited("CAAM exited congestion\n"); ++ } ++} ++ ++static int caam_qi_napi_schedule(struct qman_portal *p, struct caam_napi *np) ++{ ++ /* ++ * In case of threaded ISR, for RT kernels in_irq() does not return ++ * appropriate value, so use in_serving_softirq to distinguish between ++ * softirq and irq contexts. ++ */ ++ if (unlikely(in_irq() || !in_serving_softirq())) { ++ /* Disable QMan IRQ source and invoke NAPI */ ++ qman_p_irqsource_remove(p, QM_PIRQ_DQRI); ++ np->p = p; ++ napi_schedule(&np->irqtask); ++ return 1; ++ } ++ return 0; ++} ++ ++static enum qman_cb_dqrr_result caam_rsp_fq_dqrr_cb(struct qman_portal *p, ++ struct qman_fq *rsp_fq, ++ const struct qm_dqrr_entry *dqrr) ++{ ++ struct caam_napi *caam_napi = raw_cpu_ptr(&pcpu_qipriv.caam_napi); ++ struct caam_drv_req *drv_req; ++ const struct qm_fd *fd; ++ struct device *qidev = &(raw_cpu_ptr(&pcpu_qipriv)->net_dev.dev); ++ ++ if (caam_qi_napi_schedule(p, caam_napi)) ++ return qman_cb_dqrr_stop; ++ ++ fd = &dqrr->fd; ++ if (unlikely(fd->status)) ++ dev_err(qidev, "Error: %#x in CAAM response FD\n", fd->status); ++ ++ if (unlikely(fd->format != fd->format)) { ++ dev_err(qidev, "Non-compound FD from CAAM\n"); ++ return qman_cb_dqrr_consume; ++ } ++ ++ drv_req = (struct caam_drv_req *)phys_to_virt(fd->addr); ++ if (unlikely(!drv_req)) { ++ dev_err(qidev, ++ "Can't find original request for caam response\n"); ++ return qman_cb_dqrr_consume; ++ } ++ ++ dma_unmap_single(drv_req->drv_ctx->qidev, qm_fd_addr(fd), ++ sizeof(drv_req->fd_sgt), DMA_BIDIRECTIONAL); ++ ++ drv_req->cbk(drv_req, fd->status); ++ return qman_cb_dqrr_consume; ++} ++ ++static int alloc_rsp_fq_cpu(struct device *qidev, unsigned int cpu) ++{ ++ struct qm_mcc_initfq opts; ++ struct qman_fq *fq; ++ int ret; ++ ++ fq = kzalloc(sizeof(*fq), GFP_KERNEL | GFP_DMA); ++ if (!fq) ++ return -ENOMEM; ++ ++ fq->cb.dqrr = caam_rsp_fq_dqrr_cb; ++ ++ ret = qman_create_fq(0, QMAN_FQ_FLAG_NO_ENQUEUE | ++ QMAN_FQ_FLAG_DYNAMIC_FQID, fq); ++ if (ret) { ++ dev_err(qidev, "Rsp FQ create failed\n"); ++ kfree(fq); ++ return -ENODEV; ++ } ++ ++ opts.we_mask = QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_DESTWQ | ++ QM_INITFQ_WE_CONTEXTB | QM_INITFQ_WE_CONTEXTA | ++ QM_INITFQ_WE_CGID; ++ opts.fqd.fq_ctrl = QM_FQCTRL_CTXASTASHING | QM_FQCTRL_CPCSTASH | ++ QM_FQCTRL_CGE; ++ opts.fqd.dest.channel = qman_affine_channel(cpu); ++ opts.fqd.dest.wq = 3; ++ opts.fqd.cgid = qipriv.cgr.cgrid; ++ opts.fqd.context_a.stashing.exclusive = QM_STASHING_EXCL_CTX | ++ QM_STASHING_EXCL_DATA; ++ opts.fqd.context_a.stashing.data_cl = 1; ++ opts.fqd.context_a.stashing.context_cl = 1; ++ ++ ret = qman_init_fq(fq, QMAN_INITFQ_FLAG_SCHED, &opts); ++ if (ret) { ++ dev_err(qidev, "Rsp FQ init failed\n"); ++ kfree(fq); ++ return -ENODEV; ++ } ++ ++ per_cpu(pcpu_qipriv.rsp_fq, cpu) = fq; ++ ++ dev_dbg(qidev, "Allocated response FQ %u for CPU %u", fq->fqid, cpu); ++ return 0; ++} ++ ++static int init_cgr(struct device *qidev) ++{ ++ int ret; ++ struct qm_mcc_initcgr opts; ++ const u64 cpus = *(u64 *)qman_affine_cpus(); ++ const int num_cpus = hweight64(cpus); ++ const u64 val = num_cpus * MAX_RSP_FQ_BACKLOG_PER_CPU; ++ ++ ret = qman_alloc_cgrid(&qipriv.cgr.cgrid); ++ if (ret) { ++ dev_err(qidev, "CGR alloc failed for rsp FQs: %d\n", ret); ++ return ret; ++ } ++ ++ qipriv.cgr.cb = cgr_cb; ++ memset(&opts, 0, sizeof(opts)); ++ opts.we_mask = QM_CGR_WE_CSCN_EN | QM_CGR_WE_CS_THRES | QM_CGR_WE_MODE; ++ opts.cgr.cscn_en = QM_CGR_EN; ++ opts.cgr.mode = QMAN_CGR_MODE_FRAME; ++ qm_cgr_cs_thres_set64(&opts.cgr.cs_thres, val, 1); ++ ++ ret = qman_create_cgr(&qipriv.cgr, QMAN_CGR_FLAG_USE_INIT, &opts); ++ if (ret) { ++ dev_err(qidev, "Error %d creating CAAM CGRID: %u\n", ret, ++ qipriv.cgr.cgrid); ++ return ret; ++ } ++ ++ dev_dbg(qidev, "Congestion threshold set to %llu\n", val); ++ return 0; ++} ++ ++static int alloc_rsp_fqs(struct device *qidev) ++{ ++ int ret, i; ++ const cpumask_t *cpus = qman_affine_cpus(); ++ ++ /*Now create response FQs*/ ++ for_each_cpu(i, cpus) { ++ ret = alloc_rsp_fq_cpu(qidev, i); ++ if (ret) { ++ dev_err(qidev, "CAAM rsp FQ alloc failed, cpu: %u", i); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static void free_rsp_fqs(void) ++{ ++ int i; ++ const cpumask_t *cpus = qman_affine_cpus(); ++ ++ for_each_cpu(i, cpus) ++ kfree(per_cpu(pcpu_qipriv.rsp_fq, i)); ++} ++ ++int caam_qi_init(struct platform_device *caam_pdev) ++{ ++ int err, i; ++ struct platform_device *qi_pdev; ++ struct device *ctrldev = &caam_pdev->dev, *qidev; ++ struct caam_drv_private *ctrlpriv; ++ const cpumask_t *cpus = qman_affine_cpus(); ++ struct cpumask old_cpumask = current->cpus_allowed; ++ static struct platform_device_info qi_pdev_info = { ++ .name = "caam_qi", ++ .id = PLATFORM_DEVID_NONE ++ }; ++ ++ /* ++ * QMAN requires CGRs to be removed from same CPU+portal from where it ++ * was originally allocated. Hence we need to note down the ++ * initialisation CPU and use the same CPU for module exit. ++ * We select the first CPU to from the list of portal owning CPUs. ++ * Then we pin module init to this CPU. ++ */ ++ mod_init_cpu = cpumask_first(cpus); ++ set_cpus_allowed_ptr(current, get_cpu_mask(mod_init_cpu)); ++ ++ qi_pdev_info.parent = ctrldev; ++ qi_pdev_info.dma_mask = dma_get_mask(ctrldev); ++ qi_pdev = platform_device_register_full(&qi_pdev_info); ++ if (IS_ERR(qi_pdev)) ++ return PTR_ERR(qi_pdev); ++ arch_setup_dma_ops(&qi_pdev->dev, 0, 0, NULL, true); ++ ++ ctrlpriv = dev_get_drvdata(ctrldev); ++ qidev = &qi_pdev->dev; ++ ++ qipriv.qi_pdev = qi_pdev; ++ dev_set_drvdata(qidev, &qipriv); ++ ++ /* Initialize the congestion detection */ ++ err = init_cgr(qidev); ++ if (err) { ++ dev_err(qidev, "CGR initialization failed: %d\n", err); ++ platform_device_unregister(qi_pdev); ++ return err; ++ } ++ ++ /* Initialise response FQs */ ++ err = alloc_rsp_fqs(qidev); ++ if (err) { ++ dev_err(qidev, "Can't allocate CAAM response FQs: %d\n", err); ++ free_rsp_fqs(); ++ platform_device_unregister(qi_pdev); ++ return err; ++ } ++ ++ /* ++ * Enable the NAPI contexts on each of the core which has an affine ++ * portal. ++ */ ++ for_each_cpu(i, cpus) { ++ struct caam_qi_pcpu_priv *priv = per_cpu_ptr(&pcpu_qipriv, i); ++ struct caam_napi *caam_napi = &priv->caam_napi; ++ struct napi_struct *irqtask = &caam_napi->irqtask; ++ struct net_device *net_dev = &priv->net_dev; ++ ++ net_dev->dev = *qidev; ++ INIT_LIST_HEAD(&net_dev->napi_list); ++ ++ netif_napi_add(net_dev, irqtask, caam_qi_poll, ++ CAAM_NAPI_WEIGHT); ++ ++ napi_enable(irqtask); ++ } ++ ++ /* Hook up QI device to parent controlling caam device */ ++ ctrlpriv->qidev = qidev; ++ ++ qi_cache = kmem_cache_create("caamqicache", CAAM_QI_MEMCACHE_SIZE, 0, ++ SLAB_CACHE_DMA, NULL); ++ if (!qi_cache) { ++ dev_err(qidev, "Can't allocate CAAM cache\n"); ++ free_rsp_fqs(); ++ platform_device_unregister(qi_pdev); ++ return -ENOMEM; ++ } ++ ++ /* Done with the CGRs; restore the cpus allowed mask */ ++ set_cpus_allowed_ptr(current, &old_cpumask); ++#ifdef CONFIG_DEBUG_FS ++ debugfs_create_file("qi_congested", 0444, ctrlpriv->ctl, ++ ×_congested, &caam_fops_u64_ro); ++#endif ++ dev_info(qidev, "Linux CAAM Queue I/F driver initialised\n"); ++ return 0; ++} +diff --git a/drivers/crypto/caam/qi.h b/drivers/crypto/caam/qi.h +new file mode 100644 +index 00000000..0c2e68b3 +--- /dev/null ++++ b/drivers/crypto/caam/qi.h +@@ -0,0 +1,204 @@ ++/* ++ * Public definitions for the CAAM/QI (Queue Interface) backend. ++ * ++ * Copyright 2013-2016 Freescale Semiconductor, Inc. ++ * Copyright 2016-2017 NXP ++ */ ++ ++#ifndef __QI_H__ ++#define __QI_H__ ++ ++#include ++#include "compat.h" ++#include "desc.h" ++#include "desc_constr.h" ++ ++/* ++ * CAAM hardware constructs a job descriptor which points to a shared descriptor ++ * (as pointed by context_a of to-CAAM FQ). ++ * When the job descriptor is executed by DECO, the whole job descriptor ++ * together with shared descriptor gets loaded in DECO buffer, which is ++ * 64 words (each 32-bit) long. ++ * ++ * The job descriptor constructed by CAAM hardware has the following layout: ++ * ++ * HEADER (1 word) ++ * Shdesc ptr (1 or 2 words) ++ * SEQ_OUT_PTR (1 word) ++ * Out ptr (1 or 2 words) ++ * Out length (1 word) ++ * SEQ_IN_PTR (1 word) ++ * In ptr (1 or 2 words) ++ * In length (1 word) ++ * ++ * The shdesc ptr is used to fetch shared descriptor contents into DECO buffer. ++ * ++ * Apart from shdesc contents, the total number of words that get loaded in DECO ++ * buffer are '8' or '11'. The remaining words in DECO buffer can be used for ++ * storing shared descriptor. ++ */ ++#define MAX_SDLEN ((CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN) / CAAM_CMD_SZ) ++ ++/* Length of a single buffer in the QI driver memory cache */ ++#define CAAM_QI_MEMCACHE_SIZE 768 ++ ++extern bool caam_congested __read_mostly; ++ ++/* ++ * This is the request structure the driver application should fill while ++ * submitting a job to driver. ++ */ ++struct caam_drv_req; ++ ++/* ++ * caam_qi_cbk - application's callback function invoked by the driver when the ++ * request has been successfully processed. ++ * @drv_req: original request that was submitted ++ * @status: completion status of request (0 - success, non-zero - error code) ++ */ ++typedef void (*caam_qi_cbk)(struct caam_drv_req *drv_req, u32 status); ++ ++enum optype { ++ ENCRYPT, ++ DECRYPT, ++ GIVENCRYPT, ++ NUM_OP ++}; ++ ++/** ++ * caam_drv_ctx - CAAM/QI backend driver context ++ * ++ * The jobs are processed by the driver against a driver context. ++ * With every cryptographic context, a driver context is attached. ++ * The driver context contains data for private use by driver. ++ * For the applications, this is an opaque structure. ++ * ++ * @prehdr: preheader placed before shrd desc ++ * @sh_desc: shared descriptor ++ * @context_a: shared descriptor dma address ++ * @req_fq: to-CAAM request frame queue ++ * @rsp_fq: from-CAAM response frame queue ++ * @cpu: cpu on which to receive CAAM response ++ * @op_type: operation type ++ * @qidev: device pointer for CAAM/QI backend ++ */ ++struct caam_drv_ctx { ++ u32 prehdr[2]; ++ u32 sh_desc[MAX_SDLEN]; ++ dma_addr_t context_a; ++ struct qman_fq *req_fq; ++ struct qman_fq *rsp_fq; ++ int cpu; ++ enum optype op_type; ++ struct device *qidev; ++} ____cacheline_aligned; ++ ++/** ++ * caam_drv_req - The request structure the driver application should fill while ++ * submitting a job to driver. ++ * @fd_sgt: QMan S/G pointing to output (fd_sgt[0]) and input (fd_sgt[1]) ++ * buffers. ++ * @cbk: callback function to invoke when job is completed ++ * @app_ctx: arbitrary context attached with request by the application ++ * ++ * The fields mentioned below should not be used by application. ++ * These are for private use by driver. ++ * ++ * @hdr__: linked list header to maintain list of outstanding requests to CAAM ++ * @hwaddr: DMA address for the S/G table. ++ */ ++struct caam_drv_req { ++ struct qm_sg_entry fd_sgt[2]; ++ struct caam_drv_ctx *drv_ctx; ++ caam_qi_cbk cbk; ++ void *app_ctx; ++} ____cacheline_aligned; ++ ++/** ++ * caam_drv_ctx_init - Initialise a CAAM/QI driver context ++ * ++ * A CAAM/QI driver context must be attached with each cryptographic context. ++ * This function allocates memory for CAAM/QI context and returns a handle to ++ * the application. This handle must be submitted along with each enqueue ++ * request to the driver by the application. ++ * ++ * @cpu: CPU where the application prefers to the driver to receive CAAM ++ * responses. The request completion callback would be issued from this ++ * CPU. ++ * @sh_desc: shared descriptor pointer to be attached with CAAM/QI driver ++ * context. ++ * ++ * Returns a driver context on success or negative error code on failure. ++ */ ++struct caam_drv_ctx *caam_drv_ctx_init(struct device *qidev, int *cpu, ++ u32 *sh_desc); ++ ++/** ++ * caam_qi_enqueue - Submit a request to QI backend driver. ++ * ++ * The request structure must be properly filled as described above. ++ * ++ * @qidev: device pointer for QI backend ++ * @req: CAAM QI request structure ++ * ++ * Returns 0 on success or negative error code on failure. ++ */ ++int caam_qi_enqueue(struct device *qidev, struct caam_drv_req *req); ++ ++/** ++ * caam_drv_ctx_busy - Check if there are too many jobs pending with CAAM ++ * or too many CAAM responses are pending to be processed. ++ * @drv_ctx: driver context for which job is to be submitted ++ * ++ * Returns caam congestion status 'true/false' ++ */ ++bool caam_drv_ctx_busy(struct caam_drv_ctx *drv_ctx); ++ ++/** ++ * caam_drv_ctx_update - Update QI driver context ++ * ++ * Invoked when shared descriptor is required to be change in driver context. ++ * ++ * @drv_ctx: driver context to be updated ++ * @sh_desc: new shared descriptor pointer to be updated in QI driver context ++ * ++ * Returns 0 on success or negative error code on failure. ++ */ ++int caam_drv_ctx_update(struct caam_drv_ctx *drv_ctx, u32 *sh_desc); ++ ++/** ++ * caam_drv_ctx_rel - Release a QI driver context ++ * @drv_ctx: context to be released ++ */ ++void caam_drv_ctx_rel(struct caam_drv_ctx *drv_ctx); ++ ++int caam_qi_init(struct platform_device *pdev); ++int caam_qi_shutdown(struct device *dev); ++ ++/** ++ * qi_cache_alloc - Allocate buffers from CAAM-QI cache ++ * ++ * Invoked when a user of the CAAM-QI (i.e. caamalg-qi) needs data which has ++ * to be allocated on the hotpath. Instead of using malloc, one can use the ++ * services of the CAAM QI memory cache (backed by kmem_cache). The buffers ++ * will have a size of 256B, which is sufficient for hosting 16 SG entries. ++ * ++ * @flags: flags that would be used for the equivalent malloc(..) call ++ * ++ * Returns a pointer to a retrieved buffer on success or NULL on failure. ++ */ ++void *qi_cache_alloc(gfp_t flags); ++ ++/** ++ * qi_cache_free - Frees buffers allocated from CAAM-QI cache ++ * ++ * Invoked when a user of the CAAM-QI (i.e. caamalg-qi) no longer needs ++ * the buffer previously allocated by a qi_cache_alloc call. ++ * No checking is being done, the call is a passthrough call to ++ * kmem_cache_free(...) ++ * ++ * @obj: object previously allocated using qi_cache_alloc() ++ */ ++void qi_cache_free(void *obj); ++ ++#endif /* __QI_H__ */ +diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h +index 84d2f838..74eb8c6c 100644 +--- a/drivers/crypto/caam/regs.h ++++ b/drivers/crypto/caam/regs.h +@@ -2,6 +2,7 @@ + * CAAM hardware register-level view + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. ++ * Copyright 2017 NXP + */ + + #ifndef REGS_H +@@ -67,6 +68,7 @@ + */ + + extern bool caam_little_end; ++extern bool caam_imx; + + #define caam_to_cpu(len) \ + static inline u##len caam##len ## _to_cpu(u##len val) \ +@@ -154,13 +156,10 @@ static inline u64 rd_reg64(void __iomem *reg) + #else /* CONFIG_64BIT */ + static inline void wr_reg64(void __iomem *reg, u64 data) + { +-#ifndef CONFIG_CRYPTO_DEV_FSL_CAAM_IMX +- if (caam_little_end) { ++ if (!caam_imx && caam_little_end) { + wr_reg32((u32 __iomem *)(reg) + 1, data >> 32); + wr_reg32((u32 __iomem *)(reg), data); +- } else +-#endif +- { ++ } else { + wr_reg32((u32 __iomem *)(reg), data >> 32); + wr_reg32((u32 __iomem *)(reg) + 1, data); + } +@@ -168,41 +167,40 @@ static inline void wr_reg64(void __iomem *reg, u64 data) + + static inline u64 rd_reg64(void __iomem *reg) + { +-#ifndef CONFIG_CRYPTO_DEV_FSL_CAAM_IMX +- if (caam_little_end) ++ if (!caam_imx && caam_little_end) + return ((u64)rd_reg32((u32 __iomem *)(reg) + 1) << 32 | + (u64)rd_reg32((u32 __iomem *)(reg))); +- else +-#endif +- return ((u64)rd_reg32((u32 __iomem *)(reg)) << 32 | +- (u64)rd_reg32((u32 __iomem *)(reg) + 1)); ++ ++ return ((u64)rd_reg32((u32 __iomem *)(reg)) << 32 | ++ (u64)rd_reg32((u32 __iomem *)(reg) + 1)); + } + #endif /* CONFIG_64BIT */ + ++static inline u64 cpu_to_caam_dma64(dma_addr_t value) ++{ ++ if (caam_imx) ++ return (((u64)cpu_to_caam32(lower_32_bits(value)) << 32) | ++ (u64)cpu_to_caam32(upper_32_bits(value))); ++ ++ return cpu_to_caam64(value); ++} ++ ++static inline u64 caam_dma64_to_cpu(u64 value) ++{ ++ if (caam_imx) ++ return (((u64)caam32_to_cpu(lower_32_bits(value)) << 32) | ++ (u64)caam32_to_cpu(upper_32_bits(value))); ++ ++ return caam64_to_cpu(value); ++} ++ + #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT +-#ifdef CONFIG_SOC_IMX7D +-#define cpu_to_caam_dma(value) \ +- (((u64)cpu_to_caam32(lower_32_bits(value)) << 32) | \ +- (u64)cpu_to_caam32(upper_32_bits(value))) +-#define caam_dma_to_cpu(value) \ +- (((u64)caam32_to_cpu(lower_32_bits(value)) << 32) | \ +- (u64)caam32_to_cpu(upper_32_bits(value))) +-#else +-#define cpu_to_caam_dma(value) cpu_to_caam64(value) +-#define caam_dma_to_cpu(value) caam64_to_cpu(value) +-#endif /* CONFIG_SOC_IMX7D */ ++#define cpu_to_caam_dma(value) cpu_to_caam_dma64(value) ++#define caam_dma_to_cpu(value) caam_dma64_to_cpu(value) + #else + #define cpu_to_caam_dma(value) cpu_to_caam32(value) + #define caam_dma_to_cpu(value) caam32_to_cpu(value) +-#endif /* CONFIG_ARCH_DMA_ADDR_T_64BIT */ +- +-#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_IMX +-#define cpu_to_caam_dma64(value) \ +- (((u64)cpu_to_caam32(lower_32_bits(value)) << 32) | \ +- (u64)cpu_to_caam32(upper_32_bits(value))) +-#else +-#define cpu_to_caam_dma64(value) cpu_to_caam64(value) +-#endif ++#endif /* CONFIG_ARCH_DMA_ADDR_T_64BIT */ + + /* + * jr_outentry +@@ -293,6 +291,7 @@ struct caam_perfmon { + u32 cha_rev_ls; /* CRNR - CHA Rev No. Least significant half*/ + #define CTPR_MS_QI_SHIFT 25 + #define CTPR_MS_QI_MASK (0x1ull << CTPR_MS_QI_SHIFT) ++#define CTPR_MS_DPAA2 BIT(13) + #define CTPR_MS_VIRT_EN_INCL 0x00000001 + #define CTPR_MS_VIRT_EN_POR 0x00000002 + #define CTPR_MS_PG_SZ_MASK 0x10 +@@ -628,6 +627,8 @@ struct caam_job_ring { + #define JRSTA_DECOERR_INVSIGN 0x86 + #define JRSTA_DECOERR_DSASIGN 0x87 + ++#define JRSTA_QIERR_ERROR_MASK 0x00ff ++ + #define JRSTA_CCBERR_JUMP 0x08000000 + #define JRSTA_CCBERR_INDEX_MASK 0xff00 + #define JRSTA_CCBERR_INDEX_SHIFT 8 +diff --git a/drivers/crypto/caam/sg_sw_qm.h b/drivers/crypto/caam/sg_sw_qm.h +new file mode 100644 +index 00000000..3b3cabc4 +--- /dev/null ++++ b/drivers/crypto/caam/sg_sw_qm.h +@@ -0,0 +1,126 @@ ++/* ++ * Copyright 2013-2016 Freescale Semiconductor, Inc. ++ * Copyright 2016-2017 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of Freescale Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __SG_SW_QM_H ++#define __SG_SW_QM_H ++ ++#include ++#include "regs.h" ++ ++static inline void cpu_to_hw_sg(struct qm_sg_entry *qm_sg_ptr) ++{ ++ dma_addr_t addr = qm_sg_ptr->opaque; ++ ++ qm_sg_ptr->opaque = cpu_to_caam64(addr); ++ qm_sg_ptr->sgt_efl = cpu_to_caam32(qm_sg_ptr->sgt_efl); ++} ++ ++static inline void __dma_to_qm_sg(struct qm_sg_entry *qm_sg_ptr, dma_addr_t dma, ++ u32 len, u16 offset) ++{ ++ qm_sg_ptr->addr = dma; ++ qm_sg_ptr->length = len; ++ qm_sg_ptr->__reserved2 = 0; ++ qm_sg_ptr->bpid = 0; ++ qm_sg_ptr->__reserved3 = 0; ++ qm_sg_ptr->offset = offset & QM_SG_OFFSET_MASK; ++ ++ cpu_to_hw_sg(qm_sg_ptr); ++} ++ ++static inline void dma_to_qm_sg_one(struct qm_sg_entry *qm_sg_ptr, ++ dma_addr_t dma, u32 len, u16 offset) ++{ ++ qm_sg_ptr->extension = 0; ++ qm_sg_ptr->final = 0; ++ __dma_to_qm_sg(qm_sg_ptr, dma, len, offset); ++} ++ ++static inline void dma_to_qm_sg_one_last(struct qm_sg_entry *qm_sg_ptr, ++ dma_addr_t dma, u32 len, u16 offset) ++{ ++ qm_sg_ptr->extension = 0; ++ qm_sg_ptr->final = 1; ++ __dma_to_qm_sg(qm_sg_ptr, dma, len, offset); ++} ++ ++static inline void dma_to_qm_sg_one_ext(struct qm_sg_entry *qm_sg_ptr, ++ dma_addr_t dma, u32 len, u16 offset) ++{ ++ qm_sg_ptr->extension = 1; ++ qm_sg_ptr->final = 0; ++ __dma_to_qm_sg(qm_sg_ptr, dma, len, offset); ++} ++ ++static inline void dma_to_qm_sg_one_last_ext(struct qm_sg_entry *qm_sg_ptr, ++ dma_addr_t dma, u32 len, ++ u16 offset) ++{ ++ qm_sg_ptr->extension = 1; ++ qm_sg_ptr->final = 1; ++ __dma_to_qm_sg(qm_sg_ptr, dma, len, offset); ++} ++ ++/* ++ * convert scatterlist to h/w link table format ++ * but does not have final bit; instead, returns last entry ++ */ ++static inline struct qm_sg_entry * ++sg_to_qm_sg(struct scatterlist *sg, int sg_count, ++ struct qm_sg_entry *qm_sg_ptr, u16 offset) ++{ ++ while (sg_count && sg) { ++ dma_to_qm_sg_one(qm_sg_ptr, sg_dma_address(sg), ++ sg_dma_len(sg), offset); ++ qm_sg_ptr++; ++ sg = sg_next(sg); ++ sg_count--; ++ } ++ return qm_sg_ptr - 1; ++} ++ ++/* ++ * convert scatterlist to h/w link table format ++ * scatterlist must have been previously dma mapped ++ */ ++static inline void sg_to_qm_sg_last(struct scatterlist *sg, int sg_count, ++ struct qm_sg_entry *qm_sg_ptr, u16 offset) ++{ ++ qm_sg_ptr = sg_to_qm_sg(sg, sg_count, qm_sg_ptr, offset); ++ ++ qm_sg_ptr->sgt_efl = caam32_to_cpu(qm_sg_ptr->sgt_efl); ++ qm_sg_ptr->final = 1; ++ qm_sg_ptr->sgt_efl = cpu_to_caam32(qm_sg_ptr->sgt_efl); ++} ++ ++#endif /* __SG_SW_QM_H */ +diff --git a/drivers/crypto/caam/sg_sw_qm2.h b/drivers/crypto/caam/sg_sw_qm2.h +new file mode 100644 +index 00000000..31b44075 +--- /dev/null ++++ b/drivers/crypto/caam/sg_sw_qm2.h +@@ -0,0 +1,81 @@ ++/* ++ * Copyright 2015-2016 Freescale Semiconductor, Inc. ++ * Copyright 2017 NXP ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the names of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef _SG_SW_QM2_H_ ++#define _SG_SW_QM2_H_ ++ ++#include "../../../drivers/staging/fsl-mc/include/dpaa2-fd.h" ++ ++static inline void dma_to_qm_sg_one(struct dpaa2_sg_entry *qm_sg_ptr, ++ dma_addr_t dma, u32 len, u16 offset) ++{ ++ dpaa2_sg_set_addr(qm_sg_ptr, dma); ++ dpaa2_sg_set_format(qm_sg_ptr, dpaa2_sg_single); ++ dpaa2_sg_set_final(qm_sg_ptr, false); ++ dpaa2_sg_set_len(qm_sg_ptr, len); ++ dpaa2_sg_set_bpid(qm_sg_ptr, 0); ++ dpaa2_sg_set_offset(qm_sg_ptr, offset); ++} ++ ++/* ++ * convert scatterlist to h/w link table format ++ * but does not have final bit; instead, returns last entry ++ */ ++static inline struct dpaa2_sg_entry * ++sg_to_qm_sg(struct scatterlist *sg, int sg_count, ++ struct dpaa2_sg_entry *qm_sg_ptr, u16 offset) ++{ ++ while (sg_count && sg) { ++ dma_to_qm_sg_one(qm_sg_ptr, sg_dma_address(sg), ++ sg_dma_len(sg), offset); ++ qm_sg_ptr++; ++ sg = sg_next(sg); ++ sg_count--; ++ } ++ return qm_sg_ptr - 1; ++} ++ ++/* ++ * convert scatterlist to h/w link table format ++ * scatterlist must have been previously dma mapped ++ */ ++static inline void sg_to_qm_sg_last(struct scatterlist *sg, int sg_count, ++ struct dpaa2_sg_entry *qm_sg_ptr, ++ u16 offset) ++{ ++ qm_sg_ptr = sg_to_qm_sg(sg, sg_count, qm_sg_ptr, offset); ++ dpaa2_sg_set_final(qm_sg_ptr, true); ++} ++ ++#endif /* _SG_SW_QM2_H_ */ +diff --git a/drivers/crypto/caam/sg_sw_sec4.h b/drivers/crypto/caam/sg_sw_sec4.h +index 41cd5a35..936b1b63 100644 +--- a/drivers/crypto/caam/sg_sw_sec4.h ++++ b/drivers/crypto/caam/sg_sw_sec4.h +@@ -5,9 +5,19 @@ + * + */ + ++#ifndef _SG_SW_SEC4_H_ ++#define _SG_SW_SEC4_H_ ++ ++#include "ctrl.h" + #include "regs.h" ++#include "sg_sw_qm2.h" ++#include "../../../drivers/staging/fsl-mc/include/dpaa2-fd.h" + +-struct sec4_sg_entry; ++struct sec4_sg_entry { ++ u64 ptr; ++ u32 len; ++ u32 bpid_offset; ++}; + + /* + * convert single dma address to h/w link table format +@@ -15,9 +25,15 @@ struct sec4_sg_entry; + static inline void dma_to_sec4_sg_one(struct sec4_sg_entry *sec4_sg_ptr, + dma_addr_t dma, u32 len, u16 offset) + { +- sec4_sg_ptr->ptr = cpu_to_caam_dma64(dma); +- sec4_sg_ptr->len = cpu_to_caam32(len); +- sec4_sg_ptr->bpid_offset = cpu_to_caam32(offset & SEC4_SG_OFFSET_MASK); ++ if (caam_dpaa2) { ++ dma_to_qm_sg_one((struct dpaa2_sg_entry *)sec4_sg_ptr, dma, len, ++ offset); ++ } else { ++ sec4_sg_ptr->ptr = cpu_to_caam_dma64(dma); ++ sec4_sg_ptr->len = cpu_to_caam32(len); ++ sec4_sg_ptr->bpid_offset = cpu_to_caam32(offset & ++ SEC4_SG_OFFSET_MASK); ++ } + #ifdef DEBUG + print_hex_dump(KERN_ERR, "sec4_sg_ptr@: ", + DUMP_PREFIX_ADDRESS, 16, 4, sec4_sg_ptr, +@@ -43,6 +59,14 @@ sg_to_sec4_sg(struct scatterlist *sg, int sg_count, + return sec4_sg_ptr - 1; + } + ++static inline void sg_to_sec4_set_last(struct sec4_sg_entry *sec4_sg_ptr) ++{ ++ if (caam_dpaa2) ++ dpaa2_sg_set_final((struct dpaa2_sg_entry *)sec4_sg_ptr, true); ++ else ++ sec4_sg_ptr->len |= cpu_to_caam32(SEC4_SG_LEN_FIN); ++} ++ + /* + * convert scatterlist to h/w link table format + * scatterlist must have been previously dma mapped +@@ -52,31 +76,7 @@ static inline void sg_to_sec4_sg_last(struct scatterlist *sg, int sg_count, + u16 offset) + { + sec4_sg_ptr = sg_to_sec4_sg(sg, sg_count, sec4_sg_ptr, offset); +- sec4_sg_ptr->len |= cpu_to_caam32(SEC4_SG_LEN_FIN); +-} +- +-static inline struct sec4_sg_entry *sg_to_sec4_sg_len( +- struct scatterlist *sg, unsigned int total, +- struct sec4_sg_entry *sec4_sg_ptr) +-{ +- do { +- unsigned int len = min(sg_dma_len(sg), total); +- +- dma_to_sec4_sg_one(sec4_sg_ptr, sg_dma_address(sg), len, 0); +- sec4_sg_ptr++; +- sg = sg_next(sg); +- total -= len; +- } while (total); +- return sec4_sg_ptr - 1; ++ sg_to_sec4_set_last(sec4_sg_ptr); + } + +-/* derive number of elements in scatterlist, but return 0 for 1 */ +-static inline int sg_count(struct scatterlist *sg_list, int nbytes) +-{ +- int sg_nents = sg_nents_for_len(sg_list, nbytes); +- +- if (likely(sg_nents == 1)) +- return 0; +- +- return sg_nents; +-} ++#endif /* _SG_SW_SEC4_H_ */ +diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c +index ef5d394f..cc8deece 100644 +--- a/drivers/net/wireless/rsi/rsi_91x_usb.c ++++ b/drivers/net/wireless/rsi/rsi_91x_usb.c +@@ -516,7 +516,7 @@ static int rsi_probe(struct usb_interface *pfunction, + + /** + * rsi_disconnect() - This function performs the reverse of the probe function, +- * it deintialize the driver structure. ++ * it deinitialize the driver structure. + * @pfunction: Pointer to the USB interface structure. + * + * Return: None. +diff --git a/drivers/staging/wilc1000/linux_wlan.c b/drivers/staging/wilc1000/linux_wlan.c +index defffa75..ec88ed9c 100644 +--- a/drivers/staging/wilc1000/linux_wlan.c ++++ b/drivers/staging/wilc1000/linux_wlan.c +@@ -211,7 +211,7 @@ static void deinit_irq(struct net_device *dev) + vif = netdev_priv(dev); + wilc = vif->wilc; + +- /* Deintialize IRQ */ ++ /* Deinitialize IRQ */ + if (wilc->dev_irq_num) { + free_irq(wilc->dev_irq_num, wilc); + gpio_free(wilc->gpio); +diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +index 60d8b055..02d3e721 100644 +--- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c ++++ b/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +@@ -2359,7 +2359,7 @@ int wilc_deinit_host_int(struct net_device *net) + del_timer_sync(&wilc_during_ip_timer); + + if (s32Error) +- netdev_err(net, "Error while deintializing host interface\n"); ++ netdev_err(net, "Error while deinitializing host interface\n"); + + return s32Error; + } +diff --git a/include/crypto/acompress.h b/include/crypto/acompress.h +new file mode 100644 +index 00000000..e328b524 +--- /dev/null ++++ b/include/crypto/acompress.h +@@ -0,0 +1,269 @@ ++/* ++ * Asynchronous Compression operations ++ * ++ * Copyright (c) 2016, Intel Corporation ++ * Authors: Weigang Li ++ * Giovanni Cabiddu ++ * ++ * 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. ++ * ++ */ ++#ifndef _CRYPTO_ACOMP_H ++#define _CRYPTO_ACOMP_H ++#include ++ ++#define CRYPTO_ACOMP_ALLOC_OUTPUT 0x00000001 ++ ++/** ++ * struct acomp_req - asynchronous (de)compression request ++ * ++ * @base: Common attributes for asynchronous crypto requests ++ * @src: Source Data ++ * @dst: Destination data ++ * @slen: Size of the input buffer ++ * @dlen: Size of the output buffer and number of bytes produced ++ * @flags: Internal flags ++ * @__ctx: Start of private context data ++ */ ++struct acomp_req { ++ struct crypto_async_request base; ++ struct scatterlist *src; ++ struct scatterlist *dst; ++ unsigned int slen; ++ unsigned int dlen; ++ u32 flags; ++ void *__ctx[] CRYPTO_MINALIGN_ATTR; ++}; ++ ++/** ++ * struct crypto_acomp - user-instantiated objects which encapsulate ++ * algorithms and core processing logic ++ * ++ * @compress: Function performs a compress operation ++ * @decompress: Function performs a de-compress operation ++ * @dst_free: Frees destination buffer if allocated inside the ++ * algorithm ++ * @reqsize: Context size for (de)compression requests ++ * @base: Common crypto API algorithm data structure ++ */ ++struct crypto_acomp { ++ int (*compress)(struct acomp_req *req); ++ int (*decompress)(struct acomp_req *req); ++ void (*dst_free)(struct scatterlist *dst); ++ unsigned int reqsize; ++ struct crypto_tfm base; ++}; ++ ++/** ++ * struct acomp_alg - asynchronous compression algorithm ++ * ++ * @compress: Function performs a compress operation ++ * @decompress: Function performs a de-compress operation ++ * @dst_free: Frees destination buffer if allocated inside the algorithm ++ * @init: Initialize the cryptographic transformation object. ++ * This function is used to initialize the cryptographic ++ * transformation object. This function is called only once at ++ * the instantiation time, right after the transformation context ++ * was allocated. In case the cryptographic hardware has some ++ * special requirements which need to be handled by software, this ++ * function shall check for the precise requirement of the ++ * transformation and put any software fallbacks in place. ++ * @exit: Deinitialize the cryptographic transformation object. This is a ++ * counterpart to @init, used to remove various changes set in ++ * @init. ++ * ++ * @reqsize: Context size for (de)compression requests ++ * @base: Common crypto API algorithm data structure ++ */ ++struct acomp_alg { ++ int (*compress)(struct acomp_req *req); ++ int (*decompress)(struct acomp_req *req); ++ void (*dst_free)(struct scatterlist *dst); ++ int (*init)(struct crypto_acomp *tfm); ++ void (*exit)(struct crypto_acomp *tfm); ++ unsigned int reqsize; ++ struct crypto_alg base; ++}; ++ ++/** ++ * DOC: Asynchronous Compression API ++ * ++ * The Asynchronous Compression API is used with the algorithms of type ++ * CRYPTO_ALG_TYPE_ACOMPRESS (listed as type "acomp" in /proc/crypto) ++ */ ++ ++/** ++ * crypto_alloc_acomp() -- allocate ACOMPRESS tfm handle ++ * @alg_name: is the cra_name / name or cra_driver_name / driver name of the ++ * compression algorithm e.g. "deflate" ++ * @type: specifies the type of the algorithm ++ * @mask: specifies the mask for the algorithm ++ * ++ * Allocate a handle for a compression algorithm. The returned struct ++ * crypto_acomp is the handle that is required for any subsequent ++ * API invocation for the compression operations. ++ * ++ * Return: allocated handle in case of success; IS_ERR() is true in case ++ * of an error, PTR_ERR() returns the error code. ++ */ ++struct crypto_acomp *crypto_alloc_acomp(const char *alg_name, u32 type, ++ u32 mask); ++ ++static inline struct crypto_tfm *crypto_acomp_tfm(struct crypto_acomp *tfm) ++{ ++ return &tfm->base; ++} ++ ++static inline struct acomp_alg *__crypto_acomp_alg(struct crypto_alg *alg) ++{ ++ return container_of(alg, struct acomp_alg, base); ++} ++ ++static inline struct crypto_acomp *__crypto_acomp_tfm(struct crypto_tfm *tfm) ++{ ++ return container_of(tfm, struct crypto_acomp, base); ++} ++ ++static inline struct acomp_alg *crypto_acomp_alg(struct crypto_acomp *tfm) ++{ ++ return __crypto_acomp_alg(crypto_acomp_tfm(tfm)->__crt_alg); ++} ++ ++static inline unsigned int crypto_acomp_reqsize(struct crypto_acomp *tfm) ++{ ++ return tfm->reqsize; ++} ++ ++static inline void acomp_request_set_tfm(struct acomp_req *req, ++ struct crypto_acomp *tfm) ++{ ++ req->base.tfm = crypto_acomp_tfm(tfm); ++} ++ ++static inline struct crypto_acomp *crypto_acomp_reqtfm(struct acomp_req *req) ++{ ++ return __crypto_acomp_tfm(req->base.tfm); ++} ++ ++/** ++ * crypto_free_acomp() -- free ACOMPRESS tfm handle ++ * ++ * @tfm: ACOMPRESS tfm handle allocated with crypto_alloc_acomp() ++ */ ++static inline void crypto_free_acomp(struct crypto_acomp *tfm) ++{ ++ crypto_destroy_tfm(tfm, crypto_acomp_tfm(tfm)); ++} ++ ++static inline int crypto_has_acomp(const char *alg_name, u32 type, u32 mask) ++{ ++ type &= ~CRYPTO_ALG_TYPE_MASK; ++ type |= CRYPTO_ALG_TYPE_ACOMPRESS; ++ mask |= CRYPTO_ALG_TYPE_MASK; ++ ++ return crypto_has_alg(alg_name, type, mask); ++} ++ ++/** ++ * acomp_request_alloc() -- allocates asynchronous (de)compression request ++ * ++ * @tfm: ACOMPRESS tfm handle allocated with crypto_alloc_acomp() ++ * ++ * Return: allocated handle in case of success or NULL in case of an error ++ */ ++struct acomp_req *acomp_request_alloc(struct crypto_acomp *tfm); ++ ++/** ++ * acomp_request_free() -- zeroize and free asynchronous (de)compression ++ * request as well as the output buffer if allocated ++ * inside the algorithm ++ * ++ * @req: request to free ++ */ ++void acomp_request_free(struct acomp_req *req); ++ ++/** ++ * acomp_request_set_callback() -- Sets an asynchronous callback ++ * ++ * Callback will be called when an asynchronous operation on a given ++ * request is finished. ++ * ++ * @req: request that the callback will be set for ++ * @flgs: specify for instance if the operation may backlog ++ * @cmlp: callback which will be called ++ * @data: private data used by the caller ++ */ ++static inline void acomp_request_set_callback(struct acomp_req *req, ++ u32 flgs, ++ crypto_completion_t cmpl, ++ void *data) ++{ ++ req->base.complete = cmpl; ++ req->base.data = data; ++ req->base.flags = flgs; ++} ++ ++/** ++ * acomp_request_set_params() -- Sets request parameters ++ * ++ * Sets parameters required by an acomp operation ++ * ++ * @req: asynchronous compress request ++ * @src: pointer to input buffer scatterlist ++ * @dst: pointer to output buffer scatterlist. If this is NULL, the ++ * acomp layer will allocate the output memory ++ * @slen: size of the input buffer ++ * @dlen: size of the output buffer. If dst is NULL, this can be used by ++ * the user to specify the maximum amount of memory to allocate ++ */ ++static inline void acomp_request_set_params(struct acomp_req *req, ++ struct scatterlist *src, ++ struct scatterlist *dst, ++ unsigned int slen, ++ unsigned int dlen) ++{ ++ req->src = src; ++ req->dst = dst; ++ req->slen = slen; ++ req->dlen = dlen; ++ ++ if (!req->dst) ++ req->flags |= CRYPTO_ACOMP_ALLOC_OUTPUT; ++} ++ ++/** ++ * crypto_acomp_compress() -- Invoke asynchronous compress operation ++ * ++ * Function invokes the asynchronous compress operation ++ * ++ * @req: asynchronous compress request ++ * ++ * Return: zero on success; error code in case of error ++ */ ++static inline int crypto_acomp_compress(struct acomp_req *req) ++{ ++ struct crypto_acomp *tfm = crypto_acomp_reqtfm(req); ++ ++ return tfm->compress(req); ++} ++ ++/** ++ * crypto_acomp_decompress() -- Invoke asynchronous decompress operation ++ * ++ * Function invokes the asynchronous decompress operation ++ * ++ * @req: asynchronous compress request ++ * ++ * Return: zero on success; error code in case of error ++ */ ++static inline int crypto_acomp_decompress(struct acomp_req *req) ++{ ++ struct crypto_acomp *tfm = crypto_acomp_reqtfm(req); ++ ++ return tfm->decompress(req); ++} ++ ++#endif +diff --git a/include/crypto/internal/acompress.h b/include/crypto/internal/acompress.h +new file mode 100644 +index 00000000..1de2b5af +--- /dev/null ++++ b/include/crypto/internal/acompress.h +@@ -0,0 +1,81 @@ ++/* ++ * Asynchronous Compression operations ++ * ++ * Copyright (c) 2016, Intel Corporation ++ * Authors: Weigang Li ++ * Giovanni Cabiddu ++ * ++ * 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. ++ * ++ */ ++#ifndef _CRYPTO_ACOMP_INT_H ++#define _CRYPTO_ACOMP_INT_H ++#include ++ ++/* ++ * Transform internal helpers. ++ */ ++static inline void *acomp_request_ctx(struct acomp_req *req) ++{ ++ return req->__ctx; ++} ++ ++static inline void *acomp_tfm_ctx(struct crypto_acomp *tfm) ++{ ++ return tfm->base.__crt_ctx; ++} ++ ++static inline void acomp_request_complete(struct acomp_req *req, ++ int err) ++{ ++ req->base.complete(&req->base, err); ++} ++ ++static inline const char *acomp_alg_name(struct crypto_acomp *tfm) ++{ ++ return crypto_acomp_tfm(tfm)->__crt_alg->cra_name; ++} ++ ++static inline struct acomp_req *__acomp_request_alloc(struct crypto_acomp *tfm) ++{ ++ struct acomp_req *req; ++ ++ req = kzalloc(sizeof(*req) + crypto_acomp_reqsize(tfm), GFP_KERNEL); ++ if (likely(req)) ++ acomp_request_set_tfm(req, tfm); ++ return req; ++} ++ ++static inline void __acomp_request_free(struct acomp_req *req) ++{ ++ kzfree(req); ++} ++ ++/** ++ * crypto_register_acomp() -- Register asynchronous compression algorithm ++ * ++ * Function registers an implementation of an asynchronous ++ * compression algorithm ++ * ++ * @alg: algorithm definition ++ * ++ * Return: zero on success; error code in case of error ++ */ ++int crypto_register_acomp(struct acomp_alg *alg); ++ ++/** ++ * crypto_unregister_acomp() -- Unregister asynchronous compression algorithm ++ * ++ * Function unregisters an implementation of an asynchronous ++ * compression algorithm ++ * ++ * @alg: algorithm definition ++ * ++ * Return: zero on success; error code in case of error ++ */ ++int crypto_unregister_acomp(struct acomp_alg *alg); ++ ++#endif +diff --git a/include/crypto/internal/scompress.h b/include/crypto/internal/scompress.h +new file mode 100644 +index 00000000..3fda3c56 +--- /dev/null ++++ b/include/crypto/internal/scompress.h +@@ -0,0 +1,136 @@ ++/* ++ * Synchronous Compression operations ++ * ++ * Copyright 2015 LG Electronics Inc. ++ * Copyright (c) 2016, Intel Corporation ++ * Author: Giovanni Cabiddu ++ * ++ * 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. ++ * ++ */ ++#ifndef _CRYPTO_SCOMP_INT_H ++#define _CRYPTO_SCOMP_INT_H ++#include ++ ++#define SCOMP_SCRATCH_SIZE 131072 ++ ++struct crypto_scomp { ++ struct crypto_tfm base; ++}; ++ ++/** ++ * struct scomp_alg - synchronous compression algorithm ++ * ++ * @alloc_ctx: Function allocates algorithm specific context ++ * @free_ctx: Function frees context allocated with alloc_ctx ++ * @compress: Function performs a compress operation ++ * @decompress: Function performs a de-compress operation ++ * @init: Initialize the cryptographic transformation object. ++ * This function is used to initialize the cryptographic ++ * transformation object. This function is called only once at ++ * the instantiation time, right after the transformation context ++ * was allocated. In case the cryptographic hardware has some ++ * special requirements which need to be handled by software, this ++ * function shall check for the precise requirement of the ++ * transformation and put any software fallbacks in place. ++ * @exit: Deinitialize the cryptographic transformation object. This is a ++ * counterpart to @init, used to remove various changes set in ++ * @init. ++ * @base: Common crypto API algorithm data structure ++ */ ++struct scomp_alg { ++ void *(*alloc_ctx)(struct crypto_scomp *tfm); ++ void (*free_ctx)(struct crypto_scomp *tfm, void *ctx); ++ int (*compress)(struct crypto_scomp *tfm, const u8 *src, ++ unsigned int slen, u8 *dst, unsigned int *dlen, ++ void *ctx); ++ int (*decompress)(struct crypto_scomp *tfm, const u8 *src, ++ unsigned int slen, u8 *dst, unsigned int *dlen, ++ void *ctx); ++ struct crypto_alg base; ++}; ++ ++static inline struct scomp_alg *__crypto_scomp_alg(struct crypto_alg *alg) ++{ ++ return container_of(alg, struct scomp_alg, base); ++} ++ ++static inline struct crypto_scomp *__crypto_scomp_tfm(struct crypto_tfm *tfm) ++{ ++ return container_of(tfm, struct crypto_scomp, base); ++} ++ ++static inline struct crypto_tfm *crypto_scomp_tfm(struct crypto_scomp *tfm) ++{ ++ return &tfm->base; ++} ++ ++static inline void crypto_free_scomp(struct crypto_scomp *tfm) ++{ ++ crypto_destroy_tfm(tfm, crypto_scomp_tfm(tfm)); ++} ++ ++static inline struct scomp_alg *crypto_scomp_alg(struct crypto_scomp *tfm) ++{ ++ return __crypto_scomp_alg(crypto_scomp_tfm(tfm)->__crt_alg); ++} ++ ++static inline void *crypto_scomp_alloc_ctx(struct crypto_scomp *tfm) ++{ ++ return crypto_scomp_alg(tfm)->alloc_ctx(tfm); ++} ++ ++static inline void crypto_scomp_free_ctx(struct crypto_scomp *tfm, ++ void *ctx) ++{ ++ return crypto_scomp_alg(tfm)->free_ctx(tfm, ctx); ++} ++ ++static inline int crypto_scomp_compress(struct crypto_scomp *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen, void *ctx) ++{ ++ return crypto_scomp_alg(tfm)->compress(tfm, src, slen, dst, dlen, ctx); ++} ++ ++static inline int crypto_scomp_decompress(struct crypto_scomp *tfm, ++ const u8 *src, unsigned int slen, ++ u8 *dst, unsigned int *dlen, ++ void *ctx) ++{ ++ return crypto_scomp_alg(tfm)->decompress(tfm, src, slen, dst, dlen, ++ ctx); ++} ++ ++int crypto_init_scomp_ops_async(struct crypto_tfm *tfm); ++struct acomp_req *crypto_acomp_scomp_alloc_ctx(struct acomp_req *req); ++void crypto_acomp_scomp_free_ctx(struct acomp_req *req); ++ ++/** ++ * crypto_register_scomp() -- Register synchronous compression algorithm ++ * ++ * Function registers an implementation of a synchronous ++ * compression algorithm ++ * ++ * @alg: algorithm definition ++ * ++ * Return: zero on success; error code in case of error ++ */ ++int crypto_register_scomp(struct scomp_alg *alg); ++ ++/** ++ * crypto_unregister_scomp() -- Unregister synchronous compression algorithm ++ * ++ * Function unregisters an implementation of a synchronous ++ * compression algorithm ++ * ++ * @alg: algorithm definition ++ * ++ * Return: zero on success; error code in case of error ++ */ ++int crypto_unregister_scomp(struct scomp_alg *alg); ++ ++#endif +diff --git a/include/linux/crypto.h b/include/linux/crypto.h +index 7cee5551..8348d83d 100644 +--- a/include/linux/crypto.h ++++ b/include/linux/crypto.h +@@ -50,6 +50,8 @@ + #define CRYPTO_ALG_TYPE_SKCIPHER 0x00000005 + #define CRYPTO_ALG_TYPE_GIVCIPHER 0x00000006 + #define CRYPTO_ALG_TYPE_KPP 0x00000008 ++#define CRYPTO_ALG_TYPE_ACOMPRESS 0x0000000a ++#define CRYPTO_ALG_TYPE_SCOMPRESS 0x0000000b + #define CRYPTO_ALG_TYPE_RNG 0x0000000c + #define CRYPTO_ALG_TYPE_AKCIPHER 0x0000000d + #define CRYPTO_ALG_TYPE_DIGEST 0x0000000e +@@ -60,6 +62,7 @@ + #define CRYPTO_ALG_TYPE_HASH_MASK 0x0000000e + #define CRYPTO_ALG_TYPE_AHASH_MASK 0x0000000e + #define CRYPTO_ALG_TYPE_BLKCIPHER_MASK 0x0000000c ++#define CRYPTO_ALG_TYPE_ACOMPRESS_MASK 0x0000000e + + #define CRYPTO_ALG_LARVAL 0x00000010 + #define CRYPTO_ALG_DEAD 0x00000020 +diff --git a/include/uapi/linux/cryptouser.h b/include/uapi/linux/cryptouser.h +index 79b5ded2..11d21fce 100644 +--- a/include/uapi/linux/cryptouser.h ++++ b/include/uapi/linux/cryptouser.h +@@ -46,6 +46,7 @@ enum crypto_attr_type_t { + CRYPTOCFGA_REPORT_CIPHER, /* struct crypto_report_cipher */ + CRYPTOCFGA_REPORT_AKCIPHER, /* struct crypto_report_akcipher */ + CRYPTOCFGA_REPORT_KPP, /* struct crypto_report_kpp */ ++ CRYPTOCFGA_REPORT_ACOMP, /* struct crypto_report_acomp */ + __CRYPTOCFGA_MAX + + #define CRYPTOCFGA_MAX (__CRYPTOCFGA_MAX - 1) +@@ -112,5 +113,9 @@ struct crypto_report_kpp { + char type[CRYPTO_MAX_NAME]; + }; + ++struct crypto_report_acomp { ++ char type[CRYPTO_MAX_NAME]; ++}; ++ + #define CRYPTO_REPORT_MAXSIZE (sizeof(struct crypto_user_alg) + \ + sizeof(struct crypto_report_blkcipher)) +diff --git a/scripts/spelling.txt b/scripts/spelling.txt +index 163c720d..8392f89c 100644 +--- a/scripts/spelling.txt ++++ b/scripts/spelling.txt +@@ -305,6 +305,9 @@ defintion||definition + defintions||definitions + defualt||default + defult||default ++deintializing||deinitializing ++deintialize||deinitialize ++deintialized||deinitialized + deivce||device + delared||declared + delare||declare +diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c +index 504c7cd7..d8577374 100644 +--- a/sound/soc/amd/acp-pcm-dma.c ++++ b/sound/soc/amd/acp-pcm-dma.c +@@ -506,7 +506,7 @@ static int acp_init(void __iomem *acp_mmio) + return 0; + } + +-/* Deintialize ACP */ ++/* Deinitialize ACP */ + static int acp_deinit(void __iomem *acp_mmio) + { + u32 val; +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/805-dma-support-layerscape.patch b/target/linux/layerscape/patches-4.9/805-dma-support-layerscape.patch new file mode 100644 index 0000000000..29fc301abd --- /dev/null +++ b/target/linux/layerscape/patches-4.9/805-dma-support-layerscape.patch @@ -0,0 +1,3781 @@ +From 659603c5f6cbc3d39922d4374df25ae4627d0e88 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 12:12:20 +0800 +Subject: [PATCH] dma: support layerscape + +This is a integrated patch for layerscape dma support. + +Signed-off-by: jiaheng.fan +Signed-off-by: Yangbo Lu +--- + drivers/dma/Kconfig | 14 + + drivers/dma/Makefile | 2 + + drivers/dma/dpaa2-qdma/Kconfig | 8 + + drivers/dma/dpaa2-qdma/Makefile | 8 + + drivers/dma/dpaa2-qdma/dpaa2-qdma.c | 986 +++++++++++++++++++++++++ + drivers/dma/dpaa2-qdma/dpaa2-qdma.h | 262 +++++++ + drivers/dma/dpaa2-qdma/dpdmai.c | 454 ++++++++++++ + drivers/dma/dpaa2-qdma/fsl_dpdmai.h | 521 ++++++++++++++ + drivers/dma/dpaa2-qdma/fsl_dpdmai_cmd.h | 222 ++++++ + drivers/dma/fsl-qdma.c | 1201 +++++++++++++++++++++++++++++++ + 10 files changed, 3678 insertions(+) + create mode 100644 drivers/dma/dpaa2-qdma/Kconfig + create mode 100644 drivers/dma/dpaa2-qdma/Makefile + create mode 100644 drivers/dma/dpaa2-qdma/dpaa2-qdma.c + create mode 100644 drivers/dma/dpaa2-qdma/dpaa2-qdma.h + create mode 100644 drivers/dma/dpaa2-qdma/dpdmai.c + create mode 100644 drivers/dma/dpaa2-qdma/fsl_dpdmai.h + create mode 100644 drivers/dma/dpaa2-qdma/fsl_dpdmai_cmd.h + create mode 100644 drivers/dma/fsl-qdma.c + +diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig +index 141aefbe..e5b0fb0b 100644 +--- a/drivers/dma/Kconfig ++++ b/drivers/dma/Kconfig +@@ -192,6 +192,20 @@ config FSL_EDMA + multiplexing capability for DMA request sources(slot). + This module can be found on Freescale Vybrid and LS-1 SoCs. + ++config FSL_QDMA ++ tristate "Freescale qDMA engine support" ++ select DMA_ENGINE ++ select DMA_VIRTUAL_CHANNELS ++ select DMA_ENGINE_RAID ++ select ASYNC_TX_ENABLE_CHANNEL_SWITCH ++ help ++ Support the Freescale qDMA engine with command queue and legacy mode. ++ Channel virtualization is supported through enqueuing of DMA jobs to, ++ or dequeuing DMA jobs from, different work queues. ++ This module can be found on Freescale LS SoCs. ++ ++source drivers/dma/dpaa2-qdma/Kconfig ++ + config FSL_RAID + tristate "Freescale RAID engine Support" + depends on FSL_SOC && !ASYNC_TX_ENABLE_CHANNEL_SWITCH +diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile +index e4dc9cac..1226cbb4 100644 +--- a/drivers/dma/Makefile ++++ b/drivers/dma/Makefile +@@ -29,6 +29,8 @@ obj-$(CONFIG_DW_DMAC_CORE) += dw/ + obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o + obj-$(CONFIG_FSL_DMA) += fsldma.o + obj-$(CONFIG_FSL_EDMA) += fsl-edma.o ++obj-$(CONFIG_FSL_QDMA) += fsl-qdma.o ++obj-$(CONFIG_FSL_DPAA2_QDMA) += dpaa2-qdma/ + obj-$(CONFIG_FSL_RAID) += fsl_raid.o + obj-$(CONFIG_HSU_DMA) += hsu/ + obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o +diff --git a/drivers/dma/dpaa2-qdma/Kconfig b/drivers/dma/dpaa2-qdma/Kconfig +new file mode 100644 +index 00000000..084e34bf +--- /dev/null ++++ b/drivers/dma/dpaa2-qdma/Kconfig +@@ -0,0 +1,8 @@ ++menuconfig FSL_DPAA2_QDMA ++ tristate "NXP DPAA2 QDMA" ++ depends on FSL_MC_BUS && FSL_MC_DPIO ++ select DMA_ENGINE ++ select DMA_VIRTUAL_CHANNELS ++ ---help--- ++ NXP Data Path Acceleration Architecture 2 QDMA driver, ++ using the NXP MC bus driver. +diff --git a/drivers/dma/dpaa2-qdma/Makefile b/drivers/dma/dpaa2-qdma/Makefile +new file mode 100644 +index 00000000..ba599ac6 +--- /dev/null ++++ b/drivers/dma/dpaa2-qdma/Makefile +@@ -0,0 +1,8 @@ ++# ++# Makefile for the NXP DPAA2 CAAM controllers ++# ++ccflags-y += -DVERSION=\"\" ++ ++obj-$(CONFIG_FSL_DPAA2_QDMA) += fsl-dpaa2-qdma.o ++ ++fsl-dpaa2-qdma-objs := dpaa2-qdma.o dpdmai.o +diff --git a/drivers/dma/dpaa2-qdma/dpaa2-qdma.c b/drivers/dma/dpaa2-qdma/dpaa2-qdma.c +new file mode 100644 +index 00000000..ad6b03f7 +--- /dev/null ++++ b/drivers/dma/dpaa2-qdma/dpaa2-qdma.c +@@ -0,0 +1,986 @@ ++/* ++ * drivers/dma/dpaa2-qdma/dpaa2-qdma.c ++ * ++ * Copyright 2015-2017 NXP Semiconductor, Inc. ++ * Author: Changming Huang ++ * ++ * Driver for the NXP QDMA engine with QMan mode. ++ * Channel virtualization is supported through enqueuing of DMA jobs to, ++ * or dequeuing DMA jobs from different work queues with QMan portal. ++ * This module can be found on NXP LS2 SoCs. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../virt-dma.h" ++ ++#include "../../../drivers/staging/fsl-mc/include/mc.h" ++#include "../../../drivers/staging/fsl-mc/include/dpaa2-io.h" ++#include "../../../drivers/staging/fsl-mc/include/dpaa2-fd.h" ++#include "fsl_dpdmai_cmd.h" ++#include "fsl_dpdmai.h" ++#include "dpaa2-qdma.h" ++ ++static bool smmu_disable = true; ++ ++static struct dpaa2_qdma_chan *to_dpaa2_qdma_chan(struct dma_chan *chan) ++{ ++ return container_of(chan, struct dpaa2_qdma_chan, vchan.chan); ++} ++ ++static struct dpaa2_qdma_comp *to_fsl_qdma_comp(struct virt_dma_desc *vd) ++{ ++ return container_of(vd, struct dpaa2_qdma_comp, vdesc); ++} ++ ++static int dpaa2_qdma_alloc_chan_resources(struct dma_chan *chan) ++{ ++ return 0; ++} ++ ++static void dpaa2_qdma_free_chan_resources(struct dma_chan *chan) ++{ ++ struct dpaa2_qdma_chan *dpaa2_chan = to_dpaa2_qdma_chan(chan); ++ unsigned long flags; ++ LIST_HEAD(head); ++ ++ spin_lock_irqsave(&dpaa2_chan->vchan.lock, flags); ++ vchan_get_all_descriptors(&dpaa2_chan->vchan, &head); ++ spin_unlock_irqrestore(&dpaa2_chan->vchan.lock, flags); ++ ++ vchan_dma_desc_free_list(&dpaa2_chan->vchan, &head); ++} ++ ++/* ++ * Request a command descriptor for enqueue. ++ */ ++static struct dpaa2_qdma_comp * ++dpaa2_qdma_request_desc(struct dpaa2_qdma_chan *dpaa2_chan) ++{ ++ struct dpaa2_qdma_comp *comp_temp = NULL; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dpaa2_chan->queue_lock, flags); ++ if (list_empty(&dpaa2_chan->comp_free)) { ++ spin_unlock_irqrestore(&dpaa2_chan->queue_lock, flags); ++ comp_temp = kzalloc(sizeof(*comp_temp), GFP_KERNEL); ++ if (!comp_temp) ++ goto err; ++ comp_temp->fd_virt_addr = dma_pool_alloc(dpaa2_chan->fd_pool, ++ GFP_NOWAIT, &comp_temp->fd_bus_addr); ++ if (!comp_temp->fd_virt_addr) ++ goto err; ++ ++ comp_temp->fl_virt_addr = ++ (void *)((struct dpaa2_fd *) ++ comp_temp->fd_virt_addr + 1); ++ comp_temp->fl_bus_addr = comp_temp->fd_bus_addr + ++ sizeof(struct dpaa2_fd); ++ comp_temp->desc_virt_addr = ++ (void *)((struct dpaa2_frame_list *) ++ comp_temp->fl_virt_addr + 3); ++ comp_temp->desc_bus_addr = comp_temp->fl_bus_addr + ++ sizeof(struct dpaa2_frame_list) * 3; ++ ++ comp_temp->qchan = dpaa2_chan; ++ comp_temp->sg_blk_num = 0; ++ INIT_LIST_HEAD(&comp_temp->sg_src_head); ++ INIT_LIST_HEAD(&comp_temp->sg_dst_head); ++ return comp_temp; ++ } ++ comp_temp = list_first_entry(&dpaa2_chan->comp_free, ++ struct dpaa2_qdma_comp, list); ++ list_del(&comp_temp->list); ++ spin_unlock_irqrestore(&dpaa2_chan->queue_lock, flags); ++ ++ comp_temp->qchan = dpaa2_chan; ++err: ++ return comp_temp; ++} ++ ++static void dpaa2_qdma_populate_fd(uint32_t format, ++ struct dpaa2_qdma_comp *dpaa2_comp) ++{ ++ struct dpaa2_fd *fd; ++ ++ fd = (struct dpaa2_fd *)dpaa2_comp->fd_virt_addr; ++ memset(fd, 0, sizeof(struct dpaa2_fd)); ++ ++ /* fd populated */ ++ fd->simple.addr = dpaa2_comp->fl_bus_addr; ++ /* Bypass memory translation, Frame list format, short length disable */ ++ /* we need to disable BMT if fsl-mc use iova addr */ ++ if (smmu_disable) ++ fd->simple.bpid = QMAN_FD_BMT_ENABLE; ++ fd->simple.format_offset = QMAN_FD_FMT_ENABLE | QMAN_FD_SL_DISABLE; ++ ++ fd->simple.frc = format | QDMA_SER_CTX; ++} ++ ++/* first frame list for descriptor buffer */ ++static void dpaa2_qdma_populate_first_framel( ++ struct dpaa2_frame_list *f_list, ++ struct dpaa2_qdma_comp *dpaa2_comp) ++{ ++ struct dpaa2_qdma_sd_d *sdd; ++ ++ sdd = (struct dpaa2_qdma_sd_d *)dpaa2_comp->desc_virt_addr; ++ memset(sdd, 0, 2 * (sizeof(*sdd))); ++ /* source and destination descriptor */ ++ sdd->cmd = QDMA_SD_CMD_RDTTYPE_COHERENT; /* source descriptor CMD */ ++ sdd++; ++ sdd->cmd = QDMA_DD_CMD_WRTTYPE_COHERENT; /* dest descriptor CMD */ ++ ++ memset(f_list, 0, sizeof(struct dpaa2_frame_list)); ++ /* first frame list to source descriptor */ ++ f_list->addr_lo = dpaa2_comp->desc_bus_addr; ++ f_list->addr_hi = (dpaa2_comp->desc_bus_addr >> 32); ++ f_list->data_len.data_len_sl0 = 0x20; /* source/destination desc len */ ++ f_list->fmt = QDMA_FL_FMT_SBF; /* single buffer frame */ ++ if (smmu_disable) ++ f_list->bmt = QDMA_FL_BMT_ENABLE; /* bypass memory translation */ ++ f_list->sl = QDMA_FL_SL_LONG; /* long length */ ++ f_list->f = 0; /* not the last frame list */ ++} ++ ++/* source and destination frame list */ ++static void dpaa2_qdma_populate_frames(struct dpaa2_frame_list *f_list, ++ dma_addr_t dst, dma_addr_t src, size_t len, uint8_t fmt) ++{ ++ /* source frame list to source buffer */ ++ memset(f_list, 0, sizeof(struct dpaa2_frame_list)); ++ f_list->addr_lo = src; ++ f_list->addr_hi = (src >> 32); ++ f_list->data_len.data_len_sl0 = len; ++ f_list->fmt = fmt; /* single buffer frame or scatter gather frame */ ++ if (smmu_disable) ++ f_list->bmt = QDMA_FL_BMT_ENABLE; /* bypass memory translation */ ++ f_list->sl = QDMA_FL_SL_LONG; /* long length */ ++ f_list->f = 0; /* not the last frame list */ ++ ++ f_list++; ++ /* destination frame list to destination buffer */ ++ memset(f_list, 0, sizeof(struct dpaa2_frame_list)); ++ f_list->addr_lo = dst; ++ f_list->addr_hi = (dst >> 32); ++ f_list->data_len.data_len_sl0 = len; ++ f_list->fmt = fmt; /* single buffer frame or scatter gather frame */ ++ if (smmu_disable) ++ f_list->bmt = QDMA_FL_BMT_ENABLE; /* bypass memory translation */ ++ f_list->sl = QDMA_FL_SL_LONG; /* long length */ ++ f_list->f = QDMA_FL_F; /* Final bit: 1, for last frame list */ ++} ++ ++static struct dma_async_tx_descriptor *dpaa2_qdma_prep_memcpy( ++ struct dma_chan *chan, dma_addr_t dst, ++ dma_addr_t src, size_t len, unsigned long flags) ++{ ++ struct dpaa2_qdma_chan *dpaa2_chan = to_dpaa2_qdma_chan(chan); ++ struct dpaa2_qdma_comp *dpaa2_comp; ++ struct dpaa2_frame_list *f_list; ++ uint32_t format; ++ ++ dpaa2_comp = dpaa2_qdma_request_desc(dpaa2_chan); ++ ++#ifdef LONG_FORMAT ++ format = QDMA_FD_LONG_FORMAT; ++#else ++ format = QDMA_FD_SHORT_FORMAT; ++#endif ++ /* populate Frame descriptor */ ++ dpaa2_qdma_populate_fd(format, dpaa2_comp); ++ ++ f_list = (struct dpaa2_frame_list *)dpaa2_comp->fl_virt_addr; ++ ++#ifdef LONG_FORMAT ++ /* first frame list for descriptor buffer (logn format) */ ++ dpaa2_qdma_populate_first_framel(f_list, dpaa2_comp); ++ ++ f_list++; ++#endif ++ ++ dpaa2_qdma_populate_frames(f_list, dst, src, len, QDMA_FL_FMT_SBF); ++ ++ return vchan_tx_prep(&dpaa2_chan->vchan, &dpaa2_comp->vdesc, flags); ++} ++ ++static struct qdma_sg_blk *dpaa2_qdma_get_sg_blk( ++ struct dpaa2_qdma_comp *dpaa2_comp, ++ struct dpaa2_qdma_chan *dpaa2_chan) ++{ ++ struct qdma_sg_blk *sg_blk = NULL; ++ dma_addr_t phy_sgb; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dpaa2_chan->queue_lock, flags); ++ if (list_empty(&dpaa2_chan->sgb_free)) { ++ sg_blk = (struct qdma_sg_blk *)dma_pool_alloc( ++ dpaa2_chan->sg_blk_pool, ++ GFP_NOWAIT, &phy_sgb); ++ if (!sg_blk) { ++ spin_unlock_irqrestore(&dpaa2_chan->queue_lock, flags); ++ return sg_blk; ++ } ++ sg_blk->blk_virt_addr = (void *)(sg_blk + 1); ++ sg_blk->blk_bus_addr = phy_sgb + sizeof(*sg_blk); ++ } else { ++ sg_blk = list_first_entry(&dpaa2_chan->sgb_free, ++ struct qdma_sg_blk, list); ++ list_del(&sg_blk->list); ++ } ++ spin_unlock_irqrestore(&dpaa2_chan->queue_lock, flags); ++ ++ return sg_blk; ++} ++ ++static uint32_t dpaa2_qdma_populate_sg(struct device *dev, ++ struct dpaa2_qdma_chan *dpaa2_chan, ++ struct dpaa2_qdma_comp *dpaa2_comp, ++ struct scatterlist *dst_sg, u32 dst_nents, ++ struct scatterlist *src_sg, u32 src_nents) ++{ ++ struct dpaa2_qdma_sg *src_sge; ++ struct dpaa2_qdma_sg *dst_sge; ++ struct qdma_sg_blk *sg_blk; ++ struct qdma_sg_blk *sg_blk_dst; ++ dma_addr_t src; ++ dma_addr_t dst; ++ uint32_t num; ++ uint32_t blocks; ++ uint32_t len = 0; ++ uint32_t total_len = 0; ++ int i, j = 0; ++ ++ num = min(dst_nents, src_nents); ++ blocks = num / (NUM_SG_PER_BLK - 1); ++ if (num % (NUM_SG_PER_BLK - 1)) ++ blocks += 1; ++ if (dpaa2_comp->sg_blk_num < blocks) { ++ len = blocks - dpaa2_comp->sg_blk_num; ++ for (i = 0; i < len; i++) { ++ /* source sg blocks */ ++ sg_blk = dpaa2_qdma_get_sg_blk(dpaa2_comp, dpaa2_chan); ++ if (!sg_blk) ++ return 0; ++ list_add_tail(&sg_blk->list, &dpaa2_comp->sg_src_head); ++ /* destination sg blocks */ ++ sg_blk = dpaa2_qdma_get_sg_blk(dpaa2_comp, dpaa2_chan); ++ if (!sg_blk) ++ return 0; ++ list_add_tail(&sg_blk->list, &dpaa2_comp->sg_dst_head); ++ } ++ } else { ++ len = dpaa2_comp->sg_blk_num - blocks; ++ for (i = 0; i < len; i++) { ++ spin_lock(&dpaa2_chan->queue_lock); ++ /* handle source sg blocks */ ++ sg_blk = list_first_entry(&dpaa2_comp->sg_src_head, ++ struct qdma_sg_blk, list); ++ list_del(&sg_blk->list); ++ list_add_tail(&sg_blk->list, &dpaa2_chan->sgb_free); ++ /* handle destination sg blocks */ ++ sg_blk = list_first_entry(&dpaa2_comp->sg_dst_head, ++ struct qdma_sg_blk, list); ++ list_del(&sg_blk->list); ++ list_add_tail(&sg_blk->list, &dpaa2_chan->sgb_free); ++ spin_unlock(&dpaa2_chan->queue_lock); ++ } ++ } ++ dpaa2_comp->sg_blk_num = blocks; ++ ++ /* get the first source sg phy address */ ++ sg_blk = list_first_entry(&dpaa2_comp->sg_src_head, ++ struct qdma_sg_blk, list); ++ dpaa2_comp->sge_src_bus_addr = sg_blk->blk_bus_addr; ++ /* get the first destinaiton sg phy address */ ++ sg_blk_dst = list_first_entry(&dpaa2_comp->sg_dst_head, ++ struct qdma_sg_blk, list); ++ dpaa2_comp->sge_dst_bus_addr = sg_blk_dst->blk_bus_addr; ++ ++ for (i = 0; i < blocks; i++) { ++ src_sge = (struct dpaa2_qdma_sg *)sg_blk->blk_virt_addr; ++ dst_sge = (struct dpaa2_qdma_sg *)sg_blk_dst->blk_virt_addr; ++ ++ for (j = 0; j < (NUM_SG_PER_BLK - 1); j++) { ++ len = min(sg_dma_len(dst_sg), sg_dma_len(src_sg)); ++ if (0 == len) ++ goto fetch; ++ total_len += len; ++ src = sg_dma_address(src_sg); ++ dst = sg_dma_address(dst_sg); ++ ++ /* source SG */ ++ src_sge->addr_lo = src; ++ src_sge->addr_hi = (src >> 32); ++ src_sge->data_len.data_len_sl0 = len; ++ src_sge->ctrl.sl = QDMA_SG_SL_LONG; ++ src_sge->ctrl.fmt = QDMA_SG_FMT_SDB; ++ /* destination SG */ ++ dst_sge->addr_lo = dst; ++ dst_sge->addr_hi = (dst >> 32); ++ dst_sge->data_len.data_len_sl0 = len; ++ dst_sge->ctrl.sl = QDMA_SG_SL_LONG; ++ dst_sge->ctrl.fmt = QDMA_SG_FMT_SDB; ++fetch: ++ num--; ++ if (0 == num) { ++ src_sge->ctrl.f = QDMA_SG_F; ++ dst_sge->ctrl.f = QDMA_SG_F; ++ goto end; ++ } ++ dst_sg = sg_next(dst_sg); ++ src_sg = sg_next(src_sg); ++ src_sge++; ++ dst_sge++; ++ if (j == (NUM_SG_PER_BLK - 2)) { ++ /* for next blocks, extension */ ++ sg_blk = list_next_entry(sg_blk, list); ++ sg_blk_dst = list_next_entry(sg_blk_dst, list); ++ src_sge->addr_lo = sg_blk->blk_bus_addr; ++ src_sge->addr_hi = sg_blk->blk_bus_addr >> 32; ++ src_sge->ctrl.sl = QDMA_SG_SL_LONG; ++ src_sge->ctrl.fmt = QDMA_SG_FMT_SGTE; ++ dst_sge->addr_lo = sg_blk_dst->blk_bus_addr; ++ dst_sge->addr_hi = ++ sg_blk_dst->blk_bus_addr >> 32; ++ dst_sge->ctrl.sl = QDMA_SG_SL_LONG; ++ dst_sge->ctrl.fmt = QDMA_SG_FMT_SGTE; ++ } ++ } ++ } ++ ++end: ++ return total_len; ++} ++ ++static struct dma_async_tx_descriptor *dpaa2_qdma_prep_sg( ++ struct dma_chan *chan, ++ struct scatterlist *dst_sg, u32 dst_nents, ++ struct scatterlist *src_sg, u32 src_nents, ++ unsigned long flags) ++{ ++ struct dpaa2_qdma_chan *dpaa2_chan = to_dpaa2_qdma_chan(chan); ++ struct dpaa2_qdma_comp *dpaa2_comp; ++ struct dpaa2_frame_list *f_list; ++ struct device *dev = dpaa2_chan->qdma->priv->dev; ++ uint32_t total_len = 0; ++ ++ /* basic sanity checks */ ++ if (dst_nents == 0 || src_nents == 0) ++ return NULL; ++ ++ if (dst_sg == NULL || src_sg == NULL) ++ return NULL; ++ ++ /* get the descriptors required */ ++ dpaa2_comp = dpaa2_qdma_request_desc(dpaa2_chan); ++ ++ /* populate Frame descriptor */ ++ dpaa2_qdma_populate_fd(QDMA_FD_LONG_FORMAT, dpaa2_comp); ++ ++ /* prepare Scatter gather entry for source and destination */ ++ total_len = dpaa2_qdma_populate_sg(dev, dpaa2_chan, ++ dpaa2_comp, dst_sg, dst_nents, src_sg, src_nents); ++ ++ f_list = (struct dpaa2_frame_list *)dpaa2_comp->fl_virt_addr; ++ /* first frame list for descriptor buffer */ ++ dpaa2_qdma_populate_first_framel(f_list, dpaa2_comp); ++ f_list++; ++ /* prepare Scatter gather entry for source and destination */ ++ /* populate source and destination frame list table */ ++ dpaa2_qdma_populate_frames(f_list, dpaa2_comp->sge_dst_bus_addr, ++ dpaa2_comp->sge_src_bus_addr, ++ total_len, QDMA_FL_FMT_SGE); ++ ++ return vchan_tx_prep(&dpaa2_chan->vchan, &dpaa2_comp->vdesc, flags); ++} ++ ++static enum dma_status dpaa2_qdma_tx_status(struct dma_chan *chan, ++ dma_cookie_t cookie, struct dma_tx_state *txstate) ++{ ++ return dma_cookie_status(chan, cookie, txstate); ++} ++ ++static void dpaa2_qdma_free_desc(struct virt_dma_desc *vdesc) ++{ ++} ++ ++static void dpaa2_qdma_issue_pending(struct dma_chan *chan) ++{ ++ struct dpaa2_qdma_comp *dpaa2_comp; ++ struct dpaa2_qdma_chan *dpaa2_chan = to_dpaa2_qdma_chan(chan); ++ struct dpaa2_qdma_engine *dpaa2_qdma = dpaa2_chan->qdma; ++ struct dpaa2_qdma_priv *priv = dpaa2_qdma->priv; ++ struct virt_dma_desc *vdesc; ++ struct dpaa2_fd *fd; ++ int err; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&dpaa2_chan->queue_lock, flags); ++ spin_lock(&dpaa2_chan->vchan.lock); ++ if (vchan_issue_pending(&dpaa2_chan->vchan)) { ++ vdesc = vchan_next_desc(&dpaa2_chan->vchan); ++ if (!vdesc) ++ goto err_enqueue; ++ dpaa2_comp = to_fsl_qdma_comp(vdesc); ++ ++ fd = (struct dpaa2_fd *)dpaa2_comp->fd_virt_addr; ++ ++ list_del(&vdesc->node); ++ list_add_tail(&dpaa2_comp->list, &dpaa2_chan->comp_used); ++ ++ /* TOBO: priority hard-coded to zero */ ++ err = dpaa2_io_service_enqueue_fq(NULL, ++ priv->tx_queue_attr[0].fqid, fd); ++ if (err) { ++ list_del(&dpaa2_comp->list); ++ list_add_tail(&dpaa2_comp->list, ++ &dpaa2_chan->comp_free); ++ } ++ ++ } ++err_enqueue: ++ spin_unlock(&dpaa2_chan->vchan.lock); ++ spin_unlock_irqrestore(&dpaa2_chan->queue_lock, flags); ++} ++ ++static int __cold dpaa2_qdma_setup(struct fsl_mc_device *ls_dev) ++{ ++ struct device *dev = &ls_dev->dev; ++ struct dpaa2_qdma_priv *priv; ++ struct dpaa2_qdma_priv_per_prio *ppriv; ++ uint8_t prio_def = DPDMAI_PRIO_NUM; ++ int err; ++ int i; ++ ++ priv = dev_get_drvdata(dev); ++ ++ priv->dev = dev; ++ priv->dpqdma_id = ls_dev->obj_desc.id; ++ ++ /*Get the handle for the DPDMAI this interface is associate with */ ++ err = dpdmai_open(priv->mc_io, 0, priv->dpqdma_id, &ls_dev->mc_handle); ++ if (err) { ++ dev_err(dev, "dpdmai_open() failed\n"); ++ return err; ++ } ++ dev_info(dev, "Opened dpdmai object successfully\n"); ++ ++ err = dpdmai_get_attributes(priv->mc_io, 0, ls_dev->mc_handle, ++ &priv->dpdmai_attr); ++ if (err) { ++ dev_err(dev, "dpdmai_get_attributes() failed\n"); ++ return err; ++ } ++ ++ if (priv->dpdmai_attr.version.major > DPDMAI_VER_MAJOR) { ++ dev_err(dev, "DPDMAI major version mismatch\n" ++ "Found %u.%u, supported version is %u.%u\n", ++ priv->dpdmai_attr.version.major, ++ priv->dpdmai_attr.version.minor, ++ DPDMAI_VER_MAJOR, DPDMAI_VER_MINOR); ++ } ++ ++ if (priv->dpdmai_attr.version.minor > DPDMAI_VER_MINOR) { ++ dev_err(dev, "DPDMAI minor version mismatch\n" ++ "Found %u.%u, supported version is %u.%u\n", ++ priv->dpdmai_attr.version.major, ++ priv->dpdmai_attr.version.minor, ++ DPDMAI_VER_MAJOR, DPDMAI_VER_MINOR); ++ } ++ ++ priv->num_pairs = min(priv->dpdmai_attr.num_of_priorities, prio_def); ++ ppriv = kcalloc(priv->num_pairs, sizeof(*ppriv), GFP_KERNEL); ++ if (!ppriv) { ++ dev_err(dev, "kzalloc for ppriv failed\n"); ++ return -1; ++ } ++ priv->ppriv = ppriv; ++ ++ for (i = 0; i < priv->num_pairs; i++) { ++ err = dpdmai_get_rx_queue(priv->mc_io, 0, ls_dev->mc_handle, ++ i, &priv->rx_queue_attr[i]); ++ if (err) { ++ dev_err(dev, "dpdmai_get_rx_queue() failed\n"); ++ return err; ++ } ++ ppriv->rsp_fqid = priv->rx_queue_attr[i].fqid; ++ ++ err = dpdmai_get_tx_queue(priv->mc_io, 0, ls_dev->mc_handle, ++ i, &priv->tx_queue_attr[i]); ++ if (err) { ++ dev_err(dev, "dpdmai_get_tx_queue() failed\n"); ++ return err; ++ } ++ ppriv->req_fqid = priv->tx_queue_attr[i].fqid; ++ ppriv->prio = i; ++ ppriv->priv = priv; ++ ppriv++; ++ } ++ ++ return 0; ++} ++ ++static void dpaa2_qdma_fqdan_cb(struct dpaa2_io_notification_ctx *ctx) ++{ ++ struct dpaa2_qdma_priv_per_prio *ppriv = container_of(ctx, ++ struct dpaa2_qdma_priv_per_prio, nctx); ++ struct dpaa2_qdma_priv *priv = ppriv->priv; ++ struct dpaa2_qdma_comp *dpaa2_comp, *_comp_tmp; ++ struct dpaa2_qdma_chan *qchan; ++ const struct dpaa2_fd *fd; ++ const struct dpaa2_fd *fd_eq; ++ struct dpaa2_dq *dq; ++ int err; ++ int is_last = 0; ++ uint8_t status; ++ int i; ++ int found; ++ uint32_t n_chans = priv->dpaa2_qdma->n_chans; ++ ++ do { ++ err = dpaa2_io_service_pull_fq(NULL, ppriv->rsp_fqid, ++ ppriv->store); ++ } while (err); ++ ++ while (!is_last) { ++ do { ++ dq = dpaa2_io_store_next(ppriv->store, &is_last); ++ } while (!is_last && !dq); ++ if (!dq) { ++ dev_err(priv->dev, "FQID returned no valid frames!\n"); ++ continue; ++ } ++ ++ /* obtain FD and process the error */ ++ fd = dpaa2_dq_fd(dq); ++ status = fd->simple.ctrl & 0xff; ++ if (status) ++ dev_err(priv->dev, "FD error occurred\n"); ++ found = 0; ++ for (i = 0; i < n_chans; i++) { ++ qchan = &priv->dpaa2_qdma->chans[i]; ++ spin_lock(&qchan->queue_lock); ++ if (list_empty(&qchan->comp_used)) { ++ spin_unlock(&qchan->queue_lock); ++ continue; ++ } ++ list_for_each_entry_safe(dpaa2_comp, _comp_tmp, ++ &qchan->comp_used, list) { ++ fd_eq = (struct dpaa2_fd *) ++ dpaa2_comp->fd_virt_addr; ++ ++ if (fd_eq->simple.addr == ++ fd->simple.addr) { ++ ++ list_del(&dpaa2_comp->list); ++ list_add_tail(&dpaa2_comp->list, ++ &qchan->comp_free); ++ ++ spin_lock(&qchan->vchan.lock); ++ vchan_cookie_complete( ++ &dpaa2_comp->vdesc); ++ spin_unlock(&qchan->vchan.lock); ++ found = 1; ++ break; ++ } ++ } ++ spin_unlock(&qchan->queue_lock); ++ if (found) ++ break; ++ } ++ } ++ ++ dpaa2_io_service_rearm(NULL, ctx); ++} ++ ++static int __cold dpaa2_qdma_dpio_setup(struct dpaa2_qdma_priv *priv) ++{ ++ int err, i, num; ++ struct device *dev = priv->dev; ++ struct dpaa2_qdma_priv_per_prio *ppriv; ++ ++ num = priv->num_pairs; ++ ppriv = priv->ppriv; ++ for (i = 0; i < num; i++) { ++ ppriv->nctx.is_cdan = 0; ++ ppriv->nctx.desired_cpu = 1; ++ ppriv->nctx.id = ppriv->rsp_fqid; ++ ppriv->nctx.cb = dpaa2_qdma_fqdan_cb; ++ err = dpaa2_io_service_register(NULL, &ppriv->nctx); ++ if (err) { ++ dev_err(dev, "Notification register failed\n"); ++ goto err_service; ++ } ++ ++ ppriv->store = dpaa2_io_store_create(DPAA2_QDMA_STORE_SIZE, ++ dev); ++ if (!ppriv->store) { ++ dev_err(dev, "dpaa2_io_store_create() failed\n"); ++ goto err_store; ++ } ++ ++ ppriv++; ++ } ++ return 0; ++ ++err_store: ++ dpaa2_io_service_deregister(NULL, &ppriv->nctx); ++err_service: ++ ppriv--; ++ while (ppriv >= priv->ppriv) { ++ dpaa2_io_service_deregister(NULL, &ppriv->nctx); ++ dpaa2_io_store_destroy(ppriv->store); ++ ppriv--; ++ } ++ return -1; ++} ++ ++static void __cold dpaa2_dpmai_store_free(struct dpaa2_qdma_priv *priv) ++{ ++ struct dpaa2_qdma_priv_per_prio *ppriv = priv->ppriv; ++ int i; ++ ++ for (i = 0; i < priv->num_pairs; i++) { ++ dpaa2_io_store_destroy(ppriv->store); ++ ppriv++; ++ } ++} ++ ++static void __cold dpaa2_dpdmai_dpio_free(struct dpaa2_qdma_priv *priv) ++{ ++ struct dpaa2_qdma_priv_per_prio *ppriv = priv->ppriv; ++ int i; ++ ++ for (i = 0; i < priv->num_pairs; i++) { ++ dpaa2_io_service_deregister(NULL, &ppriv->nctx); ++ ppriv++; ++ } ++} ++ ++static int __cold dpaa2_dpdmai_bind(struct dpaa2_qdma_priv *priv) ++{ ++ int err; ++ struct dpdmai_rx_queue_cfg rx_queue_cfg; ++ struct device *dev = priv->dev; ++ struct dpaa2_qdma_priv_per_prio *ppriv; ++ struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev); ++ int i, num; ++ ++ num = priv->num_pairs; ++ ppriv = priv->ppriv; ++ for (i = 0; i < num; i++) { ++ rx_queue_cfg.options = DPDMAI_QUEUE_OPT_USER_CTX | ++ DPDMAI_QUEUE_OPT_DEST; ++ rx_queue_cfg.user_ctx = ppriv->nctx.qman64; ++ rx_queue_cfg.dest_cfg.dest_type = DPDMAI_DEST_DPIO; ++ rx_queue_cfg.dest_cfg.dest_id = ppriv->nctx.dpio_id; ++ rx_queue_cfg.dest_cfg.priority = ppriv->prio; ++ err = dpdmai_set_rx_queue(priv->mc_io, 0, ls_dev->mc_handle, ++ rx_queue_cfg.dest_cfg.priority, &rx_queue_cfg); ++ if (err) { ++ dev_err(dev, "dpdmai_set_rx_queue() failed\n"); ++ return err; ++ } ++ ++ ppriv++; ++ } ++ ++ return 0; ++} ++ ++static int __cold dpaa2_dpdmai_dpio_unbind(struct dpaa2_qdma_priv *priv) ++{ ++ int err = 0; ++ struct device *dev = priv->dev; ++ struct fsl_mc_device *ls_dev = to_fsl_mc_device(dev); ++ struct dpaa2_qdma_priv_per_prio *ppriv = priv->ppriv; ++ int i; ++ ++ for (i = 0; i < priv->num_pairs; i++) { ++ ppriv->nctx.qman64 = 0; ++ ppriv->nctx.dpio_id = 0; ++ ppriv++; ++ } ++ ++ err = dpdmai_reset(priv->mc_io, 0, ls_dev->mc_handle); ++ if (err) ++ dev_err(dev, "dpdmai_reset() failed\n"); ++ ++ return err; ++} ++ ++static void __cold dpaa2_dpdmai_free_pool(struct dpaa2_qdma_chan *qchan, ++ struct list_head *head) ++{ ++ struct qdma_sg_blk *sgb_tmp, *_sgb_tmp; ++ /* free the QDMA SG pool block */ ++ list_for_each_entry_safe(sgb_tmp, _sgb_tmp, head, list) { ++ sgb_tmp->blk_virt_addr = (void *)((struct qdma_sg_blk *) ++ sgb_tmp->blk_virt_addr - 1); ++ sgb_tmp->blk_bus_addr = sgb_tmp->blk_bus_addr ++ - sizeof(*sgb_tmp); ++ dma_pool_free(qchan->sg_blk_pool, sgb_tmp->blk_virt_addr, ++ sgb_tmp->blk_bus_addr); ++ } ++ ++} ++ ++static void __cold dpaa2_dpdmai_free_comp(struct dpaa2_qdma_chan *qchan, ++ struct list_head *head) ++{ ++ struct dpaa2_qdma_comp *comp_tmp, *_comp_tmp; ++ /* free the QDMA comp resource */ ++ list_for_each_entry_safe(comp_tmp, _comp_tmp, ++ head, list) { ++ dma_pool_free(qchan->fd_pool, ++ comp_tmp->fd_virt_addr, ++ comp_tmp->fd_bus_addr); ++ /* free the SG source block on comp */ ++ dpaa2_dpdmai_free_pool(qchan, &comp_tmp->sg_src_head); ++ /* free the SG destination block on comp */ ++ dpaa2_dpdmai_free_pool(qchan, &comp_tmp->sg_dst_head); ++ list_del(&comp_tmp->list); ++ kfree(comp_tmp); ++ } ++ ++} ++ ++static void __cold dpaa2_dpdmai_free_channels( ++ struct dpaa2_qdma_engine *dpaa2_qdma) ++{ ++ struct dpaa2_qdma_chan *qchan; ++ int num, i; ++ ++ num = dpaa2_qdma->n_chans; ++ for (i = 0; i < num; i++) { ++ qchan = &dpaa2_qdma->chans[i]; ++ dpaa2_dpdmai_free_comp(qchan, &qchan->comp_used); ++ dpaa2_dpdmai_free_comp(qchan, &qchan->comp_free); ++ dpaa2_dpdmai_free_pool(qchan, &qchan->sgb_free); ++ dma_pool_destroy(qchan->fd_pool); ++ dma_pool_destroy(qchan->sg_blk_pool); ++ } ++} ++ ++static int dpaa2_dpdmai_alloc_channels(struct dpaa2_qdma_engine *dpaa2_qdma) ++{ ++ struct dpaa2_qdma_chan *dpaa2_chan; ++ struct device *dev = &dpaa2_qdma->priv->dpdmai_dev->dev; ++ int i; ++ ++ INIT_LIST_HEAD(&dpaa2_qdma->dma_dev.channels); ++ for (i = 0; i < dpaa2_qdma->n_chans; i++) { ++ dpaa2_chan = &dpaa2_qdma->chans[i]; ++ dpaa2_chan->qdma = dpaa2_qdma; ++ dpaa2_chan->vchan.desc_free = dpaa2_qdma_free_desc; ++ vchan_init(&dpaa2_chan->vchan, &dpaa2_qdma->dma_dev); ++ ++ dpaa2_chan->fd_pool = dma_pool_create("fd_pool", ++ dev, FD_POOL_SIZE, 32, 0); ++ if (!dpaa2_chan->fd_pool) ++ return -1; ++ dpaa2_chan->sg_blk_pool = dma_pool_create("sg_blk_pool", ++ dev, SG_POOL_SIZE, 32, 0); ++ if (!dpaa2_chan->sg_blk_pool) ++ return -1; ++ ++ spin_lock_init(&dpaa2_chan->queue_lock); ++ INIT_LIST_HEAD(&dpaa2_chan->comp_used); ++ INIT_LIST_HEAD(&dpaa2_chan->comp_free); ++ INIT_LIST_HEAD(&dpaa2_chan->sgb_free); ++ } ++ return 0; ++} ++ ++static int dpaa2_qdma_probe(struct fsl_mc_device *dpdmai_dev) ++{ ++ struct dpaa2_qdma_priv *priv; ++ struct device *dev = &dpdmai_dev->dev; ++ struct dpaa2_qdma_engine *dpaa2_qdma; ++ int err; ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ dev_set_drvdata(dev, priv); ++ priv->dpdmai_dev = dpdmai_dev; ++ ++ priv->iommu_domain = iommu_get_domain_for_dev(dev); ++ if (priv->iommu_domain) ++ smmu_disable = false; ++ ++ /* obtain a MC portal */ ++ err = fsl_mc_portal_allocate(dpdmai_dev, 0, &priv->mc_io); ++ if (err) { ++ dev_err(dev, "MC portal allocation failed\n"); ++ goto err_mcportal; ++ } ++ ++ /* DPDMAI initialization */ ++ err = dpaa2_qdma_setup(dpdmai_dev); ++ if (err) { ++ dev_err(dev, "dpaa2_dpdmai_setup() failed\n"); ++ goto err_dpdmai_setup; ++ } ++ ++ /* DPIO */ ++ err = dpaa2_qdma_dpio_setup(priv); ++ if (err) { ++ dev_err(dev, "dpaa2_dpdmai_dpio_setup() failed\n"); ++ goto err_dpio_setup; ++ } ++ ++ /* DPDMAI binding to DPIO */ ++ err = dpaa2_dpdmai_bind(priv); ++ if (err) { ++ dev_err(dev, "dpaa2_dpdmai_bind() failed\n"); ++ goto err_bind; ++ } ++ ++ /* DPDMAI enable */ ++ err = dpdmai_enable(priv->mc_io, 0, dpdmai_dev->mc_handle); ++ if (err) { ++ dev_err(dev, "dpdmai_enable() faile\n"); ++ goto err_enable; ++ } ++ ++ dpaa2_qdma = kzalloc(sizeof(*dpaa2_qdma), GFP_KERNEL); ++ if (!dpaa2_qdma) { ++ err = -ENOMEM; ++ goto err_eng; ++ } ++ ++ priv->dpaa2_qdma = dpaa2_qdma; ++ dpaa2_qdma->priv = priv; ++ ++ dpaa2_qdma->n_chans = NUM_CH; ++ ++ err = dpaa2_dpdmai_alloc_channels(dpaa2_qdma); ++ if (err) { ++ dev_err(dev, "QDMA alloc channels faile\n"); ++ goto err_reg; ++ } ++ ++ dma_cap_set(DMA_PRIVATE, dpaa2_qdma->dma_dev.cap_mask); ++ dma_cap_set(DMA_SLAVE, dpaa2_qdma->dma_dev.cap_mask); ++ dma_cap_set(DMA_MEMCPY, dpaa2_qdma->dma_dev.cap_mask); ++ dma_cap_set(DMA_SG, dpaa2_qdma->dma_dev.cap_mask); ++ ++ dpaa2_qdma->dma_dev.dev = dev; ++ dpaa2_qdma->dma_dev.device_alloc_chan_resources ++ = dpaa2_qdma_alloc_chan_resources; ++ dpaa2_qdma->dma_dev.device_free_chan_resources ++ = dpaa2_qdma_free_chan_resources; ++ dpaa2_qdma->dma_dev.device_tx_status = dpaa2_qdma_tx_status; ++ dpaa2_qdma->dma_dev.device_prep_dma_memcpy = dpaa2_qdma_prep_memcpy; ++ dpaa2_qdma->dma_dev.device_prep_dma_sg = dpaa2_qdma_prep_sg; ++ dpaa2_qdma->dma_dev.device_issue_pending = dpaa2_qdma_issue_pending; ++ ++ err = dma_async_device_register(&dpaa2_qdma->dma_dev); ++ if (err) { ++ dev_err(dev, "Can't register NXP QDMA engine.\n"); ++ goto err_reg; ++ } ++ ++ return 0; ++ ++err_reg: ++ dpaa2_dpdmai_free_channels(dpaa2_qdma); ++ kfree(dpaa2_qdma); ++err_eng: ++ dpdmai_disable(priv->mc_io, 0, dpdmai_dev->mc_handle); ++err_enable: ++ dpaa2_dpdmai_dpio_unbind(priv); ++err_bind: ++ dpaa2_dpmai_store_free(priv); ++ dpaa2_dpdmai_dpio_free(priv); ++err_dpio_setup: ++ dpdmai_close(priv->mc_io, 0, dpdmai_dev->mc_handle); ++err_dpdmai_setup: ++ fsl_mc_portal_free(priv->mc_io); ++err_mcportal: ++ kfree(priv->ppriv); ++ kfree(priv); ++ dev_set_drvdata(dev, NULL); ++ return err; ++} ++ ++static int dpaa2_qdma_remove(struct fsl_mc_device *ls_dev) ++{ ++ struct device *dev; ++ struct dpaa2_qdma_priv *priv; ++ struct dpaa2_qdma_engine *dpaa2_qdma; ++ ++ dev = &ls_dev->dev; ++ priv = dev_get_drvdata(dev); ++ dpaa2_qdma = priv->dpaa2_qdma; ++ ++ dpdmai_disable(priv->mc_io, 0, ls_dev->mc_handle); ++ dpaa2_dpdmai_dpio_unbind(priv); ++ dpaa2_dpmai_store_free(priv); ++ dpaa2_dpdmai_dpio_free(priv); ++ dpdmai_close(priv->mc_io, 0, ls_dev->mc_handle); ++ fsl_mc_portal_free(priv->mc_io); ++ dev_set_drvdata(dev, NULL); ++ dpaa2_dpdmai_free_channels(dpaa2_qdma); ++ ++ dma_async_device_unregister(&dpaa2_qdma->dma_dev); ++ kfree(priv); ++ kfree(dpaa2_qdma); ++ ++ return 0; ++} ++ ++static const struct fsl_mc_device_id dpaa2_qdma_id_table[] = { ++ { ++ .vendor = FSL_MC_VENDOR_FREESCALE, ++ .obj_type = "dpdmai", ++ }, ++ { .vendor = 0x0 } ++}; ++ ++static struct fsl_mc_driver dpaa2_qdma_driver = { ++ .driver = { ++ .name = "dpaa2-qdma", ++ .owner = THIS_MODULE, ++ }, ++ .probe = dpaa2_qdma_probe, ++ .remove = dpaa2_qdma_remove, ++ .match_id_table = dpaa2_qdma_id_table ++}; ++ ++static int __init dpaa2_qdma_driver_init(void) ++{ ++ return fsl_mc_driver_register(&(dpaa2_qdma_driver)); ++} ++late_initcall(dpaa2_qdma_driver_init); ++ ++static void __exit fsl_qdma_exit(void) ++{ ++ fsl_mc_driver_unregister(&(dpaa2_qdma_driver)); ++} ++module_exit(fsl_qdma_exit); ++ ++MODULE_DESCRIPTION("NXP DPAA2 qDMA driver"); ++MODULE_LICENSE("Dual BSD/GPL"); +diff --git a/drivers/dma/dpaa2-qdma/dpaa2-qdma.h b/drivers/dma/dpaa2-qdma/dpaa2-qdma.h +new file mode 100644 +index 00000000..71a00db8 +--- /dev/null ++++ b/drivers/dma/dpaa2-qdma/dpaa2-qdma.h +@@ -0,0 +1,262 @@ ++/* Copyright 2015 NXP Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of NXP Semiconductor nor the ++ * names of its contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY NXP Semiconductor ``AS IS'' AND ANY ++ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL NXP Semiconductor BE LIABLE FOR ANY ++ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ++ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ++ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ++ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++#ifndef __DPAA2_QDMA_H ++#define __DPAA2_QDMA_H ++ ++#define LONG_FORMAT 1 ++ ++#define DPAA2_QDMA_STORE_SIZE 16 ++#define NUM_CH 8 ++#define NUM_SG_PER_BLK 16 ++ ++#define QDMA_DMR_OFFSET 0x0 ++#define QDMA_DQ_EN (0 << 30) ++#define QDMA_DQ_DIS (1 << 30) ++ ++#define QDMA_DSR_M_OFFSET 0x10004 ++ ++struct dpaa2_qdma_sd_d { ++ uint32_t rsv:32; ++ union { ++ struct { ++ uint32_t ssd:12; /* souce stride distance */ ++ uint32_t sss:12; /* souce stride size */ ++ uint32_t rsv1:8; ++ } sdf; ++ struct { ++ uint32_t dsd:12; /* Destination stride distance */ ++ uint32_t dss:12; /* Destination stride size */ ++ uint32_t rsv2:8; ++ } ddf; ++ } df; ++ uint32_t rbpcmd; /* Route-by-port command */ ++ uint32_t cmd; ++} __attribute__((__packed__)); ++/* Source descriptor command read transaction type for RBP=0: ++ coherent copy of cacheable memory */ ++#define QDMA_SD_CMD_RDTTYPE_COHERENT (0xb << 28) ++/* Destination descriptor command write transaction type for RBP=0: ++ coherent copy of cacheable memory */ ++#define QDMA_DD_CMD_WRTTYPE_COHERENT (0x6 << 28) ++ ++#define QDMA_SG_FMT_SDB 0x0 /* single data buffer */ ++#define QDMA_SG_FMT_FDS 0x1 /* frame data section */ ++#define QDMA_SG_FMT_SGTE 0x2 /* SGT extension */ ++#define QDMA_SG_SL_SHORT 0x1 /* short length */ ++#define QDMA_SG_SL_LONG 0x0 /* short length */ ++#define QDMA_SG_F 0x1 /* last sg entry */ ++struct dpaa2_qdma_sg { ++ uint32_t addr_lo; /* address 0:31 */ ++ uint32_t addr_hi:17; /* address 32:48 */ ++ uint32_t rsv:15; ++ union { ++ uint32_t data_len_sl0; /* SL=0, the long format */ ++ struct { ++ uint32_t len:17; /* SL=1, the short format */ ++ uint32_t reserve:3; ++ uint32_t sf:1; ++ uint32_t sr:1; ++ uint32_t size:10; /* buff size */ ++ } data_len_sl1; ++ } data_len; /* AVAIL_LENGTH */ ++ struct { ++ uint32_t bpid:14; ++ uint32_t ivp:1; ++ uint32_t mbt:1; ++ uint32_t offset:12; ++ uint32_t fmt:2; ++ uint32_t sl:1; ++ uint32_t f:1; ++ } ctrl; ++} __attribute__((__packed__)); ++ ++#define QMAN_FD_FMT_ENABLE (1 << 12) /* frame list table enable */ ++#define QMAN_FD_BMT_ENABLE (1 << 15) /* bypass memory translation */ ++#define QMAN_FD_BMT_DISABLE (0 << 15) /* bypass memory translation */ ++#define QMAN_FD_SL_DISABLE (0 << 14) /* short lengthe disabled */ ++#define QMAN_FD_SL_ENABLE (1 << 14) /* short lengthe enabled */ ++ ++#define QDMA_SB_FRAME (0 << 28) /* single frame */ ++#define QDMA_SG_FRAME (2 << 28) /* scatter gather frames */ ++#define QDMA_FINAL_BIT_DISABLE (0 << 31) /* final bit disable */ ++#define QDMA_FINAL_BIT_ENABLE (1 << 31) /* final bit enable */ ++ ++#define QDMA_FD_SHORT_FORMAT (1 << 11) /* short format */ ++#define QDMA_FD_LONG_FORMAT (0 << 11) /* long format */ ++#define QDMA_SER_DISABLE (0 << 8) /* no notification */ ++#define QDMA_SER_CTX (1 << 8) /* notification by FQD_CTX[fqid] */ ++#define QDMA_SER_DEST (2 << 8) /* notification by destination desc */ ++#define QDMA_SER_BOTH (3 << 8) /* soruce and dest notification */ ++#define QDMA_FD_SPF_ENALBE (1 << 30) /* source prefetch enable */ ++ ++#define QMAN_FD_VA_ENABLE (1 << 14) /* Address used is virtual address */ ++#define QMAN_FD_VA_DISABLE (0 << 14)/* Address used is a real address */ ++#define QMAN_FD_CBMT_ENABLE (1 << 15) /* Flow Context: 49bit physical address */ ++#define QMAN_FD_CBMT_DISABLE (0 << 15) /* Flow Context: 64bit virtual address */ ++#define QMAN_FD_SC_DISABLE (0 << 27) /* stashing control */ ++ ++#define QDMA_FL_FMT_SBF 0x0 /* Single buffer frame */ ++#define QDMA_FL_FMT_SGE 0x2 /* Scatter gather frame */ ++#define QDMA_FL_BMT_ENABLE 0x1 /* enable bypass memory translation */ ++#define QDMA_FL_BMT_DISABLE 0x0 /* enable bypass memory translation */ ++#define QDMA_FL_SL_LONG 0x0 /* long length */ ++#define QDMA_FL_SL_SHORT 0x1 /* short length */ ++#define QDMA_FL_F 0x1 /* last frame list bit */ ++/*Description of Frame list table structure*/ ++struct dpaa2_frame_list { ++ uint32_t addr_lo; /* lower 32 bits of address */ ++ uint32_t addr_hi:17; /* upper 17 bits of address */ ++ uint32_t resrvd:15; ++ union { ++ uint32_t data_len_sl0; /* If SL=0, then data length is 32 */ ++ struct { ++ uint32_t data_len:18; /* IF SL=1; length is 18bit */ ++ uint32_t resrvd:2; ++ uint32_t mem:12; /* Valid only when SL=1 */ ++ } data_len_sl1; ++ } data_len; ++ /* word 4 */ ++ uint32_t bpid:14; /* Frame buffer pool ID */ ++ uint32_t ivp:1; /* Invalid Pool ID. */ ++ uint32_t bmt:1; /* Bypass Memory Translation */ ++ uint32_t offset:12; /* Frame offset */ ++ uint32_t fmt:2; /* Frame Format */ ++ uint32_t sl:1; /* Short Length */ ++ uint32_t f:1; /* Final bit */ ++ ++ uint32_t frc; /* Frame Context */ ++ /* word 6 */ ++ uint32_t err:8; /* Frame errors */ ++ uint32_t resrvd0:8; ++ uint32_t asal:4; /* accelerator-specific annotation length */ ++ uint32_t resrvd1:1; ++ uint32_t ptv2:1; ++ uint32_t ptv1:1; ++ uint32_t pta:1; /* pass-through annotation */ ++ uint32_t resrvd2:8; ++ ++ uint32_t flc_lo; /* lower 32 bits fo flow context */ ++ uint32_t flc_hi; /* higher 32 bits fo flow context */ ++} __attribute__((__packed__)); ++ ++struct dpaa2_qdma_chan { ++ struct virt_dma_chan vchan; ++ struct virt_dma_desc vdesc; ++ enum dma_status status; ++ struct dpaa2_qdma_engine *qdma; ++ ++ struct mutex dpaa2_queue_mutex; ++ spinlock_t queue_lock; ++ struct dma_pool *fd_pool; ++ struct dma_pool *sg_blk_pool; ++ ++ struct list_head comp_used; ++ struct list_head comp_free; ++ ++ struct list_head sgb_free; ++}; ++ ++struct qdma_sg_blk { ++ dma_addr_t blk_bus_addr; ++ void *blk_virt_addr; ++ struct list_head list; ++}; ++ ++struct dpaa2_qdma_comp { ++ dma_addr_t fd_bus_addr; ++ dma_addr_t fl_bus_addr; ++ dma_addr_t desc_bus_addr; ++ dma_addr_t sge_src_bus_addr; ++ dma_addr_t sge_dst_bus_addr; ++ void *fd_virt_addr; ++ void *fl_virt_addr; ++ void *desc_virt_addr; ++ void *sg_src_virt_addr; ++ void *sg_dst_virt_addr; ++ struct qdma_sg_blk *sg_blk; ++ uint32_t sg_blk_num; ++ struct list_head sg_src_head; ++ struct list_head sg_dst_head; ++ struct dpaa2_qdma_chan *qchan; ++ struct virt_dma_desc vdesc; ++ struct list_head list; ++}; ++ ++struct dpaa2_qdma_engine { ++ struct dma_device dma_dev; ++ u32 n_chans; ++ struct dpaa2_qdma_chan chans[NUM_CH]; ++ ++ struct dpaa2_qdma_priv *priv; ++}; ++ ++/* ++ * dpaa2_qdma_priv - driver private data ++ */ ++struct dpaa2_qdma_priv { ++ int dpqdma_id; ++ ++ struct iommu_domain *iommu_domain; ++ struct dpdmai_attr dpdmai_attr; ++ struct device *dev; ++ struct fsl_mc_io *mc_io; ++ struct fsl_mc_device *dpdmai_dev; ++ ++ struct dpdmai_rx_queue_attr rx_queue_attr[DPDMAI_PRIO_NUM]; ++ struct dpdmai_tx_queue_attr tx_queue_attr[DPDMAI_PRIO_NUM]; ++ ++ uint8_t num_pairs; ++ ++ struct dpaa2_qdma_engine *dpaa2_qdma; ++ struct dpaa2_qdma_priv_per_prio *ppriv; ++}; ++ ++struct dpaa2_qdma_priv_per_prio { ++ int req_fqid; ++ int rsp_fqid; ++ int prio; ++ ++ struct dpaa2_io_store *store; ++ struct dpaa2_io_notification_ctx nctx; ++ ++ struct dpaa2_qdma_priv *priv; ++}; ++ ++/* FD pool size: one FD + 3 Frame list + 2 source/destination descriptor */ ++#define FD_POOL_SIZE (sizeof(struct dpaa2_fd) + \ ++ sizeof(struct dpaa2_frame_list) * 3 + \ ++ sizeof(struct dpaa2_qdma_sd_d) * 2) ++ ++/* qdma_sg_blk + 16 SGs */ ++#define SG_POOL_SIZE (sizeof(struct qdma_sg_blk) +\ ++ sizeof(struct dpaa2_qdma_sg) * NUM_SG_PER_BLK) ++#endif /* __DPAA2_QDMA_H */ +diff --git a/drivers/dma/dpaa2-qdma/dpdmai.c b/drivers/dma/dpaa2-qdma/dpdmai.c +new file mode 100644 +index 00000000..ad13fc1e +--- /dev/null ++++ b/drivers/dma/dpaa2-qdma/dpdmai.c +@@ -0,0 +1,454 @@ ++/* Copyright 2013-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#include ++#include ++#include "fsl_dpdmai.h" ++#include "fsl_dpdmai_cmd.h" ++#include "../../../drivers/staging/fsl-mc/include/mc-sys.h" ++#include "../../../drivers/staging/fsl-mc/include/mc-cmd.h" ++ ++int dpdmai_open(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ int dpdmai_id, ++ uint16_t *token) ++{ ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_OPEN, ++ cmd_flags, ++ 0); ++ DPDMAI_CMD_OPEN(cmd, dpdmai_id); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *token = MC_CMD_HDR_READ_TOKEN(cmd.header); ++ ++ return 0; ++} ++ ++int dpdmai_close(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_CLOSE, ++ cmd_flags, token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++int dpdmai_create(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ const struct dpdmai_cfg *cfg, ++ uint16_t *token) ++{ ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_CREATE, ++ cmd_flags, ++ 0); ++ DPDMAI_CMD_CREATE(cmd, cfg); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ *token = MC_CMD_HDR_READ_TOKEN(cmd.header); ++ ++ return 0; ++} ++ ++int dpdmai_destroy(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_DESTROY, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++int dpdmai_enable(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_ENABLE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++int dpdmai_disable(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_DISABLE, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++int dpdmai_is_enabled(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ int *en) ++{ ++ struct mc_command cmd = { 0 }; ++ int err; ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_IS_ENABLED, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ DPDMAI_RSP_IS_ENABLED(cmd, *en); ++ ++ return 0; ++} ++ ++int dpdmai_reset(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_RESET, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++int dpdmai_get_irq(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ int *type, ++ struct dpdmai_irq_cfg *irq_cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_GET_IRQ, ++ cmd_flags, ++ token); ++ DPDMAI_CMD_GET_IRQ(cmd, irq_index); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ DPDMAI_RSP_GET_IRQ(cmd, *type, irq_cfg); ++ ++ return 0; ++} ++ ++int dpdmai_set_irq(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ struct dpdmai_irq_cfg *irq_cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_SET_IRQ, ++ cmd_flags, ++ token); ++ DPDMAI_CMD_SET_IRQ(cmd, irq_index, irq_cfg); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++int dpdmai_get_irq_enable(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint8_t *en) ++{ ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_GET_IRQ_ENABLE, ++ cmd_flags, ++ token); ++ DPDMAI_CMD_GET_IRQ_ENABLE(cmd, irq_index); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ DPDMAI_RSP_GET_IRQ_ENABLE(cmd, *en); ++ ++ return 0; ++} ++ ++int dpdmai_set_irq_enable(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint8_t en) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_SET_IRQ_ENABLE, ++ cmd_flags, ++ token); ++ DPDMAI_CMD_SET_IRQ_ENABLE(cmd, irq_index, en); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++int dpdmai_get_irq_mask(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint32_t *mask) ++{ ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_GET_IRQ_MASK, ++ cmd_flags, ++ token); ++ DPDMAI_CMD_GET_IRQ_MASK(cmd, irq_index); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ DPDMAI_RSP_GET_IRQ_MASK(cmd, *mask); ++ ++ return 0; ++} ++ ++int dpdmai_set_irq_mask(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint32_t mask) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_SET_IRQ_MASK, ++ cmd_flags, ++ token); ++ DPDMAI_CMD_SET_IRQ_MASK(cmd, irq_index, mask); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++int dpdmai_get_irq_status(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint32_t *status) ++{ ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_GET_IRQ_STATUS, ++ cmd_flags, ++ token); ++ DPDMAI_CMD_GET_IRQ_STATUS(cmd, irq_index, *status); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ DPDMAI_RSP_GET_IRQ_STATUS(cmd, *status); ++ ++ return 0; ++} ++ ++int dpdmai_clear_irq_status(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint32_t status) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_CLEAR_IRQ_STATUS, ++ cmd_flags, ++ token); ++ DPDMAI_CMD_CLEAR_IRQ_STATUS(cmd, irq_index, status); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++int dpdmai_get_attributes(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ struct dpdmai_attr *attr) ++{ ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_GET_ATTR, ++ cmd_flags, ++ token); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ DPDMAI_RSP_GET_ATTR(cmd, attr); ++ ++ return 0; ++} ++ ++int dpdmai_set_rx_queue(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t priority, ++ const struct dpdmai_rx_queue_cfg *cfg) ++{ ++ struct mc_command cmd = { 0 }; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_SET_RX_QUEUE, ++ cmd_flags, ++ token); ++ DPDMAI_CMD_SET_RX_QUEUE(cmd, priority, cfg); ++ ++ /* send command to mc*/ ++ return mc_send_command(mc_io, &cmd); ++} ++ ++int dpdmai_get_rx_queue(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t priority, struct dpdmai_rx_queue_attr *attr) ++{ ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_GET_RX_QUEUE, ++ cmd_flags, ++ token); ++ DPDMAI_CMD_GET_RX_QUEUE(cmd, priority); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ DPDMAI_RSP_GET_RX_QUEUE(cmd, attr); ++ ++ return 0; ++} ++ ++int dpdmai_get_tx_queue(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t priority, ++ struct dpdmai_tx_queue_attr *attr) ++{ ++ struct mc_command cmd = { 0 }; ++ int err; ++ ++ /* prepare command */ ++ cmd.header = mc_encode_cmd_header(DPDMAI_CMDID_GET_TX_QUEUE, ++ cmd_flags, ++ token); ++ DPDMAI_CMD_GET_TX_QUEUE(cmd, priority); ++ ++ /* send command to mc*/ ++ err = mc_send_command(mc_io, &cmd); ++ if (err) ++ return err; ++ ++ /* retrieve response parameters */ ++ DPDMAI_RSP_GET_TX_QUEUE(cmd, attr); ++ ++ return 0; ++} +diff --git a/drivers/dma/dpaa2-qdma/fsl_dpdmai.h b/drivers/dma/dpaa2-qdma/fsl_dpdmai.h +new file mode 100644 +index 00000000..e931ce16 +--- /dev/null ++++ b/drivers/dma/dpaa2-qdma/fsl_dpdmai.h +@@ -0,0 +1,521 @@ ++/* Copyright 2013-2015 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef __FSL_DPDMAI_H ++#define __FSL_DPDMAI_H ++ ++struct fsl_mc_io; ++ ++/* Data Path DMA Interface API ++ * Contains initialization APIs and runtime control APIs for DPDMAI ++ */ ++ ++/* General DPDMAI macros */ ++ ++/** ++ * Maximum number of Tx/Rx priorities per DPDMAI object ++ */ ++#define DPDMAI_PRIO_NUM 2 ++ ++/** ++ * All queues considered; see dpdmai_set_rx_queue() ++ */ ++#define DPDMAI_ALL_QUEUES (uint8_t)(-1) ++ ++/** ++ * dpdmai_open() - Open a control session for the specified object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @dpdmai_id: DPDMAI unique ID ++ * @token: Returned token; use in subsequent API calls ++ * ++ * This function can be used to open a control session for an ++ * already created object; an object may have been declared in ++ * the DPL or by calling the dpdmai_create() function. ++ * This function returns a unique authentication token, ++ * associated with the specific object ID and the specific MC ++ * portal; this token must be used in all subsequent commands for ++ * this specific object. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_open(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ int dpdmai_id, ++ uint16_t *token); ++ ++/** ++ * dpdmai_close() - Close the control session of the object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * ++ * After this function is called, no further operations are ++ * allowed on the object without opening a new control session. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_close(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token); ++ ++/** ++ * struct dpdmai_cfg - Structure representing DPDMAI configuration ++ * @priorities: Priorities for the DMA hardware processing; valid priorities are ++ * configured with values 1-8; the entry following last valid entry ++ * should be configured with 0 ++ */ ++struct dpdmai_cfg { ++ uint8_t priorities[DPDMAI_PRIO_NUM]; ++}; ++ ++/** ++ * dpdmai_create() - Create the DPDMAI object ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @cfg: Configuration structure ++ * @token: Returned token; use in subsequent API calls ++ * ++ * Create the DPDMAI object, allocate required resources and ++ * perform required initialization. ++ * ++ * The object can be created either by declaring it in the ++ * DPL file, or by calling this function. ++ * ++ * This function returns a unique authentication token, ++ * associated with the specific object ID and the specific MC ++ * portal; this token must be used in all subsequent calls to ++ * this specific object. For objects that are created using the ++ * DPL file, call dpdmai_open() function to get an authentication ++ * token first. ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_create(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ const struct dpdmai_cfg *cfg, ++ uint16_t *token); ++ ++/** ++ * dpdmai_destroy() - Destroy the DPDMAI object and release all its resources. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * ++ * Return: '0' on Success; error code otherwise. ++ */ ++int dpdmai_destroy(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token); ++ ++/** ++ * dpdmai_enable() - Enable the DPDMAI, allow sending and receiving frames. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_enable(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token); ++ ++/** ++ * dpdmai_disable() - Disable the DPDMAI, stop sending and receiving frames. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_disable(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token); ++ ++/** ++ * dpdmai_is_enabled() - Check if the DPDMAI is enabled. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * @en: Returns '1' if object is enabled; '0' otherwise ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_is_enabled(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ int *en); ++ ++/** ++ * dpdmai_reset() - Reset the DPDMAI, returns the object to initial state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_reset(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token); ++ ++/** ++ * struct dpdmai_irq_cfg - IRQ configuration ++ * @addr: Address that must be written to signal a message-based interrupt ++ * @val: Value to write into irq_addr address ++ * @irq_num: A user defined number associated with this IRQ ++ */ ++struct dpdmai_irq_cfg { ++ uint64_t addr; ++ uint32_t val; ++ int irq_num; ++}; ++ ++/** ++ * dpdmai_set_irq() - Set IRQ information for the DPDMAI to trigger an interrupt. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * @irq_index: Identifies the interrupt index to configure ++ * @irq_cfg: IRQ configuration ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_set_irq(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ struct dpdmai_irq_cfg *irq_cfg); ++ ++/** ++ * dpdmai_get_irq() - Get IRQ information from the DPDMAI ++ * ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * @irq_index: The interrupt index to configure ++ * @type: Interrupt type: 0 represents message interrupt ++ * type (both irq_addr and irq_val are valid) ++ * @irq_cfg: IRQ attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_get_irq(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ int *type, ++ struct dpdmai_irq_cfg *irq_cfg); ++ ++/** ++ * dpdmai_set_irq_enable() - Set overall interrupt state. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * @irq_index: The interrupt index to configure ++ * @en: Interrupt state - enable = 1, disable = 0 ++ * ++ * Allows GPP software to control when interrupts are generated. ++ * Each interrupt can have up to 32 causes. The enable/disable control's the ++ * overall interrupt state. if the interrupt is disabled no causes will cause ++ * an interrupt ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_set_irq_enable(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint8_t en); ++ ++/** ++ * dpdmai_get_irq_enable() - Get overall interrupt state ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * @irq_index: The interrupt index to configure ++ * @en: Returned Interrupt state - enable = 1, disable = 0 ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_get_irq_enable(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint8_t *en); ++ ++/** ++ * dpdmai_set_irq_mask() - Set interrupt mask. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * @irq_index: The interrupt index to configure ++ * @mask: event mask to trigger interrupt; ++ * each bit: ++ * 0 = ignore event ++ * 1 = consider event for asserting IRQ ++ * ++ * Every interrupt can have up to 32 causes and the interrupt model supports ++ * masking/unmasking each cause independently ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_set_irq_mask(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint32_t mask); ++ ++/** ++ * dpdmai_get_irq_mask() - Get interrupt mask. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * @irq_index: The interrupt index to configure ++ * @mask: Returned event mask to trigger interrupt ++ * ++ * Every interrupt can have up to 32 causes and the interrupt model supports ++ * masking/unmasking each cause independently ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_get_irq_mask(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint32_t *mask); ++ ++/** ++ * dpdmai_get_irq_status() - Get the current status of any pending interrupts ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * @irq_index: The interrupt index to configure ++ * @status: Returned interrupts status - one bit per cause: ++ * 0 = no interrupt pending ++ * 1 = interrupt pending ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_get_irq_status(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint32_t *status); ++ ++/** ++ * dpdmai_clear_irq_status() - Clear a pending interrupt's status ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * @irq_index: The interrupt index to configure ++ * @status: bits to clear (W1C) - one bit per cause: ++ * 0 = don't change ++ * 1 = clear status bit ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_clear_irq_status(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t irq_index, ++ uint32_t status); ++ ++/** ++ * struct dpdmai_attr - Structure representing DPDMAI attributes ++ * @id: DPDMAI object ID ++ * @version: DPDMAI version ++ * @num_of_priorities: number of priorities ++ */ ++struct dpdmai_attr { ++ int id; ++ /** ++ * struct version - DPDMAI version ++ * @major: DPDMAI major version ++ * @minor: DPDMAI minor version ++ */ ++ struct { ++ uint16_t major; ++ uint16_t minor; ++ } version; ++ uint8_t num_of_priorities; ++}; ++ ++/** ++ * dpdmai_get_attributes() - Retrieve DPDMAI attributes. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * @attr: Returned object's attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_get_attributes(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ struct dpdmai_attr *attr); ++ ++/** ++ * enum dpdmai_dest - DPDMAI destination types ++ * @DPDMAI_DEST_NONE: Unassigned destination; The queue is set in parked mode ++ * and does not generate FQDAN notifications; user is expected to dequeue ++ * from the queue based on polling or other user-defined method ++ * @DPDMAI_DEST_DPIO: The queue is set in schedule mode and generates FQDAN ++ * notifications to the specified DPIO; user is expected to dequeue ++ * from the queue only after notification is received ++ * @DPDMAI_DEST_DPCON: The queue is set in schedule mode and does not generate ++ * FQDAN notifications, but is connected to the specified DPCON object; ++ * user is expected to dequeue from the DPCON channel ++ */ ++enum dpdmai_dest { ++ DPDMAI_DEST_NONE = 0, ++ DPDMAI_DEST_DPIO = 1, ++ DPDMAI_DEST_DPCON = 2 ++}; ++ ++/** ++ * struct dpdmai_dest_cfg - Structure representing DPDMAI destination parameters ++ * @dest_type: Destination type ++ * @dest_id: Either DPIO ID or DPCON ID, depending on the destination type ++ * @priority: Priority selection within the DPIO or DPCON channel; valid values ++ * are 0-1 or 0-7, depending on the number of priorities in that ++ * channel; not relevant for 'DPDMAI_DEST_NONE' option ++ */ ++struct dpdmai_dest_cfg { ++ enum dpdmai_dest dest_type; ++ int dest_id; ++ uint8_t priority; ++}; ++ ++/* DPDMAI queue modification options */ ++ ++/** ++ * Select to modify the user's context associated with the queue ++ */ ++#define DPDMAI_QUEUE_OPT_USER_CTX 0x00000001 ++ ++/** ++ * Select to modify the queue's destination ++ */ ++#define DPDMAI_QUEUE_OPT_DEST 0x00000002 ++ ++/** ++ * struct dpdmai_rx_queue_cfg - DPDMAI RX queue configuration ++ * @options: Flags representing the suggested modifications to the queue; ++ * Use any combination of 'DPDMAI_QUEUE_OPT_' flags ++ * @user_ctx: User context value provided in the frame descriptor of each ++ * dequeued frame; ++ * valid only if 'DPDMAI_QUEUE_OPT_USER_CTX' is contained in 'options' ++ * @dest_cfg: Queue destination parameters; ++ * valid only if 'DPDMAI_QUEUE_OPT_DEST' is contained in 'options' ++ */ ++struct dpdmai_rx_queue_cfg { ++ uint32_t options; ++ uint64_t user_ctx; ++ struct dpdmai_dest_cfg dest_cfg; ++ ++}; ++ ++/** ++ * dpdmai_set_rx_queue() - Set Rx queue configuration ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * @priority: Select the queue relative to number of ++ * priorities configured at DPDMAI creation; use ++ * DPDMAI_ALL_QUEUES to configure all Rx queues ++ * identically. ++ * @cfg: Rx queue configuration ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_set_rx_queue(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t priority, ++ const struct dpdmai_rx_queue_cfg *cfg); ++ ++/** ++ * struct dpdmai_rx_queue_attr - Structure representing attributes of Rx queues ++ * @user_ctx: User context value provided in the frame descriptor of each ++ * dequeued frame ++ * @dest_cfg: Queue destination configuration ++ * @fqid: Virtual FQID value to be used for dequeue operations ++ */ ++struct dpdmai_rx_queue_attr { ++ uint64_t user_ctx; ++ struct dpdmai_dest_cfg dest_cfg; ++ uint32_t fqid; ++}; ++ ++/** ++ * dpdmai_get_rx_queue() - Retrieve Rx queue attributes. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * @priority: Select the queue relative to number of ++ * priorities configured at DPDMAI creation ++ * @attr: Returned Rx queue attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_get_rx_queue(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t priority, ++ struct dpdmai_rx_queue_attr *attr); ++ ++/** ++ * struct dpdmai_tx_queue_attr - Structure representing attributes of Tx queues ++ * @fqid: Virtual FQID to be used for sending frames to DMA hardware ++ */ ++ ++struct dpdmai_tx_queue_attr { ++ uint32_t fqid; ++}; ++ ++/** ++ * dpdmai_get_tx_queue() - Retrieve Tx queue attributes. ++ * @mc_io: Pointer to MC portal's I/O object ++ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' ++ * @token: Token of DPDMAI object ++ * @priority: Select the queue relative to number of ++ * priorities configured at DPDMAI creation ++ * @attr: Returned Tx queue attributes ++ * ++ * Return: '0' on Success; Error code otherwise. ++ */ ++int dpdmai_get_tx_queue(struct fsl_mc_io *mc_io, ++ uint32_t cmd_flags, ++ uint16_t token, ++ uint8_t priority, ++ struct dpdmai_tx_queue_attr *attr); ++ ++#endif /* __FSL_DPDMAI_H */ +diff --git a/drivers/dma/dpaa2-qdma/fsl_dpdmai_cmd.h b/drivers/dma/dpaa2-qdma/fsl_dpdmai_cmd.h +new file mode 100644 +index 00000000..7d403c01 +--- /dev/null ++++ b/drivers/dma/dpaa2-qdma/fsl_dpdmai_cmd.h +@@ -0,0 +1,222 @@ ++/* Copyright 2013-2016 Freescale Semiconductor Inc. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are met: ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * * Neither the name of the above-listed copyright holders nor the ++ * names of any contributors may be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * ++ * ALTERNATIVELY, this software may be distributed under the terms of the ++ * GNU General Public License ("GPL") as published by the Free Software ++ * Foundation, either version 2 of that License or (at your option) any ++ * later version. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++ * POSSIBILITY OF SUCH DAMAGE. ++ */ ++#ifndef _FSL_DPDMAI_CMD_H ++#define _FSL_DPDMAI_CMD_H ++ ++/* DPDMAI Version */ ++#define DPDMAI_VER_MAJOR 2 ++#define DPDMAI_VER_MINOR 2 ++ ++#define DPDMAI_CMD_BASE_VERSION 0 ++#define DPDMAI_CMD_ID_OFFSET 4 ++ ++/* Command IDs */ ++#define DPDMAI_CMDID_CLOSE ((0x800 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++#define DPDMAI_CMDID_OPEN ((0x80E << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++#define DPDMAI_CMDID_CREATE ((0x90E << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++#define DPDMAI_CMDID_DESTROY ((0x900 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++ ++#define DPDMAI_CMDID_ENABLE ((0x002 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++#define DPDMAI_CMDID_DISABLE ((0x003 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++#define DPDMAI_CMDID_GET_ATTR ((0x004 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++#define DPDMAI_CMDID_RESET ((0x005 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++#define DPDMAI_CMDID_IS_ENABLED ((0x006 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++ ++#define DPDMAI_CMDID_SET_IRQ ((0x010 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++#define DPDMAI_CMDID_GET_IRQ ((0x011 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++#define DPDMAI_CMDID_SET_IRQ_ENABLE ((0x012 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++#define DPDMAI_CMDID_GET_IRQ_ENABLE ((0x013 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++#define DPDMAI_CMDID_SET_IRQ_MASK ((0x014 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++#define DPDMAI_CMDID_GET_IRQ_MASK ((0x015 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++#define DPDMAI_CMDID_GET_IRQ_STATUS ((0x016 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++#define DPDMAI_CMDID_CLEAR_IRQ_STATUS ((0x017 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++ ++#define DPDMAI_CMDID_SET_RX_QUEUE ((0x1A0 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++#define DPDMAI_CMDID_GET_RX_QUEUE ((0x1A1 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++#define DPDMAI_CMDID_GET_TX_QUEUE ((0x1A2 << DPDMAI_CMD_ID_OFFSET) | DPDMAI_CMD_BASE_VERSION) ++ ++ ++#define MC_CMD_HDR_TOKEN_O 32 /* Token field offset */ ++#define MC_CMD_HDR_TOKEN_S 16 /* Token field size */ ++ ++ ++#define MAKE_UMASK64(_width) \ ++ ((uint64_t)((_width) < 64 ? ((uint64_t)1 << (_width)) - 1 : \ ++ (uint64_t)-1)) ++ ++static inline uint64_t mc_enc(int lsoffset, int width, uint64_t val) ++{ ++ return (uint64_t)(((uint64_t)val & MAKE_UMASK64(width)) << lsoffset); ++} ++ ++static inline uint64_t mc_dec(uint64_t val, int lsoffset, int width) ++{ ++ return (uint64_t)((val >> lsoffset) & MAKE_UMASK64(width)); ++} ++ ++#define MC_CMD_OP(_cmd, _param, _offset, _width, _type, _arg) \ ++ ((_cmd).params[_param] |= mc_enc((_offset), (_width), _arg)) ++ ++#define MC_RSP_OP(_cmd, _param, _offset, _width, _type, _arg) \ ++ (_arg = (_type)mc_dec(_cmd.params[_param], (_offset), (_width))) ++ ++#define MC_CMD_HDR_READ_TOKEN(_hdr) \ ++ ((uint16_t)mc_dec((_hdr), MC_CMD_HDR_TOKEN_O, MC_CMD_HDR_TOKEN_S)) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_CMD_OPEN(cmd, dpdmai_id) \ ++ MC_CMD_OP(cmd, 0, 0, 32, int, dpdmai_id) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_CMD_CREATE(cmd, cfg) \ ++do { \ ++ MC_CMD_OP(cmd, 0, 8, 8, uint8_t, cfg->priorities[0]);\ ++ MC_CMD_OP(cmd, 0, 16, 8, uint8_t, cfg->priorities[1]);\ ++} while (0) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_RSP_IS_ENABLED(cmd, en) \ ++ MC_RSP_OP(cmd, 0, 0, 1, int, en) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_CMD_SET_IRQ(cmd, irq_index, irq_cfg) \ ++do { \ ++ MC_CMD_OP(cmd, 0, 0, 8, uint8_t, irq_index);\ ++ MC_CMD_OP(cmd, 0, 32, 32, uint32_t, irq_cfg->val);\ ++ MC_CMD_OP(cmd, 1, 0, 64, uint64_t, irq_cfg->addr);\ ++ MC_CMD_OP(cmd, 2, 0, 32, int, irq_cfg->irq_num); \ ++} while (0) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_CMD_GET_IRQ(cmd, irq_index) \ ++ MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_RSP_GET_IRQ(cmd, type, irq_cfg) \ ++do { \ ++ MC_RSP_OP(cmd, 0, 0, 32, uint32_t, irq_cfg->val); \ ++ MC_RSP_OP(cmd, 1, 0, 64, uint64_t, irq_cfg->addr);\ ++ MC_RSP_OP(cmd, 2, 0, 32, int, irq_cfg->irq_num); \ ++ MC_RSP_OP(cmd, 2, 32, 32, int, type); \ ++} while (0) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_CMD_SET_IRQ_ENABLE(cmd, irq_index, enable_state) \ ++do { \ ++ MC_CMD_OP(cmd, 0, 0, 8, uint8_t, enable_state); \ ++ MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index); \ ++} while (0) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_CMD_GET_IRQ_ENABLE(cmd, irq_index) \ ++ MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_RSP_GET_IRQ_ENABLE(cmd, enable_state) \ ++ MC_RSP_OP(cmd, 0, 0, 8, uint8_t, enable_state) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_CMD_SET_IRQ_MASK(cmd, irq_index, mask) \ ++do { \ ++ MC_CMD_OP(cmd, 0, 0, 32, uint32_t, mask); \ ++ MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index); \ ++} while (0) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_CMD_GET_IRQ_MASK(cmd, irq_index) \ ++ MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_RSP_GET_IRQ_MASK(cmd, mask) \ ++ MC_RSP_OP(cmd, 0, 0, 32, uint32_t, mask) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_CMD_GET_IRQ_STATUS(cmd, irq_index, status) \ ++do { \ ++ MC_CMD_OP(cmd, 0, 0, 32, uint32_t, status);\ ++ MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index);\ ++} while (0) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_RSP_GET_IRQ_STATUS(cmd, status) \ ++ MC_RSP_OP(cmd, 0, 0, 32, uint32_t, status) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_CMD_CLEAR_IRQ_STATUS(cmd, irq_index, status) \ ++do { \ ++ MC_CMD_OP(cmd, 0, 0, 32, uint32_t, status); \ ++ MC_CMD_OP(cmd, 0, 32, 8, uint8_t, irq_index); \ ++} while (0) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_RSP_GET_ATTR(cmd, attr) \ ++do { \ ++ MC_RSP_OP(cmd, 0, 0, 32, int, attr->id); \ ++ MC_RSP_OP(cmd, 0, 32, 8, uint8_t, attr->num_of_priorities); \ ++ MC_RSP_OP(cmd, 1, 0, 16, uint16_t, attr->version.major);\ ++ MC_RSP_OP(cmd, 1, 16, 16, uint16_t, attr->version.minor);\ ++} while (0) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_CMD_SET_RX_QUEUE(cmd, priority, cfg) \ ++do { \ ++ MC_CMD_OP(cmd, 0, 0, 32, int, cfg->dest_cfg.dest_id); \ ++ MC_CMD_OP(cmd, 0, 32, 8, uint8_t, cfg->dest_cfg.priority); \ ++ MC_CMD_OP(cmd, 0, 40, 8, uint8_t, priority); \ ++ MC_CMD_OP(cmd, 0, 48, 4, enum dpdmai_dest, cfg->dest_cfg.dest_type); \ ++ MC_CMD_OP(cmd, 1, 0, 64, uint64_t, cfg->user_ctx); \ ++ MC_CMD_OP(cmd, 2, 0, 32, uint32_t, cfg->options);\ ++} while (0) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_CMD_GET_RX_QUEUE(cmd, priority) \ ++ MC_CMD_OP(cmd, 0, 40, 8, uint8_t, priority) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_RSP_GET_RX_QUEUE(cmd, attr) \ ++do { \ ++ MC_RSP_OP(cmd, 0, 0, 32, int, attr->dest_cfg.dest_id);\ ++ MC_RSP_OP(cmd, 0, 32, 8, uint8_t, attr->dest_cfg.priority);\ ++ MC_RSP_OP(cmd, 0, 48, 4, enum dpdmai_dest, attr->dest_cfg.dest_type);\ ++ MC_RSP_OP(cmd, 1, 0, 64, uint64_t, attr->user_ctx);\ ++ MC_RSP_OP(cmd, 2, 0, 32, uint32_t, attr->fqid);\ ++} while (0) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_CMD_GET_TX_QUEUE(cmd, priority) \ ++ MC_CMD_OP(cmd, 0, 40, 8, uint8_t, priority) ++ ++/* cmd, param, offset, width, type, arg_name */ ++#define DPDMAI_RSP_GET_TX_QUEUE(cmd, attr) \ ++ MC_RSP_OP(cmd, 1, 0, 32, uint32_t, attr->fqid) ++ ++#endif /* _FSL_DPDMAI_CMD_H */ +diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c +new file mode 100644 +index 00000000..6c4c2813 +--- /dev/null ++++ b/drivers/dma/fsl-qdma.c +@@ -0,0 +1,1201 @@ ++/* ++ * drivers/dma/fsl-qdma.c ++ * ++ * Copyright 2014-2015 Freescale Semiconductor, Inc. ++ * ++ * Driver for the Freescale qDMA engine with software command queue mode. ++ * Channel virtualization is supported through enqueuing of DMA jobs to, ++ * or dequeuing DMA jobs from, different work queues. ++ * This module can be found on Freescale LS SoCs. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "virt-dma.h" ++ ++#define FSL_QDMA_DMR 0x0 ++#define FSL_QDMA_DSR 0x4 ++#define FSL_QDMA_DEIER 0xe00 ++#define FSL_QDMA_DEDR 0xe04 ++#define FSL_QDMA_DECFDW0R 0xe10 ++#define FSL_QDMA_DECFDW1R 0xe14 ++#define FSL_QDMA_DECFDW2R 0xe18 ++#define FSL_QDMA_DECFDW3R 0xe1c ++#define FSL_QDMA_DECFQIDR 0xe30 ++#define FSL_QDMA_DECBR 0xe34 ++ ++#define FSL_QDMA_BCQMR(x) (0xc0 + 0x100 * (x)) ++#define FSL_QDMA_BCQSR(x) (0xc4 + 0x100 * (x)) ++#define FSL_QDMA_BCQEDPA_SADDR(x) (0xc8 + 0x100 * (x)) ++#define FSL_QDMA_BCQDPA_SADDR(x) (0xcc + 0x100 * (x)) ++#define FSL_QDMA_BCQEEPA_SADDR(x) (0xd0 + 0x100 * (x)) ++#define FSL_QDMA_BCQEPA_SADDR(x) (0xd4 + 0x100 * (x)) ++#define FSL_QDMA_BCQIER(x) (0xe0 + 0x100 * (x)) ++#define FSL_QDMA_BCQIDR(x) (0xe4 + 0x100 * (x)) ++ ++#define FSL_QDMA_SQDPAR 0x80c ++#define FSL_QDMA_SQEPAR 0x814 ++#define FSL_QDMA_BSQMR 0x800 ++#define FSL_QDMA_BSQSR 0x804 ++#define FSL_QDMA_BSQICR 0x828 ++#define FSL_QDMA_CQMR 0xa00 ++#define FSL_QDMA_CQDSCR1 0xa08 ++#define FSL_QDMA_CQDSCR2 0xa0c ++#define FSL_QDMA_CQIER 0xa10 ++#define FSL_QDMA_CQEDR 0xa14 ++#define FSL_QDMA_SQCCMR 0xa20 ++ ++#define FSL_QDMA_SQICR_ICEN ++ ++#define FSL_QDMA_CQIDR_CQT 0xff000000 ++#define FSL_QDMA_CQIDR_SQPE 0x800000 ++#define FSL_QDMA_CQIDR_SQT 0x8000 ++ ++#define FSL_QDMA_BCQIER_CQTIE 0x8000 ++#define FSL_QDMA_BCQIER_CQPEIE 0x800000 ++#define FSL_QDMA_BSQICR_ICEN 0x80000000 ++#define FSL_QDMA_BSQICR_ICST(x) ((x) << 16) ++#define FSL_QDMA_CQIER_MEIE 0x80000000 ++#define FSL_QDMA_CQIER_TEIE 0x1 ++#define FSL_QDMA_SQCCMR_ENTER_WM 0x200000 ++ ++#define FSL_QDMA_QUEUE_MAX 8 ++ ++#define FSL_QDMA_BCQMR_EN 0x80000000 ++#define FSL_QDMA_BCQMR_EI 0x40000000 ++#define FSL_QDMA_BCQMR_CD_THLD(x) ((x) << 20) ++#define FSL_QDMA_BCQMR_CQ_SIZE(x) ((x) << 16) ++ ++#define FSL_QDMA_BCQSR_QF 0x10000 ++#define FSL_QDMA_BCQSR_XOFF 0x1 ++ ++#define FSL_QDMA_BSQMR_EN 0x80000000 ++#define FSL_QDMA_BSQMR_DI 0x40000000 ++#define FSL_QDMA_BSQMR_CQ_SIZE(x) ((x) << 16) ++ ++#define FSL_QDMA_BSQSR_QE 0x20000 ++ ++#define FSL_QDMA_DMR_DQD 0x40000000 ++#define FSL_QDMA_DSR_DB 0x80000000 ++ ++#define FSL_QDMA_BASE_BUFFER_SIZE 96 ++#define FSL_QDMA_EXPECT_SG_ENTRY_NUM 16 ++#define FSL_QDMA_CIRCULAR_DESC_SIZE_MIN 64 ++#define FSL_QDMA_CIRCULAR_DESC_SIZE_MAX 16384 ++#define FSL_QDMA_QUEUE_NUM_MAX 8 ++ ++#define FSL_QDMA_CMD_RWTTYPE 0x4 ++#define FSL_QDMA_CMD_LWC 0x2 ++ ++#define FSL_QDMA_CMD_RWTTYPE_OFFSET 28 ++#define FSL_QDMA_CMD_NS_OFFSET 27 ++#define FSL_QDMA_CMD_DQOS_OFFSET 24 ++#define FSL_QDMA_CMD_WTHROTL_OFFSET 20 ++#define FSL_QDMA_CMD_DSEN_OFFSET 19 ++#define FSL_QDMA_CMD_LWC_OFFSET 16 ++ ++#define FSL_QDMA_E_SG_TABLE 1 ++#define FSL_QDMA_E_DATA_BUFFER 0 ++#define FSL_QDMA_F_LAST_ENTRY 1 ++ ++u64 pre_addr, pre_queue; ++ ++struct fsl_qdma_ccdf { ++ u8 status; ++ u32 rev1:22; ++ u32 ser:1; ++ u32 rev2:1; ++ u32 rev3:20; ++ u32 offset:9; ++ u32 format:3; ++ union { ++ struct { ++ u32 addr_lo; /* low 32-bits of 40-bit address */ ++ u32 addr_hi:8; /* high 8-bits of 40-bit address */ ++ u32 rev4:16; ++ u32 queue:3; ++ u32 rev5:3; ++ u32 dd:2; /* dynamic debug */ ++ }; ++ struct { ++ u64 addr:40; ++ /* More efficient address accessor */ ++ u64 __notaddress:24; ++ }; ++ }; ++} __packed; ++ ++struct fsl_qdma_csgf { ++ u32 offset:13; ++ u32 rev1:19; ++ u32 length:30; ++ u32 f:1; ++ u32 e:1; ++ union { ++ struct { ++ u32 addr_lo; /* low 32-bits of 40-bit address */ ++ u32 addr_hi:8; /* high 8-bits of 40-bit address */ ++ u32 rev2:24; ++ }; ++ struct { ++ u64 addr:40; ++ /* More efficient address accessor */ ++ u64 __notaddress:24; ++ }; ++ }; ++} __packed; ++ ++struct fsl_qdma_sdf { ++ u32 rev3:32; ++ u32 ssd:12; /* souce stride distance */ ++ u32 sss:12; /* souce stride size */ ++ u32 rev4:8; ++ u32 rev5:32; ++ u32 cmd; ++} __packed; ++ ++struct fsl_qdma_ddf { ++ u32 rev1:32; ++ u32 dsd:12; /* Destination stride distance */ ++ u32 dss:12; /* Destination stride size */ ++ u32 rev2:8; ++ u32 rev3:32; ++ u32 cmd; ++} __packed; ++ ++struct fsl_qdma_chan { ++ struct virt_dma_chan vchan; ++ struct virt_dma_desc vdesc; ++ enum dma_status status; ++ u32 slave_id; ++ struct fsl_qdma_engine *qdma; ++ struct fsl_qdma_queue *queue; ++ struct list_head qcomp; ++}; ++ ++struct fsl_qdma_queue { ++ struct fsl_qdma_ccdf *virt_head; ++ struct fsl_qdma_ccdf *virt_tail; ++ struct list_head comp_used; ++ struct list_head comp_free; ++ struct dma_pool *comp_pool; ++ struct dma_pool *sg_pool; ++ spinlock_t queue_lock; ++ dma_addr_t bus_addr; ++ u32 n_cq; ++ u32 id; ++ struct fsl_qdma_ccdf *cq; ++}; ++ ++struct fsl_qdma_sg { ++ dma_addr_t bus_addr; ++ void *virt_addr; ++}; ++ ++struct fsl_qdma_comp { ++ dma_addr_t bus_addr; ++ void *virt_addr; ++ struct fsl_qdma_chan *qchan; ++ struct fsl_qdma_sg *sg_block; ++ struct virt_dma_desc vdesc; ++ struct list_head list; ++ u32 sg_block_src; ++ u32 sg_block_dst; ++}; ++ ++struct fsl_qdma_engine { ++ struct dma_device dma_dev; ++ void __iomem *ctrl_base; ++ void __iomem *status_base; ++ void __iomem *block_base; ++ u32 n_chans; ++ u32 n_queues; ++ struct mutex fsl_qdma_mutex; ++ int error_irq; ++ int queue_irq; ++ bool big_endian; ++ struct fsl_qdma_queue *queue; ++ struct fsl_qdma_queue *status; ++ struct fsl_qdma_chan chans[]; ++ ++}; ++ ++static u32 qdma_readl(struct fsl_qdma_engine *qdma, void __iomem *addr) ++{ ++ if (qdma->big_endian) ++ return ioread32be(addr); ++ else ++ return ioread32(addr); ++} ++ ++static void qdma_writel(struct fsl_qdma_engine *qdma, u32 val, ++ void __iomem *addr) ++{ ++ if (qdma->big_endian) ++ iowrite32be(val, addr); ++ else ++ iowrite32(val, addr); ++} ++ ++static struct fsl_qdma_chan *to_fsl_qdma_chan(struct dma_chan *chan) ++{ ++ return container_of(chan, struct fsl_qdma_chan, vchan.chan); ++} ++ ++static struct fsl_qdma_comp *to_fsl_qdma_comp(struct virt_dma_desc *vd) ++{ ++ return container_of(vd, struct fsl_qdma_comp, vdesc); ++} ++ ++static int fsl_qdma_alloc_chan_resources(struct dma_chan *chan) ++{ ++ /* ++ * In QDMA mode, We don't need to do anything. ++ */ ++ return 0; ++} ++ ++static void fsl_qdma_free_chan_resources(struct dma_chan *chan) ++{ ++ struct fsl_qdma_chan *fsl_chan = to_fsl_qdma_chan(chan); ++ unsigned long flags; ++ LIST_HEAD(head); ++ ++ spin_lock_irqsave(&fsl_chan->vchan.lock, flags); ++ vchan_get_all_descriptors(&fsl_chan->vchan, &head); ++ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags); ++ ++ vchan_dma_desc_free_list(&fsl_chan->vchan, &head); ++} ++ ++static void fsl_qdma_comp_fill_memcpy(struct fsl_qdma_comp *fsl_comp, ++ dma_addr_t dst, dma_addr_t src, u32 len) ++{ ++ struct fsl_qdma_ccdf *ccdf; ++ struct fsl_qdma_csgf *csgf_desc, *csgf_src, *csgf_dest; ++ struct fsl_qdma_sdf *sdf; ++ struct fsl_qdma_ddf *ddf; ++ ++ ccdf = (struct fsl_qdma_ccdf *)fsl_comp->virt_addr; ++ csgf_desc = (struct fsl_qdma_csgf *)fsl_comp->virt_addr + 1; ++ csgf_src = (struct fsl_qdma_csgf *)fsl_comp->virt_addr + 2; ++ csgf_dest = (struct fsl_qdma_csgf *)fsl_comp->virt_addr + 3; ++ sdf = (struct fsl_qdma_sdf *)fsl_comp->virt_addr + 4; ++ ddf = (struct fsl_qdma_ddf *)fsl_comp->virt_addr + 5; ++ ++ memset(fsl_comp->virt_addr, 0, FSL_QDMA_BASE_BUFFER_SIZE); ++ /* Head Command Descriptor(Frame Descriptor) */ ++ ccdf->addr = fsl_comp->bus_addr + 16; ++ ccdf->format = 1; /* Compound S/G format */ ++ /* Status notification is enqueued to status queue. */ ++ ccdf->ser = 1; ++ /* Compound Command Descriptor(Frame List Table) */ ++ csgf_desc->addr = fsl_comp->bus_addr + 64; ++ /* It must be 32 as Compound S/G Descriptor */ ++ csgf_desc->length = 32; ++ csgf_src->addr = src; ++ csgf_src->length = len; ++ csgf_dest->addr = dst; ++ csgf_dest->length = len; ++ /* This entry is the last entry. */ ++ csgf_dest->f = FSL_QDMA_F_LAST_ENTRY; ++ /* Descriptor Buffer */ ++ sdf->cmd = FSL_QDMA_CMD_RWTTYPE << FSL_QDMA_CMD_RWTTYPE_OFFSET; ++ ddf->cmd = FSL_QDMA_CMD_RWTTYPE << FSL_QDMA_CMD_RWTTYPE_OFFSET; ++ ddf->cmd |= FSL_QDMA_CMD_LWC << FSL_QDMA_CMD_LWC_OFFSET; ++} ++ ++static void fsl_qdma_comp_fill_sg( ++ struct fsl_qdma_comp *fsl_comp, ++ struct scatterlist *dst_sg, unsigned int dst_nents, ++ struct scatterlist *src_sg, unsigned int src_nents) ++{ ++ struct fsl_qdma_ccdf *ccdf; ++ struct fsl_qdma_csgf *csgf_desc, *csgf_src, *csgf_dest, *csgf_sg; ++ struct fsl_qdma_sdf *sdf; ++ struct fsl_qdma_ddf *ddf; ++ struct fsl_qdma_sg *sg_block, *temp; ++ struct scatterlist *sg; ++ u64 total_src_len = 0; ++ u64 total_dst_len = 0; ++ u32 i; ++ ++ ccdf = (struct fsl_qdma_ccdf *)fsl_comp->virt_addr; ++ csgf_desc = (struct fsl_qdma_csgf *)fsl_comp->virt_addr + 1; ++ csgf_src = (struct fsl_qdma_csgf *)fsl_comp->virt_addr + 2; ++ csgf_dest = (struct fsl_qdma_csgf *)fsl_comp->virt_addr + 3; ++ sdf = (struct fsl_qdma_sdf *)fsl_comp->virt_addr + 4; ++ ddf = (struct fsl_qdma_ddf *)fsl_comp->virt_addr + 5; ++ ++ memset(fsl_comp->virt_addr, 0, FSL_QDMA_BASE_BUFFER_SIZE); ++ /* Head Command Descriptor(Frame Descriptor) */ ++ ccdf->addr = fsl_comp->bus_addr + 16; ++ ccdf->format = 1; /* Compound S/G format */ ++ /* Status notification is enqueued to status queue. */ ++ ccdf->ser = 1; ++ ++ /* Compound Command Descriptor(Frame List Table) */ ++ csgf_desc->addr = fsl_comp->bus_addr + 64; ++ /* It must be 32 as Compound S/G Descriptor */ ++ csgf_desc->length = 32; ++ ++ sg_block = fsl_comp->sg_block; ++ csgf_src->addr = sg_block->bus_addr; ++ /* This entry link to the s/g entry. */ ++ csgf_src->e = FSL_QDMA_E_SG_TABLE; ++ ++ temp = sg_block + fsl_comp->sg_block_src; ++ csgf_dest->addr = temp->bus_addr; ++ /* This entry is the last entry. */ ++ csgf_dest->f = FSL_QDMA_F_LAST_ENTRY; ++ /* This entry link to the s/g entry. */ ++ csgf_dest->e = FSL_QDMA_E_SG_TABLE; ++ ++ for_each_sg(src_sg, sg, src_nents, i) { ++ temp = sg_block + i / (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1); ++ csgf_sg = (struct fsl_qdma_csgf *)temp->virt_addr + ++ i % (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1); ++ csgf_sg->addr = sg_dma_address(sg); ++ csgf_sg->length = sg_dma_len(sg); ++ total_src_len += sg_dma_len(sg); ++ ++ if (i == src_nents - 1) ++ csgf_sg->f = FSL_QDMA_F_LAST_ENTRY; ++ if (i % (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1) == ++ FSL_QDMA_EXPECT_SG_ENTRY_NUM - 2) { ++ csgf_sg = (struct fsl_qdma_csgf *)temp->virt_addr + ++ FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1; ++ temp = sg_block + ++ i / (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1) + 1; ++ csgf_sg->addr = temp->bus_addr; ++ csgf_sg->e = FSL_QDMA_E_SG_TABLE; ++ } ++ } ++ ++ sg_block += fsl_comp->sg_block_src; ++ for_each_sg(dst_sg, sg, dst_nents, i) { ++ temp = sg_block + i / (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1); ++ csgf_sg = (struct fsl_qdma_csgf *)temp->virt_addr + ++ i % (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1); ++ csgf_sg->addr = sg_dma_address(sg); ++ csgf_sg->length = sg_dma_len(sg); ++ total_dst_len += sg_dma_len(sg); ++ ++ if (i == dst_nents - 1) ++ csgf_sg->f = FSL_QDMA_F_LAST_ENTRY; ++ if (i % (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1) == ++ FSL_QDMA_EXPECT_SG_ENTRY_NUM - 2) { ++ csgf_sg = (struct fsl_qdma_csgf *)temp->virt_addr + ++ FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1; ++ temp = sg_block + ++ i / (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1) + 1; ++ csgf_sg->addr = temp->bus_addr; ++ csgf_sg->e = FSL_QDMA_E_SG_TABLE; ++ } ++ } ++ ++ if (total_src_len != total_dst_len) ++ dev_err(&fsl_comp->qchan->vchan.chan.dev->device, ++ "The data length for src and dst isn't match.\n"); ++ ++ csgf_src->length = total_src_len; ++ csgf_dest->length = total_dst_len; ++ ++ /* Descriptor Buffer */ ++ sdf->cmd = FSL_QDMA_CMD_RWTTYPE << FSL_QDMA_CMD_RWTTYPE_OFFSET; ++ ddf->cmd = FSL_QDMA_CMD_RWTTYPE << FSL_QDMA_CMD_RWTTYPE_OFFSET; ++} ++ ++/* ++ * Prei-request full command descriptor for enqueue. ++ */ ++static int fsl_qdma_pre_request_enqueue_desc(struct fsl_qdma_queue *queue) ++{ ++ struct fsl_qdma_comp *comp_temp; ++ int i; ++ ++ for (i = 0; i < queue->n_cq; i++) { ++ comp_temp = kzalloc(sizeof(*comp_temp), GFP_KERNEL); ++ if (!comp_temp) ++ return -1; ++ comp_temp->virt_addr = dma_pool_alloc(queue->comp_pool, ++ GFP_NOWAIT, ++ &comp_temp->bus_addr); ++ if (!comp_temp->virt_addr) ++ return -1; ++ list_add_tail(&comp_temp->list, &queue->comp_free); ++ } ++ return 0; ++} ++ ++/* ++ * Request a command descriptor for enqueue. ++ */ ++static struct fsl_qdma_comp *fsl_qdma_request_enqueue_desc( ++ struct fsl_qdma_chan *fsl_chan, ++ unsigned int dst_nents, ++ unsigned int src_nents) ++{ ++ struct fsl_qdma_comp *comp_temp; ++ struct fsl_qdma_sg *sg_block; ++ struct fsl_qdma_queue *queue = fsl_chan->queue; ++ unsigned long flags; ++ unsigned int dst_sg_entry_block, src_sg_entry_block, sg_entry_total, i; ++ ++ spin_lock_irqsave(&queue->queue_lock, flags); ++ if (list_empty(&queue->comp_free)) { ++ spin_unlock_irqrestore(&queue->queue_lock, flags); ++ comp_temp = kzalloc(sizeof(*comp_temp), GFP_KERNEL); ++ if (!comp_temp) ++ return NULL; ++ comp_temp->virt_addr = dma_pool_alloc(queue->comp_pool, ++ GFP_NOWAIT, ++ &comp_temp->bus_addr); ++ if (!comp_temp->virt_addr) ++ return NULL; ++ } else { ++ comp_temp = list_first_entry(&queue->comp_free, ++ struct fsl_qdma_comp, ++ list); ++ list_del(&comp_temp->list); ++ spin_unlock_irqrestore(&queue->queue_lock, flags); ++ } ++ ++ if (dst_nents != 0) ++ dst_sg_entry_block = dst_nents / ++ (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1) + 1; ++ else ++ dst_sg_entry_block = 0; ++ ++ if (src_nents != 0) ++ src_sg_entry_block = src_nents / ++ (FSL_QDMA_EXPECT_SG_ENTRY_NUM - 1) + 1; ++ else ++ src_sg_entry_block = 0; ++ ++ sg_entry_total = dst_sg_entry_block + src_sg_entry_block; ++ if (sg_entry_total) { ++ sg_block = kzalloc(sizeof(*sg_block) * ++ sg_entry_total, ++ GFP_KERNEL); ++ if (!sg_block) ++ return NULL; ++ comp_temp->sg_block = sg_block; ++ for (i = 0; i < sg_entry_total; i++) { ++ sg_block->virt_addr = dma_pool_alloc(queue->sg_pool, ++ GFP_NOWAIT, ++ &sg_block->bus_addr); ++ memset(sg_block->virt_addr, 0, ++ FSL_QDMA_EXPECT_SG_ENTRY_NUM * 16); ++ sg_block++; ++ } ++ } ++ ++ comp_temp->sg_block_src = src_sg_entry_block; ++ comp_temp->sg_block_dst = dst_sg_entry_block; ++ comp_temp->qchan = fsl_chan; ++ ++ return comp_temp; ++} ++ ++static struct fsl_qdma_queue *fsl_qdma_alloc_queue_resources( ++ struct platform_device *pdev, ++ unsigned int queue_num) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct fsl_qdma_queue *queue_head, *queue_temp; ++ int ret, len, i; ++ unsigned int queue_size[FSL_QDMA_QUEUE_MAX]; ++ ++ if (queue_num > FSL_QDMA_QUEUE_MAX) ++ queue_num = FSL_QDMA_QUEUE_MAX; ++ len = sizeof(*queue_head) * queue_num; ++ queue_head = devm_kzalloc(&pdev->dev, len, GFP_KERNEL); ++ if (!queue_head) ++ return NULL; ++ ++ ret = of_property_read_u32_array(np, "queue-sizes", queue_size, ++ queue_num); ++ if (ret) { ++ dev_err(&pdev->dev, "Can't get queue-sizes.\n"); ++ return NULL; ++ } ++ ++ for (i = 0; i < queue_num; i++) { ++ if (queue_size[i] > FSL_QDMA_CIRCULAR_DESC_SIZE_MAX ++ || queue_size[i] < FSL_QDMA_CIRCULAR_DESC_SIZE_MIN) { ++ dev_err(&pdev->dev, "Get wrong queue-sizes.\n"); ++ return NULL; ++ } ++ queue_temp = queue_head + i; ++ queue_temp->cq = dma_alloc_coherent(&pdev->dev, ++ sizeof(struct fsl_qdma_ccdf) * ++ queue_size[i], ++ &queue_temp->bus_addr, ++ GFP_KERNEL); ++ if (!queue_temp->cq) ++ return NULL; ++ queue_temp->n_cq = queue_size[i]; ++ queue_temp->id = i; ++ queue_temp->virt_head = queue_temp->cq; ++ queue_temp->virt_tail = queue_temp->cq; ++ /* ++ * The dma pool for queue command buffer ++ */ ++ queue_temp->comp_pool = dma_pool_create("comp_pool", ++ &pdev->dev, ++ FSL_QDMA_BASE_BUFFER_SIZE, ++ 16, 0); ++ if (!queue_temp->comp_pool) { ++ dma_free_coherent(&pdev->dev, ++ sizeof(struct fsl_qdma_ccdf) * ++ queue_size[i], ++ queue_temp->cq, ++ queue_temp->bus_addr); ++ return NULL; ++ } ++ /* ++ * The dma pool for queue command buffer ++ */ ++ queue_temp->sg_pool = dma_pool_create("sg_pool", ++ &pdev->dev, ++ FSL_QDMA_EXPECT_SG_ENTRY_NUM * 16, ++ 64, 0); ++ if (!queue_temp->sg_pool) { ++ dma_free_coherent(&pdev->dev, ++ sizeof(struct fsl_qdma_ccdf) * ++ queue_size[i], ++ queue_temp->cq, ++ queue_temp->bus_addr); ++ dma_pool_destroy(queue_temp->comp_pool); ++ return NULL; ++ } ++ /* ++ * List for queue command buffer ++ */ ++ INIT_LIST_HEAD(&queue_temp->comp_used); ++ INIT_LIST_HEAD(&queue_temp->comp_free); ++ spin_lock_init(&queue_temp->queue_lock); ++ } ++ ++ return queue_head; ++} ++ ++static struct fsl_qdma_queue *fsl_qdma_prep_status_queue( ++ struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct fsl_qdma_queue *status_head; ++ unsigned int status_size; ++ int ret; ++ ++ ret = of_property_read_u32(np, "status-sizes", &status_size); ++ if (ret) { ++ dev_err(&pdev->dev, "Can't get status-sizes.\n"); ++ return NULL; ++ } ++ if (status_size > FSL_QDMA_CIRCULAR_DESC_SIZE_MAX ++ || status_size < FSL_QDMA_CIRCULAR_DESC_SIZE_MIN) { ++ dev_err(&pdev->dev, "Get wrong status_size.\n"); ++ return NULL; ++ } ++ status_head = devm_kzalloc(&pdev->dev, sizeof(*status_head), ++ GFP_KERNEL); ++ if (!status_head) ++ return NULL; ++ ++ /* ++ * Buffer for queue command ++ */ ++ status_head->cq = dma_alloc_coherent(&pdev->dev, ++ sizeof(struct fsl_qdma_ccdf) * ++ status_size, ++ &status_head->bus_addr, ++ GFP_KERNEL); ++ if (!status_head->cq) ++ return NULL; ++ status_head->n_cq = status_size; ++ status_head->virt_head = status_head->cq; ++ status_head->virt_tail = status_head->cq; ++ status_head->comp_pool = NULL; ++ ++ return status_head; ++} ++ ++static int fsl_qdma_halt(struct fsl_qdma_engine *fsl_qdma) ++{ ++ void __iomem *ctrl = fsl_qdma->ctrl_base; ++ void __iomem *block = fsl_qdma->block_base; ++ int i, count = 5; ++ u32 reg; ++ ++ /* Disable the command queue and wait for idle state. */ ++ reg = qdma_readl(fsl_qdma, ctrl + FSL_QDMA_DMR); ++ reg |= FSL_QDMA_DMR_DQD; ++ qdma_writel(fsl_qdma, reg, ctrl + FSL_QDMA_DMR); ++ for (i = 0; i < FSL_QDMA_QUEUE_NUM_MAX; i++) ++ qdma_writel(fsl_qdma, 0, block + FSL_QDMA_BCQMR(i)); ++ ++ while (1) { ++ reg = qdma_readl(fsl_qdma, ctrl + FSL_QDMA_DSR); ++ if (!(reg & FSL_QDMA_DSR_DB)) ++ break; ++ if (count-- < 0) ++ return -EBUSY; ++ udelay(100); ++ } ++ ++ /* Disable status queue. */ ++ qdma_writel(fsl_qdma, 0, block + FSL_QDMA_BSQMR); ++ ++ /* ++ * Clear the command queue interrupt detect register for all queues. ++ */ ++ qdma_writel(fsl_qdma, 0xffffffff, block + FSL_QDMA_BCQIDR(0)); ++ ++ return 0; ++} ++ ++static int fsl_qdma_queue_transfer_complete(struct fsl_qdma_engine *fsl_qdma) ++{ ++ struct fsl_qdma_queue *fsl_queue = fsl_qdma->queue; ++ struct fsl_qdma_queue *fsl_status = fsl_qdma->status; ++ struct fsl_qdma_queue *temp_queue; ++ struct fsl_qdma_comp *fsl_comp; ++ struct fsl_qdma_ccdf *status_addr; ++ struct fsl_qdma_csgf *csgf_src; ++ void __iomem *block = fsl_qdma->block_base; ++ u32 reg, i; ++ bool duplicate, duplicate_handle; ++ ++ while (1) { ++ duplicate = 0; ++ duplicate_handle = 0; ++ reg = qdma_readl(fsl_qdma, block + FSL_QDMA_BSQSR); ++ if (reg & FSL_QDMA_BSQSR_QE) ++ return 0; ++ status_addr = fsl_status->virt_head; ++ if (status_addr->queue == pre_queue && ++ status_addr->addr == pre_addr) ++ duplicate = 1; ++ ++ i = status_addr->queue; ++ pre_queue = status_addr->queue; ++ pre_addr = status_addr->addr; ++ temp_queue = fsl_queue + i; ++ spin_lock(&temp_queue->queue_lock); ++ if (list_empty(&temp_queue->comp_used)) { ++ if (duplicate) ++ duplicate_handle = 1; ++ else { ++ spin_unlock(&temp_queue->queue_lock); ++ return -1; ++ } ++ } else { ++ fsl_comp = list_first_entry(&temp_queue->comp_used, ++ struct fsl_qdma_comp, ++ list); ++ csgf_src = (struct fsl_qdma_csgf *)fsl_comp->virt_addr ++ + 2; ++ if (fsl_comp->bus_addr + 16 != ++ (dma_addr_t)status_addr->addr) { ++ if (duplicate) ++ duplicate_handle = 1; ++ else { ++ spin_unlock(&temp_queue->queue_lock); ++ return -1; ++ } ++ } ++ } ++ ++ if (duplicate_handle) { ++ reg = qdma_readl(fsl_qdma, block + FSL_QDMA_BSQMR); ++ reg |= FSL_QDMA_BSQMR_DI; ++ status_addr->addr = 0x0; ++ fsl_status->virt_head++; ++ if (fsl_status->virt_head == fsl_status->cq ++ + fsl_status->n_cq) ++ fsl_status->virt_head = fsl_status->cq; ++ qdma_writel(fsl_qdma, reg, block + FSL_QDMA_BSQMR); ++ spin_unlock(&temp_queue->queue_lock); ++ continue; ++ } ++ list_del(&fsl_comp->list); ++ ++ reg = qdma_readl(fsl_qdma, block + FSL_QDMA_BSQMR); ++ reg |= FSL_QDMA_BSQMR_DI; ++ status_addr->addr = 0x0; ++ fsl_status->virt_head++; ++ if (fsl_status->virt_head == fsl_status->cq + fsl_status->n_cq) ++ fsl_status->virt_head = fsl_status->cq; ++ qdma_writel(fsl_qdma, reg, block + FSL_QDMA_BSQMR); ++ spin_unlock(&temp_queue->queue_lock); ++ ++ spin_lock(&fsl_comp->qchan->vchan.lock); ++ vchan_cookie_complete(&fsl_comp->vdesc); ++ fsl_comp->qchan->status = DMA_COMPLETE; ++ spin_unlock(&fsl_comp->qchan->vchan.lock); ++ } ++ return 0; ++} ++ ++static irqreturn_t fsl_qdma_error_handler(int irq, void *dev_id) ++{ ++ struct fsl_qdma_engine *fsl_qdma = dev_id; ++ unsigned int intr; ++ void __iomem *status = fsl_qdma->status_base; ++ ++ intr = qdma_readl(fsl_qdma, status + FSL_QDMA_DEDR); ++ ++ if (intr) ++ dev_err(fsl_qdma->dma_dev.dev, "DMA transaction error!\n"); ++ ++ qdma_writel(fsl_qdma, 0xffffffff, status + FSL_QDMA_DEDR); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t fsl_qdma_queue_handler(int irq, void *dev_id) ++{ ++ struct fsl_qdma_engine *fsl_qdma = dev_id; ++ unsigned int intr, reg; ++ void __iomem *block = fsl_qdma->block_base; ++ void __iomem *ctrl = fsl_qdma->ctrl_base; ++ ++ intr = qdma_readl(fsl_qdma, block + FSL_QDMA_BCQIDR(0)); ++ ++ if ((intr & FSL_QDMA_CQIDR_SQT) != 0) ++ intr = fsl_qdma_queue_transfer_complete(fsl_qdma); ++ ++ if (intr != 0) { ++ reg = qdma_readl(fsl_qdma, ctrl + FSL_QDMA_DMR); ++ reg |= FSL_QDMA_DMR_DQD; ++ qdma_writel(fsl_qdma, reg, ctrl + FSL_QDMA_DMR); ++ qdma_writel(fsl_qdma, 0, block + FSL_QDMA_BCQIER(0)); ++ dev_err(fsl_qdma->dma_dev.dev, "QDMA: status err!\n"); ++ } ++ ++ qdma_writel(fsl_qdma, 0xffffffff, block + FSL_QDMA_BCQIDR(0)); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ++fsl_qdma_irq_init(struct platform_device *pdev, ++ struct fsl_qdma_engine *fsl_qdma) ++{ ++ int ret; ++ ++ fsl_qdma->error_irq = platform_get_irq_byname(pdev, ++ "qdma-error"); ++ if (fsl_qdma->error_irq < 0) { ++ dev_err(&pdev->dev, "Can't get qdma controller irq.\n"); ++ return fsl_qdma->error_irq; ++ } ++ ++ fsl_qdma->queue_irq = platform_get_irq_byname(pdev, "qdma-queue"); ++ if (fsl_qdma->queue_irq < 0) { ++ dev_err(&pdev->dev, "Can't get qdma queue irq.\n"); ++ return fsl_qdma->queue_irq; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, fsl_qdma->error_irq, ++ fsl_qdma_error_handler, 0, "qDMA error", fsl_qdma); ++ if (ret) { ++ dev_err(&pdev->dev, "Can't register qDMA controller IRQ.\n"); ++ return ret; ++ } ++ ret = devm_request_irq(&pdev->dev, fsl_qdma->queue_irq, ++ fsl_qdma_queue_handler, 0, "qDMA queue", fsl_qdma); ++ if (ret) { ++ dev_err(&pdev->dev, "Can't register qDMA queue IRQ.\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int fsl_qdma_reg_init(struct fsl_qdma_engine *fsl_qdma) ++{ ++ struct fsl_qdma_queue *fsl_queue = fsl_qdma->queue; ++ struct fsl_qdma_queue *temp; ++ void __iomem *ctrl = fsl_qdma->ctrl_base; ++ void __iomem *status = fsl_qdma->status_base; ++ void __iomem *block = fsl_qdma->block_base; ++ int i, ret; ++ u32 reg; ++ ++ /* Try to halt the qDMA engine first. */ ++ ret = fsl_qdma_halt(fsl_qdma); ++ if (ret) { ++ dev_err(fsl_qdma->dma_dev.dev, "DMA halt failed!"); ++ return ret; ++ } ++ ++ /* ++ * Clear the command queue interrupt detect register for all queues. ++ */ ++ qdma_writel(fsl_qdma, 0xffffffff, block + FSL_QDMA_BCQIDR(0)); ++ ++ for (i = 0; i < fsl_qdma->n_queues; i++) { ++ temp = fsl_queue + i; ++ /* ++ * Initialize Command Queue registers to point to the first ++ * command descriptor in memory. ++ * Dequeue Pointer Address Registers ++ * Enqueue Pointer Address Registers ++ */ ++ qdma_writel(fsl_qdma, temp->bus_addr, ++ block + FSL_QDMA_BCQDPA_SADDR(i)); ++ qdma_writel(fsl_qdma, temp->bus_addr, ++ block + FSL_QDMA_BCQEPA_SADDR(i)); ++ ++ /* Initialize the queue mode. */ ++ reg = FSL_QDMA_BCQMR_EN; ++ reg |= FSL_QDMA_BCQMR_CD_THLD(ilog2(temp->n_cq)-4); ++ reg |= FSL_QDMA_BCQMR_CQ_SIZE(ilog2(temp->n_cq)-6); ++ qdma_writel(fsl_qdma, reg, block + FSL_QDMA_BCQMR(i)); ++ } ++ ++ /* ++ * Workaround for erratum: ERR010812. ++ * We must enable XOFF to avoid the enqueue rejection occurs. ++ * Setting SQCCMR ENTER_WM to 0x20. ++ */ ++ qdma_writel(fsl_qdma, FSL_QDMA_SQCCMR_ENTER_WM, ++ block + FSL_QDMA_SQCCMR); ++ /* ++ * Initialize status queue registers to point to the first ++ * command descriptor in memory. ++ * Dequeue Pointer Address Registers ++ * Enqueue Pointer Address Registers ++ */ ++ qdma_writel(fsl_qdma, fsl_qdma->status->bus_addr, ++ block + FSL_QDMA_SQEPAR); ++ qdma_writel(fsl_qdma, fsl_qdma->status->bus_addr, ++ block + FSL_QDMA_SQDPAR); ++ /* Initialize status queue interrupt. */ ++ qdma_writel(fsl_qdma, FSL_QDMA_BCQIER_CQTIE, ++ block + FSL_QDMA_BCQIER(0)); ++ qdma_writel(fsl_qdma, FSL_QDMA_BSQICR_ICEN | FSL_QDMA_BSQICR_ICST(5) ++ | 0x8000, ++ block + FSL_QDMA_BSQICR); ++ qdma_writel(fsl_qdma, FSL_QDMA_CQIER_MEIE | FSL_QDMA_CQIER_TEIE, ++ block + FSL_QDMA_CQIER); ++ /* Initialize controller interrupt register. */ ++ qdma_writel(fsl_qdma, 0xffffffff, status + FSL_QDMA_DEDR); ++ qdma_writel(fsl_qdma, 0xffffffff, status + FSL_QDMA_DEIER); ++ ++ /* Initialize the status queue mode. */ ++ reg = FSL_QDMA_BSQMR_EN; ++ reg |= FSL_QDMA_BSQMR_CQ_SIZE(ilog2(fsl_qdma->status->n_cq)-6); ++ qdma_writel(fsl_qdma, reg, block + FSL_QDMA_BSQMR); ++ ++ reg = qdma_readl(fsl_qdma, ctrl + FSL_QDMA_DMR); ++ reg &= ~FSL_QDMA_DMR_DQD; ++ qdma_writel(fsl_qdma, reg, ctrl + FSL_QDMA_DMR); ++ ++ return 0; ++} ++ ++static struct dma_async_tx_descriptor *fsl_qdma_prep_dma_sg( ++ struct dma_chan *chan, ++ struct scatterlist *dst_sg, unsigned int dst_nents, ++ struct scatterlist *src_sg, unsigned int src_nents, ++ unsigned long flags) ++{ ++ struct fsl_qdma_chan *fsl_chan = to_fsl_qdma_chan(chan); ++ struct fsl_qdma_comp *fsl_comp; ++ ++ fsl_comp = fsl_qdma_request_enqueue_desc(fsl_chan, ++ dst_nents, ++ src_nents); ++ fsl_qdma_comp_fill_sg(fsl_comp, dst_sg, dst_nents, src_sg, src_nents); ++ ++ return vchan_tx_prep(&fsl_chan->vchan, &fsl_comp->vdesc, flags); ++} ++ ++static struct dma_async_tx_descriptor * ++fsl_qdma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, ++ dma_addr_t src, size_t len, unsigned long flags) ++{ ++ struct fsl_qdma_chan *fsl_chan = to_fsl_qdma_chan(chan); ++ struct fsl_qdma_comp *fsl_comp; ++ ++ fsl_comp = fsl_qdma_request_enqueue_desc(fsl_chan, 0, 0); ++ fsl_qdma_comp_fill_memcpy(fsl_comp, dst, src, len); ++ ++ return vchan_tx_prep(&fsl_chan->vchan, &fsl_comp->vdesc, flags); ++} ++ ++static void fsl_qdma_enqueue_desc(struct fsl_qdma_chan *fsl_chan) ++{ ++ void __iomem *block = fsl_chan->qdma->block_base; ++ struct fsl_qdma_queue *fsl_queue = fsl_chan->queue; ++ struct fsl_qdma_comp *fsl_comp; ++ struct virt_dma_desc *vdesc; ++ u32 reg; ++ ++ reg = qdma_readl(fsl_chan->qdma, block + FSL_QDMA_BCQSR(fsl_queue->id)); ++ if (reg & (FSL_QDMA_BCQSR_QF | FSL_QDMA_BCQSR_XOFF)) ++ return; ++ vdesc = vchan_next_desc(&fsl_chan->vchan); ++ if (!vdesc) ++ return; ++ list_del(&vdesc->node); ++ fsl_comp = to_fsl_qdma_comp(vdesc); ++ ++ memcpy(fsl_queue->virt_head++, fsl_comp->virt_addr, 16); ++ if (fsl_queue->virt_head == fsl_queue->cq + fsl_queue->n_cq) ++ fsl_queue->virt_head = fsl_queue->cq; ++ ++ list_add_tail(&fsl_comp->list, &fsl_queue->comp_used); ++ barrier(); ++ reg = qdma_readl(fsl_chan->qdma, block + FSL_QDMA_BCQMR(fsl_queue->id)); ++ reg |= FSL_QDMA_BCQMR_EI; ++ qdma_writel(fsl_chan->qdma, reg, block + FSL_QDMA_BCQMR(fsl_queue->id)); ++ fsl_chan->status = DMA_IN_PROGRESS; ++} ++ ++static enum dma_status fsl_qdma_tx_status(struct dma_chan *chan, ++ dma_cookie_t cookie, struct dma_tx_state *txstate) ++{ ++ return dma_cookie_status(chan, cookie, txstate); ++} ++ ++static void fsl_qdma_free_desc(struct virt_dma_desc *vdesc) ++{ ++ struct fsl_qdma_comp *fsl_comp; ++ struct fsl_qdma_queue *fsl_queue; ++ struct fsl_qdma_sg *sg_block; ++ unsigned long flags; ++ unsigned int i; ++ ++ fsl_comp = to_fsl_qdma_comp(vdesc); ++ fsl_queue = fsl_comp->qchan->queue; ++ ++ if (fsl_comp->sg_block) { ++ for (i = 0; i < fsl_comp->sg_block_src + ++ fsl_comp->sg_block_dst; i++) { ++ sg_block = fsl_comp->sg_block + i; ++ dma_pool_free(fsl_queue->sg_pool, ++ sg_block->virt_addr, ++ sg_block->bus_addr); ++ } ++ kfree(fsl_comp->sg_block); ++ } ++ ++ spin_lock_irqsave(&fsl_queue->queue_lock, flags); ++ list_add_tail(&fsl_comp->list, &fsl_queue->comp_free); ++ spin_unlock_irqrestore(&fsl_queue->queue_lock, flags); ++} ++ ++static void fsl_qdma_issue_pending(struct dma_chan *chan) ++{ ++ struct fsl_qdma_chan *fsl_chan = to_fsl_qdma_chan(chan); ++ struct fsl_qdma_queue *fsl_queue = fsl_chan->queue; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&fsl_queue->queue_lock, flags); ++ spin_lock(&fsl_chan->vchan.lock); ++ if (vchan_issue_pending(&fsl_chan->vchan)) ++ fsl_qdma_enqueue_desc(fsl_chan); ++ spin_unlock(&fsl_chan->vchan.lock); ++ spin_unlock_irqrestore(&fsl_queue->queue_lock, flags); ++} ++ ++static int fsl_qdma_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct fsl_qdma_engine *fsl_qdma; ++ struct fsl_qdma_chan *fsl_chan; ++ struct resource *res; ++ unsigned int len, chans, queues; ++ int ret, i; ++ ++ ret = of_property_read_u32(np, "channels", &chans); ++ if (ret) { ++ dev_err(&pdev->dev, "Can't get channels.\n"); ++ return ret; ++ } ++ ++ len = sizeof(*fsl_qdma) + sizeof(*fsl_chan) * chans; ++ fsl_qdma = devm_kzalloc(&pdev->dev, len, GFP_KERNEL); ++ if (!fsl_qdma) ++ return -ENOMEM; ++ ++ ret = of_property_read_u32(np, "queues", &queues); ++ if (ret) { ++ dev_err(&pdev->dev, "Can't get queues.\n"); ++ return ret; ++ } ++ ++ fsl_qdma->queue = fsl_qdma_alloc_queue_resources(pdev, queues); ++ if (!fsl_qdma->queue) ++ return -ENOMEM; ++ ++ fsl_qdma->status = fsl_qdma_prep_status_queue(pdev); ++ if (!fsl_qdma->status) ++ return -ENOMEM; ++ ++ fsl_qdma->n_chans = chans; ++ fsl_qdma->n_queues = queues; ++ mutex_init(&fsl_qdma->fsl_qdma_mutex); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ fsl_qdma->ctrl_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(fsl_qdma->ctrl_base)) ++ return PTR_ERR(fsl_qdma->ctrl_base); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ++ fsl_qdma->status_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(fsl_qdma->status_base)) ++ return PTR_ERR(fsl_qdma->status_base); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 2); ++ fsl_qdma->block_base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(fsl_qdma->block_base)) ++ return PTR_ERR(fsl_qdma->block_base); ++ ++ ret = fsl_qdma_irq_init(pdev, fsl_qdma); ++ if (ret) ++ return ret; ++ ++ fsl_qdma->big_endian = of_property_read_bool(np, "big-endian"); ++ INIT_LIST_HEAD(&fsl_qdma->dma_dev.channels); ++ for (i = 0; i < fsl_qdma->n_chans; i++) { ++ struct fsl_qdma_chan *fsl_chan = &fsl_qdma->chans[i]; ++ ++ fsl_chan->qdma = fsl_qdma; ++ fsl_chan->queue = fsl_qdma->queue + i % fsl_qdma->n_queues; ++ fsl_chan->vchan.desc_free = fsl_qdma_free_desc; ++ INIT_LIST_HEAD(&fsl_chan->qcomp); ++ vchan_init(&fsl_chan->vchan, &fsl_qdma->dma_dev); ++ } ++ for (i = 0; i < fsl_qdma->n_queues; i++) ++ fsl_qdma_pre_request_enqueue_desc(fsl_qdma->queue + i); ++ ++ dma_cap_set(DMA_MEMCPY, fsl_qdma->dma_dev.cap_mask); ++ dma_cap_set(DMA_SG, fsl_qdma->dma_dev.cap_mask); ++ ++ fsl_qdma->dma_dev.dev = &pdev->dev; ++ fsl_qdma->dma_dev.device_alloc_chan_resources ++ = fsl_qdma_alloc_chan_resources; ++ fsl_qdma->dma_dev.device_free_chan_resources ++ = fsl_qdma_free_chan_resources; ++ fsl_qdma->dma_dev.device_tx_status = fsl_qdma_tx_status; ++ fsl_qdma->dma_dev.device_prep_dma_memcpy = fsl_qdma_prep_memcpy; ++ fsl_qdma->dma_dev.device_prep_dma_sg = fsl_qdma_prep_dma_sg; ++ fsl_qdma->dma_dev.device_issue_pending = fsl_qdma_issue_pending; ++ ++ dma_set_mask(&pdev->dev, DMA_BIT_MASK(40)); ++ ++ platform_set_drvdata(pdev, fsl_qdma); ++ ++ ret = dma_async_device_register(&fsl_qdma->dma_dev); ++ if (ret) { ++ dev_err(&pdev->dev, "Can't register Freescale qDMA engine.\n"); ++ return ret; ++ } ++ ++ ret = fsl_qdma_reg_init(fsl_qdma); ++ if (ret) { ++ dev_err(&pdev->dev, "Can't Initialize the qDMA engine.\n"); ++ return ret; ++ } ++ ++ ++ return 0; ++} ++ ++static int fsl_qdma_remove(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct fsl_qdma_engine *fsl_qdma = platform_get_drvdata(pdev); ++ struct fsl_qdma_queue *queue_temp; ++ struct fsl_qdma_queue *status = fsl_qdma->status; ++ struct fsl_qdma_comp *comp_temp, *_comp_temp; ++ int i; ++ ++ of_dma_controller_free(np); ++ dma_async_device_unregister(&fsl_qdma->dma_dev); ++ ++ /* Free descriptor areas */ ++ for (i = 0; i < fsl_qdma->n_queues; i++) { ++ queue_temp = fsl_qdma->queue + i; ++ list_for_each_entry_safe(comp_temp, _comp_temp, ++ &queue_temp->comp_used, list) { ++ dma_pool_free(queue_temp->comp_pool, ++ comp_temp->virt_addr, ++ comp_temp->bus_addr); ++ list_del(&comp_temp->list); ++ kfree(comp_temp); ++ } ++ list_for_each_entry_safe(comp_temp, _comp_temp, ++ &queue_temp->comp_free, list) { ++ dma_pool_free(queue_temp->comp_pool, ++ comp_temp->virt_addr, ++ comp_temp->bus_addr); ++ list_del(&comp_temp->list); ++ kfree(comp_temp); ++ } ++ dma_free_coherent(&pdev->dev, sizeof(struct fsl_qdma_ccdf) * ++ queue_temp->n_cq, queue_temp->cq, ++ queue_temp->bus_addr); ++ dma_pool_destroy(queue_temp->comp_pool); ++ } ++ ++ dma_free_coherent(&pdev->dev, sizeof(struct fsl_qdma_ccdf) * ++ status->n_cq, status->cq, status->bus_addr); ++ return 0; ++} ++ ++static const struct of_device_id fsl_qdma_dt_ids[] = { ++ { .compatible = "fsl,ls1021a-qdma", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, fsl_qdma_dt_ids); ++ ++static struct platform_driver fsl_qdma_driver = { ++ .driver = { ++ .name = "fsl-qdma", ++ .owner = THIS_MODULE, ++ .of_match_table = fsl_qdma_dt_ids, ++ }, ++ .probe = fsl_qdma_probe, ++ .remove = fsl_qdma_remove, ++}; ++ ++static int __init fsl_qdma_init(void) ++{ ++ return platform_driver_register(&fsl_qdma_driver); ++} ++subsys_initcall(fsl_qdma_init); ++ ++static void __exit fsl_qdma_exit(void) ++{ ++ platform_driver_unregister(&fsl_qdma_driver); ++} ++module_exit(fsl_qdma_exit); ++ ++MODULE_ALIAS("platform:fsl-qdma"); ++MODULE_DESCRIPTION("Freescale qDMA engine driver"); ++MODULE_LICENSE("GPL v2"); +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/806-flextimer-support-layerscape.patch b/target/linux/layerscape/patches-4.9/806-flextimer-support-layerscape.patch new file mode 100644 index 0000000000..190e8d5307 --- /dev/null +++ b/target/linux/layerscape/patches-4.9/806-flextimer-support-layerscape.patch @@ -0,0 +1,331 @@ +From a5b3155b532289af793c26251cb087b4a24d5c15 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 12:13:12 +0800 +Subject: [PATCH] flextimer: support layerscape + +This is a integrated patch for layerscape flextimer support. + +Signed-off-by: Wang Dongsheng +Signed-off-by: Meng Yi +Signed-off-by: Yangbo Lu +--- + drivers/clocksource/fsl_ftm_timer.c | 8 +- + drivers/soc/fsl/layerscape/ftm_alarm.c | 286 +++++++++++++++++++++++++++++++++ + 2 files changed, 290 insertions(+), 4 deletions(-) + create mode 100644 drivers/soc/fsl/layerscape/ftm_alarm.c + +diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/fsl_ftm_timer.c +index 738515b8..770bbbca 100644 +--- a/drivers/clocksource/fsl_ftm_timer.c ++++ b/drivers/clocksource/fsl_ftm_timer.c +@@ -83,11 +83,11 @@ static inline void ftm_counter_disable(void __iomem *base) + + static inline void ftm_irq_acknowledge(void __iomem *base) + { +- u32 val; ++ unsigned int timeout = 100; + +- val = ftm_readl(base + FTM_SC); +- val &= ~FTM_SC_TOF; +- ftm_writel(val, base + FTM_SC); ++ while ((FTM_SC_TOF & ftm_readl(base + FTM_SC)) && timeout--) ++ ftm_writel(ftm_readl(base + FTM_SC) & (~FTM_SC_TOF), ++ base + FTM_SC); + } + + static inline void ftm_irq_enable(void __iomem *base) +diff --git a/drivers/soc/fsl/layerscape/ftm_alarm.c b/drivers/soc/fsl/layerscape/ftm_alarm.c +new file mode 100644 +index 00000000..6f9882ff +--- /dev/null ++++ b/drivers/soc/fsl/layerscape/ftm_alarm.c +@@ -0,0 +1,286 @@ ++/* ++ * Freescale FlexTimer Module (FTM) Alarm driver. ++ * ++ * Copyright 2014 Freescale Semiconductor, 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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define FTM_SC 0x00 ++#define FTM_SC_CLK_SHIFT 3 ++#define FTM_SC_CLK_MASK (0x3 << FTM_SC_CLK_SHIFT) ++#define FTM_SC_CLK(c) ((c) << FTM_SC_CLK_SHIFT) ++#define FTM_SC_PS_MASK 0x7 ++#define FTM_SC_TOIE BIT(6) ++#define FTM_SC_TOF BIT(7) ++ ++#define FTM_SC_CLKS_FIXED_FREQ 0x02 ++ ++#define FTM_CNT 0x04 ++#define FTM_MOD 0x08 ++#define FTM_CNTIN 0x4C ++ ++#define FIXED_FREQ_CLK 32000 ++#define MAX_FREQ_DIV (1 << FTM_SC_PS_MASK) ++#define MAX_COUNT_VAL 0xffff ++ ++static void __iomem *ftm1_base; ++static void __iomem *rcpm_ftm_addr; ++static u32 alarm_freq; ++static bool big_endian; ++ ++static inline u32 ftm_readl(void __iomem *addr) ++{ ++ if (big_endian) ++ return ioread32be(addr); ++ ++ return ioread32(addr); ++} ++ ++static inline void ftm_writel(u32 val, void __iomem *addr) ++{ ++ if (big_endian) ++ iowrite32be(val, addr); ++ else ++ iowrite32(val, addr); ++} ++ ++static inline void ftm_counter_enable(void __iomem *base) ++{ ++ u32 val; ++ ++ /* select and enable counter clock source */ ++ val = ftm_readl(base + FTM_SC); ++ val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK); ++ val |= (FTM_SC_PS_MASK | FTM_SC_CLK(FTM_SC_CLKS_FIXED_FREQ)); ++ ftm_writel(val, base + FTM_SC); ++} ++ ++static inline void ftm_counter_disable(void __iomem *base) ++{ ++ u32 val; ++ ++ /* disable counter clock source */ ++ val = ftm_readl(base + FTM_SC); ++ val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK); ++ ftm_writel(val, base + FTM_SC); ++} ++ ++static inline void ftm_irq_acknowledge(void __iomem *base) ++{ ++ unsigned int timeout = 100; ++ ++ while ((FTM_SC_TOF & ftm_readl(base + FTM_SC)) && timeout--) ++ ftm_writel(ftm_readl(base + FTM_SC) & (~FTM_SC_TOF), ++ base + FTM_SC); ++} ++ ++static inline void ftm_irq_enable(void __iomem *base) ++{ ++ u32 val; ++ ++ val = ftm_readl(base + FTM_SC); ++ val |= FTM_SC_TOIE; ++ ftm_writel(val, base + FTM_SC); ++} ++ ++static inline void ftm_irq_disable(void __iomem *base) ++{ ++ u32 val; ++ ++ val = ftm_readl(base + FTM_SC); ++ val &= ~FTM_SC_TOIE; ++ ftm_writel(val, base + FTM_SC); ++} ++ ++static inline void ftm_reset_counter(void __iomem *base) ++{ ++ /* ++ * The CNT register contains the FTM counter value. ++ * Reset clears the CNT register. Writing any value to COUNT ++ * updates the counter with its initial value, CNTIN. ++ */ ++ ftm_writel(0x00, base + FTM_CNT); ++} ++ ++static u32 time_to_cycle(unsigned long time) ++{ ++ u32 cycle; ++ ++ cycle = time * alarm_freq; ++ if (cycle > MAX_COUNT_VAL) { ++ pr_err("Out of alarm range.\n"); ++ cycle = 0; ++ } ++ ++ return cycle; ++} ++ ++static u32 cycle_to_time(u32 cycle) ++{ ++ return cycle / alarm_freq + 1; ++} ++ ++static void ftm_clean_alarm(void) ++{ ++ ftm_counter_disable(ftm1_base); ++ ++ ftm_writel(0x00, ftm1_base + FTM_CNTIN); ++ ftm_writel(~0U, ftm1_base + FTM_MOD); ++ ++ ftm_reset_counter(ftm1_base); ++} ++ ++static int ftm_set_alarm(u64 cycle) ++{ ++ ftm_irq_disable(ftm1_base); ++ ++ /* ++ * The counter increments until the value of MOD is reached, ++ * at which point the counter is reloaded with the value of CNTIN. ++ * The TOF (the overflow flag) bit is set when the FTM counter ++ * changes from MOD to CNTIN. So we should using the cycle - 1. ++ */ ++ ftm_writel(cycle - 1, ftm1_base + FTM_MOD); ++ ++ ftm_counter_enable(ftm1_base); ++ ++ ftm_irq_enable(ftm1_base); ++ ++ return 0; ++} ++ ++static irqreturn_t ftm_alarm_interrupt(int irq, void *dev_id) ++{ ++ ftm_irq_acknowledge(ftm1_base); ++ ftm_irq_disable(ftm1_base); ++ ftm_clean_alarm(); ++ ++ return IRQ_HANDLED; ++} ++ ++static ssize_t ftm_alarm_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ u32 count, val; ++ ++ count = ftm_readl(ftm1_base + FTM_MOD); ++ val = ftm_readl(ftm1_base + FTM_CNT); ++ val = (count & MAX_COUNT_VAL) - val; ++ val = cycle_to_time(val); ++ ++ return sprintf(buf, "%u\n", val); ++} ++ ++static ssize_t ftm_alarm_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ u32 cycle; ++ unsigned long time; ++ ++ if (kstrtoul(buf, 0, &time)) ++ return -EINVAL; ++ ++ ftm_clean_alarm(); ++ ++ cycle = time_to_cycle(time); ++ if (!cycle) ++ return -EINVAL; ++ ++ ftm_set_alarm(cycle); ++ ++ return count; ++} ++ ++static struct device_attribute ftm_alarm_attributes = __ATTR(ftm_alarm, 0644, ++ ftm_alarm_show, ftm_alarm_store); ++ ++static int ftm_alarm_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct resource *r; ++ int irq; ++ int ret; ++ u32 ippdexpcr; ++ ++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!r) ++ return -ENODEV; ++ ++ ftm1_base = devm_ioremap_resource(&pdev->dev, r); ++ if (IS_ERR(ftm1_base)) ++ return PTR_ERR(ftm1_base); ++ ++ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "FlexTimer1"); ++ if (r) { ++ rcpm_ftm_addr = devm_ioremap_resource(&pdev->dev, r); ++ if (IS_ERR(rcpm_ftm_addr)) ++ return PTR_ERR(rcpm_ftm_addr); ++ ippdexpcr = ioread32be(rcpm_ftm_addr); ++ ippdexpcr |= 0x20000; ++ iowrite32be(ippdexpcr, rcpm_ftm_addr); ++ } ++ ++ irq = irq_of_parse_and_map(np, 0); ++ if (irq <= 0) { ++ pr_err("ftm: unable to get IRQ from DT, %d\n", irq); ++ return -EINVAL; ++ } ++ ++ big_endian = of_property_read_bool(np, "big-endian"); ++ ++ ret = devm_request_irq(&pdev->dev, irq, ftm_alarm_interrupt, ++ IRQF_NO_SUSPEND, dev_name(&pdev->dev), NULL); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "failed to request irq\n"); ++ return ret; ++ } ++ ++ ret = device_create_file(&pdev->dev, &ftm_alarm_attributes); ++ if (ret) { ++ dev_err(&pdev->dev, "create sysfs fail.\n"); ++ return ret; ++ } ++ ++ alarm_freq = (u32)FIXED_FREQ_CLK / (u32)MAX_FREQ_DIV; ++ ++ ftm_clean_alarm(); ++ ++ device_init_wakeup(&pdev->dev, true); ++ ++ return ret; ++} ++ ++static const struct of_device_id ftm_alarm_match[] = { ++ { .compatible = "fsl,ftm-alarm", }, ++ { .compatible = "fsl,ftm-timer", }, ++ { }, ++}; ++ ++static struct platform_driver ftm_alarm_driver = { ++ .probe = ftm_alarm_probe, ++ .driver = { ++ .name = "ftm-alarm", ++ .owner = THIS_MODULE, ++ .of_match_table = ftm_alarm_match, ++ }, ++}; ++ ++static int __init ftm_alarm_init(void) ++{ ++ return platform_driver_register(&ftm_alarm_driver); ++} ++device_initcall(ftm_alarm_init); +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/807-gpu-support-layerscape.patch b/target/linux/layerscape/patches-4.9/807-gpu-support-layerscape.patch new file mode 100644 index 0000000000..8321d392aa --- /dev/null +++ b/target/linux/layerscape/patches-4.9/807-gpu-support-layerscape.patch @@ -0,0 +1,73 @@ +From 4278a546526094dd57bfa3cf7ae2bf34092246db Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 12:10:01 +0800 +Subject: [PATCH] gpu: support layerscape + +This is a integrated patch for layerscape dcu support. + +Signed-off-by: Alison Wang +Signed-off-by: Yangbo Lu +--- + drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c +index cc2fde2a..54f60ba1 100644 +--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c ++++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c +@@ -225,7 +225,6 @@ static int fsl_dcu_drm_pm_suspend(struct device *dev) + if (!fsl_dev) + return 0; + +- disable_irq(fsl_dev->irq); + drm_kms_helper_poll_disable(fsl_dev->drm); + + console_lock(); +@@ -243,6 +242,8 @@ static int fsl_dcu_drm_pm_suspend(struct device *dev) + return PTR_ERR(fsl_dev->state); + } + ++ disable_irq(fsl_dev->irq); ++ + clk_disable_unprepare(fsl_dev->pix_clk); + clk_disable_unprepare(fsl_dev->clk); + +@@ -263,6 +264,14 @@ static int fsl_dcu_drm_pm_resume(struct device *dev) + return ret; + } + ++ ret = clk_prepare_enable(fsl_dev->pix_clk); ++ if (ret < 0) { ++ dev_err(dev, "failed to enable dcu pix clk\n"); ++ return ret; ++ } ++ ++ enable_irq(fsl_dev->irq); ++ + if (fsl_dev->tcon) + fsl_tcon_bypass_enable(fsl_dev->tcon); + fsl_dcu_drm_init_planes(fsl_dev->drm); +@@ -273,7 +282,6 @@ static int fsl_dcu_drm_pm_resume(struct device *dev) + console_unlock(); + + drm_kms_helper_poll_enable(fsl_dev->drm); +- enable_irq(fsl_dev->irq); + + return 0; + } +@@ -389,6 +397,12 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev) + goto disable_clk; + } + ++ ret = clk_prepare_enable(fsl_dev->pix_clk); ++ if (ret < 0) { ++ dev_err(dev, "failed to enable dcu pix clk\n"); ++ return ret; ++ } ++ + fsl_dev->tcon = fsl_tcon_init(dev); + + drm = drm_dev_alloc(driver, dev); +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/808-guts-support-layerscape.patch b/target/linux/layerscape/patches-4.9/808-guts-support-layerscape.patch new file mode 100644 index 0000000000..51476dac5f --- /dev/null +++ b/target/linux/layerscape/patches-4.9/808-guts-support-layerscape.patch @@ -0,0 +1,462 @@ +From d51e307e4ecf51832c9e3bc30acb5dbd559d5f4d Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 12:19:34 +0800 +Subject: [PATCH] guts: support layerscape + +This is a integrated patch for layerscape guts support. + +Signed-off-by: Roy Pledge +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Amrita Kumari +Signed-off-by: Yangbo Lu +--- + drivers/base/soc.c | 12 ++- + drivers/soc/fsl/guts.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++ + include/linux/fsl/guts.h | 125 +++++++++++++++---------- + 3 files changed, 323 insertions(+), 52 deletions(-) + create mode 100644 drivers/soc/fsl/guts.c + +diff --git a/drivers/base/soc.c b/drivers/base/soc.c +index 0c5cf872..0e701e22 100644 +--- a/drivers/base/soc.c ++++ b/drivers/base/soc.c +@@ -167,19 +167,23 @@ static int soc_device_match_one(struct device *dev, void *arg) + const struct soc_device_attribute *match = arg; + + if (match->machine && +- !glob_match(match->machine, soc_dev->attr->machine)) ++ (!soc_dev->attr->machine || ++ !glob_match(match->machine, soc_dev->attr->machine))) + return 0; + + if (match->family && +- !glob_match(match->family, soc_dev->attr->family)) ++ (!soc_dev->attr->family || ++ !glob_match(match->family, soc_dev->attr->family))) + return 0; + + if (match->revision && +- !glob_match(match->revision, soc_dev->attr->revision)) ++ (!soc_dev->attr->revision || ++ !glob_match(match->revision, soc_dev->attr->revision))) + return 0; + + if (match->soc_id && +- !glob_match(match->soc_id, soc_dev->attr->soc_id)) ++ (!soc_dev->attr->soc_id || ++ !glob_match(match->soc_id, soc_dev->attr->soc_id))) + return 0; + + return 1; +diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c +new file mode 100644 +index 00000000..7d28784a +--- /dev/null ++++ b/drivers/soc/fsl/guts.c +@@ -0,0 +1,238 @@ ++/* ++ * Freescale QorIQ Platforms GUTS Driver ++ * ++ * Copyright (C) 2016 Freescale Semiconductor, 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct guts { ++ struct ccsr_guts __iomem *regs; ++ bool little_endian; ++}; ++ ++struct fsl_soc_die_attr { ++ char *die; ++ u32 svr; ++ u32 mask; ++}; ++ ++static struct guts *guts; ++static struct soc_device_attribute soc_dev_attr; ++static struct soc_device *soc_dev; ++ ++ ++/* SoC die attribute definition for QorIQ platform */ ++static const struct fsl_soc_die_attr fsl_soc_die[] = { ++ /* ++ * Power Architecture-based SoCs T Series ++ */ ++ ++ /* Die: T4240, SoC: T4240/T4160/T4080 */ ++ { .die = "T4240", ++ .svr = 0x82400000, ++ .mask = 0xfff00000, ++ }, ++ /* Die: T1040, SoC: T1040/T1020/T1042/T1022 */ ++ { .die = "T1040", ++ .svr = 0x85200000, ++ .mask = 0xfff00000, ++ }, ++ /* Die: T2080, SoC: T2080/T2081 */ ++ { .die = "T2080", ++ .svr = 0x85300000, ++ .mask = 0xfff00000, ++ }, ++ /* Die: T1024, SoC: T1024/T1014/T1023/T1013 */ ++ { .die = "T1024", ++ .svr = 0x85400000, ++ .mask = 0xfff00000, ++ }, ++ ++ /* ++ * ARM-based SoCs LS Series ++ */ ++ ++ /* Die: LS1043A, SoC: LS1043A/LS1023A */ ++ { .die = "LS1043A", ++ .svr = 0x87920000, ++ .mask = 0xffff0000, ++ }, ++ /* Die: LS2080A, SoC: LS2080A/LS2040A/LS2085A */ ++ { .die = "LS2080A", ++ .svr = 0x87010000, ++ .mask = 0xff3f0000, ++ }, ++ /* Die: LS1088A, SoC: LS1088A/LS1048A/LS1084A/LS1044A */ ++ { .die = "LS1088A", ++ .svr = 0x87030000, ++ .mask = 0xff3f0000, ++ }, ++ /* Die: LS1012A, SoC: LS1012A */ ++ { .die = "LS1012A", ++ .svr = 0x87040000, ++ .mask = 0xffff0000, ++ }, ++ /* Die: LS1046A, SoC: LS1046A/LS1026A */ ++ { .die = "LS1046A", ++ .svr = 0x87070000, ++ .mask = 0xffff0000, ++ }, ++ /* Die: LS2088A, SoC: LS2088A/LS2048A/LS2084A/LS2044A */ ++ { .die = "LS2088A", ++ .svr = 0x87090000, ++ .mask = 0xff3f0000, ++ }, ++ /* Die: LS1021A, SoC: LS1021A/LS1020A/LS1022A */ ++ { .die = "LS1021A", ++ .svr = 0x87000000, ++ .mask = 0xfff70000, ++ }, ++ { }, ++}; ++ ++static const struct fsl_soc_die_attr *fsl_soc_die_match( ++ u32 svr, const struct fsl_soc_die_attr *matches) ++{ ++ while (matches->svr) { ++ if (matches->svr == (svr & matches->mask)) ++ return matches; ++ matches++; ++ }; ++ return NULL; ++} ++ ++u32 fsl_guts_get_svr(void) ++{ ++ u32 svr = 0; ++ ++ if (!guts || !guts->regs) ++ return svr; ++ ++ if (guts->little_endian) ++ svr = ioread32(&guts->regs->svr); ++ else ++ svr = ioread32be(&guts->regs->svr); ++ ++ return svr; ++} ++EXPORT_SYMBOL(fsl_guts_get_svr); ++ ++static int fsl_guts_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct device *dev = &pdev->dev; ++ struct resource *res; ++ const struct fsl_soc_die_attr *soc_die; ++ const char *machine; ++ u32 svr; ++ ++ /* Initialize guts */ ++ guts = devm_kzalloc(dev, sizeof(*guts), GFP_KERNEL); ++ if (!guts) ++ return -ENOMEM; ++ ++ guts->little_endian = of_property_read_bool(np, "little-endian"); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ guts->regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(guts->regs)) ++ return PTR_ERR(guts->regs); ++ ++ /* Register soc device */ ++ machine = of_flat_dt_get_machine_name(); ++ if (machine) ++ soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL); ++ ++ svr = fsl_guts_get_svr(); ++ soc_die = fsl_soc_die_match(svr, fsl_soc_die); ++ if (soc_die) { ++ soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL, ++ "QorIQ %s", soc_die->die); ++ } else { ++ soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL, "QorIQ"); ++ } ++ soc_dev_attr.soc_id = devm_kasprintf(dev, GFP_KERNEL, ++ "svr:0x%08x", svr); ++ soc_dev_attr.revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d", ++ (svr >> 4) & 0xf, svr & 0xf); ++ ++ soc_dev = soc_device_register(&soc_dev_attr); ++ if (IS_ERR(soc_dev)) ++ return PTR_ERR(soc_dev); ++ ++ pr_info("Machine: %s\n", soc_dev_attr.machine); ++ pr_info("SoC family: %s\n", soc_dev_attr.family); ++ pr_info("SoC ID: %s, Revision: %s\n", ++ soc_dev_attr.soc_id, soc_dev_attr.revision); ++ return 0; ++} ++ ++static int fsl_guts_remove(struct platform_device *dev) ++{ ++ soc_device_unregister(soc_dev); ++ return 0; ++} ++ ++/* ++ * Table for matching compatible strings, for device tree ++ * guts node, for Freescale QorIQ SOCs. ++ */ ++static const struct of_device_id fsl_guts_of_match[] = { ++ { .compatible = "fsl,qoriq-device-config-1.0", }, ++ { .compatible = "fsl,qoriq-device-config-2.0", }, ++ { .compatible = "fsl,p1010-guts", }, ++ { .compatible = "fsl,p1020-guts", }, ++ { .compatible = "fsl,p1021-guts", }, ++ { .compatible = "fsl,p1022-guts", }, ++ { .compatible = "fsl,p1023-guts", }, ++ { .compatible = "fsl,p2020-guts", }, ++ { .compatible = "fsl,bsc9131-guts", }, ++ { .compatible = "fsl,bsc9132-guts", }, ++ { .compatible = "fsl,mpc8536-guts", }, ++ { .compatible = "fsl,mpc8544-guts", }, ++ { .compatible = "fsl,mpc8548-guts", }, ++ { .compatible = "fsl,mpc8568-guts", }, ++ { .compatible = "fsl,mpc8569-guts", }, ++ { .compatible = "fsl,mpc8572-guts", }, ++ { .compatible = "fsl,ls1021a-dcfg", }, ++ { .compatible = "fsl,ls1043a-dcfg", }, ++ { .compatible = "fsl,ls1046a-dcfg", }, ++ { .compatible = "fsl,ls2080a-dcfg", }, ++ { .compatible = "fsl,ls1088a-dcfg", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, fsl_guts_of_match); ++ ++static struct platform_driver fsl_guts_driver = { ++ .driver = { ++ .name = "fsl-guts", ++ .of_match_table = fsl_guts_of_match, ++ }, ++ .probe = fsl_guts_probe, ++ .remove = fsl_guts_remove, ++}; ++ ++static int __init fsl_guts_init(void) ++{ ++ return platform_driver_register(&fsl_guts_driver); ++} ++core_initcall(fsl_guts_init); ++ ++static void __exit fsl_guts_exit(void) ++{ ++ platform_driver_unregister(&fsl_guts_driver); ++} ++module_exit(fsl_guts_exit); +diff --git a/include/linux/fsl/guts.h b/include/linux/fsl/guts.h +index 649e9171..3efa3b86 100644 +--- a/include/linux/fsl/guts.h ++++ b/include/linux/fsl/guts.h +@@ -29,83 +29,112 @@ + * #ifdefs. + */ + struct ccsr_guts { +- __be32 porpllsr; /* 0x.0000 - POR PLL Ratio Status Register */ +- __be32 porbmsr; /* 0x.0004 - POR Boot Mode Status Register */ +- __be32 porimpscr; /* 0x.0008 - POR I/O Impedance Status and Control Register */ +- __be32 pordevsr; /* 0x.000c - POR I/O Device Status Register */ +- __be32 pordbgmsr; /* 0x.0010 - POR Debug Mode Status Register */ +- __be32 pordevsr2; /* 0x.0014 - POR device status register 2 */ ++ u32 porpllsr; /* 0x.0000 - POR PLL Ratio Status Register */ ++ u32 porbmsr; /* 0x.0004 - POR Boot Mode Status Register */ ++ u32 porimpscr; /* 0x.0008 - POR I/O Impedance Status and ++ * Control Register ++ */ ++ u32 pordevsr; /* 0x.000c - POR I/O Device Status Register */ ++ u32 pordbgmsr; /* 0x.0010 - POR Debug Mode Status Register */ ++ u32 pordevsr2; /* 0x.0014 - POR device status register 2 */ + u8 res018[0x20 - 0x18]; +- __be32 porcir; /* 0x.0020 - POR Configuration Information Register */ ++ u32 porcir; /* 0x.0020 - POR Configuration Information ++ * Register ++ */ + u8 res024[0x30 - 0x24]; +- __be32 gpiocr; /* 0x.0030 - GPIO Control Register */ ++ u32 gpiocr; /* 0x.0030 - GPIO Control Register */ + u8 res034[0x40 - 0x34]; +- __be32 gpoutdr; /* 0x.0040 - General-Purpose Output Data Register */ ++ u32 gpoutdr; /* 0x.0040 - General-Purpose Output Data ++ * Register ++ */ + u8 res044[0x50 - 0x44]; +- __be32 gpindr; /* 0x.0050 - General-Purpose Input Data Register */ ++ u32 gpindr; /* 0x.0050 - General-Purpose Input Data ++ * Register ++ */ + u8 res054[0x60 - 0x54]; +- __be32 pmuxcr; /* 0x.0060 - Alternate Function Signal Multiplex Control */ +- __be32 pmuxcr2; /* 0x.0064 - Alternate function signal multiplex control 2 */ +- __be32 dmuxcr; /* 0x.0068 - DMA Mux Control Register */ ++ u32 pmuxcr; /* 0x.0060 - Alternate Function Signal ++ * Multiplex Control ++ */ ++ u32 pmuxcr2; /* 0x.0064 - Alternate function signal ++ * multiplex control 2 ++ */ ++ u32 dmuxcr; /* 0x.0068 - DMA Mux Control Register */ + u8 res06c[0x70 - 0x6c]; +- __be32 devdisr; /* 0x.0070 - Device Disable Control */ ++ u32 devdisr; /* 0x.0070 - Device Disable Control */ + #define CCSR_GUTS_DEVDISR_TB1 0x00001000 + #define CCSR_GUTS_DEVDISR_TB0 0x00004000 +- __be32 devdisr2; /* 0x.0074 - Device Disable Control 2 */ ++ u32 devdisr2; /* 0x.0074 - Device Disable Control 2 */ + u8 res078[0x7c - 0x78]; +- __be32 pmjcr; /* 0x.007c - 4 Power Management Jog Control Register */ +- __be32 powmgtcsr; /* 0x.0080 - Power Management Status and Control Register */ +- __be32 pmrccr; /* 0x.0084 - Power Management Reset Counter Configuration Register */ +- __be32 pmpdccr; /* 0x.0088 - Power Management Power Down Counter Configuration Register */ +- __be32 pmcdr; /* 0x.008c - 4Power management clock disable register */ +- __be32 mcpsumr; /* 0x.0090 - Machine Check Summary Register */ +- __be32 rstrscr; /* 0x.0094 - Reset Request Status and Control Register */ +- __be32 ectrstcr; /* 0x.0098 - Exception reset control register */ +- __be32 autorstsr; /* 0x.009c - Automatic reset status register */ +- __be32 pvr; /* 0x.00a0 - Processor Version Register */ +- __be32 svr; /* 0x.00a4 - System Version Register */ ++ u32 pmjcr; /* 0x.007c - 4 Power Management Jog Control ++ * Register ++ */ ++ u32 powmgtcsr; /* 0x.0080 - Power Management Status and ++ * Control Register ++ */ ++ u32 pmrccr; /* 0x.0084 - Power Management Reset Counter ++ * Configuration Register ++ */ ++ u32 pmpdccr; /* 0x.0088 - Power Management Power Down Counter ++ * Configuration Register ++ */ ++ u32 pmcdr; /* 0x.008c - 4Power management clock disable ++ * register ++ */ ++ u32 mcpsumr; /* 0x.0090 - Machine Check Summary Register */ ++ u32 rstrscr; /* 0x.0094 - Reset Request Status and ++ * Control Register ++ */ ++ u32 ectrstcr; /* 0x.0098 - Exception reset control register */ ++ u32 autorstsr; /* 0x.009c - Automatic reset status register */ ++ u32 pvr; /* 0x.00a0 - Processor Version Register */ ++ u32 svr; /* 0x.00a4 - System Version Register */ + u8 res0a8[0xb0 - 0xa8]; +- __be32 rstcr; /* 0x.00b0 - Reset Control Register */ ++ u32 rstcr; /* 0x.00b0 - Reset Control Register */ + u8 res0b4[0xc0 - 0xb4]; +- __be32 iovselsr; /* 0x.00c0 - I/O voltage select status register ++ u32 iovselsr; /* 0x.00c0 - I/O voltage select status register + Called 'elbcvselcr' on 86xx SOCs */ + u8 res0c4[0x100 - 0xc4]; +- __be32 rcwsr[16]; /* 0x.0100 - Reset Control Word Status registers ++ u32 rcwsr[16]; /* 0x.0100 - Reset Control Word Status registers + There are 16 registers */ + u8 res140[0x224 - 0x140]; +- __be32 iodelay1; /* 0x.0224 - IO delay control register 1 */ +- __be32 iodelay2; /* 0x.0228 - IO delay control register 2 */ ++ u32 iodelay1; /* 0x.0224 - IO delay control register 1 */ ++ u32 iodelay2; /* 0x.0228 - IO delay control register 2 */ + u8 res22c[0x604 - 0x22c]; +- __be32 pamubypenr; /* 0x.604 - PAMU bypass enable register */ ++ u32 pamubypenr; /* 0x.604 - PAMU bypass enable register */ + u8 res608[0x800 - 0x608]; +- __be32 clkdvdr; /* 0x.0800 - Clock Divide Register */ ++ u32 clkdvdr; /* 0x.0800 - Clock Divide Register */ + u8 res804[0x900 - 0x804]; +- __be32 ircr; /* 0x.0900 - Infrared Control Register */ ++ u32 ircr; /* 0x.0900 - Infrared Control Register */ + u8 res904[0x908 - 0x904]; +- __be32 dmacr; /* 0x.0908 - DMA Control Register */ ++ u32 dmacr; /* 0x.0908 - DMA Control Register */ + u8 res90c[0x914 - 0x90c]; +- __be32 elbccr; /* 0x.0914 - eLBC Control Register */ ++ u32 elbccr; /* 0x.0914 - eLBC Control Register */ + u8 res918[0xb20 - 0x918]; +- __be32 ddr1clkdr; /* 0x.0b20 - DDR1 Clock Disable Register */ +- __be32 ddr2clkdr; /* 0x.0b24 - DDR2 Clock Disable Register */ +- __be32 ddrclkdr; /* 0x.0b28 - DDR Clock Disable Register */ ++ u32 ddr1clkdr; /* 0x.0b20 - DDR1 Clock Disable Register */ ++ u32 ddr2clkdr; /* 0x.0b24 - DDR2 Clock Disable Register */ ++ u32 ddrclkdr; /* 0x.0b28 - DDR Clock Disable Register */ + u8 resb2c[0xe00 - 0xb2c]; +- __be32 clkocr; /* 0x.0e00 - Clock Out Select Register */ ++ u32 clkocr; /* 0x.0e00 - Clock Out Select Register */ + u8 rese04[0xe10 - 0xe04]; +- __be32 ddrdllcr; /* 0x.0e10 - DDR DLL Control Register */ ++ u32 ddrdllcr; /* 0x.0e10 - DDR DLL Control Register */ + u8 rese14[0xe20 - 0xe14]; +- __be32 lbcdllcr; /* 0x.0e20 - LBC DLL Control Register */ +- __be32 cpfor; /* 0x.0e24 - L2 charge pump fuse override register */ ++ u32 lbcdllcr; /* 0x.0e20 - LBC DLL Control Register */ ++ u32 cpfor; /* 0x.0e24 - L2 charge pump fuse override ++ * register ++ */ + u8 rese28[0xf04 - 0xe28]; +- __be32 srds1cr0; /* 0x.0f04 - SerDes1 Control Register 0 */ +- __be32 srds1cr1; /* 0x.0f08 - SerDes1 Control Register 0 */ ++ u32 srds1cr0; /* 0x.0f04 - SerDes1 Control Register 0 */ ++ u32 srds1cr1; /* 0x.0f08 - SerDes1 Control Register 0 */ + u8 resf0c[0xf2c - 0xf0c]; +- __be32 itcr; /* 0x.0f2c - Internal transaction control register */ ++ u32 itcr; /* 0x.0f2c - Internal transaction control ++ * register ++ */ + u8 resf30[0xf40 - 0xf30]; +- __be32 srds2cr0; /* 0x.0f40 - SerDes2 Control Register 0 */ +- __be32 srds2cr1; /* 0x.0f44 - SerDes2 Control Register 0 */ ++ u32 srds2cr0; /* 0x.0f40 - SerDes2 Control Register 0 */ ++ u32 srds2cr1; /* 0x.0f44 - SerDes2 Control Register 0 */ + } __attribute__ ((packed)); + ++u32 fsl_guts_get_svr(void); + + /* Alternate function signal multiplex control */ + #define MPC85xx_PMUXCR_QE(x) (0x8000 >> (x)) +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/809-i2c-support-layerscape.patch b/target/linux/layerscape/patches-4.9/809-i2c-support-layerscape.patch new file mode 100644 index 0000000000..fd4371adb1 --- /dev/null +++ b/target/linux/layerscape/patches-4.9/809-i2c-support-layerscape.patch @@ -0,0 +1,140 @@ +From 3c5032fe34f1af50e9e5fe58d40bf93c1717302f Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 12:19:53 +0800 +Subject: [PATCH] i2c: support layerscape + +This is a integrated patch for layerscape i2c support. + +Signed-off-by: Zhang Ying-22455 +Signed-off-by: Priyanka Jain +Signed-off-by: Yangbo Lu +--- + drivers/i2c/busses/i2c-imx.c | 10 ++++++++- + drivers/i2c/muxes/i2c-mux-pca954x.c | 43 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 52 insertions(+), 1 deletion(-) + +diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c +index 47fc1f1a..a35c366b 100644 +--- a/drivers/i2c/busses/i2c-imx.c ++++ b/drivers/i2c/busses/i2c-imx.c +@@ -889,6 +889,14 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, + + dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); + ++ /* ++ * workround for ERR010027: ensure that the I2C BUS is idle ++ * before switching to master mode and attempting a Start cycle ++ */ ++ result = i2c_imx_bus_busy(i2c_imx, 0); ++ if (result) ++ goto out; ++ + result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent); + if (result < 0) + goto out; +@@ -1100,7 +1108,7 @@ static int i2c_imx_probe(struct platform_device *pdev) + } + + /* Request IRQ */ +- ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0, ++ ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, IRQF_SHARED, + pdev->name, i2c_imx); + if (ret) { + dev_err(&pdev->dev, "can't claim irq %d\n", irq); +diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c +index 9c4ac26c..3c27ab84 100644 +--- a/drivers/i2c/muxes/i2c-mux-pca954x.c ++++ b/drivers/i2c/muxes/i2c-mux-pca954x.c +@@ -74,6 +74,7 @@ struct pca954x { + u8 last_chan; /* last register value */ + u8 deselect; + struct i2c_client *client; ++ u8 disable_mux; /* do not disable mux if val not 0 */ + }; + + /* Provide specs for the PCA954x types we know about */ +@@ -196,6 +197,13 @@ static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan) + if (!(data->deselect & (1 << chan))) + return 0; + ++#ifdef CONFIG_ARCH_LAYERSCAPE ++ if (data->disable_mux != 0) ++ data->last_chan = data->chip->nchans; ++ else ++ data->last_chan = 0; ++ return pca954x_reg_write(muxc->parent, client, data->disable_mux); ++#endif + /* Deselect active channel */ + data->last_chan = 0; + return pca954x_reg_write(muxc->parent, client, data->last_chan); +@@ -228,6 +236,28 @@ static int pca954x_probe(struct i2c_client *client, + return -ENOMEM; + data = i2c_mux_priv(muxc); + ++#ifdef CONFIG_ARCH_LAYERSCAPE ++ /* The point here is that you must not disable a mux if there ++ * are no pullups on the input or you mess up the I2C. This ++ * needs to be put into the DTS really as the kernel cannot ++ * know this otherwise. ++ */ ++ match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); ++ if (match) ++ data->chip = of_device_get_match_data(&client->dev); ++ else ++ data->chip = &chips[id->driver_data]; ++ ++ data->disable_mux = of_node && ++ of_property_read_bool(of_node, "i2c-mux-never-disable") && ++ data->chip->muxtype == pca954x_ismux ? ++ data->chip->enable : 0; ++ /* force the first selection */ ++ if (data->disable_mux != 0) ++ data->last_chan = data->chip->nchans; ++ else ++ data->last_chan = 0; ++#endif + i2c_set_clientdata(client, muxc); + data->client = client; + +@@ -240,11 +270,16 @@ static int pca954x_probe(struct i2c_client *client, + * that the mux is in fact present. This also + * initializes the mux to disconnected state. + */ ++#ifdef CONFIG_ARCH_LAYERSCAPE ++ if (i2c_smbus_write_byte(client, data->disable_mux) < 0) { ++#else + if (i2c_smbus_write_byte(client, 0) < 0) { ++#endif + dev_warn(&client->dev, "probe failed\n"); + return -ENODEV; + } + ++#ifndef CONFIG_ARCH_LAYERSCAPE + match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); + if (match) + data->chip = of_device_get_match_data(&client->dev); +@@ -252,6 +287,7 @@ static int pca954x_probe(struct i2c_client *client, + data->chip = &chips[id->driver_data]; + + data->last_chan = 0; /* force the first selection */ ++#endif + + idle_disconnect_dt = of_node && + of_property_read_bool(of_node, "i2c-mux-idle-disconnect"); +@@ -312,6 +348,13 @@ static int pca954x_resume(struct device *dev) + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct pca954x *data = i2c_mux_priv(muxc); + ++#ifdef CONFIG_ARCH_LAYERSCAPE ++ if (data->disable_mux != 0) ++ data->last_chan = data->chip->nchans; ++ else ++ data->last_chan = 0; ++ return i2c_smbus_write_byte(client, data->disable_mux); ++#endif + data->last_chan = 0; + return i2c_smbus_write_byte(client, 0); + } +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/810-iommu-support-layerscape.patch b/target/linux/layerscape/patches-4.9/810-iommu-support-layerscape.patch new file mode 100644 index 0000000000..dd536093e3 --- /dev/null +++ b/target/linux/layerscape/patches-4.9/810-iommu-support-layerscape.patch @@ -0,0 +1,1338 @@ +From f1874c71c855bd8ca8478a622053276f2c61eeca Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Wed, 27 Sep 2017 10:33:26 +0800 +Subject: [PATCH] iommu: support layerscape + +This is a integrated patch for layerscape smmu support. + +Signed-off-by: Eric Auger +Signed-off-by: Robin Murphy +Signed-off-by: Nipun Gupta +Signed-off-by: Sunil Goutham +Signed-off-by: Yangbo Lu +--- + drivers/iommu/amd_iommu.c | 56 ++++++---- + drivers/iommu/arm-smmu-v3.c | 35 ++++++- + drivers/iommu/arm-smmu.c | 74 ++++++++++--- + drivers/iommu/dma-iommu.c | 242 ++++++++++++++++++++++++++++++++++++------- + drivers/iommu/intel-iommu.c | 92 ++++++++++++---- + drivers/iommu/iommu.c | 191 ++++++++++++++++++++++++++++++++-- + drivers/iommu/mtk_iommu.c | 2 + + drivers/iommu/mtk_iommu_v1.c | 2 + + include/linux/dma-iommu.h | 11 ++ + include/linux/iommu.h | 55 +++++++--- + 10 files changed, 645 insertions(+), 115 deletions(-) + +diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c +index c380b7e8..93199931 100644 +--- a/drivers/iommu/amd_iommu.c ++++ b/drivers/iommu/amd_iommu.c +@@ -373,6 +373,8 @@ static struct iommu_group *acpihid_device_group(struct device *dev) + + if (!entry->group) + entry->group = generic_device_group(dev); ++ else ++ iommu_group_ref_get(entry->group); + + return entry->group; + } +@@ -3159,9 +3161,10 @@ static bool amd_iommu_capable(enum iommu_cap cap) + return false; + } + +-static void amd_iommu_get_dm_regions(struct device *dev, +- struct list_head *head) ++static void amd_iommu_get_resv_regions(struct device *dev, ++ struct list_head *head) + { ++ struct iommu_resv_region *region; + struct unity_map_entry *entry; + int devid; + +@@ -3170,41 +3173,56 @@ static void amd_iommu_get_dm_regions(struct device *dev, + return; + + list_for_each_entry(entry, &amd_iommu_unity_map, list) { +- struct iommu_dm_region *region; ++ size_t length; ++ int prot = 0; + + if (devid < entry->devid_start || devid > entry->devid_end) + continue; + +- region = kzalloc(sizeof(*region), GFP_KERNEL); ++ length = entry->address_end - entry->address_start; ++ if (entry->prot & IOMMU_PROT_IR) ++ prot |= IOMMU_READ; ++ if (entry->prot & IOMMU_PROT_IW) ++ prot |= IOMMU_WRITE; ++ ++ region = iommu_alloc_resv_region(entry->address_start, ++ length, prot, ++ IOMMU_RESV_DIRECT); + if (!region) { + pr_err("Out of memory allocating dm-regions for %s\n", + dev_name(dev)); + return; + } +- +- region->start = entry->address_start; +- region->length = entry->address_end - entry->address_start; +- if (entry->prot & IOMMU_PROT_IR) +- region->prot |= IOMMU_READ; +- if (entry->prot & IOMMU_PROT_IW) +- region->prot |= IOMMU_WRITE; +- + list_add_tail(®ion->list, head); + } ++ ++ region = iommu_alloc_resv_region(MSI_RANGE_START, ++ MSI_RANGE_END - MSI_RANGE_START + 1, ++ 0, IOMMU_RESV_MSI); ++ if (!region) ++ return; ++ list_add_tail(®ion->list, head); ++ ++ region = iommu_alloc_resv_region(HT_RANGE_START, ++ HT_RANGE_END - HT_RANGE_START + 1, ++ 0, IOMMU_RESV_RESERVED); ++ if (!region) ++ return; ++ list_add_tail(®ion->list, head); + } + +-static void amd_iommu_put_dm_regions(struct device *dev, ++static void amd_iommu_put_resv_regions(struct device *dev, + struct list_head *head) + { +- struct iommu_dm_region *entry, *next; ++ struct iommu_resv_region *entry, *next; + + list_for_each_entry_safe(entry, next, head, list) + kfree(entry); + } + +-static void amd_iommu_apply_dm_region(struct device *dev, ++static void amd_iommu_apply_resv_region(struct device *dev, + struct iommu_domain *domain, +- struct iommu_dm_region *region) ++ struct iommu_resv_region *region) + { + struct dma_ops_domain *dma_dom = to_dma_ops_domain(to_pdomain(domain)); + unsigned long start, end; +@@ -3228,9 +3246,9 @@ static const struct iommu_ops amd_iommu_ops = { + .add_device = amd_iommu_add_device, + .remove_device = amd_iommu_remove_device, + .device_group = amd_iommu_device_group, +- .get_dm_regions = amd_iommu_get_dm_regions, +- .put_dm_regions = amd_iommu_put_dm_regions, +- .apply_dm_region = amd_iommu_apply_dm_region, ++ .get_resv_regions = amd_iommu_get_resv_regions, ++ .put_resv_regions = amd_iommu_put_resv_regions, ++ .apply_resv_region = amd_iommu_apply_resv_region, + .pgsize_bitmap = AMD_IOMMU_PGSIZES, + }; + +diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c +index e6f9b2d7..e3ed8dc5 100644 +--- a/drivers/iommu/arm-smmu-v3.c ++++ b/drivers/iommu/arm-smmu-v3.c +@@ -410,6 +410,9 @@ + /* High-level queue structures */ + #define ARM_SMMU_POLL_TIMEOUT_US 100 + ++#define MSI_IOVA_BASE 0x8000000 ++#define MSI_IOVA_LENGTH 0x100000 ++ + static bool disable_bypass; + module_param_named(disable_bypass, disable_bypass, bool, S_IRUGO); + MODULE_PARM_DESC(disable_bypass, +@@ -1370,8 +1373,6 @@ static bool arm_smmu_capable(enum iommu_cap cap) + switch (cap) { + case IOMMU_CAP_CACHE_COHERENCY: + return true; +- case IOMMU_CAP_INTR_REMAP: +- return true; /* MSIs are just memory writes */ + case IOMMU_CAP_NOEXEC: + return true; + default: +@@ -1709,6 +1710,9 @@ arm_smmu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova) + struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); + struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops; + ++ if (domain->type == IOMMU_DOMAIN_IDENTITY) ++ return iova; ++ + if (!ops) + return 0; + +@@ -1880,6 +1884,31 @@ static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args) + return iommu_fwspec_add_ids(dev, args->args, 1); + } + ++static void arm_smmu_get_resv_regions(struct device *dev, ++ struct list_head *head) ++{ ++ struct iommu_resv_region *region; ++ int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO; ++ ++ region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH, ++ prot, IOMMU_RESV_SW_MSI); ++ if (!region) ++ return; ++ ++ list_add_tail(®ion->list, head); ++ ++ iommu_dma_get_resv_regions(dev, head); ++} ++ ++static void arm_smmu_put_resv_regions(struct device *dev, ++ struct list_head *head) ++{ ++ struct iommu_resv_region *entry, *next; ++ ++ list_for_each_entry_safe(entry, next, head, list) ++ kfree(entry); ++} ++ + static struct iommu_ops arm_smmu_ops = { + .capable = arm_smmu_capable, + .domain_alloc = arm_smmu_domain_alloc, +@@ -1895,6 +1924,8 @@ static struct iommu_ops arm_smmu_ops = { + .domain_get_attr = arm_smmu_domain_get_attr, + .domain_set_attr = arm_smmu_domain_set_attr, + .of_xlate = arm_smmu_of_xlate, ++ .get_resv_regions = arm_smmu_get_resv_regions, ++ .put_resv_regions = arm_smmu_put_resv_regions, + .pgsize_bitmap = -1UL, /* Restricted during device attach */ + }; + +diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c +index 8f728144..df18dac3 100644 +--- a/drivers/iommu/arm-smmu.c ++++ b/drivers/iommu/arm-smmu.c +@@ -49,6 +49,7 @@ + #include + + #include ++#include "../staging/fsl-mc/include/mc-bus.h" + + #include "io-pgtable.h" + +@@ -247,6 +248,7 @@ enum arm_smmu_s2cr_privcfg { + #define ARM_MMU500_ACTLR_CPRE (1 << 1) + + #define ARM_MMU500_ACR_CACHE_LOCK (1 << 26) ++#define ARM_MMU500_ACR_SMTNMB_TLBEN (1 << 8) + + #define CB_PAR_F (1 << 0) + +@@ -278,6 +280,9 @@ enum arm_smmu_s2cr_privcfg { + + #define FSYNR0_WNR (1 << 4) + ++#define MSI_IOVA_BASE 0x8000000 ++#define MSI_IOVA_LENGTH 0x100000 ++ + static int force_stage; + module_param(force_stage, int, S_IRUGO); + MODULE_PARM_DESC(force_stage, +@@ -1343,6 +1348,9 @@ static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain, + struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); + struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops; + ++ if (domain->type == IOMMU_DOMAIN_IDENTITY) ++ return iova; ++ + if (!ops) + return 0; + +@@ -1368,8 +1376,6 @@ static bool arm_smmu_capable(enum iommu_cap cap) + * requests. + */ + return true; +- case IOMMU_CAP_INTR_REMAP: +- return true; /* MSIs are just memory writes */ + case IOMMU_CAP_NOEXEC: + return true; + default: +@@ -1478,10 +1484,12 @@ static struct iommu_group *arm_smmu_device_group(struct device *dev) + } + + if (group) +- return group; ++ return iommu_group_ref_get(group); + + if (dev_is_pci(dev)) + group = pci_device_group(dev); ++ else if (dev_is_fsl_mc(dev)) ++ group = fsl_mc_device_group(dev); + else + group = generic_device_group(dev); + +@@ -1534,17 +1542,44 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain, + + static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args) + { +- u32 fwid = 0; ++ u32 mask, fwid = 0; + + if (args->args_count > 0) + fwid |= (u16)args->args[0]; + + if (args->args_count > 1) + fwid |= (u16)args->args[1] << SMR_MASK_SHIFT; ++ else if (!of_property_read_u32(args->np, "stream-match-mask", &mask)) ++ fwid |= (u16)mask << SMR_MASK_SHIFT; + + return iommu_fwspec_add_ids(dev, &fwid, 1); + } + ++static void arm_smmu_get_resv_regions(struct device *dev, ++ struct list_head *head) ++{ ++ struct iommu_resv_region *region; ++ int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO; ++ ++ region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH, ++ prot, IOMMU_RESV_SW_MSI); ++ if (!region) ++ return; ++ ++ list_add_tail(®ion->list, head); ++ ++ iommu_dma_get_resv_regions(dev, head); ++} ++ ++static void arm_smmu_put_resv_regions(struct device *dev, ++ struct list_head *head) ++{ ++ struct iommu_resv_region *entry, *next; ++ ++ list_for_each_entry_safe(entry, next, head, list) ++ kfree(entry); ++} ++ + static struct iommu_ops arm_smmu_ops = { + .capable = arm_smmu_capable, + .domain_alloc = arm_smmu_domain_alloc, +@@ -1560,6 +1595,8 @@ static struct iommu_ops arm_smmu_ops = { + .domain_get_attr = arm_smmu_domain_get_attr, + .domain_set_attr = arm_smmu_domain_set_attr, + .of_xlate = arm_smmu_of_xlate, ++ .get_resv_regions = arm_smmu_get_resv_regions, ++ .put_resv_regions = arm_smmu_put_resv_regions, + .pgsize_bitmap = -1UL, /* Restricted during device attach */ + }; + +@@ -1581,16 +1618,22 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu) + for (i = 0; i < smmu->num_mapping_groups; ++i) + arm_smmu_write_sme(smmu, i); + +- /* +- * Before clearing ARM_MMU500_ACTLR_CPRE, need to +- * clear CACHE_LOCK bit of ACR first. And, CACHE_LOCK +- * bit is only present in MMU-500r2 onwards. +- */ +- reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID7); +- major = (reg >> ID7_MAJOR_SHIFT) & ID7_MAJOR_MASK; +- if ((smmu->model == ARM_MMU500) && (major >= 2)) { ++ if (smmu->model == ARM_MMU500) { ++ /* ++ * Before clearing ARM_MMU500_ACTLR_CPRE, need to ++ * clear CACHE_LOCK bit of ACR first. And, CACHE_LOCK ++ * bit is only present in MMU-500r2 onwards. ++ */ ++ reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID7); ++ major = (reg >> ID7_MAJOR_SHIFT) & ID7_MAJOR_MASK; + reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_sACR); +- reg &= ~ARM_MMU500_ACR_CACHE_LOCK; ++ if (major >= 2) ++ reg &= ~ARM_MMU500_ACR_CACHE_LOCK; ++ /* ++ * Allow unmatched Stream IDs to allocate bypass ++ * TLB entries for reduced latency. ++ */ ++ reg |= ARM_MMU500_ACR_SMTNMB_TLBEN; + writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_sACR); + } + +@@ -2024,6 +2067,11 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) + bus_set_iommu(&pci_bus_type, &arm_smmu_ops); + } + #endif ++#ifdef CONFIG_FSL_MC_BUS ++ if (!iommu_present(&fsl_mc_bus_type)) ++ bus_set_iommu(&fsl_mc_bus_type, &arm_smmu_ops); ++#endif ++ + return 0; + } + +diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c +index 1520e7f0..3ade4153 100644 +--- a/drivers/iommu/dma-iommu.c ++++ b/drivers/iommu/dma-iommu.c +@@ -37,15 +37,50 @@ struct iommu_dma_msi_page { + phys_addr_t phys; + }; + ++enum iommu_dma_cookie_type { ++ IOMMU_DMA_IOVA_COOKIE, ++ IOMMU_DMA_MSI_COOKIE, ++}; ++ + struct iommu_dma_cookie { +- struct iova_domain iovad; +- struct list_head msi_page_list; +- spinlock_t msi_lock; ++ enum iommu_dma_cookie_type type; ++ union { ++ /* Full allocator for IOMMU_DMA_IOVA_COOKIE */ ++ struct iova_domain iovad; ++ /* Trivial linear page allocator for IOMMU_DMA_MSI_COOKIE */ ++ dma_addr_t msi_iova; ++ }; ++ struct list_head msi_page_list; ++ spinlock_t msi_lock; + }; + ++static inline size_t cookie_msi_granule(struct iommu_dma_cookie *cookie) ++{ ++ if (cookie->type == IOMMU_DMA_IOVA_COOKIE) ++ return cookie->iovad.granule; ++ return PAGE_SIZE; ++} ++ + static inline struct iova_domain *cookie_iovad(struct iommu_domain *domain) + { +- return &((struct iommu_dma_cookie *)domain->iova_cookie)->iovad; ++ struct iommu_dma_cookie *cookie = domain->iova_cookie; ++ ++ if (cookie->type == IOMMU_DMA_IOVA_COOKIE) ++ return &cookie->iovad; ++ return NULL; ++} ++ ++static struct iommu_dma_cookie *cookie_alloc(enum iommu_dma_cookie_type type) ++{ ++ struct iommu_dma_cookie *cookie; ++ ++ cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); ++ if (cookie) { ++ spin_lock_init(&cookie->msi_lock); ++ INIT_LIST_HEAD(&cookie->msi_page_list); ++ cookie->type = type; ++ } ++ return cookie; + } + + int iommu_dma_init(void) +@@ -61,26 +96,54 @@ int iommu_dma_init(void) + * callback when domain->type == IOMMU_DOMAIN_DMA. + */ + int iommu_get_dma_cookie(struct iommu_domain *domain) ++{ ++ if (domain->iova_cookie) ++ return -EEXIST; ++ ++ domain->iova_cookie = cookie_alloc(IOMMU_DMA_IOVA_COOKIE); ++ if (!domain->iova_cookie) ++ return -ENOMEM; ++ ++ return 0; ++} ++EXPORT_SYMBOL(iommu_get_dma_cookie); ++ ++/** ++ * iommu_get_msi_cookie - Acquire just MSI remapping resources ++ * @domain: IOMMU domain to prepare ++ * @base: Start address of IOVA region for MSI mappings ++ * ++ * Users who manage their own IOVA allocation and do not want DMA API support, ++ * but would still like to take advantage of automatic MSI remapping, can use ++ * this to initialise their own domain appropriately. Users should reserve a ++ * contiguous IOVA region, starting at @base, large enough to accommodate the ++ * number of PAGE_SIZE mappings necessary to cover every MSI doorbell address ++ * used by the devices attached to @domain. ++ */ ++int iommu_get_msi_cookie(struct iommu_domain *domain, dma_addr_t base) + { + struct iommu_dma_cookie *cookie; + ++ if (domain->type != IOMMU_DOMAIN_UNMANAGED) ++ return -EINVAL; ++ + if (domain->iova_cookie) + return -EEXIST; + +- cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); ++ cookie = cookie_alloc(IOMMU_DMA_MSI_COOKIE); + if (!cookie) + return -ENOMEM; + +- spin_lock_init(&cookie->msi_lock); +- INIT_LIST_HEAD(&cookie->msi_page_list); ++ cookie->msi_iova = base; + domain->iova_cookie = cookie; + return 0; + } +-EXPORT_SYMBOL(iommu_get_dma_cookie); ++EXPORT_SYMBOL(iommu_get_msi_cookie); + + /** + * iommu_put_dma_cookie - Release a domain's DMA mapping resources +- * @domain: IOMMU domain previously prepared by iommu_get_dma_cookie() ++ * @domain: IOMMU domain previously prepared by iommu_get_dma_cookie() or ++ * iommu_get_msi_cookie() + * + * IOMMU drivers should normally call this from their domain_free callback. + */ +@@ -92,7 +155,7 @@ void iommu_put_dma_cookie(struct iommu_domain *domain) + if (!cookie) + return; + +- if (cookie->iovad.granule) ++ if (cookie->type == IOMMU_DMA_IOVA_COOKIE && cookie->iovad.granule) + put_iova_domain(&cookie->iovad); + + list_for_each_entry_safe(msi, tmp, &cookie->msi_page_list, list) { +@@ -104,21 +167,99 @@ void iommu_put_dma_cookie(struct iommu_domain *domain) + } + EXPORT_SYMBOL(iommu_put_dma_cookie); + +-static void iova_reserve_pci_windows(struct pci_dev *dev, +- struct iova_domain *iovad) ++/** ++ * iommu_dma_get_resv_regions - Reserved region driver helper ++ * @dev: Device from iommu_get_resv_regions() ++ * @list: Reserved region list from iommu_get_resv_regions() ++ * ++ * IOMMU drivers can use this to implement their .get_resv_regions callback ++ * for general non-IOMMU-specific reservations. Currently, this covers host ++ * bridge windows for PCI devices. ++ */ ++void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list) + { +- struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus); ++ struct pci_host_bridge *bridge; + struct resource_entry *window; +- unsigned long lo, hi; + ++ if (!dev_is_pci(dev)) ++ return; ++ ++ bridge = pci_find_host_bridge(to_pci_dev(dev)->bus); + resource_list_for_each_entry(window, &bridge->windows) { ++ struct iommu_resv_region *region; ++ phys_addr_t start; ++ size_t length; ++ + if (resource_type(window->res) != IORESOURCE_MEM) + continue; + +- lo = iova_pfn(iovad, window->res->start - window->offset); +- hi = iova_pfn(iovad, window->res->end - window->offset); ++ start = window->res->start - window->offset; ++ length = window->res->end - window->res->start + 1; ++ region = iommu_alloc_resv_region(start, length, 0, ++ IOMMU_RESV_RESERVED); ++ if (!region) ++ return; ++ ++ list_add_tail(®ion->list, list); ++ } ++} ++EXPORT_SYMBOL(iommu_dma_get_resv_regions); ++ ++static int cookie_init_hw_msi_region(struct iommu_dma_cookie *cookie, ++ phys_addr_t start, phys_addr_t end) ++{ ++ struct iova_domain *iovad = &cookie->iovad; ++ struct iommu_dma_msi_page *msi_page; ++ int i, num_pages; ++ ++ start -= iova_offset(iovad, start); ++ num_pages = iova_align(iovad, end - start) >> iova_shift(iovad); ++ ++ msi_page = kcalloc(num_pages, sizeof(*msi_page), GFP_KERNEL); ++ if (!msi_page) ++ return -ENOMEM; ++ ++ for (i = 0; i < num_pages; i++) { ++ msi_page[i].phys = start; ++ msi_page[i].iova = start; ++ INIT_LIST_HEAD(&msi_page[i].list); ++ list_add(&msi_page[i].list, &cookie->msi_page_list); ++ start += iovad->granule; ++ } ++ ++ return 0; ++} ++ ++static int iova_reserve_iommu_regions(struct device *dev, ++ struct iommu_domain *domain) ++{ ++ struct iommu_dma_cookie *cookie = domain->iova_cookie; ++ struct iova_domain *iovad = &cookie->iovad; ++ struct iommu_resv_region *region; ++ LIST_HEAD(resv_regions); ++ int ret = 0; ++ ++ iommu_get_resv_regions(dev, &resv_regions); ++ list_for_each_entry(region, &resv_regions, list) { ++ unsigned long lo, hi; ++ ++ /* We ARE the software that manages these! */ ++ if (region->type == IOMMU_RESV_SW_MSI) ++ continue; ++ ++ lo = iova_pfn(iovad, region->start); ++ hi = iova_pfn(iovad, region->start + region->length - 1); + reserve_iova(iovad, lo, hi); ++ ++ if (region->type == IOMMU_RESV_MSI) ++ ret = cookie_init_hw_msi_region(cookie, region->start, ++ region->start + region->length); ++ if (ret) ++ break; + } ++ iommu_put_resv_regions(dev, &resv_regions); ++ ++ return ret; + } + + /** +@@ -136,11 +277,12 @@ static void iova_reserve_pci_windows(struct pci_dev *dev, + int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, + u64 size, struct device *dev) + { +- struct iova_domain *iovad = cookie_iovad(domain); ++ struct iommu_dma_cookie *cookie = domain->iova_cookie; ++ struct iova_domain *iovad = &cookie->iovad; + unsigned long order, base_pfn, end_pfn; + +- if (!iovad) +- return -ENODEV; ++ if (!cookie || cookie->type != IOMMU_DMA_IOVA_COOKIE) ++ return -EINVAL; + + /* Use the smallest supported page size for IOVA granularity */ + order = __ffs(domain->pgsize_bitmap); +@@ -160,22 +302,37 @@ int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, + end_pfn = min_t(unsigned long, end_pfn, + domain->geometry.aperture_end >> order); + } ++ /* ++ * PCI devices may have larger DMA masks, but still prefer allocating ++ * within a 32-bit mask to avoid DAC addressing. Such limitations don't ++ * apply to the typical platform device, so for those we may as well ++ * leave the cache limit at the top of their range to save an rb_last() ++ * traversal on every allocation. ++ */ ++ if (dev && dev_is_pci(dev)) ++ end_pfn &= DMA_BIT_MASK(32) >> order; + +- /* All we can safely do with an existing domain is enlarge it */ ++ /* start_pfn is always nonzero for an already-initialised domain */ + if (iovad->start_pfn) { + if (1UL << order != iovad->granule || +- base_pfn != iovad->start_pfn || +- end_pfn < iovad->dma_32bit_pfn) { ++ base_pfn != iovad->start_pfn) { + pr_warn("Incompatible range for DMA domain\n"); + return -EFAULT; + } +- iovad->dma_32bit_pfn = end_pfn; +- } else { +- init_iova_domain(iovad, 1UL << order, base_pfn, end_pfn); +- if (dev && dev_is_pci(dev)) +- iova_reserve_pci_windows(to_pci_dev(dev), iovad); ++ /* ++ * If we have devices with different DMA masks, move the free ++ * area cache limit down for the benefit of the smaller one. ++ */ ++ iovad->dma_32bit_pfn = min(end_pfn, iovad->dma_32bit_pfn); ++ ++ return 0; + } +- return 0; ++ ++ init_iova_domain(iovad, 1UL << order, base_pfn, end_pfn); ++ if (!dev) ++ return 0; ++ ++ return iova_reserve_iommu_regions(dev, domain); + } + EXPORT_SYMBOL(iommu_dma_init_domain); + +@@ -643,11 +800,12 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, + { + struct iommu_dma_cookie *cookie = domain->iova_cookie; + struct iommu_dma_msi_page *msi_page; +- struct iova_domain *iovad = &cookie->iovad; ++ struct iova_domain *iovad = cookie_iovad(domain); + struct iova *iova; + int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO; ++ size_t size = cookie_msi_granule(cookie); + +- msi_addr &= ~(phys_addr_t)iova_mask(iovad); ++ msi_addr &= ~(phys_addr_t)(size - 1); + list_for_each_entry(msi_page, &cookie->msi_page_list, list) + if (msi_page->phys == msi_addr) + return msi_page; +@@ -656,13 +814,18 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, + if (!msi_page) + return NULL; + +- iova = __alloc_iova(domain, iovad->granule, dma_get_mask(dev)); +- if (!iova) +- goto out_free_page; +- + msi_page->phys = msi_addr; +- msi_page->iova = iova_dma_addr(iovad, iova); +- if (iommu_map(domain, msi_page->iova, msi_addr, iovad->granule, prot)) ++ if (iovad) { ++ iova = __alloc_iova(domain, size, dma_get_mask(dev)); ++ if (!iova) ++ goto out_free_page; ++ msi_page->iova = iova_dma_addr(iovad, iova); ++ } else { ++ msi_page->iova = cookie->msi_iova; ++ cookie->msi_iova += size; ++ } ++ ++ if (iommu_map(domain, msi_page->iova, msi_addr, size, prot)) + goto out_free_iova; + + INIT_LIST_HEAD(&msi_page->list); +@@ -670,7 +833,10 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, + return msi_page; + + out_free_iova: +- __free_iova(iovad, iova); ++ if (iovad) ++ __free_iova(iovad, iova); ++ else ++ cookie->msi_iova -= size; + out_free_page: + kfree(msi_page); + return NULL; +@@ -711,7 +877,7 @@ void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg) + msg->data = ~0U; + } else { + msg->address_hi = upper_32_bits(msi_page->iova); +- msg->address_lo &= iova_mask(&cookie->iovad); ++ msg->address_lo &= cookie_msi_granule(cookie) - 1; + msg->address_lo += lower_32_bits(msi_page->iova); + } + } +diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c +index 002f8a42..befbfd30 100644 +--- a/drivers/iommu/intel-iommu.c ++++ b/drivers/iommu/intel-iommu.c +@@ -440,6 +440,7 @@ struct dmar_rmrr_unit { + u64 end_address; /* reserved end address */ + struct dmar_dev_scope *devices; /* target devices */ + int devices_cnt; /* target device count */ ++ struct iommu_resv_region *resv; /* reserved region handle */ + }; + + struct dmar_atsr_unit { +@@ -4250,27 +4251,40 @@ static inline void init_iommu_pm_ops(void) {} + int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg) + { + struct acpi_dmar_reserved_memory *rmrr; ++ int prot = DMA_PTE_READ|DMA_PTE_WRITE; + struct dmar_rmrr_unit *rmrru; ++ size_t length; + + rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL); + if (!rmrru) +- return -ENOMEM; ++ goto out; + + rmrru->hdr = header; + rmrr = (struct acpi_dmar_reserved_memory *)header; + rmrru->base_address = rmrr->base_address; + rmrru->end_address = rmrr->end_address; ++ ++ length = rmrr->end_address - rmrr->base_address + 1; ++ rmrru->resv = iommu_alloc_resv_region(rmrr->base_address, length, prot, ++ IOMMU_RESV_DIRECT); ++ if (!rmrru->resv) ++ goto free_rmrru; ++ + rmrru->devices = dmar_alloc_dev_scope((void *)(rmrr + 1), + ((void *)rmrr) + rmrr->header.length, + &rmrru->devices_cnt); +- if (rmrru->devices_cnt && rmrru->devices == NULL) { +- kfree(rmrru); +- return -ENOMEM; +- } ++ if (rmrru->devices_cnt && rmrru->devices == NULL) ++ goto free_all; + + list_add(&rmrru->list, &dmar_rmrr_units); + + return 0; ++free_all: ++ kfree(rmrru->resv); ++free_rmrru: ++ kfree(rmrru); ++out: ++ return -ENOMEM; + } + + static struct dmar_atsr_unit *dmar_find_atsr(struct acpi_dmar_atsr *atsr) +@@ -4484,6 +4498,7 @@ static void intel_iommu_free_dmars(void) + list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) { + list_del(&rmrru->list); + dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt); ++ kfree(rmrru->resv); + kfree(rmrru); + } + +@@ -5219,6 +5234,45 @@ static void intel_iommu_remove_device(struct device *dev) + iommu_device_unlink(iommu->iommu_dev, dev); + } + ++static void intel_iommu_get_resv_regions(struct device *device, ++ struct list_head *head) ++{ ++ struct iommu_resv_region *reg; ++ struct dmar_rmrr_unit *rmrr; ++ struct device *i_dev; ++ int i; ++ ++ rcu_read_lock(); ++ for_each_rmrr_units(rmrr) { ++ for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt, ++ i, i_dev) { ++ if (i_dev != device) ++ continue; ++ ++ list_add_tail(&rmrr->resv->list, head); ++ } ++ } ++ rcu_read_unlock(); ++ ++ reg = iommu_alloc_resv_region(IOAPIC_RANGE_START, ++ IOAPIC_RANGE_END - IOAPIC_RANGE_START + 1, ++ 0, IOMMU_RESV_MSI); ++ if (!reg) ++ return; ++ list_add_tail(®->list, head); ++} ++ ++static void intel_iommu_put_resv_regions(struct device *dev, ++ struct list_head *head) ++{ ++ struct iommu_resv_region *entry, *next; ++ ++ list_for_each_entry_safe(entry, next, head, list) { ++ if (entry->type == IOMMU_RESV_RESERVED) ++ kfree(entry); ++ } ++} ++ + #ifdef CONFIG_INTEL_IOMMU_SVM + #define MAX_NR_PASID_BITS (20) + static inline unsigned long intel_iommu_get_pts(struct intel_iommu *iommu) +@@ -5349,19 +5403,21 @@ struct intel_iommu *intel_svm_device_to_iommu(struct device *dev) + #endif /* CONFIG_INTEL_IOMMU_SVM */ + + static const struct iommu_ops intel_iommu_ops = { +- .capable = intel_iommu_capable, +- .domain_alloc = intel_iommu_domain_alloc, +- .domain_free = intel_iommu_domain_free, +- .attach_dev = intel_iommu_attach_device, +- .detach_dev = intel_iommu_detach_device, +- .map = intel_iommu_map, +- .unmap = intel_iommu_unmap, +- .map_sg = default_iommu_map_sg, +- .iova_to_phys = intel_iommu_iova_to_phys, +- .add_device = intel_iommu_add_device, +- .remove_device = intel_iommu_remove_device, +- .device_group = pci_device_group, +- .pgsize_bitmap = INTEL_IOMMU_PGSIZES, ++ .capable = intel_iommu_capable, ++ .domain_alloc = intel_iommu_domain_alloc, ++ .domain_free = intel_iommu_domain_free, ++ .attach_dev = intel_iommu_attach_device, ++ .detach_dev = intel_iommu_detach_device, ++ .map = intel_iommu_map, ++ .unmap = intel_iommu_unmap, ++ .map_sg = default_iommu_map_sg, ++ .iova_to_phys = intel_iommu_iova_to_phys, ++ .add_device = intel_iommu_add_device, ++ .remove_device = intel_iommu_remove_device, ++ .get_resv_regions = intel_iommu_get_resv_regions, ++ .put_resv_regions = intel_iommu_put_resv_regions, ++ .device_group = pci_device_group, ++ .pgsize_bitmap = INTEL_IOMMU_PGSIZES, + }; + + static void quirk_iommu_g4x_gfx(struct pci_dev *dev) +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index 87d3060f..372fc463 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -68,6 +68,13 @@ struct iommu_group_attribute { + const char *buf, size_t count); + }; + ++static const char * const iommu_group_resv_type_string[] = { ++ [IOMMU_RESV_DIRECT] = "direct", ++ [IOMMU_RESV_RESERVED] = "reserved", ++ [IOMMU_RESV_MSI] = "msi", ++ [IOMMU_RESV_SW_MSI] = "msi", ++}; ++ + #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \ + struct iommu_group_attribute iommu_group_attr_##_name = \ + __ATTR(_name, _mode, _show, _store) +@@ -133,8 +140,131 @@ static ssize_t iommu_group_show_name(struct iommu_group *group, char *buf) + return sprintf(buf, "%s\n", group->name); + } + ++/** ++ * iommu_insert_resv_region - Insert a new region in the ++ * list of reserved regions. ++ * @new: new region to insert ++ * @regions: list of regions ++ * ++ * The new element is sorted by address with respect to the other ++ * regions of the same type. In case it overlaps with another ++ * region of the same type, regions are merged. In case it ++ * overlaps with another region of different type, regions are ++ * not merged. ++ */ ++static int iommu_insert_resv_region(struct iommu_resv_region *new, ++ struct list_head *regions) ++{ ++ struct iommu_resv_region *region; ++ phys_addr_t start = new->start; ++ phys_addr_t end = new->start + new->length - 1; ++ struct list_head *pos = regions->next; ++ ++ while (pos != regions) { ++ struct iommu_resv_region *entry = ++ list_entry(pos, struct iommu_resv_region, list); ++ phys_addr_t a = entry->start; ++ phys_addr_t b = entry->start + entry->length - 1; ++ int type = entry->type; ++ ++ if (end < a) { ++ goto insert; ++ } else if (start > b) { ++ pos = pos->next; ++ } else if ((start >= a) && (end <= b)) { ++ if (new->type == type) ++ goto done; ++ else ++ pos = pos->next; ++ } else { ++ if (new->type == type) { ++ phys_addr_t new_start = min(a, start); ++ phys_addr_t new_end = max(b, end); ++ ++ list_del(&entry->list); ++ entry->start = new_start; ++ entry->length = new_end - new_start + 1; ++ iommu_insert_resv_region(entry, regions); ++ } else { ++ pos = pos->next; ++ } ++ } ++ } ++insert: ++ region = iommu_alloc_resv_region(new->start, new->length, ++ new->prot, new->type); ++ if (!region) ++ return -ENOMEM; ++ ++ list_add_tail(®ion->list, pos); ++done: ++ return 0; ++} ++ ++static int ++iommu_insert_device_resv_regions(struct list_head *dev_resv_regions, ++ struct list_head *group_resv_regions) ++{ ++ struct iommu_resv_region *entry; ++ int ret; ++ ++ list_for_each_entry(entry, dev_resv_regions, list) { ++ ret = iommu_insert_resv_region(entry, group_resv_regions); ++ if (ret) ++ break; ++ } ++ return ret; ++} ++ ++int iommu_get_group_resv_regions(struct iommu_group *group, ++ struct list_head *head) ++{ ++ struct iommu_device *device; ++ int ret = 0; ++ ++ mutex_lock(&group->mutex); ++ list_for_each_entry(device, &group->devices, list) { ++ struct list_head dev_resv_regions; ++ ++ INIT_LIST_HEAD(&dev_resv_regions); ++ iommu_get_resv_regions(device->dev, &dev_resv_regions); ++ ret = iommu_insert_device_resv_regions(&dev_resv_regions, head); ++ iommu_put_resv_regions(device->dev, &dev_resv_regions); ++ if (ret) ++ break; ++ } ++ mutex_unlock(&group->mutex); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(iommu_get_group_resv_regions); ++ ++static ssize_t iommu_group_show_resv_regions(struct iommu_group *group, ++ char *buf) ++{ ++ struct iommu_resv_region *region, *next; ++ struct list_head group_resv_regions; ++ char *str = buf; ++ ++ INIT_LIST_HEAD(&group_resv_regions); ++ iommu_get_group_resv_regions(group, &group_resv_regions); ++ ++ list_for_each_entry_safe(region, next, &group_resv_regions, list) { ++ str += sprintf(str, "0x%016llx 0x%016llx %s\n", ++ (long long int)region->start, ++ (long long int)(region->start + ++ region->length - 1), ++ iommu_group_resv_type_string[region->type]); ++ kfree(region); ++ } ++ ++ return (str - buf); ++} ++ + static IOMMU_GROUP_ATTR(name, S_IRUGO, iommu_group_show_name, NULL); + ++static IOMMU_GROUP_ATTR(reserved_regions, 0444, ++ iommu_group_show_resv_regions, NULL); ++ + static void iommu_group_release(struct kobject *kobj) + { + struct iommu_group *group = to_iommu_group(kobj); +@@ -212,6 +342,11 @@ struct iommu_group *iommu_group_alloc(void) + */ + kobject_put(&group->kobj); + ++ ret = iommu_group_create_file(group, ++ &iommu_group_attr_reserved_regions); ++ if (ret) ++ return ERR_PTR(ret); ++ + pr_debug("Allocated group %d\n", group->id); + + return group; +@@ -318,7 +453,7 @@ static int iommu_group_create_direct_mappings(struct iommu_group *group, + struct device *dev) + { + struct iommu_domain *domain = group->default_domain; +- struct iommu_dm_region *entry; ++ struct iommu_resv_region *entry; + struct list_head mappings; + unsigned long pg_size; + int ret = 0; +@@ -331,18 +466,21 @@ static int iommu_group_create_direct_mappings(struct iommu_group *group, + pg_size = 1UL << __ffs(domain->pgsize_bitmap); + INIT_LIST_HEAD(&mappings); + +- iommu_get_dm_regions(dev, &mappings); ++ iommu_get_resv_regions(dev, &mappings); + + /* We need to consider overlapping regions for different devices */ + list_for_each_entry(entry, &mappings, list) { + dma_addr_t start, end, addr; + +- if (domain->ops->apply_dm_region) +- domain->ops->apply_dm_region(dev, domain, entry); ++ if (domain->ops->apply_resv_region) ++ domain->ops->apply_resv_region(dev, domain, entry); + + start = ALIGN(entry->start, pg_size); + end = ALIGN(entry->start + entry->length, pg_size); + ++ if (entry->type != IOMMU_RESV_DIRECT) ++ continue; ++ + for (addr = start; addr < end; addr += pg_size) { + phys_addr_t phys_addr; + +@@ -358,7 +496,7 @@ static int iommu_group_create_direct_mappings(struct iommu_group *group, + } + + out: +- iommu_put_dm_regions(dev, &mappings); ++ iommu_put_resv_regions(dev, &mappings); + + return ret; + } +@@ -562,6 +700,19 @@ struct iommu_group *iommu_group_get(struct device *dev) + } + EXPORT_SYMBOL_GPL(iommu_group_get); + ++/** ++ * iommu_group_ref_get - Increment reference on a group ++ * @group: the group to use, must not be NULL ++ * ++ * This function is called by iommu drivers to take additional references on an ++ * existing group. Returns the given group for convenience. ++ */ ++struct iommu_group *iommu_group_ref_get(struct iommu_group *group) ++{ ++ kobject_get(group->devices_kobj); ++ return group; ++} ++ + /** + * iommu_group_put - Decrement group reference + * @group: the group to use +@@ -1557,20 +1708,38 @@ int iommu_domain_set_attr(struct iommu_domain *domain, + } + EXPORT_SYMBOL_GPL(iommu_domain_set_attr); + +-void iommu_get_dm_regions(struct device *dev, struct list_head *list) ++void iommu_get_resv_regions(struct device *dev, struct list_head *list) + { + const struct iommu_ops *ops = dev->bus->iommu_ops; + +- if (ops && ops->get_dm_regions) +- ops->get_dm_regions(dev, list); ++ if (ops && ops->get_resv_regions) ++ ops->get_resv_regions(dev, list); + } + +-void iommu_put_dm_regions(struct device *dev, struct list_head *list) ++void iommu_put_resv_regions(struct device *dev, struct list_head *list) + { + const struct iommu_ops *ops = dev->bus->iommu_ops; + +- if (ops && ops->put_dm_regions) +- ops->put_dm_regions(dev, list); ++ if (ops && ops->put_resv_regions) ++ ops->put_resv_regions(dev, list); ++} ++ ++struct iommu_resv_region *iommu_alloc_resv_region(phys_addr_t start, ++ size_t length, int prot, ++ enum iommu_resv_type type) ++{ ++ struct iommu_resv_region *region; ++ ++ region = kzalloc(sizeof(*region), GFP_KERNEL); ++ if (!region) ++ return NULL; ++ ++ INIT_LIST_HEAD(®ion->list); ++ region->start = start; ++ region->length = length; ++ region->prot = prot; ++ region->type = type; ++ return region; + } + + /* Request that a device is direct mapped by the IOMMU */ +diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c +index b12c12d7..9799daea 100644 +--- a/drivers/iommu/mtk_iommu.c ++++ b/drivers/iommu/mtk_iommu.c +@@ -410,6 +410,8 @@ static struct iommu_group *mtk_iommu_device_group(struct device *dev) + data->m4u_group = iommu_group_alloc(); + if (IS_ERR(data->m4u_group)) + dev_err(dev, "Failed to allocate M4U IOMMU group\n"); ++ } else { ++ iommu_group_ref_get(data->m4u_group); + } + return data->m4u_group; + } +diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c +index b8aeb076..c7063e9d 100644 +--- a/drivers/iommu/mtk_iommu_v1.c ++++ b/drivers/iommu/mtk_iommu_v1.c +@@ -502,6 +502,8 @@ static struct iommu_group *mtk_iommu_device_group(struct device *dev) + data->m4u_group = iommu_group_alloc(); + if (IS_ERR(data->m4u_group)) + dev_err(dev, "Failed to allocate M4U IOMMU group\n"); ++ } else { ++ iommu_group_ref_get(data->m4u_group); + } + return data->m4u_group; + } +diff --git a/include/linux/dma-iommu.h b/include/linux/dma-iommu.h +index 32c58906..36d3206d 100644 +--- a/include/linux/dma-iommu.h ++++ b/include/linux/dma-iommu.h +@@ -27,6 +27,7 @@ int iommu_dma_init(void); + + /* Domain management interface for IOMMU drivers */ + int iommu_get_dma_cookie(struct iommu_domain *domain); ++int iommu_get_msi_cookie(struct iommu_domain *domain, dma_addr_t base); + void iommu_put_dma_cookie(struct iommu_domain *domain); + + /* Setup call for arch DMA mapping code */ +@@ -66,6 +67,7 @@ int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr); + + /* The DMA API isn't _quite_ the whole story, though... */ + void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg); ++void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list); + + #else + +@@ -82,6 +84,11 @@ static inline int iommu_get_dma_cookie(struct iommu_domain *domain) + return -ENODEV; + } + ++static inline int iommu_get_msi_cookie(struct iommu_domain *domain, dma_addr_t base) ++{ ++ return -ENODEV; ++} ++ + static inline void iommu_put_dma_cookie(struct iommu_domain *domain) + { + } +@@ -90,6 +97,10 @@ static inline void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg) + { + } + ++static inline void iommu_dma_get_resv_regions(struct device *dev, struct list_head *list) ++{ ++} ++ + #endif /* CONFIG_IOMMU_DMA */ + #endif /* __KERNEL__ */ + #endif /* __DMA_IOMMU_H */ +diff --git a/include/linux/iommu.h b/include/linux/iommu.h +index 436dc213..188599f5 100644 +--- a/include/linux/iommu.h ++++ b/include/linux/iommu.h +@@ -117,18 +117,32 @@ enum iommu_attr { + DOMAIN_ATTR_MAX, + }; + ++/* These are the possible reserved region types */ ++enum iommu_resv_type { ++ /* Memory regions which must be mapped 1:1 at all times */ ++ IOMMU_RESV_DIRECT, ++ /* Arbitrary "never map this or give it to a device" address ranges */ ++ IOMMU_RESV_RESERVED, ++ /* Hardware MSI region (untranslated) */ ++ IOMMU_RESV_MSI, ++ /* Software-managed MSI translation window */ ++ IOMMU_RESV_SW_MSI, ++}; ++ + /** +- * struct iommu_dm_region - descriptor for a direct mapped memory region ++ * struct iommu_resv_region - descriptor for a reserved memory region + * @list: Linked list pointers + * @start: System physical start address of the region + * @length: Length of the region in bytes + * @prot: IOMMU Protection flags (READ/WRITE/...) ++ * @type: Type of the reserved region + */ +-struct iommu_dm_region { ++struct iommu_resv_region { + struct list_head list; + phys_addr_t start; + size_t length; + int prot; ++ enum iommu_resv_type type; + }; + + #ifdef CONFIG_IOMMU_API +@@ -150,9 +164,9 @@ struct iommu_dm_region { + * @device_group: find iommu group for a particular device + * @domain_get_attr: Query domain attributes + * @domain_set_attr: Change domain attributes +- * @get_dm_regions: Request list of direct mapping requirements for a device +- * @put_dm_regions: Free list of direct mapping requirements for a device +- * @apply_dm_region: Temporary helper call-back for iova reserved ranges ++ * @get_resv_regions: Request list of reserved regions for a device ++ * @put_resv_regions: Free list of reserved regions for a device ++ * @apply_resv_region: Temporary helper call-back for iova reserved ranges + * @domain_window_enable: Configure and enable a particular window for a domain + * @domain_window_disable: Disable a particular window for a domain + * @domain_set_windows: Set the number of windows for a domain +@@ -184,11 +198,12 @@ struct iommu_ops { + int (*domain_set_attr)(struct iommu_domain *domain, + enum iommu_attr attr, void *data); + +- /* Request/Free a list of direct mapping requirements for a device */ +- void (*get_dm_regions)(struct device *dev, struct list_head *list); +- void (*put_dm_regions)(struct device *dev, struct list_head *list); +- void (*apply_dm_region)(struct device *dev, struct iommu_domain *domain, +- struct iommu_dm_region *region); ++ /* Request/Free a list of reserved regions for a device */ ++ void (*get_resv_regions)(struct device *dev, struct list_head *list); ++ void (*put_resv_regions)(struct device *dev, struct list_head *list); ++ void (*apply_resv_region)(struct device *dev, ++ struct iommu_domain *domain, ++ struct iommu_resv_region *region); + + /* Window handling functions */ + int (*domain_window_enable)(struct iommu_domain *domain, u32 wnd_nr, +@@ -233,9 +248,14 @@ extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t io + extern void iommu_set_fault_handler(struct iommu_domain *domain, + iommu_fault_handler_t handler, void *token); + +-extern void iommu_get_dm_regions(struct device *dev, struct list_head *list); +-extern void iommu_put_dm_regions(struct device *dev, struct list_head *list); ++extern void iommu_get_resv_regions(struct device *dev, struct list_head *list); ++extern void iommu_put_resv_regions(struct device *dev, struct list_head *list); + extern int iommu_request_dm_for_dev(struct device *dev); ++extern struct iommu_resv_region * ++iommu_alloc_resv_region(phys_addr_t start, size_t length, int prot, ++ enum iommu_resv_type type); ++extern int iommu_get_group_resv_regions(struct iommu_group *group, ++ struct list_head *head); + + extern int iommu_attach_group(struct iommu_domain *domain, + struct iommu_group *group); +@@ -253,6 +273,7 @@ extern void iommu_group_remove_device(struct device *dev); + extern int iommu_group_for_each_dev(struct iommu_group *group, void *data, + int (*fn)(struct device *, void *)); + extern struct iommu_group *iommu_group_get(struct device *dev); ++extern struct iommu_group *iommu_group_ref_get(struct iommu_group *group); + extern void iommu_group_put(struct iommu_group *group); + extern int iommu_group_register_notifier(struct iommu_group *group, + struct notifier_block *nb); +@@ -439,16 +460,22 @@ static inline void iommu_set_fault_handler(struct iommu_domain *domain, + { + } + +-static inline void iommu_get_dm_regions(struct device *dev, ++static inline void iommu_get_resv_regions(struct device *dev, + struct list_head *list) + { + } + +-static inline void iommu_put_dm_regions(struct device *dev, ++static inline void iommu_put_resv_regions(struct device *dev, + struct list_head *list) + { + } + ++static inline int iommu_get_group_resv_regions(struct iommu_group *group, ++ struct list_head *head) ++{ ++ return -ENODEV; ++} ++ + static inline int iommu_request_dm_for_dev(struct device *dev) + { + return -ENODEV; +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/811-irqchip-support-layerscape.patch b/target/linux/layerscape/patches-4.9/811-irqchip-support-layerscape.patch new file mode 100644 index 0000000000..c10abfbf87 --- /dev/null +++ b/target/linux/layerscape/patches-4.9/811-irqchip-support-layerscape.patch @@ -0,0 +1,182 @@ +From 1d596855b596db88f10b12a1be6fd19e249be170 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 12:13:29 +0800 +Subject: [PATCH] irqchip: support layerscape + +This is a integrated patch for layerscape gic support. + +Signed-off-by: Eric Auger +Signed-off-by: Zhao Qiang +Signed-off-by: Yangbo Lu +--- + drivers/irqchip/Makefile | 1 + + drivers/irqchip/irq-gic-v3-its.c | 1 + + include/linux/irqdomain.h | 36 ++++++++++++++++++++++++++++++++++++ + kernel/irq/irqdomain.c | 39 +++++++++++++++++++++++++++++++++++++++ + kernel/irq/msi.c | 4 ++-- + 5 files changed, 79 insertions(+), 2 deletions(-) + +diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile +index e4dbfc85..53d2cd54 100644 +--- a/drivers/irqchip/Makefile ++++ b/drivers/irqchip/Makefile +@@ -74,3 +74,4 @@ obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o + obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o + obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o + obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o ++obj-$(CONFIG_QUICC_ENGINE) += irq-qeic.o +diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c +index acb9d250..2f1c8826 100644 +--- a/drivers/irqchip/irq-gic-v3-its.c ++++ b/drivers/irqchip/irq-gic-v3-its.c +@@ -1659,6 +1659,7 @@ static int its_init_domain(struct fwnode_handle *handle, struct its_node *its) + + inner_domain->parent = its_parent; + inner_domain->bus_token = DOMAIN_BUS_NEXUS; ++ inner_domain->flags |= IRQ_DOMAIN_FLAG_MSI_REMAP; + info->ops = &its_msi_domain_ops; + info->data = its; + inner_domain->host_data = info; +diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h +index ffb84604..188eced6 100644 +--- a/include/linux/irqdomain.h ++++ b/include/linux/irqdomain.h +@@ -183,6 +183,12 @@ enum { + /* Irq domain is an IPI domain with single virq */ + IRQ_DOMAIN_FLAG_IPI_SINGLE = (1 << 3), + ++ /* Irq domain implements MSIs */ ++ IRQ_DOMAIN_FLAG_MSI = (1 << 4), ++ ++ /* Irq domain implements MSI remapping */ ++ IRQ_DOMAIN_FLAG_MSI_REMAP = (1 << 5), ++ + /* + * Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved + * for implementation specific purposes and ignored by the +@@ -216,6 +222,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, + void *host_data); + extern struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec, + enum irq_domain_bus_token bus_token); ++extern bool irq_domain_check_msi_remap(void); + extern void irq_set_default_host(struct irq_domain *host); + extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs, + irq_hw_number_t hwirq, int node, +@@ -446,6 +453,19 @@ static inline bool irq_domain_is_ipi_single(struct irq_domain *domain) + { + return domain->flags & IRQ_DOMAIN_FLAG_IPI_SINGLE; + } ++ ++static inline bool irq_domain_is_msi(struct irq_domain *domain) ++{ ++ return domain->flags & IRQ_DOMAIN_FLAG_MSI; ++} ++ ++static inline bool irq_domain_is_msi_remap(struct irq_domain *domain) ++{ ++ return domain->flags & IRQ_DOMAIN_FLAG_MSI_REMAP; ++} ++ ++extern bool irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain); ++ + #else /* CONFIG_IRQ_DOMAIN_HIERARCHY */ + static inline void irq_domain_activate_irq(struct irq_data *data) { } + static inline void irq_domain_deactivate_irq(struct irq_data *data) { } +@@ -477,6 +497,22 @@ static inline bool irq_domain_is_ipi_single(struct irq_domain *domain) + { + return false; + } ++ ++static inline bool irq_domain_is_msi(struct irq_domain *domain) ++{ ++ return false; ++} ++ ++static inline bool irq_domain_is_msi_remap(struct irq_domain *domain) ++{ ++ return false; ++} ++ ++static inline bool ++irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain) ++{ ++ return false; ++} + #endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */ + + #else /* CONFIG_IRQ_DOMAIN */ +diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c +index b59e6768..31805f23 100644 +--- a/kernel/irq/irqdomain.c ++++ b/kernel/irq/irqdomain.c +@@ -277,6 +277,31 @@ struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec, + } + EXPORT_SYMBOL_GPL(irq_find_matching_fwspec); + ++/** ++ * irq_domain_check_msi_remap - Check whether all MSI irq domains implement ++ * IRQ remapping ++ * ++ * Return: false if any MSI irq domain does not support IRQ remapping, ++ * true otherwise (including if there is no MSI irq domain) ++ */ ++bool irq_domain_check_msi_remap(void) ++{ ++ struct irq_domain *h; ++ bool ret = true; ++ ++ mutex_lock(&irq_domain_mutex); ++ list_for_each_entry(h, &irq_domain_list, link) { ++ if (irq_domain_is_msi(h) && ++ !irq_domain_hierarchical_is_msi_remap(h)) { ++ ret = false; ++ break; ++ } ++ } ++ mutex_unlock(&irq_domain_mutex); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(irq_domain_check_msi_remap); ++ + /** + * irq_set_default_host() - Set a "default" irq domain + * @domain: default domain pointer +@@ -1408,6 +1433,20 @@ static void irq_domain_check_hierarchy(struct irq_domain *domain) + if (domain->ops->alloc) + domain->flags |= IRQ_DOMAIN_FLAG_HIERARCHY; + } ++ ++/** ++ * irq_domain_hierarchical_is_msi_remap - Check if the domain or any ++ * parent has MSI remapping support ++ * @domain: domain pointer ++ */ ++bool irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain) ++{ ++ for (; domain; domain = domain->parent) { ++ if (irq_domain_is_msi_remap(domain)) ++ return true; ++ } ++ return false; ++} + #else /* CONFIG_IRQ_DOMAIN_HIERARCHY */ + /** + * irq_domain_get_irq_data - Get irq_data associated with @virq and @domain +diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c +index 8a3e8727..2e2b2c45 100644 +--- a/kernel/irq/msi.c ++++ b/kernel/irq/msi.c +@@ -272,8 +272,8 @@ struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode, + if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS) + msi_domain_update_chip_ops(info); + +- return irq_domain_create_hierarchy(parent, 0, 0, fwnode, +- &msi_domain_ops, info); ++ return irq_domain_create_hierarchy(parent, IRQ_DOMAIN_FLAG_MSI, 0, ++ fwnode, &msi_domain_ops, info); + } + + int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev, +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/812-mmc-layerscape-support.patch b/target/linux/layerscape/patches-4.9/812-mmc-layerscape-support.patch new file mode 100644 index 0000000000..ff19a6da03 --- /dev/null +++ b/target/linux/layerscape/patches-4.9/812-mmc-layerscape-support.patch @@ -0,0 +1,611 @@ +From b31046c51c72232363711f0c623df08bf28c37e4 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 12:21:30 +0800 +Subject: [PATCH] mmc: layerscape support + +This is a integrated patch for layerscape mmc support. + +Adrian Hunter +Jaehoon Chung +Masahiro Yamada +Signed-off-by: Yangbo Lu +--- + drivers/mmc/host/Kconfig | 1 + + drivers/mmc/host/sdhci-esdhc.h | 52 +++++--- + drivers/mmc/host/sdhci-of-esdhc.c | 251 ++++++++++++++++++++++++++++++++++++-- + drivers/mmc/host/sdhci.c | 45 ++++--- + drivers/mmc/host/sdhci.h | 3 + + 5 files changed, 306 insertions(+), 46 deletions(-) + +diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig +index 5274f503..a1135a92 100644 +--- a/drivers/mmc/host/Kconfig ++++ b/drivers/mmc/host/Kconfig +@@ -144,6 +144,7 @@ config MMC_SDHCI_OF_ESDHC + depends on MMC_SDHCI_PLTFM + depends on PPC || ARCH_MXC || ARCH_LAYERSCAPE + select MMC_SDHCI_IO_ACCESSORS ++ select FSL_GUTS + help + This selects the Freescale eSDHC controller support. + +diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h +index de132e28..98898a30 100644 +--- a/drivers/mmc/host/sdhci-esdhc.h ++++ b/drivers/mmc/host/sdhci-esdhc.h +@@ -24,30 +24,46 @@ + SDHCI_QUIRK_PIO_NEEDS_DELAY | \ + SDHCI_QUIRK_NO_HISPD_BIT) + +-#define ESDHC_PROCTL 0x28 +- +-#define ESDHC_SYSTEM_CONTROL 0x2c +-#define ESDHC_CLOCK_MASK 0x0000fff0 +-#define ESDHC_PREDIV_SHIFT 8 +-#define ESDHC_DIVIDER_SHIFT 4 +-#define ESDHC_CLOCK_PEREN 0x00000004 +-#define ESDHC_CLOCK_HCKEN 0x00000002 +-#define ESDHC_CLOCK_IPGEN 0x00000001 +- + /* pltfm-specific */ + #define ESDHC_HOST_CONTROL_LE 0x20 + + /* +- * P2020 interpretation of the SDHCI_HOST_CONTROL register ++ * eSDHC register definition + */ +-#define ESDHC_CTRL_4BITBUS (0x1 << 1) +-#define ESDHC_CTRL_8BITBUS (0x2 << 1) +-#define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1) + +-/* OF-specific */ +-#define ESDHC_DMA_SYSCTL 0x40c +-#define ESDHC_DMA_SNOOP 0x00000040 ++/* Present State Register */ ++#define ESDHC_PRSSTAT 0x24 ++#define ESDHC_CLOCK_STABLE 0x00000008 ++ ++/* Protocol Control Register */ ++#define ESDHC_PROCTL 0x28 ++#define ESDHC_VOLT_SEL 0x00000400 ++#define ESDHC_CTRL_4BITBUS (0x1 << 1) ++#define ESDHC_CTRL_8BITBUS (0x2 << 1) ++#define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1) ++#define ESDHC_HOST_CONTROL_RES 0x01 ++ ++/* System Control Register */ ++#define ESDHC_SYSTEM_CONTROL 0x2c ++#define ESDHC_CLOCK_MASK 0x0000fff0 ++#define ESDHC_PREDIV_SHIFT 8 ++#define ESDHC_DIVIDER_SHIFT 4 ++#define ESDHC_CLOCK_SDCLKEN 0x00000008 ++#define ESDHC_CLOCK_PEREN 0x00000004 ++#define ESDHC_CLOCK_HCKEN 0x00000002 ++#define ESDHC_CLOCK_IPGEN 0x00000001 ++ ++/* Host Controller Capabilities Register 2 */ ++#define ESDHC_CAPABILITIES_1 0x114 ++ ++/* Tuning Block Control Register */ ++#define ESDHC_TBCTL 0x120 ++#define ESDHC_TB_EN 0x00000004 + +-#define ESDHC_HOST_CONTROL_RES 0x01 ++/* Control Register for DMA transfer */ ++#define ESDHC_DMA_SYSCTL 0x40c ++#define ESDHC_PERIPHERAL_CLK_SEL 0x00080000 ++#define ESDHC_FLUSH_ASYNC_FIFO 0x00040000 ++#define ESDHC_DMA_SNOOP 0x00000040 + + #endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */ +diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c +index 3c27401c..4b0f375b 100644 +--- a/drivers/mmc/host/sdhci-of-esdhc.c ++++ b/drivers/mmc/host/sdhci-of-esdhc.c +@@ -16,8 +16,12 @@ + #include + #include + #include ++#include + #include + #include ++#include ++#include ++#include + #include + #include "sdhci-pltfm.h" + #include "sdhci-esdhc.h" +@@ -28,8 +32,12 @@ + struct sdhci_esdhc { + u8 vendor_ver; + u8 spec_ver; ++ bool quirk_incorrect_hostver; ++ unsigned int peripheral_clock; + }; + ++static void esdhc_clock_enable(struct sdhci_host *host, bool enable); ++ + /** + * esdhc_read*_fixup - Fixup the value read from incompatible eSDHC register + * to make it compatible with SD spec. +@@ -80,6 +88,17 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host, + return ret; + } + ++ /* ++ * DTS properties of mmc host are used to enable each speed mode ++ * according to soc and board capability. So clean up ++ * SDR50/SDR104/DDR50 support bits here. ++ */ ++ if (spec_reg == SDHCI_CAPABILITIES_1) { ++ ret = value & (~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 | ++ SDHCI_SUPPORT_DDR50)); ++ return ret; ++ } ++ + ret = value; + return ret; + } +@@ -87,6 +106,8 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host, + static u16 esdhc_readw_fixup(struct sdhci_host *host, + int spec_reg, u32 value) + { ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); + u16 ret; + int shift = (spec_reg & 0x2) * 8; + +@@ -94,6 +115,12 @@ static u16 esdhc_readw_fixup(struct sdhci_host *host, + ret = value & 0xffff; + else + ret = (value >> shift) & 0xffff; ++ /* Workaround for T4240-R1.0-R2.0 eSDHC which has incorrect ++ * vendor version and spec version information. ++ */ ++ if ((spec_reg == SDHCI_HOST_VERSION) && ++ (esdhc->quirk_incorrect_hostver)) ++ ret = (VENDOR_V_23 << SDHCI_VENDOR_VER_SHIFT) | SDHCI_SPEC_200; + return ret; + } + +@@ -235,7 +262,11 @@ static u32 esdhc_be_readl(struct sdhci_host *host, int reg) + u32 ret; + u32 value; + +- value = ioread32be(host->ioaddr + reg); ++ if (reg == SDHCI_CAPABILITIES_1) ++ value = ioread32be(host->ioaddr + ESDHC_CAPABILITIES_1); ++ else ++ value = ioread32be(host->ioaddr + reg); ++ + ret = esdhc_readl_fixup(host, reg, value); + + return ret; +@@ -246,7 +277,11 @@ static u32 esdhc_le_readl(struct sdhci_host *host, int reg) + u32 ret; + u32 value; + +- value = ioread32(host->ioaddr + reg); ++ if (reg == SDHCI_CAPABILITIES_1) ++ value = ioread32(host->ioaddr + ESDHC_CAPABILITIES_1); ++ else ++ value = ioread32(host->ioaddr + reg); ++ + ret = esdhc_readl_fixup(host, reg, value); + + return ret; +@@ -404,15 +439,25 @@ static int esdhc_of_enable_dma(struct sdhci_host *host) + static unsigned int esdhc_of_get_max_clock(struct sdhci_host *host) + { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); + +- return pltfm_host->clock; ++ if (esdhc->peripheral_clock) ++ return esdhc->peripheral_clock; ++ else ++ return pltfm_host->clock; + } + + static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host) + { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); ++ unsigned int clock; + +- return pltfm_host->clock / 256 / 16; ++ if (esdhc->peripheral_clock) ++ clock = esdhc->peripheral_clock; ++ else ++ clock = pltfm_host->clock; ++ return clock / 256 / 16; + } + + static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) +@@ -421,17 +466,34 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); + int pre_div = 1; + int div = 1; ++ ktime_t timeout; + u32 temp; + + host->mmc->actual_clock = 0; + +- if (clock == 0) ++ if (clock == 0) { ++ esdhc_clock_enable(host, false); + return; ++ } + + /* Workaround to start pre_div at 2 for VNN < VENDOR_V_23 */ + if (esdhc->vendor_ver < VENDOR_V_23) + pre_div = 2; + ++ /* ++ * Limit SD clock to 167MHz for ls1046a according to its datasheet ++ */ ++ if (clock > 167000000 && ++ of_find_compatible_node(NULL, NULL, "fsl,ls1046a-esdhc")) ++ clock = 167000000; ++ ++ /* ++ * Limit SD clock to 125MHz for ls1012a according to its datasheet ++ */ ++ if (clock > 125000000 && ++ of_find_compatible_node(NULL, NULL, "fsl,ls1012a-esdhc")) ++ clock = 125000000; ++ + /* Workaround to reduce the clock frequency for p1010 esdhc */ + if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) { + if (clock > 20000000) +@@ -441,8 +503,8 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) + } + + temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); +- temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN +- | ESDHC_CLOCK_MASK); ++ temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ++ ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK); + sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); + + while (host->max_clk / pre_div / 16 > clock && pre_div < 256) +@@ -462,7 +524,20 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) + | (div << ESDHC_DIVIDER_SHIFT) + | (pre_div << ESDHC_PREDIV_SHIFT)); + sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); +- mdelay(1); ++ ++ /* Wait max 20 ms */ ++ timeout = ktime_add_ms(ktime_get(), 20); ++ while (!(sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)) { ++ if (ktime_after(ktime_get(), timeout)) { ++ pr_err("%s: Internal clock never stabilised.\n", ++ mmc_hostname(host->mmc)); ++ return; ++ } ++ udelay(10); ++ } ++ ++ temp |= ESDHC_CLOCK_SDCLKEN; ++ sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); + } + + static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) +@@ -487,6 +562,33 @@ static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width) + sdhci_writel(host, ctrl, ESDHC_PROCTL); + } + ++static void esdhc_clock_enable(struct sdhci_host *host, bool enable) ++{ ++ u32 val; ++ ktime_t timeout; ++ ++ val = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); ++ ++ if (enable) ++ val |= ESDHC_CLOCK_SDCLKEN; ++ else ++ val &= ~ESDHC_CLOCK_SDCLKEN; ++ ++ sdhci_writel(host, val, ESDHC_SYSTEM_CONTROL); ++ ++ /* Wait max 20 ms */ ++ timeout = ktime_add_ms(ktime_get(), 20); ++ val = ESDHC_CLOCK_STABLE; ++ while (!(sdhci_readl(host, ESDHC_PRSSTAT) & val)) { ++ if (ktime_after(ktime_get(), timeout)) { ++ pr_err("%s: Internal clock never stabilised.\n", ++ mmc_hostname(host->mmc)); ++ break; ++ } ++ udelay(10); ++ } ++} ++ + static void esdhc_reset(struct sdhci_host *host, u8 mask) + { + sdhci_reset(host, mask); +@@ -495,6 +597,95 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask) + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + } + ++/* The SCFG, Supplemental Configuration Unit, provides SoC specific ++ * configuration and status registers for the device. There is a ++ * SDHC IO VSEL control register on SCFG for some platforms. It's ++ * used to support SDHC IO voltage switching. ++ */ ++static const struct of_device_id scfg_device_ids[] = { ++ { .compatible = "fsl,t1040-scfg", }, ++ { .compatible = "fsl,ls1012a-scfg", }, ++ { .compatible = "fsl,ls1046a-scfg", }, ++ {} ++}; ++ ++/* SDHC IO VSEL control register definition */ ++#define SCFG_SDHCIOVSELCR 0x408 ++#define SDHCIOVSELCR_TGLEN 0x80000000 ++#define SDHCIOVSELCR_VSELVAL 0x60000000 ++#define SDHCIOVSELCR_SDHC_VS 0x00000001 ++ ++static int esdhc_signal_voltage_switch(struct mmc_host *mmc, ++ struct mmc_ios *ios) ++{ ++ struct sdhci_host *host = mmc_priv(mmc); ++ struct device_node *scfg_node; ++ void __iomem *scfg_base = NULL; ++ u32 sdhciovselcr; ++ u32 val; ++ ++ /* ++ * Signal Voltage Switching is only applicable for Host Controllers ++ * v3.00 and above. ++ */ ++ if (host->version < SDHCI_SPEC_300) ++ return 0; ++ ++ val = sdhci_readl(host, ESDHC_PROCTL); ++ ++ switch (ios->signal_voltage) { ++ case MMC_SIGNAL_VOLTAGE_330: ++ val &= ~ESDHC_VOLT_SEL; ++ sdhci_writel(host, val, ESDHC_PROCTL); ++ return 0; ++ case MMC_SIGNAL_VOLTAGE_180: ++ scfg_node = of_find_matching_node(NULL, scfg_device_ids); ++ if (scfg_node) ++ scfg_base = of_iomap(scfg_node, 0); ++ if (scfg_base) { ++ sdhciovselcr = SDHCIOVSELCR_TGLEN | ++ SDHCIOVSELCR_VSELVAL; ++ iowrite32be(sdhciovselcr, ++ scfg_base + SCFG_SDHCIOVSELCR); ++ ++ val |= ESDHC_VOLT_SEL; ++ sdhci_writel(host, val, ESDHC_PROCTL); ++ mdelay(5); ++ ++ sdhciovselcr = SDHCIOVSELCR_TGLEN | ++ SDHCIOVSELCR_SDHC_VS; ++ iowrite32be(sdhciovselcr, ++ scfg_base + SCFG_SDHCIOVSELCR); ++ iounmap(scfg_base); ++ } else { ++ val |= ESDHC_VOLT_SEL; ++ sdhci_writel(host, val, ESDHC_PROCTL); ++ } ++ return 0; ++ default: ++ return 0; ++ } ++} ++ ++static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) ++{ ++ struct sdhci_host *host = mmc_priv(mmc); ++ u32 val; ++ ++ /* Use tuning block for tuning procedure */ ++ esdhc_clock_enable(host, false); ++ val = sdhci_readl(host, ESDHC_DMA_SYSCTL); ++ val |= ESDHC_FLUSH_ASYNC_FIFO; ++ sdhci_writel(host, val, ESDHC_DMA_SYSCTL); ++ ++ val = sdhci_readl(host, ESDHC_TBCTL); ++ val |= ESDHC_TB_EN; ++ sdhci_writel(host, val, ESDHC_TBCTL); ++ esdhc_clock_enable(host, true); ++ ++ return sdhci_execute_tuning(mmc, opcode); ++} ++ + #ifdef CONFIG_PM_SLEEP + static u32 esdhc_proctl; + static int esdhc_of_suspend(struct device *dev) +@@ -575,10 +766,19 @@ static const struct sdhci_pltfm_data sdhci_esdhc_le_pdata = { + .ops = &sdhci_esdhc_le_ops, + }; + ++static struct soc_device_attribute soc_incorrect_hostver[] = { ++ { .family = "QorIQ T4240", .revision = "1.0", }, ++ { .family = "QorIQ T4240", .revision = "2.0", }, ++ { }, ++}; ++ + static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) + { + struct sdhci_pltfm_host *pltfm_host; + struct sdhci_esdhc *esdhc; ++ struct device_node *np; ++ struct clk *clk; ++ u32 val; + u16 host_ver; + + pltfm_host = sdhci_priv(host); +@@ -588,6 +788,36 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) + esdhc->vendor_ver = (host_ver & SDHCI_VENDOR_VER_MASK) >> + SDHCI_VENDOR_VER_SHIFT; + esdhc->spec_ver = host_ver & SDHCI_SPEC_VER_MASK; ++ if (soc_device_match(soc_incorrect_hostver)) ++ esdhc->quirk_incorrect_hostver = true; ++ else ++ esdhc->quirk_incorrect_hostver = false; ++ ++ np = pdev->dev.of_node; ++ clk = of_clk_get(np, 0); ++ if (!IS_ERR(clk)) { ++ /* ++ * esdhc->peripheral_clock would be assigned with a value ++ * which is eSDHC base clock when use periperal clock. ++ * For ls1046a, the clock value got by common clk API is ++ * peripheral clock while the eSDHC base clock is 1/2 ++ * peripheral clock. ++ */ ++ if (of_device_is_compatible(np, "fsl,ls1046a-esdhc")) ++ esdhc->peripheral_clock = clk_get_rate(clk) / 2; ++ else ++ esdhc->peripheral_clock = clk_get_rate(clk); ++ ++ clk_put(clk); ++ } ++ ++ if (esdhc->peripheral_clock) { ++ esdhc_clock_enable(host, false); ++ val = sdhci_readl(host, ESDHC_DMA_SYSCTL); ++ val |= ESDHC_PERIPHERAL_CLK_SEL; ++ sdhci_writel(host, val, ESDHC_DMA_SYSCTL); ++ esdhc_clock_enable(host, true); ++ } + } + + static int sdhci_esdhc_probe(struct platform_device *pdev) +@@ -610,6 +840,11 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) + if (IS_ERR(host)) + return PTR_ERR(host); + ++ host->mmc_host_ops.start_signal_voltage_switch = ++ esdhc_signal_voltage_switch; ++ host->mmc_host_ops.execute_tuning = esdhc_execute_tuning; ++ host->tuning_delay = 1; ++ + esdhc_init(pdev, host); + + sdhci_get_of_property(pdev); +diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c +index 7d275e72..099c3bf5 100644 +--- a/drivers/mmc/host/sdhci.c ++++ b/drivers/mmc/host/sdhci.c +@@ -1624,26 +1624,24 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + + ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); + +- if ((ios->timing == MMC_TIMING_SD_HS || +- ios->timing == MMC_TIMING_MMC_HS) +- && !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) +- ctrl |= SDHCI_CTRL_HISPD; +- else +- ctrl &= ~SDHCI_CTRL_HISPD; ++ if (!(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) { ++ if ((ios->timing == MMC_TIMING_SD_HS || ++ ios->timing == MMC_TIMING_MMC_HS || ++ ios->timing == MMC_TIMING_MMC_HS400 || ++ ios->timing == MMC_TIMING_MMC_HS200 || ++ ios->timing == MMC_TIMING_MMC_DDR52 || ++ ios->timing == MMC_TIMING_UHS_SDR50 || ++ ios->timing == MMC_TIMING_UHS_SDR104 || ++ ios->timing == MMC_TIMING_UHS_DDR50 || ++ ios->timing == MMC_TIMING_UHS_SDR25)) ++ ctrl |= SDHCI_CTRL_HISPD; ++ else ++ ctrl &= ~SDHCI_CTRL_HISPD; ++ } + + if (host->version >= SDHCI_SPEC_300) { + u16 clk, ctrl_2; + +- /* In case of UHS-I modes, set High Speed Enable */ +- if ((ios->timing == MMC_TIMING_MMC_HS400) || +- (ios->timing == MMC_TIMING_MMC_HS200) || +- (ios->timing == MMC_TIMING_MMC_DDR52) || +- (ios->timing == MMC_TIMING_UHS_SDR50) || +- (ios->timing == MMC_TIMING_UHS_SDR104) || +- (ios->timing == MMC_TIMING_UHS_DDR50) || +- (ios->timing == MMC_TIMING_UHS_SDR25)) +- ctrl |= SDHCI_CTRL_HISPD; +- + if (!host->preset_enabled) { + sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); + /* +@@ -1956,7 +1954,7 @@ static int sdhci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios) + return 0; + } + +-static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) ++int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) + { + struct sdhci_host *host = mmc_priv(mmc); + u16 ctrl; +@@ -2015,6 +2013,9 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) + return err; + } + ++ if (host->tuning_delay < 0) ++ host->tuning_delay = opcode == MMC_SEND_TUNING_BLOCK; ++ + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); + ctrl |= SDHCI_CTRL_EXEC_TUNING; + if (host->quirks2 & SDHCI_QUIRK2_TUNING_WORK_AROUND) +@@ -2127,9 +2128,10 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) + + ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); + +- /* eMMC spec does not require a delay between tuning cycles */ +- if (opcode == MMC_SEND_TUNING_BLOCK) +- mdelay(1); ++ /* Spec does not require a delay between tuning cycles */ ++ if (host->tuning_delay > 0) ++ mdelay(host->tuning_delay); ++ + } while (ctrl & SDHCI_CTRL_EXEC_TUNING); + + /* +@@ -2165,6 +2167,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) + spin_unlock_irqrestore(&host->lock, flags); + return err; + } ++EXPORT_SYMBOL_GPL(sdhci_execute_tuning); + + static int sdhci_select_drive_strength(struct mmc_card *card, + unsigned int max_dtr, int host_drv, +@@ -2997,6 +3000,8 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev, + + host->flags = SDHCI_SIGNALING_330; + ++ host->tuning_delay = -1; ++ + return host; + } + +diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h +index 2570455b..088bed43 100644 +--- a/drivers/mmc/host/sdhci.h ++++ b/drivers/mmc/host/sdhci.h +@@ -524,6 +524,8 @@ struct sdhci_host { + #define SDHCI_TUNING_MODE_1 0 + #define SDHCI_TUNING_MODE_2 1 + #define SDHCI_TUNING_MODE_3 2 ++ /* Delay (ms) between tuning commands */ ++ int tuning_delay; + + unsigned long private[0] ____cacheline_aligned; + }; +@@ -689,6 +691,7 @@ void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, + void sdhci_set_bus_width(struct sdhci_host *host, int width); + void sdhci_reset(struct sdhci_host *host, u8 mask); + void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing); ++int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); + + #ifdef CONFIG_PM + extern int sdhci_suspend_host(struct sdhci_host *host); +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/813-qe-support-layerscape.patch b/target/linux/layerscape/patches-4.9/813-qe-support-layerscape.patch new file mode 100644 index 0000000000..ad5dd28d63 --- /dev/null +++ b/target/linux/layerscape/patches-4.9/813-qe-support-layerscape.patch @@ -0,0 +1,1378 @@ +From adb377019768396f339010ebb9e80fa8384992f7 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 12:20:30 +0800 +Subject: [PATCH] qe: support layerscape + +This is a integrated patch for layerscape qe support. + +Signed-off-by: Zhao Qiang +Signed-off-by: Yangbo Lu +--- + drivers/{soc/fsl/qe/qe_ic.c => irqchip/irq-qeic.c} | 389 +++++++++++++-------- + drivers/net/wan/fsl_ucc_hdlc.c | 4 +- + drivers/soc/fsl/qe/Kconfig | 2 +- + drivers/soc/fsl/qe/Makefile | 2 +- + drivers/soc/fsl/qe/qe.c | 80 +++-- + drivers/soc/fsl/qe/qe_ic.h | 103 ------ + drivers/soc/fsl/qe/qe_io.c | 42 +-- + drivers/soc/fsl/qe/qe_tdm.c | 8 +- + drivers/soc/fsl/qe/ucc.c | 10 +- + drivers/soc/fsl/qe/ucc_fast.c | 74 ++-- + drivers/tty/serial/ucc_uart.c | 1 + + include/soc/fsl/qe/qe.h | 1 - + include/soc/fsl/qe/qe_ic.h | 139 -------- + 13 files changed, 359 insertions(+), 496 deletions(-) + rename drivers/{soc/fsl/qe/qe_ic.c => irqchip/irq-qeic.c} (54%) + delete mode 100644 drivers/soc/fsl/qe/qe_ic.h + delete mode 100644 include/soc/fsl/qe/qe_ic.h + +diff --git a/drivers/soc/fsl/qe/qe_ic.c b/drivers/irqchip/irq-qeic.c +similarity index 54% +rename from drivers/soc/fsl/qe/qe_ic.c +rename to drivers/irqchip/irq-qeic.c +index ec2ca864..21e3b43c 100644 +--- a/drivers/soc/fsl/qe/qe_ic.c ++++ b/drivers/irqchip/irq-qeic.c +@@ -1,7 +1,7 @@ + /* +- * arch/powerpc/sysdev/qe_lib/qe_ic.c ++ * drivers/irqchip/irq-qeic.c + * +- * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved. ++ * Copyright (C) 2016 Freescale Semiconductor, Inc. All rights reserved. + * + * Author: Li Yang + * Based on code from Shlomi Gridish +@@ -18,7 +18,11 @@ + #include + #include + #include ++#include ++#include + #include ++#include ++#include + #include + #include + #include +@@ -26,11 +30,136 @@ + #include + #include + #include +-#include ++#include + #include +-#include + +-#include "qe_ic.h" ++#define NR_QE_IC_INTS 64 ++ ++/* QE IC registers offset */ ++#define QEIC_CICR 0x00 ++#define QEIC_CIVEC 0x04 ++#define QEIC_CRIPNR 0x08 ++#define QEIC_CIPNR 0x0c ++#define QEIC_CIPXCC 0x10 ++#define QEIC_CIPYCC 0x14 ++#define QEIC_CIPWCC 0x18 ++#define QEIC_CIPZCC 0x1c ++#define QEIC_CIMR 0x20 ++#define QEIC_CRIMR 0x24 ++#define QEIC_CICNR 0x28 ++#define QEIC_CIPRTA 0x30 ++#define QEIC_CIPRTB 0x34 ++#define QEIC_CRICR 0x3c ++#define QEIC_CHIVEC 0x60 ++ ++/* Interrupt priority registers */ ++#define CIPCC_SHIFT_PRI0 29 ++#define CIPCC_SHIFT_PRI1 26 ++#define CIPCC_SHIFT_PRI2 23 ++#define CIPCC_SHIFT_PRI3 20 ++#define CIPCC_SHIFT_PRI4 13 ++#define CIPCC_SHIFT_PRI5 10 ++#define CIPCC_SHIFT_PRI6 7 ++#define CIPCC_SHIFT_PRI7 4 ++ ++/* CICR priority modes */ ++#define CICR_GWCC 0x00040000 ++#define CICR_GXCC 0x00020000 ++#define CICR_GYCC 0x00010000 ++#define CICR_GZCC 0x00080000 ++#define CICR_GRTA 0x00200000 ++#define CICR_GRTB 0x00400000 ++#define CICR_HPIT_SHIFT 8 ++#define CICR_HPIT_MASK 0x00000300 ++#define CICR_HP_SHIFT 24 ++#define CICR_HP_MASK 0x3f000000 ++ ++/* CICNR */ ++#define CICNR_WCC1T_SHIFT 20 ++#define CICNR_ZCC1T_SHIFT 28 ++#define CICNR_YCC1T_SHIFT 12 ++#define CICNR_XCC1T_SHIFT 4 ++ ++/* CRICR */ ++#define CRICR_RTA1T_SHIFT 20 ++#define CRICR_RTB1T_SHIFT 28 ++ ++/* Signal indicator */ ++#define SIGNAL_MASK 3 ++#define SIGNAL_HIGH 2 ++#define SIGNAL_LOW 0 ++ ++#define NUM_OF_QE_IC_GROUPS 6 ++ ++/* Flags when we init the QE IC */ ++#define QE_IC_SPREADMODE_GRP_W 0x00000001 ++#define QE_IC_SPREADMODE_GRP_X 0x00000002 ++#define QE_IC_SPREADMODE_GRP_Y 0x00000004 ++#define QE_IC_SPREADMODE_GRP_Z 0x00000008 ++#define QE_IC_SPREADMODE_GRP_RISCA 0x00000010 ++#define QE_IC_SPREADMODE_GRP_RISCB 0x00000020 ++ ++#define QE_IC_LOW_SIGNAL 0x00000100 ++#define QE_IC_HIGH_SIGNAL 0x00000200 ++ ++#define QE_IC_GRP_W_PRI0_DEST_SIGNAL_HIGH 0x00001000 ++#define QE_IC_GRP_W_PRI1_DEST_SIGNAL_HIGH 0x00002000 ++#define QE_IC_GRP_X_PRI0_DEST_SIGNAL_HIGH 0x00004000 ++#define QE_IC_GRP_X_PRI1_DEST_SIGNAL_HIGH 0x00008000 ++#define QE_IC_GRP_Y_PRI0_DEST_SIGNAL_HIGH 0x00010000 ++#define QE_IC_GRP_Y_PRI1_DEST_SIGNAL_HIGH 0x00020000 ++#define QE_IC_GRP_Z_PRI0_DEST_SIGNAL_HIGH 0x00040000 ++#define QE_IC_GRP_Z_PRI1_DEST_SIGNAL_HIGH 0x00080000 ++#define QE_IC_GRP_RISCA_PRI0_DEST_SIGNAL_HIGH 0x00100000 ++#define QE_IC_GRP_RISCA_PRI1_DEST_SIGNAL_HIGH 0x00200000 ++#define QE_IC_GRP_RISCB_PRI0_DEST_SIGNAL_HIGH 0x00400000 ++#define QE_IC_GRP_RISCB_PRI1_DEST_SIGNAL_HIGH 0x00800000 ++#define QE_IC_GRP_W_DEST_SIGNAL_SHIFT (12) ++ ++/* QE interrupt sources groups */ ++enum qe_ic_grp_id { ++ QE_IC_GRP_W = 0, /* QE interrupt controller group W */ ++ QE_IC_GRP_X, /* QE interrupt controller group X */ ++ QE_IC_GRP_Y, /* QE interrupt controller group Y */ ++ QE_IC_GRP_Z, /* QE interrupt controller group Z */ ++ QE_IC_GRP_RISCA, /* QE interrupt controller RISC group A */ ++ QE_IC_GRP_RISCB /* QE interrupt controller RISC group B */ ++}; ++ ++struct qe_ic { ++ /* Control registers offset */ ++ u32 __iomem *regs; ++ ++ /* The remapper for this QEIC */ ++ struct irq_domain *irqhost; ++ ++ /* The "linux" controller struct */ ++ struct irq_chip hc_irq; ++ ++ /* VIRQ numbers of QE high/low irqs */ ++ unsigned int virq_high; ++ unsigned int virq_low; ++}; ++ ++/* ++ * QE interrupt controller internal structure ++ */ ++struct qe_ic_info { ++ /* location of this source at the QIMR register. */ ++ u32 mask; ++ ++ /* Mask register offset */ ++ u32 mask_reg; ++ ++ /* ++ * for grouped interrupts sources - the interrupt ++ * code as appears at the group priority register ++ */ ++ u8 pri_code; ++ ++ /* Group priority register offset */ ++ u32 pri_reg; ++}; + + static DEFINE_RAW_SPINLOCK(qe_ic_lock); + +@@ -175,15 +304,15 @@ static struct qe_ic_info qe_ic_info[] = { + }, + }; + +-static inline u32 qe_ic_read(volatile __be32 __iomem * base, unsigned int reg) ++static inline u32 qe_ic_read(__be32 __iomem *base, unsigned int reg) + { +- return in_be32(base + (reg >> 2)); ++ return ioread32be(base + (reg >> 2)); + } + +-static inline void qe_ic_write(volatile __be32 __iomem * base, unsigned int reg, ++static inline void qe_ic_write(__be32 __iomem *base, unsigned int reg, + u32 value) + { +- out_be32(base + (reg >> 2), value); ++ iowrite32be(value, base + (reg >> 2)); + } + + static inline struct qe_ic *qe_ic_from_irq(unsigned int virq) +@@ -285,8 +414,8 @@ static const struct irq_domain_ops qe_ic_host_ops = { + .xlate = irq_domain_xlate_onetwocell, + }; + +-/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ +-unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic) ++/* Return an interrupt vector or 0 if no interrupt is pending. */ ++static unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic) + { + int irq; + +@@ -296,13 +425,13 @@ unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic) + irq = qe_ic_read(qe_ic->regs, QEIC_CIVEC) >> 26; + + if (irq == 0) +- return NO_IRQ; ++ return 0; + + return irq_linear_revmap(qe_ic->irqhost, irq); + } + +-/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ +-unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic) ++/* Return an interrupt vector or 0 if no interrupt is pending. */ ++static unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic) + { + int irq; + +@@ -312,32 +441,96 @@ unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic) + irq = qe_ic_read(qe_ic->regs, QEIC_CHIVEC) >> 26; + + if (irq == 0) +- return NO_IRQ; ++ return 0; + + return irq_linear_revmap(qe_ic->irqhost, irq); + } + +-void __init qe_ic_init(struct device_node *node, unsigned int flags, +- void (*low_handler)(struct irq_desc *desc), +- void (*high_handler)(struct irq_desc *desc)) ++static inline void qe_ic_cascade_low_ipic(struct irq_desc *desc) ++{ ++ struct qe_ic *qe_ic = irq_desc_get_handler_data(desc); ++ unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic); ++ ++ if (cascade_irq != 0) ++ generic_handle_irq(cascade_irq); ++} ++ ++static inline void qe_ic_cascade_high_ipic(struct irq_desc *desc) ++{ ++ struct qe_ic *qe_ic = irq_desc_get_handler_data(desc); ++ unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic); ++ ++ if (cascade_irq != 0) ++ generic_handle_irq(cascade_irq); ++} ++ ++static inline void qe_ic_cascade_low_mpic(struct irq_desc *desc) ++{ ++ struct qe_ic *qe_ic = irq_desc_get_handler_data(desc); ++ unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic); ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ ++ if (cascade_irq != 0) ++ generic_handle_irq(cascade_irq); ++ ++ chip->irq_eoi(&desc->irq_data); ++} ++ ++static inline void qe_ic_cascade_high_mpic(struct irq_desc *desc) ++{ ++ struct qe_ic *qe_ic = irq_desc_get_handler_data(desc); ++ unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic); ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ ++ if (cascade_irq != 0) ++ generic_handle_irq(cascade_irq); ++ ++ chip->irq_eoi(&desc->irq_data); ++} ++ ++static inline void qe_ic_cascade_muxed_mpic(struct irq_desc *desc) ++{ ++ struct qe_ic *qe_ic = irq_desc_get_handler_data(desc); ++ unsigned int cascade_irq; ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ ++ cascade_irq = qe_ic_get_high_irq(qe_ic); ++ if (cascade_irq == 0) ++ cascade_irq = qe_ic_get_low_irq(qe_ic); ++ ++ if (cascade_irq != 0) ++ generic_handle_irq(cascade_irq); ++ ++ chip->irq_eoi(&desc->irq_data); ++} ++ ++static int __init qe_ic_init(struct device_node *node, unsigned int flags) + { + struct qe_ic *qe_ic; + struct resource res; +- u32 temp = 0, ret, high_active = 0; ++ u32 temp = 0, high_active = 0; ++ int ret = 0; ++ ++ if (!node) ++ return -ENODEV; + + ret = of_address_to_resource(node, 0, &res); +- if (ret) +- return; ++ if (ret) { ++ ret = -ENODEV; ++ goto err_put_node; ++ } + + qe_ic = kzalloc(sizeof(*qe_ic), GFP_KERNEL); +- if (qe_ic == NULL) +- return; ++ if (qe_ic == NULL) { ++ ret = -ENOMEM; ++ goto err_put_node; ++ } + + qe_ic->irqhost = irq_domain_add_linear(node, NR_QE_IC_INTS, + &qe_ic_host_ops, qe_ic); + if (qe_ic->irqhost == NULL) { +- kfree(qe_ic); +- return; ++ ret = -ENOMEM; ++ goto err_free_qe_ic; + } + + qe_ic->regs = ioremap(res.start, resource_size(&res)); +@@ -347,10 +540,10 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags, + qe_ic->virq_high = irq_of_parse_and_map(node, 0); + qe_ic->virq_low = irq_of_parse_and_map(node, 1); + +- if (qe_ic->virq_low == NO_IRQ) { +- printk(KERN_ERR "Failed to map QE_IC low IRQ\n"); +- kfree(qe_ic); +- return; ++ if (qe_ic->virq_low == 0) { ++ pr_err("Failed to map QE_IC low IRQ\n"); ++ ret = -ENOMEM; ++ goto err_domain_remove; + } + + /* default priority scheme is grouped. If spread mode is */ +@@ -377,136 +570,36 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags, + qe_ic_write(qe_ic->regs, QEIC_CICR, temp); + + irq_set_handler_data(qe_ic->virq_low, qe_ic); +- irq_set_chained_handler(qe_ic->virq_low, low_handler); ++ irq_set_chained_handler(qe_ic->virq_low, qe_ic_cascade_low_mpic); + +- if (qe_ic->virq_high != NO_IRQ && ++ if (qe_ic->virq_high != 0 && + qe_ic->virq_high != qe_ic->virq_low) { + irq_set_handler_data(qe_ic->virq_high, qe_ic); +- irq_set_chained_handler(qe_ic->virq_high, high_handler); +- } +-} +- +-void qe_ic_set_highest_priority(unsigned int virq, int high) +-{ +- struct qe_ic *qe_ic = qe_ic_from_irq(virq); +- unsigned int src = virq_to_hw(virq); +- u32 temp = 0; +- +- temp = qe_ic_read(qe_ic->regs, QEIC_CICR); +- +- temp &= ~CICR_HP_MASK; +- temp |= src << CICR_HP_SHIFT; +- +- temp &= ~CICR_HPIT_MASK; +- temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << CICR_HPIT_SHIFT; +- +- qe_ic_write(qe_ic->regs, QEIC_CICR, temp); +-} +- +-/* Set Priority level within its group, from 1 to 8 */ +-int qe_ic_set_priority(unsigned int virq, unsigned int priority) +-{ +- struct qe_ic *qe_ic = qe_ic_from_irq(virq); +- unsigned int src = virq_to_hw(virq); +- u32 temp; +- +- if (priority > 8 || priority == 0) +- return -EINVAL; +- if (WARN_ONCE(src >= ARRAY_SIZE(qe_ic_info), +- "%s: Invalid hw irq number for QEIC\n", __func__)) +- return -EINVAL; +- if (qe_ic_info[src].pri_reg == 0) +- return -EINVAL; +- +- temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].pri_reg); +- +- if (priority < 4) { +- temp &= ~(0x7 << (32 - priority * 3)); +- temp |= qe_ic_info[src].pri_code << (32 - priority * 3); +- } else { +- temp &= ~(0x7 << (24 - priority * 3)); +- temp |= qe_ic_info[src].pri_code << (24 - priority * 3); ++ irq_set_chained_handler(qe_ic->virq_high, ++ qe_ic_cascade_high_mpic); + } +- +- qe_ic_write(qe_ic->regs, qe_ic_info[src].pri_reg, temp); +- ++ of_node_put(node); + return 0; +-} +- +-/* Set a QE priority to use high irq, only priority 1~2 can use high irq */ +-int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high) +-{ +- struct qe_ic *qe_ic = qe_ic_from_irq(virq); +- unsigned int src = virq_to_hw(virq); +- u32 temp, control_reg = QEIC_CICNR, shift = 0; +- +- if (priority > 2 || priority == 0) +- return -EINVAL; +- if (WARN_ONCE(src >= ARRAY_SIZE(qe_ic_info), +- "%s: Invalid hw irq number for QEIC\n", __func__)) +- return -EINVAL; +- +- switch (qe_ic_info[src].pri_reg) { +- case QEIC_CIPZCC: +- shift = CICNR_ZCC1T_SHIFT; +- break; +- case QEIC_CIPWCC: +- shift = CICNR_WCC1T_SHIFT; +- break; +- case QEIC_CIPYCC: +- shift = CICNR_YCC1T_SHIFT; +- break; +- case QEIC_CIPXCC: +- shift = CICNR_XCC1T_SHIFT; +- break; +- case QEIC_CIPRTA: +- shift = CRICR_RTA1T_SHIFT; +- control_reg = QEIC_CRICR; +- break; +- case QEIC_CIPRTB: +- shift = CRICR_RTB1T_SHIFT; +- control_reg = QEIC_CRICR; +- break; +- default: +- return -EINVAL; +- } +- +- shift += (2 - priority) * 2; +- temp = qe_ic_read(qe_ic->regs, control_reg); +- temp &= ~(SIGNAL_MASK << shift); +- temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << shift; +- qe_ic_write(qe_ic->regs, control_reg, temp); + +- return 0; ++err_domain_remove: ++ irq_domain_remove(qe_ic->irqhost); ++err_free_qe_ic: ++ kfree(qe_ic); ++err_put_node: ++ of_node_put(node); ++ return ret; + } + +-static struct bus_type qe_ic_subsys = { +- .name = "qe_ic", +- .dev_name = "qe_ic", +-}; +- +-static struct device device_qe_ic = { +- .id = 0, +- .bus = &qe_ic_subsys, +-}; +- +-static int __init init_qe_ic_sysfs(void) ++static int __init init_qe_ic(struct device_node *node, ++ struct device_node *parent) + { +- int rc; ++ int ret; + +- printk(KERN_DEBUG "Registering qe_ic with sysfs...\n"); ++ ret = qe_ic_init(node, 0); ++ if (ret) ++ return ret; + +- rc = subsys_system_register(&qe_ic_subsys, NULL); +- if (rc) { +- printk(KERN_ERR "Failed registering qe_ic sys class\n"); +- return -ENODEV; +- } +- rc = device_register(&device_qe_ic); +- if (rc) { +- printk(KERN_ERR "Failed registering qe_ic sys device\n"); +- return -ENODEV; +- } + return 0; + } + +-subsys_initcall(init_qe_ic_sysfs); ++IRQCHIP_DECLARE(qeic, "fsl,qe-ic", init_qe_ic); +diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c +index 65647533..27e11404 100644 +--- a/drivers/net/wan/fsl_ucc_hdlc.c ++++ b/drivers/net/wan/fsl_ucc_hdlc.c +@@ -381,8 +381,8 @@ static netdev_tx_t ucc_hdlc_tx(struct sk_buff *skb, struct net_device *dev) + /* set bd status and length */ + bd_status = (bd_status & T_W_S) | T_R_S | T_I_S | T_L_S | T_TC_S; + +- iowrite16be(bd_status, &bd->status); + iowrite16be(skb->len, &bd->length); ++ iowrite16be(bd_status, &bd->status); + + /* Move to next BD in the ring */ + if (!(bd_status & T_W_S)) +@@ -457,7 +457,7 @@ static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit) + struct sk_buff *skb; + hdlc_device *hdlc = dev_to_hdlc(dev); + struct qe_bd *bd; +- u32 bd_status; ++ u16 bd_status; + u16 length, howmany = 0; + u8 *bdbuffer; + int i; +diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig +index 73a2e08b..b26b6431 100644 +--- a/drivers/soc/fsl/qe/Kconfig ++++ b/drivers/soc/fsl/qe/Kconfig +@@ -4,7 +4,7 @@ + + config QUICC_ENGINE + bool "Freescale QUICC Engine (QE) Support" +- depends on FSL_SOC && PPC32 ++ depends on OF && HAS_IOMEM + select GENERIC_ALLOCATOR + select CRC32 + help +diff --git a/drivers/soc/fsl/qe/Makefile b/drivers/soc/fsl/qe/Makefile +index 2031d385..51e47264 100644 +--- a/drivers/soc/fsl/qe/Makefile ++++ b/drivers/soc/fsl/qe/Makefile +@@ -1,7 +1,7 @@ + # + # Makefile for the linux ppc-specific parts of QE + # +-obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_common.o qe_ic.o qe_io.o ++obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_common.o qe_io.o + obj-$(CONFIG_CPM) += qe_common.o + obj-$(CONFIG_UCC) += ucc.o + obj-$(CONFIG_UCC_SLOW) += ucc_slow.o +diff --git a/drivers/soc/fsl/qe/qe.c b/drivers/soc/fsl/qe/qe.c +index 2707a827..2b53e852 100644 +--- a/drivers/soc/fsl/qe/qe.c ++++ b/drivers/soc/fsl/qe/qe.c +@@ -33,8 +33,6 @@ + #include + #include + #include +-#include +-#include + + static void qe_snums_init(void); + static int qe_sdma_init(void); +@@ -109,15 +107,27 @@ void qe_reset(void) + panic("sdma init failed!"); + } + ++/* issue commands to QE, return 0 on success while -EIO on error ++ * ++ * @cmd: the command code, should be QE_INIT_TX_RX, QE_STOP_TX and so on ++ * @device: which sub-block will run the command, QE_CR_SUBBLOCK_UCCFAST1 - 8 ++ * , QE_CR_SUBBLOCK_UCCSLOW1 - 8, QE_CR_SUBBLOCK_MCC1 - 3, ++ * QE_CR_SUBBLOCK_IDMA1 - 4 and such on. ++ * @mcn_protocol: specifies mode for the command for non-MCC, should be ++ * QE_CR_PROTOCOL_HDLC_TRANSPARENT, QE_CR_PROTOCOL_QMC, QE_CR_PROTOCOL_UART ++ * and such on. ++ * @cmd_input: command related data. ++ */ + int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input) + { + unsigned long flags; + u8 mcn_shift = 0, dev_shift = 0; +- u32 ret; ++ int ret; ++ int i; + + spin_lock_irqsave(&qe_lock, flags); + if (cmd == QE_RESET) { +- out_be32(&qe_immr->cp.cecr, (u32) (cmd | QE_CR_FLG)); ++ iowrite32be((cmd | QE_CR_FLG), &qe_immr->cp.cecr); + } else { + if (cmd == QE_ASSIGN_PAGE) { + /* Here device is the SNUM, not sub-block */ +@@ -134,20 +144,26 @@ int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input) + mcn_shift = QE_CR_MCN_NORMAL_SHIFT; + } + +- out_be32(&qe_immr->cp.cecdr, cmd_input); +- out_be32(&qe_immr->cp.cecr, +- (cmd | QE_CR_FLG | ((u32) device << dev_shift) | (u32) +- mcn_protocol << mcn_shift)); ++ iowrite32be(cmd_input, &qe_immr->cp.cecdr); ++ iowrite32be((cmd | QE_CR_FLG | ((u32)device << dev_shift) | ++ (u32)mcn_protocol << mcn_shift), &qe_immr->cp.cecr); + } + + /* wait for the QE_CR_FLG to clear */ +- ret = spin_event_timeout((in_be32(&qe_immr->cp.cecr) & QE_CR_FLG) == 0, +- 100, 0); ++ ret = -EIO; ++ for (i = 0; i < 100; i++) { ++ if ((ioread32be(&qe_immr->cp.cecr) & QE_CR_FLG) == 0) { ++ ret = 0; ++ break; ++ } ++ udelay(1); ++ } ++ + /* On timeout (e.g. failure), the expression will be false (ret == 0), + otherwise it will be true (ret == 1). */ + spin_unlock_irqrestore(&qe_lock, flags); + +- return ret == 1; ++ return ret; + } + EXPORT_SYMBOL(qe_issue_cmd); + +@@ -166,8 +182,8 @@ static unsigned int brg_clk = 0; + unsigned int qe_get_brg_clk(void) + { + struct device_node *qe; +- int size; +- const u32 *prop; ++ u32 val; ++ int ret; + + if (brg_clk) + return brg_clk; +@@ -179,9 +195,9 @@ unsigned int qe_get_brg_clk(void) + return brg_clk; + } + +- prop = of_get_property(qe, "brg-frequency", &size); +- if (prop && size == sizeof(*prop)) +- brg_clk = *prop; ++ ret = of_property_read_u32(qe, "brg-frequency", &val); ++ if (!ret) ++ brg_clk = val; + + of_node_put(qe); + +@@ -221,7 +237,7 @@ int qe_setbrg(enum qe_clock brg, unsigned int rate, unsigned int multiplier) + tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | + QE_BRGC_ENABLE | div16; + +- out_be32(&qe_immr->brg.brgc[brg - QE_BRG1], tempval); ++ iowrite32be(tempval, &qe_immr->brg.brgc[brg - QE_BRG1]); + + return 0; + } +@@ -355,9 +371,9 @@ static int qe_sdma_init(void) + return -ENOMEM; + } + +- out_be32(&sdma->sdebcr, (u32) sdma_buf_offset & QE_SDEBCR_BA_MASK); +- out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK | +- (0x1 << QE_SDMR_CEN_SHIFT))); ++ iowrite32be((u32)sdma_buf_offset & QE_SDEBCR_BA_MASK, &sdma->sdebcr); ++ iowrite32be((QE_SDMR_GLB_1_MSK | (0x1 << QE_SDMR_CEN_SHIFT)), ++ &sdma->sdmr); + + return 0; + } +@@ -395,14 +411,14 @@ static void qe_upload_microcode(const void *base, + "uploading microcode '%s'\n", ucode->id); + + /* Use auto-increment */ +- out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) | +- QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR); ++ iowrite32be(be32_to_cpu(ucode->iram_offset) | QE_IRAM_IADD_AIE | ++ QE_IRAM_IADD_BADDR, &qe_immr->iram.iadd); + + for (i = 0; i < be32_to_cpu(ucode->count); i++) +- out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i])); ++ iowrite32be(be32_to_cpu(code[i]), &qe_immr->iram.idata); + + /* Set I-RAM Ready Register */ +- out_be32(&qe_immr->iram.iready, be32_to_cpu(QE_IRAM_READY)); ++ iowrite32be(be32_to_cpu(QE_IRAM_READY), &qe_immr->iram.iready); + } + + /* +@@ -487,7 +503,7 @@ int qe_upload_firmware(const struct qe_firmware *firmware) + * If the microcode calls for it, split the I-RAM. + */ + if (!firmware->split) +- setbits16(&qe_immr->cp.cercr, QE_CP_CERCR_CIR); ++ qe_setbits16(&qe_immr->cp.cercr, QE_CP_CERCR_CIR); + + if (firmware->soc.model) + printk(KERN_INFO +@@ -521,11 +537,11 @@ int qe_upload_firmware(const struct qe_firmware *firmware) + u32 trap = be32_to_cpu(ucode->traps[j]); + + if (trap) +- out_be32(&qe_immr->rsp[i].tibcr[j], trap); ++ iowrite32be(trap, &qe_immr->rsp[i].tibcr[j]); + } + + /* Enable traps */ +- out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr)); ++ iowrite32be(be32_to_cpu(ucode->eccr), &qe_immr->rsp[i].eccr); + } + + qe_firmware_uploaded = 1; +@@ -644,9 +660,9 @@ EXPORT_SYMBOL(qe_get_num_of_risc); + unsigned int qe_get_num_of_snums(void) + { + struct device_node *qe; +- int size; + unsigned int num_of_snums; +- const u32 *prop; ++ u32 val; ++ int ret; + + num_of_snums = 28; /* The default number of snum for threads is 28 */ + qe = of_find_compatible_node(NULL, NULL, "fsl,qe"); +@@ -660,9 +676,9 @@ unsigned int qe_get_num_of_snums(void) + return num_of_snums; + } + +- prop = of_get_property(qe, "fsl,qe-num-snums", &size); +- if (prop && size == sizeof(*prop)) { +- num_of_snums = *prop; ++ ret = of_property_read_u32(qe, "fsl,qe-num-snums", &val); ++ if (!ret) { ++ num_of_snums = val; + if ((num_of_snums < 28) || (num_of_snums > QE_NUM_OF_SNUM)) { + /* No QE ever has fewer than 28 SNUMs */ + pr_err("QE: number of snum is invalid\n"); +diff --git a/drivers/soc/fsl/qe/qe_ic.h b/drivers/soc/fsl/qe/qe_ic.h +deleted file mode 100644 +index 926a2ed4..00000000 +--- a/drivers/soc/fsl/qe/qe_ic.h ++++ /dev/null +@@ -1,103 +0,0 @@ +-/* +- * drivers/soc/fsl/qe/qe_ic.h +- * +- * QUICC ENGINE Interrupt Controller Header +- * +- * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved. +- * +- * Author: Li Yang +- * Based on code from Shlomi Gridish +- * +- * 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. +- */ +-#ifndef _POWERPC_SYSDEV_QE_IC_H +-#define _POWERPC_SYSDEV_QE_IC_H +- +-#include +- +-#define NR_QE_IC_INTS 64 +- +-/* QE IC registers offset */ +-#define QEIC_CICR 0x00 +-#define QEIC_CIVEC 0x04 +-#define QEIC_CRIPNR 0x08 +-#define QEIC_CIPNR 0x0c +-#define QEIC_CIPXCC 0x10 +-#define QEIC_CIPYCC 0x14 +-#define QEIC_CIPWCC 0x18 +-#define QEIC_CIPZCC 0x1c +-#define QEIC_CIMR 0x20 +-#define QEIC_CRIMR 0x24 +-#define QEIC_CICNR 0x28 +-#define QEIC_CIPRTA 0x30 +-#define QEIC_CIPRTB 0x34 +-#define QEIC_CRICR 0x3c +-#define QEIC_CHIVEC 0x60 +- +-/* Interrupt priority registers */ +-#define CIPCC_SHIFT_PRI0 29 +-#define CIPCC_SHIFT_PRI1 26 +-#define CIPCC_SHIFT_PRI2 23 +-#define CIPCC_SHIFT_PRI3 20 +-#define CIPCC_SHIFT_PRI4 13 +-#define CIPCC_SHIFT_PRI5 10 +-#define CIPCC_SHIFT_PRI6 7 +-#define CIPCC_SHIFT_PRI7 4 +- +-/* CICR priority modes */ +-#define CICR_GWCC 0x00040000 +-#define CICR_GXCC 0x00020000 +-#define CICR_GYCC 0x00010000 +-#define CICR_GZCC 0x00080000 +-#define CICR_GRTA 0x00200000 +-#define CICR_GRTB 0x00400000 +-#define CICR_HPIT_SHIFT 8 +-#define CICR_HPIT_MASK 0x00000300 +-#define CICR_HP_SHIFT 24 +-#define CICR_HP_MASK 0x3f000000 +- +-/* CICNR */ +-#define CICNR_WCC1T_SHIFT 20 +-#define CICNR_ZCC1T_SHIFT 28 +-#define CICNR_YCC1T_SHIFT 12 +-#define CICNR_XCC1T_SHIFT 4 +- +-/* CRICR */ +-#define CRICR_RTA1T_SHIFT 20 +-#define CRICR_RTB1T_SHIFT 28 +- +-/* Signal indicator */ +-#define SIGNAL_MASK 3 +-#define SIGNAL_HIGH 2 +-#define SIGNAL_LOW 0 +- +-struct qe_ic { +- /* Control registers offset */ +- volatile u32 __iomem *regs; +- +- /* The remapper for this QEIC */ +- struct irq_domain *irqhost; +- +- /* The "linux" controller struct */ +- struct irq_chip hc_irq; +- +- /* VIRQ numbers of QE high/low irqs */ +- unsigned int virq_high; +- unsigned int virq_low; +-}; +- +-/* +- * QE interrupt controller internal structure +- */ +-struct qe_ic_info { +- u32 mask; /* location of this source at the QIMR register. */ +- u32 mask_reg; /* Mask register offset */ +- u8 pri_code; /* for grouped interrupts sources - the interrupt +- code as appears at the group priority register */ +- u32 pri_reg; /* Group priority register offset */ +-}; +- +-#endif /* _POWERPC_SYSDEV_QE_IC_H */ +diff --git a/drivers/soc/fsl/qe/qe_io.c b/drivers/soc/fsl/qe/qe_io.c +index 7ae59abc..8966e8b6 100644 +--- a/drivers/soc/fsl/qe/qe_io.c ++++ b/drivers/soc/fsl/qe/qe_io.c +@@ -22,8 +22,6 @@ + + #include + #include +-#include +-#include + + #undef DEBUG + +@@ -61,16 +59,16 @@ void __par_io_config_pin(struct qe_pio_regs __iomem *par_io, u8 pin, int dir, + pin_mask1bit = (u32) (1 << (QE_PIO_PINS - (pin + 1))); + + /* Set open drain, if required */ +- tmp_val = in_be32(&par_io->cpodr); ++ tmp_val = ioread32be(&par_io->cpodr); + if (open_drain) +- out_be32(&par_io->cpodr, pin_mask1bit | tmp_val); ++ iowrite32be(pin_mask1bit | tmp_val, &par_io->cpodr); + else +- out_be32(&par_io->cpodr, ~pin_mask1bit & tmp_val); ++ iowrite32be(~pin_mask1bit & tmp_val, &par_io->cpodr); + + /* define direction */ + tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ? +- in_be32(&par_io->cpdir2) : +- in_be32(&par_io->cpdir1); ++ ioread32be(&par_io->cpdir2) : ++ ioread32be(&par_io->cpdir1); + + /* get all bits mask for 2 bit per port */ + pin_mask2bits = (u32) (0x3 << (QE_PIO_PINS - +@@ -82,34 +80,30 @@ void __par_io_config_pin(struct qe_pio_regs __iomem *par_io, u8 pin, int dir, + + /* clear and set 2 bits mask */ + if (pin > (QE_PIO_PINS / 2) - 1) { +- out_be32(&par_io->cpdir2, +- ~pin_mask2bits & tmp_val); ++ iowrite32be(~pin_mask2bits & tmp_val, &par_io->cpdir2); + tmp_val &= ~pin_mask2bits; +- out_be32(&par_io->cpdir2, new_mask2bits | tmp_val); ++ iowrite32be(new_mask2bits | tmp_val, &par_io->cpdir2); + } else { +- out_be32(&par_io->cpdir1, +- ~pin_mask2bits & tmp_val); ++ iowrite32be(~pin_mask2bits & tmp_val, &par_io->cpdir1); + tmp_val &= ~pin_mask2bits; +- out_be32(&par_io->cpdir1, new_mask2bits | tmp_val); ++ iowrite32be(new_mask2bits | tmp_val, &par_io->cpdir1); + } + /* define pin assignment */ + tmp_val = (pin > (QE_PIO_PINS / 2) - 1) ? +- in_be32(&par_io->cppar2) : +- in_be32(&par_io->cppar1); ++ ioread32be(&par_io->cppar2) : ++ ioread32be(&par_io->cppar1); + + new_mask2bits = (u32) (assignment << (QE_PIO_PINS - + (pin % (QE_PIO_PINS / 2) + 1) * 2)); + /* clear and set 2 bits mask */ + if (pin > (QE_PIO_PINS / 2) - 1) { +- out_be32(&par_io->cppar2, +- ~pin_mask2bits & tmp_val); ++ iowrite32be(~pin_mask2bits & tmp_val, &par_io->cppar2); + tmp_val &= ~pin_mask2bits; +- out_be32(&par_io->cppar2, new_mask2bits | tmp_val); ++ iowrite32be(new_mask2bits | tmp_val, &par_io->cppar2); + } else { +- out_be32(&par_io->cppar1, +- ~pin_mask2bits & tmp_val); ++ iowrite32be(~pin_mask2bits & tmp_val, &par_io->cppar1); + tmp_val &= ~pin_mask2bits; +- out_be32(&par_io->cppar1, new_mask2bits | tmp_val); ++ iowrite32be(new_mask2bits | tmp_val, &par_io->cppar1); + } + } + EXPORT_SYMBOL(__par_io_config_pin); +@@ -137,12 +131,12 @@ int par_io_data_set(u8 port, u8 pin, u8 val) + /* calculate pin location */ + pin_mask = (u32) (1 << (QE_PIO_PINS - 1 - pin)); + +- tmp_val = in_be32(&par_io[port].cpdata); ++ tmp_val = ioread32be(&par_io[port].cpdata); + + if (val == 0) /* clear */ +- out_be32(&par_io[port].cpdata, ~pin_mask & tmp_val); ++ iowrite32be(~pin_mask & tmp_val, &par_io[port].cpdata); + else /* set */ +- out_be32(&par_io[port].cpdata, pin_mask | tmp_val); ++ iowrite32be(pin_mask | tmp_val, &par_io[port].cpdata); + + return 0; + } +diff --git a/drivers/soc/fsl/qe/qe_tdm.c b/drivers/soc/fsl/qe/qe_tdm.c +index a1048b44..818e6798 100644 +--- a/drivers/soc/fsl/qe/qe_tdm.c ++++ b/drivers/soc/fsl/qe/qe_tdm.c +@@ -227,10 +227,10 @@ void ucc_tdm_init(struct ucc_tdm *utdm, struct ucc_tdm_info *ut_info) + &siram[siram_entry_id * 32 + 0x200 + i]); + } + +- setbits16(&siram[(siram_entry_id * 32) + (utdm->num_of_ts - 1)], +- SIR_LAST); +- setbits16(&siram[(siram_entry_id * 32) + 0x200 + (utdm->num_of_ts - 1)], +- SIR_LAST); ++ qe_setbits16(&siram[(siram_entry_id * 32) + (utdm->num_of_ts - 1)], ++ SIR_LAST); ++ qe_setbits16(&siram[(siram_entry_id * 32) + 0x200 + ++ (utdm->num_of_ts - 1)], SIR_LAST); + + /* Set SIxMR register */ + sixmr = SIMR_SAD(siram_entry_id); +diff --git a/drivers/soc/fsl/qe/ucc.c b/drivers/soc/fsl/qe/ucc.c +index c646d871..bc64b834 100644 +--- a/drivers/soc/fsl/qe/ucc.c ++++ b/drivers/soc/fsl/qe/ucc.c +@@ -39,7 +39,7 @@ int ucc_set_qe_mux_mii_mng(unsigned int ucc_num) + return -EINVAL; + + spin_lock_irqsave(&cmxgcr_lock, flags); +- clrsetbits_be32(&qe_immr->qmx.cmxgcr, QE_CMXGCR_MII_ENET_MNG, ++ qe_clrsetbits32(&qe_immr->qmx.cmxgcr, QE_CMXGCR_MII_ENET_MNG, + ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT); + spin_unlock_irqrestore(&cmxgcr_lock, flags); + +@@ -84,7 +84,7 @@ int ucc_set_type(unsigned int ucc_num, enum ucc_speed_type speed) + return -EINVAL; + } + +- clrsetbits_8(guemr, UCC_GUEMR_MODE_MASK, ++ qe_clrsetbits8(guemr, UCC_GUEMR_MODE_MASK, + UCC_GUEMR_SET_RESERVED3 | speed); + + return 0; +@@ -113,9 +113,9 @@ int ucc_mux_set_grant_tsa_bkpt(unsigned int ucc_num, int set, u32 mask) + get_cmxucr_reg(ucc_num, &cmxucr, ®_num, &shift); + + if (set) +- setbits32(cmxucr, mask << shift); ++ qe_setbits32(cmxucr, mask << shift); + else +- clrbits32(cmxucr, mask << shift); ++ qe_clrbits32(cmxucr, mask << shift); + + return 0; + } +@@ -211,7 +211,7 @@ int ucc_set_qe_mux_rxtx(unsigned int ucc_num, enum qe_clock clock, + if (mode == COMM_DIR_RX) + shift += 4; + +- clrsetbits_be32(cmxucr, QE_CMXUCR_TX_CLK_SRC_MASK << shift, ++ qe_clrsetbits32(cmxucr, QE_CMXUCR_TX_CLK_SRC_MASK << shift, + clock_bits << shift); + + return 0; +diff --git a/drivers/soc/fsl/qe/ucc_fast.c b/drivers/soc/fsl/qe/ucc_fast.c +index 83d8d16e..5115e935 100644 +--- a/drivers/soc/fsl/qe/ucc_fast.c ++++ b/drivers/soc/fsl/qe/ucc_fast.c +@@ -33,41 +33,41 @@ void ucc_fast_dump_regs(struct ucc_fast_private * uccf) + printk(KERN_INFO "Base address: 0x%p\n", uccf->uf_regs); + + printk(KERN_INFO "gumr : addr=0x%p, val=0x%08x\n", +- &uccf->uf_regs->gumr, in_be32(&uccf->uf_regs->gumr)); ++ &uccf->uf_regs->gumr, ioread32be(&uccf->uf_regs->gumr)); + printk(KERN_INFO "upsmr : addr=0x%p, val=0x%08x\n", +- &uccf->uf_regs->upsmr, in_be32(&uccf->uf_regs->upsmr)); ++ &uccf->uf_regs->upsmr, ioread32be(&uccf->uf_regs->upsmr)); + printk(KERN_INFO "utodr : addr=0x%p, val=0x%04x\n", +- &uccf->uf_regs->utodr, in_be16(&uccf->uf_regs->utodr)); ++ &uccf->uf_regs->utodr, ioread16be(&uccf->uf_regs->utodr)); + printk(KERN_INFO "udsr : addr=0x%p, val=0x%04x\n", +- &uccf->uf_regs->udsr, in_be16(&uccf->uf_regs->udsr)); ++ &uccf->uf_regs->udsr, ioread16be(&uccf->uf_regs->udsr)); + printk(KERN_INFO "ucce : addr=0x%p, val=0x%08x\n", +- &uccf->uf_regs->ucce, in_be32(&uccf->uf_regs->ucce)); ++ &uccf->uf_regs->ucce, ioread32be(&uccf->uf_regs->ucce)); + printk(KERN_INFO "uccm : addr=0x%p, val=0x%08x\n", +- &uccf->uf_regs->uccm, in_be32(&uccf->uf_regs->uccm)); ++ &uccf->uf_regs->uccm, ioread32be(&uccf->uf_regs->uccm)); + printk(KERN_INFO "uccs : addr=0x%p, val=0x%02x\n", +- &uccf->uf_regs->uccs, in_8(&uccf->uf_regs->uccs)); ++ &uccf->uf_regs->uccs, ioread8(&uccf->uf_regs->uccs)); + printk(KERN_INFO "urfb : addr=0x%p, val=0x%08x\n", +- &uccf->uf_regs->urfb, in_be32(&uccf->uf_regs->urfb)); ++ &uccf->uf_regs->urfb, ioread32be(&uccf->uf_regs->urfb)); + printk(KERN_INFO "urfs : addr=0x%p, val=0x%04x\n", +- &uccf->uf_regs->urfs, in_be16(&uccf->uf_regs->urfs)); ++ &uccf->uf_regs->urfs, ioread16be(&uccf->uf_regs->urfs)); + printk(KERN_INFO "urfet : addr=0x%p, val=0x%04x\n", +- &uccf->uf_regs->urfet, in_be16(&uccf->uf_regs->urfet)); ++ &uccf->uf_regs->urfet, ioread16be(&uccf->uf_regs->urfet)); + printk(KERN_INFO "urfset: addr=0x%p, val=0x%04x\n", +- &uccf->uf_regs->urfset, in_be16(&uccf->uf_regs->urfset)); ++ &uccf->uf_regs->urfset, ioread16be(&uccf->uf_regs->urfset)); + printk(KERN_INFO "utfb : addr=0x%p, val=0x%08x\n", +- &uccf->uf_regs->utfb, in_be32(&uccf->uf_regs->utfb)); ++ &uccf->uf_regs->utfb, ioread32be(&uccf->uf_regs->utfb)); + printk(KERN_INFO "utfs : addr=0x%p, val=0x%04x\n", +- &uccf->uf_regs->utfs, in_be16(&uccf->uf_regs->utfs)); ++ &uccf->uf_regs->utfs, ioread16be(&uccf->uf_regs->utfs)); + printk(KERN_INFO "utfet : addr=0x%p, val=0x%04x\n", +- &uccf->uf_regs->utfet, in_be16(&uccf->uf_regs->utfet)); ++ &uccf->uf_regs->utfet, ioread16be(&uccf->uf_regs->utfet)); + printk(KERN_INFO "utftt : addr=0x%p, val=0x%04x\n", +- &uccf->uf_regs->utftt, in_be16(&uccf->uf_regs->utftt)); ++ &uccf->uf_regs->utftt, ioread16be(&uccf->uf_regs->utftt)); + printk(KERN_INFO "utpt : addr=0x%p, val=0x%04x\n", +- &uccf->uf_regs->utpt, in_be16(&uccf->uf_regs->utpt)); ++ &uccf->uf_regs->utpt, ioread16be(&uccf->uf_regs->utpt)); + printk(KERN_INFO "urtry : addr=0x%p, val=0x%08x\n", +- &uccf->uf_regs->urtry, in_be32(&uccf->uf_regs->urtry)); ++ &uccf->uf_regs->urtry, ioread32be(&uccf->uf_regs->urtry)); + printk(KERN_INFO "guemr : addr=0x%p, val=0x%02x\n", +- &uccf->uf_regs->guemr, in_8(&uccf->uf_regs->guemr)); ++ &uccf->uf_regs->guemr, ioread8(&uccf->uf_regs->guemr)); + } + EXPORT_SYMBOL(ucc_fast_dump_regs); + +@@ -89,7 +89,7 @@ EXPORT_SYMBOL(ucc_fast_get_qe_cr_subblock); + + void ucc_fast_transmit_on_demand(struct ucc_fast_private * uccf) + { +- out_be16(&uccf->uf_regs->utodr, UCC_FAST_TOD); ++ iowrite16be(UCC_FAST_TOD, &uccf->uf_regs->utodr); + } + EXPORT_SYMBOL(ucc_fast_transmit_on_demand); + +@@ -101,7 +101,7 @@ void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode) + uf_regs = uccf->uf_regs; + + /* Enable reception and/or transmission on this UCC. */ +- gumr = in_be32(&uf_regs->gumr); ++ gumr = ioread32be(&uf_regs->gumr); + if (mode & COMM_DIR_TX) { + gumr |= UCC_FAST_GUMR_ENT; + uccf->enabled_tx = 1; +@@ -110,7 +110,7 @@ void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode) + gumr |= UCC_FAST_GUMR_ENR; + uccf->enabled_rx = 1; + } +- out_be32(&uf_regs->gumr, gumr); ++ iowrite32be(gumr, &uf_regs->gumr); + } + EXPORT_SYMBOL(ucc_fast_enable); + +@@ -122,7 +122,7 @@ void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode) + uf_regs = uccf->uf_regs; + + /* Disable reception and/or transmission on this UCC. */ +- gumr = in_be32(&uf_regs->gumr); ++ gumr = ioread32be(&uf_regs->gumr); + if (mode & COMM_DIR_TX) { + gumr &= ~UCC_FAST_GUMR_ENT; + uccf->enabled_tx = 0; +@@ -131,7 +131,7 @@ void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode) + gumr &= ~UCC_FAST_GUMR_ENR; + uccf->enabled_rx = 0; + } +- out_be32(&uf_regs->gumr, gumr); ++ iowrite32be(gumr, &uf_regs->gumr); + } + EXPORT_SYMBOL(ucc_fast_disable); + +@@ -263,12 +263,13 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc + gumr |= uf_info->tenc; + gumr |= uf_info->tcrc; + gumr |= uf_info->mode; +- out_be32(&uf_regs->gumr, gumr); ++ iowrite32be(gumr, &uf_regs->gumr); + + /* Allocate memory for Tx Virtual Fifo */ + uccf->ucc_fast_tx_virtual_fifo_base_offset = + qe_muram_alloc(uf_info->utfs, UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); +- if (IS_ERR_VALUE(uccf->ucc_fast_tx_virtual_fifo_base_offset)) { ++ if (IS_ERR_VALUE((unsigned long)uccf-> ++ ucc_fast_tx_virtual_fifo_base_offset)) { + printk(KERN_ERR "%s: cannot allocate MURAM for TX FIFO\n", + __func__); + uccf->ucc_fast_tx_virtual_fifo_base_offset = 0; +@@ -281,7 +282,8 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc + qe_muram_alloc(uf_info->urfs + + UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR, + UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); +- if (IS_ERR_VALUE(uccf->ucc_fast_rx_virtual_fifo_base_offset)) { ++ if (IS_ERR_VALUE((unsigned long)uccf-> ++ ucc_fast_rx_virtual_fifo_base_offset)) { + printk(KERN_ERR "%s: cannot allocate MURAM for RX FIFO\n", + __func__); + uccf->ucc_fast_rx_virtual_fifo_base_offset = 0; +@@ -290,15 +292,15 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc + } + + /* Set Virtual Fifo registers */ +- out_be16(&uf_regs->urfs, uf_info->urfs); +- out_be16(&uf_regs->urfet, uf_info->urfet); +- out_be16(&uf_regs->urfset, uf_info->urfset); +- out_be16(&uf_regs->utfs, uf_info->utfs); +- out_be16(&uf_regs->utfet, uf_info->utfet); +- out_be16(&uf_regs->utftt, uf_info->utftt); ++ iowrite16be(uf_info->urfs, &uf_regs->urfs); ++ iowrite16be(uf_info->urfet, &uf_regs->urfet); ++ iowrite16be(uf_info->urfset, &uf_regs->urfset); ++ iowrite16be(uf_info->utfs, &uf_regs->utfs); ++ iowrite16be(uf_info->utfet, &uf_regs->utfet); ++ iowrite16be(uf_info->utftt, &uf_regs->utftt); + /* utfb, urfb are offsets from MURAM base */ +- out_be32(&uf_regs->utfb, uccf->ucc_fast_tx_virtual_fifo_base_offset); +- out_be32(&uf_regs->urfb, uccf->ucc_fast_rx_virtual_fifo_base_offset); ++ iowrite32be(uccf->ucc_fast_tx_virtual_fifo_base_offset, &uf_regs->utfb); ++ iowrite32be(uccf->ucc_fast_rx_virtual_fifo_base_offset, &uf_regs->urfb); + + /* Mux clocking */ + /* Grant Support */ +@@ -366,14 +368,14 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc + } + + /* Set interrupt mask register at UCC level. */ +- out_be32(&uf_regs->uccm, uf_info->uccm_mask); ++ iowrite32be(uf_info->uccm_mask, &uf_regs->uccm); + + /* First, clear anything pending at UCC level, + * otherwise, old garbage may come through + * as soon as the dam is opened. */ + + /* Writing '1' clears */ +- out_be32(&uf_regs->ucce, 0xffffffff); ++ iowrite32be(0xffffffff, &uf_regs->ucce); + + *uccf_ret = uccf; + return 0; +diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c +index 481eb298..ee409fdf 100644 +--- a/drivers/tty/serial/ucc_uart.c ++++ b/drivers/tty/serial/ucc_uart.c +@@ -34,6 +34,7 @@ + #include + + #include ++#include + #include + + /* +diff --git a/include/soc/fsl/qe/qe.h b/include/soc/fsl/qe/qe.h +index 70339d79..f7a14f2d 100644 +--- a/include/soc/fsl/qe/qe.h ++++ b/include/soc/fsl/qe/qe.h +@@ -21,7 +21,6 @@ + #include + #include + #include +-#include + #include + #include + #include +diff --git a/include/soc/fsl/qe/qe_ic.h b/include/soc/fsl/qe/qe_ic.h +deleted file mode 100644 +index 1e155ca6..00000000 +--- a/include/soc/fsl/qe/qe_ic.h ++++ /dev/null +@@ -1,139 +0,0 @@ +-/* +- * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved. +- * +- * Authors: Shlomi Gridish +- * Li Yang +- * +- * Description: +- * QE IC external definitions and structure. +- * +- * 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. +- */ +-#ifndef _ASM_POWERPC_QE_IC_H +-#define _ASM_POWERPC_QE_IC_H +- +-#include +- +-struct device_node; +-struct qe_ic; +- +-#define NUM_OF_QE_IC_GROUPS 6 +- +-/* Flags when we init the QE IC */ +-#define QE_IC_SPREADMODE_GRP_W 0x00000001 +-#define QE_IC_SPREADMODE_GRP_X 0x00000002 +-#define QE_IC_SPREADMODE_GRP_Y 0x00000004 +-#define QE_IC_SPREADMODE_GRP_Z 0x00000008 +-#define QE_IC_SPREADMODE_GRP_RISCA 0x00000010 +-#define QE_IC_SPREADMODE_GRP_RISCB 0x00000020 +- +-#define QE_IC_LOW_SIGNAL 0x00000100 +-#define QE_IC_HIGH_SIGNAL 0x00000200 +- +-#define QE_IC_GRP_W_PRI0_DEST_SIGNAL_HIGH 0x00001000 +-#define QE_IC_GRP_W_PRI1_DEST_SIGNAL_HIGH 0x00002000 +-#define QE_IC_GRP_X_PRI0_DEST_SIGNAL_HIGH 0x00004000 +-#define QE_IC_GRP_X_PRI1_DEST_SIGNAL_HIGH 0x00008000 +-#define QE_IC_GRP_Y_PRI0_DEST_SIGNAL_HIGH 0x00010000 +-#define QE_IC_GRP_Y_PRI1_DEST_SIGNAL_HIGH 0x00020000 +-#define QE_IC_GRP_Z_PRI0_DEST_SIGNAL_HIGH 0x00040000 +-#define QE_IC_GRP_Z_PRI1_DEST_SIGNAL_HIGH 0x00080000 +-#define QE_IC_GRP_RISCA_PRI0_DEST_SIGNAL_HIGH 0x00100000 +-#define QE_IC_GRP_RISCA_PRI1_DEST_SIGNAL_HIGH 0x00200000 +-#define QE_IC_GRP_RISCB_PRI0_DEST_SIGNAL_HIGH 0x00400000 +-#define QE_IC_GRP_RISCB_PRI1_DEST_SIGNAL_HIGH 0x00800000 +-#define QE_IC_GRP_W_DEST_SIGNAL_SHIFT (12) +- +-/* QE interrupt sources groups */ +-enum qe_ic_grp_id { +- QE_IC_GRP_W = 0, /* QE interrupt controller group W */ +- QE_IC_GRP_X, /* QE interrupt controller group X */ +- QE_IC_GRP_Y, /* QE interrupt controller group Y */ +- QE_IC_GRP_Z, /* QE interrupt controller group Z */ +- QE_IC_GRP_RISCA, /* QE interrupt controller RISC group A */ +- QE_IC_GRP_RISCB /* QE interrupt controller RISC group B */ +-}; +- +-#ifdef CONFIG_QUICC_ENGINE +-void qe_ic_init(struct device_node *node, unsigned int flags, +- void (*low_handler)(struct irq_desc *desc), +- void (*high_handler)(struct irq_desc *desc)); +-unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic); +-unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic); +-#else +-static inline void qe_ic_init(struct device_node *node, unsigned int flags, +- void (*low_handler)(struct irq_desc *desc), +- void (*high_handler)(struct irq_desc *desc)) +-{} +-static inline unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic) +-{ return 0; } +-static inline unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic) +-{ return 0; } +-#endif /* CONFIG_QUICC_ENGINE */ +- +-void qe_ic_set_highest_priority(unsigned int virq, int high); +-int qe_ic_set_priority(unsigned int virq, unsigned int priority); +-int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high); +- +-static inline void qe_ic_cascade_low_ipic(struct irq_desc *desc) +-{ +- struct qe_ic *qe_ic = irq_desc_get_handler_data(desc); +- unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic); +- +- if (cascade_irq != NO_IRQ) +- generic_handle_irq(cascade_irq); +-} +- +-static inline void qe_ic_cascade_high_ipic(struct irq_desc *desc) +-{ +- struct qe_ic *qe_ic = irq_desc_get_handler_data(desc); +- unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic); +- +- if (cascade_irq != NO_IRQ) +- generic_handle_irq(cascade_irq); +-} +- +-static inline void qe_ic_cascade_low_mpic(struct irq_desc *desc) +-{ +- struct qe_ic *qe_ic = irq_desc_get_handler_data(desc); +- unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic); +- struct irq_chip *chip = irq_desc_get_chip(desc); +- +- if (cascade_irq != NO_IRQ) +- generic_handle_irq(cascade_irq); +- +- chip->irq_eoi(&desc->irq_data); +-} +- +-static inline void qe_ic_cascade_high_mpic(struct irq_desc *desc) +-{ +- struct qe_ic *qe_ic = irq_desc_get_handler_data(desc); +- unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic); +- struct irq_chip *chip = irq_desc_get_chip(desc); +- +- if (cascade_irq != NO_IRQ) +- generic_handle_irq(cascade_irq); +- +- chip->irq_eoi(&desc->irq_data); +-} +- +-static inline void qe_ic_cascade_muxed_mpic(struct irq_desc *desc) +-{ +- struct qe_ic *qe_ic = irq_desc_get_handler_data(desc); +- unsigned int cascade_irq; +- struct irq_chip *chip = irq_desc_get_chip(desc); +- +- cascade_irq = qe_ic_get_high_irq(qe_ic); +- if (cascade_irq == NO_IRQ) +- cascade_irq = qe_ic_get_low_irq(qe_ic); +- +- if (cascade_irq != NO_IRQ) +- generic_handle_irq(cascade_irq); +- +- chip->irq_eoi(&desc->irq_data); +-} +- +-#endif /* _ASM_POWERPC_QE_IC_H */ +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/814-rtc-support-layerscape.patch b/target/linux/layerscape/patches-4.9/814-rtc-support-layerscape.patch new file mode 100644 index 0000000000..b186fb31ee --- /dev/null +++ b/target/linux/layerscape/patches-4.9/814-rtc-support-layerscape.patch @@ -0,0 +1,688 @@ +From 7e7944c484954ff7b5d53047194e59bfffd1540a Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 12:20:55 +0800 +Subject: [PATCH] rtc: support layerscape + +This is a integrated patch for layerscape rtc support. + +Signed-off-by: Zhang Ying-22455 +Signed-off-by: Yangbo Lu +--- + drivers/rtc/rtc-pcf85263.c | 665 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 665 insertions(+) + create mode 100644 drivers/rtc/rtc-pcf85263.c + +diff --git a/drivers/rtc/rtc-pcf85263.c b/drivers/rtc/rtc-pcf85263.c +new file mode 100644 +index 00000000..629c2840 +--- /dev/null ++++ b/drivers/rtc/rtc-pcf85263.c +@@ -0,0 +1,665 @@ ++/* ++ * rtc-pcf85263 Driver for the NXP PCF85263 RTC ++ * Copyright 2016 Parkeon ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define DRV_NAME "rtc-pcf85263" ++ ++/* Quartz capacitance */ ++#define PCF85263_QUARTZCAP_7pF 0 ++#define PCF85263_QUARTZCAP_6pF 1 ++#define PCF85263_QUARTZCAP_12p5pF 2 ++ ++/* Quartz drive strength */ ++#define PCF85263_QUARTZDRIVE_NORMAL 0 ++#define PCF85263_QUARTZDRIVE_LOW 1 ++#define PCF85263_QUARTZDRIVE_HIGH 2 ++ ++ ++#define PCF85263_REG_RTC_SC 0x01 /* Seconds */ ++#define PCF85263_REG_RTC_SC_OS BIT(7) /* Oscilator stopped flag */ ++ ++#define PCF85263_REG_RTC_MN 0x02 /* Minutes */ ++#define PCF85263_REG_RTC_HR 0x03 /* Hours */ ++#define PCF85263_REG_RTC_DT 0x04 /* Day of month 1-31 */ ++#define PCF85263_REG_RTC_DW 0x05 /* Day of week 0-6 */ ++#define PCF85263_REG_RTC_MO 0x06 /* Month 1-12 */ ++#define PCF85263_REG_RTC_YR 0x07 /* Year 0-99 */ ++ ++#define PCF85263_REG_ALM1_SC 0x08 /* Seconds */ ++#define PCF85263_REG_ALM1_MN 0x09 /* Minutes */ ++#define PCF85263_REG_ALM1_HR 0x0a /* Hours */ ++#define PCF85263_REG_ALM1_DT 0x0b /* Day of month 1-31 */ ++#define PCF85263_REG_ALM1_MO 0x0c /* Month 1-12 */ ++ ++#define PCF85263_REG_ALM_CTL 0x10 ++#define PCF85263_REG_ALM_CTL_ALL_A1E 0x1f /* sec,min,hr,day,mon alarm 1 */ ++ ++#define PCF85263_REG_OSC 0x25 ++#define PCF85263_REG_OSC_CL_MASK (BIT(0) | BIT(1)) ++#define PCF85263_REG_OSC_CL_SHIFT 0 ++#define PCF85263_REG_OSC_OSCD_MASK (BIT(2) | BIT(3)) ++#define PCF85263_REG_OSC_OSCD_SHIFT 2 ++#define PCF85263_REG_OSC_LOWJ BIT(4) ++#define PCF85263_REG_OSC_12H BIT(5) ++ ++#define PCF85263_REG_PINIO 0x27 ++#define PCF85263_REG_PINIO_INTAPM_MASK (BIT(0) | BIT(1)) ++#define PCF85263_REG_PINIO_INTAPM_SHIFT 0 ++#define PCF85263_INTAPM_INTA (0x2 << PCF85263_REG_PINIO_INTAPM_SHIFT) ++#define PCF85263_INTAPM_HIGHZ (0x3 << PCF85263_REG_PINIO_INTAPM_SHIFT) ++#define PCF85263_REG_PINIO_TSPM_MASK (BIT(2) | BIT(3)) ++#define PCF85263_REG_PINIO_TSPM_SHIFT 2 ++#define PCF85263_TSPM_DISABLED (0x0 << PCF85263_REG_PINIO_TSPM_SHIFT) ++#define PCF85263_TSPM_INTB (0x1 << PCF85263_REG_PINIO_TSPM_SHIFT) ++#define PCF85263_REG_PINIO_CLKDISABLE BIT(7) ++ ++#define PCF85263_REG_FUNCTION 0x28 ++#define PCF85263_REG_FUNCTION_COF_MASK 0x7 ++#define PCF85263_REG_FUNCTION_COF_OFF 0x7 /* No clock output */ ++ ++#define PCF85263_REG_INTA_CTL 0x29 ++#define PCF85263_REG_INTB_CTL 0x2A ++#define PCF85263_REG_INTx_CTL_A1E BIT(4) /* Alarm 1 */ ++#define PCF85263_REG_INTx_CTL_ILP BIT(7) /* 0=pulse, 1=level */ ++ ++#define PCF85263_REG_FLAGS 0x2B ++#define PCF85263_REG_FLAGS_A1F BIT(5) ++ ++#define PCF85263_REG_RAM_BYTE 0x2c ++ ++#define PCF85263_REG_STOPENABLE 0x2e ++#define PCF85263_REG_STOPENABLE_STOP BIT(0) ++ ++#define PCF85263_REG_RESET 0x2f /* Reset command */ ++#define PCF85263_REG_RESET_CMD_CPR 0xa4 /* Clear prescaler */ ++ ++#define PCF85263_MAX_REG 0x2f ++ ++#define PCF85263_HR_PM BIT(5) ++ ++enum pcf85263_irqpin { ++ PCF85263_IRQPIN_NONE, ++ PCF85263_IRQPIN_INTA, ++ PCF85263_IRQPIN_INTB ++}; ++ ++static const char *const pcf85263_irqpin_names[] = { ++ [PCF85263_IRQPIN_NONE] = "None", ++ [PCF85263_IRQPIN_INTA] = "INTA", ++ [PCF85263_IRQPIN_INTB] = "INTB" ++}; ++ ++struct pcf85263 { ++ struct device *dev; ++ struct rtc_device *rtc; ++ struct regmap *regmap; ++ enum pcf85263_irqpin irq_pin; ++ int irq; ++ bool mode_12h; ++}; ++ ++/* ++ * Helpers to convert 12h to 24h and vice versa. ++ * Values in register are stored in BCD with a PM flag in bit 5 ++ * ++ * 23:00 <=> 11PM <=> 0x31 ++ * 00:00 <=> 12AM <=> 0x12 ++ * 01:00 <=> 1AM <=> 0x01 ++ * 12:00 <=> 12PM <=> 0x32 ++ * 13:00 <=> 1PM <=> 0x21 ++ */ ++static int pcf85263_bcd12h_to_bin24h(int regval) ++{ ++ int hr = bcd2bin(regval & 0x1f); ++ bool pm = regval & PCF85263_HR_PM; ++ ++ if (hr == 12) ++ return pm ? 12 : 0; ++ ++ return pm ? hr + 12 : hr; ++} ++ ++static int pcf85263_bin24h_to_bcd12h(int hr24) ++{ ++ bool pm = hr24 >= 12; ++ int hr12 = hr24 % 12; ++ ++ if (!hr12) ++ hr12++; ++ ++ return bin2bcd(hr12) | pm ? 0 : PCF85263_HR_PM; ++} ++ ++static int pcf85263_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct pcf85263 *pcf85263 = dev_get_drvdata(dev); ++ const int first = PCF85263_REG_RTC_SC; ++ const int last = PCF85263_REG_RTC_YR; ++ const int len = last - first + 1; ++ u8 regs[len]; ++ u8 hr_reg; ++ int ret; ++ ++ ret = regmap_bulk_read(pcf85263->regmap, first, regs, len); ++ if (ret) ++ return ret; ++ ++ if (regs[PCF85263_REG_RTC_SC - first] & PCF85263_REG_RTC_SC_OS) { ++ dev_warn(dev, "Oscillator stop detected, date/time is not reliable.\n"); ++ return -EINVAL; ++ } ++ ++ tm->tm_sec = bcd2bin(regs[PCF85263_REG_RTC_SC - first] & 0x7f); ++ tm->tm_min = bcd2bin(regs[PCF85263_REG_RTC_MN - first] & 0x7f); ++ ++ hr_reg = regs[PCF85263_REG_RTC_HR - first]; ++ if (pcf85263->mode_12h) ++ tm->tm_hour = pcf85263_bcd12h_to_bin24h(hr_reg); ++ else ++ tm->tm_hour = bcd2bin(hr_reg & 0x3f); ++ ++ tm->tm_mday = bcd2bin(regs[PCF85263_REG_RTC_DT - first]); ++ tm->tm_wday = bcd2bin(regs[PCF85263_REG_RTC_DW - first]); ++ tm->tm_mon = bcd2bin(regs[PCF85263_REG_RTC_MO - first]) - 1; ++ tm->tm_year = bcd2bin(regs[PCF85263_REG_RTC_YR - first]); ++ ++ tm->tm_year += 100; /* Assume 21st century */ ++ ++ return 0; ++} ++ ++static int pcf85263_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct pcf85263 *pcf85263 = dev_get_drvdata(dev); ++ ++ /* ++ * Before setting time need to stop RTC and disable prescaler ++ * Do this all in a single I2C transaction exploiting wraparound ++ * as described in data sheet. ++ * This means that the array below must be in register order ++ */ ++ u8 regs[] = { ++ PCF85263_REG_STOPENABLE_STOP, /* STOP */ ++ PCF85263_REG_RESET_CMD_CPR, /* Disable prescaler */ ++ /* Wrap around to register 0 (1/100s) */ ++ 0, /* 1/100s always zero. */ ++ bin2bcd(tm->tm_sec), ++ bin2bcd(tm->tm_min), ++ bin2bcd(tm->tm_hour), /* 24-hour */ ++ bin2bcd(tm->tm_mday), ++ bin2bcd(tm->tm_wday + 1), ++ bin2bcd(tm->tm_mon + 1), ++ bin2bcd(tm->tm_year % 100) ++ }; ++ int ret; ++ ++ ret = regmap_bulk_write(pcf85263->regmap, PCF85263_REG_STOPENABLE, ++ regs, sizeof(regs)); ++ if (ret) ++ return ret; ++ ++ /* As we have set the time in 24H update the hardware for that */ ++ if (pcf85263->mode_12h) { ++ pcf85263->mode_12h = false; ++ ret = regmap_update_bits(pcf85263->regmap, PCF85263_REG_OSC, ++ PCF85263_REG_OSC_12H, 0); ++ if (ret) ++ return ret; ++ } ++ ++ /* Start it again */ ++ return regmap_write(pcf85263->regmap, PCF85263_REG_STOPENABLE, 0); ++} ++ ++static int pcf85263_enable_alarm(struct pcf85263 *pcf85263, bool enable) ++{ ++ int reg; ++ int ret; ++ ++ ret = regmap_update_bits(pcf85263->regmap, PCF85263_REG_ALM_CTL, ++ PCF85263_REG_ALM_CTL_ALL_A1E, ++ enable ? PCF85263_REG_ALM_CTL_ALL_A1E : 0); ++ if (ret) ++ return ret; ++ ++ switch (pcf85263->irq_pin) { ++ case PCF85263_IRQPIN_NONE: ++ return 0; ++ ++ case PCF85263_IRQPIN_INTA: ++ reg = PCF85263_REG_INTA_CTL; ++ break; ++ ++ case PCF85263_IRQPIN_INTB: ++ reg = PCF85263_REG_INTB_CTL; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ return regmap_update_bits(pcf85263->regmap, reg, ++ PCF85263_REG_INTx_CTL_A1E, ++ enable ? PCF85263_REG_INTx_CTL_A1E : 0); ++} ++ ++static int pcf85263_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) ++{ ++ struct pcf85263 *pcf85263 = dev_get_drvdata(dev); ++ struct rtc_time *tm = &alarm->time; ++ const int first = PCF85263_REG_ALM1_SC; ++ const int last = PCF85263_REG_ALM1_MO; ++ const int len = last - first + 1; ++ u8 regs[len]; ++ u8 hr_reg; ++ unsigned int regval; ++ int ret; ++ ++ ret = regmap_bulk_read(pcf85263->regmap, first, regs, len); ++ if (ret) ++ return ret; ++ ++ tm->tm_sec = bcd2bin(regs[PCF85263_REG_ALM1_SC - first] & 0x7f); ++ tm->tm_min = bcd2bin(regs[PCF85263_REG_ALM1_MN - first] & 0x7f); ++ ++ hr_reg = regs[PCF85263_REG_ALM1_HR - first]; ++ if (pcf85263->mode_12h) ++ tm->tm_hour = pcf85263_bcd12h_to_bin24h(hr_reg); ++ else ++ tm->tm_hour = bcd2bin(hr_reg & 0x3f); ++ ++ tm->tm_mday = bcd2bin(regs[PCF85263_REG_ALM1_DT - first]); ++ tm->tm_mon = bcd2bin(regs[PCF85263_REG_ALM1_MO - first]) - 1; ++ tm->tm_year = -1; ++ tm->tm_wday = -1; ++ ++ ret = regmap_read(pcf85263->regmap, PCF85263_REG_ALM_CTL, ®val); ++ if (ret) ++ return ret; ++ alarm->enabled = !!(regval & PCF85263_REG_ALM_CTL_ALL_A1E); ++ ++ ret = regmap_read(pcf85263->regmap, PCF85263_REG_FLAGS, ®val); ++ if (ret) ++ return ret; ++ alarm->pending = !!(regval & PCF85263_REG_FLAGS_A1F); ++ ++ return 0; ++} ++ ++static int pcf85263_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) ++{ ++ struct pcf85263 *pcf85263 = dev_get_drvdata(dev); ++ struct rtc_time *tm = &alarm->time; ++ const int first = PCF85263_REG_ALM1_SC; ++ const int last = PCF85263_REG_ALM1_MO; ++ const int len = last - first + 1; ++ u8 regs[len]; ++ int ret; ++ ++ /* Disable alarm comparison during update */ ++ ret = pcf85263_enable_alarm(pcf85263, false); ++ if (ret) ++ return ret; ++ ++ /* Clear any pending alarm (write 0=>clr, 1=>no change) */ ++ ret = regmap_write(pcf85263->regmap, PCF85263_REG_FLAGS, ++ (unsigned int)(~PCF85263_REG_FLAGS_A1F)); ++ if (ret) ++ return ret; ++ ++ /* Set the alarm time registers */ ++ regs[PCF85263_REG_ALM1_SC - first] = bin2bcd(tm->tm_sec); ++ regs[PCF85263_REG_ALM1_MN - first] = bin2bcd(tm->tm_min); ++ regs[PCF85263_REG_ALM1_HR - first] = pcf85263->mode_12h ? ++ pcf85263_bin24h_to_bcd12h(tm->tm_hour) : ++ bin2bcd(tm->tm_hour); ++ regs[PCF85263_REG_ALM1_DT - first] = bin2bcd(tm->tm_mday); ++ regs[PCF85263_REG_ALM1_MO - first] = bin2bcd(tm->tm_mon + 1); ++ ++ ret = regmap_bulk_write(pcf85263->regmap, first, regs, sizeof(regs)); ++ if (ret) ++ return ret; ++ ++ if (alarm->enabled) ++ ret = pcf85263_enable_alarm(pcf85263, true); ++ ++ return ret; ++} ++ ++static int pcf85263_alarm_irq_enable(struct device *dev, unsigned int enable) ++{ ++ struct pcf85263 *pcf85263 = dev_get_drvdata(dev); ++ ++ return pcf85263_enable_alarm(pcf85263, !!enable); ++} ++ ++static irqreturn_t pcf85263_irq(int irq, void *data) ++{ ++ struct pcf85263 *pcf85263 = data; ++ unsigned int regval; ++ int ret; ++ ++ ret = regmap_read(pcf85263->regmap, PCF85263_REG_FLAGS, ®val); ++ if (ret) ++ return IRQ_NONE; ++ ++ if (regval & PCF85263_REG_FLAGS_A1F) { ++ regmap_write(pcf85263->regmap, PCF85263_REG_FLAGS, ++ (unsigned int)(~PCF85263_REG_FLAGS_A1F)); ++ ++ rtc_update_irq(pcf85263->rtc, 1, RTC_IRQF | RTC_AF); ++ ++ return IRQ_HANDLED; ++ } ++ ++ return IRQ_NONE; ++} ++ ++static int pcf85263_check_osc_stopped(struct pcf85263 *pcf85263) ++{ ++ unsigned int regval; ++ int ret; ++ ++ ret = regmap_read(pcf85263->regmap, PCF85263_REG_RTC_SC, ®val); ++ if (ret) ++ return ret; ++ ++ ret = regval & PCF85263_REG_RTC_SC_OS ? 1 : 0; ++ if (ret) ++ dev_warn(pcf85263->dev, "Oscillator stop detected, date/time is not reliable.\n"); ++ ++ return ret; ++} ++ ++#ifdef CONFIG_RTC_INTF_DEV ++static int pcf85263_ioctl(struct device *dev, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct pcf85263 *pcf85263 = dev_get_drvdata(dev); ++ int ret; ++ ++ switch (cmd) { ++ case RTC_VL_READ: ++ ret = pcf85263_check_osc_stopped(pcf85263); ++ if (ret < 0) ++ return ret; ++ ++ if (copy_to_user((void __user *)arg, &ret, sizeof(int))) ++ return -EFAULT; ++ return 0; ++ ++ case RTC_VL_CLR: ++ return regmap_update_bits(pcf85263->regmap, ++ PCF85263_REG_RTC_SC, ++ PCF85263_REG_RTC_SC_OS, 0); ++ default: ++ return -ENOIOCTLCMD; ++ } ++} ++#else ++#define pcf85263_ioctl NULL ++#endif ++ ++static int pcf85263_init_hw(struct pcf85263 *pcf85263) ++{ ++ struct device_node *np = pcf85263->dev->of_node; ++ unsigned int regval; ++ u32 propval; ++ int ret; ++ ++ /* Determine if oscilator has been stopped (probably low power) */ ++ ret = pcf85263_check_osc_stopped(pcf85263); ++ if (ret < 0) { ++ /* Log here since this is the first hw access on probe */ ++ dev_err(pcf85263->dev, "Unable to read register\n"); ++ ++ return ret; ++ } ++ ++ /* Determine 12/24H mode */ ++ ret = regmap_read(pcf85263->regmap, PCF85263_REG_OSC, ®val); ++ if (ret) ++ return ret; ++ pcf85263->mode_12h = !!(regval & PCF85263_REG_OSC_12H); ++ ++ /* Set oscilator register */ ++ regval &= ~PCF85263_REG_OSC_12H; /* keep current 12/24 h setting */ ++ ++ propval = PCF85263_QUARTZCAP_12p5pF; ++ of_property_read_u32(np, "quartz-load-capacitance", &propval); ++ regval |= ((propval << PCF85263_REG_OSC_CL_SHIFT) ++ & PCF85263_REG_OSC_CL_MASK); ++ ++ propval = PCF85263_QUARTZDRIVE_NORMAL; ++ of_property_read_u32(np, "quartz-drive-strength", &propval); ++ regval |= ((propval << PCF85263_REG_OSC_OSCD_SHIFT) ++ & PCF85263_REG_OSC_OSCD_MASK); ++ ++ if (of_property_read_bool(np, "quartz-low-jitter")) ++ regval |= PCF85263_REG_OSC_LOWJ; ++ ++ ret = regmap_write(pcf85263->regmap, PCF85263_REG_OSC, regval); ++ if (ret) ++ return ret; ++ ++ /* Set function register (RTC mode, 1s tick, clock output static) */ ++ ret = regmap_write(pcf85263->regmap, PCF85263_REG_FUNCTION, ++ PCF85263_REG_FUNCTION_COF_OFF); ++ if (ret) ++ return ret; ++ ++ /* Set all interrupts to disabled, level mode */ ++ ret = regmap_write(pcf85263->regmap, PCF85263_REG_INTA_CTL, ++ PCF85263_REG_INTx_CTL_ILP); ++ if (ret) ++ return ret; ++ ret = regmap_write(pcf85263->regmap, PCF85263_REG_INTB_CTL, ++ PCF85263_REG_INTx_CTL_ILP); ++ if (ret) ++ return ret; ++ ++ /* Setup IO pin config register */ ++ regval = PCF85263_REG_PINIO_CLKDISABLE; ++ switch (pcf85263->irq_pin) { ++ case PCF85263_IRQPIN_INTA: ++ regval |= (PCF85263_INTAPM_INTA | PCF85263_TSPM_DISABLED); ++ break; ++ case PCF85263_IRQPIN_INTB: ++ regval |= (PCF85263_INTAPM_HIGHZ | PCF85263_TSPM_INTB); ++ break; ++ case PCF85263_IRQPIN_NONE: ++ regval |= (PCF85263_INTAPM_HIGHZ | PCF85263_TSPM_DISABLED); ++ break; ++ } ++ ret = regmap_write(pcf85263->regmap, PCF85263_REG_PINIO, regval); ++ ++ return ret; ++} ++ ++static const struct rtc_class_ops rtc_ops = { ++ .ioctl = pcf85263_ioctl, ++ .read_time = pcf85263_read_time, ++ .set_time = pcf85263_set_time, ++ .read_alarm = pcf85263_read_alarm, ++ .set_alarm = pcf85263_set_alarm, ++ .alarm_irq_enable = pcf85263_alarm_irq_enable, ++}; ++ ++static const struct regmap_config pcf85263_regmap_cfg = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .max_register = PCF85263_MAX_REG, ++}; ++ ++/* ++ * On some boards the interrupt line may not be wired to the CPU but only to ++ * a power supply circuit. ++ * In that case no interrupt will be specified in the device tree but the ++ * wakeup-source DT property may be used to enable wakeup programming in ++ * sysfs ++ */ ++static bool pcf85263_can_wakeup_machine(struct pcf85263 *pcf85263) ++{ ++ return pcf85263->irq || ++ of_property_read_bool(pcf85263->dev->of_node, "wakeup-source"); ++} ++ ++static int pcf85263_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct device *dev = &client->dev; ++ struct pcf85263 *pcf85263; ++ int ret; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | ++ I2C_FUNC_SMBUS_BYTE_DATA | ++ I2C_FUNC_SMBUS_I2C_BLOCK)) ++ return -ENODEV; ++ ++ pcf85263 = devm_kzalloc(dev, sizeof(*pcf85263), GFP_KERNEL); ++ if (!pcf85263) ++ return -ENOMEM; ++ ++ pcf85263->dev = dev; ++ pcf85263->irq = client->irq; ++ dev_set_drvdata(dev, pcf85263); ++ ++ pcf85263->regmap = devm_regmap_init_i2c(client, &pcf85263_regmap_cfg); ++ if (IS_ERR(pcf85263->regmap)) { ++ ret = PTR_ERR(pcf85263->regmap); ++ dev_err(dev, "regmap allocation failed (%d)\n", ret); ++ ++ return ret; ++ } ++ ++ /* Determine which interrupt pin the board uses */ ++ if (pcf85263_can_wakeup_machine(pcf85263)) { ++ if (of_property_match_string(dev->of_node, ++ "interrupt-names", "INTB") >= 0) ++ pcf85263->irq_pin = PCF85263_IRQPIN_INTB; ++ else ++ pcf85263->irq_pin = PCF85263_IRQPIN_INTA; ++ } else { ++ pcf85263->irq_pin = PCF85263_IRQPIN_NONE; ++ } ++ ++ ret = pcf85263_init_hw(pcf85263); ++ if (ret) ++ return ret; ++ ++ if (pcf85263->irq) { ++ ret = devm_request_threaded_irq(dev, pcf85263->irq, NULL, ++ pcf85263_irq, ++ IRQF_ONESHOT, ++ dev->driver->name, pcf85263); ++ if (ret) { ++ dev_err(dev, "irq %d unavailable (%d)\n", ++ pcf85263->irq, ret); ++ pcf85263->irq = 0; ++ } ++ } ++ ++ if (pcf85263_can_wakeup_machine(pcf85263)) ++ device_init_wakeup(dev, true); ++ ++ pcf85263->rtc = devm_rtc_device_register(dev, dev->driver->name, ++ &rtc_ops, THIS_MODULE); ++ ret = PTR_ERR_OR_ZERO(pcf85263->rtc); ++ if (ret) ++ return ret; ++ ++ /* We cannot support UIE mode if we do not have an IRQ line */ ++ if (!pcf85263->irq) ++ pcf85263->rtc->uie_unsupported = 1; ++ ++ dev_info(pcf85263->dev, ++ "PCF85263 RTC (irqpin=%s irq=%d)\n", ++ pcf85263_irqpin_names[pcf85263->irq_pin], ++ pcf85263->irq); ++ ++ return 0; ++} ++ ++static int pcf85263_remove(struct i2c_client *client) ++{ ++ struct pcf85263 *pcf85263 = i2c_get_clientdata(client); ++ ++ if (pcf85263_can_wakeup_machine(pcf85263)) ++ device_init_wakeup(pcf85263->dev, false); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int pcf85263_suspend(struct device *dev) ++{ ++ struct pcf85263 *pcf85263 = dev_get_drvdata(dev); ++ int ret = 0; ++ ++ if (device_may_wakeup(dev)) ++ ret = enable_irq_wake(pcf85263->irq); ++ ++ return ret; ++} ++ ++static int pcf85263_resume(struct device *dev) ++{ ++ struct pcf85263 *pcf85263 = dev_get_drvdata(dev); ++ int ret = 0; ++ ++ if (device_may_wakeup(dev)) ++ ret = disable_irq_wake(pcf85263->irq); ++ ++ return ret; ++} ++ ++#endif ++ ++static const struct i2c_device_id pcf85263_id[] = { ++ { "pcf85263", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, pcf85263_id); ++ ++#ifdef CONFIG_OF ++static const struct of_device_id pcf85263_of_match[] = { ++ { .compatible = "nxp,pcf85263" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, pcf85263_of_match); ++#endif ++ ++static SIMPLE_DEV_PM_OPS(pcf85263_pm_ops, pcf85263_suspend, pcf85263_resume); ++ ++static struct i2c_driver pcf85263_driver = { ++ .driver = { ++ .name = "rtc-pcf85263", ++ .of_match_table = of_match_ptr(pcf85263_of_match), ++ .pm = &pcf85263_pm_ops, ++ }, ++ .probe = pcf85263_probe, ++ .remove = pcf85263_remove, ++ .id_table = pcf85263_id, ++}; ++ ++module_i2c_driver(pcf85263_driver); ++ ++MODULE_AUTHOR("Martin Fuzzey "); ++MODULE_DESCRIPTION("PCF85263 RTC Driver"); ++MODULE_LICENSE("GPL"); ++ +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/815-spi-support-layerscape.patch b/target/linux/layerscape/patches-4.9/815-spi-support-layerscape.patch new file mode 100644 index 0000000000..eab230ef27 --- /dev/null +++ b/target/linux/layerscape/patches-4.9/815-spi-support-layerscape.patch @@ -0,0 +1,445 @@ +From a12f522b48a8cb637c1c026b46a76b2ef7983f8d Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Mon, 25 Sep 2017 12:12:41 +0800 +Subject: [PATCH] spi: support layerscape + +This is a integrated patch for layerscape dspi support. + +Signed-off-by: Christophe JAILLET +Signed-off-by: Sanchayan Maity +Signed-off-by: Geert Uytterhoeven +Signed-off-by: Sanchayan Maity +Signed-off-by: Yangbo Lu +--- + drivers/spi/Kconfig | 1 + + drivers/spi/spi-fsl-dspi.c | 309 ++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 305 insertions(+), 5 deletions(-) + +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +index b7995474..8e281e47 100644 +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -365,6 +365,7 @@ config SPI_FSL_SPI + config SPI_FSL_DSPI + tristate "Freescale DSPI controller" + select REGMAP_MMIO ++ depends on HAS_DMA + depends on SOC_VF610 || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST + help + This enables support for the Freescale DSPI controller in master +diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c +index a67b0ff6..15201645 100644 +--- a/drivers/spi/spi-fsl-dspi.c ++++ b/drivers/spi/spi-fsl-dspi.c +@@ -15,6 +15,8 @@ + + #include + #include ++#include ++#include + #include + #include + #include +@@ -40,6 +42,7 @@ + #define TRAN_STATE_WORD_ODD_NUM 0x04 + + #define DSPI_FIFO_SIZE 4 ++#define DSPI_DMA_BUFSIZE (DSPI_FIFO_SIZE * 1024) + + #define SPI_MCR 0x00 + #define SPI_MCR_MASTER (1 << 31) +@@ -72,6 +75,11 @@ + #define SPI_SR_TCFQF 0x80000000 + #define SPI_SR_CLEAR 0xdaad0000 + ++#define SPI_RSER_TFFFE BIT(25) ++#define SPI_RSER_TFFFD BIT(24) ++#define SPI_RSER_RFDFE BIT(17) ++#define SPI_RSER_RFDFD BIT(16) ++ + #define SPI_RSER 0x30 + #define SPI_RSER_EOQFE 0x10000000 + #define SPI_RSER_TCFQE 0x80000000 +@@ -109,6 +117,8 @@ + + #define SPI_TCR_TCNT_MAX 0x10000 + ++#define DMA_COMPLETION_TIMEOUT msecs_to_jiffies(3000) ++ + struct chip_data { + u32 mcr_val; + u32 ctar_val; +@@ -118,6 +128,7 @@ struct chip_data { + enum dspi_trans_mode { + DSPI_EOQ_MODE = 0, + DSPI_TCFQ_MODE, ++ DSPI_DMA_MODE, + }; + + struct fsl_dspi_devtype_data { +@@ -126,7 +137,7 @@ struct fsl_dspi_devtype_data { + }; + + static const struct fsl_dspi_devtype_data vf610_data = { +- .trans_mode = DSPI_EOQ_MODE, ++ .trans_mode = DSPI_DMA_MODE, + .max_clock_factor = 2, + }; + +@@ -140,6 +151,23 @@ static const struct fsl_dspi_devtype_data ls2085a_data = { + .max_clock_factor = 8, + }; + ++struct fsl_dspi_dma { ++ /* Length of transfer in words of DSPI_FIFO_SIZE */ ++ u32 curr_xfer_len; ++ ++ u32 *tx_dma_buf; ++ struct dma_chan *chan_tx; ++ dma_addr_t tx_dma_phys; ++ struct completion cmd_tx_complete; ++ struct dma_async_tx_descriptor *tx_desc; ++ ++ u32 *rx_dma_buf; ++ struct dma_chan *chan_rx; ++ dma_addr_t rx_dma_phys; ++ struct completion cmd_rx_complete; ++ struct dma_async_tx_descriptor *rx_desc; ++}; ++ + struct fsl_dspi { + struct spi_master *master; + struct platform_device *pdev; +@@ -166,8 +194,11 @@ struct fsl_dspi { + u32 waitflags; + + u32 spi_tcnt; ++ struct fsl_dspi_dma *dma; + }; + ++static u32 dspi_data_to_pushr(struct fsl_dspi *dspi, int tx_word); ++ + static inline int is_double_byte_mode(struct fsl_dspi *dspi) + { + unsigned int val; +@@ -177,6 +208,255 @@ static inline int is_double_byte_mode(struct fsl_dspi *dspi) + return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1; + } + ++static void dspi_tx_dma_callback(void *arg) ++{ ++ struct fsl_dspi *dspi = arg; ++ struct fsl_dspi_dma *dma = dspi->dma; ++ ++ complete(&dma->cmd_tx_complete); ++} ++ ++static void dspi_rx_dma_callback(void *arg) ++{ ++ struct fsl_dspi *dspi = arg; ++ struct fsl_dspi_dma *dma = dspi->dma; ++ int rx_word; ++ int i; ++ u16 d; ++ ++ rx_word = is_double_byte_mode(dspi); ++ ++ if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) { ++ for (i = 0; i < dma->curr_xfer_len; i++) { ++ d = dspi->dma->rx_dma_buf[i]; ++ rx_word ? (*(u16 *)dspi->rx = d) : ++ (*(u8 *)dspi->rx = d); ++ dspi->rx += rx_word + 1; ++ } ++ } ++ ++ complete(&dma->cmd_rx_complete); ++} ++ ++static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi) ++{ ++ struct fsl_dspi_dma *dma = dspi->dma; ++ struct device *dev = &dspi->pdev->dev; ++ int time_left; ++ int tx_word; ++ int i; ++ ++ tx_word = is_double_byte_mode(dspi); ++ ++ for (i = 0; i < dma->curr_xfer_len; i++) { ++ dspi->dma->tx_dma_buf[i] = dspi_data_to_pushr(dspi, tx_word); ++ if ((dspi->cs_change) && (!dspi->len)) ++ dspi->dma->tx_dma_buf[i] &= ~SPI_PUSHR_CONT; ++ } ++ ++ dma->tx_desc = dmaengine_prep_slave_single(dma->chan_tx, ++ dma->tx_dma_phys, ++ dma->curr_xfer_len * ++ DMA_SLAVE_BUSWIDTH_4_BYTES, ++ DMA_MEM_TO_DEV, ++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK); ++ if (!dma->tx_desc) { ++ dev_err(dev, "Not able to get desc for DMA xfer\n"); ++ return -EIO; ++ } ++ ++ dma->tx_desc->callback = dspi_tx_dma_callback; ++ dma->tx_desc->callback_param = dspi; ++ if (dma_submit_error(dmaengine_submit(dma->tx_desc))) { ++ dev_err(dev, "DMA submit failed\n"); ++ return -EINVAL; ++ } ++ ++ dma->rx_desc = dmaengine_prep_slave_single(dma->chan_rx, ++ dma->rx_dma_phys, ++ dma->curr_xfer_len * ++ DMA_SLAVE_BUSWIDTH_4_BYTES, ++ DMA_DEV_TO_MEM, ++ DMA_PREP_INTERRUPT | DMA_CTRL_ACK); ++ if (!dma->rx_desc) { ++ dev_err(dev, "Not able to get desc for DMA xfer\n"); ++ return -EIO; ++ } ++ ++ dma->rx_desc->callback = dspi_rx_dma_callback; ++ dma->rx_desc->callback_param = dspi; ++ if (dma_submit_error(dmaengine_submit(dma->rx_desc))) { ++ dev_err(dev, "DMA submit failed\n"); ++ return -EINVAL; ++ } ++ ++ reinit_completion(&dspi->dma->cmd_rx_complete); ++ reinit_completion(&dspi->dma->cmd_tx_complete); ++ ++ dma_async_issue_pending(dma->chan_rx); ++ dma_async_issue_pending(dma->chan_tx); ++ ++ time_left = wait_for_completion_timeout(&dspi->dma->cmd_tx_complete, ++ DMA_COMPLETION_TIMEOUT); ++ if (time_left == 0) { ++ dev_err(dev, "DMA tx timeout\n"); ++ dmaengine_terminate_all(dma->chan_tx); ++ dmaengine_terminate_all(dma->chan_rx); ++ return -ETIMEDOUT; ++ } ++ ++ time_left = wait_for_completion_timeout(&dspi->dma->cmd_rx_complete, ++ DMA_COMPLETION_TIMEOUT); ++ if (time_left == 0) { ++ dev_err(dev, "DMA rx timeout\n"); ++ dmaengine_terminate_all(dma->chan_tx); ++ dmaengine_terminate_all(dma->chan_rx); ++ return -ETIMEDOUT; ++ } ++ ++ return 0; ++} ++ ++static int dspi_dma_xfer(struct fsl_dspi *dspi) ++{ ++ struct fsl_dspi_dma *dma = dspi->dma; ++ struct device *dev = &dspi->pdev->dev; ++ int curr_remaining_bytes; ++ int bytes_per_buffer; ++ int word = 1; ++ int ret = 0; ++ ++ if (is_double_byte_mode(dspi)) ++ word = 2; ++ curr_remaining_bytes = dspi->len; ++ bytes_per_buffer = DSPI_DMA_BUFSIZE / DSPI_FIFO_SIZE; ++ while (curr_remaining_bytes) { ++ /* Check if current transfer fits the DMA buffer */ ++ dma->curr_xfer_len = curr_remaining_bytes / word; ++ if (dma->curr_xfer_len > bytes_per_buffer) ++ dma->curr_xfer_len = bytes_per_buffer; ++ ++ ret = dspi_next_xfer_dma_submit(dspi); ++ if (ret) { ++ dev_err(dev, "DMA transfer failed\n"); ++ goto exit; ++ ++ } else { ++ curr_remaining_bytes -= dma->curr_xfer_len * word; ++ if (curr_remaining_bytes < 0) ++ curr_remaining_bytes = 0; ++ } ++ } ++ ++exit: ++ return ret; ++} ++ ++static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr) ++{ ++ struct fsl_dspi_dma *dma; ++ struct dma_slave_config cfg; ++ struct device *dev = &dspi->pdev->dev; ++ int ret; ++ ++ dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); ++ if (!dma) ++ return -ENOMEM; ++ ++ dma->chan_rx = dma_request_slave_channel(dev, "rx"); ++ if (!dma->chan_rx) { ++ dev_err(dev, "rx dma channel not available\n"); ++ ret = -ENODEV; ++ return ret; ++ } ++ ++ dma->chan_tx = dma_request_slave_channel(dev, "tx"); ++ if (!dma->chan_tx) { ++ dev_err(dev, "tx dma channel not available\n"); ++ ret = -ENODEV; ++ goto err_tx_channel; ++ } ++ ++ dma->tx_dma_buf = dma_alloc_coherent(dev, DSPI_DMA_BUFSIZE, ++ &dma->tx_dma_phys, GFP_KERNEL); ++ if (!dma->tx_dma_buf) { ++ ret = -ENOMEM; ++ goto err_tx_dma_buf; ++ } ++ ++ dma->rx_dma_buf = dma_alloc_coherent(dev, DSPI_DMA_BUFSIZE, ++ &dma->rx_dma_phys, GFP_KERNEL); ++ if (!dma->rx_dma_buf) { ++ ret = -ENOMEM; ++ goto err_rx_dma_buf; ++ } ++ ++ cfg.src_addr = phy_addr + SPI_POPR; ++ cfg.dst_addr = phy_addr + SPI_PUSHR; ++ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ++ cfg.src_maxburst = 1; ++ cfg.dst_maxburst = 1; ++ ++ cfg.direction = DMA_DEV_TO_MEM; ++ ret = dmaengine_slave_config(dma->chan_rx, &cfg); ++ if (ret) { ++ dev_err(dev, "can't configure rx dma channel\n"); ++ ret = -EINVAL; ++ goto err_slave_config; ++ } ++ ++ cfg.direction = DMA_MEM_TO_DEV; ++ ret = dmaengine_slave_config(dma->chan_tx, &cfg); ++ if (ret) { ++ dev_err(dev, "can't configure tx dma channel\n"); ++ ret = -EINVAL; ++ goto err_slave_config; ++ } ++ ++ dspi->dma = dma; ++ init_completion(&dma->cmd_tx_complete); ++ init_completion(&dma->cmd_rx_complete); ++ ++ return 0; ++ ++err_slave_config: ++ dma_free_coherent(dev, DSPI_DMA_BUFSIZE, ++ dma->rx_dma_buf, dma->rx_dma_phys); ++err_rx_dma_buf: ++ dma_free_coherent(dev, DSPI_DMA_BUFSIZE, ++ dma->tx_dma_buf, dma->tx_dma_phys); ++err_tx_dma_buf: ++ dma_release_channel(dma->chan_tx); ++err_tx_channel: ++ dma_release_channel(dma->chan_rx); ++ ++ devm_kfree(dev, dma); ++ dspi->dma = NULL; ++ ++ return ret; ++} ++ ++static void dspi_release_dma(struct fsl_dspi *dspi) ++{ ++ struct fsl_dspi_dma *dma = dspi->dma; ++ struct device *dev = &dspi->pdev->dev; ++ ++ if (dma) { ++ if (dma->chan_tx) { ++ dma_unmap_single(dev, dma->tx_dma_phys, ++ DSPI_DMA_BUFSIZE, DMA_TO_DEVICE); ++ dma_release_channel(dma->chan_tx); ++ } ++ ++ if (dma->chan_rx) { ++ dma_unmap_single(dev, dma->rx_dma_phys, ++ DSPI_DMA_BUFSIZE, DMA_FROM_DEVICE); ++ dma_release_channel(dma->chan_rx); ++ } ++ } ++} ++ + static void hz_to_spi_baud(char *pbr, char *br, int speed_hz, + unsigned long clkrate) + { +@@ -425,6 +705,12 @@ static int dspi_transfer_one_message(struct spi_master *master, + regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_TCFQE); + dspi_tcfq_write(dspi); + break; ++ case DSPI_DMA_MODE: ++ regmap_write(dspi->regmap, SPI_RSER, ++ SPI_RSER_TFFFE | SPI_RSER_TFFFD | ++ SPI_RSER_RFDFE | SPI_RSER_RFDFD); ++ status = dspi_dma_xfer(dspi); ++ break; + default: + dev_err(&dspi->pdev->dev, "unsupported trans_mode %u\n", + trans_mode); +@@ -432,9 +718,13 @@ static int dspi_transfer_one_message(struct spi_master *master, + goto out; + } + +- if (wait_event_interruptible(dspi->waitq, dspi->waitflags)) +- dev_err(&dspi->pdev->dev, "wait transfer complete fail!\n"); +- dspi->waitflags = 0; ++ if (trans_mode != DSPI_DMA_MODE) { ++ if (wait_event_interruptible(dspi->waitq, ++ dspi->waitflags)) ++ dev_err(&dspi->pdev->dev, ++ "wait transfer complete fail!\n"); ++ dspi->waitflags = 0; ++ } + + if (transfer->delay_usecs) + udelay(transfer->delay_usecs); +@@ -712,7 +1002,8 @@ static int dspi_probe(struct platform_device *pdev) + if (IS_ERR(dspi->regmap)) { + dev_err(&pdev->dev, "failed to init regmap: %ld\n", + PTR_ERR(dspi->regmap)); +- return PTR_ERR(dspi->regmap); ++ ret = PTR_ERR(dspi->regmap); ++ goto out_master_put; + } + + dspi_init(dspi); +@@ -740,6 +1031,13 @@ static int dspi_probe(struct platform_device *pdev) + if (ret) + goto out_master_put; + ++ if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) { ++ if (dspi_request_dma(dspi, res->start)) { ++ dev_err(&pdev->dev, "can't get dma channels\n"); ++ goto out_clk_put; ++ } ++ } ++ + master->max_speed_hz = + clk_get_rate(dspi->clk) / dspi->devtype_data->max_clock_factor; + +@@ -768,6 +1066,7 @@ static int dspi_remove(struct platform_device *pdev) + struct fsl_dspi *dspi = spi_master_get_devdata(master); + + /* Disconnect from the SPI framework */ ++ dspi_release_dma(dspi); + clk_disable_unprepare(dspi->clk); + spi_unregister_master(dspi->master); + +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/816-tty-serial-support-layerscape.patch b/target/linux/layerscape/patches-4.9/816-tty-serial-support-layerscape.patch new file mode 100644 index 0000000000..3e0d30f61d --- /dev/null +++ b/target/linux/layerscape/patches-4.9/816-tty-serial-support-layerscape.patch @@ -0,0 +1,163 @@ +From 469daac0faff06209bc1d1390571b860d153a82b Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Wed, 27 Sep 2017 10:33:47 +0800 +Subject: [PATCH] tty: serial: support layerscape + +This is a integrated patch for layerscape uart support. + +Signed-off-by: Nikita Yushchenko +Signed-off-by: Yuan Yao +Signed-off-by: Stefan Agner +Signed-off-by: Yangbo Lu +--- + drivers/tty/serial/fsl_lpuart.c | 66 ++++++++++++++++++++++++++++------------- + 1 file changed, 46 insertions(+), 20 deletions(-) + +diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c +index 76103f2c..61453820 100644 +--- a/drivers/tty/serial/fsl_lpuart.c ++++ b/drivers/tty/serial/fsl_lpuart.c +@@ -231,6 +231,8 @@ + #define DEV_NAME "ttyLP" + #define UART_NR 6 + ++static DECLARE_BITMAP(linemap, UART_NR); ++ + struct lpuart_port { + struct uart_port port; + struct clk *clk; +@@ -1348,6 +1350,18 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, + /* ask the core to calculate the divisor */ + baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16); + ++ /* ++ * Need to update the Ring buffer length according to the selected ++ * baud rate and restart Rx DMA path. ++ * ++ * Since timer function acqures sport->port.lock, need to stop before ++ * acquring same lock because otherwise del_timer_sync() can deadlock. ++ */ ++ if (old && sport->lpuart_dma_rx_use) { ++ del_timer_sync(&sport->lpuart_timer); ++ lpuart_dma_rx_free(&sport->port); ++ } ++ + spin_lock_irqsave(&sport->port.lock, flags); + + sport->port.read_status_mask = 0; +@@ -1397,22 +1411,11 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, + /* restore control register */ + writeb(old_cr2, sport->port.membase + UARTCR2); + +- /* +- * If new baud rate is set, we will also need to update the Ring buffer +- * length according to the selected baud rate and restart Rx DMA path. +- */ +- if (old) { +- if (sport->lpuart_dma_rx_use) { +- del_timer_sync(&sport->lpuart_timer); +- lpuart_dma_rx_free(&sport->port); +- } +- +- if (sport->dma_rx_chan && !lpuart_start_rx_dma(sport)) { +- sport->lpuart_dma_rx_use = true; ++ if (old && sport->lpuart_dma_rx_use) { ++ if (!lpuart_start_rx_dma(sport)) + rx_dma_timer_init(sport); +- } else { ++ else + sport->lpuart_dma_rx_use = false; +- } + } + + spin_unlock_irqrestore(&sport->port.lock, flags); +@@ -1640,6 +1643,13 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count) + { + struct lpuart_port *sport = lpuart_ports[co->index]; + unsigned char old_cr2, cr2; ++ unsigned long flags; ++ int locked = 1; ++ ++ if (sport->port.sysrq || oops_in_progress) ++ locked = spin_trylock_irqsave(&sport->port.lock, flags); ++ else ++ spin_lock_irqsave(&sport->port.lock, flags); + + /* first save CR2 and then disable interrupts */ + cr2 = old_cr2 = readb(sport->port.membase + UARTCR2); +@@ -1654,6 +1664,9 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count) + barrier(); + + writeb(old_cr2, sport->port.membase + UARTCR2); ++ ++ if (locked) ++ spin_unlock_irqrestore(&sport->port.lock, flags); + } + + static void +@@ -1661,6 +1674,13 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count) + { + struct lpuart_port *sport = lpuart_ports[co->index]; + unsigned long old_cr, cr; ++ unsigned long flags; ++ int locked = 1; ++ ++ if (sport->port.sysrq || oops_in_progress) ++ locked = spin_trylock_irqsave(&sport->port.lock, flags); ++ else ++ spin_lock_irqsave(&sport->port.lock, flags); + + /* first save CR2 and then disable interrupts */ + cr = old_cr = lpuart32_read(sport->port.membase + UARTCTRL); +@@ -1675,6 +1695,9 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count) + barrier(); + + lpuart32_write(old_cr, sport->port.membase + UARTCTRL); ++ ++ if (locked) ++ spin_unlock_irqrestore(&sport->port.lock, flags); + } + + /* +@@ -1899,9 +1922,13 @@ static int lpuart_probe(struct platform_device *pdev) + + ret = of_alias_get_id(np, "serial"); + if (ret < 0) { +- dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); +- return ret; ++ ret = find_first_zero_bit(linemap, UART_NR); ++ if (ret >= UART_NR) { ++ dev_err(&pdev->dev, "port line is full, add device failed\n"); ++ return ret; ++ } + } ++ set_bit(ret, linemap); + sport->port.line = ret; + sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart"); + +@@ -1983,6 +2010,7 @@ static int lpuart_remove(struct platform_device *pdev) + struct lpuart_port *sport = platform_get_drvdata(pdev); + + uart_remove_one_port(&lpuart_reg, &sport->port); ++ clear_bit(sport->port.line, linemap); + + clk_disable_unprepare(sport->clk); + +@@ -2067,12 +2095,10 @@ static int lpuart_resume(struct device *dev) + + if (sport->lpuart_dma_rx_use) { + if (sport->port.irq_wake) { +- if (!lpuart_start_rx_dma(sport)) { +- sport->lpuart_dma_rx_use = true; ++ if (!lpuart_start_rx_dma(sport)) + rx_dma_timer_init(sport); +- } else { ++ else + sport->lpuart_dma_rx_use = false; +- } + } + } + +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/817-usb-support-layerscape.patch b/target/linux/layerscape/patches-4.9/817-usb-support-layerscape.patch new file mode 100644 index 0000000000..ce29f5b17a --- /dev/null +++ b/target/linux/layerscape/patches-4.9/817-usb-support-layerscape.patch @@ -0,0 +1,1471 @@ +From f8daa8e984213554008e73cd155530dceec5a109 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Wed, 27 Sep 2017 10:34:07 +0800 +Subject: [PATCH] usb: support layerscape + +This is a integrated patch for layerscape usb support. + +Signed-off-by: yinbo.zhu +Signed-off-by: Ramneek Mehresh +Signed-off-by: Nikhil Badola +Signed-off-by: Changming Huang +Signed-off-by: Catalin Marinas +Signed-off-by: Rajesh Bhagat +Signed-off-by: Suresh Gupta +Signed-off-by: Zhao Chenhui +Signed-off-by: Yangbo Lu +--- + drivers/usb/common/common.c | 50 ++++++ + drivers/usb/core/hub.c | 8 + + drivers/usb/dwc3/core.c | 235 ++++++++++++++++++++++++++- + drivers/usb/dwc3/core.h | 46 +++++- + drivers/usb/dwc3/host.c | 15 +- + drivers/usb/gadget/udc/fsl_udc_core.c | 46 +++--- + drivers/usb/gadget/udc/fsl_usb2_udc.h | 16 +- + drivers/usb/host/Kconfig | 2 +- + drivers/usb/host/ehci-fsl.c | 289 +++++++++++++++++++++++++++++++--- + drivers/usb/host/ehci-fsl.h | 3 + + drivers/usb/host/ehci-hub.c | 2 + + drivers/usb/host/ehci.h | 5 + + drivers/usb/host/fsl-mph-dr-of.c | 12 ++ + drivers/usb/phy/phy-fsl-usb.c | 59 +++++-- + drivers/usb/phy/phy-fsl-usb.h | 8 + + include/linux/usb.h | 1 + + include/linux/usb/of.h | 2 + + 17 files changed, 726 insertions(+), 73 deletions(-) + +diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c +index 5ef8da6e..176dee01 100644 +--- a/drivers/usb/common/common.c ++++ b/drivers/usb/common/common.c +@@ -105,6 +105,56 @@ static const char *const usb_dr_modes[] = { + [USB_DR_MODE_OTG] = "otg", + }; + ++/** ++ * of_usb_get_dr_mode - Get dual role mode for given device_node ++ * @np: Pointer to the given device_node ++ * ++ * The function gets phy interface string from property 'dr_mode', ++ * and returns the correspondig enum usb_dr_mode ++ */ ++enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np) ++{ ++ const char *dr_mode; ++ int err, i; ++ ++ err = of_property_read_string(np, "dr_mode", &dr_mode); ++ if (err < 0) ++ return USB_DR_MODE_UNKNOWN; ++ ++ for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++) ++ if (!strcmp(dr_mode, usb_dr_modes[i])) ++ return i; ++ ++ return USB_DR_MODE_UNKNOWN; ++} ++EXPORT_SYMBOL_GPL(of_usb_get_dr_mode); ++ ++/** ++ * of_usb_get_maximum_speed - Get maximum requested speed for a given USB ++ * controller. ++ * @np: Pointer to the given device_node ++ * ++ * The function gets the maximum speed string from property "maximum-speed", ++ * and returns the corresponding enum usb_device_speed. ++ */ ++enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np) ++{ ++ const char *maximum_speed; ++ int err; ++ int i; ++ ++ err = of_property_read_string(np, "maximum-speed", &maximum_speed); ++ if (err < 0) ++ return USB_SPEED_UNKNOWN; ++ ++ for (i = 0; i < ARRAY_SIZE(speed_names); i++) ++ if (strcmp(maximum_speed, speed_names[i]) == 0) ++ return i; ++ ++ return USB_SPEED_UNKNOWN; ++} ++EXPORT_SYMBOL_GPL(of_usb_get_maximum_speed); ++ + static enum usb_dr_mode usb_get_dr_mode_from_string(const char *str) + { + int ret; +diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c +index 80d4ef31..e23acf03 100644 +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -4412,6 +4412,14 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, + else + speed = usb_speed_string(udev->speed); + ++#if !defined(CONFIG_FSL_USB2_OTG) && !defined(CONFIG_FSL_USB2_OTG_MODULE) ++if (udev->speed != USB_SPEED_SUPER) ++ dev_info(&udev->dev, ++ "%s %s USB device number %d using %s\n", ++ (udev->config) ? "reset" : "new", speed, ++ devnum, udev->bus->controller->driver->name); ++#endif ++ + if (udev->speed < USB_SPEED_SUPER) + dev_info(&udev->dev, + "%s %s USB device number %d using %s\n", +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index fea44690..e34ef90a 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -58,6 +58,7 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc) + enum usb_dr_mode mode; + struct device *dev = dwc->dev; + unsigned int hw_mode; ++ struct device_node *node = dev->of_node; + + if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) + dwc->dr_mode = USB_DR_MODE_OTG; +@@ -83,6 +84,24 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc) + mode = USB_DR_MODE_HOST; + break; + default: ++ /* Adjust Frame Length */ ++ if (dwc->configure_gfladj) ++ dwc3_writel(dwc->regs, DWC3_GFLADJ, GFLADJ_30MHZ_REG_SEL | ++ GFLADJ_30MHZ(GFLADJ_30MHZ_DEFAULT)); ++ ++ /* Change burst beat and outstanding pipelined transfers requests */ ++ dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, ++ (dwc3_readl(dwc->regs, DWC3_GSBUSCFG0) & ~0xff) | 0xf); ++ dwc3_writel(dwc->regs, DWC3_GSBUSCFG1, ++ dwc3_readl(dwc->regs, DWC3_GSBUSCFG1) | 0xf00); ++ ++ /* Enable Snooping */ ++ if (node && of_dma_is_coherent(node)) { ++ dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, ++ dwc3_readl(dwc->regs, DWC3_GSBUSCFG0) | 0x22220000); ++ dev_dbg(dev, "enabled snooping for usb\n"); ++ } ++ + if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) + mode = USB_DR_MODE_HOST; + else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) +@@ -213,8 +232,9 @@ static void dwc3_frame_length_adjustment(struct dwc3 *dwc) + + reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); + dft = reg & DWC3_GFLADJ_30MHZ_MASK; +- if (!dev_WARN_ONCE(dwc->dev, dft == dwc->fladj, +- "request value same as default, ignoring\n")) { ++ if (dft == dwc->fladj) { ++ dev_warn(dwc->dev, "request value same as default, ignoring\n"); ++ } else { + reg &= ~DWC3_GFLADJ_30MHZ_MASK; + reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj; + dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); +@@ -579,6 +599,99 @@ static int dwc3_phy_setup(struct dwc3 *dwc) + return 0; + } + ++/* set global soc bus configuration registers */ ++static void dwc3_set_soc_bus_cfg(struct dwc3 *dwc) ++{ ++ struct device *dev = dwc->dev; ++ u32 *vals; ++ u32 cfg; ++ int ntype; ++ int ret; ++ int i; ++ ++ cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0); ++ ++ /* ++ * Handle property "snps,incr-burst-type-adjustment". ++ * Get the number of value from this property: ++ * result <= 0, means this property is not supported. ++ * result = 1, means INCRx burst mode supported. ++ * result > 1, means undefined length burst mode supported. ++ */ ++ ntype = device_property_read_u32_array(dev, ++ "snps,incr-burst-type-adjustment", NULL, 0); ++ if (ntype > 0) { ++ vals = kcalloc(ntype, sizeof(u32), GFP_KERNEL); ++ if (!vals) { ++ dev_err(dev, "Error to get memory\n"); ++ return; ++ } ++ /* Get INCR burst type, and parse it */ ++ ret = device_property_read_u32_array(dev, ++ "snps,incr-burst-type-adjustment", vals, ntype); ++ if (ret) { ++ dev_err(dev, "Error to get property\n"); ++ return; ++ } ++ *(dwc->incrx_type + 1) = vals[0]; ++ if (ntype > 1) { ++ *dwc->incrx_type = 1; ++ for (i = 1; i < ntype; i++) { ++ if (vals[i] > *(dwc->incrx_type + 1)) ++ *(dwc->incrx_type + 1) = vals[i]; ++ } ++ } else ++ *dwc->incrx_type = 0; ++ ++ /* Enable Undefined Length INCR Burst and Enable INCRx Burst */ ++ cfg &= ~DWC3_GSBUSCFG0_INCRBRST_MASK; ++ if (*dwc->incrx_type) ++ cfg |= DWC3_GSBUSCFG0_INCRBRSTENA; ++ switch (*(dwc->incrx_type + 1)) { ++ case 256: ++ cfg |= DWC3_GSBUSCFG0_INCR256BRSTENA; ++ break; ++ case 128: ++ cfg |= DWC3_GSBUSCFG0_INCR128BRSTENA; ++ break; ++ case 64: ++ cfg |= DWC3_GSBUSCFG0_INCR64BRSTENA; ++ break; ++ case 32: ++ cfg |= DWC3_GSBUSCFG0_INCR32BRSTENA; ++ break; ++ case 16: ++ cfg |= DWC3_GSBUSCFG0_INCR16BRSTENA; ++ break; ++ case 8: ++ cfg |= DWC3_GSBUSCFG0_INCR8BRSTENA; ++ break; ++ case 4: ++ cfg |= DWC3_GSBUSCFG0_INCR4BRSTENA; ++ break; ++ case 1: ++ break; ++ default: ++ dev_err(dev, "Invalid property\n"); ++ break; ++ } ++ } ++ ++ /* Handle usb snooping */ ++ if (dwc->dma_snooping_quirk) { ++ cfg &= ~DWC3_GSBUSCFG0_SNP_MASK; ++ cfg |= (AXI3_CACHE_TYPE_SNP << DWC3_GSBUSCFG0_DATARD_SHIFT) | ++ (AXI3_CACHE_TYPE_SNP << DWC3_GSBUSCFG0_DESCRD_SHIFT) | ++ (AXI3_CACHE_TYPE_SNP << DWC3_GSBUSCFG0_DATAWR_SHIFT) | ++ (AXI3_CACHE_TYPE_SNP << DWC3_GSBUSCFG0_DESCWR_SHIFT); ++ } ++ ++ dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, cfg); ++ ++} ++ ++ ++ + static void dwc3_core_exit(struct dwc3 *dwc) + { + dwc3_event_buffers_cleanup(dwc); +@@ -721,6 +834,8 @@ static int dwc3_core_init(struct dwc3 *dwc) + if (ret) + goto err1; + ++ dwc3_set_soc_bus_cfg(dwc); ++ + /* Adjust Frame Length */ + dwc3_frame_length_adjustment(dwc); + +@@ -919,11 +1034,109 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc) + } + } + ++static void dwc3_get_properties(struct dwc3 *dwc) ++{ ++ struct device *dev = dwc->dev; ++ struct device_node *node = dev->of_node; ++ u8 lpm_nyet_threshold; ++ u8 tx_de_emphasis; ++ u8 hird_threshold; ++ ++ /* default to highest possible threshold */ ++ lpm_nyet_threshold = 0xff; ++ ++ /* default to -3.5dB de-emphasis */ ++ tx_de_emphasis = 1; ++ ++ /* ++ * default to assert utmi_sleep_n and use maximum allowed HIRD ++ * threshold value of 0b1100 ++ */ ++ hird_threshold = 12; ++ ++ dwc->maximum_speed = usb_get_maximum_speed(dev); ++ dwc->dr_mode = usb_get_dr_mode(dev); ++ dwc->hsphy_mode = of_usb_get_phy_mode(dev->of_node); ++ ++ dwc->sysdev_is_parent = device_property_read_bool(dev, ++ "linux,sysdev_is_parent"); ++ if (dwc->sysdev_is_parent) ++ dwc->sysdev = dwc->dev->parent; ++ else ++ dwc->sysdev = dwc->dev; ++ ++ dwc->has_lpm_erratum = device_property_read_bool(dev, ++ "snps,has-lpm-erratum"); ++ device_property_read_u8(dev, "snps,lpm-nyet-threshold", ++ &lpm_nyet_threshold); ++ dwc->is_utmi_l1_suspend = device_property_read_bool(dev, ++ "snps,is-utmi-l1-suspend"); ++ device_property_read_u8(dev, "snps,hird-threshold", ++ &hird_threshold); ++ dwc->usb3_lpm_capable = device_property_read_bool(dev, ++ "snps,usb3_lpm_capable"); ++ ++ dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); ++ ++ dwc->configure_gfladj = ++ of_property_read_bool(node, "configure-gfladj"); ++ dwc->dr_mode = usb_get_dr_mode(dev); ++ ++ dwc->disable_scramble_quirk = device_property_read_bool(dev, ++ "snps,disable_scramble_quirk"); ++ dwc->u2exit_lfps_quirk = device_property_read_bool(dev, ++ "snps,u2exit_lfps_quirk"); ++ dwc->u2ss_inp3_quirk = device_property_read_bool(dev, ++ "snps,u2ss_inp3_quirk"); ++ dwc->req_p1p2p3_quirk = device_property_read_bool(dev, ++ "snps,req_p1p2p3_quirk"); ++ dwc->del_p1p2p3_quirk = device_property_read_bool(dev, ++ "snps,del_p1p2p3_quirk"); ++ dwc->del_phy_power_chg_quirk = device_property_read_bool(dev, ++ "snps,del_phy_power_chg_quirk"); ++ dwc->lfps_filter_quirk = device_property_read_bool(dev, ++ "snps,lfps_filter_quirk"); ++ dwc->rx_detect_poll_quirk = device_property_read_bool(dev, ++ "snps,rx_detect_poll_quirk"); ++ dwc->dis_u3_susphy_quirk = device_property_read_bool(dev, ++ "snps,dis_u3_susphy_quirk"); ++ dwc->dis_u2_susphy_quirk = device_property_read_bool(dev, ++ "snps,dis_u2_susphy_quirk"); ++ dwc->dis_enblslpm_quirk = device_property_read_bool(dev, ++ "snps,dis_enblslpm_quirk"); ++ dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev, ++ "snps,dis_rxdet_inp3_quirk"); ++ dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev, ++ "snps,dis-u2-freeclk-exists-quirk"); ++ dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev, ++ "snps,dis-del-phy-power-chg-quirk"); ++ dwc->dma_snooping_quirk = device_property_read_bool(dev, ++ "snps,dma-snooping"); ++ ++ dwc->tx_de_emphasis_quirk = device_property_read_bool(dev, ++ "snps,tx_de_emphasis_quirk"); ++ device_property_read_u8(dev, "snps,tx_de_emphasis", ++ &tx_de_emphasis); ++ device_property_read_string(dev, "snps,hsphy_interface", ++ &dwc->hsphy_interface); ++ device_property_read_u32(dev, "snps,quirk-frame-length-adjustment", ++ &dwc->fladj); ++ ++ dwc->lpm_nyet_threshold = lpm_nyet_threshold; ++ dwc->tx_de_emphasis = tx_de_emphasis; ++ ++ dwc->hird_threshold = hird_threshold ++ | (dwc->is_utmi_l1_suspend << 4); ++ ++ dwc->imod_interval = 0; ++} ++ + #define DWC3_ALIGN_MASK (16 - 1) + + static int dwc3_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; ++ struct device_node *node = dev->of_node; + struct resource *res; + struct dwc3 *dwc; + u8 lpm_nyet_threshold; +@@ -955,6 +1168,11 @@ static int dwc3_probe(struct platform_device *pdev) + dwc->xhci_resources[0].flags = res->flags; + dwc->xhci_resources[0].name = res->name; + ++ if (node) { ++ dwc->configure_gfladj = ++ of_property_read_bool(node, "configure-gfladj"); ++ } ++ + res->start += DWC3_GLOBALS_REGS_START; + + /* +@@ -997,6 +1215,12 @@ static int dwc3_probe(struct platform_device *pdev) + dwc->usb3_lpm_capable = device_property_read_bool(dev, + "snps,usb3_lpm_capable"); + ++ dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); ++ ++ dwc->configure_gfladj = ++ of_property_read_bool(node, "configure-gfladj"); ++ dwc->dr_mode = of_usb_get_dr_mode(node); ++ + dwc->disable_scramble_quirk = device_property_read_bool(dev, + "snps,disable_scramble_quirk"); + dwc->u2exit_lfps_quirk = device_property_read_bool(dev, +@@ -1041,6 +1265,8 @@ static int dwc3_probe(struct platform_device *pdev) + dwc->hird_threshold = hird_threshold + | (dwc->is_utmi_l1_suspend << 4); + ++ dwc3_get_properties(dwc); ++ + platform_set_drvdata(pdev, dwc); + dwc3_cache_hwparams(dwc); + +@@ -1064,6 +1290,11 @@ static int dwc3_probe(struct platform_device *pdev) + if (ret < 0) + goto err1; + ++ /* Adjust Frame Length */ ++ if (dwc->configure_gfladj) ++ dwc3_writel(dwc->regs, DWC3_GFLADJ, GFLADJ_30MHZ_REG_SEL | ++ GFLADJ_30MHZ(GFLADJ_30MHZ_DEFAULT)); ++ + pm_runtime_forbid(dev); + + ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); +diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h +index 884c4371..9151eef4 100644 +--- a/drivers/usb/dwc3/core.h ++++ b/drivers/usb/dwc3/core.h +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -154,6 +155,32 @@ + + /* Bit fields */ + ++/* Global SoC Bus Configuration Register 0 */ ++#define AXI3_CACHE_TYPE_AW 0x8 /* write allocate */ ++#define AXI3_CACHE_TYPE_AR 0x4 /* read allocate */ ++#define AXI3_CACHE_TYPE_SNP 0x2 /* cacheable */ ++#define AXI3_CACHE_TYPE_BUF 0x1 /* bufferable */ ++#define DWC3_GSBUSCFG0_DATARD_SHIFT 28 ++#define DWC3_GSBUSCFG0_DESCRD_SHIFT 24 ++#define DWC3_GSBUSCFG0_DATAWR_SHIFT 20 ++#define DWC3_GSBUSCFG0_DESCWR_SHIFT 16 ++#define DWC3_GSBUSCFG0_SNP_MASK 0xffff0000 ++#define DWC3_GSBUSCFG0_DATABIGEND (1 << 11) ++#define DWC3_GSBUSCFG0_DESCBIGEND (1 << 10) ++#define DWC3_GSBUSCFG0_INCR256BRSTENA (1 << 7) /* INCR256 burst */ ++#define DWC3_GSBUSCFG0_INCR128BRSTENA (1 << 6) /* INCR128 burst */ ++#define DWC3_GSBUSCFG0_INCR64BRSTENA (1 << 5) /* INCR64 burst */ ++#define DWC3_GSBUSCFG0_INCR32BRSTENA (1 << 4) /* INCR32 burst */ ++#define DWC3_GSBUSCFG0_INCR16BRSTENA (1 << 3) /* INCR16 burst */ ++#define DWC3_GSBUSCFG0_INCR8BRSTENA (1 << 2) /* INCR8 burst */ ++#define DWC3_GSBUSCFG0_INCR4BRSTENA (1 << 1) /* INCR4 burst */ ++#define DWC3_GSBUSCFG0_INCRBRSTENA (1 << 0) /* undefined length enable */ ++#define DWC3_GSBUSCFG0_INCRBRST_MASK 0xff ++ ++/* Global SoC Bus Configuration Register 1 */ ++#define DWC3_GSBUSCFG1_1KPAGEENA (1 << 12) /* 1K page boundary enable */ ++#define DWC3_GSBUSCFG1_PTRANSLIMIT_MASK 0xf00 ++ + /* Global Debug Queue/FIFO Space Available Register */ + #define DWC3_GDBGFIFOSPACE_NUM(n) ((n) & 0x1f) + #define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0) +@@ -180,7 +207,6 @@ + #define DWC3_GCTL_CLK_PIPE (1) + #define DWC3_GCTL_CLK_PIPEHALF (2) + #define DWC3_GCTL_CLK_MASK (3) +- + #define DWC3_GCTL_PRTCAP(n) (((n) & (3 << 12)) >> 12) + #define DWC3_GCTL_PRTCAPDIR(n) ((n) << 12) + #define DWC3_GCTL_PRTCAP_HOST 1 +@@ -289,6 +315,10 @@ + /* Global Frame Length Adjustment Register */ + #define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7) + #define DWC3_GFLADJ_30MHZ_MASK 0x3f ++#define GFLADJ_30MHZ_REG_SEL (1 << 7) ++#define GFLADJ_30MHZ(n) ((n) & 0x3f) ++#define GFLADJ_30MHZ_DEFAULT 0x20 ++ + + /* Global User Control Register 2 */ + #define DWC3_GUCTL2_RST_ACTBITLATER (1 << 14) +@@ -753,6 +783,7 @@ struct dwc3_scratchpad_array { + * @regs: base address for our registers + * @regs_size: address space size + * @fladj: frame length adjustment ++ * @incrx_type: INCR burst type adjustment + * @irq_gadget: peripheral controller's IRQ number + * @nr_scratch: number of scratch buffers + * @u1u2: only used on revisions <1.83a for workaround +@@ -847,6 +878,7 @@ struct dwc3 { + spinlock_t lock; + + struct device *dev; ++ struct device *sysdev; + + struct platform_device *xhci; + struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM]; +@@ -872,6 +904,12 @@ struct dwc3 { + enum usb_phy_interface hsphy_mode; + + u32 fladj; ++ /* ++ * For INCR burst type. ++ * First field: for undefined length INCR burst type enable. ++ * Second field: for INCRx burst type enable ++ */ ++ u32 incrx_type[2]; + u32 irq_gadget; + u32 nr_scratch; + u32 u1u2; +@@ -948,9 +986,12 @@ struct dwc3 { + unsigned ep0_bounced:1; + unsigned ep0_expect_in:1; + unsigned has_hibernation:1; ++ unsigned sysdev_is_parent:1; + unsigned has_lpm_erratum:1; + unsigned is_utmi_l1_suspend:1; + unsigned is_fpga:1; ++ unsigned needs_fifo_resize:1; ++ unsigned configure_gfladj:1; + unsigned pending_events:1; + unsigned pullups_connected:1; + unsigned setup_packet_pending:1; +@@ -971,9 +1012,12 @@ struct dwc3 { + unsigned dis_rxdet_inp3_quirk:1; + unsigned dis_u2_freeclk_exists_quirk:1; + unsigned dis_del_phy_power_chg_quirk:1; ++ unsigned dma_snooping_quirk:1; + + unsigned tx_de_emphasis_quirk:1; + unsigned tx_de_emphasis:2; ++ ++ u16 imod_interval; + }; + + /* -------------------------------------------------------------------------- */ +diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c +index 626d87d5..f1b98273 100644 +--- a/drivers/usb/dwc3/host.c ++++ b/drivers/usb/dwc3/host.c +@@ -17,6 +17,8 @@ + + #include + ++#include ++ + #include "core.h" + + int dwc3_host_init(struct dwc3 *dwc) +@@ -73,12 +75,21 @@ int dwc3_host_init(struct dwc3 *dwc) + return -ENOMEM; + } + +- dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask); ++ if (IS_ENABLED(CONFIG_OF) && dwc->dev->of_node) ++ of_dma_configure(&xhci->dev, dwc->dev->of_node); ++ else ++ dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask); + +- xhci->dev.parent = dwc->dev; ++ xhci->dev.parent = dwc->dev; + xhci->dev.dma_mask = dwc->dev->dma_mask; + xhci->dev.dma_parms = dwc->dev->dma_parms; + ++ /* set DMA operations */ ++ if (dwc->dev->of_node && of_dma_is_coherent(dwc->dev->of_node)) { ++ xhci->dev.archdata.dma_ops = dwc->dev->archdata.dma_ops; ++ dev_dbg(dwc->dev, "set dma_ops for usb\n"); ++ } ++ + dwc->xhci = xhci; + + ret = platform_device_add_resources(xhci, dwc->xhci_resources, +diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c +index aac0ce8a..fe49e758 100644 +--- a/drivers/usb/gadget/udc/fsl_udc_core.c ++++ b/drivers/usb/gadget/udc/fsl_udc_core.c +@@ -198,7 +198,11 @@ __acquires(ep->udc->lock) + + spin_unlock(&ep->udc->lock); + +- usb_gadget_giveback_request(&ep->ep, &req->req); ++ /* this complete() should a func implemented by gadget layer, ++ * eg fsg->bulk_in_complete() ++ */ ++ if (req->req.complete) ++ usb_gadget_giveback_request(&ep->ep, &req->req); + + spin_lock(&ep->udc->lock); + ep->stopped = stopped; +@@ -245,10 +249,10 @@ static int dr_controller_setup(struct fsl_udc *udc) + if (udc->pdata->have_sysif_regs) { + if (udc->pdata->controller_ver) { + /* controller version 1.6 or above */ +- ctrl = __raw_readl(&usb_sys_regs->control); ++ ctrl = ioread32be(&usb_sys_regs->control); + ctrl &= ~USB_CTRL_UTMI_PHY_EN; + ctrl |= USB_CTRL_USB_EN; +- __raw_writel(ctrl, &usb_sys_regs->control); ++ iowrite32be(ctrl, &usb_sys_regs->control); + } + } + portctrl |= PORTSCX_PTS_ULPI; +@@ -257,13 +261,14 @@ static int dr_controller_setup(struct fsl_udc *udc) + portctrl |= PORTSCX_PTW_16BIT; + /* fall through */ + case FSL_USB2_PHY_UTMI: ++ case FSL_USB2_PHY_UTMI_DUAL: + if (udc->pdata->have_sysif_regs) { + if (udc->pdata->controller_ver) { + /* controller version 1.6 or above */ +- ctrl = __raw_readl(&usb_sys_regs->control); ++ ctrl = ioread32be(&usb_sys_regs->control); + ctrl |= (USB_CTRL_UTMI_PHY_EN | + USB_CTRL_USB_EN); +- __raw_writel(ctrl, &usb_sys_regs->control); ++ iowrite32be(ctrl, &usb_sys_regs->control); + mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI + PHY CLK to become stable - 10ms*/ + } +@@ -329,22 +334,22 @@ static int dr_controller_setup(struct fsl_udc *udc) + /* Config control enable i/o output, cpu endian register */ + #ifndef CONFIG_ARCH_MXC + if (udc->pdata->have_sysif_regs) { +- ctrl = __raw_readl(&usb_sys_regs->control); ++ ctrl = ioread32be(&usb_sys_regs->control); + ctrl |= USB_CTRL_IOENB; +- __raw_writel(ctrl, &usb_sys_regs->control); ++ iowrite32be(ctrl, &usb_sys_regs->control); + } + #endif + +-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE) ++#if !defined(CONFIG_NOT_COHERENT_CACHE) + /* Turn on cache snooping hardware, since some PowerPC platforms + * wholly rely on hardware to deal with cache coherent. */ + + if (udc->pdata->have_sysif_regs) { + /* Setup Snooping for all the 4GB space */ + tmp = SNOOP_SIZE_2GB; /* starts from 0x0, size 2G */ +- __raw_writel(tmp, &usb_sys_regs->snoop1); ++ iowrite32be(tmp, &usb_sys_regs->snoop1); + tmp |= 0x80000000; /* starts from 0x8000000, size 2G */ +- __raw_writel(tmp, &usb_sys_regs->snoop2); ++ iowrite32be(tmp, &usb_sys_regs->snoop2); + } + #endif + +@@ -1057,7 +1062,7 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep) + struct ep_queue_head *qh; + + ep = container_of(_ep, struct fsl_ep, ep); +- if (!_ep || (!ep->ep.desc && ep_index(ep) != 0)) ++ if (!_ep || !ep->ep.desc || (ep_index(ep) == 0)) + return -ENODEV; + + udc = (struct fsl_udc *)ep->udc; +@@ -1599,14 +1604,13 @@ static int process_ep_req(struct fsl_udc *udc, int pipe, + struct fsl_req *curr_req) + { + struct ep_td_struct *curr_td; +- int td_complete, actual, remaining_length, j, tmp; ++ int actual, remaining_length, j, tmp; + int status = 0; + int errors = 0; + struct ep_queue_head *curr_qh = &udc->ep_qh[pipe]; + int direction = pipe % 2; + + curr_td = curr_req->head; +- td_complete = 0; + actual = curr_req->req.length; + + for (j = 0; j < curr_req->dtd_count; j++) { +@@ -1651,11 +1655,9 @@ static int process_ep_req(struct fsl_udc *udc, int pipe, + status = -EPROTO; + break; + } else { +- td_complete++; + break; + } + } else { +- td_complete++; + VDBG("dTD transmitted successful"); + } + +@@ -1698,7 +1700,7 @@ static void dtd_complete_irq(struct fsl_udc *udc) + curr_ep = get_ep_by_pipe(udc, i); + + /* If the ep is configured */ +- if (curr_ep->name == NULL) { ++ if (strncmp(curr_ep->name, "ep", 2)) { + WARNING("Invalid EP?"); + continue; + } +@@ -2420,10 +2422,12 @@ static int fsl_udc_probe(struct platform_device *pdev) + usb_sys_regs = (void *)dr_regs + USB_DR_SYS_OFFSET; + #endif + ++#ifdef CONFIG_ARCH_MXC + /* Initialize USB clocks */ + ret = fsl_udc_clk_init(pdev); + if (ret < 0) + goto err_iounmap_noclk; ++#endif + + /* Read Device Controller Capability Parameters register */ + dccparams = fsl_readl(&dr_regs->dccparams); +@@ -2463,9 +2467,11 @@ static int fsl_udc_probe(struct platform_device *pdev) + dr_controller_setup(udc_controller); + } + ++#ifdef CONFIG_ARCH_MXC + ret = fsl_udc_clk_finalize(pdev); + if (ret) + goto err_free_irq; ++#endif + + /* Setup gadget structure */ + udc_controller->gadget.ops = &fsl_gadget_ops; +@@ -2478,6 +2484,7 @@ static int fsl_udc_probe(struct platform_device *pdev) + /* Setup gadget.dev and register with kernel */ + dev_set_name(&udc_controller->gadget.dev, "gadget"); + udc_controller->gadget.dev.of_node = pdev->dev.of_node; ++ set_dma_ops(&udc_controller->gadget.dev, pdev->dev.archdata.dma_ops); + + if (!IS_ERR_OR_NULL(udc_controller->transceiver)) + udc_controller->gadget.is_otg = 1; +@@ -2529,7 +2536,9 @@ static int fsl_udc_probe(struct platform_device *pdev) + err_iounmap: + if (pdata->exit) + pdata->exit(pdev); ++#ifdef CONFIG_ARCH_MXC + fsl_udc_clk_release(); ++#endif + err_iounmap_noclk: + iounmap(dr_regs); + err_release_mem_region: +@@ -2557,8 +2566,9 @@ static int fsl_udc_remove(struct platform_device *pdev) + udc_controller->done = &done; + usb_del_gadget_udc(&udc_controller->gadget); + ++#ifdef CONFIG_ARCH_MXC + fsl_udc_clk_release(); +- ++#endif + /* DR has been stopped in usb_gadget_unregister_driver() */ + remove_proc_file(); + +@@ -2570,7 +2580,7 @@ static int fsl_udc_remove(struct platform_device *pdev) + dma_pool_destroy(udc_controller->td_pool); + free_irq(udc_controller->irq, udc_controller); + iounmap(dr_regs); +- if (pdata->operating_mode == FSL_USB2_DR_DEVICE) ++ if (res && (pdata->operating_mode == FSL_USB2_DR_DEVICE)) + release_mem_region(res->start, resource_size(res)); + + /* free udc --wait for the release() finished */ +diff --git a/drivers/usb/gadget/udc/fsl_usb2_udc.h b/drivers/usb/gadget/udc/fsl_usb2_udc.h +index 84715625..f76c4ddd 100644 +--- a/drivers/usb/gadget/udc/fsl_usb2_udc.h ++++ b/drivers/usb/gadget/udc/fsl_usb2_udc.h +@@ -20,6 +20,10 @@ + #define USB_MAX_CTRL_PAYLOAD 64 + #define USB_DR_SYS_OFFSET 0x400 + ++#ifdef CONFIG_SOC_LS1021A ++#undef CONFIG_ARCH_MXC ++#endif ++ + /* USB DR device mode registers (Little Endian) */ + struct usb_dr_device { + /* Capability register */ +@@ -597,18 +601,6 @@ struct platform_device; + int fsl_udc_clk_init(struct platform_device *pdev); + int fsl_udc_clk_finalize(struct platform_device *pdev); + void fsl_udc_clk_release(void); +-#else +-static inline int fsl_udc_clk_init(struct platform_device *pdev) +-{ +- return 0; +-} +-static inline int fsl_udc_clk_finalize(struct platform_device *pdev) +-{ +- return 0; +-} +-static inline void fsl_udc_clk_release(void) +-{ +-} + #endif + + #endif +diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig +index 0b80cee3..a57d95c3 100644 +--- a/drivers/usb/host/Kconfig ++++ b/drivers/usb/host/Kconfig +@@ -165,7 +165,7 @@ config XPS_USB_HCD_XILINX + + config USB_EHCI_FSL + tristate "Support for Freescale PPC on-chip EHCI USB controller" +- depends on FSL_SOC ++ depends on USB_EHCI_HCD + select USB_EHCI_ROOT_HUB_TT + ---help--- + Variation of ARC USB block used in some Freescale chips. +diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c +index 9f5ffb62..cd16860c 100644 +--- a/drivers/usb/host/ehci-fsl.c ++++ b/drivers/usb/host/ehci-fsl.c +@@ -37,13 +37,141 @@ + #include + #include + ++#ifdef CONFIG_PPC ++#include ++#include ++#endif ++ + #include "ehci.h" + #include "ehci-fsl.h" + ++#define FSL_USB_PHY_ADDR 0xffe214000 ++ ++struct ccsr_usb_port_ctrl { ++ u32 ctrl; ++ u32 drvvbuscfg; ++ u32 pwrfltcfg; ++ u32 sts; ++ u8 res_14[0xc]; ++ u32 bistcfg; ++ u32 biststs; ++ u32 abistcfg; ++ u32 abiststs; ++ u8 res_30[0x10]; ++ u32 xcvrprg; ++ u32 anaprg; ++ u32 anadrv; ++ u32 anasts; ++}; ++ ++struct ccsr_usb_phy { ++ u32 id; ++ struct ccsr_usb_port_ctrl port1; ++ u8 res_50[0xc]; ++ u32 tvr; ++ u32 pllprg[4]; ++ u8 res_70[0x4]; ++ u32 anaccfg; ++ u32 dbg; ++ u8 res_7c[0x4]; ++ struct ccsr_usb_port_ctrl port2; ++ u8 res_dc[0x334]; ++}; ++ + #define DRIVER_DESC "Freescale EHCI Host controller driver" + #define DRV_NAME "ehci-fsl" + + static struct hc_driver __read_mostly fsl_ehci_hc_driver; ++struct ehci_fsl { ++ /* store current hcd state for otg; ++ * have_hcd is true when host drv al already part of otg framework, ++ * otherwise false; ++ * hcd_add is true when otg framework wants to add host ++ * drv as part of otg;flase when it wants to remove it ++ */ ++unsigned have_hcd:1; ++unsigned hcd_add:1; ++}; ++ ++static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd) ++{ ++struct ehci_hcd *ehci = hcd_to_ehci(hcd); ++ ++return container_of(ehci, struct ehci_fsl, ehci); ++} ++ ++#if defined(CONFIG_FSL_USB2_OTG) || defined(CONFIG_FSL_USB2_OTG_MODULE) ++static void do_change_hcd(struct work_struct *work) ++{ ++struct ehci_hcd *ehci = container_of(work, struct ehci_hcd, ++ change_hcd_work); ++struct usb_hcd *hcd = ehci_to_hcd(ehci); ++struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd); ++void __iomem *non_ehci = hcd->regs; ++int retval; ++ ++ if (ehci_fsl->hcd_add && !ehci_fsl->have_hcd) { ++ writel(USBMODE_CM_HOST, non_ehci + FSL_SOC_USB_USBMODE); ++ /* host, gadget and otg share same int line */ ++ retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); ++ if (retval == 0) ++ ehci_fsl->have_hcd = 1; ++ } else if (!ehci_fsl->hcd_add && ehci_fsl->have_hcd) { ++ usb_remove_hcd(hcd); ++ ehci_fsl->have_hcd = 0; ++ } ++} ++#endif ++ ++struct ehci_fsl { ++ struct ehci_hcd ehci; ++ ++#ifdef CONFIG_PM ++struct ehci_regs saved_regs; ++struct ccsr_usb_phy saved_phy_regs; ++/* Saved USB PHY settings, need to restore after deep sleep. */ ++u32 usb_ctrl; ++#endif ++ /* ++ * store current hcd state for otg; ++ * have_hcd is true when host drv al already part of otg framework, ++ * otherwise false; ++ * hcd_add is true when otg framework wants to add host ++ * drv as part of otg;flase when it wants to remove it ++ */ ++unsigned have_hcd:1; ++unsigned hcd_add:1; ++}; ++ ++static strut ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd) ++{ ++struct ehci_hcd *ehci = hcd_to_ehci(hcd); ++ ++return container_of(ehci, struct ehci_fsl, ehci); ++} ++ ++#if defined(CONFIG_FSL_USB2_OTG) || defined(CONFIG_FSL_USB2_OTG_MODULE) ++static void do_change_hcd(struct work_struct *work) ++{ ++struct ehci_hcd *ehci = container_of(work, struct ehci_hcd, ++change_hcd_work); ++struct usb_hcd *hcd = ehci_to_hcd(ehci); ++struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd); ++void __iomem *non_ehci = hcd->regs; ++int retval; ++ ++if (ehci_fsl->hcd_add && !ehci_fsl->have_hcd) { ++writel(USBMODE_CM_HOST, non_ehci + FSL_SOC_USB_USBMODE); ++/* host, gadget and otg share same int line */ ++retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); ++if (retval == 0) ++ehci_fsl->have_hcd = 1; ++} else if (!ehci_fsl->hcd_add && ehci_fsl->have_hcd) { ++ usb_remove_hcd(hcd); ++ehci_fsl->have_hcd = 0; ++} ++} ++#endif + + /* configure so an HC device and id are always provided */ + /* always called with process context; sleeping is OK */ +@@ -131,6 +259,12 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) + clrsetbits_be32(hcd->regs + FSL_SOC_USB_CTRL, + CONTROL_REGISTER_W1C_MASK, 0x4); + ++ /* Set USB_EN bit to select ULPI phy for USB controller version 2.5 */ ++ if (pdata->controller_ver == FSL_USB_VER_2_5 && ++ pdata->phy_mode == FSL_USB2_PHY_ULPI) ++ iowrite32be(USB_CTRL_USB_EN, hcd->regs + FSL_SOC_USB_CTRL); ++ ++ + /* + * Enable UTMI phy and program PTS field in UTMI mode before asserting + * controller reset for USB Controller version 2.5 +@@ -143,16 +277,20 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) + + /* Don't need to set host mode here. It will be done by tdi_reset() */ + +- retval = usb_add_hcd(hcd, irq, IRQF_SHARED); ++ retval = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_NO_SUSPEND); + if (retval != 0) + goto err2; + device_wakeup_enable(hcd->self.controller); + +-#ifdef CONFIG_USB_OTG ++#if defined(CONFIG_FSL_USB2_OTG) || defined(CONFIG_FSL_USB2_OTG_MODULE) + if (pdata->operating_mode == FSL_USB2_DR_OTG) { + struct ehci_hcd *ehci = hcd_to_ehci(hcd); ++ struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd); + + hcd->usb_phy = usb_get_phy(USB_PHY_TYPE_USB2); ++ ++ INIT_WORK(&ehci->change_hcd_work, do_change_hcd); ++ + dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, phy=0x%p\n", + hcd, ehci, hcd->usb_phy); + +@@ -168,6 +306,11 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) + retval = -ENODEV; + goto err2; + } ++ ++ ehci_fsl->have_hcd = 1; ++ } else { ++ dev_err(&pdev->dev, "wrong operating mode\n"); ++ return -ENODEV; + } + #endif + return retval; +@@ -181,6 +324,18 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) + return retval; + } + ++static bool usb_phy_clk_valid(struct usb_hcd *hcd, ++ enum fsl_usb2_phy_modes phy_mode) ++{ ++ void __iomem *non_ehci = hcd->regs; ++ bool ret = true; ++ ++ if (!(in_be32(non_ehci + FSL_SOC_USB_CTRL) & PHY_CLK_VALID)) ++ ret = false; ++ ++ return ret; ++} ++ + static int ehci_fsl_setup_phy(struct usb_hcd *hcd, + enum fsl_usb2_phy_modes phy_mode, + unsigned int port_offset) +@@ -219,6 +374,21 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd, + /* fall through */ + case FSL_USB2_PHY_UTMI: + case FSL_USB2_PHY_UTMI_DUAL: ++ if (pdata->has_fsl_erratum_a006918) { ++ pr_warn("fsl-ehci: USB PHY clock invalid\n"); ++ return -EINVAL; ++ } ++ ++ /* PHY_CLK_VALID bit is de-featured from all controller ++ * versions below 2.4 and is to be checked only for ++ * internal UTMI phy ++ */ ++ if (pdata->controller_ver > FSL_USB_VER_2_4 && ++ pdata->have_sysif_regs && !usb_phy_clk_valid(hcd)) { ++ pr_err("fsl-ehci: USB PHY clock invalid\n"); ++ return -EINVAL; ++ } ++ + if (pdata->have_sysif_regs && pdata->controller_ver) { + /* controller version 1.6 or above */ + clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, +@@ -292,14 +462,9 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci) + return -EINVAL; + + if (pdata->operating_mode == FSL_USB2_MPH_HOST) { +- unsigned int chip, rev, svr; +- +- svr = mfspr(SPRN_SVR); +- chip = svr >> 16; +- rev = (svr >> 4) & 0xf; + + /* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */ +- if ((rev == 1) && (chip >= 0x8050) && (chip <= 0x8055)) ++ if (pdata->has_fsl_erratum_14 == 1) + ehci->has_fsl_port_bug = 1; + + if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) +@@ -379,16 +544,57 @@ static int ehci_fsl_setup(struct usb_hcd *hcd) + return retval; + } + +-struct ehci_fsl { +- struct ehci_hcd ehci; + + #ifdef CONFIG_PM +- /* Saved USB PHY settings, need to restore after deep sleep. */ +- u32 usb_ctrl; +-#endif +-}; ++void __iomem *phy_reg; + +-#ifdef CONFIG_PM ++#ifdef CONFIG_PPC ++/* save usb registers */ ++static int ehci_fsl_save_context(struct usb_hcd *hcd) ++{ ++ struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd); ++ struct ehci_hcd *ehci = hcd_to_ehci(hcd); ++ void __iomem *non_ehci = hcd->regs; ++ struct device *dev = hcd->self.controller; ++ struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev); ++ ++ if (pdata->phy_mode == FSL_USB2_PHY_UTMI_DUAL) { ++ phy_reg = ioremap(FSL_USB_PHY_ADDR, ++ sizeof(struct ccsr_usb_phy)); ++ _memcpy_fromio((void *)&ehci_fsl->saved_phy_regs, phy_reg, ++ sizeof(struct ccsr_usb_phy)); ++ } ++ ++ _memcpy_fromio((void *)&ehci_fsl->saved_regs, ehci->regs, ++ sizeof(struct ehci_regs)); ++ ehci_fsl->usb_ctrl = ioread32be(non_ehci + FSL_SOC_USB_CTRL); ++ ++ return 0; ++} ++ ++/*Restore usb registers */ ++static int ehci_fsl_restore_context(struct usb_hcd *hcd) ++{ ++ struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd); ++ struct ehci_hcd *ehci = hcd_to_ehci(hcd); ++ void __iomem *non_ehci = hcd->regs; ++ struct device *dev = hcd->self.controller; ++ struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev); ++ ++ if (pdata->phy_mode == FSL_USB2_PHY_UTMI_DUAL) { ++ if (phy_reg) ++ _memcpy_toio(phy_reg, ++ (void *)&ehci_fsl->saved_phy_regs, ++ sizeof(struct ccsr_usb_phy)); ++ } ++ ++ _memcpy_toio(ehci->regs, (void *)&ehci_fsl->saved_regs, ++ sizeof(struct ehci_regs)); ++ iowrite32be(ehci_fsl->usb_ctrl, non_ehci + FSL_SOC_USB_CTRL); ++ ++ return 0; ++} ++#endif + + #ifdef CONFIG_PPC_MPC512x + static int ehci_fsl_mpc512x_drv_suspend(struct device *dev) +@@ -535,26 +741,43 @@ static inline int ehci_fsl_mpc512x_drv_resume(struct device *dev) + } + #endif /* CONFIG_PPC_MPC512x */ + +-static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd) +-{ +- struct ehci_hcd *ehci = hcd_to_ehci(hcd); +- +- return container_of(ehci, struct ehci_fsl, ehci); +-} +- + static int ehci_fsl_drv_suspend(struct device *dev) + { + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd); + void __iomem *non_ehci = hcd->regs; ++#if defined(CONFIG_FSL_USB2_OTG) || defined(CONFIG_FSL_USB2_OTG_MODULE) ++ struct usb_bus host = hcd->self; ++#endif ++ ++#ifdef CONFIG_PPC ++suspend_state_t pm_state; ++pm_state = pm_suspend_state(); ++ ++if (pm_state == PM_SUSPEND_MEM) ++ ehci_fsl_save_context(hcd); ++#endif + + if (of_device_is_compatible(dev->parent->of_node, + "fsl,mpc5121-usb2-dr")) { + return ehci_fsl_mpc512x_drv_suspend(dev); + } + ++#if defined(CONFIG_FSL_USB2_OTG) || defined(CONFIG_FSL_USB2_OTG_MODULE) ++ if (host.is_otg) { ++ struct ehci_hcd *ehci = hcd_to_ehci(hcd); ++ ++ /* remove hcd */ ++ ehci_fsl->hcd_add = 0; ++ schedule_work(&ehci->change_hcd_work); ++ host.is_otg = 0; ++ return 0; ++ } ++#endif ++ + ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), + device_may_wakeup(dev)); ++ + if (!fsl_deep_sleep()) + return 0; + +@@ -568,12 +791,34 @@ static int ehci_fsl_drv_resume(struct device *dev) + struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + void __iomem *non_ehci = hcd->regs; ++#if defined(CONFIG_FSL_USB2_OTG) || defined(CONFIG_FSL_USB2_OTG_MODULE) ++ struct usb_bus host = hcd->self; ++#endif ++ ++#ifdef CONFIG_PPC ++suspend_state_t pm_state; ++pm_state = pm_suspend_state(); ++ ++if (pm_state == PM_SUSPEND_MEM) ++ ehci_fsl_restore_context(hcd); ++#endif + + if (of_device_is_compatible(dev->parent->of_node, + "fsl,mpc5121-usb2-dr")) { + return ehci_fsl_mpc512x_drv_resume(dev); + } + ++#if defined(CONFIG_FSL_USB2_OTG) || defined(CONFIG_FSL_USB2_OTG_MODULE) ++ if (host.is_otg) { ++ /* add hcd */ ++ ehci_fsl->hcd_add = 1; ++ schedule_work(&ehci->change_hcd_work); ++ usb_hcd_resume_root_hub(hcd); ++ host.is_otg = 0; ++ return 0; ++ } ++#endif ++ + ehci_prepare_ports_for_controller_resume(ehci); + if (!fsl_deep_sleep()) + return 0; +diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h +index 1a8a60a5..42ea2976 100644 +--- a/drivers/usb/host/ehci-fsl.h ++++ b/drivers/usb/host/ehci-fsl.h +@@ -63,4 +63,7 @@ + #define UTMI_PHY_EN (1<<9) + #define ULPI_PHY_CLK_SEL (1<<10) + #define PHY_CLK_VALID (1<<17) ++ ++/* Retry count for checking UTMI PHY CLK validity */ ++#define UTMI_PHY_CLK_VALID_CHK_RETRY 5 + #endif /* _EHCI_FSL_H */ +diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c +index 255acca8..c8838c33 100644 +--- a/drivers/usb/host/ehci-hub.c ++++ b/drivers/usb/host/ehci-hub.c +@@ -305,6 +305,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) + USB_PORT_STAT_HIGH_SPEED) + fs_idle_delay = true; + ehci_writel(ehci, t2, reg); ++ if (ehci_has_fsl_susp_errata(ehci)) ++ usleep_range(10000, 20000); + changed = 1; + } + } +diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h +index 3b06bb77..f296d1fb 100644 +--- a/drivers/usb/host/ehci.h ++++ b/drivers/usb/host/ehci.h +@@ -180,6 +180,9 @@ struct ehci_hcd { /* one per controller */ + unsigned periodic_count; /* periodic activity count */ + unsigned uframe_periodic_max; /* max periodic time per uframe */ + ++#if defined(CONFIG_FSL_USB2_OTG) || defined(CONFIG_FSL_USB2_OTG_MODULE) ++ struct work_struct change_hcd_work; ++#endif + + /* list of itds & sitds completed while now_frame was still active */ + struct list_head cached_itd_list; +@@ -706,8 +709,10 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) + * incoming packets get corrupted in HS mode + */ + #define ehci_has_fsl_hs_errata(e) ((e)->has_fsl_hs_errata) ++#define ehci_has_fsl_susp_errata(e) ((e)->has_fsl_susp_errata) + #else + #define ehci_has_fsl_hs_errata(e) (0) ++#define ehci_has_fsl_susp_errata(e) (0) + #endif + + /* +diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c +index f07ccb25..1e59ea9f 100644 +--- a/drivers/usb/host/fsl-mph-dr-of.c ++++ b/drivers/usb/host/fsl-mph-dr-of.c +@@ -226,6 +226,18 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) + of_property_read_bool(np, "fsl,usb-erratum-a007792"); + pdata->has_fsl_erratum_a005275 = + of_property_read_bool(np, "fsl,usb-erratum-a005275"); ++ pdata->has_fsl_erratum_a005697 = ++ of_property_read_bool(np, "fsl,usb_erratum-a005697"); ++ if (of_get_property(np, "fsl,erratum_a006918", NULL)) ++ pdata->has_fsl_erratum_a006918 = 1; ++ else ++ pdata->has_fsl_erratum_a006918 = 0; ++ ++ if (of_get_property(np, "fsl,usb_erratum_14", NULL)) ++ pdata->has_fsl_erratum_14 = 1; ++ else ++ pdata->has_fsl_erratum_14 = 0; ++ + + /* + * Determine whether phy_clk_valid needs to be checked +diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c +index 94eb2923..836355fa 100644 +--- a/drivers/usb/phy/phy-fsl-usb.c ++++ b/drivers/usb/phy/phy-fsl-usb.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2007,2008 Freescale semiconductor, Inc. ++ * Copyright 2007,2008 Freescale Semiconductor, Inc. + * + * Author: Li Yang + * Jerry Huang +@@ -463,6 +463,7 @@ void otg_reset_controller(void) + int fsl_otg_start_host(struct otg_fsm *fsm, int on) + { + struct usb_otg *otg = fsm->otg; ++ struct usb_bus *host = otg->host; + struct device *dev; + struct fsl_otg *otg_dev = + container_of(otg->usb_phy, struct fsl_otg, phy); +@@ -486,6 +487,7 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on) + otg_reset_controller(); + VDBG("host on......\n"); + if (dev->driver->pm && dev->driver->pm->resume) { ++ host->is_otg = 1; + retval = dev->driver->pm->resume(dev); + if (fsm->id) { + /* default-b */ +@@ -510,8 +512,11 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on) + else { + VDBG("host off......\n"); + if (dev && dev->driver) { +- if (dev->driver->pm && dev->driver->pm->suspend) ++ if (dev->driver->pm && ++ dev->driver->pm->suspend) { ++ host->is_otg = 1; + retval = dev->driver->pm->suspend(dev); ++ } + if (fsm->id) + /* default-b */ + fsl_otg_drv_vbus(fsm, 0); +@@ -539,8 +544,17 @@ int fsl_otg_start_gadget(struct otg_fsm *fsm, int on) + dev = otg->gadget->dev.parent; + + if (on) { +- if (dev->driver->resume) ++ /* Delay gadget resume to synchronize between host and gadget ++ * drivers. Upon role-reversal host drv is shutdown by kernel ++ * worker thread. By the time host drv shuts down, controller ++ * gets programmed for gadget role. Shutting host drv after ++ * this results in controller getting reset, and it stops ++ * responding to otg events ++ */ ++ if (dev->driver->resume) { ++ msleep(1000); + dev->driver->resume(dev); ++ } + } else { + if (dev->driver->suspend) + dev->driver->suspend(dev, otg_suspend_state); +@@ -672,6 +686,10 @@ static void fsl_otg_event(struct work_struct *work) + fsl_otg_start_host(fsm, 0); + otg_drv_vbus(fsm, 0); + fsl_otg_start_gadget(fsm, 1); ++ } else { ++ fsl_otg_start_gadget(fsm, 0); ++ otg_drv_vbus(fsm, 1); ++ fsl_otg_start_host(fsm, 1); + } + } + +@@ -724,6 +742,7 @@ irqreturn_t fsl_otg_isr(int irq, void *dev_id) + { + struct otg_fsm *fsm = &((struct fsl_otg *)dev_id)->fsm; + struct usb_otg *otg = ((struct fsl_otg *)dev_id)->phy.otg; ++ struct fsl_otg *otg_dev = dev_id; + u32 otg_int_src, otg_sc; + + otg_sc = fsl_readl(&usb_dr_regs->otgsc); +@@ -753,18 +772,8 @@ irqreturn_t fsl_otg_isr(int irq, void *dev_id) + otg->gadget->is_a_peripheral = !fsm->id; + VDBG("ID int (ID is %d)\n", fsm->id); + +- if (fsm->id) { /* switch to gadget */ +- schedule_delayed_work( +- &((struct fsl_otg *)dev_id)->otg_event, +- 100); +- } else { /* switch to host */ +- cancel_delayed_work(& +- ((struct fsl_otg *)dev_id)-> +- otg_event); +- fsl_otg_start_gadget(fsm, 0); +- otg_drv_vbus(fsm, 1); +- fsl_otg_start_host(fsm, 1); +- } ++ schedule_delayed_work(&otg_dev->otg_event, 100); ++ + return IRQ_HANDLED; + } + } +@@ -923,12 +932,32 @@ int usb_otg_start(struct platform_device *pdev) + temp &= ~(PORTSC_PHY_TYPE_SEL | PORTSC_PTW); + switch (pdata->phy_mode) { + case FSL_USB2_PHY_ULPI: ++ if (pdata->controller_ver) { ++ /* controller version 1.6 or above */ ++ setbits32(&p_otg->dr_mem_map->control, ++ USB_CTRL_ULPI_PHY_CLK_SEL); ++ /* ++ * Due to controller issue of PHY_CLK_VALID in ULPI ++ * mode, we set USB_CTRL_USB_EN before checking ++ * PHY_CLK_VALID, otherwise PHY_CLK_VALID doesn't work. ++ */ ++ clrsetbits_be32(&p_otg->dr_mem_map->control, ++ USB_CTRL_UTMI_PHY_EN, USB_CTRL_IOENB); ++ } + temp |= PORTSC_PTS_ULPI; + break; + case FSL_USB2_PHY_UTMI_WIDE: + temp |= PORTSC_PTW_16BIT; + /* fall through */ + case FSL_USB2_PHY_UTMI: ++ if (pdata->controller_ver) { ++ /* controller version 1.6 or above */ ++ setbits32(&p_otg->dr_mem_map->control, ++ USB_CTRL_UTMI_PHY_EN); ++ /* Delay for UTMI PHY CLK to become stable - 10ms */ ++ mdelay(FSL_UTMI_PHY_DLY); ++ } ++ setbits32(&p_otg->dr_mem_map->control, USB_CTRL_UTMI_PHY_EN); + temp |= PORTSC_PTS_UTMI; + /* fall through */ + default: +diff --git a/drivers/usb/phy/phy-fsl-usb.h b/drivers/usb/phy/phy-fsl-usb.h +index 23149954..c4c08730 100644 +--- a/drivers/usb/phy/phy-fsl-usb.h ++++ b/drivers/usb/phy/phy-fsl-usb.h +@@ -199,6 +199,14 @@ + /* control Register Bit Masks */ + #define USB_CTRL_IOENB (0x1<<2) + #define USB_CTRL_ULPI_INT0EN (0x1<<0) ++#define USB_CTRL_WU_INT_EN (0x1<<1) ++#define USB_CTRL_LINE_STATE_FILTER__EN (0x1<<3) ++#define USB_CTRL_KEEP_OTG_ON (0x1<<4) ++#define USB_CTRL_OTG_PORT (0x1<<5) ++#define USB_CTRL_PLL_RESET (0x1<<8) ++#define USB_CTRL_UTMI_PHY_EN (0x1<<9) ++#define USB_CTRL_ULPI_PHY_CLK_SEL (0x1<<10) ++#define USB_CTRL_PHY_CLK_VALID (0x1<<17) + + /* BCSR5 */ + #define BCSR5_INT_USB (0x02) +diff --git a/include/linux/usb.h b/include/linux/usb.h +index eba1f10e..c334e281 100644 +--- a/include/linux/usb.h ++++ b/include/linux/usb.h +@@ -362,6 +362,7 @@ struct usb_bus { + * for control transfers? + */ + u8 otg_port; /* 0, or number of OTG/HNP port */ ++ unsigned is_otg:1; /* true when host is also otg */ + unsigned is_b_host:1; /* true during some HNP roleswitches */ + unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */ + unsigned no_stop_on_short:1; /* +diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h +index 5ff9032e..2a57e0d2 100644 +--- a/include/linux/usb/of.h ++++ b/include/linux/usb/of.h +@@ -11,6 +11,8 @@ + #include + #include + ++enum usb_dr_mode of_usb_get_dr_mode(struct device_node *np); ++ + #if IS_ENABLED(CONFIG_OF) + enum usb_dr_mode of_usb_get_dr_mode_by_phy(struct device_node *np, int arg0); + bool of_usb_host_tpl_support(struct device_node *np); +-- +2.14.1 + diff --git a/target/linux/layerscape/patches-4.9/818-vfio-support-layerscape.patch b/target/linux/layerscape/patches-4.9/818-vfio-support-layerscape.patch new file mode 100644 index 0000000000..1dba7b3158 --- /dev/null +++ b/target/linux/layerscape/patches-4.9/818-vfio-support-layerscape.patch @@ -0,0 +1,1192 @@ +From 8d82d92ea697145c32bb36d9f39afd5bb0927bc2 Mon Sep 17 00:00:00 2001 +From: Yangbo Lu +Date: Wed, 27 Sep 2017 10:34:46 +0800 +Subject: [PATCH] vfio: support layerscape + +This is a integrated patch for layerscape vfio support. + +Signed-off-by: Bharat Bhushan +Signed-off-by: Eric Auger +Signed-off-by: Robin Murphy +Signed-off-by: Wei Yongjun +Signed-off-by: Yangbo Lu +--- + drivers/vfio/Kconfig | 1 + + drivers/vfio/Makefile | 1 + + drivers/vfio/fsl-mc/Kconfig | 9 + + drivers/vfio/fsl-mc/Makefile | 2 + + drivers/vfio/fsl-mc/vfio_fsl_mc.c | 753 ++++++++++++++++++++++++++++++ + drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c | 199 ++++++++ + drivers/vfio/fsl-mc/vfio_fsl_mc_private.h | 55 +++ + drivers/vfio/vfio_iommu_type1.c | 39 +- + include/uapi/linux/vfio.h | 1 + + 9 files changed, 1058 insertions(+), 2 deletions(-) + create mode 100644 drivers/vfio/fsl-mc/Kconfig + create mode 100644 drivers/vfio/fsl-mc/Makefile + create mode 100644 drivers/vfio/fsl-mc/vfio_fsl_mc.c + create mode 100644 drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c + create mode 100644 drivers/vfio/fsl-mc/vfio_fsl_mc_private.h + +diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig +index da6e2ce7..8a8a33e0 100644 +--- a/drivers/vfio/Kconfig ++++ b/drivers/vfio/Kconfig +@@ -48,4 +48,5 @@ menuconfig VFIO_NOIOMMU + + source "drivers/vfio/pci/Kconfig" + source "drivers/vfio/platform/Kconfig" ++source "drivers/vfio/fsl-mc/Kconfig" + source "virt/lib/Kconfig" +diff --git a/drivers/vfio/Makefile b/drivers/vfio/Makefile +index 7b8a31f6..560f0c67 100644 +--- a/drivers/vfio/Makefile ++++ b/drivers/vfio/Makefile +@@ -7,3 +7,4 @@ obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o + obj-$(CONFIG_VFIO_SPAPR_EEH) += vfio_spapr_eeh.o + obj-$(CONFIG_VFIO_PCI) += pci/ + obj-$(CONFIG_VFIO_PLATFORM) += platform/ ++obj-$(CONFIG_VFIO_FSL_MC) += fsl-mc/ +diff --git a/drivers/vfio/fsl-mc/Kconfig b/drivers/vfio/fsl-mc/Kconfig +new file mode 100644 +index 00000000..b1a527d6 +--- /dev/null ++++ b/drivers/vfio/fsl-mc/Kconfig +@@ -0,0 +1,9 @@ ++config VFIO_FSL_MC ++ tristate "VFIO support for QorIQ DPAA2 fsl-mc bus devices" ++ depends on VFIO && FSL_MC_BUS && EVENTFD ++ help ++ Driver to enable support for the VFIO QorIQ DPAA2 fsl-mc ++ (Management Complex) devices. This is required to passthrough ++ fsl-mc bus devices using the VFIO framework. ++ ++ If you don't know what to do here, say N. +diff --git a/drivers/vfio/fsl-mc/Makefile b/drivers/vfio/fsl-mc/Makefile +new file mode 100644 +index 00000000..2aca75af +--- /dev/null ++++ b/drivers/vfio/fsl-mc/Makefile +@@ -0,0 +1,2 @@ ++vfio-fsl_mc-y := vfio_fsl_mc.o ++obj-$(CONFIG_VFIO_FSL_MC) += vfio_fsl_mc.o vfio_fsl_mc_intr.o +diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc.c b/drivers/vfio/fsl-mc/vfio_fsl_mc.c +new file mode 100644 +index 00000000..9dc32d27 +--- /dev/null ++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c +@@ -0,0 +1,753 @@ ++/* ++ * Freescale Management Complex (MC) device passthrough using VFIO ++ * ++ * Copyright (C) 2013-2016 Freescale Semiconductor, Inc. ++ * Copyright 2016-2017 NXP ++ * Author: Bharat Bhushan ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../../staging/fsl-mc/include/mc.h" ++#include "../../staging/fsl-mc/include/mc-bus.h" ++#include "../../staging/fsl-mc/include/mc-sys.h" ++#include "../../staging/fsl-mc/bus/dprc-cmd.h" ++ ++#include "vfio_fsl_mc_private.h" ++ ++#define DRIVER_VERSION "0.10" ++#define DRIVER_AUTHOR "Bharat Bhushan " ++#define DRIVER_DESC "VFIO for FSL-MC devices - User Level meta-driver" ++ ++static DEFINE_MUTEX(driver_lock); ++ ++/* FSl-MC device regions (address and size) are aligned to 64K. ++ * While MC firmware reports size less than 64K for some objects (it actually ++ * reports size which does not include reserved space beyond valid bytes). ++ * Align the size to PAGE_SIZE for userspace to mmap. ++ */ ++static size_t aligned_region_size(struct fsl_mc_device *mc_dev, int index) ++{ ++ size_t size; ++ ++ size = resource_size(&mc_dev->regions[index]); ++ return PAGE_ALIGN(size); ++} ++ ++static int vfio_fsl_mc_regions_init(struct vfio_fsl_mc_device *vdev) ++{ ++ struct fsl_mc_device *mc_dev = vdev->mc_dev; ++ int count = mc_dev->obj_desc.region_count; ++ int i; ++ ++ vdev->regions = kcalloc(count, sizeof(struct vfio_fsl_mc_region), ++ GFP_KERNEL); ++ if (!vdev->regions) ++ return -ENOMEM; ++ ++ for (i = 0; i < mc_dev->obj_desc.region_count; i++) { ++ vdev->regions[i].addr = mc_dev->regions[i].start; ++ vdev->regions[i].size = aligned_region_size(mc_dev, i); ++ vdev->regions[i].type = VFIO_FSL_MC_REGION_TYPE_MMIO; ++ if (mc_dev->regions[i].flags & IORESOURCE_CACHEABLE) ++ vdev->regions[i].type |= ++ VFIO_FSL_MC_REGION_TYPE_CACHEABLE; ++ vdev->regions[i].flags = VFIO_REGION_INFO_FLAG_MMAP; ++ vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_READ; ++ if (!(mc_dev->regions[i].flags & IORESOURCE_READONLY)) ++ vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_WRITE; ++ } ++ ++ vdev->num_regions = mc_dev->obj_desc.region_count; ++ return 0; ++} ++ ++static void vfio_fsl_mc_regions_cleanup(struct vfio_fsl_mc_device *vdev) ++{ ++ int i; ++ ++ for (i = 0; i < vdev->num_regions; i++) ++ iounmap(vdev->regions[i].ioaddr); ++ ++ vdev->num_regions = 0; ++ kfree(vdev->regions); ++} ++ ++static int vfio_fsl_mc_open(void *device_data) ++{ ++ struct vfio_fsl_mc_device *vdev = device_data; ++ int ret; ++ ++ if (!try_module_get(THIS_MODULE)) ++ return -ENODEV; ++ ++ mutex_lock(&driver_lock); ++ if (!vdev->refcnt) { ++ ret = vfio_fsl_mc_regions_init(vdev); ++ if (ret) ++ goto error_region_init; ++ ++ ret = vfio_fsl_mc_irqs_init(vdev); ++ if (ret) ++ goto error_irq_init; ++ } ++ ++ vdev->refcnt++; ++ mutex_unlock(&driver_lock); ++ return 0; ++ ++error_irq_init: ++ vfio_fsl_mc_regions_cleanup(vdev); ++error_region_init: ++ mutex_unlock(&driver_lock); ++ if (ret) ++ module_put(THIS_MODULE); ++ ++ return ret; ++} ++ ++static void vfio_fsl_mc_release(void *device_data) ++{ ++ struct vfio_fsl_mc_device *vdev = device_data; ++ struct fsl_mc_device *mc_dev = vdev->mc_dev; ++ ++ mutex_lock(&driver_lock); ++ ++ if (!(--vdev->refcnt)) { ++ vfio_fsl_mc_regions_cleanup(vdev); ++ vfio_fsl_mc_irqs_cleanup(vdev); ++ } ++ ++ if (strcmp(mc_dev->obj_desc.type, "dprc") == 0) ++ dprc_reset_container(mc_dev->mc_io, 0, mc_dev->mc_handle, ++ mc_dev->obj_desc.id); ++ ++ mutex_unlock(&driver_lock); ++ ++ module_put(THIS_MODULE); ++} ++ ++static long vfio_fsl_mc_ioctl(void *device_data, unsigned int cmd, ++ unsigned long arg) ++{ ++ struct vfio_fsl_mc_device *vdev = device_data; ++ struct fsl_mc_device *mc_dev = vdev->mc_dev; ++ unsigned long minsz; ++ ++ if (WARN_ON(!mc_dev)) ++ return -ENODEV; ++ ++ switch (cmd) { ++ case VFIO_DEVICE_GET_INFO: ++ { ++ struct vfio_device_info info; ++ ++ minsz = offsetofend(struct vfio_device_info, num_irqs); ++ ++ if (copy_from_user(&info, (void __user *)arg, minsz)) ++ return -EFAULT; ++ ++ if (info.argsz < minsz) ++ return -EINVAL; ++ ++ info.flags = VFIO_DEVICE_FLAGS_FSL_MC; ++ info.num_regions = mc_dev->obj_desc.region_count; ++ info.num_irqs = mc_dev->obj_desc.irq_count; ++ ++ return copy_to_user((void __user *)arg, &info, minsz); ++ } ++ case VFIO_DEVICE_GET_REGION_INFO: ++ { ++ struct vfio_region_info info; ++ ++ minsz = offsetofend(struct vfio_region_info, offset); ++ ++ if (copy_from_user(&info, (void __user *)arg, minsz)) ++ return -EFAULT; ++ ++ if (info.argsz < minsz) ++ return -EINVAL; ++ ++ if (info.index >= vdev->num_regions) ++ return -EINVAL; ++ ++ /* map offset to the physical address */ ++ info.offset = VFIO_FSL_MC_INDEX_TO_OFFSET(info.index); ++ info.size = vdev->regions[info.index].size; ++ info.flags = vdev->regions[info.index].flags; ++ ++ return copy_to_user((void __user *)arg, &info, minsz); ++ } ++ case VFIO_DEVICE_GET_IRQ_INFO: ++ { ++ struct vfio_irq_info info; ++ ++ minsz = offsetofend(struct vfio_irq_info, count); ++ if (copy_from_user(&info, (void __user *)arg, minsz)) ++ return -EFAULT; ++ ++ if (info.argsz < minsz) ++ return -EINVAL; ++ ++ if (info.index >= mc_dev->obj_desc.irq_count) ++ return -EINVAL; ++ ++ if (vdev->mc_irqs != NULL) { ++ info.flags = vdev->mc_irqs[info.index].flags; ++ info.count = vdev->mc_irqs[info.index].count; ++ } else { ++ /* ++ * If IRQs are not initialized then these can not ++ * be configuted and used by user-space/ ++ */ ++ info.flags = 0; ++ info.count = 0; ++ } ++ ++ return copy_to_user((void __user *)arg, &info, minsz); ++ } ++ case VFIO_DEVICE_SET_IRQS: ++ { ++ struct vfio_irq_set hdr; ++ u8 *data = NULL; ++ int ret = 0; ++ ++ minsz = offsetofend(struct vfio_irq_set, count); ++ ++ if (copy_from_user(&hdr, (void __user *)arg, minsz)) ++ return -EFAULT; ++ ++ if (hdr.argsz < minsz) ++ return -EINVAL; ++ ++ if (hdr.index >= mc_dev->obj_desc.irq_count) ++ return -EINVAL; ++ ++ if (hdr.start != 0 || hdr.count > 1) ++ return -EINVAL; ++ ++ if (hdr.count == 0 && ++ (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE) || ++ !(hdr.flags & VFIO_IRQ_SET_ACTION_TRIGGER))) ++ return -EINVAL; ++ ++ if (hdr.flags & ~(VFIO_IRQ_SET_DATA_TYPE_MASK | ++ VFIO_IRQ_SET_ACTION_TYPE_MASK)) ++ return -EINVAL; ++ ++ if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) { ++ size_t size; ++ ++ if (hdr.flags & VFIO_IRQ_SET_DATA_BOOL) ++ size = sizeof(uint8_t); ++ else if (hdr.flags & VFIO_IRQ_SET_DATA_EVENTFD) ++ size = sizeof(int32_t); ++ else ++ return -EINVAL; ++ ++ if (hdr.argsz - minsz < hdr.count * size) ++ return -EINVAL; ++ ++ data = memdup_user((void __user *)(arg + minsz), ++ hdr.count * size); ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ } ++ ++ ret = vfio_fsl_mc_set_irqs_ioctl(vdev, hdr.flags, ++ hdr.index, hdr.start, ++ hdr.count, data); ++ return ret; ++ } ++ case VFIO_DEVICE_RESET: ++ { ++ return -EINVAL; ++ } ++ default: ++ return -EINVAL; ++ } ++} ++ ++static ssize_t vfio_fsl_mc_read(void *device_data, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct vfio_fsl_mc_device *vdev = device_data; ++ unsigned int index = VFIO_FSL_MC_OFFSET_TO_INDEX(*ppos); ++ loff_t off = *ppos & VFIO_FSL_MC_OFFSET_MASK; ++ struct vfio_fsl_mc_region *region; ++ uint64_t data[8]; ++ int i; ++ ++ /* Read ioctl supported only for DPRC device */ ++ if (strcmp(vdev->mc_dev->obj_desc.type, "dprc")) ++ return -EINVAL; ++ ++ if (index >= vdev->num_regions) ++ return -EINVAL; ++ ++ region = &vdev->regions[index]; ++ ++ if (!(region->flags & VFIO_REGION_INFO_FLAG_READ)) ++ return -EINVAL; ++ ++ if (!region->type & VFIO_FSL_MC_REGION_TYPE_MMIO) ++ return -EINVAL; ++ ++ if (!region->ioaddr) { ++ region->ioaddr = ioremap_nocache(region->addr, region->size); ++ if (!region->ioaddr) ++ return -ENOMEM; ++ } ++ ++ if (count != 64 || off != 0) ++ return -EINVAL; ++ ++ for (i = 7; i >= 0; i--) ++ data[i] = readq(region->ioaddr + i * sizeof(uint64_t)); ++ ++ if (copy_to_user(buf, data, 64)) ++ return -EFAULT; ++ ++ return count; ++} ++ ++#define MC_CMD_COMPLETION_TIMEOUT_MS 5000 ++#define MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS 500 ++ ++static int vfio_fsl_mc_dprc_wait_for_response(void __iomem *ioaddr) ++{ ++ enum mc_cmd_status status; ++ unsigned long timeout_usecs = MC_CMD_COMPLETION_TIMEOUT_MS * 1000; ++ ++ for (;;) { ++ u64 header; ++ struct mc_cmd_header *resp_hdr; ++ ++ __iormb(); ++ header = readq(ioaddr); ++ __iormb(); ++ ++ resp_hdr = (struct mc_cmd_header *)&header; ++ status = (enum mc_cmd_status)resp_hdr->status; ++ if (status != MC_CMD_STATUS_READY) ++ break; ++ ++ udelay(MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS); ++ timeout_usecs -= MC_CMD_COMPLETION_POLLING_MAX_SLEEP_USECS; ++ if (timeout_usecs == 0) ++ return -ETIMEDOUT; ++ } ++ ++ return 0; ++} ++ ++static int vfio_fsl_mc_send_command(void __iomem *ioaddr, uint64_t *cmd_data) ++{ ++ int i; ++ ++ /* Write at command header in the end */ ++ for (i = 7; i >= 0; i--) ++ writeq(cmd_data[i], ioaddr + i * sizeof(uint64_t)); ++ ++ /* Wait for response before returning to user-space ++ * This can be optimized in future to even prepare response ++ * before returning to user-space and avoid read ioctl. ++ */ ++ return vfio_fsl_mc_dprc_wait_for_response(ioaddr); ++} ++ ++static int vfio_handle_dprc_commands(void __iomem *ioaddr, uint64_t *cmd_data) ++{ ++ uint64_t cmd_hdr = cmd_data[0]; ++ int cmd = (cmd_hdr >> 52) & 0xfff; ++ ++ switch (cmd) { ++ case DPRC_CMDID_OPEN: ++ default: ++ return vfio_fsl_mc_send_command(ioaddr, cmd_data); ++ } ++ ++ return 0; ++} ++ ++static ssize_t vfio_fsl_mc_write(void *device_data, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct vfio_fsl_mc_device *vdev = device_data; ++ unsigned int index = VFIO_FSL_MC_OFFSET_TO_INDEX(*ppos); ++ loff_t off = *ppos & VFIO_FSL_MC_OFFSET_MASK; ++ struct vfio_fsl_mc_region *region; ++ uint64_t data[8]; ++ int ret; ++ ++ /* Write ioctl supported only for DPRC device */ ++ if (strcmp(vdev->mc_dev->obj_desc.type, "dprc")) ++ return -EINVAL; ++ ++ if (index >= vdev->num_regions) ++ return -EINVAL; ++ ++ region = &vdev->regions[index]; ++ ++ if (!(region->flags & VFIO_REGION_INFO_FLAG_WRITE)) ++ return -EINVAL; ++ ++ if (!region->type & VFIO_FSL_MC_REGION_TYPE_MMIO) ++ return -EINVAL; ++ ++ if (!region->ioaddr) { ++ region->ioaddr = ioremap_nocache(region->addr, region->size); ++ if (!region->ioaddr) ++ return -ENOMEM; ++ } ++ ++ if (count != 64 || off != 0) ++ return -EINVAL; ++ ++ if (copy_from_user(&data, buf, 64)) ++ return -EFAULT; ++ ++ ret = vfio_handle_dprc_commands(region->ioaddr, data); ++ if (ret) ++ return ret; ++ ++ return count; ++} ++ ++static int vfio_fsl_mc_mmap_mmio(struct vfio_fsl_mc_region region, ++ struct vm_area_struct *vma) ++{ ++ u64 size = vma->vm_end - vma->vm_start; ++ u64 pgoff, base; ++ ++ pgoff = vma->vm_pgoff & ++ ((1U << (VFIO_FSL_MC_OFFSET_SHIFT - PAGE_SHIFT)) - 1); ++ base = pgoff << PAGE_SHIFT; ++ ++ if (region.size < PAGE_SIZE || base + size > region.size) ++ return -EINVAL; ++ /* ++ * Set the REGION_TYPE_CACHEABLE (QBman CENA regs) to be the ++ * cache inhibited area of the portal to avoid coherency issues ++ * if a user migrates to another core. ++ */ ++ if (region.type & VFIO_FSL_MC_REGION_TYPE_CACHEABLE) ++ vma->vm_page_prot = pgprot_cached_ns(vma->vm_page_prot); ++ else ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ ++ vma->vm_pgoff = (region.addr >> PAGE_SHIFT) + pgoff; ++ ++ return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, ++ size, vma->vm_page_prot); ++} ++ ++/* Allows mmaping fsl_mc device regions in assigned DPRC */ ++static int vfio_fsl_mc_mmap(void *device_data, struct vm_area_struct *vma) ++{ ++ struct vfio_fsl_mc_device *vdev = device_data; ++ struct fsl_mc_device *mc_dev = vdev->mc_dev; ++ unsigned long size, addr; ++ int index; ++ ++ index = vma->vm_pgoff >> (VFIO_FSL_MC_OFFSET_SHIFT - PAGE_SHIFT); ++ ++ if (vma->vm_end < vma->vm_start) ++ return -EINVAL; ++ if (vma->vm_start & ~PAGE_MASK) ++ return -EINVAL; ++ if (vma->vm_end & ~PAGE_MASK) ++ return -EINVAL; ++ if (!(vma->vm_flags & VM_SHARED)) ++ return -EINVAL; ++ if (index >= vdev->num_regions) ++ return -EINVAL; ++ ++ if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_MMAP)) ++ return -EINVAL; ++ ++ if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ) ++ && (vma->vm_flags & VM_READ)) ++ return -EINVAL; ++ ++ if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_WRITE) ++ && (vma->vm_flags & VM_WRITE)) ++ return -EINVAL; ++ ++ addr = vdev->regions[index].addr; ++ size = vdev->regions[index].size; ++ ++ vma->vm_private_data = mc_dev; ++ ++ if (vdev->regions[index].type & VFIO_FSL_MC_REGION_TYPE_MMIO) ++ return vfio_fsl_mc_mmap_mmio(vdev->regions[index], vma); ++ ++ return -EFAULT; ++} ++ ++static const struct vfio_device_ops vfio_fsl_mc_ops = { ++ .name = "vfio-fsl-mc", ++ .open = vfio_fsl_mc_open, ++ .release = vfio_fsl_mc_release, ++ .ioctl = vfio_fsl_mc_ioctl, ++ .read = vfio_fsl_mc_read, ++ .write = vfio_fsl_mc_write, ++ .mmap = vfio_fsl_mc_mmap, ++}; ++ ++static int vfio_fsl_mc_initialize_dprc(struct vfio_fsl_mc_device *vdev) ++{ ++ struct device *root_dprc_dev; ++ struct fsl_mc_device *mc_dev = vdev->mc_dev; ++ struct device *dev = &mc_dev->dev; ++ struct fsl_mc_bus *mc_bus; ++ struct irq_domain *mc_msi_domain; ++ unsigned int irq_count; ++ int ret; ++ ++ /* device must be DPRC */ ++ if (strcmp(mc_dev->obj_desc.type, "dprc")) ++ return -EINVAL; ++ ++ /* mc_io must be un-initialized */ ++ WARN_ON(mc_dev->mc_io); ++ ++ /* allocate a portal from the root DPRC for vfio use */ ++ fsl_mc_get_root_dprc(dev, &root_dprc_dev); ++ if (WARN_ON(!root_dprc_dev)) ++ return -EINVAL; ++ ++ ret = fsl_mc_portal_allocate(to_fsl_mc_device(root_dprc_dev), ++ FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, ++ &mc_dev->mc_io); ++ if (ret < 0) ++ goto clean_msi_domain; ++ ++ /* Reset MCP before move on */ ++ ret = fsl_mc_portal_reset(mc_dev->mc_io); ++ if (ret < 0) { ++ dev_err(dev, "dprc portal reset failed: error = %d\n", ret); ++ goto free_mc_portal; ++ } ++ ++ /* MSI domain set up */ ++ ret = fsl_mc_find_msi_domain(root_dprc_dev->parent, &mc_msi_domain); ++ if (ret < 0) ++ goto free_mc_portal; ++ ++ dev_set_msi_domain(&mc_dev->dev, mc_msi_domain); ++ ++ ret = dprc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id, ++ &mc_dev->mc_handle); ++ if (ret) { ++ dev_err(dev, "dprc_open() failed: error = %d\n", ret); ++ goto free_mc_portal; ++ } ++ ++ /* Initialize resource pool */ ++ fsl_mc_init_all_resource_pools(mc_dev); ++ ++ mc_bus = to_fsl_mc_bus(mc_dev); ++ ++ if (!mc_bus->irq_resources) { ++ irq_count = FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS; ++ ret = fsl_mc_populate_irq_pool(mc_bus, irq_count); ++ if (ret < 0) { ++ dev_err(dev, "%s: Failed to init irq-pool\n", __func__); ++ goto clean_resource_pool; ++ } ++ } ++ ++ mutex_init(&mc_bus->scan_mutex); ++ ++ mutex_lock(&mc_bus->scan_mutex); ++ ret = dprc_scan_objects(mc_dev, mc_dev->driver_override, ++ &irq_count); ++ mutex_unlock(&mc_bus->scan_mutex); ++ if (ret) { ++ dev_err(dev, "dprc_scan_objects() fails (%d)\n", ret); ++ goto clean_irq_pool; ++ } ++ ++ if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) { ++ dev_warn(&mc_dev->dev, ++ "IRQs needed (%u) exceed IRQs preallocated (%u)\n", ++ irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); ++ } ++ ++ return 0; ++ ++clean_irq_pool: ++ fsl_mc_cleanup_irq_pool(mc_bus); ++ ++clean_resource_pool: ++ fsl_mc_cleanup_all_resource_pools(mc_dev); ++ dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); ++ ++free_mc_portal: ++ fsl_mc_portal_free(mc_dev->mc_io); ++ ++clean_msi_domain: ++ dev_set_msi_domain(&mc_dev->dev, NULL); ++ ++ return ret; ++} ++ ++static int vfio_fsl_mc_device_remove(struct device *dev, void *data) ++{ ++ struct fsl_mc_device *mc_dev; ++ ++ WARN_ON(dev == NULL); ++ ++ mc_dev = to_fsl_mc_device(dev); ++ if (WARN_ON(mc_dev == NULL)) ++ return -ENODEV; ++ ++ fsl_mc_device_remove(mc_dev); ++ return 0; ++} ++ ++static void vfio_fsl_mc_cleanup_dprc(struct vfio_fsl_mc_device *vdev) ++{ ++ struct fsl_mc_device *mc_dev = vdev->mc_dev; ++ struct fsl_mc_bus *mc_bus; ++ ++ /* device must be DPRC */ ++ if (strcmp(mc_dev->obj_desc.type, "dprc")) ++ return; ++ ++ device_for_each_child(&mc_dev->dev, NULL, vfio_fsl_mc_device_remove); ++ ++ mc_bus = to_fsl_mc_bus(mc_dev); ++ if (dev_get_msi_domain(&mc_dev->dev)) ++ fsl_mc_cleanup_irq_pool(mc_bus); ++ ++ dev_set_msi_domain(&mc_dev->dev, NULL); ++ ++ fsl_mc_cleanup_all_resource_pools(mc_dev); ++ dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); ++ fsl_mc_portal_free(mc_dev->mc_io); ++} ++ ++static int vfio_fsl_mc_probe(struct fsl_mc_device *mc_dev) ++{ ++ struct iommu_group *group; ++ struct vfio_fsl_mc_device *vdev; ++ struct device *dev = &mc_dev->dev; ++ int ret; ++ ++ group = vfio_iommu_group_get(dev); ++ if (!group) { ++ dev_err(dev, "%s: VFIO: No IOMMU group\n", __func__); ++ return -EINVAL; ++ } ++ ++ vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); ++ if (!vdev) { ++ vfio_iommu_group_put(group, dev); ++ return -ENOMEM; ++ } ++ ++ vdev->mc_dev = mc_dev; ++ ++ ret = vfio_add_group_dev(dev, &vfio_fsl_mc_ops, vdev); ++ if (ret) { ++ dev_err(dev, "%s: Failed to add to vfio group\n", __func__); ++ goto free_vfio_device; ++ } ++ ++ /* DPRC container scanned and it's chilren bound with vfio driver */ ++ if (strcmp(mc_dev->obj_desc.type, "dprc") == 0) { ++ ret = vfio_fsl_mc_initialize_dprc(vdev); ++ if (ret) { ++ vfio_del_group_dev(dev); ++ goto free_vfio_device; ++ } ++ } else { ++ struct fsl_mc_device *mc_bus_dev; ++ ++ /* Non-dprc devices share mc_io from the parent dprc */ ++ mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); ++ if (mc_bus_dev == NULL) { ++ vfio_del_group_dev(dev); ++ goto free_vfio_device; ++ } ++ ++ mc_dev->mc_io = mc_bus_dev->mc_io; ++ ++ /* Inherit parent MSI domain */ ++ dev_set_msi_domain(&mc_dev->dev, ++ dev_get_msi_domain(mc_dev->dev.parent)); ++ } ++ return 0; ++ ++free_vfio_device: ++ kfree(vdev); ++ vfio_iommu_group_put(group, dev); ++ return ret; ++} ++ ++static int vfio_fsl_mc_remove(struct fsl_mc_device *mc_dev) ++{ ++ struct vfio_fsl_mc_device *vdev; ++ struct device *dev = &mc_dev->dev; ++ ++ vdev = vfio_del_group_dev(dev); ++ if (!vdev) ++ return -EINVAL; ++ ++ if (strcmp(mc_dev->obj_desc.type, "dprc") == 0) ++ vfio_fsl_mc_cleanup_dprc(vdev); ++ else ++ dev_set_msi_domain(&mc_dev->dev, NULL); ++ ++ mc_dev->mc_io = NULL; ++ ++ vfio_iommu_group_put(mc_dev->dev.iommu_group, dev); ++ kfree(vdev); ++ ++ return 0; ++} ++ ++/* ++ * vfio-fsl_mc is a meta-driver, so use driver_override interface to ++ * bind a fsl_mc container with this driver and match_id_table is NULL. ++ */ ++static struct fsl_mc_driver vfio_fsl_mc_driver = { ++ .probe = vfio_fsl_mc_probe, ++ .remove = vfio_fsl_mc_remove, ++ .match_id_table = NULL, ++ .driver = { ++ .name = "vfio-fsl-mc", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init vfio_fsl_mc_driver_init(void) ++{ ++ return fsl_mc_driver_register(&vfio_fsl_mc_driver); ++} ++ ++static void __exit vfio_fsl_mc_driver_exit(void) ++{ ++ fsl_mc_driver_unregister(&vfio_fsl_mc_driver); ++} ++ ++module_init(vfio_fsl_mc_driver_init); ++module_exit(vfio_fsl_mc_driver_exit); ++ ++MODULE_VERSION(DRIVER_VERSION); ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_DESCRIPTION(DRIVER_DESC); +diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c +new file mode 100644 +index 00000000..eb244bb0 +--- /dev/null ++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_intr.c +@@ -0,0 +1,199 @@ ++/* ++ * Freescale Management Complex (MC) device passthrough using VFIO ++ * ++ * Copyright (C) 2013-2016 Freescale Semiconductor, Inc. ++ * Author: Bharat Bhushan ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "../../staging/fsl-mc/include/mc.h" ++#include "vfio_fsl_mc_private.h" ++ ++static irqreturn_t vfio_fsl_mc_irq_handler(int irq_num, void *arg) ++{ ++ struct vfio_fsl_mc_irq *mc_irq = (struct vfio_fsl_mc_irq *)arg; ++ ++ eventfd_signal(mc_irq->trigger, 1); ++ return IRQ_HANDLED; ++} ++ ++static int vfio_fsl_mc_irq_mask(struct vfio_fsl_mc_device *vdev, ++ unsigned int index, unsigned int start, ++ unsigned int count, uint32_t flags, ++ void *data) ++{ ++ return -EINVAL; ++} ++ ++static int vfio_fsl_mc_irq_unmask(struct vfio_fsl_mc_device *vdev, ++ unsigned int index, unsigned int start, ++ unsigned int count, uint32_t flags, ++ void *data) ++{ ++ return -EINVAL; ++} ++ ++static int vfio_set_trigger(struct vfio_fsl_mc_device *vdev, ++ int index, int fd) ++{ ++ struct vfio_fsl_mc_irq *irq = &vdev->mc_irqs[index]; ++ struct eventfd_ctx *trigger; ++ int hwirq; ++ int ret; ++ ++ hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq; ++ if (irq->trigger) { ++ free_irq(hwirq, irq); ++ kfree(irq->name); ++ eventfd_ctx_put(irq->trigger); ++ irq->trigger = NULL; ++ } ++ ++ if (fd < 0) /* Disable only */ ++ return 0; ++ ++ irq->name = kasprintf(GFP_KERNEL, "vfio-irq[%d](%s)", ++ hwirq, dev_name(&vdev->mc_dev->dev)); ++ if (!irq->name) ++ return -ENOMEM; ++ ++ trigger = eventfd_ctx_fdget(fd); ++ if (IS_ERR(trigger)) { ++ kfree(irq->name); ++ return PTR_ERR(trigger); ++ } ++ ++ irq->trigger = trigger; ++ ++ ret = request_irq(hwirq, vfio_fsl_mc_irq_handler, 0, ++ irq->name, irq); ++ if (ret) { ++ kfree(irq->name); ++ eventfd_ctx_put(trigger); ++ irq->trigger = NULL; ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int vfio_fsl_mc_irqs_init(struct vfio_fsl_mc_device *vdev) ++{ ++ struct fsl_mc_device *mc_dev = vdev->mc_dev; ++ struct vfio_fsl_mc_irq *mc_irq; ++ int irq_count; ++ int ret, i; ++ ++ /* Device does not support any interrupt */ ++ if (mc_dev->obj_desc.irq_count == 0) ++ return 0; ++ ++ irq_count = mc_dev->obj_desc.irq_count; ++ ++ mc_irq = kcalloc(irq_count, sizeof(*mc_irq), GFP_KERNEL); ++ if (mc_irq == NULL) ++ return -ENOMEM; ++ ++ /* Allocate IRQs */ ++ ret = fsl_mc_allocate_irqs(mc_dev); ++ if (ret) { ++ kfree(mc_irq); ++ return ret; ++ } ++ ++ for (i = 0; i < irq_count; i++) { ++ mc_irq[i].count = 1; ++ mc_irq[i].flags = VFIO_IRQ_INFO_EVENTFD; ++ } ++ ++ vdev->mc_irqs = mc_irq; ++ ++ return 0; ++} ++ ++/* Free All IRQs for the given MC object */ ++void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev) ++{ ++ struct fsl_mc_device *mc_dev = vdev->mc_dev; ++ int irq_count = mc_dev->obj_desc.irq_count; ++ int i; ++ ++ /* Device does not support any interrupt */ ++ if (mc_dev->obj_desc.irq_count == 0) ++ return; ++ ++ for (i = 0; i < irq_count; i++) ++ vfio_set_trigger(vdev, i, -1); ++ ++ fsl_mc_free_irqs(mc_dev); ++ kfree(vdev->mc_irqs); ++} ++ ++static int vfio_fsl_mc_set_irq_trigger(struct vfio_fsl_mc_device *vdev, ++ unsigned int index, unsigned int start, ++ unsigned int count, uint32_t flags, ++ void *data) ++{ ++ struct vfio_fsl_mc_irq *irq = &vdev->mc_irqs[index]; ++ int hwirq; ++ ++ if (!count && (flags & VFIO_IRQ_SET_DATA_NONE)) ++ return vfio_set_trigger(vdev, index, -1); ++ ++ if (start != 0 || count != 1) ++ return -EINVAL; ++ ++ if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { ++ int32_t fd = *(int32_t *)data; ++ ++ return vfio_set_trigger(vdev, index, fd); ++ } ++ ++ hwirq = vdev->mc_dev->irqs[index]->msi_desc->irq; ++ ++ if (flags & VFIO_IRQ_SET_DATA_NONE) { ++ vfio_fsl_mc_irq_handler(hwirq, irq); ++ ++ } else if (flags & VFIO_IRQ_SET_DATA_BOOL) { ++ uint8_t trigger = *(uint8_t *)data; ++ ++ if (trigger) ++ vfio_fsl_mc_irq_handler(hwirq, irq); ++ } ++ ++ return 0; ++} ++ ++int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev, ++ uint32_t flags, unsigned int index, ++ unsigned int start, unsigned int count, ++ void *data) ++{ ++ int ret = -ENOTTY; ++ ++ switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) { ++ case VFIO_IRQ_SET_ACTION_MASK: ++ ret = vfio_fsl_mc_irq_mask(vdev, index, start, count, ++ flags, data); ++ break; ++ case VFIO_IRQ_SET_ACTION_UNMASK: ++ ret = vfio_fsl_mc_irq_unmask(vdev, index, start, count, ++ flags, data); ++ break; ++ case VFIO_IRQ_SET_ACTION_TRIGGER: ++ ret = vfio_fsl_mc_set_irq_trigger(vdev, index, start, ++ count, flags, data); ++ break; ++ } ++ ++ return ret; ++} +diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h +new file mode 100644 +index 00000000..34e75754 +--- /dev/null ++++ b/drivers/vfio/fsl-mc/vfio_fsl_mc_private.h +@@ -0,0 +1,55 @@ ++/* ++ * Freescale Management Complex VFIO private declarations ++ * ++ * Copyright (C) 2013-2016 Freescale Semiconductor, Inc. ++ * Copyright 2016 NXP ++ * Author: Bharat Bhushan ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#ifndef VFIO_FSL_MC_PRIVATE_H ++#define VFIO_FSL_MC_PRIVATE_H ++ ++#define VFIO_FSL_MC_OFFSET_SHIFT 40 ++#define VFIO_FSL_MC_OFFSET_MASK (((u64)(1) << VFIO_FSL_MC_OFFSET_SHIFT) - 1) ++ ++#define VFIO_FSL_MC_OFFSET_TO_INDEX(off) (off >> VFIO_FSL_MC_OFFSET_SHIFT) ++ ++#define VFIO_FSL_MC_INDEX_TO_OFFSET(index) \ ++ ((u64)(index) << VFIO_FSL_MC_OFFSET_SHIFT) ++ ++struct vfio_fsl_mc_irq { ++ u32 flags; ++ u32 count; ++ struct eventfd_ctx *trigger; ++ char *name; ++}; ++ ++struct vfio_fsl_mc_region { ++ u32 flags; ++#define VFIO_FSL_MC_REGION_TYPE_MMIO 1 ++#define VFIO_FSL_MC_REGION_TYPE_CACHEABLE 2 ++ u32 type; ++ u64 addr; ++ resource_size_t size; ++ void __iomem *ioaddr; ++}; ++ ++struct vfio_fsl_mc_device { ++ struct fsl_mc_device *mc_dev; ++ int refcnt; ++ u32 num_regions; ++ struct vfio_fsl_mc_region *regions; ++ struct vfio_fsl_mc_irq *mc_irqs; ++}; ++ ++int vfio_fsl_mc_irqs_init(struct vfio_fsl_mc_device *vdev); ++void vfio_fsl_mc_irqs_cleanup(struct vfio_fsl_mc_device *vdev); ++int vfio_fsl_mc_set_irqs_ioctl(struct vfio_fsl_mc_device *vdev, ++ uint32_t flags, unsigned int index, ++ unsigned int start, unsigned int count, ++ void *data); ++#endif /* VFIO_PCI_PRIVATE_H */ +diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c +index 1d48e62f..f0a39331 100644 +--- a/drivers/vfio/vfio_iommu_type1.c ++++ b/drivers/vfio/vfio_iommu_type1.c +@@ -36,6 +36,8 @@ + #include + #include + #include ++#include ++#include + + #define DRIVER_VERSION "0.2" + #define DRIVER_AUTHOR "Alex Williamson " +@@ -720,6 +722,27 @@ static void vfio_test_domain_fgsp(struct vfio_domain *domain) + __free_pages(pages, order); + } + ++static bool vfio_iommu_has_sw_msi(struct iommu_group *group, phys_addr_t *base) ++{ ++ struct list_head group_resv_regions; ++ struct iommu_resv_region *region, *next; ++ bool ret = false; ++ ++ INIT_LIST_HEAD(&group_resv_regions); ++ iommu_get_group_resv_regions(group, &group_resv_regions); ++ list_for_each_entry(region, &group_resv_regions, list) { ++ if (region->type == IOMMU_RESV_SW_MSI) { ++ *base = region->start; ++ ret = true; ++ goto out; ++ } ++ } ++out: ++ list_for_each_entry_safe(region, next, &group_resv_regions, list) ++ kfree(region); ++ return ret; ++} ++ + static int vfio_iommu_type1_attach_group(void *iommu_data, + struct iommu_group *iommu_group) + { +@@ -728,6 +751,8 @@ static int vfio_iommu_type1_attach_group(void *iommu_data, + struct vfio_domain *domain, *d; + struct bus_type *bus = NULL; + int ret; ++ bool resv_msi, msi_remap; ++ phys_addr_t resv_msi_base; + + mutex_lock(&iommu->lock); + +@@ -774,11 +799,15 @@ static int vfio_iommu_type1_attach_group(void *iommu_data, + if (ret) + goto out_domain; + ++ resv_msi = vfio_iommu_has_sw_msi(iommu_group, &resv_msi_base); ++ + INIT_LIST_HEAD(&domain->group_list); + list_add(&group->next, &domain->group_list); + +- if (!allow_unsafe_interrupts && +- !iommu_capable(bus, IOMMU_CAP_INTR_REMAP)) { ++ msi_remap = resv_msi ? irq_domain_check_msi_remap() : ++ iommu_capable(bus, IOMMU_CAP_INTR_REMAP); ++ ++ if (!allow_unsafe_interrupts && !msi_remap) { + pr_warn("%s: No interrupt remapping support. Use the module param \"allow_unsafe_interrupts\" to enable VFIO IOMMU support on this platform\n", + __func__); + ret = -EPERM; +@@ -820,6 +849,12 @@ static int vfio_iommu_type1_attach_group(void *iommu_data, + if (ret) + goto out_detach; + ++ if (resv_msi) { ++ ret = iommu_get_msi_cookie(domain->domain, resv_msi_base); ++ if (ret) ++ goto out_detach; ++ } ++ + list_add(&domain->next, &iommu->domain_list); + + mutex_unlock(&iommu->lock); +diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h +index 255a2113..1bbaa13d 100644 +--- a/include/uapi/linux/vfio.h ++++ b/include/uapi/linux/vfio.h +@@ -198,6 +198,7 @@ struct vfio_device_info { + #define VFIO_DEVICE_FLAGS_PCI (1 << 1) /* vfio-pci device */ + #define VFIO_DEVICE_FLAGS_PLATFORM (1 << 2) /* vfio-platform device */ + #define VFIO_DEVICE_FLAGS_AMBA (1 << 3) /* vfio-amba device */ ++#define VFIO_DEVICE_FLAGS_FSL_MC (1 << 5) /* vfio-fsl-mc device */ + __u32 num_regions; /* Max region index + 1 */ + __u32 num_irqs; /* Max IRQ index + 1 */ + }; +-- +2.14.1 +